[med-svn] [blat] 01/02: Imported Upstream version 35

Andreas Tille tille at debian.org
Thu Feb 20 18:54:21 UTC 2014


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

tille pushed a commit to branch master
in repository blat.

commit d5792b25e99b832e067e112b493896613914e248
Author: Andreas Tille <tille at debian.org>
Date:   Thu Feb 20 19:51:05 2014 +0100

    Imported Upstream version 35
---
 README                                             |   38 +
 blat/.cvsignore                                    |    1 +
 blat/blat.c                                        |  754 +++++
 blat/hCrea.geno                                    |  100 +
 blat/hCrea.mrna                                    |   23 +
 blat/hCrea.pep                                     |    7 +
 blat/mCrea.geno                                    |  114 +
 blat/mCrea.mrna                                    |   24 +
 blat/mCrea.pep                                     |    7 +
 blat/makefile                                      |   34 +
 blat/refFine.psl                                   |    6 +
 blat/refProt.psl                                   |    7 +
 blat/refProtX.psl                                  |    6 +
 blat/refRna.psl                                    |    6 +
 blat/refRnaX.psl                                   |    6 +
 blat/test/badSplice/chr16part.fa                   | 2001 ++++++++++++
 blat/test/badSplice/small2.fa                      |  109 +
 blat/test/badSplice/test                           |    4 +
 blat/test/intron50k/expected/test1.psl             |    6 +
 blat/test/intron50k/expected/test2.psl             |    7 +
 blat/test/intron50k/expected/test3.psl             |    8 +
 blat/test/intron50k/query.fa                       |   13 +
 blat/test/intron50k/target.fa                      | 2001 ++++++++++++
 blat/test/makefile                                 |   20 +
 blat/test/missBlastOut/C57_0005_A6_BB_5.fa         |   17 +
 blat/test/missBlastOut/genome.lst                  |    2 +
 blat/test/missBlastOut/out.blast                   |   76 +
 blat/test/missBlastOut/out.psl                     |   10 +
 blat/test/noHit19/noHit19.fa                       |   69 +
 blat/test/noHit19/noHit19.psl                      |    6 +
 blat/test/small/expected.psl                       |    6 +
 blat/test/small/query.fa                           |    2 +
 blat/test/small/target.fa                          |   21 +
 blat/test/throwback/.cvsignore                     |    1 +
 blat/test/throwback/query1.fa                      |   37 +
 blat/test/throwback/target1.fa                     | 2590 +++++++++++++++
 blat/test/urchProt/prot.fa                         |   16 +
 blat/test/urchProt/works.fa                        |    9 +
 blat/test/v29skips/.cvsignore                      |    1 +
 blat/test/v29skips/ex1_database.fa                 |   58 +
 blat/test/v29skips/ex1_query.fa                    |   58 +
 blat/test/v29skips/ex1_reference.psl               |    6 +
 blat/test/v29skips/ex2_database.fa                 |   54 +
 blat/test/v29skips/ex2_query.fa                    |   54 +
 blat/test/v29skips/ex2_reference.psl               |    6 +
 gfClient/AB000095.fa                               |   49 +
 gfClient/AB000220.fa                               |   39 +
 gfClient/gfClient.c                                |  174 +
 gfClient/gfRange.as                                |   10 +
 gfClient/makefile                                  |   15 +
 gfClient/repeat.fa                                 |    7 +
 gfClient/test1.fa                                  |   11 +
 gfClient/test2.fa                                  |    7 +
 gfClient/test3.fa                                  |    9 +
 gfServer/AB000095.fa                               |   49 +
 gfServer/AB000220.fa                               |   39 +
 gfServer/gfServer.c                                | 1027 ++++++
 gfServer/makefile                                  |   29 +
 gfServer/repeat.fa                                 |    7 +
 gfServer/test1.fa                                  |   11 +
 gfServer/test1.nib                                 |  Bin 0 -> 241 bytes
 gfServer/test2.fa                                  |    7 +
 gfServer/test3.fa                                  |    9 +
 gfServer/tests/expected/testNib                    |   24 +
 gfServer/tests/expected/testPcr                    |   18 +
 gfServer/tests/expected/testProtNib                |   38 +
 gfServer/tests/expected/testProtTwoBit             |   38 +
 gfServer/tests/expected/testTransNib               |   94 +
 gfServer/tests/expected/testTransTwoBit            |   94 +
 gfServer/tests/expected/testTwoBit                 |   21 +
 gfServer/tests/input/crea.mrna                     |   47 +
 gfServer/tests/input/creaGeno.2bit                 |  Bin 0 -> 3837 bytes
 gfServer/tests/input/hCrea.mrna                    |   23 +
 gfServer/tests/input/hCreaGeno.nib                 |  Bin 0 -> 3456 bytes
 gfServer/tests/input/mCrea.mrna                    |   24 +
 gfServer/tests/input/mCrea.pep                     |    7 +
 gfServer/tests/input/mCreaGeno.nib                 |  Bin 0 -> 3935 bytes
 gfServer/tests/input/testPcr.2bit                  |  Bin 0 -> 13406 bytes
 gfServer/tests/testPcr                             |    3 +
 gfServer/tests/testProtNib                         |    4 +
 gfServer/tests/testProtTwoBit                      |    4 +
 gfServer/tests/testTransNib                        |    4 +
 gfServer/tests/testTransTwoBit                     |    4 +
 hg/pslPretty/input/S1.lst                          |   18 +
 hg/pslPretty/input/S2.lst                          |    1 +
 hg/pslPretty/input/test1.psl                       |    1 +
 hg/pslPretty/makefile                              |   28 +
 hg/pslPretty/pslPretty.c                           |  746 +++++
 hg/pslPretty/test/input/dnax.psl                   |    7 +
 hg/pslPretty/test/input/hCrea.geno                 |  100 +
 hg/pslPretty/test/input/hCrea.mrna                 |   23 +
 hg/pslPretty/test/input/hCrea.pep                  |    7 +
 hg/pslPretty/test/input/mCrea.geno                 |  114 +
 hg/pslReps/makefile                                |   18 +
 hg/pslReps/pslReps.c                               |  429 +++
 hg/pslSort/makefile                                |   19 +
 hg/pslSort/old.as                                  |   18 +
 hg/pslSort/pslSort.c                               |  397 +++
 inc/ace.h                                          |   79 +
 inc/aliType.h                                      |   32 +
 inc/annoColumn.h                                   |   26 +
 inc/annoFilter.h                                   |   79 +
 inc/annoFormatTab.h                                |   11 +
 inc/annoFormatter.h                                |   54 +
 inc/annoGrator.h                                   |   55 +
 inc/annoGratorQuery.h                              |   44 +
 inc/annoOption.h                                   |   22 +
 inc/annoRow.h                                      |   47 +
 inc/annoStreamVcf.h                                |   12 +
 inc/annoStreamer.h                                 |  103 +
 inc/apacheLog.h                                    |   43 +
 inc/asParse.h                                      |  120 +
 inc/axt.h                                          |  272 ++
 inc/bPlusTree.h                                    |  114 +
 inc/bamFile.h                                      |  148 +
 inc/bandExt.h                                      |   42 +
 inc/base64.h                                       |   30 +
 inc/basicBed.h                                     |  281 ++
 inc/bbiFile.h                                      |  361 ++
 inc/bigBed.h                                       |   83 +
 inc/bigWig.h                                       |  112 +
 inc/binRange.h                                     |  120 +
 inc/bits.h                                         |   76 +
 inc/blastParse.h                                   |  116 +
 inc/boxClump.h                                     |   41 +
 inc/boxLump.h                                      |   25 +
 inc/bwgInternal.h                                  |  113 +
 inc/cda.h                                          |  104 +
 inc/cgi_build_rules.mk                             |   36 +
 inc/chain.h                                        |  163 +
 inc/chainBlock.h                                   |   42 +
 inc/chainConnect.h                                 |   60 +
 inc/chainToAxt.h                                   |   15 +
 inc/chainToPsl.h                                   |   28 +
 inc/cheapcgi.h                                     |  506 +++
 inc/cirTree.h                                      |   82 +
 inc/codebias.h                                     |   33 +
 inc/common.h                                       | 1435 ++++++++
 inc/common.mk                                      |   33 +
 inc/correlate.h                                    |   39 +
 inc/crTree.h                                       |   90 +
 inc/crudeali.h                                     |   26 +
 inc/diGraph.h                                      |  202 ++
 inc/diGraph.h.97                                   |  210 ++
 inc/dlist.h                                        |  138 +
 inc/dnaLoad.h                                      |   40 +
 inc/dnaMarkov.h                                    |   43 +
 inc/dnaMotif.h                                     |  126 +
 inc/dnaseq.h                                       |   73 +
 inc/dnautil.h                                      |  260 ++
 inc/dsPrint.h                                      |  108 +
 inc/dtdParse.h                                     |   57 +
 inc/dystring.h                                     |   98 +
 inc/emblParse.h                                    |   75 +
 inc/ens.h                                          |  168 +
 inc/errCatch.h                                     |   56 +
 inc/errabort.h                                     |   93 +
 inc/fa.h                                           |  129 +
 inc/filePath.h                                     |   31 +
 inc/flydna.h                                       |   32 +
 inc/fof.h                                          |   82 +
 inc/foo                                            |  361 ++
 inc/fuzzyFind.h                                    |  260 ++
 inc/gapCalc.h                                      |   44 +
 inc/gdf.h                                          |   61 +
 inc/genoFind.h                                     |  385 +++
 inc/genomeRangeTree.h                              |  111 +
 inc/gfClientLib.h                                  |   26 +
 inc/gfPcrLib.h                                     |  100 +
 inc/gfWebLib.h                                     |   28 +
 inc/gff.h                                          |  141 +
 inc/gff3.h                                         |  265 ++
 inc/gfxPoly.h                                      |   31 +
 inc/gifLabel.h                                     |   10 +
 inc/hacTree.h                                      |   82 +
 inc/hash.h                                         |  279 ++
 inc/hgGene.h                                       |  129 +
 inc/hgap.h                                         |  233 ++
 inc/hgdb.h                                         |   46 +
 inc/histogram.h                                    |   26 +
 inc/hmmPfamParse.h                                 |   55 +
 inc/hmmstats.h                                     |   30 +
 inc/htmlPage.h                                     |  239 ++
 inc/htmshell.h                                     |  180 +
 inc/https.h                                        |    9 +
 inc/intValTree.h                                   |   50 +
 inc/internet.h                                     |   43 +
 inc/itsa.h                                         |   90 +
 inc/iupac.h                                        |   42 +
 inc/jointalign.h                                   |   30 +
 inc/jpegSize.h                                     |   11 +
 inc/keys.h                                         |   66 +
 inc/knetUdc.h                                      |   10 +
 inc/kxTok.h                                        |   65 +
 inc/linefile.h                                     |  289 ++
 inc/localmem.h                                     |   47 +
 inc/log.h                                          |   74 +
 inc/maDbRep.h                                      |   62 +
 inc/maToFf.h                                       |   21 +
 inc/maf.h                                          |  258 ++
 inc/md5.h                                          |   21 +
 inc/memalloc.h                                     |   55 +
 inc/memgfx.h                                       |  389 +++
 inc/metaWig.h                                      |   44 +
 inc/mime.h                                         |   62 +
 inc/net.h                                          |  248 ++
 inc/nib.h                                          |  113 +
 inc/nibTwo.h                                       |   55 +
 inc/nt4.h                                          |   45 +
 inc/obscure.h                                      |  174 +
 inc/oldGff.h                                       |  103 +
 inc/oligoTm.h                                      |   98 +
 inc/ooc.h                                          |   16 +
 inc/options.h                                      |   97 +
 inc/pairHmm.h                                      |   94 +
 inc/patSpace.h                                     |   48 +
 inc/peakCluster.h                                  |   98 +
 inc/phyloTree.h                                    |   77 +
 inc/pipeline.h                                     |  154 +
 inc/portable.h                                     |  152 +
 inc/psGfx.h                                        |  118 +
 inc/psPoly.h                                       |   31 +
 inc/pscmGfx.h                                      |   71 +
 inc/psl.h                                          |  326 ++
 inc/pslTbl.h                                       |   42 +
 inc/pslTransMap.h                                  |   17 +
 inc/pthreadWrap.h                                  |   45 +
 inc/qa.h                                           |   65 +
 inc/quickHeap.h                                    |   53 +
 inc/quotedP.h                                      |   21 +
 inc/ra.h                                           |   81 +
 inc/rainbow.h                                      |   18 +
 inc/rangeTree.h                                    |   98 +
 inc/rbTree.h                                       |  102 +
 inc/regexHelper.h                                  |   29 +
 inc/repMask.h                                      |   56 +
 inc/rle.h                                          |   16 +
 inc/rnautil.h                                      |   55 +
 inc/rql.h                                          |  130 +
 inc/rudp.h                                         |  175 +
 inc/scoreWindow.h                                  |    7 +
 inc/seg.h                                          |  109 +
 inc/seqOut.h                                       |   91 +
 inc/seqStats.h                                     |   11 +
 inc/shaRes.h                                       |   45 +
 inc/sig.h                                          |  101 +
 inc/slog.h                                         |   18 +
 inc/snof.h                                         |   60 +
 inc/snofmake.h                                     |   35 +
 inc/spaceSaver.h                                   |   65 +
 inc/spacedColumn.h                                 |   46 +
 inc/spacedSeed.h                                   |   19 +
 inc/splatAli.h                                     |   80 +
 inc/splix.h                                        |   80 +
 inc/sqlList.h                                      |  142 +
 inc/sqlNum.h                                       |   83 +
 inc/subText.h                                      |   41 +
 inc/sufa.h                                         |   60 +
 inc/sufx.h                                         |   64 +
 inc/supStitch.h                                    |   73 +
 inc/synQueue.h                                     |   34 +
 inc/tabRow.h                                       |   45 +
 inc/textOut.h                                      |   46 +
 inc/tokenizer.h                                    |   66 +
 inc/trans3.h                                       |   59 +
 inc/trix.h                                         |   45 +
 inc/twoBit.h                                       |  194 ++
 inc/udc.h                                          |  143 +
 inc/unfin.h                                        |   31 +
 inc/vGfx.h                                         |  193 ++
 inc/vcf.h                                          |  232 ++
 inc/verbose.h                                      |   53 +
 inc/wormdna.h                                      |  245 ++
 inc/xAli.h                                         |   73 +
 inc/xa.h                                           |   63 +
 inc/xap.h                                          |   78 +
 inc/xenalign.h                                     |   41 +
 inc/xmlEscape.h                                    |   17 +
 inc/xp.h                                           |   78 +
 inc/zlibFace.h                                     |   26 +
 jkOwnLib/README                                    |    5 +
 jkOwnLib/bandExt.c                                 |  489 +++
 jkOwnLib/crudeali.c                                |  877 +++++
 jkOwnLib/ffAliHelp.c                               |  434 +++
 jkOwnLib/ffSeedExtend.c                            | 1284 ++++++++
 jkOwnLib/fuzzyFind.c                               | 1522 +++++++++
 jkOwnLib/genoFind.c                                | 2255 +++++++++++++
 jkOwnLib/gfBlatLib.c                               | 1613 +++++++++
 jkOwnLib/gfClientLib.c                             |  223 ++
 jkOwnLib/gfInternal.c                              |  141 +
 jkOwnLib/gfInternal.h                              |   64 +
 jkOwnLib/gfOut.c                                   |  603 ++++
 jkOwnLib/gfPcrLib.c                                |  571 ++++
 jkOwnLib/gfWebLib.c                                |   92 +
 jkOwnLib/makefile                                  |   19 +
 jkOwnLib/ooc.c                                     |   77 +
 jkOwnLib/patSpace.c                                |  463 +++
 jkOwnLib/splix.c                                   |  152 +
 jkOwnLib/supStitch.c                               |  912 ++++++
 jkOwnLib/tests/freen/freen.c                       |  115 +
 jkOwnLib/tests/freen/makefile                      |   13 +
 jkOwnLib/trans3.c                                  |  133 +
 jkOwnLib/version.doc                               |   54 +
 jkOwnLib/xenbig.c                                  | 1223 +++++++
 jkOwnLib/xensmall.c                                |  471 +++
 lib/README                                         |   22 +
 lib/aliType.c                                      |   30 +
 lib/alpha/placeHolder.c                            |    0
 lib/annoColumn.c                                   |   41 +
 lib/annoFilter.c                                   |  307 ++
 lib/annoFormatTab.c                                |  224 ++
 lib/annoFormatter.c                                |   26 +
 lib/annoGrator.c                                   |  222 ++
 lib/annoGratorQuery.c                              |  153 +
 lib/annoOption.c                                   |   97 +
 lib/annoRow.c                                      |  105 +
 lib/annoStreamVcf.c                                |  143 +
 lib/annoStreamer.c                                 |  104 +
 lib/apacheLog.c                                    |  208 ++
 lib/asParse.c                                      |  563 ++++
 lib/axt.c                                          | 1038 ++++++
 lib/axtAffine.c                                    |  781 +++++
 lib/bPlusTree.c                                    |  440 +++
 lib/bamFile.c                                      |  667 ++++
 lib/base64.c                                       |  129 +
 lib/basicBed.c                                     | 1632 +++++++++
 lib/bbiRead.c                                      |  738 +++++
 lib/bbiWrite.c                                     |  581 ++++
 lib/bigBed.c                                       |  253 ++
 lib/binRange.c                                     |  392 +++
 lib/bits.c                                         |  280 ++
 lib/blastOut.c                                     |  830 +++++
 lib/blastParse.c                                   |  897 +++++
 lib/boxClump.c                                     |  312 ++
 lib/boxLump.c                                      |  159 +
 lib/bwgCreate.c                                    | 1114 +++++++
 lib/bwgQuery.c                                     |  400 +++
 lib/bwgValsOnChrom.c                               |  214 ++
 lib/cda.c                                          |  477 +++
 lib/chain.c                                        |  644 ++++
 lib/chainBlock.c                                   |  450 +++
 lib/chainConnect.c                                 |  366 +++
 lib/chainToAxt.c                                   |  121 +
 lib/chainToPsl.c                                   |  122 +
 lib/cheapcgi.c                                     | 2110 ++++++++++++
 lib/cirTree.c                                      |  558 ++++
 lib/codebias.c                                     |  147 +
 lib/colHash.c                                      |   48 +
 lib/colHash.h                                      |   38 +
 lib/common.c                                       | 3449 ++++++++++++++++++++
 lib/common.ps                                      |   97 +
 lib/common.pss                                     |   96 +
 lib/correlate.c                                    |   77 +
 lib/crTree.c                                       |  398 +++
 lib/dgRange.c                                      |  219 ++
 lib/diGraph.c                                      |  738 +++++
 lib/diGraph.c.97                                   |  764 +++++
 lib/diff                                           |    0
 lib/diffs                                          |  599 ++++
 lib/dlist.c                                        |  300 ++
 lib/dnaLoad.c                                      |  300 ++
 lib/dnaMarkov.c                                    |  239 ++
 lib/dnaMotif.c                                     |  628 ++++
 lib/dnaMotif.pss                                   |   61 +
 lib/dnaseq.c                                       |  181 +
 lib/dnautil.c                                      | 1124 +++++++
 lib/dsPrint.c                                      |  330 ++
 lib/dtdParse.c                                     |  466 +++
 lib/dystring.c                                     |  250 ++
 lib/emblParse.c                                    |  156 +
 lib/errCatch.c                                     |  123 +
 lib/errabort.c                                     |  326 ++
 lib/fa.c                                           |  648 ++++
 lib/ffAli.c                                        |  185 ++
 lib/ffScore.c                                      |  212 ++
 lib/filePath.c                                     |  130 +
 lib/fixColor.c                                     |   20 +
 lib/flydna.c                                       |  111 +
 lib/fof.c                                          |  580 ++++
 lib/font/README                                    |   23 +
 lib/font/mgCourier10.c                             |  299 ++
 lib/font/mgCourier12.c                             |  364 +++
 lib/font/mgCourier14.c                             |  734 +++++
 lib/font/mgCourier18.c                             |  875 +++++
 lib/font/mgCourier24.c                             | 1122 +++++++
 lib/font/mgCourier34.c                             | 2161 ++++++++++++
 lib/font/mgCourier8.c                              |  273 ++
 lib/font/mgHelvetica10.c                           |  335 ++
 lib/font/mgHelvetica12.c                           |  431 +++
 lib/font/mgHelvetica14.c                           |  527 +++
 lib/font/mgHelvetica18.c                           |  845 +++++
 lib/font/mgHelvetica24.c                           | 1245 +++++++
 lib/font/mgHelvetica34.c                           | 2228 +++++++++++++
 lib/font/mgHelvetica8.c                            |  278 ++
 lib/font/mgHelveticaBold10.c                       |  345 ++
 lib/font/mgHelveticaBold12.c                       |  424 +++
 lib/font/mgHelveticaBold14.c                       |  579 ++++
 lib/font/mgHelveticaBold18.c                       |  883 +++++
 lib/font/mgHelveticaBold24.c                       | 1277 ++++++++
 lib/font/mgHelveticaBold34.c                       | 2270 +++++++++++++
 lib/font/mgHelveticaBold8.c                        |  285 ++
 lib/font/mgMenlo12.c                               |  903 +++++
 lib/font/mgSail8.c                                 |  112 +
 lib/font/mgSixhi6.c                                |  210 ++
 lib/font/mgTimes10.c                               |  324 ++
 lib/font/mgTimes12.c                               |  424 +++
 lib/font/mgTimes14.c                               |  500 +++
 lib/font/mgTimes18.c                               |  764 +++++
 lib/font/mgTimes24.c                               | 1193 +++++++
 lib/font/mgTimes34.c                               | 1962 +++++++++++
 lib/font/mgTimes8.c                                |  256 ++
 lib/foo                                            |  287 ++
 lib/fuzzyShow.c                                    |  406 +++
 lib/gapCalc.c                                      |  351 ++
 lib/gdf.c                                          |  153 +
 lib/gemfont.c                                      |  200 ++
 lib/gemfont.h                                      |   69 +
 lib/genomeRangeTree.c                              |  185 ++
 lib/gfNet.c                                        |   21 +
 lib/gff.c                                          |  476 +++
 lib/gff3.c                                         | 1091 +++++++
 lib/gfxPoly.c                                      |   49 +
 lib/gifLabel.c                                     |  101 +
 lib/gifcodes.h                                     |   48 +
 lib/gifcomp.c                                      |  304 ++
 lib/gifdecomp.c                                    |  391 +++
 lib/gifread.c                                      |  186 ++
 lib/gifwrite.c                                     |   98 +
 lib/hacTree.c                                      |  276 ++
 lib/hash.c                                         |  717 ++++
 lib/histogram.c                                    |  267 ++
 lib/hmmPfamParse.c                                 |  191 ++
 lib/hmmstats.c                                     |   48 +
 lib/htmlPage.c                                     | 1820 +++++++++++
 lib/htmshell.c                                     |  668 ++++
 lib/https.c                                        |  385 +++
 lib/i386/placeHolder.c                             |    0
 lib/i686/placeHolder.c                             |    0
 lib/intExp.c                                       |  153 +
 lib/intValTree.c                                   |  102 +
 lib/internet.c                                     |  159 +
 lib/itsa.c                                         |  187 ++
 lib/iupac.c                                        |  213 ++
 lib/jointalign.c                                   |   74 +
 lib/jpegSize.c                                     |  136 +
 lib/keys.c                                         |  558 ++++
 lib/knetUdc.c                                      |   86 +
 lib/kxTok.c                                        |  239 ++
 lib/lineFileOnBigBed.c                             |  111 +
 lib/linefile.c                                     | 1396 ++++++++
 lib/localmem.c                                     |  162 +
 lib/log.c                                          |  343 ++
 lib/maf.c                                          |  888 +++++
 lib/maf.doc                                        |  222 ++
 lib/mafFromAxt.c                                   |   77 +
 lib/mafScore.c                                     |  152 +
 lib/makefile                                       |   61 +
 lib/md5.c                                          |  287 ++
 lib/memalloc.c                                     |  481 +++
 lib/memgfx.c                                       | 1187 +++++++
 lib/metaWig.c                                      |  185 ++
 lib/mgCircle.c                                     |   79 +
 lib/mgPolygon.c                                    |  436 +++
 lib/mime.c                                         |  687 ++++
 lib/net.c                                          | 2594 +++++++++++++++
 lib/nib.c                                          |  516 +++
 lib/nibTwo.c                                       |  122 +
 lib/nt4.c                                          |  260 ++
 lib/numObscure.c                                   |  103 +
 lib/obscure.c                                      |  737 +++++
 lib/oldGff.c                                       |  643 ++++
 lib/oligoTm.c                                      |  333 ++
 lib/options.c                                      |  423 +++
 lib/osunix.c                                       |  641 ++++
 lib/oswin9x.c                                      |   98 +
 lib/pairHmm.c                                      |  346 ++
 lib/peakCluster.c                                  |  244 ++
 lib/phyloTree.c                                    |  418 +++
 lib/pipeline.c                                     |  698 ++++
 lib/pngwrite.c                                     |  115 +
 lib/portimpl.c                                     |  136 +
 lib/portimpl.h                                     |   39 +
 lib/ppc/placeHolder.c                              |    0
 lib/psGfx.c                                        |  409 +++
 lib/psPoly.c                                       |   49 +
 lib/pscmGfx.c                                      |  816 +++++
 lib/psl.as                                         |   25 +
 lib/psl.c                                          | 2008 ++++++++++++
 lib/psl.sql                                        |   33 +
 lib/pslGenoShow.c                                  |  346 ++
 lib/pslShow.c                                      |  317 ++
 lib/pslTbl.c                                       |   86 +
 lib/pslTransMap.c                                  |  325 ++
 lib/pslWScore.as                                   |   26 +
 lib/pslWScore.sql                                  |   31 +
 lib/pthreadWrap.c                                  |  102 +
 lib/qa.c                                           |  219 ++
 lib/quickHeap.c                                    |  196 ++
 lib/quotedP.c                                      |  114 +
 lib/ra.c                                           |  400 +++
 lib/rainbow.c                                      |  151 +
 lib/rangeTree.c                                    |  333 ++
 lib/rbTree.c                                       |  740 +++++
 lib/regexHelper.c                                  |   88 +
 lib/repMask.c                                      |  170 +
 lib/rle.c                                          |  102 +
 lib/rnautil.c                                      |  220 ++
 lib/rqlEval.c                                      |  332 ++
 lib/rqlParse.c                                     |  764 +++++
 lib/rudp.c                                         |  560 ++++
 lib/scoreWindow.c                                  |   47 +
 lib/seg.c                                          |  472 +++
 lib/seqOut.c                                       |  330 ++
 lib/seqStats.c                                     |   36 +
 lib/servBrcMcw.c                                   |   47 +
 lib/servCrunx.c                                    |   51 +
 lib/servcis.c                                      |   48 +
 lib/servcl.c                                       |   49 +
 lib/servmsII.c                                     |   45 +
 lib/servpws.c                                      |   44 +
 lib/shaRes.c                                       |   80 +
 lib/slog.c                                         |   32 +
 lib/snof.c                                         |  293 ++
 lib/snofmake.c                                     |  228 ++
 lib/snofsig.c                                      |   24 +
 lib/spaceSaver.c                                   |  144 +
 lib/spacedColumn.c                                 |  134 +
 lib/spacedSeed.c                                   |   65 +
 lib/sparc/placeHolder.c                            |    0
 lib/splatAli.as                                    |   12 +
 lib/splatAli.c                                     |  234 ++
 lib/sqlList.c                                      | 1306 ++++++++
 lib/sqlNum.c                                       |  301 ++
 lib/status                                         |  482 +++
 lib/subText.c                                      |  153 +
 lib/sufa.c                                         |  142 +
 lib/sufx.c                                         |  146 +
 lib/synQueue.c                                     |  107 +
 lib/tabRow.c                                       |  229 ++
 lib/tests/dyStringTester.c                         |  101 +
 lib/tests/errCatchTest.c                           |   56 +
 lib/tests/expected/base64Decode.out                |    3 +
 lib/tests/expected/base64Encode.out                |    3 +
 lib/tests/expected/errCatch.bad                    |    3 +
 lib/tests/expected/errCatch.good                   |    3 +
 lib/tests/expected/gff3DiscontiousTest.out         |   31 +
 lib/tests/expected/gff3ErrorCasesTest.err          |    4 +
 lib/tests/expected/gff3SacCerTest.out              |   36 +
 lib/tests/expected/google.out                      |    6 +
 lib/tests/expected/hacTreeTest.out                 |  103 +
 lib/tests/expected/hashTest1.out                   |   62 +
 lib/tests/expected/htmlExpandUrlTest               |   48 +
 lib/tests/expected/htmlMime1.out                   |   13 +
 lib/tests/expected/mime1.out                       |   17 +
 lib/tests/expected/mime2.out                       |   35 +
 lib/tests/expected/mime3.out                       |   44 +
 lib/tests/expected/mime4.out                       |   53 +
 lib/tests/expected/mime5.out                       |   58 +
 lib/tests/expected/mimeAltHead.out                 |   61 +
 lib/tests/expected/mimeAutoBoundary.out            |   58 +
 lib/tests/expected/mimeBin.out                     |   36 +
 lib/tests/expected/mimeBlat.out                    |  121 +
 lib/tests/expected/noName1.html                    |  121 +
 lib/tests/expected/pipelineExecError.err           |    2 +
 lib/tests/expected/pipelineExecError.parent.err    |    2 +
 lib/tests/expected/pipelineWriteErr.out            |    1 +
 lib/tests/expected/quotedPDecode.out               |    3 +
 lib/tests/expected/quotedPEncode.out               |    4 +
 lib/tests/expected/simple1.wc                      |    1 +
 lib/tests/expected/tabixFetch1kGNoGenotypes.out    |    6 +
 lib/tests/expected/tabixFetch1kGWithGenotypes.out  |    7 +
 lib/tests/expected/vcfParse1kGNoGenotypes.out      |    7 +
 lib/tests/expected/vcfParse1kGWithGenotypes.out    |    8 +
 lib/tests/expected/vcfParseOldV3.out               |   44 +
 lib/tests/fetchUrlTest.c                           |   81 +
 lib/tests/gff3Tester.c                             |   31 +
 lib/tests/hacTreeTest.c                            |  260 ++
 lib/tests/htmlExpandUrlTest.c                      |  259 ++
 lib/tests/htmlMimeTest.c                           |   94 +
 lib/tests/htmlPageTest.c                           |   43 +
 ...ilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz |  Bin 0 -> 2806 bytes
 ...1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz.tbi |  Bin 0 -> 249 bytes
 ...I.low_coverage.2010_07_excerpt.genotypes.vcf.gz |  Bin 0 -> 82185 bytes
 ...w_coverage.2010_07_excerpt.genotypes.vcf.gz.tbi |  Bin 0 -> 327 bytes
 .../YRI.trio.2010_06.novelsequences.sites.vcf.gz   |  Bin 0 -> 3530 bytes
 ...RI.trio.2010_06.novelsequences.sites.vcf.gz.tbi |  Bin 0 -> 980 bytes
 lib/tests/input/discontinuous.gff3                 |   31 +
 lib/tests/input/errorCasesTest.gff3                |   28 +
 lib/tests/input/google.html                        |   13 +
 lib/tests/input/hacTreeTest.txt                    |   25 +
 lib/tests/input/hashTest1.txt                      |   24 +
 lib/tests/input/htmlMime.txt                       |   60 +
 lib/tests/input/mime1.txt                          |   12 +
 lib/tests/input/mime2.txt                          |   24 +
 lib/tests/input/mime3.txt                          |   30 +
 lib/tests/input/mime4.txt                          |   40 +
 lib/tests/input/mime5.txt                          |   39 +
 lib/tests/input/mimeAltHead.txt                    |   37 +
 lib/tests/input/mimeAutoBoundary.txt               |   37 +
 lib/tests/input/mimeBin.txt                        |  Bin 0 -> 536 bytes
 lib/tests/input/mimeBlat.txt                       |   97 +
 lib/tests/input/mimeDecodeTest.txt                 | 1391 ++++++++
 lib/tests/input/sacCerTest.gff3                    |   43 +
 lib/tests/input/simple1.txt                        |    6 +
 lib/tests/input/specialCasesTest.gff3              |   11 +
 lib/tests/makefile                                 |  309 ++
 lib/tests/mimeDecodeTest.c                         |  368 +++
 lib/tests/mimeTester.c                             |  317 ++
 lib/tests/miniBlat.c                               |   26 +
 lib/tests/pipelineTester.c                         |  274 ++
 lib/tests/safeTester.c                             |  174 +
 lib/tests/tabixFetch.c                             |  114 +
 lib/tests/testBase64.c                             |   44 +
 lib/tests/testHash.c                               |   81 +
 lib/tests/testQuotedP.c                            |   22 +
 lib/tests/testQuotedString.c                       |   57 +
 lib/tests/udcTest.c                                |  466 +++
 lib/tests/udcTrials.csh                            |   22 +
 lib/tests/vcfParseTest.c                           |   59 +
 lib/textOut.c                                      |  163 +
 lib/tokenizer.c                                    |  213 ++
 lib/trix.c                                         |  718 ++++
 lib/twoBit.c                                       | 1074 ++++++
 lib/udc.c                                          | 1596 +++++++++
 lib/vGfx.c                                         |   50 +
 lib/vGfxPrivate.h                                  |   44 +
 lib/vGif.c                                         |   63 +
 lib/vPng.c                                         |   65 +
 lib/valgrind.suppress                              |  106 +
 lib/vcf.c                                          |  954 ++++++
 lib/verbose.c                                      |  128 +
 lib/wildcmp.c                                      |  116 +
 lib/wormdna.c                                      | 1212 +++++++
 lib/x86_64/placeHolder.c                           |    0
 lib/xAli.as                                        |   27 +
 lib/xAli.c                                         |  280 ++
 lib/xAli.sql                                       |   33 +
 lib/xa.c                                           |  229 ++
 lib/xap.c                                          |  182 ++
 lib/xenshow.c                                      |   64 +
 lib/xmlEscape.c                                    |   79 +
 lib/xp.c                                           |  553 ++++
 lib/zlibFace.c                                     |   91 +
 makefile                                           |   18 +
 utils/faToNib/faToNib.c                            |   58 +
 utils/faToNib/makefile                             |   16 +
 utils/faToTwoBit/faToTwoBit.c                      |  127 +
 utils/faToTwoBit/makefile                          |   33 +
 utils/faToTwoBit/tests/expected/genbank.fa         |    4 +
 utils/faToTwoBit/tests/expected/noDna.fa           |    0
 utils/faToTwoBit/tests/expected/noDna.out          |    3 +
 utils/faToTwoBit/tests/input/genbank.fa            |    4 +
 utils/faToTwoBit/tests/input/noDna.fa              |    1 +
 utils/faToTwoBit/tests/input/testMask.fa           |   10 +
 utils/faToTwoBit/tests/input/testN.fa              |    4 +
 utils/nibFrag/makefile                             |   15 +
 utils/nibFrag/nibFrag.c                            |  107 +
 utils/twoBitInfo/makefile                          |   29 +
 utils/twoBitInfo/tests/expected/ml.info            |    1 +
 utils/twoBitInfo/tests/expected/ml_multiple.info   |    2 +
 utils/twoBitInfo/tests/expected/ml_sub.info        |    1 +
 utils/twoBitInfo/tests/expected/testMask.info      |    5 +
 utils/twoBitInfo/tests/expected/testN.info         |    2 +
 utils/twoBitInfo/twoBitInfo.c                      |   86 +
 utils/twoBitToFa/makefile                          |   37 +
 utils/twoBitToFa/tests/expected/ml_1_11.fa         |    2 +
 utils/twoBitToFa/tests/expected/ml_2_10.fa         |    2 +
 utils/twoBitToFa/tests/expected/ml_3_9.fa          |    2 +
 utils/twoBitToFa/tests/expected/ml_4_8.fa          |    2 +
 utils/twoBitToFa/tests/expected/ml_5_6.fa          |    2 +
 utils/twoBitToFa/tests/expected/ml_5_7.fa          |    2 +
 utils/twoBitToFa/tests/expected/ml_6_7.fa          |    2 +
 utils/twoBitToFa/tests/expected/ml_7_8.fa          |    2 +
 utils/twoBitToFa/tests/expected/ml_8_9.fa          |    2 +
 utils/twoBitToFa/tests/expected/spec_ml.fa         |    2 +
 utils/twoBitToFa/tests/expected/spec_ml_2_10.fa    |    2 +
 .../tests/expected/spec_ml_no_start_end.fa         |    6 +
 .../tests/expected/spec_ml_partial_list.fa         |    6 +
 utils/twoBitToFa/tests/expected/testMask.fa        |   10 +
 utils/twoBitToFa/tests/expected/testN.fa           |    4 +
 utils/twoBitToFa/tests/input/seqlist1              |    3 +
 utils/twoBitToFa/tests/input/seqlist2              |    3 +
 utils/twoBitToFa/tests/input/testMask.2bit         |  Bin 0 -> 236 bytes
 utils/twoBitToFa/tests/input/testN.2bit            |  Bin 0 -> 127 bytes
 utils/twoBitToFa/twoBitToFa.c                      |  201 ++
 webBlat/install.txt                                |  109 +
 webBlat/makefile                                   |   27 +
 webBlat/webBlat                                    |  Bin 0 -> 458744 bytes
 webBlat/webBlat.c                                  |  548 ++++
 webBlat/webBlat.cfg                                |   16 +
 690 files changed, 155792 insertions(+)

diff --git a/README b/README
new file mode 100644
index 0000000..a5f3d9e
--- /dev/null
+++ b/README
@@ -0,0 +1,38 @@
+CONTENTS AND COPYRIGHT
+
+This archive contains the entire source tree for BLAT and
+associated utilities.  All files are copyrighted, but license 
+is hereby granted for personal, academic, and non-profit use.  
+A license is also granted for the contents of the top level 
+lib and inc directories for commercial users.  Commercial 
+users should contact jim_kent at pacbell.net for access to other modules.
+
+INSTALL INSTRUCTIONS
+
+1. Unzip this to create a blatSrc directory.
+2. Check that the environment variable MACHTYPE
+   exists on your system.  It should on Unix.  
+   (And making this on non-Unix systems is beyond
+   the scope of this README).  For a Linux 
+   system MACHTYPE will probably be 'i386', for
+   and Alpha it will be 'alpha', for a Sun
+   probably 'sparc'.  If necessary set up
+   this environment variable.  Do this under the
+   bash shell as so:
+       MACHTYPE=something
+       export MACHTYPE
+   or under tcsh as so:
+       setenv MACHTYPE something
+3. Make the directory ~/bin/$MACHTYPE which is
+   where the (non-web) executables will go.
+   Add this directory to your path.
+4. Go to the lib directory.  If it doesn't
+   already exist do a mkdir $MACHTYPE.
+5. If you're on an alpha system do a:
+     setenv SOCKETLIB -lxnet
+   on Solaris do
+     setenv SOCKETLIB "-lsocket -lnsl"
+   on SunOS do
+     setenv SOCKETLIB "-lsocket -lnsl -lresolv"
+   on Linux you can skip this step.
+6. At the blatSrc directory type 'make'
diff --git a/blat/.cvsignore b/blat/.cvsignore
new file mode 100644
index 0000000..7643024
--- /dev/null
+++ b/blat/.cvsignore
@@ -0,0 +1 @@
+test*.psl
diff --git a/blat/blat.c b/blat/blat.c
new file mode 100644
index 0000000..0f8b171
--- /dev/null
+++ b/blat/blat.c
@@ -0,0 +1,754 @@
+/* blat - Standalone BLAT fast sequence search command line tool. */
+/* Copyright 2001-2004 Jim Kent.  All rights reserved. */
+#include "common.h"
+#include "memalloc.h"
+#include "linefile.h"
+#include "bits.h"
+#include "hash.h"
+#include "dnautil.h"
+#include "dnaseq.h"
+#include "fa.h"
+#include "nib.h"
+#include "twoBit.h"
+#include "psl.h"
+#include "sig.h"
+#include "options.h"
+#include "obscure.h"
+#include "genoFind.h"
+#include "trans3.h"
+#include "gfClientLib.h"
+
+
+/* Variables shared with other modules.  Set in this module, read only
+ * elsewhere. */
+char *databaseName;		/* File name of database. */
+int databaseSeqCount = 0;	/* Number of sequences in database. */
+unsigned long databaseLetters = 0;	/* Number of bases in database. */
+
+enum constants {
+    qWarnSize = 5000000, /* Warn if more than this many bases in one query. */
+    };
+
+/* Variables that can be set from command line. */
+int tileSize = 11;
+int stepSize = 0;	/* Default (same as tileSize) */
+int minMatch = 2;
+int minScore = 30;
+int maxGap = 2;
+int repMatch = 1024*4;
+int dotEvery = 0;
+boolean oneOff = FALSE;
+boolean noHead = FALSE;
+boolean trimA = FALSE;
+boolean trimHardA = FALSE;
+boolean trimT = FALSE;
+boolean fastMap = FALSE;
+char *makeOoc = NULL;
+char *ooc = NULL;
+enum gfType qType = gftDna;
+enum gfType tType = gftDna;
+char *mask = NULL;
+char *repeats = NULL;
+char *qMask = NULL;
+double minRepDivergence = 15;
+double minIdentity = 90;
+char *outputFormat = "psl";
+
+
+void usage()
+/* Explain usage and exit. */
+{
+printf(
+  "blat - Standalone BLAT v. %s fast sequence search command line tool\n"
+  "usage:\n"
+  "   blat database query [-ooc=11.ooc] output.psl\n"
+  "where:\n"
+  "   database and query are each either a .fa , .nib or .2bit file,\n"
+  "   or a list these files one file name per line.\n"
+  "   -ooc=11.ooc tells the program to load over-occurring 11-mers from\n"
+  "               and external file.  This will increase the speed\n"
+  "               by a factor of 40 in many cases, but is not required\n"
+  "   output.psl is where to put the output.\n"
+  "   Subranges of nib and .2bit files may specified using the syntax:\n"
+  "      /path/file.nib:seqid:start-end\n"
+  "   or\n"
+  "      /path/file.2bit:seqid:start-end\n"
+  "   or\n"
+  "      /path/file.nib:start-end\n"
+  "   With the second form, a sequence id of file:start-end will be used.\n"
+  "options:\n"
+  "   -t=type     Database type.  Type is one of:\n"
+  "                 dna - DNA sequence\n"
+  "                 prot - protein sequence\n"
+  "                 dnax - DNA sequence translated in six frames to protein\n"
+  "               The default is dna\n"
+  "   -q=type     Query type.  Type is one of:\n"
+  "                 dna - DNA sequence\n"
+  "                 rna - RNA sequence\n"
+  "                 prot - protein sequence\n"
+  "                 dnax - DNA sequence translated in six frames to protein\n"
+  "                 rnax - DNA sequence translated in three frames to protein\n"
+  "               The default is dna\n"
+  "   -prot       Synonymous with -t=prot -q=prot\n"
+  "   -ooc=N.ooc  Use overused tile file N.ooc.  N should correspond to \n"
+  "               the tileSize\n"
+  "   -tileSize=N sets the size of match that triggers an alignment.  \n"
+  "               Usually between 8 and 12\n"
+  "               Default is 11 for DNA and 5 for protein.\n"
+  "   -stepSize=N spacing between tiles. Default is tileSize.\n"
+  "   -oneOff=N   If set to 1 this allows one mismatch in tile and still\n"
+  "               triggers an alignments.  Default is 0.\n"
+  "   -minMatch=N sets the number of tile matches.  Usually set from 2 to 4\n"
+  "               Default is 2 for nucleotide, 1 for protein.\n"
+  "   -minScore=N sets minimum score.  This is the matches minus the \n"
+  "               mismatches minus some sort of gap penalty.  Default is 30\n"
+  "   -minIdentity=N Sets minimum sequence identity (in percent).  Default is\n"
+  "               90 for nucleotide searches, 25 for protein or translated\n"
+  "               protein searches.\n"
+  "   -maxGap=N   sets the size of maximum gap between tiles in a clump.  Usually\n"
+  "               set from 0 to 3.  Default is 2. Only relevent for minMatch > 1.\n"
+  "   -noHead     suppress .psl header (so it's just a tab-separated file)\n"
+  "   -makeOoc=N.ooc Make overused tile file. Target needs to be complete genome.\n"
+  "   -repMatch=N sets the number of repetitions of a tile allowed before\n"
+  "               it is marked as overused.  Typically this is 256 for tileSize\n"
+  "               12, 1024 for tile size 11, 4096 for tile size 10.\n"
+  "               Default is 1024.  Typically only comes into play with makeOoc.\n"
+  "               Also affected by stepSize. When stepSize is halved repMatch is\n"
+  "               doubled to compensate.\n"
+  "   -mask=type  Mask out repeats.  Alignments won't be started in masked region\n"
+  "               but may extend through it in nucleotide searches.  Masked areas\n"
+  "               are ignored entirely in protein or translated searches. Types are\n"
+  "                 lower - mask out lower cased sequence\n"
+  "                 upper - mask out upper cased sequence\n"
+  "                 out   - mask according to database.out RepeatMasker .out file\n"
+  "                 file.out - mask database according to RepeatMasker file.out\n"
+  "   -qMask=type Mask out repeats in query sequence.  Similar to -mask above but\n"
+  "               for query rather than target sequence.\n"
+  "   -repeats=type Type is same as mask types above.  Repeat bases will not be\n"
+  "               masked in any way, but matches in repeat areas will be reported\n"
+  "               separately from matches in other areas in the psl output.\n"
+  "   -minRepDivergence=NN - minimum percent divergence of repeats to allow \n"
+  "               them to be unmasked.  Default is 15.  Only relevant for \n"
+  "               masking using RepeatMasker .out files.\n"
+  "   -dots=N     Output dot every N sequences to show program's progress\n"
+  "   -trimT      Trim leading poly-T\n"
+  "   -noTrimA    Don't trim trailing poly-A\n"
+  "   -trimHardA  Remove poly-A tail from qSize as well as alignments in \n"
+  "               psl output\n"
+  "   -fastMap    Run for fast DNA/DNA remapping - not allowing introns, \n"
+  "               requiring high %%ID. Query sizes must not exceed %d.\n"
+  "   -out=type   Controls output file format.  Type is one of:\n"
+  "                   psl - Default.  Tab separated format, no sequence\n"
+  "                   pslx - Tab separated format with sequence\n"
+  "                   axt - blastz-associated axt format\n"
+  "                   maf - multiz-associated maf format\n"
+  "                   sim4 - similar to sim4 format\n"
+  "                   wublast - similar to wublast format\n"
+  "                   blast - similar to NCBI blast format\n"
+  "                   blast8- NCBI blast tabular format\n"
+  "                   blast9 - NCBI blast tabular format with comments\n"
+  "   -fine       For high quality mRNAs look harder for small initial and\n"
+  "               terminal exons.  Not recommended for ESTs\n"
+  "   -maxIntron=N  Sets maximum intron size. Default is %d\n"
+  "   -extendThroughN - Allows extension of alignment through large blocks of N's\n"
+  , gfVersion, MAXSINGLEPIECESIZE, ffIntronMaxDefault
+  );
+exit(-1);
+}
+
+
+struct optionSpec options[] = {
+   {"t", OPTION_STRING},
+   {"q", OPTION_STRING},
+   {"prot", OPTION_BOOLEAN},
+   {"ooc", OPTION_STRING},
+   {"tileSize", OPTION_INT},
+   {"stepSize", OPTION_INT},
+   {"oneOff", OPTION_INT},
+   {"minMatch", OPTION_INT},
+   {"minScore", OPTION_INT},
+   {"minIdentity", OPTION_FLOAT},
+   {"maxGap", OPTION_INT},
+   {"noHead", OPTION_BOOLEAN},
+   {"makeOoc", OPTION_STRING},
+   {"repMatch", OPTION_INT},
+   {"mask", OPTION_STRING},
+   {"qMask", OPTION_STRING},
+   {"repeats", OPTION_STRING},
+   {"minRepDivergence", OPTION_FLOAT},
+   {"dots", OPTION_INT},
+   {"trimT", OPTION_BOOLEAN},
+   {"noTrimA", OPTION_BOOLEAN},
+   {"trimHardA", OPTION_BOOLEAN},
+   {"fastMap", OPTION_BOOLEAN},
+   {"out", OPTION_STRING},
+   {"fine", OPTION_BOOLEAN},
+   {"maxIntron", OPTION_INT},
+   {"extendThroughN", OPTION_BOOLEAN},
+   {NULL, 0},
+};
+
+
+/* Stuff to support various output formats. */
+struct gfOutput *gvo;		/* Overall output controller */
+
+void searchOneStrand(struct dnaSeq *seq, struct genoFind *gf, FILE *psl, 
+	boolean isRc, struct hash *maskHash, Bits *qMaskBits)
+/* Search for seq in index, align it, and write results to psl. */
+{
+if (fastMap && (seq->size > MAXSINGLEPIECESIZE))
+    errAbort("Maximum single piece size (%d) exceeded by query %s of size (%d). "
+	"Larger pieces will have to be split up until no larger than this limit "
+	"when the -fastMap option is used."	
+	, MAXSINGLEPIECESIZE, seq->name, seq->size);
+gfLongDnaInMem(seq, gf, isRc, minScore, qMaskBits, gvo, fastMap, optionExists("fine"));
+}
+
+
+void searchOneProt(aaSeq *seq, struct genoFind *gf, FILE *f)
+/* Search for protein seq in index and write results to psl. */
+{
+int hitCount;
+struct lm *lm = lmInit(0);
+struct gfClump *clumpList = gfFindClumps(gf, seq, lm, &hitCount);
+gfAlignAaClumps(gf, clumpList, seq, FALSE, minScore, gvo);
+gfClumpFreeList(&clumpList);
+lmCleanup(&lm);
+}
+
+void dotOut()
+/* Put out a dot every now and then if user want's to. */
+{
+static int mod = 1;
+if (dotEvery > 0)
+    {
+    if (--mod <= 0)
+	{
+	fputc('.', stdout);
+	fflush(stdout);
+	mod = dotEvery;
+	}
+    }
+}
+
+void searchOne(bioSeq *seq, struct genoFind *gf, FILE *f, boolean isProt, struct hash *maskHash, Bits *qMaskBits)
+/* Search for seq on either strand in index. */
+{
+dotOut();
+if (isProt)
+    {
+    searchOneProt(seq, gf, f);
+    }
+else
+    {
+    gvo->maskHash = maskHash;
+    searchOneStrand(seq, gf, f, FALSE, maskHash, qMaskBits);
+    reverseComplement(seq->dna, seq->size);
+    searchOneStrand(seq, gf, f, TRUE, maskHash, qMaskBits);
+    reverseComplement(seq->dna, seq->size);
+    }
+gfOutputQuery(gvo, f);
+}
+
+void trimSeq(struct dnaSeq *seq, struct dnaSeq *trimmed)
+/* Copy seq to trimmed (shallow copy) and optionally trim
+ * off polyA tail or polyT head. */
+{
+DNA *dna = seq->dna;
+int size = seq->size;
+*trimmed = *seq;
+if (trimT)
+    maskHeadPolyT(dna, size);
+if (trimA || trimHardA)
+    {
+    int trimSize = maskTailPolyA(dna, size);
+    if (trimHardA)
+	{
+	trimmed->size -= trimSize;
+	dna[size-trimSize] = 0;
+	}
+    }
+}
+
+
+Bits *maskQuerySeq(struct dnaSeq *seq, boolean isProt, 
+	boolean maskQuery, boolean lcMask)
+/* Massage query sequence a bit, converting it to correct
+ * case (upper for protein/lower for DNA) and optionally
+ * returning upper/lower case info , and trimming poly A. */
+{
+Bits *qMaskBits = NULL;
+verbose(2, "%s\n", seq->name);
+if (isProt)
+    faToProtein(seq->dna, seq->size);
+else
+    {
+    if (maskQuery)
+	{
+	if (lcMask)
+	    toggleCase(seq->dna, seq->size);
+	qMaskBits = maskFromUpperCaseSeq(seq);
+	}
+    faToDna(seq->dna, seq->size);
+    }
+if (seq->size > qWarnSize)
+    {
+    warn("Query sequence %s has size %d, it might take a while.",
+	 seq->name, seq->size);
+    }
+return qMaskBits;
+}
+	    
+void searchOneMaskTrim(struct dnaSeq *seq, boolean isProt,
+		       struct genoFind *gf, FILE *outFile,
+		       struct hash *maskHash,
+		       long long *retTotalSize, int *retCount)
+/* Search a single sequence against a single genoFind index. */
+{
+boolean maskQuery = (qMask != NULL);
+boolean lcMask = (qMask != NULL && sameWord(qMask, "lower"));
+Bits *qMaskBits = maskQuerySeq(seq, isProt, maskQuery, lcMask);
+struct dnaSeq trimmedSeq;
+ZeroVar(&trimmedSeq);
+trimSeq(seq, &trimmedSeq);
+if (qType == gftRna || qType == gftRnaX)
+   memSwapChar(trimmedSeq.dna, trimmedSeq.size, 'u', 't');
+searchOne(&trimmedSeq, gf, outFile, isProt, maskHash, qMaskBits);
+*retTotalSize += seq->size;
+*retCount += 1;
+bitFree(&qMaskBits);
+}
+
+void searchOneIndex(int fileCount, char *files[], struct genoFind *gf, char *outName, 
+	boolean isProt, struct hash *maskHash, FILE *outFile, boolean showStatus)
+/* Search all sequences in all files against single genoFind index. */
+{
+int i;
+char *fileName;
+int count = 0; 
+long long totalSize = 0;
+
+gfOutputHead(gvo, outFile);
+for (i=0; i<fileCount; ++i)
+    {
+    fileName = files[i];
+    if (nibIsFile(fileName))
+        {
+	struct dnaSeq *seq;
+
+	if (isProt)
+	    errAbort("%s: Can't use .nib files with -prot or d=prot option\n", fileName);
+	seq = nibLoadAllMasked(NIB_MASK_MIXED, fileName);
+	freez(&seq->name);
+	seq->name = cloneString(fileName);
+	searchOneMaskTrim(seq, isProt, gf, outFile,
+			  maskHash, &totalSize, &count);
+	freeDnaSeq(&seq);
+	}
+    else if (twoBitIsSpec(fileName))
+	{
+	struct twoBitSpec *tbs = twoBitSpecNew(fileName);
+	struct twoBitFile *tbf = twoBitOpen(tbs->fileName);
+	if (isProt)
+	    errAbort("%s is a two bit file, which doesn't work for proteins.", 
+	    	fileName);
+	if (tbs->seqs != NULL)
+	    {
+	    struct twoBitSeqSpec *ss = NULL;
+	    for (ss = tbs->seqs;  ss != NULL;  ss = ss->next)
+		{
+		struct dnaSeq *seq = twoBitReadSeqFrag(tbf, ss->name,
+						       ss->start, ss->end);
+		searchOneMaskTrim(seq, isProt, gf, outFile,
+				  maskHash, &totalSize, &count);
+		dnaSeqFree(&seq);
+		}
+	    }
+	else
+	    {
+	    struct twoBitIndex *index = NULL;
+	    for (index = tbf->indexList; index != NULL; index = index->next)
+		{
+		struct dnaSeq *seq = twoBitReadSeqFrag(tbf, index->name, 0, 0);
+		searchOneMaskTrim(seq, isProt, gf, outFile,
+				  maskHash, &totalSize, &count);
+		dnaSeqFree(&seq);
+		}
+	    }
+	twoBitClose(&tbf);
+	}
+    else
+        {
+	static struct dnaSeq seq;
+	struct lineFile *lf = lineFileOpen(fileName, TRUE);
+	while (faMixedSpeedReadNext(lf, &seq.dna, &seq.size, &seq.name))
+	    {
+	    searchOneMaskTrim(&seq, isProt, gf, outFile,
+			      maskHash, &totalSize, &count);
+	    }
+	lineFileClose(&lf);
+	}
+    }
+carefulClose(&outFile);
+if (showStatus)
+    printf("Searched %lld bases in %d sequences\n", totalSize, count);
+}
+
+struct trans3 *seqListToTrans3List(struct dnaSeq *seqList, aaSeq *transLists[3], struct hash **retHash)
+/* Convert sequence list to a trans3 list and lists for each of three frames. */
+{
+int frame;
+struct dnaSeq *seq;
+struct trans3 *t3List = NULL, *t3;
+struct hash *hash = newHash(0);
+
+for (seq = seqList; seq != NULL; seq = seq->next)
+    {
+    t3 = trans3New(seq);
+    hashAddUnique(hash, t3->name, t3);
+    slAddHead(&t3List, t3);
+    for (frame = 0; frame < 3; ++frame)
+        {
+	slAddHead(&transLists[frame], t3->trans[frame]);
+	}
+    }
+slReverse(&t3List);
+for (frame = 0; frame < 3; ++frame)
+    {
+    slReverse(&transLists[frame]);
+    }
+*retHash = hash;
+return t3List;
+}
+
+void tripleSearch(aaSeq *qSeq, struct genoFind *gfs[3], struct hash *t3Hash, boolean dbIsRc, FILE *f)
+/* Look for qSeq in indices for three frames.  Then do rest of alignment. */
+{
+gvo->reportTargetStrand = TRUE;
+gfFindAlignAaTrans(gfs, qSeq, t3Hash, dbIsRc, minScore, gvo);
+}
+
+void transTripleSearch(struct dnaSeq *qSeq, struct genoFind *gfs[3], struct hash *t3Hash, 
+	boolean dbIsRc, boolean qIsDna, FILE *f)
+/* Translate qSeq three ways and look for each in three frames of index. */
+{
+int qIsRc;
+gvo->reportTargetStrand = TRUE;
+for (qIsRc = 0; qIsRc <= qIsDna; qIsRc += 1)
+    {
+    gfLongTransTransInMem(qSeq, gfs, t3Hash, qIsRc, dbIsRc, !qIsDna, minScore, gvo);
+    if (qIsDna)
+        reverseComplement(qSeq->dna, qSeq->size);
+    }
+}
+
+void bigBlat(struct dnaSeq *untransList, int queryCount, char *queryFiles[], char *outFile, boolean transQuery, boolean qIsDna, FILE *out, boolean showStatus)
+/* Run query against translated DNA database (3 frames on each strand). */
+{
+int frame, i;
+struct dnaSeq *seq, trimmedSeq;
+struct genoFind *gfs[3];
+aaSeq *dbSeqLists[3];
+struct trans3 *t3List = NULL;
+int isRc;
+struct lineFile *lf = NULL;
+struct hash *t3Hash = NULL;
+boolean forceUpper = FALSE;
+boolean forceLower = FALSE;
+boolean toggle = FALSE;
+boolean maskUpper = FALSE;
+
+ZeroVar(&trimmedSeq);
+if (showStatus)
+    printf("Blatx %d sequences in database, %d files in query\n", slCount(untransList), queryCount);
+
+/* Figure out how to manage query case.  Proteins want to be in
+ * upper case, generally, nucleotides in lower case.  But there
+ * may be repeatMasking based on case as well. */
+if (transQuery)
+    {
+    if (qMask == NULL)
+       forceLower = TRUE;
+    else
+       {
+       maskUpper = TRUE;
+       toggle = !sameString(qMask, "upper");
+       }
+    }
+else
+    {
+    forceUpper = TRUE;
+    }
+
+if (gvo->fileHead != NULL)
+    gvo->fileHead(gvo, out);
+
+for (isRc = FALSE; isRc <= 1; ++isRc)
+    {
+    /* Initialize local pointer arrays to NULL to prevent surprises. */
+    for (frame = 0; frame < 3; ++frame)
+	{
+	gfs[frame] = NULL;
+	dbSeqLists[frame] = NULL;
+	}
+
+    t3List = seqListToTrans3List(untransList, dbSeqLists, &t3Hash);
+    for (frame = 0; frame < 3; ++frame)
+	{
+	gfs[frame] = gfIndexSeq(dbSeqLists[frame], minMatch, maxGap, tileSize, 
+		repMatch, ooc, TRUE, oneOff, FALSE, stepSize);
+	}
+
+    for (i=0; i<queryCount; ++i)
+        {
+	aaSeq qSeq;
+
+	lf = lineFileOpen(queryFiles[i], TRUE);
+	while (faMixedSpeedReadNext(lf, &qSeq.dna, &qSeq.size, &qSeq.name))
+	    {
+	    dotOut();
+	    /* Put it into right case and optionally mask on case. */
+	    if (forceLower)
+	        toLowerN(qSeq.dna, qSeq.size);
+	    else if (forceUpper)
+	        toUpperN(qSeq.dna, qSeq.size);
+	    else if (maskUpper)
+	        {
+		if (toggle)
+		    toggleCase(qSeq.dna, qSeq.size);
+		upperToN(qSeq.dna, qSeq.size);
+		}
+	    if (qSeq.size > qWarnSize)
+	        {
+		warn("Query sequence %s has size %d, it might take a while.",
+		     qSeq.name, qSeq.size);
+		}
+	    trimSeq(&qSeq, &trimmedSeq);
+	    if (transQuery)
+	        transTripleSearch(&trimmedSeq, gfs, t3Hash, isRc, qIsDna, out);
+	    else
+		tripleSearch(&trimmedSeq, gfs, t3Hash, isRc, out);
+	    gfOutputQuery(gvo, out);
+	    }
+	lineFileClose(&lf);
+	}
+
+    /* Clean up time. */
+    trans3FreeList(&t3List);
+    freeHash(&t3Hash);
+    for (frame = 0; frame < 3; ++frame)
+	{
+	genoFindFree(&gfs[frame]);
+	}
+
+    for (seq = untransList; seq != NULL; seq = seq->next)
+        {
+	reverseComplement(seq->dna, seq->size);
+	}
+    }
+carefulClose(&out);
+}
+
+
+void blat(char *dbFile, char *queryFile, char *outName)
+/* blat - Standalone BLAT fast sequence search command line tool. */
+{
+char **dbFiles, **queryFiles;
+int dbCount, queryCount;
+struct dnaSeq *dbSeqList, *seq;
+struct genoFind *gf;
+boolean tIsProt = (tType == gftProt);
+boolean qIsProt = (qType == gftProt);
+boolean bothSimpleNuc = (tType == gftDna && (qType == gftDna || qType == gftRna));
+boolean bothSimpleProt = (tIsProt && qIsProt);
+FILE *f = mustOpen(outName, "w");
+boolean showStatus = (f != stdout);
+
+databaseName = dbFile;
+gfClientFileArray(dbFile, &dbFiles, &dbCount);
+if (makeOoc != NULL)
+    {
+    gfMakeOoc(makeOoc, dbFiles, dbCount, tileSize, repMatch, tType);
+    if (showStatus)
+	printf("Done making %s\n", makeOoc);
+    exit(0);
+    }
+gfClientFileArray(queryFile, &queryFiles, &queryCount);
+dbSeqList = gfClientSeqList(dbCount, dbFiles, tIsProt, tType == gftDnaX, repeats, 
+	minRepDivergence, showStatus);
+databaseSeqCount = slCount(dbSeqList);
+for (seq = dbSeqList; seq != NULL; seq = seq->next)
+    databaseLetters += seq->size;
+
+gvo = gfOutputAny(outputFormat, minIdentity*10, qIsProt, tIsProt, noHead, 
+	databaseName, databaseSeqCount, databaseLetters, minIdentity, f);
+
+if (bothSimpleNuc || bothSimpleProt)
+    {
+    struct hash *maskHash = NULL;
+
+    /* Save away masking info for output. */
+    if (repeats != NULL)
+	{
+	maskHash = newHash(0);
+	for (seq = dbSeqList; seq != NULL; seq = seq->next)
+	    {
+	    Bits *maskedBits = maskFromUpperCaseSeq(seq);
+	    hashAdd(maskHash, seq->name, maskedBits);
+	    }
+	}
+
+    /* Handle masking and indexing.  If masking is off, we want the indexer
+     * to see unmasked sequence, otherwise we want it to see masked.  However
+     * after indexing we always want it unmasked, because things are always
+     * unmasked for the extension phase. */
+    if (mask == NULL && !bothSimpleProt)
+        gfClientUnmask(dbSeqList);
+    gf = gfIndexSeq(dbSeqList, minMatch, maxGap, tileSize, repMatch, ooc, 
+    	tIsProt, oneOff, FALSE, stepSize);
+    if (mask != NULL)
+        gfClientUnmask(dbSeqList);
+
+    searchOneIndex(queryCount, queryFiles, gf, outName, tIsProt, maskHash, f, showStatus);
+    freeHash(&maskHash);
+    }
+else if (tType == gftDnaX && qType == gftProt)
+    {
+    bigBlat(dbSeqList, queryCount, queryFiles, outName, FALSE, TRUE, f, showStatus);
+    }
+else if (tType == gftDnaX && (qType == gftDnaX || qType == gftRnaX))
+    {
+    bigBlat(dbSeqList, queryCount, queryFiles, outName, TRUE, qType == gftDnaX, f, showStatus);
+    }
+else
+    {
+    errAbort("Unrecognized combination of target and query types\n");
+    }
+if (dotEvery > 0)
+    printf("\n");
+freeDnaSeqList(&dbSeqList);
+}
+
+int main(int argc, char *argv[])
+/* Process command line into global variables and call blat. */
+{
+boolean tIsProtLike, qIsProtLike;
+
+#ifdef DEBUG
+{
+char *cmd = "blat hCrea.geno hCrea.mrna foo.psl -t=dnax -q=rnax";
+char *words[16];
+
+printf("Debugging parameters\n");
+cmd = cloneString(cmd);
+argc = chopLine(cmd, words);
+argv = words;
+}
+#endif /* DEBUG */
+
+optionInit(&argc, argv, options);
+if (argc != 4)
+    usage();
+
+/* Get database and query sequence types and make sure they are
+ * legal and compatable. */
+if (optionExists("prot"))
+    qType = tType = gftProt;
+if (optionExists("t"))
+    tType = gfTypeFromName(optionVal("t", NULL));
+trimA = optionExists("trimA") || optionExists("trima");
+trimT = optionExists("trimT") || optionExists("trimt");
+trimHardA = optionExists("trimHardA");
+switch (tType)
+    {
+    case gftProt:
+    case gftDnaX:
+        tIsProtLike = TRUE;
+	break;
+    case gftDna:
+        tIsProtLike = FALSE;
+	break;
+    default:
+	tIsProtLike = FALSE;
+        errAbort("Illegal value for 't' parameter");
+	break;
+    }
+if (optionExists("q"))
+    qType = gfTypeFromName(optionVal("q", NULL));
+if (qType == gftRnaX || qType == gftRna)
+    trimA = TRUE;
+if (optionExists("noTrimA"))
+    trimA = FALSE;
+switch (qType)
+    {
+    case gftProt:
+    case gftDnaX:
+    case gftRnaX:
+	minIdentity = 25;
+        qIsProtLike = TRUE;
+	break;
+    default:
+        qIsProtLike = FALSE;
+	break;
+    }
+if ((tIsProtLike ^ qIsProtLike) != 0)
+    errAbort("t and q must both be either protein or dna");
+
+/* Set default tile size for protein-based comparisons. */
+if (tIsProtLike)
+    {
+    tileSize = 5;
+    minMatch = 1;
+    oneOff = FALSE;
+    maxGap = 0;
+    }
+
+/* Get tile size and related parameters from user and make sure
+ * they are within range. */
+tileSize = optionInt("tileSize", tileSize);
+stepSize = optionInt("stepSize", tileSize);
+minMatch = optionInt("minMatch", minMatch);
+oneOff = optionExists("oneOff");
+fastMap = optionExists("fastMap");
+minScore = optionInt("minScore", minScore);
+maxGap = optionInt("maxGap", maxGap);
+minRepDivergence = optionFloat("minRepDivergence", minRepDivergence);
+minIdentity = optionFloat("minIdentity", minIdentity);
+gfCheckTileSize(tileSize, tIsProtLike);
+if (minMatch < 0)
+    errAbort("minMatch must be at least 1");
+if (maxGap > 100)
+    errAbort("maxGap must be less than 100");
+
+
+
+/* Set repMatch parameter from command line, or
+ * to reasonable value that depends on tile size. */
+if (optionExists("repMatch"))
+    repMatch = optionInt("repMatch", repMatch);
+else
+    repMatch = gfDefaultRepMatch(tileSize, stepSize, tIsProtLike);
+
+/* Gather last few command line options. */
+noHead = optionExists("noHead");
+ooc = optionVal("ooc", NULL);
+makeOoc = optionVal("makeOoc", NULL);
+mask = optionVal("mask", NULL);
+qMask = optionVal("qMask", NULL);
+repeats = optionVal("repeats", NULL);
+if (repeats != NULL && mask != NULL && differentString(repeats, mask))
+    errAbort("The -mask and -repeat settings disagree.  "
+             "You can just omit -repeat if -mask is on");
+if (mask != NULL)	/* Mask setting will also set repeats. */
+    repeats = mask;
+outputFormat = optionVal("out", outputFormat);
+dotEvery = optionInt("dots", 0);
+/* set global for fuzzy find functions */
+setFfIntronMax(optionInt("maxIntron", ffIntronMaxDefault));
+setFfExtendThroughN(optionExists("extendThroughN"));
+
+
+/* Call routine that does the work. */
+blat(argv[1], argv[2], argv[3]);
+return 0;
+}
diff --git a/blat/hCrea.geno b/blat/hCrea.geno
new file mode 100644
index 0000000..edc0255
--- /dev/null
+++ b/blat/hCrea.geno
@@ -0,0 +1,100 @@
+>hCreaGeno
+CATGCCACATCCCCGGGGCGGGAGGGGGCTACATCCCCGGCTTTAGACGCGCGAGTCTCAGGTCCCGCTA
+ATTACCTGGCGGGTGCTGCCCACCCCTGCCCTCGCGCACCTAGCGCGTGGCAGCGGGAAGGCGGGGCCTG
+GGGGAGCCCCACCCCTGGAGACTGCGGCTGGGGCCTCCCTCTCCTCCGCCCGCCCGCCTGCCACTAGCTC
+ATTGCGCCTCTCCTGCAGTCTGATTGGGCACCGGCTCCCATTCCGGCTCCAGCCTCCAATCCGACCCCCA
+TTTCGGCTGCAGCCTCGGACCTAGCTCCGGCCCTCGGTCTATCCGGTTGCATCCTCCCTCCCTGTTCCGG
+ATCTTATCTTGCGCCAGCGCCTACTCCAGGATCCCGTAGCCAGACCTCAAGCCATGGCTGGTCCCTTCTC
+CCGTCTGCTGTCCGCCCGCCCGGGACTCAGGCTCCTGGCTTTGGCCGGAGCGGGGTCTCTAGCCGCTGGG
+TTTCTGCTCCGACCGGAACCTGTACGAGCTGCCAGTGAACGACGGAGGCTGTATCCCCCGAGGTAACAGT
+GCCTGAGGCGCGGGAGGAGGCGGGGGCAGGAGGTGATGGGAACGAAGGTGCGGGTAGAAGTGAGAATCCG
+GGCAACAGAGAAGGGCTATAATCACGAAGGCCCTGGAGCTGGAGGGCTGTGCAGTCTGCAGACCTCAGTG
+GGGTGGGGGTGGGGGCCAAAACCATAAAGCAAGAACATTCCTGGGGACCTGCCAAGACCAGCTCTGGCCC
+TACGAGTTCTAGCTGCACTGGCTGCCCAAATCCCTAATTGTAAAGCCAGGAACTATCCTTTTCGCTCCCC
+TCCATCTCCTTCCCTCATTTCCTCAATTCCTCTCCTTAGGCTTTTCCCCTCCTCCATCCGTAGTGTTGTG
+TCATGGGAGGAAAGAACTGAGCAGATCTGAAGAAACTGAGCTGGCCAGCCAGAGGCAACTAGAACTATTA
+GGAAAGCATAGACTCTGAAAGTCCCTAAAGAGATTACCAAGGTTTACCCTCTTTCTAATTCCCCTCCTCC
+CGCGGAGCAAAGCCAGACATGGCCAACTGGACAGCTCCCAGGTAACTGCACTAGGTCTAGGCGTCTGTGA
+CCCTCCCTCCATGGTTACTGGGTACCCCCTCCCCAGCGCTGAGTACCCAGACCTCCGAAAGCACAACAAC
+TGCATGGCCAGTCACCTGACCCCAGCAGTCTATGCACGGCTCTGCGACAAGACCACACCCACTGGTTGGA
+CGCTAGATCAGTGTATCCAGACTGGCGTGGACAACCCTGGCCACCCCTTCATCAAGACTGTGGGCATGGT
+GGCTGGAGATGAGGAGACCTATGAGGTAGGGGGTCCCCAGAGTCTCCCTGATGATCCAATTCATCTTCCC
+AGTAATCCCAGCTCCTTTCCCTTAAAGACCTCTCACTTTCCCCCAAGACTCTGAGCCCCCCATACTTAAG
+TTTTCTGAACCAGTGAAATCAATGCACAATTGAAGTCTGGGGAGGGATTCCCTCTCCTTAACCATCTCTC
+CCTCTTAACTCCCCTTAGGTATTTGCTGACCTGTTTGACCCTGTGATCCAAGAGCGACACAATGGATATG
+ACCCCCGGACAATGAAGCACACCACGGATCTAGATGCCAGTAAAGTGAGTTCAAATATCCCACTTCTGAT
+TTGCATTGCCTGTGTACAACACTCTGTATCTCCAACCCCTTCACCTTATTTCCTGACTCATGGTCATTAT
+ACTGCTGAGCTTTTAATCTTAATGTAAGGAAAGAATCATATCTTAAGGGGCAGCATATATGGAGATGGAA
+GGATAGATAAGAATGACCATGACCCAAGGTGGGTGGTTTGGGGACGGGTCTGCAATGCCCCCTTCAATTC
+CAGTGCTTTCCCAAAGGGCCTCTTCTTCCAATGCATGCAGGAAGAATGCACACAGAGTCCTCTAATGCCT
+AAGGAAGGTCTCTCCTTTCCCAGGGGCCCTCAGTTCCCACCGTGTTTCTGTGACTTACATTCATTTCCCT
+TATCTCCCAGATCCGTTCTGGCTACTTTGATGAGAGGTATGTATTGTCCTCTAGAGTCAGAACTGGCCGA
+AGCATCCGAGGACTCAGTCTGCCTCCAGCTTGCACTCGAGCAGAGCGACGAGAGGTGGAACGTGTTGTGG
+TGGATGCACTGAGTGGCCTGAAGGGTGACCTGGCTGGACGTTACTATAGGCTCAGTGAGATGACAGAGGC
+TGAACAGCAGCAGCTTATTGATGTGAGGGCCTTAAGAGGGTGCTGGTTGGTGGGAGCAGATGGGGAAGGC
+TGGGCCAGATGAGACATGGGCTCTGAAAGGCCCAGGGGCCACCATGAAGATTCTTAACCCAAGTCCCGTT
+ACTCTTCCCAGGACCACTTTCTGTTTGATAAGCCTGTGTCCCCGTTGCTGACTGCAGCAGGAATGGCTCG
+AGACTGGCCAGATGCTCGTGGAATTTGGTATGAAGCTGCTCATTACCTCTTTTGTCTTCATGCCCTCATA
+AATGCTTTTTTTCCCTCTATCTCTCCCAATTCTTGCCTTGCCTCTTGATCACTGTCCCTCTCCGGCCCTC
+AGGCACAACAATGAGAAGAGCTTCCTGATCTGGGTGAATGAGGAGGATCATACACGGGTGATCTCCATGG
+AGAAGGGTGGTAACATGAAGAGAGTGTTTGAAAGATTCTGCCGAGGCCTCAAAGAGGTTAGAGAAGACTA
+TGTAGGGGAGCTAGGTGGGAGGACATAAGGAAAACCAAAGAGTAGCATAAATAGATTATGTAATTTACCA
+ACCAACCCAGGACATGTCTTATAGTAAAAAGGACTATCTAGGACTCACTCCAGGACTAAAGGTGTAAACC
+AGCTGGGACCATACTGGGAAAACCAGGACATGTGGTCACACTAAGATTAGGAAAAGAAAGAGTGTCAGGA
+ATCTTAGGAAGTGAACAAGGCTTTTGACAGAGAGTGCAAAGAAGGAATAAATGAGATGGCACGTCAGTGC
+CTGGGATGTGTGCAGTGGGATGGTGAGGTGTGCAGATAAGGAAAACATTCGAGCTTAGATTGATGTTGGC
+GGGGAGAGGTTGCTGTGTTCATGACTCTAATATAACCACCCAGTTCTGAGACAAGGTAGGCCTTGACTCT
+GGATTCTATCATTCTTGTTAAAGTTTCGGGTCTAGGCTTTAAGTTGAGAGTTCGGAGAGAGACTGGGGAA
+GGTGGAGGATAGAATGGTTCGAGTTCTAGAATATGTGGCTCTAGATGAGAGGTTGAACTGAATCATCAAT
+CCTACATGGATTGGGTCTCCGTATTCAAGTCTACATTAGAAATCCCCATAAACTCAATTCAATTCTTACT
+GTATGTTCTCAAACATACAGTTCTATTTTAGGTTTGCAAAGAAAAAGAGCTCCTCTTTTAGATTCTGAGA
+AGTTTCTACTATTTTTGGCAAGTAATAGATAACATATTCTGACTATGAGTGGGtagggaagtacctttaa
+attatatgcctcagtttcctcatctgtaaaattgggataatgagattttctacattttaggttgttgtgg
+ggattaagtgaaatacaggtaaagtacttggtccacagtaagtgcttaataagtgttaaagtgttagctg
+caatattattCTGGATGGAAGAGTTTCCCCCCATGTTCAGCATGTAAGATATCCCCTATGGCATGGTTCC
+TTCTGAACTATAAAGAGGATCCCTTTACTCATGTTGGGTTGTGGTCTTTGTGACCATCATTCTGCTAGAT
+CCCTTGTCTCTTGAACTCTAATAGTCATCTTCATGACTACATGGTTAAGTGAAGCCAAACGCCTTCCCCC
+CGCCCCCTATTCCTATGAATCTGGCTTTTCTGCTCTGTTTTCATCTTTCTCTGCATTCACACAGGTGCTC
+CGTTCACAGCTAACAGAATGTTATCTTACCTCTTCCTGGCAAAGCTTACACCTTCATCTTCTGTCTGAAG
+GGACCCTTCTAAGCTCTAGGCTCATTAGCAAAGCAAAGATAATCGATGCATGCAGACCTCATTGAATAAT
+CAGTCATCTCTCAGTTCAGTTTACCACCTCTGTTCATTTCCCTAGATCATCCTTAATACACCACTCCTTC
+GAGTTTTCTTCTTCCACATAAGATATTTTTTCACAATCTCATTATTATGCACATCATAATTTTGCATCAT
+GCATGCATGAAAACAATAACAAACCTTTTTCATTTAAAAAAAGACCAATGTCATTCATTCACAGCCAAGT
+TTCTGTTCTAGACATATTTCTAGTGTTCTTGTGGGTCTAGCTAAGGGAGGGTCCAGGGTTAATGAAATAT
+CCCTGATTTTTCGTTAACAAAACCTTTGTGGACTCAGGTGGAGAGACTTATCCAAGAACGTGGCTGGGAG
+TTCATGTGGAATGAGCGTTTGGGATACATCTTGACCTGTCCATCTAACCTGGGCACTGGACTTCGGGCAG
+GAGTGCACATCAAACTGCCCCTGCTAAGCAAAGTAAAGGAGTTGTGGGGTTACAGAGGGGTGTGAGTAAG
+GAAGGGTGGGTTGTGGATGGGGAGGGAGTGGACCCTTTGGAAAGGAGCCAAACATGTTGTGGCTAAAGGG
+TCAGAGGACAggccaggcacagtggctcatgcctctaatcccaacacttgggaggccaaggcaggcagat
+tacttgagcccaggagttcaagaccagcctgggcaacctggtgaaaccccatctctacctacaaatacaa
+aagttagctgggtgtagtggaggctgaggtgagaggatcacttaagcctgggaagtcgaggcttcagtga
+gctgtgatcactccagcctgggtgacagagagagaccctgtctaaaaaaaattaaaaaagaaaaaagaaa
+aaaGGAAAAAAAAAGTTCAGGAGACAGAGCTCTGAGCAGGTTCAGGGCTCTTTCAGGTAGGACCTAGTCT
+CTGCCTCTATTGACCCTGCTCCCAATCCCTATCTCCTCTCTAGGATAGCCGCTTCCCAAAGATCCTGGAG
+AACCTAAGACTCCAAAAACGTGGTACTGGAGGAGTGGACACTGCTGCTACAGGCGGTGTCTTTGATATTT
+CTAATTTGGACCGACTAGGCAAATCAGAGGTGAGATCCTAAGGGATTAGGACAAGGAGAGGTATAGGTCT
+GCGAGGGCCGAAATATGGCAGTGAGTGAGCCTCCGGGATGTAACATAATCTGAAATGAAATTCAGGTTGA
+GTGGGAGGCAATTGGAAATGAGCAGGCAAGTCAGTCAGTGATAAAGAAAAACTCAGACTGTAGGAAGCAG
+ATCAAAGATTAGTGTCCCTTAGGTGGAGCTGGTGCAACTGGTCATCGATGGAGTAAACTATTTGATTGAT
+TGTGAACGGCGTCTGGAGAGAGGCCAGGATATCCGCATCCCCACACCTGTCATCCACACCAAGCATTAAC
+TCCCCATCGCCAGCTGATGACTCAAGATTCCCAGGAGTTTTGCTCATTCTAATGATGGCCCATTCTACTT
+GCTCTGGACCTGCCCCCGCATCCCCTGCCTCCATCCTAGTAAAGACTCCTTGCTATGCTGCAGCTGTCTG
+TGTTACTTCTAATGGTGGGGTGAGGAGGGAGCAGCCTTCAGGAAATGAAAAGAGGCAGTGGGATTATTTA
+TGATGGAAAGAGACTCCAGATATGGCAACCCAGGAACACTGATTCTCAGGTGGGTGGAAAGCATTAACAT
+TTTACCCATATTCCTCATCAGCTTCTGAAAATAATCAGGATGCACTTCTGTTTGCACTTTATTCATTATG
+ACTTAAGATTTCTCTCCCCACAATCTCCTTCTACTGTAGAGACAGGCTCATAGCAGGTGGCCAAGGAAGC
+TGATAGTCAATACCAGGGACCAGGAAGGTCGTGACCAGTCCTGGAGGCCCCAGGCTGTACTTCGACCTAT
+AATAGACAGGGAATGGGAGTAATATCACAACTCAGCTCTCCAGGAGCATTGATACTTGGAAATTAGCGCT
+CTGCCTGTAGACTCCTTCACTCCAGGGATCTCCCTGGGTGCACTCTAAGAGCCAGACAGCACCAAATTAG
+GGGTTTGATTCTGGGTCAGGAGATGGAGGATCAAGCTGTGCAGCTGGGAACTCACCTTGCTGTTCTGGGC
+TCTCCTTTCCCTCATGTTGGGCCCATGCAACTGCTCGTCGCTGCTCAGGACTCAGAAAGGCCATTTGCTC
+AGGAGTGACAGCCACAGCCTGAGCACTGGTGAGACTAGATAGTTGGATGGGACTAAACACCACCTGAGGG
+CAGGGGTAGGAATCAGTGCATGCATGTAGTCCCCATTGGGCCCTGGCTCTCCTGTGGTCACCCCAGTCCA
+TTAATACTTACAGCAAATTTAGGAGGAGGGATGACAGAAATGGCAAGAGGAGTAACGCCCTGGATCTGTC
+CCCGCAGCAGTGCTGAAAGAGCCAGGTCTGGGATCCCAGCTGTTGAAGCAAGTGGCATCCAAACATTGTC
+TTAGACTGACCTTCCCTCTCTTCAAACCTATAGACCTTCTCTAACTACTCCCAAAGTGCCCTATCATAGA
+CCTTCCCCAATATGTCTCTAGCCCCTTATTTAAACACCCTCAGGCCCCCACCTTAAGAATTGCAGGGCAG
+TCTTCCATCCAGTCCACCCATGGTATAGAAACCAAACCAACTTGCACCAGCAGTGGCCCAGCTCCCCACC
+TGCTATGGTGCCAATTTCAGTGAAGATCTCAGGCCCCCAGTTACTGATTGGGCCAAACCCACCAGGCAGT
+ACAAGTAGGTGGGCCAGAACCTCCAGTTGTTCCTCAGAGCACTGCAGATGCAGGGTGCCGAGGAAGAGAG
+CTGCTTGGCTGTAGAACAGTGGGAAGGAAGGAAGAA
diff --git a/blat/hCrea.mrna b/blat/hCrea.mrna
new file mode 100644
index 0000000..739a6b8
--- /dev/null
+++ b/blat/hCrea.mrna
@@ -0,0 +1,23 @@
+>hCreaMrna
+CCGGCTCCCATTCCGGCTCCAGCCTCCAATCCGACCCCCATTTCGGCTGCAGCCTCGGACCTAGCTCCGG
+CCCTCGGTCTATCCGGTTGCATCCTCCCTCCCTGTTCCGGATCTTATCTTGCGCCAGCGCCTACTCCAGG
+ATCCCGTAGCCAGACCTCAAGCCATGGCTGGTCCCTTCTCCCGTCTGCTGTCCGCCCGCCCGGGACTCAG
+GCTCCTGGCTTTGGCCGGAGCGGGGTCTCTAGCCGCTGGGTTTCTGCTCCGACCGGAACCTGTACGAGCT
+GCCAGTGAACGACGGAGGCTGTATCCCCCGAGCGCTGAGTACCCAGACCTCCGAAAGCACAACAACTGCA
+TGGCCAGTCACCTGACCCCAGCAGTCTATGCACGGCTCTGCGACAAGACCACACCCACTGGTTGGACGCT
+AGATCAGTGTATCCAGACTGGCGTGGACAACCCTGGCCACCCCTTCATCAAGACTGTGGGCATGGTGGCT
+GGAGATGAGGAGACCTATGAGGTATTTGCTGACCTGTTTGACCCTGTGATCCAAGAGCGACACAATGGAT
+ATGACCCCCGGACAATGAAGCACACCACGGATCTAGATGCCAGTAAAATCCGTTCTGGCTACTTTGATGA
+GAGGTATGTATTGTCCTCTAGAGTCAGAACTGGCCGAAGCATCCGAGGACTCAGTCTGCCTCCAGCTTGC
+ACTCGAGCAGAGCGACGAGAGGTGGAACGTGTTGTGGTGGATGCACTGAGTGGCCTGAAGGGTGACCTGG
+CTGGACGTTACTATAGGCTCAGTGAGATGACAGAGGCTGAACAGCAGCAGCTTATTGATGACCACTTTCT
+GTTTGATAAGCCTGTGTCCCCGTTGCTGACTGCAGCAGGAATGGCTCGAGACTGGCCAGATGCTCGTGGA
+ATTTGGCACAACAATGAGAAGAGCTTCCTGATCTGGGTGAATGAGGAGGATCATACACGGGTGATCTCCA
+TGGAGAAGGGTGGTAACATGAAGAGAGTGTTTGAAAGATTCTGCCGAGGCCTCAAAGAGGTGGAGAGACT
+TATCCAAGAACGTGGCTGGGAGTTCATGTGGAATGAGCGTTTGGGATACATCTTGACCTGTCCATCTAAC
+CTGGGCACTGGACTTCGGGCAGGAGTGCACATCAAACTGCCCCTGCTAAGCAAAGATAGCCGCTTCCCAA
+AGATCCTGGAGAACCTAAGACTCCAAAAACGTGGTACTGGAGGAGTGGACACTGCTGCTACAGGCGGTGT
+CTTTGATATTTCTAATTTGGACCGACTAGGCAAATCAGAGGTGGAGCTGGTGCAACTGGTCATCGATGGA
+GTAAACTATTTGATTGATTGTGAACGGCGTCTGGAGAGAGGCCAGGATATCCGCATCCCCACACCTGTCA
+TCCACACCAAGCATTAACTCCCCATCGCCAGCTGATGACTCAAGATTCCCAGGAGTTTTGCTCATTCTAA
+TGATGGCCCATTCTACTTGCTCTGGACCTGCCCCCGCATCCCCTGCCTCCATCCTAGTAAAAAAAAAAAA
diff --git a/blat/hCrea.pep b/blat/hCrea.pep
new file mode 100644
index 0000000..3cc44d1
--- /dev/null
+++ b/blat/hCrea.pep
@@ -0,0 +1,7 @@
+>hCreaPep
+MAGPFSRLLSARPGLRLLALAGAGSLAAGFLLRPEPVRAASERRRLYPPSAEYPDLRKHNNCMASHLTPA
+VYARLCDKTTPTGWTLDQCIQTGVDNPGHPFIKTVGMVAGDEETYEVFADLFDPVIQERHNGYDPRTMKH
+TTDLDASKIRSGYFDERYVLSSRVRTGRSIRGLSLPPACTRAERREVERVVVDALSGLKGDLAGRYYRLS
+EMTEAEQQQLIDDHFLFDKPVSPLLTAAGMARDWPDARGIWHNNEKSFLIWVNEEDHTRVISMEKGGNMK
+RVFERFCRGLKEVERLIQERGWEFMWNERLGYILTCPSNLGTGLRAGVHIKLPLLSKDSRFPKILENLRL
+QKRGTGGVDTAATGGVFDISNLDRLGKSEVELVQLVIDGVNYLIDCERRLERGQDIRIPTPVIHTKH
diff --git a/blat/mCrea.geno b/blat/mCrea.geno
new file mode 100644
index 0000000..093abe5
--- /dev/null
+++ b/blat/mCrea.geno
@@ -0,0 +1,114 @@
+>mCreatGeno
+GAATTCATCAAGGGATAAATCCATTAATTAGAGTAGAGCCCTTTTGAGCTTTTTGCAATAGCTGGTAATT
+AACCAAACCCCAATACATGAGCCAGTAAAGAACATTTCTTATCGAAAAAGAATTGATGATACTGATGATA
+TGAAAGCTTATTTACGCATATGTTACTGTTGACCTTGAATCTTCATTTAGGAGTTTGAGTGCCCCCATTT
+GTTCTCTATAATTTTGGGAACCTAGGAATTGTCCTAGTTAGATGCCTCATCTTACTGAAACCTCTGCCCC
+AGGCTTCCTGAATTGATAGAGATAGATTCTAAGAGCAGAATCTACAAAGAATCAGTGATAGTTAGGGCTC
+AGACTCATTCCTCTTCTACCACTCCAACCCTGGGAGCGAGTAATTACCGCAGCTCCCAGCTGTAAACAGC
+CTCCAGCGACCCCACTGGCATACTGAGCCTCACAAAGAATTTAAAAAGTGCACAAATCGATGAGCCCTCT
+TGGAAGAGCTATTGTTTCCCATAGGAAGGCATTTNCCAAATTTGAATGACTTCTCTGTACCCTGGCTGCC
+TTTACTTCTTCTGTTAGCCTCTCTTCCCACACCCCACTCCTGAACACCTTCTCAGCCAAATAATAGCCCA
+ATTGCTCTCGAAGACTATCTCCTCCTTTTATCTGGGTAAATATCNCCATCCCAAGTAATTATATCACTTA
+CTCATACCTCNCCTTACCTGGATATGAACACCCACAGCACAGGTAACATTTTTTTTCCCTCTCCAAAAAT
+AAGGAAGTTCCACCAGTAGATCTCTATCTTGGAAAATGTGTTATGTTACCAAGAGAAGAGGCTTAAGTAA
+TGGAGCCAAAAGTGAAATGGATTCTTTCTAAGGATACNCACCAATGAGAAAGGTCAGAAAGGAGACATAT
+GGGGTGGGGACTTGAGGGAAATAATTAATGTATATAGTTGGGCCAGTGGGGATTATGAAGGGTAATTCTT
+TTTCCCAAGTACTTTCTTACAACTTCCAAATATCTTACTGTCTTCTGGAACATCAGGAAGCTGAAGGTAG
+ACATATTAANNNCAATATGTCTGCTTTTGCTTTGGCTGGCCCTCCGCACCCAAACCTCAGGTCTCTATCT
+CAGCTTCAGCTTTCATTCCCCTTCCCAATATGTCTGCTTTGCTTTGGCTGGCCCTCCGCACCCAAACCTC
+AGGTCTCTATCTCAGCTTCAGCTTTCATTCCCCTTCCTGCACTAATAAAAGTCAAGTTGCTCCTAGCCCA
+GCACGTAGCTGTGGAAACAAACCCTCTTGAGTCTGAGTATGCACTTCGCAAAAGAGAGAGCGGACCAGGA
+AGAAGACAGAGACTCCCTGATGACCTTATGCCCTTGGATACTACCAGCCTTCACACTCCAGTTTAAACTG
+CCTTAGCAAGCCAAGAGAGGAAGCACGAGTGGTTCGGGAGACCTGTGCCTGCCTGTTCCATTCCACACCC
+AGTCATCTCACCAGACCCTCCTCCTCTCTTTATATTCCCCCTCCAGTCCTAGGAACTGCCAGCTGCAGAG
+AAGAAGGAAGAGAAGGAAGAAGAAACTCACCATTCCCTGCCCAACCCCAGCCCCACACCCAGAGCAATCA
+ACAGGTAGGCTTTCAGACACTACTCAGGAAGAGTCCTTCGAACAGCAAACAGATTTAAGCCTGGAAAAGA
+AGAAGAGAAATAAAAGATCAAAGGTGAAGCAGGGGTTAGAGTAGAGGAAAAAAAGAAAAAAAAAGCAGGT
+CCCCAATGAGAGGCAGGAAATAGCCAAGCTGAAGACTTGGAGGCAGTGAGTTTGGGAGACAGGATTCTTA
+AGGGATCCTTTCTCGACCTTATTAGGAAAGCATAGGTGTAGCTGGAGTTCCCTGGTGCTTCCTGGTTCTT
+AGGGAAGGTGACTTGAGGCTGTGCTGTCTTTCCCCTGAGCTCGCTCAGTCTTCCTCCTCTATCTGTTTAT
+TCTGTGGTTTTCCTGCGGCTGACTCTCCTGGGGAAAATGGAGAGATGGCGTGCAGATCGAATTCAATTCA
+GAAAAGAGGCTGGGCAATGTCAACCTCCCCACCCCCACCCCCAAAACCCAGAAATAGACGGATTGGTTTC
+AGATTTAAACAGAGAGGGTATGAAAGAAGGGGGGTTTCAGGTTCGGGAATCCCCGTGGTGCTGTCCTCTA
+CTTAGTGCTGAAATCTGACACCCTCATCCTTGGTGGGCGTCTGTCTCCAGCCTCAGGGAGTAAATCTCCA
+GTCTTCTTAATTACCTGGCTAGTGCTACCCAACCCCACCCCCGCACACCTAGCGCGGTGGCAGGCGGGAA
+GGCGGAGCCTGAGTGAGCCCCACCCCTGGAGACTGCGGCTGGGGCCTCCCTCTGCTCTGGCTGGCTCCTT
+GCTTCGCTGCGCTTCTCCTGCAGCCTGGTAGGCACCGGCTGCCACTTCAGCTTCAGCCTTCATCGTGACC
+CCTATTTTGGCTCCAGTCTCCGACCCAGCTCCGTCCTCTCTCTACCCGGTTGCATCTTCCCTCCTAGTTC
+CTGACTTGCACCAGATCCTGCTCTGAATCTTTGTAGCCGCATCCCCAAGCCATGGCTGGTCCCTTCTCCC
+GTCTGCTGTCTGCCCGCCCTGGACTCAGGCTCCTGGCTTTGGCTGGAGCTGGGTCTCTCACCGCCGGGAT
+TCTGCTCCGCCCGGAATCTGTAGGAGCTGCCGCTGCTGAACGGAGGAGACTGTATCCCCCGAGGTATTAG
+AGCCTGAGATGCACGAGGTGGGGGCTGGGGGTGGTAGTGGTGGTGATGGGAACCGAACAGGTAGAGAGGA
+TAACCTGAGCAAAAGATAGGCCTCGAAGATGGATTTCCTGTACAGTTTGGAGATCCTAGCCCTGTAATGG
+AAGAACATGTCTAAGGACATGTCACCCGATGTCACTGCCTCCACACCAGCTTTACCTTTGCAAATTCTAG
+GTTCACCCACTGCCCAAATCCTTTTTGGATGACTAGAAGCTTTTTTTTTTTTTTTTTTTTTTTAATCTCG
+ACCTATTCTCCTTGTTCTCCCGAATTCTCCTGAGTCTCTCCCCTCCCCCATCTCTAATGTTATGCTCACT
+AGAGAAAAGCAACTCTGTAGACAAGGGGGAATTGAGGTGTTAGAACTATTAGGAAAGAAAAGACCCTGGA
+AATCCCTGAAGAGATTATCAAGATTTAGCCTACCTCTAATTCCCCCTCCTTCCAATAAGCAAAGCCAGAC
+ATGGCTCACTGGACAGCTCCCAGCTGACATCAGTAGGTCTAGGCTCCTGTGCCCTCCCTCCATGGTTACT
+GGGTACCCCCTTCCCAGCGCTGAGTACCCAGACCTCCGAAAGCACAACAACTGCATGGCCAGTCACCTGA
+CCCCAGCAGTCTATGCACGGCTCTGCGACAAGACCACACCCACTGGTTGGACACTAGATCAGTGCATCCA
+GACTGGAGTGGACAACCCTGGCCACCCCTTCATCAAGACTGTGGGCATGGTGGCTGGAGATGAGGAGACC
+TATGAGGTAGGGGGCCCCTCAGAAATCCCAGTTCCTTCCTCCTAAAGATCCCTCATGTCTGTTCCCTCAA
+GACTCTGGATTGTCTATACTCAAACGTTCTGATCCAGTGATATCAATCTACAACTCAAGTGTTTCTTCTT
+TATAATCGCCTCTTCCTCTTAACTCCTTTTCAGGTATTTGCTGAACTGTTTGACCCTGTGATCCAAGAGC
+GGCATAATGGATATGACCCCAGAACAATGAAGCACACCACTGACCTTGATGCCAGTAAAGTGAGCCAAAT
+GTGACACTTCCGATATGTGCAGCCTTGTGCACAATGTTCTGTATCTCCAATCATTACACCTTGTTTCCTG
+ACTCAGGGTTAGACTGCTGAGCTTTGTATATTGATAAGAGAAAGAATTGCATATCTTGAAGTATAGCAGA
+TAGGAGGACGTAGTGGATAAGAGTCTGGATAATGGAGTTGAGGAGAATCTGATCAAAGTACAAAATGGTG
+AAAGAATTTTTAAGAAGTGACTATGTCCTGGCTGGGTGTGGTGGCTCACACCTGTAATCTCAGCTCTCAG
+ACGGCTCAGAAGAGCACTCCTCCCTCCACCAAAAAAAAAAAAAAAAAGGCTGTACCCAAAGTGAGAAATG
+TGGAGAAATGACCACAGTGTTTTCAGTTAGCATGCCTGTCCAATGTGTCTTCCTTCTGGCACCTGCTTTA
+TAATCCCCAAGAGTTCCCACCTGCTGTGTTTCTATGATTTATAGTCATTTCTCTTATTCCTCAGATTCGT
+TCTGGCTACTTTGATGAGAGGTATGTATTGTCTTCAAGAGTCAGAACTGGCCGAAGTATCAGGGGACTCA
+GTCTCCCTCCAGCCTGCACTCGGGCAGAGCGAAGAGAGGTAGAACGTGTTGTGGTGGATGCTCTGAGTGG
+CCTGAAGGGTGACCTGGCTGGACGGTACTATAGGCTCAGTGAGATGACGGAGGCCGAACAGCAGCAGCTT
+ATTGATGTGAGGGCCTTGACAGGGAACGGGATTGTGGAAAAAGAGGTGGAGGGGAGAGTGGACCAGAAAA
+GGTAGATGGCCTGGATGGTACTGTGAGAATTCTTAGACCCAATCCCTTTATTCTCCTCAGGACCATTTTC
+TGTTTGATAAACCTGTGTCCCCATTGCTGACTGCAGCAGGAATGGCTCGAGACTGGCCTGATGCTCGAGG
+GATCTGGTATGGAGCCAACACACTTTTTTGGTTTTTTTTTTCCCCCTTGTATGTGCAAAGTTTTTTCTCC
+ATCTACCCCAGTGCTTGTCTTGCCCACTGATGGCTATACCTATCCTGCCCTCAGGCACAACAATGAGAAG
+AGTTTCTTGATCTGGGTGAATGAGGAGGACCACACACGGGTCATCTCTATGGAGAAAGGCGGCAACATGA
+AGAGAGTGTTTGAAAGATTCTGCCGGGGCCTCAAAGAGGTTGGAGAAGGGTATACCAGGGAGCTAGGGGA
+GAGGAAATGAGAAATACCACACAGCAGCATAGCTAGATCGGCTATATCACTTGTCAGTCAACCCAGAGTA
+TTTCTGATAGTAGAAAGGGTCATTATCATGCTAGGATAATAGTTACAAACCAGGGCCGTCCTTGGNAAAC
+CAGGGCATATAGTTACTCTAAAAATAGAAAGAGTGTCAGTAACCTAAGGAAGGAAATAAAGCATAATCTT
+TGCCAAGTAATGAAAAGAAGGAACCAATGATCAGCAAGCCAGTGCCGGGGTAGGTGGTATGAGGTAGTAT
+GTGCAGTTAAGGAGAACGTTTGAGCCTGGACTGATGGAAGGCGTGAGAGATTGGTTTGTTCATGATACAT
+CACCAAGTTCTGANCAAGGCTCACCTTGGCTCTGGAGATCTGATCCTTGATGTATTTTCTTGTATCTACA
+GTTTTATTTTTGGACTTGTAAAGAAAGGGTGCTTCTCTTTTAGATTCTAGCCAGGAAGCTCACACTATTT
+TCGGCAAGGAATGGATAATGTTCTATGAGTAGCATAGAGAAATACTCTTTAATTATATGACTCTGTTTAT
+TTGTCTATAAAGTTGAGGACTAAATGAAATAATGTAGGCAGAGGAATTGTTCTATAATAAGTGTTAGCTT
+TACGATGTAAAAATCTCCATGCTTGTGATTCCTTCTGAGTTACAGAGCATCATCTTTAGGTAGTGTGGTC
+TTTGTGTCTATTGCTCTGGCAGGCCCCTGTCTCTTCCATCCTAATAGTCATTATGGTGGTCAGGAAAGCA
+AGAACATCTCTTGAAGTCCCCCTCTTCTCACATGTACCTGTGAATCTGGCTTCTCTGCTGTACCTTCTCA
+TGTCTCCCTGCTCTATTATCCATGTTCCTTTTATAGCTAAGAGTAGGCTCTCCTGCCTTAGCACCTCGTT
+TCTGTCCAAAGGGACCCTTTGTCAAAGATGTAATTGATGCATGAGAACTCCCTGTCCTGTTTACTACTTC
+TATTCATTTCCCAAGTCACTCTTAATGTATCATTCTCCAAAGCTTCTTCTACGAACAATCTATCTGCCAC
+AATCTTATCAGCATGCATATAATGCAACATCCAAGTGTCCTTCCATGTGCAATGACAATAAGTTTTAACA
+ACAACAAAGAGCATGTCATTCATCGATCGTCAAGTTTCTCGTTGTAGACATAGTTCTAGAATGTCTGTGG
+GGCTAAGAGGGATCCCTCCCTCCCTGATTTTTCACAACAGAACCTCTGTTGACACAGGTGGAGAAGCTGA
+TCCAGGAACGAGGCTGGGAGTTCATGTGGAATGAGCGTTTAGGCTACATCTTGACCTGTCCATCTAACCT
+GGGCACTGGACTTCGGGCAGGAGTCCACATCAAACTGCCACTGCTGAGCAAAGTAAAGGATATGTGGGGC
+TAGAGGGGGTGTAAGAAGGGGGACTTGGAAGGGGGTGGAGGAGACACTCTAAAAAGAGCCAGTCCTAAGG
+GCTTATGGCTAGTGGGCCAAGGGTAGGAGCAGTCTCAGAAACTATTGACATGCCCCTGATCTTTACCTTG
+CATCTAGGATAACCGCTTCCCAAAGATCCTGGAGAACCTAAGACTGCAAAAGCGTGGAACTGGAGGAGTG
+GACACTGCTGCTACAGGCAGCGTCTTTGACATCTCTAATTTGGATCGACTTGGCAAGTCAGAGGTGAGGT
+CTTATGAATCAGGTTAAGAGGTTGAGATAAGGCAGTGAGTGAGCCTCAGGAACATAATAGAATCTGAAGC
+AATGGTCAGGTTGAGTGGGGTAGGGAAGAGAAAACGAGTTTTCAGAGATGGAAGAGCTAAAGAAACTCAG
+GTCAGGCAAGGTGGTCTGTGCTTTTAATACCAGCAGAAGCAAGACAGATCTCTGTGAGTCTCAGGCCAGC
+CAGGGCTACATAATGAGATCCTGTCACAAAAACTGAAAAAAGAAAAAGAAGGAAAAGAAGGAAGGAGGGA
+AGGAAGGAAGGGAGAGAGAGAGAGAGGGAGGGAGAGAGAGGAAGAGAGAGAGATTAAGAGAAGCTCGGGT
+ACACCGGGAAGCAGGGATCAAGGACTGTGTTCTTCAGGTGGAGCTGGTGCAGCTCGTCATCGATGGGGTG
+AACTATTTGATTGACTGTGAACGGCGTCTGGAGAGAGGACAGGATATTCGAATCCCTCCACCTCTTGTCC
+ACAGCAAACATTAACTCCCCATCCCCAGCGGATGAGTCAAGACCCCCAGGACTTCTGCATATTTAACAGT
+GGCCCAGTCTACTTGCCCTGGACCTGCCTCTCTCCCTGTCCTAGTAAAGACTCCACATTATGTTGCAGCT
+GTCTGTGTTATTTCTATTGGTGTGGTGAGGAGGAAGTAGGAAATGAAAAGAAACAGTGAGGTTATTCATG
+ATGGCAAGAGGCGTATATGCCAGGAGCACAGTTCTCAGGTGGGTGGAATGCATTGGAATTTTACCCACAA
+TCCTCATCCACTTACTGAGAATAATTAGTATGCACTTCCATTTACAAGTTGTTCAGTATGATGTAAATTT
+TCTCCCTCAACTGAAGGAACAGTTATCATAATAGGTGGCCAAAAAAAATGCTGACGGGGCAATGCCAGGG
+CCCAGGAGGCTTGGAACCAGTCGTAGAGACCCCAGGCTGAGTTTCGACCTAGAATGAGACAAGGAATGGG
+AGGAAAAAAAATCACAGTTCCGTTCCCCAGGAGCCTTTGATGTTTCAAATTTAGCTCTGTGTATAGATCC
+CTCTACTCCAGAGATTCTCCTGTGTGGGGTCTGAGGACCAGACAGCACCAAGTTAGGACTTAGATGGACT
+CTGGGTCAGATGACAGCTTATCAAACTATGCAGTTGGTAACGTACCCAGCTGCTCTGGGATCTCCTTCCC
+TTCGTGTTGGGCCC
diff --git a/blat/mCrea.mrna b/blat/mCrea.mrna
new file mode 100644
index 0000000..62047c2
--- /dev/null
+++ b/blat/mCrea.mrna
@@ -0,0 +1,24 @@
+>mCreaMrna
+TGCTCTGGCTGGCTCCTTGCTTCGCTGCGCTTCTCCTGCAGCCTGGTAGGCACCGGCTGCCACTTCAGCT
+tcagccttcatcgtgacccctattttggctccagtctccgacccagctccgtcctctctctacccggttg
+CATCTTCCCTCCTAGTTCCTGACTTGCACCAGATCCTGCTCTGAATCTTTGTAGCCGCATCCCCAAGCCA
+tggctggtcccttctcccgtctgctgtctgcccgccctggactcaggctcctggctttggctggagctgg
+GTCTCTCACCGCCGGGATTCTGCTCCGCCCGGAATCTGTAGGAGCTGCCGCTGCTGAACGGAGGAGACTG
+tatcccccgagcgctgagtacccagacctccgaaagcacaacaactgcatggccagtcacctgaccccag
+CAGTCTATGCACGGCTCTGCGACAAGACCACACCCACTGGTTGGACACTAGATCAGTGCATCCAGACTGG
+agtggacaaccctggccaccccttcatcaagactgtgggcatggtggctggagatgaggagacctatgag
+GTATTTGCTGAACTGTTTGACCCTGTGATCCAAGAGCGGCATAATGGATATGACCCCAGAACAATGAAGC
+acaccactgaccttgatgccagtaaaattcgttctggctactttgatgagaggtatgtattgtcttcaag
+AGTCAGAACTGGCCGAAGTATCAGGGGACTCAGTCTCCCTCCAGCCTGCACTCGGGCAGAGCGAAGAGAG
+gtagaacgtgttgtggtggatgctctgagtggcctgaagggtgacctggctggacggtactataggctca
+GTGAGATGACGGAGGCCGAACAGCAGCAGCTTATTGATGACCATTTTCTGTTTGATAAACCTGTGTCCCC
+attgctgactgcagcaggaatggctcgagactggcctgatgctcgagggatctggcacaacaatgagaag
+AGTTTCTTGATCTGGGTGAATGAGGAGGACCACACACGGGTCATCTCTATGGAGAAAGGCGGCAACATGA
+agagagtgtttgaaagattctgccggggcctcaaagaggtggagaagctgatccaggaacgaggctggga
+GTTCATGTGGAATGAGCGTTTAGGCTACATCTTGACCTGTCCATCTAACCTGGGCACTGGACTTCGGGCA
+ggagtccacatcaaactgccactgctgagcaaagataaccgcttcccaaagatcctggagaacctaagac
+TGCAAAAGCGTGGAACTGGAGGAGTGGACACTGCTGCTACAGGCAGCGTCTTTGACATCTCTAATTTGGA
+tcgacttggcaagtcagaggtggagctggtgcagctcgtcatcgatggggtgaactatttgattgactgt
+GAACGGCGTCTGGAGAGAGGACAGGATATTCGAATCCCTCCACCTCTTGTCCACAGCAAACATTAACTCC
+ccatccccagcggatgagtcaagacccccaggacttctgcatatttaacagtggcccagtctacttgccc
+TGGACCTGCCTCTCTCCCTGTCCTAGTAAAGACTCCACATTATGTTGCAaaaaaaaaaaaaaaaaa
diff --git a/blat/mCrea.pep b/blat/mCrea.pep
new file mode 100644
index 0000000..2cc2ab4
--- /dev/null
+++ b/blat/mCrea.pep
@@ -0,0 +1,7 @@
+>mCreaPep
+MAGPFSRLLSARPGLRLLALAGAGSLTAGILLRPESVGAAAAERRRLYPPSAEYPDLRKHNNCMASHLTP
+AVYARLCDKTTPTGWTLDQCIQTGVDNPGHPFIKTVGMVAGDEETYEVFAELFDPVIQERHNGYDPRTMK
+HTTDLDASKIRSGYFDERYVLSSRVRTGRSIRGLSLPPACTRAERREVERVVVDALSGLKGDLAGRYYRL
+SEMTEAEQQQLIDDHFLFDKPVSPLLTAAGMARDWPDARGIWHNNEKSFLIWVNEEDHTRVISMEKGGNM
+KRVFERFCRGLKEVEKLIQERGWEFMWNERLGYILTCPSNLGTGLRAGVHIKLPLLSKDNRFPKILENLR
+LQKRGTGGVDTAATGSVFDISNLDRLGKSEVELVQLVIDGVNYLIDCERRLERGQDIRIPPPLVHSKH
diff --git a/blat/makefile b/blat/makefile
new file mode 100644
index 0000000..be9a2da
--- /dev/null
+++ b/blat/makefile
@@ -0,0 +1,34 @@
+include ../inc/common.mk
+
+L += -lm $(SOCKETLIB)
+MYLIBDIR = ../lib/$(MACHTYPE)
+MYLIBS =  $(MYLIBDIR)/jkOwnLib.a $(MYLIBDIR)/jkweb.a 
+
+O = blat.o
+
+blat: $O $(MYLIBS)
+	${CC} ${COPT} ${CFLAGS} -o ${DESTDIR}${BINDIR}/blat $O $(MYLIBS) $L
+	${STRIP} ${DESTDIR}${BINDIR}/blat${EXE}
+
+all:
+	cd ../lib && ${MAKE}
+	make
+tags:
+	ctags *.c *.h ../lib/*.c ../inc/*.h
+
+test::
+	blat -verbose=0 hCrea.geno hCrea.mrna testRna.psl
+	cmp testRna.psl refRna.psl
+	blat -verbose=0 -prot hCrea.pep mCrea.pep testProt.psl
+	cmp testProt.psl refProt.psl
+	blat -verbose=0 -t=dnax -q=prot hCrea.geno mCrea.pep testProtX.psl
+	cmp testProtX.psl refProtX.psl
+	blat -verbose=0 -t=dnax -q=rnax hCrea.geno mCrea.mrna testRnaX.psl
+	cmp testRnaX.psl refRnaX.psl
+	blat -verbose=0 -fine hCrea.geno hCrea.mrna testFine.psl
+	cmp testFine.psl refFine.psl
+	cd test && ${MAKE}
+
+clean::
+	rm -f testRna.psl testProt.psl testProtX.psl testRnaX.psl \
+	testFine.psl $(O) blat
diff --git a/blat/refFine.psl b/blat/refFine.psl
new file mode 100644
index 0000000..14970c3
--- /dev/null
+++ b/blat/refFine.psl
@@ -0,0 +1,6 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+1531	0	0	0	0	0	8	3802	+	hCreaMrna	1540	0	1531	hCreaGeno	6896	240	5573	9	312,199,96,222,86,124,135,126,231,	0,312,511,607,829,915,1039,1174,1300,	240,1156,1558,2040,2391,2592,4377,5013,5342,
diff --git a/blat/refProt.psl b/blat/refProt.psl
new file mode 100644
index 0000000..6880f36
--- /dev/null
+++ b/blat/refProt.psl
@@ -0,0 +1,7 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+370	9	0	0	0	0	0	0	+	mCreaPep	418	39	418	hCreaPep	417	38	417	1	379,	39,	38,
+38	7	0	0	0	0	0	0	+	mCreaPep	418	0	45	hCreaPep	417	0	45	1	45,	0,	0,
diff --git a/blat/refProtX.psl b/blat/refProtX.psl
new file mode 100644
index 0000000..4396c7e
--- /dev/null
+++ b/blat/refProtX.psl
@@ -0,0 +1,6 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+399	15	0	0	1	4	8	3811	++	mCreaPep	418	0	418	hCreaGeno	6896	403	5456	9	45,68,32,74,29,41,45,42,38,	0,49,117,149,223,252,293,338,380,	403,1151,1558,2040,2391,2593,4377,5013,5342,
diff --git a/blat/refRna.psl b/blat/refRna.psl
new file mode 100644
index 0000000..14970c3
--- /dev/null
+++ b/blat/refRna.psl
@@ -0,0 +1,6 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+1531	0	0	0	0	0	8	3802	+	hCreaMrna	1540	0	1531	hCreaGeno	6896	240	5573	9	312,199,96,222,86,124,135,126,231,	0,312,511,607,829,915,1039,1174,1300,	240,1156,1558,2040,2391,2592,4377,5013,5342,
diff --git a/blat/refRnaX.psl b/blat/refRnaX.psl
new file mode 100644
index 0000000..d991176
--- /dev/null
+++ b/blat/refRnaX.psl
@@ -0,0 +1,6 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+1219	114	0	0	2	56	9	3865	++	mCreaMrna	1606	200	1589	hCreaGeno	6896	394	5592	10	145,205,96,222,82,128,135,126,167,27,	200,355,560,656,878,960,1088,1223,1349,1562,	394,1150,1558,2040,2391,2588,4377,5013,5342,5565,
diff --git a/blat/test/badSplice/chr16part.fa b/blat/test/badSplice/chr16part.fa
new file mode 100644
index 0000000..dfd24d7
--- /dev/null
+++ b/blat/test/badSplice/chr16part.fa
@@ -0,0 +1,2001 @@
+>chr16part
+TTTTACttttttttttttaacgtcctttttttttctgcgggggggatgaa
+gtctcagtctgttgcccaggctggagtgcagcagcacgatctcagctcac
+tgtaacctctgcctcctgggttcaagtgattttcctgcctcaacctcttg
+agtggctgggattacagacatccaccaccatgcctggctaatttttgtat
+ttttagtagagatggggtttcaccatgttggccaggctggtcttgaactc
+ctgacctcaagtgatctgcctaccttggcatcccaaagtgctggaattac
+aggcatgagccaccatgccgggtcAGCTTTACTTTTTGATTTGATCTTTG
+GTTATGGAGGtgatgtggtttggctgtttgtctccaccaaatctcatgtt
+gaaatgtgattctcagtgttggaggtggcgcctggcaggtggtgtttagg
+tcatgggggtgggtccctcatgaatggcttggttccccccacacagtaat
+aagttaccatgagctctgattgttagagcctgggagcttccccttctccc
+ttttattccctctctcttcatgtgacacacctgtttccacttcaccttct
+gccatgattggaaacttcctgaggcctcaccagaagtaggtgcccacacc
+atgcttcttgtacagcctgcagaatcatgacccaaaaaaacttttcttta
+taaattacccagagtcaggtatttctttatagcagcgaaaacggactaac
+acaGAAGGCCTGGAGGCTGGTGAATGTTATCCATTCATTATAAATTATAT
+TAAATACCTTCTAGAAATAGAATGATCTTTGTCCTCTTCAATTCTTGTTT
+CTGCTTAAAGCATACTTTGGTTAATACTAATATTACTCATTCTGCTTTCT
+TGTGTTTGCTCATTCTCTCAGACTTTCTGAAATAGTTGACTTGGATGAAG
+GGCTCCTTCCCTCTGTATCAAGATCTTCCTTTTCAAAGCTTTCAGTATGT
+GAGAAAAAATTAgggcaggcaaggtggctcacgcctgtaatcccagcact
+ttgggaggcctaggctggtggatcacgacgtcaggagatcgagaccatcc
+tggctaacacggtgaaaccccgtctctactaaaaatacaaaaaaattatc
+caggcatggtggtgggcacctgcagtcccagttacttgggaggctgaggc
+aggagaatcacttgaacctgggaggtggaggctgcagtgagccaagatca
+cgctgctgcactccagcctggatgacagagtgagactctgtctaaaaaaa
+attaaaaaaaataaaaaaaaaaTAGAGTGTAATCTAACACCTAGAAAGAA
+CAGTCTACAggccgggcatggtggctcacgcctgtaatcccagcccttgg
+ggaggctgaagtaggcgcctgtaatcccagcctttggggaggccgaggta
+ggcggatcacctgaggtcaggagttcgagaccagactgaccaacatggtg
+aaaccgcatctctactaaaaatacaaaaaaaaatctgggcgtggtggtgg
+gttcttgtaataccagctactcaggaacctgcggtgggaggatcccttga
+gcctgggaagtggaggttgcagtgagtcgagattgtgttactgcactaca
+gcctgggcgacagtaagactctgtctcaaaaaaaaaaaaaGTGATTCTGT
+TTTTCAGTTTGTCTTTTGTCTATCTCACACACTTTTGTCTCTGCTCTTCC
+ACGTATATTTTTATCTACTAATTTTCACCTTTGAATGTCCCTCTTTTGAA
+GATGGGTGAGTGGGGCTTCCAGTTTTGTAAGGGATACTTGCGTTATGTTA
+GGATCCAGCCTAACATTTTCAGGAGGGTGTGTTTTGGGGAAGAGGTGTGC
+GTATTAATACCACAAGCCAGAGGATGACTCTAgtggacatttgtcagact
+ttgtggcttccaagcatctgggcccacttccaaagtttgtagagtcccct
+aatttatggatgttgttgggaagagagcccacctcccactatagaaataa
+gtacaccagaaacttgcttctgagtgtctctttcagctagaatgagagca
+agtgacaggctctctgcccatcagatatatctgccctgcatttgacacag
+agaaggggagacaaggaggaacttgctctgtcagtttgtaggcagccatt
+gtagggacatggattcctggagcgtgacgacagtaatgctaggggtagca
+gcgaatgtctgtgagaagtacatcagaaatgcaagctgcagcatctagtg
+cttggtggcagcagcactggtgtcctcactagctggcttggagtcatgat
+ttggggcactgttAACAGATGAATTTTTGTTGTTGTTGTAGTTttgtttt
+gttttgtttttgtttttgtagaaacggggtctcgctgtgttgcccagggt
+gatgttgaactcctggcctcaagcaatcctcctgtcttggcctcccaaag
+cgctgggacttcaggcatgagacaccacactcagccATAGACTCGTTTGT
+TAgttctcctaagaaacagagccaacaaaatatattgctaaagggtgggt
+ggggtgggtgggaaggtaagattttaaactctaaggaattggcacatgtg
+attgtggaggcttggcaagttcaaagtatgcagggtggaccagaaggctg
+tagacctagcgaagagctgatgttgttgcagcttgagtccaaaggcagtg
+ggttgactttttctattgtggccttcaactgattggataaggcccaccca
+cattatggaggctaatctggtgtactcaagttctattgatttaaatgtta
+atctcatcttaaaaatacTCCCCAAaaagaaaaataagaaagaaagaaag
+aaagaaggaaagaaagaggaaagaaaagagaaagaaagaaagagagagaa
+agaaagaaagaaagaggaaagaaaagaaagagaaagaaagagagagagag
+aaagaaagaaagaaagaaagaaagaaagaaagaaagaaagaaagaaagaa
+aagaaaagaaaagaaagagaagaaagaGggctgggcgcggtggctcacgc
+ctgtaatcccagcactttgagaggccgaggtgggtgggtcacgaggtcaa
+gaaatcaagaccatcctgggcaaaatggtgaaaccctgtctttactaaaa
+atacaaaaaattagctgggcgtggtggcgcgtgcctgtagtcccagctac
+tcgggaggctgaggcaggaaaatcactcgaacctgggaggtggaggttgc
+agtgagccgagattgcgccactgcactccagcctggcgacagagcgagac
+tccgtctcaaaaaaaaaaaaaaaagaaagaaagaaaGAGGCgccaggcgg
+ggtggttcacgcctgtaatcccaccactttgggaggctgaggtcaagaga
+tcgagaccattatggccaacaatgtgaaaccctgtctctactaaaaatac
+aaaaattagctgggcatggtggtacgtgcctgtagtcccagctactcggg
+aggctgaggcaggagaatctcttgaacccgggaggtggaggttgcagtga
+gttgagatcaaaccactgaactccagcctgatgacagagtgaaactccat
+ctcaaaaaaaaaaaaaaaaaaaaaaagagaaTGGGACAGAGAGAAGGTGA
+TTGGATTTATACATTGTAGCCAAGCATGTAGTGATAGCTTTGCTCAATCC
+TGGTTCCAAATACTCTGGTTCAACCAGCTATGGTGAAGGGGAGGTGGTAG
+AAACACGACTCCTGGGGCTCCACCACATTGTGCCTATGCAGATTAGGAAG
+CTCTATCCCAAGAAAAGGGCAAACCATGTGAGTTGCAGGGACATCCCCAA
+AGATGTCCATCCTAGGGGTCTAGAGTTCATAAATCACGGCATCCTGGATT
+CTCCTGGAGAAAACCTCCCTTACAATCAGACTACCCTTCATCTCAAACAt
+tttctttttccttttttttttttttttgagacagagtcttgctctattgc
+ccaggctggagtgcagtggcacgatctcggttcactgcaacatccacctc
+ctgggttcaagtaattattgtgcctcaccctcccaagtagctaggactac
+aggcacatgccaccatgcctggctaatttttgtatttttagtagagactg
+ggtttcaccatgatggccaggctggtctcgaacccctgaccttaggtgat
+ctgcccaccttggcttcccaaacttttgggttacaggcgtgagccactgt
+gcctgaccCCAAACATTTTCACGAATTAAGCCCATCTCAGTAATGTGCTC
+GTAACATTCCCTCCTGTAAAATGGAAAACACGAAGCATCACTAATGTCTT
+AAGATGACCAGGCAGAGGAAAGCAAGGGCTACACAGAAAACACGGAAGAG
+CCCCATATCTCAACAAAGGAAGTGATACTGCAAAGGATTTCATGACAGAA
+TTTCCACACCTGTGGGCACAGGAGCAGATCACAAGGTGAGGAGGTTTGTG
+GTTCCAAGGAATCTTGTCTGCGATTTATCTGTATCAGGATGGCTTCATTT
+CTAATATCTACAAGTTTTGGTCCAAGAGTTTTATCTAAACGTTAGATAAT
+ATTGAATGTCGTCGTTGTTTGGTCCAAAGGGGCCAAAATTAGGTGGGACA
+ATTATGTTCTTCTTGTCCCTAATGAGGCTCTCAGGGAATCTGGTCCCAGT
+GGCCAAAGGAGGTTCCTACAAATGCCTGCTCTGTGATTGCCCCAAACATT
+TACTTACACAGAGGACTAAGACCATGAGCCCCTACTCCTCACACACTCAG
+GACCCGCCTGTGTTTCCAAGACATTCCAACTCCCACAGTAAGTAGAAGCA
+TTGACCAGTTATGTAGAAATGAGGAACAACTGAGAGTGACAGCACCAACC
+TTCTCCAGGAAAGGTCGCAGAGGTGAACAATTAAGTATGTGTTGGCTCAG
+ATGTGAAGTTCTTTTAGGAATCTTCTTTGCTACATCATCCAGATACAGGA
+AGTAATGAGTAATGTACAGAGAAGTGAAGTACAGGAGTCCTGAATCCATC
+AGTTGTCACTTGAGATTAACCCAGTAATCATCAGTCATTCCTCCAGTCTC
+TTTATGAGCTGCTAACTAGTTGGGTGGGGAACTGAATGTACCAGAGACAC
+ACACATTCTCAGAGTCAGGCTATGTGTACGTGTCTGTGTGTTTTGTtttc
+ttttcttttttaatagagatggggtcttggtatgttgtccaggctggtct
+tgaactcctggcctcaagccatcttccctctttggccttccaaagttcta
+ggattacaggcatgagccaccatgcccagccTGTCTGTGTTTTCAACGTT
+AAATATGCAAAATAAGAATCAGTGAGTCGTCTAGGAAAAGCATCGTAACT
+GAGTGTTGGAAATTGGACGTATGGGTGAGGAGACCACATCCTGTTTTTGC
+AAGTTTGTGAATTGATTTGCAAACGTGGTTCTTCCTGGAGCCTCATCACA
+TCTTAACCACCCATGTGTATGTTTCTGAATTCACTGTCTTCTATGCAGCT
+GGGTCCAGACATATGAGAGGGACAAACCAGTGAGTGTCTCCGAGTTCCTC
+CTCTTGGGACTCTCCAGGCAGCCCCAGCAGCAGCATCTCCTCTTTGTGTT
+CTTCCTCAGCATGTACCTGGCCACTGTCCTGGGGAACCTGCTCATCATCC
+TGGCCATAAGCATAGACTCCCGCCTGCACACCCCCATGTACTTCTTCCTC
+AGCAACATGTCCTTTGTGGACAACTGCTTCTCCACCACCGTCCCCAAGAT
+GCTGGCCAATCACATACTCAGGACTCAAACCATCTCCTTCTCTGGCTGTC
+TCATGCAGATGTATTTTATCAGTGAGCTTGCTGACATGGACAATTTCCTC
+CTGGCTGTGATGGCCTATGACCGCTTTGTCGCCGTGTGCCGCCCCTTACA
+TTACACAGCAAAGATGACCCATCAGCTCTGTGCCCTGCTGGTCACTGGAT
+CATGGGTGGTTGCCAACTCGAATGCTCTGCTGCACACCCTGCTGATGGCT
+CGACTCTCATTCTGTGCAGACAACACCATCCCCCACATCTTCTGCGATGT
+GACTCCCCTCCTGAAACTCTCCTGTTCAGACACACACCTCAGTGAAGTGA
+TGATTCTTACTGAGGCTGCCCTAGTCACGATCACCCCATTTCTTTGCCTC
+CTGGCTTCCTATATGCACATCACCTGCGTTGTCCTGAGGGTCCCATCCAC
+AAAGGGAAGATGGAAAGCCTTCTCCACCTGTGGCTCCCACCTGGCTGTGG
+TTCTCCTCTTCTATGGCACCATCATGTCTCCATATTTCAGAACTTCATCC
+TCCCACTCAGCTCAGAGAGATATAGCAGCTGCTGTGAGGTTCACAGTGGT
+GACTCCCGTGATGAATCCTTTGATCTACAGCCTGAGGAACAAGGACATAA
+AAGGGGCTCTTGTAAAAGTGGTTGCTGTGAAATTTTTTTCTGTTCAATAA
+TGGTATAGGCTTAAGAAAGTCCTAGAAGGAGCTAATTTCTGAGATAATCG
+TTTATTTTTTCTACTGTGTGAAACTTAGCAttgtttgtttgtttgtttgt
+tttgagacggagtctctgtcacccaggctggagtggagtcgtgcgatttc
+ggctcactgtaacctttgcctcttgggttcaagataatctcctgcctcag
+cctcctgagtagatgagattacagatgtgtgccaccacaatttttttttt
+ttttgtatttttagtagagacggggtttcaccatgttggtcaggctggtc
+tcgagctcctgacctcaaatgatccacctgccttggcctctctaagtgct
+gggattacagatgtgagccaccgcacctggccAGCATTTGTTTTCATAAT
+AGAAACATCTGGTATCTATTTTGGGAGAACAAAACCCTGCATATAGACTC
+TTTAGGTTAAAGATGGAAAGAGAGATCCTTTAATTAAATGACCCGACAAT
+TCCAATtgtcaatgccctcctgccaaaacctagaaggaacacacctgtag
+ttcaataagttggatttactaattatataacaagggagaatacacagcat
+cagcatcgggaatagtgaggtgtctcaatagaagagtcctaaaaaggact
+tctgcttgtgtaatgttggtgaggaaataggaatgagtctgtgctctgga
+gtagatgccattacagaatagagataattctgaatgagtatctttttttt
+ttttttttttttttttgagacagagtctcactcagtcgcccaggctggag
+tgcagtagctcgatctccgctcactgcaagctccgccttctgggttcacg
+ccattctcctgcctcagcctcctgagtagctgggactacaggcgcccgcc
+accatgcccggctaatttttttgtattttttttagtagagagggggtttc
+accgtgttagccaggatggtctcgatttcctgacctggtgatccgcccgc
+ctcagcctcccaaagtgctgggattacaggcgtgagccaccacgcccggc
+catgaatgagtatcttaatatattttatctagaaggaaagaagaggccaa
+agctgtgattgccaaagaaatagcagtcactcatatcaaccaccataggg
+ggatgtttggtgatttttgtggctatgaccatgttcctgtttttgtgttg
+agacatcattacagaaaggtcttgctttgttttgctctagcacagtcagt
+gtggccttatctgataccgatgttctgtgaaattctctatgttgatcagg
+agaacacaaaaaccttgctgtgagggccaggccaactcctgtcagggttg
+tttactctttctcaCAACAGAGACCTTGACATGAACACATCTGATGGAAA
+GATCAGACATTTGTTGGGACAGGAAGGGGAGGATTGAttttattttattt
+tatttgagacggagtctcgctctcttgcccaggctggagtgcagtggcga
+gatctcggctcaccgcaacctctgtctaccaggttgaagtgattctcctg
+attcagcctcctgagtagatgggattacaggtgcgtgtcaccacgccagg
+ctaatttttgttatttttagtagagatgggttttcactgtgttagccagg
+atggtctcgatctcctgacctcgagatctgccagcctcggcctcccaaag
+tgctgggattacaggcgtgagccaccgtgcacggctGAAGGGAGGATTTA
+TTTAGCGTTCCAGAAAGCCCTAATTCTGCCACTCATTTGAGCTATTTTTA
+TTTTCTTATCTAACCTTTATGTATCACACATTACAGCAGGAATATGGGTA
+AGTTAAACAAGAAAAATATCTTCCACAGTCCCAAATATCCAGCCATATCA
+ATCAACTACATCTATTTTTTTACACTCTGTTCTGTGTCAATGCACATATA
+TATTTTTATTTAGATACTGATTTATATCCTGGTTTTTCACCTTTCATTTT
+ATAATAAAGCTTTTCCAAATCACTACATAGTCTCCACAATTTTATCTTAA
+TACTTTATATGTCTCCATCAAGTTCTCTAGCAAAAGACTCTTACTAATAA
+TTCTATTTCTAAATTAAAACATAAAGGAAATTTACTATTTAAGAGCGTGA
+TTTGAATTTTATTTGTAggccaggcgcagtggctcacgcctgtcatccca
+gcactttaggaggctgaggtgggcggattacctgaggtcaggagtttcag
+accagcctggccaatatggtaaaaccccgtctctactaaaaatacaaaaa
+ttagccgggtgtggtggcgtggtgcctataatcccagctactcgggaggc
+tgaggcaagagaattgcttgaccctgggaggcagaggttgcagtgagctg
+agatcacgccactgcactccagcctgggtgacagaccgagactgtctcaa
+aaaataaataaataaataaaaagaaaGCGATTGTAGAAAATAACAAAACT
+GACCAATTATGAAACTGGTTATTTTTTCCTTGTCTTTGACATTCAGCATT
+TCTTTCttttttctttttttttttttttttttttttgagaaggagtctcg
+ctctgtcgcccaggctagagtgcagtcttgcgatctcggctcactgcaag
+ctccgcctcctgggttcacgctattctcctgcctcaggctcccaagctgc
+tgggaatgcaggcgccggccaccacgcccggctaattttttttttttttt
+ttgtattactgagacagggtttcactgtgttagctacgatggtctcgatt
+tcctgactttgtgatccgcccgcctcaggctcccaagctgctgggaatgc
+aggcgtgagccaccacgcctggctAACAttcagcatttttactatgatgc
+atctgtttgtgggtctctttgtgtttatcttacttgaagtttactaagct
+tcctgtctgtatagattattatgttttaataaatttggggccgggcgcgg
+tggctcaagcctgtaatcccagcactttgggaggccgaggcgggtggatc
+acgaggtcaggagatcaagaccatcctggctaacacggtgaaaccccatc
+tccactaaaaatacaaaaaaattagctgggcgtgatggtgggcgcctgta
+gtcccagctactcgggaggctgaagcaggagaatggcgtgaactcgggag
+gtggaggttgcagtgagccaagaacgtgtcactgcactccagcctgaccg
+acagagtgagactccgtctcaaaaaataaaattaattaattaattaatta
+gggaaatttttagccattatttttccaaaattttttcctctcctttctct
+cttcttctggtactcccattgtgtgtatttggtgcacttaatgatgtcca
+catttctttgaagttatattcaCttgtcttttttttttttttttgagatg
+gagtcttgctctgtcacccaggctggatctcccctcactgtgggttcaag
+agattctcctgcctcagcctcccaagtagctgggactacaggcacTCTCA
+CACTGTCATGCTGGAGTCAACCTCCCATTTACTCTGATTTTTTTTTTTAA
+AGAGATGAGcccagcgctttggaaggccaaggcagggggatcacttgggc
+ccaggagtttgaggccatcatggacaacatagcaagaccgcgtttctaga
+aaaataaaaataaaaaaattagctgggtgaggtggcatgtccctgtagtc
+ccagatacttgggagagttaggcggaaggatctcttgagtctacgagttc
+agggctgtagtgagctatgatcacagctctgtactccagtctgcgcaaca
+gagtgagaccctgtttcttaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaG
+ATGTGGTCTCAGTAAGTTGCTCAGGCTGgtctctaactcctggattcaag
+gaatcctcccacctcagcttccaaagtagctgggactacacgcacatgcc
+accatgccgtcttgataatgttttttaaattttaaaaataattgtttttt
+gaaatggtatctcactctatagcccaggctagagtgcagtggcataatct
+cggctcactgcaactccacttcccgggttcaagcaatcctccttcctcag
+cctcctgagtagctgggactacagatgcctgccaccgcaactggctactt
+tttgtattattagtagagatggggtttcaccatgttggccaggctggcct
+tgaactcctgacctcaggtgatccacctgccttggcctcccaaagtgctg
+ggattataggcgttgagccactgcactcaaccaaatcttttttttttttt
+ttttcgtagacagggtctcactatgttgcccaggctggtcttgaactcct
+ggcctcaagccatcctcctgattcggcttcccaaagtgctgggattacag
+gtgtgagccactgcgcctggctTATTTTCTGTAGTTACTACTGGAATTGG
+ATCTTTGGTCTCTTACATTTTCCAACTCTCGCTCTACCGCTATATTGGGA
+AACTGTTCACTGTTGTTTACTTTTTCAACTTAACTGGTGATCAGGCTCCT
+TAGGTAACAGAACTTACTCATCCAACAACTTCCCAGGGGCTCTCGTGTTT
+GGGGGCGGCCCCTGGTCCTGGTCGGGGCGCTCCTCTCATTCCCACCCAGC
+CTCACTATTGCGGAAGGAAACCCTGCGGCCCATGTCCTGCCCTCTGGGAC
+ACTGGGTGCTGATTGACGGCAACCCTGACCGTGGGCACCTCCCCAGTCCA
+GGAGATGGTGTGGGTTGTGGTGGCTTCACCCACCTACACTTAAAAAAACA
+AAAagctactcaggaagctgaggcaggaggattgtttgagcctaggaggt
+ggaggttgcagtgagccaagatcgtcccactccagccttagcaacagagc
+cagtctcaactaaagaaaaaaGTGTCTCAGGTACCGTGCCATGGCTTCAT
+GAGAACTGATGTAACCCCCGACTCTGGGCAGGGCTGCCAAAGAGTGAGAG
+AGTGGAGACTCTCTCTCACCACTCACTTCCTGGCAGCTACTTTTCTGGAT
+GCATGGGCAGGTCCCCTACACATGAGATGGTGTGGGTTGTGGTGGCTTCA
+CCCACCTACACTTAAACGAAAagctactcaagaggttgaggcaggaagat
+cgcttgagcctagcaggcgggaggttgcagcgagccaagatcaccccact
+ccagccttatcaacagagccagtctcaaagaaaaaaTTAACTGTCTCGGG
+TACTGTGCCATGGCTGCATGAGGACTGATAAAATACCCGACTCTGGGCAG
+GGGTACCAAAGAGTGAGTGGAGACTCTCTCTCACCACTCACTTCCTGGCA
+GCTACTTTTCTGGGTGCACAGGCAGGTCCACTGCACATGGTAACAGCCTG
+CCGACTCTGGAAACACAGTTCAGGATCCCAGTCCTAGTGCACTGGTCAGA
+CTTTCAAATAAGCGAATAACGTTGTGGGCAGCCTGTTTTGTTCGCTTTGC
+TGGCTTTACAGGGTACTTCCTGTTGGCCTGAAATACAATGTTGGTAAAGA
+CAGTTTTTCTGTGGCCTTTCTCTGTTGTGGAGGATTTGTTGTTTTTAAAT
+TACGATTCAGGACTGAACTGTATCATAGAATGTCCTTCTTTCAGAATGCT
+TTGTGCCAAAACAAGAAACCTCAGAATTACATGTTAATAACAACAAACAA
+AACAAAAAAGACCAATAGGCAGAAGGCAAGAAACAAAAACTATTCTTTGT
+AGATGGTGTCATTTTACCAaaagttaacagaactaaaccaacaaactatt
+gaaaattaacaacagtgagatgactatacaaatatataattaaaaataac
+tttcccatgtaaaagcaataatcaactataaaaatataatggaaaaaact
+acaataacaaaattgtgtaaaacaagtgaagaaaattagaaaaattttca
+caggaatataatactctaataaatagaaaggcatgtttctggatgggaaa
+catacactataatttttcccaaatagcttataggatttctttattccaat
+caaaacaccaatgTATAACTTTTGGAAACCTAAAGCAAGCAAAACTGAAG
+AATCCCTAAATCGCACCACACGATCAGTCCGTAAAGGCACCGCTGGCCTT
+GCTTCTAGGCAGAGGACAGGAAGGTATGGATATCAAGAGGCTGAAGACAA
+TTAATACCCACTACAATGAAGACACCTGGAAACCTGTCTCTTGAGAGGCA
+ATGTGAGCTAACCACTGGAGACGTAATTTCTAATCATACAACACTTTGCC
+TTGTGAGGTAGTGACCACCCCATTGCCAAAGGTCTGATGACAGCATAGAG
+GGGACCTAAGCATATGGTAAGGTTATTGATGAGACATGGATCCAAGCCAA
+CTTTTTCCTGCCTCCAGGTTGACCCTTCCTCTCTGGGTCTTGGGGTTTCC
+TTCGTAGCACATGAGATCTGGGCTCAACAGAGGGACAAGATTCTGAAGAG
+CTTTTCTAGTGGTGGGGCTGGATGGCCCTGCCTGAGTAATCCAAACTTCT
+TTTAGCAAGGGAGAAGCATGAGACGGCTGCTGGAGAGATCAACAGCAGAA
+CAAAATACAATAAGAACAGTAGACACCTAAATTATGTTGTGAAAAGGAAT
+CTGTAAAAGTCAGTTTTATCACAAATTGTAAATATTATTGAAATTGATTG
+CAAATTTAGATCACATACAAATGAGAGTCTGACATTCAACTGTTTTCCTA
+TATTCCAAAGTAAACAATTCCTTTCAACACTCAAGACTTAAACAGGTATT
+CTTAGAGGGTTATATGAATTGCTATCAGAAGCTGTTGGCTAACAAGCCAG
+TAATTTGGTTCTTTCACCAGAACACAGTTCCAGATAAGCATCTTTGCACT
+ATTTCTCAAGTATGAATCCCCATGTGGGGGGAAAACGGATATACTTTCAA
+TAGACACAAGTCACTCTTTGCCTTCCAAGTAAGCAGACTCCAGATTCATC
+TTCAAAGTGTTGGGAAAGGGGATCTGTGACCTGTACATTATCATATAACT
+TCAAAAAGGAAAGCTCCTTAGTCCAAAAAGCCTAGATGCTGAGGTATAGC
+CCTTGAAATGTTTTCTTCCCTGTGAATTTTCTAGCAATTTGAGGTTTTAG
+CTAAGATGGGCATTTATCCAATTTTGGCAATAATGAGATTTTTACACATT
+TATACCTTTTTAGGCAGCTTGGGAATTCAGAACTACTTATGAAAGCTCTC
+AGGTTGAGGCAGCACCATCAGACCCAGAAAGGGTTCCCAGTATTACTTCT
+GCTTTCGGGTCTTACAGGCTGAGTGGGTTTTCTCATGCCGGGTACAGTTT
+GACAGCCGACCAAATCTTCTCCCACATTTTTTGCAACCATATGGTCTCTC
+AGCCTCATGACTCTGCAGATGAAGCACAAACTCCTCATTCTTTGGGAAGG
+TTTTCCCACATTCTGGACACTTAAATATCTTCTCCCTTATATGGATTCCT
+TCATGACGACTCCGATGAGAATTCTGACGGAAGTTTTTTCCACACTGAGA
+ACAGGAATAAGGTTTCTCTCCTGTATGAATTCGCTCATGTTTATTGAGGT
+TTGTTTTATGATTGAAGCTTTTCCCACAGTGATTACAGTCATAGGGTTTT
+TCTCCAGTGTGGGTCCTCTGGTGGGAAATGAGGTAAGAACTTTCATTAAA
+CTGTTTCCCACACAGTGGACAAGTGTACCATCTCCTTGTCCTCCGATTTC
+GAGTAAGGGCAATAATACTGATGTCTACATATTTTGAGAGTTCCTCTAGA
+GGAGTATCATTCTCAATGGTAACTAACAGATTTCTCATTTTCCTTTTTTG
+TGGAATGGATGTATTTAGTCGTTCCTTTTCCTGGTTATCGGGAGGCTGCT
+GAGAGACCAAGGAAGAATCCATTTCATCATCATCTGAAGACTTTTCTCTA
+TAATCTTCATTTTCTACAGGTTCCCTCTCAGGATCTTCACCTTCAGGATT
+ACTGCCATTGACTGCTGAAACAAAGAGAGAATTTAACAACTTCTGAGAGA
+TATCACAACACCAGGCAGGAAAAAACAAGTCAGGTTTCTTATGCCACAGC
+CACCTTGAACGTCAATCTGGGGAGTGGCGGATACTGCCGTCGCACTCCTT
+TTCCATACTTATTGAGGGTGGGATACATAACTGATAAATCTTTCCATCTA
+CCACAATGCAAGCACACTTTAAAGAAATAAAATGAGTGGGATTTCACTGA
+AAGACTTCAAATGTTTGTTCTCTTCATAGGTGTTAATTACTCGACAAGTT
+CATATTCACCTTATACTCTGTAGAGCACTCAGGTAAGGACTAGGGATGAA
+GACTATACATCTATACAGGGAACCACTCATCATCTTGAAGGAGTCTGGTA
+ACTGAATAGTAAGACGAACCACTTGTAGGTTTTCACTATATTAAATATTA
+TCACACTATTATAGCACTAAATAATATCATAATGTCTTACAATGAGAAAA
+TTGAAACAATTCCAATAAGCAAAATTAAAGAGGGCACAGCATATTCATAC
+AAAAGTTTATTATTggccaggcgtggtggctcacacctgtaatcccagca
+ctttgggaggtcaaggcgagcagatcacccaaggctgggagttcaagacc
+agcctgaccatcgtggagaaaccctgtctctactaaaaatacaaaataag
+ctgggcatggtggcacatgcctgtaatctcagctactagggaggctgagg
+caggagaatcacttgaaaccggaaggcagaggttgcagtgagccgagatc
+gcgccattgcactccagcctgggcaacaagagcgaatctgtctcaaaaca
+gaaaaaaGTTTATTATTTGGCAATTAAAGAGATTACTACaactaatgaag
+ctttgggattagaagtcagtagtgtttctctttgtgtaggaaaggaagta
+gtgagtgggtacagggcacaaaagggatttttgggatgctaagaaaagtc
+cattttgggtggtgcttagtgtgtacattttgtgaaaacttgagctatat
+atttacaattggtaggctttttctatatttccattatacttcagaaaaaa
+gtcaGTGTAAGCAGATTATAAAGACTGGGTAACAAAGTGAAAAAGAACCA
+TGCTGTGGATATACTTGTGTGACAAGGGACCCCTCAACTCAGGCCTACTG
+AGAGTCAAGGGTTCAAATCAACCACCAAGACATGGGGGCTGATCCTGAAG
+CTGGAGTTGGAATCTCTGCTGGATTCAGCAGTTTCACACCAATAGATTTT
+TTTTTATTTCACttttttttttttttggcagagatagggtcttgctatgt
+tgcctaggctggttttgcactcgtgtactcaagcaatcttcccaaagtgc
+tggggattacaggtgtaagcccccacacccagccTTAATTAttttttctt
+tctttttttttttttttttttgagatggagtctcgctttgtcgcccaggt
+tggagtgcaatggcaccatctcagttcactgcaagctccgcctcctgggt
+tcactccattctcctacctgagcctccccagtagctgggactacagacgt
+ccaccaccgcgcccagctaattttttgtatttatagtagagagagggttt
+catcgtgttagccaggatggtcttgatgatctcctgacctcgtgatccac
+ccgcctaggcctcccaaagtgctgggattacaggcatgagccactgcgcc
+cgaccTAATTATTCTTTTTAATCACTCCCTTAGGATAATGAAATGTCAAT
+TTTTACCATAGCTCTTGACATGAACTACCATTCTGCTTTCAAAAACAGCT
+CTACTAATTTCATGTGAATATTAACTTTacctaatcttgttagcattaaa
+ttttaaaatatttaataggtataaaatagtttctcattgtagttttactt
+tggattttcattatgcaaaataatctactgggttaaggcttttataaatg
+tatatctttgtcaatgatttcttGTCTAAATAATTTTTAACTCAACTCTT
+CCTCTTTAACTacacttggactgcttccaaccttgtgtttttacaaacaa
+taccacagtgaataatcttctttgtacatcatttcgaatgtgttctgttg
+ctatatctgtaggtcagatttccagaattgaactcctggaacaaaggata
+agatgggtagttacagatgcaattacccttatacagggactataccattt
+tatatgcccaccagcaatatacctgtttctcaacaacctcaccatcaatg
+tgtttttatttctataaatatgaaatacgcaaaatgttaattcactagag
+gcttaatttgcacttctttttgctcctgtcacgcaggctggagtgcagtg
+gcgtgatctcggctcactgcaacctccacctcctgggttcaagtgattct
+ccttcctcagcctcccgagtagctgggattataggcatgccccaccacat
+ccagctaatttttgtatttttagtaaaaatggggttttgccatgttggcc
+aggctggtctcaaaactcctgacctcaggtgatccacctgcctcggcctc
+ccaaagtgctgggattacaggcgtgagccaccatgcccCAGCCTTTTGTA
+CGTATTTGAATCTGTCAATCTTTTCTTTCAAGGCTTCTGGGCTTTTGAAT
+CTTAATTACAAAAACCTTCCTATCCCATGGTTATAAAGGAATCACTCATA
+TTTTCTAAATGTGCTTTTTATATTTGTTTTAAACATTTAAAATCTTTGAT
+CCATGTGGACTTTTTCTTGGTATGTAAAGTAAGGTACTAATTTATCAAGT
+GGCTGTCAGTCGTCCTAACACCTTTTATCAAAAAGTCCCCCTTtatggtt
+aggctttgtgtcctcgcccaaatctcatcttaaattgtaatcccacatgt
+caaggagacatcaggtgaaggtaactgagtcatgggcgggggggccttcc
+cccatgctattctcatgatagtgagttctcatgagatctgatggttttat
+aaggggctcttccccctttactcgtacttctccctcctgctgccttgtga
+agatgatgccttgcttcctcttgcctttgccatgattttaagtttctgga
+ggcctccccagccatgctgaactgtgagtcaattaaacctgtttccttta
+taaattaccaagtctcggacaattctttataccagtgtgaaaatggacga
+atacaCCAACTTTATCACACACTAAACTCCCATGTGTATTTGAGGCTATT
+TCGGGACTTTCTGAGATCACAGTCTTGTTCCAAGGGaaaaatgctattgg
+tattgttgaaaaaaaacacatcaaattaataaatcaacaagaggagaaat
+gacctttttatgatattgtctccctagccaaaaacatagtattttttttt
+tttgctttcgttgaaatctactcttgtcctttagccttgttttaaagttt
+cctcataaatttgcacatttcttgagtttattcctaagtatttaaacttt
+catgtttctattctaatggggccttccactgtatcttctaaatgacccca
+tttatatatgtgaaagccaatgatttctgtttattcactttatttcccac
+taccttagtgaatGGTCTCATTTTTTCCCATGAGAGTACTTAAGACAAAT
+AAATGTTCTTATTTTTAAGTTTTCTGATTACTCTGTTCTACCTAtaagga
+agtatctgttaactattttgttaaatgttcttataaaggagaggcttcaa
+ttttgtcaagtatcttttcagtaactatacaagtaaacaaatgatttttc
+tcctttatATATAAGAAATATTAATAGATTTGTAttatttctgttttttt
+aattattttttttgagatggagtcttgctctgtcccctaggctggagtac
+aatgatgtgatctcagctcactgcaacctctgcctcccgggttcaagtga
+ttctcctacctcagcctccagagtaactgggattacaagcacgcaccacc
+acacccagctaacttttgtatattttttttttagtagagatggggttttg
+ctatgttggacaggctggtctcaaactcctgacctcaggtatcacccgcc
+tttgcctcccaaagtgctgggattacagccgtgaaccactgtgcccagcA
+tggggactggatttcaacacgagatttggaggggacaaatatccaaacta
+tatcaGCAACCTTGCGTCAAAGGGGTAAAAACAAATTAAAATTGCATATT
+TTTTCTAGAAAACATTATACAGAccttcatattcataggttctgcatctg
+aggattcaaccaaccaaggattgaaaatatttgagagaaaaaaaaaggat
+ggttttgtctgtacatattcagtttttttgtcattccctaaacaatttag
+tataacaactatttatgtagcatttactttgtattaggtattataattga
+tctagaaataaaatatatggtaggatatgtgtggagtatatgtaaatgct
+acaccattttatataatgaatttgagcatccatggattttggtatctgag
+tgggggtcctggaaccaatcccccatgaataccaaggACAAGTGTatatc
+agaatttatggtataacctaaagtgatgctcataagagagctcatggctg
+taaaaacatgtattaatttagaaaaatgagaataataaagcctctgattc
+aaagttagaaaaacaataggataaatttaaaagaatgaaggtattaataa
+ataccaattagaaagtaatgagttaaaaatagaaaaaaactagtaagatt
+taagcaaaaataaaccaatttccatagagaaaattgaaattatcaaaaaa
+agactagccacctacccaagaaaagcaccagcctcagacagttccacaga
+aaattcttctaaacttttaaaaattaaataattcaaatgctaggaaaatt
+tccagagtatagaaaaagaaggttgggaggccaaggcgggcagatcacaa
+ggtcaggagattgagaccatcctggctaacatggtgaaaccctgtctcta
+ctaaaaatacaaaaaatcagccggacaaggtggcaggcacctgtagtccc
+agctactcgggaggctgaggcaggagaatggcatgaaccgcagggggcgg
+agactgcaggaagccaagatcgcaccactgcactccagcctaggtgacag
+cgagactccgtctcaaaaaaaaaaaagaaggaaacttccaaattcaaaca
+agagcgaaactctgtctcaaaaaaataaataaataaataaagaCAGAgaa
+atctgagccccagtgatggaggtggggcctagtcggaggtgtctgcatca
+tgtgggtagatcgctcatgaatggcttgatgccacctcaaaataataagt
+gatttctcactcttagttcactaacaatgtggctgtttaaaagagcctgg
+caccttcctactctctttcttcctctcttgccatgtgaagtctgctctcc
+ttcaaccatgagtagtttcttgaagccctcaccagaagcagacgctgacg
+ccatgcttcttgtacagcctacagaaaactgtgagccaaataaacctctt
+ttctttataaattacccagcctcaggtattcttttatagcagcacaaaat
+gtactaagacagttgcttaagagttttaaattttccaggtggaaggaact
+ttaatttactgatctttattattaatttctagttgtactgcattgtgaca
+gatcctactttatttctactccttggaatctgagtctttgtttgttgcct
+agtatttagtcaattttcttcaatcttgaaaaggtgtattctcctatcac
+agcacacagtagctataataagaattatcttactgaaaatctgtttaagt
+gttctacgtttttccttatttttacgtggttCACTTGGCCAACACACACA
+TTCTCTGTTTCCCTAGGTTATCAAGGACTGTTCTTTGATTCCTGCCACCA
+CAATGTTCAATCCGTTATAGTTTTTCCTTTGCAAAAATTGGTTAAATGTT
+ACTGTTTCAATTATCATCACCTATAAATTGATGGCTCCCCAATCCCTATA
+TCCTCACATCTGAACTCCAATCCCCAATTTCCAAATATCTGGAGGATAAT
+CTCATTTTATTTCCCATCATGGATTCAATCTCATCCAAAATCAATTCCAC
+CTTCTTCACTACTCTGCCCCGGGTCCAAATCTTACCTCAGTCTTGCGATA
+GCTCATTATACCTATAAAAATTTCACACTGCTTATCGTTTGATGAATGAC
+TTGTCTTACAAACCAAATTGGAAGATTACAAAAGGCAAGAATATAACATC
+TTCGTAACCTGATGAATACAATTCCAGAACCCAATCCTGCCTGAGGAAAA
+AACTAGTACATTTATGAAATGCTGGTAAATGACTAAGCTTAAGCCACCAG
+CTTCAGGGTACGGGTGGAGGAAGTGGGGAACAGAGGGTGAGGATTGGGTC
+TTAGGGGCCCTGAAGTGCATAGTCGAAGTGATCTTGGAGGCAATATATCC
+ACTAACCAGTCACCCAAAATAAATGCCAGCTCTGCCCAAGACTCAGGAAA
+AACTCAGTGTTAATAAATCTGATCTTTTTATCCTTTTCTCTAAAATAAAG
+AAGATATCACATAGAGCAACCTGCGGGAAATTAACTACACTCATTACATA
+CCAATACTTCTGACCATACGGTATAATTACAGCTAAGAGTTTGACAGTCA
+TAATGGATTTCTGTCACCCCAGGCAACTTCTAAAACCTATTCTCTGTACA
+ACTTCACCCTCAGAAACAAAAAGCCCTGAAGGCAAAGTAAAAAGTGTCCG
+GCACTCAGTAAAGACATTTGTGCGGGCCTCTGCCTCTAGGGTTGCAACAT
+TTCTAGAGAAAAGGTAAAGCATCTCTAAGCAAATTATAGAGAGGCTGCTG
+CTTGATCAGTTCATACACAGCACTGGGGGACACTTGTCAACTATTACTGG
+GAAATGAGGACAAATAAAGAATGCCCCATTCACCAACCATACACGGAATT
+CATTGACAAAATTATGAGAAATGCATCTAGGAGacagtacagccctgggc
+cattactgcaaattctgatgtcagattccctgagtccgaatccctgttcc
+cctacttacaactgtgtgaactttagcaaattttgtaacccctctctgcc
+tcagttctgtcacctgtaaggtggcagtaatttctataccactcagtatt
+actctgagaagtacatgagagaataaacacatgaaaagcatttggactag
+tgcctagcatgtaacagcatataagtgctcattaagtgttaaacattact
+TTCACCAATAGTGGAATATATTTTCACTTAGGCTAGTAGTCTTCACATCT
+ATTGAACATCAAAAAGGGGAGGGGGATTACAAGAGTTAGTCATGTGTTCA
+ATGAAAACATTCAAATATACCTGTTGAGAACAGAGTTCAGAAAATGGGTT
+CAGAACAGTTTCTATATCCACAGTTTCTATGTCTGCAGGTTTTCCCTACC
+TCTCCCCTCACTGCCCCCAAGATACAGGGAAAAATGGCCACCCACCCACA
+GCTGGAGTTCTGTGGCAAGGCTCTGCTACATTGAATAAAACAAAAGTAAA
+ATAAAATGTGTGTGTGCACATAGGCTTACCAGGTGTGAATCGTCCCCCAA
+AGCTAAAGAGATGAAGGACATGCTTTTCCCAAAGCAAACAACCTGAACAC
+ACAAAGGCTGTGATTTCTTACCCAGTAACATCATTTCCCCGACACTGCTG
+TCATCTTCCTTCTCTGACGTGAGTTGTTGAGTAGGATCCAAGCTCACACA
+TTCTTCCTGGCAGTGAAATACATTCAAATCCTCAAAGACCACCAGCTCCT
+GAAAGAGCAAGAGGCCCCTTTCATCTTAGTAACTGAGGTTCACTGACAGC
+CCTACTGGTAAGAAAAGCTGACACACAAAGATCAAGGGAAGGGATAGCAA
+GAGGGACCTATAAATCCCACAGAGGTGCAGCAAAGACAGGACAGCCAGGC
+TGAGAAGGGCTCAAGGAAAAAGCAGAAGAAAAACACCCAAGAAGGCCAAC
+TCCTAAGAATGTGTTTTTACACACAGGTTGGCCAAGCACGGAAGGTGATG
+GATTCAGGCAGTAAATGGGAAAACCAAACCCACCTCAGGGTTAGCTTTCA
+AATACAGAGACACTGTCTCTTGTTCCTTTTGGACTCCTTTGGGCAGAAGC
+TTCACCAAGGGACGAGGATGCACTGGGGAAAGAGGAAGGTTTAGTTAGTG
+AAAAACTCAGTGACTCTAACACAGAGACTCCCCATACCGCGAGGCCAGGC
+TGTCCTCATTCCTTTGACAGGTAACTCATGGCCTTTTCTGCTCCTGTGAG
+CCCTTATAGAGTTCAAGCCATAAACTCTAGGGTCTTGAACCTATGGCATC
+TCCCTGTTATGAAAAGAATGACTTCTCTAAGCACCTTTCAGAATTTCCCA
+TAGAGTATTACTAAAGGAGAGCTTAGGGCAACGTAAAGTGTGAAGATGCC
+CAGAAAAAGCACAAAATTTCTAAAATTCCACATCAACCTAACTCAATAAT
+TCATCTGATTTATCCTTAAAAGATATTTCCCTCAGAATGTTTGGGTAAAA
+CTGACACTACAGAAAGATGCACACTGTTTATTCTGTGGCCTTACTCACAC
+CCAGCACTTGAGAAGAACTTCCTCTTTCCAACACTAGAATTGACTCCTTT
+TCCAATATACACCATCCTAACTTGAATTTATAACTAACACAGAAACCTAT
+CTTAGACTCCAGTACCTCCTCCTCCTCTTCTAGTGAAACAAGCATGTGCT
+TCTCACCTCTGTTCTGAAGGCTTGAGCTCACATCTTTCATAATAACCAAG
+GTCTCCTTGACTTTCTGACTGGGCTGGACCAGGCTTGGCTTGGGCAAGAA
+GGTGAGGAAGTGCTCCAGCACTAGCTGGTGGATGGTCTTGGGCCCGTTAG
+TGGCATCTCGAAGTAGGTCTTGGCCCAGCTTGGAGTCTGGCGGAACTCTC
+AGTATAAAGGACTGCTTTGGCTTTGGGGGCATAGGAACCACTTTTGCAGC
+CATCATGCCTTGCAACCACACACCACACTCGTTTCGCGGGGCCTCCAGAG
+CCACCTCTTACTAGAGGAAATCTGCCAGAGAGCCAAGCTGTAGACAGAGA
+AACCAGGGATTACCCAAAAGACCAGGCACGGCATTACTGCACTCCAATAT
+GTGGCATGGCTGGTGAGGCTACATGAGATCTAAAGAAAACGACAGCTGGG
+ATAGGGAAATCATAACTGAAACGCAGTATTTGAACAAGATATGCTTAGGA
+AGATGTGAAAGGAAGATCCTGAGAATGAAAAACAGAGACTGTGCAAACCT
+CAAGTCCAAAGGGAAGGGAGTAAGGGTGGAGCGGAGAAGGCCAAGGTCCA
+GCCTCCTGAGAAATACAAAGTGTggccaggtaccggtggctcacacctgt
+aatcccagcactttggaaggccctggcgggtggatcgcttgagtccagga
+gttcaagaccagcctgggcaacacagcaagacaccgactccataaaaaaa
+aaaaaaattagctgggcgtggcgacacaagcctgtggtcccagctactgg
+ggagctgggaggattgcttgtgcccaggaggtcgaggctgcagtgaactg
+tgatcgcgccactgcactgcagtctgagcgacaaagcaagaccctgactc
+taaaaaaagaaaggaaaagagaaaggaaagaaggaggaagggaatcaggg
+aagagaaagaaaataaaaggaaaaagaaagaaaagacagaaagaaagaCG
+GTGTGTAAAACCCACCAGGAATAGGTTAAATCAGGCTTGGAGAAAGAGCA
+ATGGGCTAGAAGACAGGAAATCTGGGGTCAATACCGAGGACATCTGCCTA
+AAAGCAGGTTGGTCACTGAATCTGGCCATACTGTACCCCTCGAACCGAAG
+CTCCCTCCGGTGCCCTTTGGGCGGGGAGGCGGTTGGTGACTCTCCCGGGG
+AGCAGATGCAAGGCCGAGGAGGTGTCCACACACCGCCTGCCGACTCCTCT
+CCGCCGTCAAAGCTCTGCTGAGAGCGGCAGGCGACATCCCACTAAGGACC
+GCCGGGCCAGGCTCACTCTGGGGCCTCTTCCGCTGGTCAAGGAACACCTT
+TACCGTAAAGCTCAGCGTGCGCCCCTGCCTGAGGCGCTCACCAGGCTCCC
+TACCCGGCCTTGCTCCCTCAGCAACGGACACGCTCCGCTCCCCAGAGGCG
+GCCTCAGCCTGGTTCCCGCCCTCACGGAGCCCCTCACCTCTCGGGGCCTC
+TGCAGCCCCTGAGCGTTTGCTGGGGACGGCTCAGAGACTCAGGCTCCGGG
+AGAGATAGAAAAACTAGGCGCGAGCGGTCGAGCCCTCCCCTCGCCCTTCC
+GAGTGCCCTCACAGGTCGCCGGCGACTATTCGTTCGCGCCGCCGCCAGTT
+GAGGAGAACGGCAGGGACTCGGTGCCTTCTGGGAAGTCGGGCGCTCTGCG
+GCTGTGACGTCACAACCGGTGCCTTGTTTCCGGTGCAGAAGCCTGGTCTC
+CCCGTTCGGAGCCGGCAGTCTGCGCTTGAGACGTTAAGACTTGAGACAGG
+CCAGAGGAGCTCTCAGGGCCGGAGGGAGGCCAGGACGGCTGTAGCCTCTC
+TGTGGTTCTGCCTGGAAGACGGAAGGCAGGTGGTTGGCTCTAGTCATCCA
+CGACGGGCTGGCACCTCTCCAGCTGCGGCCAGTCTAACCCCAGGGCCTGC
+TGGGAAATGTAGTTCGAATGCAAACAACCAATGGACGACCGTCAGGCGCG
+GCGGTTGGGGCGGGGCAGGcccccccaccgccccaccccccgcccaccca
+gcgcccgcgctccccccaccccccaccccgccacccccctaccccgccac
+tcccccaccgccctactctccccaccccccacccccctactctccccacc
+ccccaccccccaccccgccaccccccacggcgccaccccccaacccccac
+ccccctactctccccacccccctactctccccacccccctactctcccca
+ccccctactctccccacccccctactctccccacccccccaccccctact
+ctccccacccccctactctccccacccccctactctccccacccccccac
+cccctaccctccccacccccccacccccctaccctccccacccccctacc
+ctccccacccccctaccctccccaccccccTACCCCGAGGCTTAAAGGAA
+GCAAGCTATCTCTCCGACCGGAAAATCAAGACGCCTCCGCGGTTTCCGCC
+TTTTACTGCGGTTCTCCAGTAAAAAGACTGCGGAGGCGGACAGGGTGTGG
+CCGCCATGGGACTCCGCCCCCGCTCTGGTGACTCCCATAGGTTAGAGATG
+GGGCACCGACATTGCCCACTCCAGCTTGCTAACTTCTACACTGCTGTCCG
+CACCGGCCGTCTTGTTTTTAAAGACATCTTAATTGCCCTTCTCCTACTGT
+CTCGGTTTCCTTTCTCAATTTCAGCTTCCTACGGAGGCCGAACAGAGTTT
+TGTGTTTGTGCGTTGTATCCACACTCGGTTCGTTCCCCAGTGACGCACTG
+ATCAGGGTTCGGACAACTTGTGGGCAGGGATGGCCTTATTTCTCGATGTA
+ATACCAGCCTCCAGAAAGTTGACAAAAGTAAAAATATAAATGAATGCCTC
+TTCTTAAAGTTAATTATACCTGACTAATGGCTGACGATGGCTTAAAATAT
+GTTACAAAGAAACGAGTATGAAAACTGTGTGGCACCAAGACATTCTAGAA
+AAATAAGGAATATCTGCCTTTTCAGATCAAAATTTACTAAAAAGCCTCCG
+TTAATCAAAGCATTATGGTTTGAATTATGAGGCAAAACAGATAACTGAGA
+TGTCTTGAAGTAAAATATAAACCTGTGTGATTGTATTTTTTAAGAACTTT
+TTCTTGACTCTGTTAACAAACAAGAAATAGACTGGAAGATAATTGTAAAG
+ATTAGCTACACAAAAGATTATACATTCCTAAGACAAAATGAACCCCTGCC
+AACTGACAAAAAGCAAAGGCAATGAGGAgctcttcccgagaggaggaaaa
+ctaattggtcattaacatttaaaaagatgcttaaccacactactagtcaa
+gATTATCACTTTTAAAGGGAACCACATTTTTCACCTATCAAACAATGAAG
+GTGGAGAAATAGGCACTCCTTTCGCTGGTAGTGTGGTGTGTGAAGTCATC
+TTGtaatatatattaaaattaaaaGTACAAGTATGTACCCTTTGACCTTC
+ACAATCTCATCTGTGAATCTGATGTCtacaaatttcttgtagaattcttt
+gtagtgacaaaaactagaaatgacatgcatgttcatacgtaaggaaagga
+gtaaattggtgcattcatactctggaaattacccagctatgaaaaagaat
+ggattggaactatatgtacacctggagggatggccataaaataTTACATG
+AAAAAGTTTCAGAGCTACATATATTATGCATAATTATATTTTTGGAACAA
+ACAAAACACCTTGTGTATGTTTGTGTTGAGGGATACACAATAGATTATTA
+AAATGGTTACTCATGGGATggccaggcgcagtggctcatgcctgtaatcc
+cagcactttgggaagccagaggtgggctgatcactggaggttaggagttc
+aagaccagcctggccaacatggggaaaccccatctgtactaaaaatacaa
+aaattagccgggcgtggtggcgggtgcctgtaatctcatctacttgggag
+gaggctgaagcacaagaattgcttgaacccaggaggtggaggtggacgtt
+acagtgagccaagatcgcaccactgcactccagcctgagtgacaGgcaca
+ccagcctgggcgacagagtagtaagactctgtctctaaataaatacgtaa
+aataaaaataaaaTGGTTACTCAGAGGGAGGGAATGGAAATGGAGAAAAG
+GGAGAGATTACACTTTTTTTTTATTGTGTCACTTCATTTAATGAGCACGT
+CAATTTGGTAACTAAAAATAATAAAACCTTAAAAAAAAATAGAACAATAg
+gccgggcatggtggctcatcccagcacttttggaggctgaggtgggcaga
+tcatctgaggtcaggagttcgagagcagcctaacatagtgaaacccgtct
+ctactaaaaaatacaaaattagccgggcgtggtgatgcatgcctataatc
+ccagctactcaggaggctgagacaggagaatcatttgaacctgggaggca
+gaggttgcagtgagctgagatcatgccactgcactccagcctgggtgaca
+gagcaagactccatcttgtgggggcggaaaaaaaagaaaaaagaaCGATA
+AAGATTTTTTAAAACAATTTGATGGAAAAAAAGAACGATAAAGATTTTTT
+AAAACAATTTGATGGAAAAAAAAGAACGAAAAAGATTTTTTAAAACAATT
+TGATGGAATCCTGTTTTTAGAATCTAATCCGTAAAATAAATGACATAAAT
+GGATTTGAAATGATACCATAAATTAAGGGTGTAAACACAATATGTATCTC
+TATAAATGCCTTTTAACATGAAAAGATGGCTATTGTCACATACAATTAAA
+GAAATGaaatttaaaataataattacaaaaataatattCAGTATTCTAAA
+AGCAAATTAATACAATTATTTAAGAGGGCAATATGACACTTCCTATTTTA
+AGAAGTAAACTGTTCATAAACTTTGTAATGGTCAATTCTCAACTCATTTT
+AAAGAAAAActcacgcctgtaatcccagcactttgggaggccgaggtggg
+cggatcatgaggtcagaagatcaagactatcctggccaacatggtgaaac
+cccgcctctactaaaaatacaaaaattagctgggtgtagaggtacacgcc
+tgtaatcccagctacttgggaggctgaggcaggagaatagcttgaaccag
+ggagttggaggttgcagtgagccaagattctgccactgcactccagctcg
+ggtgacagaaggagactccatctccaaaaaaaaaaaaaaaaaGGTTACAT
+CATGATATGTTTATACAGTGGAAGCCAACAGAACCATTGAAAAGAGATAC
+TTTAAGTGAAAAGGCAAGTTATAAAGCAGTATGTATAATAAGTCGTTTTA
+AAAATAAAATGTTAGGCtttttttttttgagatggagtcttgctctgttg
+cccaggctggagtgcagtggcgtggtctcggctcactgcaacctccatct
+cccaggttcaagcaattcttctgcctcagcctcctgagtagcagggacta
+ccggcgcccgccaccacacccagctaatttttgtatttttactagagacg
+ggggtttcaccatgttggccaggatggtctcgatctcttgacctcgtgat
+ctgcccgcctcggcctcccaaagtgttgggattacaggtgtgagccaccg
+cccccagccTAGGCTTTTTTTTTTTTTTTTTTAACTGGAGGAATATACAA
+TAACAAGAGTTAACAGTTGCTTTCTAGAAATGTTGGCCGGGGGGGAGGGA
+AAGAGAGTTAATATTGGTTGTCTCTAAGGAGTAGGATTAGAAGGAATTTG
+TCACTTTTTATGTTTTATAAATCCATACATTTTCAAATAACAAGTGTTCC
+TTTTGTAGTTGAAAAAAACAACTATTTGAAAGGTGAGTTAATTTAGTATC
+TGATCATCTAGGAGTAAAACTAAGTGAAGAAAGAATTTCCTATTTAAAAG
+ATCTTGaatgcaaatcaaaactataatgagataccacttcacacacacta
+gaattactataataaaaaataccataaaaatgttattggtgaggatgtgg
+agaaaatgaaaccctcctatattgctggtggtccagctactttggaaagg
+acctaaaatggtccagctactttggaaaacagtttggcagtttctttttt
+ttttttttttttttttgagacggagtctcgctctgtcgcccaggctggag
+tgcagtggcgggatctcggctcactgcaagctccgcctcccgggttcacg
+ccattctcctgcctcagcctcgtcagtagctggaactacaggcgcccacc
+accacgcccggctaatttttttttgtattcttagtagaaacggggtttca
+ccgtgttagccaggatggtctcgatctcctgaccttgtgatccgcctgcc
+tcggcctcccaaagtgttgggattacaggcgtgagccaccgcacccggcc
+ggcagtttcttaaaatagttaccatgtgaacaagcagttcaatttcaagg
+tataaactcaagagaaatggaaatgtgtgttcacacaataacgtgttcac
+actagcctaaaagtggaaacaacccaatgtcctgtaagtgatcagtggat
+gaacaagaagtgatatttacatgtaatcatataatggattattcagtgat
+aaaacaggatgaaagtagtgacacatgctgcaacgtggatgggccatgaa
+aacacactaagcaaaagaatcagtcgcaaaaaacacatatcgtatgattc
+cacttaacatcatatgtccagaataggcaaatccatagagacagaaagta
+gcctagtggtttacatgctctggggaatgggggagaatggggagtgactg
+ctaatacatatgataaaatgttctggtattagtggtgatatttatacaca
+caatgcatatactaagaaacactgaattttccactttaaaaggatgcatt
+ttatggtatggatttagagctccataaaATAACCACTAGGCAGAGAAATT
+TCATCAGACAGATTCAAATGTGTACTACCTAAAACATTTATGTTtttgtt
+ttccttttttaatttttttattttttgagacagggtgttgttctgttgcc
+gaggttggagtgcagtggcacaatctcggcttactgcagcctctgcctca
+aaggctcaagcaattctcctgcctcagcttccggagcagctgggactaca
+ggtgctcaccaccatgcctggctaatttttgtattttctggtagagacga
+ggtttcgccatgttgcccaggctggtctcgaaccctggatgcaagcgatc
+tgcccacctccggctcccaaagtgttgggattgcaggcgtgagccaccgc
+acccagccTAAAACATGTATGAAGAAGTACAGCAAAACACGAAGTTCAAT
+ATGTAGATTCCAAATAGCAAGTATTCAAAGGAACTGTACAATTTCCATAG
+AATGAAGCAAAAAGCAGAAATTCACATGGAAAAATTCACAGCCTCATTAA
+CAGGTAATGAAATAAAACAGAAGTAAGGCCTCATTACATCCCTATTAAAT
+CAGCAAAAAAATTTTAAATGGCAGTCATTGCTTTGGGCATGAAATATTTT
+AAAAATCTTTGCAAAGGATGGTATGGCAACCCGTAGGAAGCATTATCAGA
+TATTTCACATTCAGGAACCATTTTAGGAATAACACAGGAGAAAAAAATAT
+GTATATGGTGAGGTGGTGGAAAATATACACAAAGATATTCATGAAAAGCT
+TATAACAAGGGAGAATCGGGAATAAGACATGACCCACCGCAGGGAACAGC
+TAAGCCGTAGGTCATGTGAACTGTCCTGGGATGTGGATTACTCTTATAGA
+ATAAAACTCGTGGAGGAAAGCCCAGCAAGTTTACCTGCTCTCATCATAGC
+CATGGAGTATCTGAGTCTAATCTACACTCTAGTAGTGAAGACAGAGGAGT
+TGGCATAGGAGTTTGGAATTTAATCTTCATTTGAtttttttcttcttaca
+tccactttttggagacagggactcactctgttgcccaggctggattgccg
+tagtgcagtctcagttcactgctgcagcctcgatctcctgcgctcaagcc
+atcctcccacccccatccctatggctaatttttgtattttttgtagagac
+gggttttcgccacattgcccagctggtctcaatccctgggctcaggcgat
+ccacccgcctttgcctcccaaaatgctgagattacagatgtgagtcacca
+tgcccggccCCTTTACATCTCTTTAAATGAAGGACAAATGCACGGGATGT
+GTGTGAAGTAGAACCTAATATTCCACAACCCGCAGATTTTCCCATACAAA
+CCAAGACAGAATAATCTGACACTTGGAATACATGCCAAATGTTTTTCCAT
+ACAGTAGTCCCATCTGCTTCCTGAAATGCAGTCGGGAAATGGGATTCCAC
+AGTGATTGAGTGACAAATGCAAATGACCAGATTTTCTAATTTTTTTATTC
+ATGAGGCCCAGTCAATTCTCTTAAGAATCATggcccggcatggtggctca
+tgcctgtaatccctgcactttgggaggctgaggtgggtgcatcacctgag
+gtcaggagtttgagaccggcctggccaacatgatgaaacctcatgtctac
+taaaaatgcaaaaaattagccgggcatggtggcgggcgcctgtaatccca
+gctacttcggaggctgaggcaggagaatctcttgaacctgggaggcggag
+gttgcgagccaagattgcaccactgcactccagcctgggtgacaagagca
+aaactttgtctcaaaaaaaaaaaaaaaaaagaaTCATAggccgggcacag
+tggctcatgcctgtaatcccagcactttgggaggctgaggcgggtggatc
+acctgaggtcaggagttcgagaccagcctggctaacatggtgaaaccccc
+gtctctactaaaaatacaagaaaaccagcctggtgtggtggcacgcacct
+gtaatcccagctgctcaggaggctgaggcaggagaatcgcttgaacctgg
+gaggtggaggttgcagtgagctgagatcgtgccactgcactccagcctgg
+gccacagagcaagatttggtctcaaaaaaaaaaaaaaaaaaTCATAGTTC
+ATTAATCCAGGTACACAAATACTTCTATCCCAATCCAGTCTGCTTGCGTT
+TCTCTAGGCTTCCCATATCCTCAAGACAGAAGCAGAGAGAACAAGGGGAC
+ATATATCCTTGCCGTGGGGTTCTGAGGGAAAATGAGGGCCAAATCTTCTG
+TTCAGGAGCACCTGAGAGTGCCACCCACCAGGGGCGGATTATGCAACGAC
+TCCGTACTTCCTCCTCTGAAATCCATGGTGTGTCATCAGTACATGTCTTC
+ACCCGGATTGACTAACATGTTCGTTCCTAACTTACCTCTGCTATAATCGG
+GTAGGCTCCGTGGGCACAGTAACTATTTTGTTATTTTTGCATTTCCCATA
+GCAGCTAGCACCTAGTCGGCATTCCGTGACTATTGAGTGTGAATGCAAGA
+TACAAGGCCAGAAGCAGGAAGAGAGATGCAGTGTTGGGCATTCAGTCAGG
+CCCCTGACCACCCACTGGACAGATAGTCAGAGGAGCTGTGTTCTTCCCTC
+CATCACGTGTCCCAGGGCTGAAGATAGGTTGAAGGGGCCCAGAGAAAGAG
+CAGCTGGCGAATGTATAGATGTGGGATCTGGCTGTCACATTGTAAAAGGA
+GATGCTTCCAACTCTGTAGTCCACGAAGATGCCCACACGCTTGGGAGGCT
+CCTTTATTAGCAGGCGGGTCGGGGGAACGCTGGACGCCTGGTACTCATTT
+TCCTTCATCATTATCACCACCCAGTAGCCATTCTCTGGCGACAGAGTCAT
+GTTCCCTTTCCTGCTTATGGATGTCTTGCAGGCTCCCAGGATCCATGCTG
+TCTTGTCTCCAACCTCCACCTCCCAGTAACGGCGGCCAGAGAGGAAACTC
+GGAGAGCCCAGAACAATGATACAGCTGTCAAATCTTTGCGGGCCATCAGG
+CAGCCTCTCCCACTTGTTTCCAAGTCTAACACTCTTCAGATCATCAGAGA
+AGATGAGGTTGGGGTAAGCGGTTTCTGCATCCAGAATCACATTAACTGCA
+AAGAAAATTTGAATACCTAGGTAGGGGTCCATGGGCAACATCCCTACAGG
+GTTCTCCCCACCTGCAGGAAACAGGGACAGGGTAGTTCTTCTGGAACGTG
+GTAGGGGAGAGCACAGGGATCCAGCAGGCCAGGGCCACTTGCCTTGATCT
+GGGCACTTACCAGCATGTGCCTGAGCGCCAATCAGCTCCGGAACTACGGA
+GAAAAATCAGATAGGGAAAAAAATCCTGAGCATTAGCATTAAGAGGGGCT
+AAATTACACTGTCCTGACAACAAGGAAAGACAAGGAACCCCCTGCTTAGG
+GCCCTGCATGCTATGTTGGGTATAATCCCGTTCCTCCCAGGAACCCAGGC
+CATGTTGGGGACTGTGGTCTAATGAGTCAACTCAGTCAATGAGTCACGCA
+CAGAGCCTGGGGGGCCTGCCATGACCTTTCTCCTACCTTTGCTCCAGGTG
+TTTGGTTTTTTTTTTTGTCTTCTAAATAGGGCCCCTCAAGTCAACAGCAC
+AAGGGAACACTGCAACAACCCCAGGCCAGCACACACCATTACCGCTGGAC
+TCACCATTGAACATTTCCATTTCTGAACGCAGGGTTTCTAAAATGTGGGA
+AAGGGAGCAGAGAGAAGCTGGAGTTAGGTCCCTCAGCCAGGGACAGATGG
+AGGAGAGGTTGAAGGCAGGTCAGCAAGACCAGGGGAAGAGGAGGGAAGTG
+AGGGGCTCTGGGCTATGTGGATCTTAGGGAGGAAGTGAGCATGCACCTCC
+AATCTTCTCCCAAGCCCATCTACCTGAGAAGTACTTTGTGCTCTTCTCCA
+CAAACTCTGACTTCTGGTGGAGGAGTTGGATCTTTTGTTTTATCTCTTGA
+GGAGTGGTCCACTTTTCAGGGACAGGCACTGTCTTAGCCCTAGAGACAAA
+AGACTGTTGACCAGAGAAGGCCGGAGCGAGGGGGTGGCCCAAGTACCCGT
+GAGCTGGAAATGAACTACATTCTCCACAGGGCACACCTAGCCCAGCCTGA
+GCTACACAAAGAAAAGTCTTCCCTGGATTCAGAGGTCTAAATGCtggtcc
+tcaactttggccacagactgtcatgtactggggtgctttaaagacatgga
+tatcaaaaccacaAGGAGTTTTCAGAATGGACTTAAAATGACATTGATAT
+TATCTACTAGAATTATCTATGTCAAATTGATTATACACCCCTTTCTTTCT
+ATTGAAATAAAAAGATAATaaatgaaaaaaaaacacacacaacaaaatat
+cccttcacatccattagaatggctattataaaaacagcaacaacaGAAAA
+AAATAgaccaggtatggtggctcatgcctgtaatcctagcacttcaggag
+gccggggcagtgggatcgcttgagcccaggagttcaagtccagcttgggc
+aacatggcgaaaccctgtctctattaaaaatacaaaaaagtagccggaag
+tggtagcacatgcctgtagtcccagctactcaggatgccagctactcaga
+atcacccgagcccaggaagctgagcctgcagtgagctgtgactgtgccac
+tgctctccagccttagtgatgggagtgagaccttgtctcaagaagaaaag
+aaaggaaggaaggaagaaaggaaggaagggagggagggagggaaggaagg
+aaagagaaatggctgggcacggtggctcacgcctgcaatcccagcgcttt
+gggaggccaaggtgggtggatcacttgaggtcaggagtttgagaccagcc
+tggctaatatggtgaaaccctgtctaccaaaaaaattagctgggcatggt
+ggcacgctcctgtagtcccagctactagggaggctgaggtgggagaatcc
+cttgaacctgggaggcagaggttgtagtgagccaagatcgcgccactgca
+ctccagcctggatgacagagcaagacgctgtcttcaaaaaaaaagagaga
+gagagagagTGaaacagaagaaaataagtgatggcaaagatgtggagaaa
+ctggagcccctgtgtgctgctggtgggaatgtgaagcgatgcagcccctg
+tgagaattaggatggtggttcctcaaaaaaaattaaacacaggataacca
+catggtcccgcagttccacttctgggtaggtacccaaaataacaaagcag
+ggtctcaagcagatatttgtacacccttgttcatagcaacattattcaca
+aaccaaaagttagaagaagtcccgatatccatgaatggataagcaaaatg
+tatgaacacacactggactatgattcagccataaaaagaaaataaattct
+gatacacgttacaacacggatgaagcccgaagacattatgctaagtgaag
+aagccagacacaaaaggacaccgggattttgtaaagctcccaggtgattt
+taaggcttagccTCTTCCTGTCCCTTCCCTCCCCTCCCCTTCCTGCTGGG
+CTTAGCCCAGCTCCACTCCAAACAAGCTTCCCAAGGCCACCAGTAGGCCT
+GAAGGGGCAGCTTTCATCAGATGAACTGCACGGGACACAATGCACTCGGA
+AGGTTTCTTAGGGAGCCTCCATCTTGTTTCAGCAGGATGGGCTGAATTCA
+CCCTTCCCAGTCTGCAGCTCCATACCCGGCCAGCCTCCCTGCTGACCAGA
+TGCCCTTCTCCCTATCAAATCCAGAGAGGCTTTGGGAAGCTGCAGAAAAA
+AGGAGGAGTCTGGAATCACAGACCCCGGGGTTGGGAACATCTCCCTCCCA
+GGTCCCTTCTGGGACTGTCTCCCCCATATGCTTTCTGCAAGACACCCCAG
+GGTACACCACAGGACCTCGCTGTACCTGTGCAAGATGTCTCCAATGTCCT
+AGGAGAAAAAAGAAGGAAACTGTCGGTTACCAGGCTCCTAGTGGCTGGGC
+TGACTCCTGGCCTCTACTTCTGGGCTCCTGGACTTTTAGCTCCCCGCTGC
+ACTTACCAGGGCTCCCTGCCCTAGGGTGTCAGTGGAAGTGGAGCACCTTT
+CTTCAAGTCTAATTCTAACCACGGGAATTCAGGCATCCCAGGTGGCGAGG
+CCTGCAATGGAACGGCCCTCAAGCCCTGCTGATCCCTTCTGGGAAATGGC
+AGAGATCCCCTGGATACCAGGCCACCCTGGGCTCCTGAGAGACCTCATCA
+AAGGGGTCTGGGCACAAGAGGCACTGTGGGTCACCAAGACCAAGTCCTAT
+CCTAGGCCTTAGGGGCTTCACCCACTTGTTCCAGCACGGCTGATGGCAGA
+GCTGGGAGCCTGAGGCATCCTGATAGGCACAGGGGACCCAAGAAAGCCGG
+GCCCAGGCACACCCACCTGCAGAAGTTCCCATTCTGACTGGCACTCCTTG
+GCCTCCAGTTCCCCAATCAGCGCATCGAGCAGGGCGATGTCCTGGGATAC
+GCGGGTGTCATATGCCTTCCTGATCTGCCCAACCATCTGGCCCACGTCCT
+CCAGTGAGGCCACAAAGAAATGCTCTTGCTGCTCCAGGAAGTAGTACACC
+TGCTCCAGCTTCCTCTGCACCCGCTGCTTCAGCGCTTCAGTTTGTTTCTG
+GGGAGCAGAGGACAGGGAGGTATGGGGGTCTGTGCTGTGGGTGGACGTGG
+ATGTCCAGGAACCCCCAGAAGCCCACCTCCTGGAGGTGGATAAGAGGTGG
+GCTTATGCTGCCTCTTCAAGGCCTAGATTCCAGAGCAGGAGGCGATATTG
+TCTGGAACCTTCCAGAAAAGACTGAGCATGGCTGGGGCTAGCTCTGGGAA
+AATGTCCTTAAACCTGGtgttaaggtttaactgtgtcccttccaaaattt
+acacgttgaagccctaacccccagtactcagcatgtgatcttatttggag
+ataagagttcttgcagatgtaattagttaagatgtggtcctactgggatt
+gggtgggtccctaatccaatataaatgttgtcttataaaatggggaaatt
+tgggctgggtgcattggctcatgtctgtaatcccagcactttgggaggct
+gagttgggcagatcacttgagatcaggagttcgagaccagcctggccaac
+atggggaaactctgtctttactaaaaatacaaaaattagccaggagtggt
+ggcatgtgcctacagtcccagcaactcgggaggctgaggcaggagaattg
+cttcaactggggaggcgaaggtttgcagtgagccgagattgcaccactgc
+accccagcctggacgacggagtgagattccatctcaaaaaaaaaaaaaaa
+aaaaaaccctaaaaaacaaAAAAACCAGCccaggcacgatggctcacacc
+tgtaatcccagcactttgggaggccgaggcaggtggatcacctgaggtca
+ggagtttgagaccagcctggccaacacggtgaaatcccgtctctactaaa
+aatacaaaaattagccaggcgcggtggcaggcgcctgtaattccagccac
+taaggaggctgaggcaggagaattgcttgaacctcggaggtggaggttgg
+agcaagccaagatcgtgccactgtactccagcctgggtgacagagcgaga
+ctccatcttggaaacaaaacaaaaaaaCAGAGAGTAAATTATGAAGTTAA
+AAGTGTTCTTggccgggcgcagtggctcacatctgtaatcccagtacttt
+gggaggccaaggcgggcggatcacgagttcaggagttcgagaacagcctg
+accaacatggtgaaaccccatctctactaaaactacaaaaattagccagg
+catggtggcactcacctataatcccagctactcaggaggctgaggcagga
+gaatcgcttgaacccgggaggcagaggttgcagtgagccaagatcacacc
+actgcactacaacctgggtgacagagcgagactccgtcacaaaaaaagaa
+aGTGGCGTTCTCCTCCCTTTTCCTCAATCCCATCTTTCTGCAGTAGTCAC
+CGGCATAGGTTGCTCTCTACCATCTTCTGGTGAGTATGAGAAAGCATGAC
+AGGATCCTCAGAGGTGACCCCTGCCTGCTGGGGGTGGTCTCCCTCTACAG
+GGATGAGCTTACCCTTGGCTGCTGGTTACCCTCTGTCCCCTGAGAGGAGG
+TGGCCATCCCTGCTGCCCTGTGAACCACAGCAGAATCTCGGGGACCCCTG
+CTCACTCTTCCCACCTTCCTCCCAGGGACGGATGGGCCATCAGCCACCTC
+TGACCTTACCAGAAAGCTCACTGCCTTCTCCTCCCCATAGGATCGCTGCT
+CCTCCCCTGATTTTCTCAGCTTCTTCAGATGCTCCAGCTGCTTCTGAATT
+TTCTTCTGGAAAAACAGCACTTGTTGAAAAGCTTGAATTTGGCTCCTGCC
+ATCTTTAGCTGGTGCCAACTCTGGAGGGGAACATCTCCTTCTGGTAGCAA
+GGCTGAGGGTGCTGCTGCCAGCGGCATGGGGAGGGGTGCTCAGGAAAGAG
+GAGGGAGGAATGGCTGAATTGCCAAAGGCAGCAGAGCTGAGAGGCacttc
+ctctgagcctctggattcagccatacctgaagccagctccccctggatct
+ctgagcaacataaacctgtagctcccctctttgctggactggtttatatt
+gtgttcttgccatttccagcccaagaatgctggttaatgcaCCAACAACC
+CAGAGTTGTTGGGAAAATGAAGTAAGGCCCAGTGTGTCCAAGTGCCTGGC
+AGAGAAGAGCCCACAGGCAGGGAGTGCCTACCTTGTGTTCCAGGGCGACC
+TCCTCAATGGGGCGCACCCGGTGGCCTTGGTGCTCCTGACTCAGACTGCA
+GATGAGGCAGATGGGCTCATCGTGATCCTCACAGAAGAGCAGCTGGACCT
+GCTTCAGGTGGCGCTTACACTGTGGCAGGGGCTGGGGGCTTAGGCTTCCC
+GGGCTCTTCCTTTCATGGGAGTCCTGGCACCGGGGGCAGCCAGGTGAGCG
+GCTGCCTGAGGCCTGGGGGTGCCCAGAAACTGCCTCGGGGAAGCTGCAGG
+AATCACGCACACAGGTACCGTCAACTGGGTCTCCTTCCTGGGCGTGGCAG
+CGGGGACTCGCAGCCGTGTCTGGTGGCCTTCCTGGGGACATGCAGTGGAA
+AAACCCCCTGAATGGCAAACCCAAGTTGCTTACACAGAGGTATCACAAAG
+CACAGCGGACACAGCCCTTGCCTGAGATGTGCGAGTTCTCAGTTAGACTC
+TGCCCACTTCCTAGCTTGTCCTCCCCCGACTTCCATCCAGTGAGGAAGCA
+AACAGGCCACTGGGCCTGAGAGCTAAGGGCCAGACCTCAGACATTCCTGA
+GCCTTGGAATTCTTGGGCATTTATCCTAAAGAAAGACCCATGGCCTTGTG
+CTGTTCCTCCTGCACAGACATAGATCTAGCAGGTGATGCCAAGGAAAGAG
+ACATTCTGACCAGTGTTCCTTTGCCACTTGAACCCATCCCTGGCTGCCCA
+TAACGTgagtggaggcttccaggggatggtgacttgtgtacctcgctcct
+agctggatcccagcccctagcagagtacctggcaaatgcaagcatttgga
+aaatgagtattgaatgaaggaatAAATAGACCACTGCTCACATATGAGTT
+caataaccattaaatgaaagcaaagaaggggctgggtggtggctcatgcc
+tataatcccagtgctttgggaggccaaggtgggaggactgcttaagctca
+ggagtttgagaccagcctgggcaacatggcaagagcccacctctacaaaa
+aattaaaaaattagccaggtgtggtggtgcacacctctaatcccagctac
+ttgggaggctgagacaggaggattgcttgaacctaggaggttgatgctgc
+accactgcactccagcctgggcaacagagtaagatgccatcttaaaagaa
+aaagcaaagaaggggggcattatagggctaaagactggaactcatcatga
+agacctaacagttatgaatagctctactccaaGACTCTAATTGCAACTTC
+ATAAGCAGACATGCCACGAGATACAAGAAGAAATAGAAACACAAggccga
+gcgcagtggctcacgcctgtaatcccagcactttgggaggccgaggcggg
+tgggtcatgaggtcaggagttcaagaccagcctggccaagatggtgaaac
+cctgtctctactaaaaatacaaaaattagccggacgtggtggtgggcacc
+tgtaatcccagctactcgggaggctgaggcaggagaattgcttgaacccg
+ggaggcggagtttgcagtgagctgaagttgcgccactgcactccagtctg
+ggtgaccaagagagactccatctcaaaaaaaaaaaaaaaaaaaaaaagaa
+aTAGAAACACACTCAATCCTTTAGCCCCTGCTACCTCCTCCCACCTCACA
+GTGTCCCAGAAATTCACAGCACATCTGTAAATgagactgctagtagtcac
+cagaaattattctccctccttctctcgtgatagaattaattgtccacgtt
+tccctgtttccctgcctcccattgccccccaaatgccctgcatttctcag
+cctcctttgcagttaggtgtggctatttgacaataatatgaccaaaggga
+tgtaaatggaggtgtcacaagcagcttctagaaacttctagagctttccc
+gagggatactattcccctctgttcctccatcttgctgcctggcatgagga
+cgtcaccttctgagagcagaagcttgaggacaaacttggtgggacagagc
+aacagcaggaccccagggtcctggcccacggatctgcctgggaccgcctg
+tgtatcatttatgtgaaggaggcacaaacttcttttctgttgaggttact
+gttatttgggtgtttctattattcacaaccaaacataattttaaTGACTA
+CCTCAGCAGTAGATAGTTAGGACTTTAGCCAATAGGCTTTTCTTTCTGCT
+GAGAGAAAGGCAAATGGTAGAATCTCAACCCCATGATGATGCATTGCTGT
+GAGGTTATTGTGAGAGGGAGTATTTTTAACCAGTCTTCCCCAGATTTTCT
+ACCTGGTGTCCATAAACCCCTTGGATTCTAAAGATGGTCTTCAGAGTGTC
+CAAGAACTACCTGAAATTTGATGTGACATTTGTGAAGCTGTGCATATATG
+CATTTTTCAGGGTCTAAGCCTGCATCAGATTAACGAAGCGGCCCTAGAAG
+ACACCCAGGAATCCCAATGATATAAATACAGTGGGgacctggtgcagtgg
+tgcacacctgtaatcccagcagtttcggaggcaaagatgggaggattgtt
+tgagatcaggagttcgagaccaacctgggcaacatagcaagaccccatat
+ctaaaaaaaaaaaaaaaTTAAAAAAAATACAGTAGGGATAAAAGAAAATT
+AGGGGGGAAATACTTCAGTACTTTTCAGGTCACTATTCCTAAGGATGCTA
+GGTTTTCCAGATCCCAGGGTCCTTTCTCACTGGAAGACCCAGGGACTTCT
+GGATTTGAAGACTCATGCAGCATACCACATCCTTTCCCCTCCCAGGTCTC
+AGGGGTCCCTGGACTCCCAAttcttttttttttttttttttgagacagag
+ttttgctcttgtcgcccaggctagagtgcagtggcatgatcttggctcac
+tgcaacctctgcctcctcggttcaagcaattctcctgcctcgaagccttc
+tgagtagctgggattatggacacccgccaccacgcccagcaaatttagta
+tttttagtagagatggcgtttcaccatgttggcaggctggtctcgaactc
+ctcacctcaggtgatccgcccccattggcctcccaaagtgctgggattac
+aggtatgagccaccgcacccggccTGGACCCCCAATTCTATTTCTCCTCC
+TTGAGTGCTGTGATTTCTCCTCTCCAGCCAACAATGCATTGGAAAGTGTG
+TTCCATAggctgggtgtagtgactcacacctgaaatcctagcacttttag
+aggctaaggcgggggatcgcttgagcccaagagttcaaaaccagcctggg
+caacatagacagtcctcgtaactacaaaaaatacaaaaaaaaaaaaaaaa
+attaaccaggtgtggtggtgagcacctatagtctcagctacttggaaggc
+tgaggtgggaggatcgcttgagcctaggaggttgaggctgcagtaaactg
+tgctcacactactgcactccagcatgggagacagactgagactctgtctc
+aaaaaaaaaaaaaaaaaaaaaaaaggaaaGTGTGTTTCTGAATGCTGCCC
+CCACCACGAGCATGGAATTGTCACCTGGATAGCCTCGGTACCCTCTAAAC
+TGGTGGcatttttcttttacagtttttttttagtctctttacctataggg
+acagctgcttaaaaaaatccagatggcctggagcctcctgatcccttgcc
+aaaaaccagaggaagttaagatcagagcaaaaccagtgcaaactggaaga
+ggtgacttccagttaccttaagatcatttacacattgttataaggctaaa
+ggtccctcccctaaaagaagatggccagggttttgtgtccatgcgatgta
+ggaagaagcatgctggggacagcgcctgcacatatggaaccctgccctgg
+gcctgcttacctatctcccttcccctccctggactctaaaatcgccctgc
+ctcccatccctggcaagcagacgcctgcagaggtgagctccccttctcca
+ttctttggccactgataacacctgattgcctttttcaatcggacattctt
+tctttctttttttttccccccaaaatgtttaagagacagggtcttgctct
+gttgcccaggccggagtgcagtggcacatcctcagctcactgcagcctgg
+aactccctggctcaagcaatcctcctgcctcagcttcctgagtggctaga
+attacaggcgtgtgccaccatacccagctaattttttttttagttttgta
+gaagtggagtctggctacgttgctcaggctggtgtgcagtggcatgatct
+cagctcactgtagcctggaactccgtctgctcaagtgaacccgagcagct
+gggactacaggcgcgtgccactattgtattttgtagagatggggtctcac
+tgtgttgcctaggctagtatggaactcctggggtcaagagatcctcccgt
+gcaggcctctcaaagctctgggattacaggcgagagctaccacgccctgc
+ccaacctttgggtttttatttttttaatttcgtttatagagatggcgggg
+gtctcactacattcaccaggctggtctcaaagtcttggcctccagcaatc
+ctcccgccctggcctcccaaagcgctgggattacaggcatgagctatcgt
+gcccggccagccattctttctctgcagccgatataaagtaggaaagaaca
+caatttaccggtgacCGAATGTTCTGGATTTCCAGGGCCTTCCTTCAGGT
+CCGCAGATGCCCCTCCATCCGGAGTGGGCCTTGCCCGGGGTTCTGTTGCC
+GAGTCCAGATTCGCAGCTGTCTTTTCCTCTAGAGTCAGGAGAATTTCTGG
+ATTTGCGGGCGCCTTCTCCCCTGTAGAAATGGTGACCTCAAGGCTTCTAG
+GTCGCATCTTTCCCGAGGGCAGGTACACTTCGAAGGGCCTGCACTCCTTC
+TGCCCCGGGGCGCCCCCCGCCAGCCCCTGCAGCCTCCCCGCGGAGCTGGC
+GTTTCTGCGCAGCCGGACCTCGGCCTGGCCCCCCTCTAGCGCCCTGCAGG
+GGCCGGGGCTTCTCCCGCCCGGCAGGGCCGGGCTCCGGGTCCGAGGCTTG
+CCCTGCGCGTCCAGGCCCTCCGAGGCCTTCTCTCTGCGTTTGCTCAGGGG
+CTTCCTCGACAGCCCCCTCCCGGCCTCGGGCTGGCTGCACCGCAGGCTGG
+CAGCTCCGCCCCCGTACGGCCGAGGGCCGTTCCCCTCGTTCCCCTCGGGG
+TGGTCTGGAGTCTTCAGGCTCCTGGGCTTGTTCTCCCCCAGGGAGCTGGA
+CGCTGCGGAATCATCTGTGCCGTTTTCTTGTGTGGAATATTCTGGAAGGA
+CAACCAGATGCAAAATGATGAAGCTGTCCCACGTTTAGGGCCCAAGATTC
+AGGGCAGAGGAGAGAGAATCCCCTTGGATATTAAAGTTTAGAAATTGAGG
+AAAACAACGggccgggcgcggtggctcatgcctgtattcccggcactctg
+ggaggccgaggcgggaggatcacctgagatcaggagttcaagaccaacag
+ggtgaaaccccgtctctactaaaaatacaaaaatAagctgagcgtggtgg
+cgcatgcctgtaatcccagcttctccagaggccaaggtgggaggatcatt
+tgaggtcaggagttcgagaccagcctggccaacatggcaaaaccccgttc
+ctactaaaaataagaaactcagccagacgcggtggtgcgcacctgtagtc
+ccagctactcgggaggctgaggcatgagaatcgcttgagcccgggatgtg
+gaggttgcagtgagctgagatcgggccactgcactccagcctgagtgaca
+gagcaagactccatctcaaaaacaaaaGTTCAGGACTTCCTAGACTAGAC
+AATGGCAGTCAATTACCATTCAGTAAGAACATGCTTGATGTTGCTATGTA
+tttctctctctcttattttattttttgagacaggatcttgctctgttgcc
+ctgatgtgatctcagctcactgcaacctctgcctcccaggctcaagcaat
+cctctcacctcagcctgttttctgttttttcaatagctgaaaatacaggt
+gtgtgctaccacgcctggctcatttttttgtatttttggtagagacaggg
+tttcaccatgttgcccaagctggtctcaaactcctgagctctagcaatcc
+acccaccttagcctcccaaagtgctgagattatttataagtgtgagccac
+catgcctagccTATATTTCTCAAATAGTACTTTTCAAACGTTTTAAGCAG
+GACAACTGTTTCAAATAAGATCTTACACAGGTCAGCAAAACCCAGATTAT
+ACGCTTTAAAAATAAAAATAagccgggcacggtggcctatgtctgaaatc
+ccagcactttgggaggctgaggcgggaggatcacttgaggtcaggagttc
+gagaccagcctggccaacatggtgaaCAGCACTGAGAAGATTCTATACCA
+ACCCCGTTCATATGATTGCATAGCAATCCCTTTTTGCTAACCTAGAGATG
+TTTGTCTGACATGAGTATTAATCATAAATGTAGTGAAGAAGTCTCAAAGA
+ACAGGTGTTCCAGCTCCTGCCTTTCGTGACCCTGACCTGCTTCTTAAAAA
+ACCCATTAGGAGCCTGAAGGAAGTTTACTAACCCAGTTCCAAAGGCCAGA
+GTGAAGAAAGGGACGTTCCTGAACTAAAGTCATCTGGATTTTGGTAGACC
+TGAGACTCCCAATCCCCAGGTCAGAGTGAGCTGCTCTGAGCTCCTGGTCC
+CCTTTCCCACAAAGCAGCCAGCACTCAGCACTGGATGAGGAGGAGGCCTG
+GGCCCGCTTACCCTGAATGGCTGCCCTGTGGAGCTCCTCGGCCAGCAGGC
+GCTGGTTGATGGCCCGCAGGACCTGCAGGGTGAGCTGCACGGCGTACTCT
+TCCCCATAGTAGGTGACCAGCAGAGTGGCCATCTTCACCGGCCTGGCTCT
+CTGGATCTGGCTCCGGGGGATCCTGGAGTGCTCCTTCTGCACACTGGTGT
+TCTGCAGCTTGAACTTGAACTTCTCGAAGTCATAGGGCACCAGCTCCTCC
+AGGGTGGACAGCAGATGGTCACTAGGGGTCTTAGCCATGGTGCTGAGCAG
+GAGAGGCTCGAGCCAGCTGTCTGGCTTCTGGTAGGAAAAGAAGCCTCTGT
+CCTTGGTGAGCAAGAAAAGGCAGGTTGTGAAATAGCGGAAAAGGCACAGG
+AAATGCTCTGTGTCTTGGTGGGAACTGAGACTAAGGGTAAGGGTGTGTCC
+ATGCCGGCTGTGTTCTCTTCTTACAGGTTCAGAGGATTTTCCAGCTGGGA
+GGGCTCCATGCCTTGGCAGACATGTGCCCCCACACCCCTCCCAAACCCTG
+GACCTCGCCTCCACACTAGACCACAGACAGATGGGCAAGTCTGCAAGGGA
+AGGTCTGGGATTGGATTCCAGACACCCCCTCCAATCTTCCTTCCTGCCAG
+GATCTGGGGCTGGCAGAGCGGGTGAGTGGGAACAGAGAGGACTATGCTGA
+GGGCCCGCCCTGCTGGTCAACTGTTCTCCTCCAGACTCGGGGTTTCAGGG
+ACCTTCCAGAGCCAATGGCACAGGACGGGGGAAGGGGTGGGCACTGAATA
+CAGTCCTGTGAGCTTTGCCTTTCCTGGCCCAAGAAGGCAAGTGAGGCCAG
+AAGGGCACTGCCAGGAGATAACTCTTGCCATGCCATCACCCCTGTTGATC
+CGGTTCCAGTTGACTGGTTCTTCCAGCCACATGAAGGACTTGAAAAGCAA
+TGCCTGGACCACCAGCCTGACTCATCTGTTCCCAGAGCTGACTCAGTCCT
+CGCTCCCTGGAGCCAGAATGCTCTTCCGTGCACATTCATTGAACATTCTA
+GACAGTGTGCCAAGATGCTGGAGCTACACGGGTGAAAAGGCACGGGTGTC
+CTTCAGCTCATATGTGGTGCAGGGCCCCAGAGGTGGCTTTGAAGCTAACA
+GAAGTTACATGTTGGGggcagggcacagtggctaacgcctgtaatcccag
+cactttgggaggccgaggtgggtggatcacctcaggttgggagtacaaga
+ccagcctggccaacacagtaaaaccccatctctactaaaaatacaaaaat
+tagccaggcatggtggcacgcacctgtactcccagctactcaggaggctg
+aggcaggagaatcacttgaacatgggaggcagatgttgcagtgagccgag
+gttgcgccattgtactccaccttgggcgacagagcgggactttgtctcaa
+aaaaaataaataaatgaaaaaTTACATGTAGGGTGAACTGACTCCTCACT
+TACCTACTTCTGACCGTTGCATACCCTAAtttttttatttttagataggg
+tcttgctcagtcactcaggctggagtgcagtagtgggatcttggctcact
+gcaacttctgcctcctgggcttgagcaaccctccaacctcagcctcccaa
+gtagctgagactacaggtgcattccaccacatctggccaatttttgtatt
+ttttatagagacagggtctcactatgttgcgcaggctggtcttgaactcc
+tgatctcaagcgatccactcgctttggcctcccaaagtgctgggattaca
+ggtgtgagccactgcgcccggccAGAAGTTTTGTTaataatgcaatttac
+ccttcaccagcacttcatcggcaccagccaccactagctttataaacact
+tcctcctagaatctctgcagcaccctgcagggctgcgtttatcatccccc
+tgtgcagccaagaatctgtagcttagtgacttgcctagagccaAGATCCA
+AACGTCAAACCACTTCACAACATCGTCTCCTGCATGACAATAATTTGTGA
+TTTTACTGTTAATGACTACCCATGGATGTCACATTTCCAGCTGACCACTG
+AGGTCCAGGATGGGTCACTTCCACAGGTCAGTCACAACATTGCGACGCCT
+AGCTGAACACCCAGCTCTGGGTGTGAGCTCCTCTGTGTGTGCCCAGCCTG
+GGATTCAAGGCTTTGATGAGTTCTGGTTGGTTGAATTTAACTTACTGTCC
+AGCTGGTCCACCTGTTTCCTATTTCACAGAGTATTTGGTGTTTTTGCATT
+GTTTTCATAGCTGACAACAAACATGCAGTTTGCTAGATCTTTCTGAGCCC
+AAACCCAACATCTTCCCTAAAAAAAGGGTGAATTGggctgggtgtagtgg
+ctcacacctgcaatcccagcccttgggaggctgagacaggaggattactt
+aagcccaagagtttgagattagcctgggcaacataaggagaccctgcctc
+tacaaaaaatagaaaaaatattagctgggtgtggtggcacacactggtgg
+tccctgctgctactcaggaggctgaggtgggaagattgcttgagcctagg
+ttcaggctgcaatgagctgtgattgcaccactgctctccagcctgggtga
+cacagcaagacaccctgtctcaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+GTGGATGAAATGCACATTGATGGTGCAGACAGCAGATTTTTGGAATTTTT
+AGGCTGGGCCAGAAGAAGGGTGTTGAATGGGGTATCACTGGGGCCAGCAC
+CCGTCCCTGACTCTGGACGGTGGCAACCCAGCACCTCCCAGGCAGTCTCC
+CACTACCAGATGGAGAAAGGATGAGACTGTGCAGTGACGCTGTGGGTGCT
+GTGTGATCCCATCTCGTCTGGTCAGAAAACTCCTCGGAGCTGATACCAAA
+ACCCCATGACAGAATTGGGCAGGGAATGATACTTTCTGGTCTAAAGCAGG
+ATATTTTGCAATTGCGGTGACACGTTTTGCAACAGAGGCTGCTCTGAGGC
+AGGACTTCTGGAAGGCAGTGTTTTGATGCCACTTTGGACTTTCTAGGGCA
+AGGCAGGCTCACAAAGCTTTTGTTTGGAGGGGTTCCAGTAATTTCTCACA
+GTGAAAATAGAATTATTGCCCTTCTAACGTCATTTAAGTGTTTAATAATC
+AAAGTGGAATGGTCATGGGCTGTCTTGTGTGCCCCTGCCATTGGATGTGT
+GACCTTATTTGGGGTGACATGGCAAATCTAAACCCAACAAAGCTGCTGCA
+AAGGGTCTACTCTCGGCTATTACTCCTGGGAAATGTGCGGCTCAGACACC
+ACGACCTTCACTCCACTCCTGGTCACCAGGGGTTTCACTTTCTATGGCAT
+TTACTTCTGCACATTTTGGGATTTAAAAAAATGAAGATTGTATTACTTTC
+GTAATAAGCAAAAAAGATAGTTTTAAAAAGTCTTTCAgaccaggtgtggt
+ggcgcacgcctgtaatttcaacactttggaaggccgagacaggtggatca
+cttgaggtcaggagttccagaccagcctggccaacacggcaaaacctcgt
+ctctaatgaaaatacaaaaattagccaggtgaggtggcccgcgcctgtaa
+tcccaggtactccggaggctgaggtagaactgcttgaacctgggaggtgg
+aggtttcagtgagtcgagattgcatcactgcactccaggttgggcaacag
+agcaagattccgtatttaaaaaaaaaaaaaGTCTTTCACAATTAGCTTAA
+CTTCTAAGGGAGTATCAGTCCCGTGCCCCTAAACCATCATGATAAAGGAG
+GTATATAGtatttacttatttatttacttgatttattttgagacagagtc
+tcactcttatcacctgggctggagtgcagtggcaagatcatggcccactg
+caacctccgcctcccgggttcaagcgattctcctgcctctgcctcccgag
+tagctggcattacaggtgcccgccattacacccagctaattttttgtatt
+tttagtagagacggggtttcaccatgttggccaggctggtcttgaactcc
+tgaccttgtgattcgcccgcctcagcctcccaaagttctgggattacagg
+cgtgcgccaccgtgaccagccAACTATTTTTTCATAGATGATGAAATGTA
+GGCTTACAGGtagggtgaccaacacattttgtctaggagcaaaacccaat
+ttgcccagtcttagcactgaaagcctagttctgggaacgaccacagtccg
+gggaaattgggacaattgcccaccctGTTTAGATGGGTTAATTGACATAC
+TGAACACATGTCTAGCTAGGAAGAGGCACCACAGGGCcattcatttactc
+ttggagcacctgctgtatgccagatgctattctaggtactactgatacag
+aactgaacagaaaaaaacttcttgcagtgctcacattctTTTTTTTCTGA
+TATAAATGCCCTTCAGAAGAGGCCACAttcttttttttttttcgagatgg
+aatttcactcagtcgcccaggctggagggcagtagcgcaatctcgccact
+gcaacctctgcctccagtgtttgagcgatcctcctgcctcagcgtcccaa
+gtagttgggattataggtaccgacaaccacgcctggctaatttttgtatt
+tttagtagagacggggtttcaccatgttggccaggctggtcttaaactcc
+cggcctcaagtgatttacccacctcggcctcccaaagtgctgggattaca
+ggcgtgagctgctgcgcctggctCAGAAGATCCCGCAttttttttttttt
+gacggagtctagctatattgcccaggctggagtgcagtggtgctatctca
+gctcactgcaagctccacctcccgggttcacgccatcctcctgcctcagc
+ctcccgagtagctggaactacaggcgcctgccaccacgcccggctaattt
+ttgtatttttagtagagacggggtttcaccgtgttagccaggatggtctc
+gatctcctgaccttgtgatctgcccacctcggcctcccaaagtgctggga
+ttacaggcatgagccactgcgcccagccAAgagcccacattcttatagga
+aagtgtgaattgatataaacaaacaaatacacaatgtatcagggagtgat
+aagttgggggaaaaaacagcagaataatagggttagtgagtgcaggggat
+tggtttcatatttttttatttttatttatttatttagagacagagtctca
+ctctgtcacccaggctggagtgcagtggtgctatcttggctcactgcaac
+ttctgcctcccgggttcaagcaattctcctgcctcagcctcccaagtagt
+tgggattacaggctcacaccaccatgccaggctaatttttgtatttttag
+taaagacggggtttcaccatgttggccaggccagtctcaaacaactgacc
+tcaagtgatccaaccgccttggcctcccaaagtgctgtgattacaggcat
+gagccaccgtgccccctggtttcatattttaatagggcacttgaagaagg
+cttttgtgcttgaacagagacccaaaggaagaggagtaagccaggtattc
+attttgaggatgagcagtctttgcctatttacagagtgcaaaaggggtaa
+ctttgtgcttagtgtttgaggaagagtggtggctggagcagaggcacgga
+ggaggagtggatggaggggttagagagggagctggagtcccctatcaagt
+agcagggctcccaggacacagcaaggacttggctcttactctgagatgag
+gggacactggaaagtttgagcagagcagtgacataattggagttacgctt
+taaaagaaacattctgggccgggcgcggtggctcacacatataatccagc
+actttgggaagccaaggaaggtggatcacctgaggtcagaagttcgagat
+aagcctggccaacatggtgaaagcccgtctctactgaaaatacaaaaatt
+tgctgagtgtggtggtgatgtgcgcgtagtcccagctactctggaggctg
+aggtgaatcacctgaacctgggaggcggaggttgcagtgacctgtgatcg
+caccactgtactctggcctgggtgaaagagtgagactgtttcaaaaaaag
+aaagaaaagaaaagagaacactctggcttccataagagacaagagatgag
+aaaggtggaaacagagaggagaaagcaatctattgtcacaatgcaggaaa
+gcgactgcagggccctgaaccactgtggaggcagaagggtcagattctgg
+gtgattctgaaagcagggctgacatgataagggtagactggatactggcg
+ggtgtgaagatgcatctaagatacctgtttctggccagaTTTTACAAAGG
+GCCCTTGTTGCTACCTTAAGGAGTTAGTGTTGAATCCTGCAGCAGCTAAG
+AGCTTCTGCAGGATCTCCCTCTCAACTTGGACCAACCCACCTGCCGATCC
+CAGCCCAGATCAATGAGATCTGCTGCCCAGTCCCCTACGCAGATAACACT
+AATTGTAACTGATCTTTCTGAGGGCACCTCCTGAGCAGCTTGGAAACGGA
+GGGAGAGGAGAGGAAGCCAGCTTCCCAAAGTGGGGTGTGGCAGGTGGCCT
+TAACCCTGCTGAAGGGCTGCAGTCATGGGGCTCTGAATAGATCCCCACAC
+CACTCACCAATGAGCTTCATTTGGAAGGCGGTAACGTTAAACAAGAGGGT
+TTGTAAAAAATAAAGGCCTACACACATAATTTTTTCTGATTATTAAATCT
+AGGTGGAGAGTACGTGAGTATTCATGTTACTCTCTCAACTTTCTTGTGCT
+TAAAAATCTTAAAATAAAAACTTTAATACGCTCTGTCCTACCAATATTTA
+TAGGAACCTGACTAGCAGCCAGGCTTTGGACACGCAATCCCCGGCCACCA
+AAGGGCTGACAGGCTAGTGAAAGGGGCAGAAAAATAACAAAACTGTGTCT
+GGAAGGCAGCTACTCCCtttttttgtttgtttgttttttgagacgcagtc
+tcactctgtcgcccatgctggagtgcagtggcgcgatcttagctcactac
+atgtgcctccggggttcaagcgattctcctgcctcagcctcctgagtagc
+tgggactacaggcgcgcgccaccacgcccggctaatttttgtatttttta
+gtagagacagggtttcaccatattggtcaggctggtctcgaactcctgac
+ctcgcgatccgaccgcctcggcctcccaaagtggtgggattacaggcgtg
+agccaccgcgcccggccCTTTGTTTTCTTACCAACTAAGCAGCAGCACTG
+ACACTGTTTCCTTTGAGGTTCCGTTTGCTGAATCCTGCCCTCTAAGGTGC
+TCCGCCCTTCCACTCCCCGCCCCGTGCTGCTGTCATTCCCACGCCTCACC
+CTGTTTTGCAACTTCTTGTTTATGAGCCTGGAAGCCACGAAGTGGTGGGA
+AATACGAGATTCAAATATCTGGtggccgtgtgacgtgagtaaattactcg
+atttttctcagtttccatttcctatcaaatgggTTGTTCTGGGAATTCGG
+GGAAGTAACAGTGCCGGGAACCGCGGGAGGAACCGCCAGCTGCGTCCTCG
+GACGTCCCCAAAGCCCAGGGCGGCGACTGGCACGACTGTCAGGGGCGCGT
+CTGTTAAGAGGACAGGGGGTCCCGCCCCGGCACAGCCGTCTCCTCCAGGA
+CCCCTCCCGCCGACGCCCCACGGACCCCACGCCCGAGCGGAGACCGGCGC
+GAGTCCGGGGTCTCCGGTCCGGCAGCCCCTCCCTGGCCCGGCGCCCCAAA
+GGGAAGCGGCCTGGGGGAGGAGACGTGTGGAAAGAGCGGCAGAAGATAAA
+GAGGAAGTAGCGGTAGAGAATAAAAAGGAACTGTCCGCAGTGTGCCCGGA
+CGCGGGGAGGCGCTGGGGTCAAGCGAGACCCGACCTGCACGCAATTCCCG
+CCGGGGTCCCGGCCTGCCTGCGGGAGGGAAAGGACCCAGGGCGGCTTCTG
+CCAAAAGTGCGGCTTCTGCCGAAAGTGCGTCTTCTGCCGAGGGGCCCACA
+TAAGGCGCGACAGACACTCCAGCCCGACCCCGACGCCCCGCCCTCACGCA
+TGCACATGCGCGGAACACTCCCAGAAACACATCTCCCAGAGCGCCCCGGG
+AGCACGCGAGCCAATTGGAGGGCGGATTAGCGGGGGCCCACGTCTCCCAG
+AGGTCTCCGAGTCGCGGCTCTGTTGGTCTGATTGGCAGCCGCAACAGCCT
+ATAGCTGCTTTTCGCCGGAGGGGCCACGCGCCGTTTGCCGGGACTGAGCC
+GCTGTTGTCGCTGGTATCCCGGGAGCAGCGCCGGCAAGTGGAGTCGTCGT
+ATTCCGGGCGGCCCGCGGCCCACGGGGATGGGACGTCCCGGGGCTGTGCT
+GACCCCAAAACCCTTCCACACTTTATTAGCCTGTCGCCCTTCTttcatgt
+ttacagcaaatattttccgagtgcctaatgtgtcccacttactgtgccac
+gtgcgagggtgcacgtgtcaggcaagaTCGCTGTTCCAAGGAGGCTGAGA
+ACAAGTAAATGGTAATTACCAGTTATGACCAAAGCTGTGAAAGGAACAGA
+TACATCAGCCTAACAGCAGCACTGCCGTTTTCTCCCTTATAATCAGCAGA
+GGCGGGCTAGAGCAAGGATTCTCAAACTCTGCCCCCTCAGAACCCTAGAG
+TACGGTTGCTGAAACTTCTGTTTTTTCCTTTTGAACAAATCTAGTAACAT
+GCTGTGAGCCAGAGAGGTAATGGTTTGGCTCAAAGAAGGCACATGCATCT
+GGtttctttcttcttttttgagacggagtctcgctctgtcgtccaggctg
+gagtgcagtggcgccatctccgctcactgcaagctccgcctcgcgagttc
+acgccagtctcctgcctcagccttccgagtagctgggattacaggcgccc
+gccaccacgcccggctaattttcacgcccggctaattttttgtattttta
+gtagagacggggtttcaccatgttagccaggatggtctcgctctcctgac
+ctcgtgatccgcccgcttcggcctcccaaagtgctgggattacaggcgtg
+agccaccgcgcccggccCAGGTTTCTTATTTCAGGAGCTTCATAGGCATA
+GACCTCCCTCCTTCCCTCCTACCCCCTCCCCCCTCTCCCAACTAATGCCA
+GACCGGCCACTACTTTTTAACTGTTTTACATATTTAACCTTCAAGAAAGA
+TTTCCTTTGATCCAAGTGTATTGCAGCCCACAAAAAAGCTTGGAAACCCA
+GCTAGATGGTCTGTTTTTCTAGTTCCTACATTGGATTTAAGTCCTACCCA
+TCGAGACTACTGTCTTCAGGTAAGCATATCGAGGCTGTATTCACCTTCAT
+GGTGTTCTCAGGGGCACTTTCTTACACAAATGATGGTAATCATCCTAGAT
+CATTTCCCTGCCTGCCACACTTGCCAGTtagttagaaactgtaaacccct
+taaatgtctgtcaccagggcactggctgaatagctgagtaagttttggtg
+aatccattccttggactacactgcatccactgaaaacagtgcggtgaatt
+tctgtgtgctaatgtgcaaagatggtttatgtattattcagtggaaaaag
+cacatttgcactacagtgcagatagcatgatcccatgtttgtaaataaga
+gaaaaaaatgttaaaatttaagtatctggagggaaatgcaagaaataaat
+atgactacctttcaagagtagaattgggggtAGAAGTTGGCCTTTTCCCT
+CTATGTCATCTATACGTtttatttttttattttattattatttttttgag
+acggagtctcacgctgctgcccaggctggagtgcagtggcatgatctggg
+cttactgcgacctccgcctcccgggttcaagcaattttctgtctcagcct
+cctgagtagctgggattacaagcgcacgccaccacgcccggctaattttt
+gtatttttagttagagatggggtttcaccatgttggtcaggctggtctcg
+aacttctgaccttgtgttctgcccgcctcagcctcccaaagtgctcagat
+tacaggcgtgaaccagtatgcccggcGTTCAATGAGCATTTTTAAAGTTT
+TATGACTCATGAAACATAGTCCACAAATATATGCTCATTGTGAAATAGTA
+ACGGAAAATAAAATATGGCAAGCTAAATGTTAGAGGAGAAATTTCTTATT
+TTGCTCCATTACTTTTACAGCAGAAAAATTAAAAAATTTATTAGCTGAGA
+CTTTGTTTCACTGGGGTGCAGAAGATTAAACAAATGATTTTTAAAAGCAG
+ACTCTGCCCATAGAGAAAAAATATTCGAGGTTTCCAAAGTAGAATAAGTT
+TAAATTAGCAAGTCAAATAAGGAACCTTGAGCCAGTACCGAAGGAAACAC
+GTCCCAGACCTATCTCCAAacacacacacacacacacacacacacacaca
+cTGCAGGCATAACATTTATGCAGACAGACTGTTCTTTAGGGCATAATTGT
+CTCATGTCTCAATTCCTCTGAAGCTCCAGAGCAGAAACTGAAATTTTAAA
+AATGCAGTTGAGATAAACTGAAATGACTGACAGGCCATTTGCCAAGAAAA
+GCTTTGGTTCTTTGGAACAAAGACAGTGCCCATATCCCAGCCAACATCAG
+GTGGTATTTCTCTTTCTGTCCTGTAGAGGGCATCTTCATGTGTGGGCACC
+AGGGCTGCGGCTGGAACCACAGTGGACACCCCACGCTCCAAGGACAATCC
+TCTGCAGAAACCAGCAGCTGGAAACAATTCTTAATGCTGCAGGAAGTAGT
+TAGGAGAAAACGACTGTGTAAGTCAGAGCTAAAACTGGAGTTCAAAAACC
+ACAGAAAATATTTCCAAGGCTGTCTGTGAAGTGGGGATGTCAAAATACCA
+AAAATTACAGCTTTGGAACTGCAGTGGATGACCTTTAATTGATGCAGTTT
+ATAGGTGCTAAGTATTGTGTGTGCTTTACGTTGCCTCATGTGAGTGCTTC
+ATAGCAGGgtgtgacgctggccaagtgatatacctaccctctttgtccct
+gtttctatcaactgtaaaatgggggttctagagttgttgtgaagattaaa
+tgagctaatacacacaaagcaccaagaacaatgctggatacaaggtaaTA
+GGTGTTTCTTCCTAGACTTCACTATCCTCATGTGAGGTGGGTATGtttat
+ttatttatttggggacagggtctcgctctatcacccagactggagtgcag
+tgttgcaatcatggcttagctccctacagctttttaaatttaattattta
+ttattattatttttttgagatggagtctcactctgtcacccaggctggag
+tgcagtggcacgatctctgcttactgcaagctgggcctcccggattcaca
+ccattctcctgcctcagcctcctgagtagctgggactacaggcgcctgcc
+accacgcccagcatatttttgtatttttagtagaggcggggtttcaccgt
+gttagtcaggatggtctcgatctcctgaccttgtgatctgcccacctcgg
+cctcccaaagtgctgggattacaggcgtgagccaccgtgcctggcctcag
+ctccctacagctttgacctccccagctcaagtaatgtcccacttcagcct
+cccgagtagctgacactacaggaatgcaccatcatgTAtacctgtggtcc
+tagctacttgggaagctgaggtgggaagattgcCCCTGAAATAAGACTCT
+AGATACAGGTCCCTTTCTCTGAAATTTTTGAAACAAAACGCCTAATTCAA
+AAAAAGTtatttttggtagagacggggtctcactatgtttcccaggctga
+tctcaaacttgggttcaagccatcctccctcattggcctcccaaagtgtt
+gggattataggcaggagccactgtgcctgtccAaggtgggtgttgatata
+ttcaatttaacacagaaaacaggaagtttgtacacactgacttgcccaag
+gctacacaactacaaagagtcaggtagccaacattcagtctcaaggtctg
+tgtctgcagagctcaaggcctttcctttggctttgctgtctctTGGCATC
+TGGTAGcttagcagtcatcaagccaaccccgtcatgttacagaggaggac
+acaggcttccaggggaactgactgacttgagttctacacatcagtgcaga
+gctgggactagaattctgtccacctaactGTATTTGGAAGAAAGTTAAGT
+GCTATTGACTACACCTAATATCTGAAAGATAAAGGGAGAGGCAGAAGCAA
+GAATGAATAATGTggctgggcgcggtggctcacgcctttaatcccagcac
+tttgagaggccgaggcaggtggatcacgagatcaggagttcaagaccagc
+ctgaccaacatggtgaaactccatttctactaaaaatacaaaaattagcc
+gggcatggtagcgtgcgcctgtaaccccagctactaagtaggctgaggcg
+ggaggatcgattgaagccgggaggtggaggttgcagtgagccgagatcgc
+accattgcactccagcctgggcaacagagcgagactctgtcaaaaagaaa
+aaaaaaagaaTGAATAATTTTTAAAGCAGGCTGTGAAGAACTAAAAACAT
+GAGGACACGGAAATTCAGAAACACCCATTTCAATATGATTCCTTTCGGAT
+AACTTGAAGCCCAAACAGGATGGAAAATCACAGGCCAAAGTCACCTGAAG
+GAAGGCTGTCACCCATGACGGACAACCGGGATGTTGCTCTCCATTCATCC
+CAACGGCAGCAAAGTCTGTCCTGGAACATGGAATGGTTTCTTTATACAGA
+CAACTAAGACTGGCTCCAAGAGAAGAGTTGCTACCACTAACCCCTACATG
+CTGCCTTGAAAGAGTTGGTGGTAGGTGTTGGAAAATTAATCTgagtaatt
+aggaaacaaaatttgaaacaaagaatcccatgcacaatagtagcaaaacc
+cataaccagacatgataagaaatttgcaagacctataagaagaaaagtat
+ataggattacagaattttaaaagtcccagatcattgaagaaatacaccac
+agtcgtggatggaagagttaatattacaaatatatcatgcattcctaaat
+taatcaacaaattataagcaaacccaattgaaattgtaacgagatttttt
+ttttacatttttaaaaaaatgtgatcttgctatgttgcctgagctggtct
+caaacttctaagctcatgcgatcttcctgccttggcctctcaaaatgctg
+gcattacaagtgtgagccaccatgcccagccATAACAAGACtttcttttt
+tttttcagactgggtctcactgttgcccaggctggagtgcagtggcgtga
+tctcaggtcactgcaacctctgcctcccaggttcaagtgattctcctgcc
+tcagcctcccgagtagctgggattacaggtgcgccccaccatgcccagct
+aatttttgtatttttagtagagatgaggtttcgccatgttggccaggctg
+ttctgcccacctcaccctcccaaagtgctgggattacaggcatcagccac
+cgcaccaggctgcaagatgtttaagaatgggctttgacaagttgattttt
+aaaattcatagccaaaaaaattgtgaaaaaaatacagtggtgtgagatgt
+attgtaacagatataacaacaagctgtgaaaatacagtaaattagaacag
+taatatgtttttacaagaatggatataaggtaaatggaaacaagattccg
+taagacgtgtgtatatgcaaaagatggtatttaaaacccaaggggaaaag
+gtggcccaacttataaatagttttgggactgttgacagttgagctggaaa
+acatagacttctgcctgacatatataaaaaataaactccatatatatata
+tatatatatatatatatatatatatatttttttttttttttgagacggaa
+tgtcgctcttgtttcccaggctggagtgcaatggtgtgatctgggctcat
+tgcaacctctgcctcccaggttcaagtgattctcctgcctcagcctccca
+agtagctgggattacaggcatgtgccaccacacccggctaattttttgta
+tttttagtggagatgggttttcaccatgttgcccagactggtctcgaact
+cctgacctcgagtgatccacccgcctcggcctcccaaaatgctgggatta
+caaccatgagccaccgcacctggcccagatgatttaaagaaacacgaagt
+gtaatatctgtaaattTGTTTAAATTTCGCAGTGAGGAAGATCTTTCTTT
+Ttttttattttttatttttttattgatcattcttgggtgtttctcgcaga
+gggggacttggcagggccataggacaacagtggagggaaggtcagcagac
+aaacaagtgaacaaaggtctctggttttcctaggcagaggaccctgcggc
+cttctgcagtgtttgtgtccttgggtacttgagattagggagtggtgatg
+actcttaacgagcatgctgccttcaagcatctgtttaacaaagcacatct
+tgcactgcccttaatccatttaaccctgagtggacacagcacatgtttca
+gagagcacagggttgggggtaaggtcacagatcaacagtatcccaaggca
+gaagaatttttcttagtacagaacaaaatgaaaagtctcccatgtctact
+tttttctacacagacacagcaaccatctgatttctcaatcttttccccac
+ctttcccccttttctattccacaaaaccgccattgtcatcatggcccctt
+ctcaatgagctgttgggtacccctcccagacggggtggtggctgggcaaa
+ggggctcctcacttcccagaaggggcggccgggcaaaggcggccccccac
+cacccggacggggcggttgggcgggcggaggcaccccccacctccctccc
+ggacggggcggctggccgggcaggggctgaccccccacctctctcccgga
+cggggcggctggccgggcaggggctgaccccccacctccctcccggacgg
+ggcggctggCCGGGCGGGGGCTGACAGATCTTTCTAACCAAGATAAAAAA
+ACTGAAAAAGTTAAAAAATTCAGGTAAATAGAAAAATTAGAAAACTTCAG
+TATGACAAAAACAGCCATGAATATGGTTAAAAggctggatgcagtggctc
+atgcctgtaatccctgcactttgggaggccaaggtgggaggattgcttga
+gcctaggggtttgagtctccacaatgtaggcagaccccatctctaccctc
+cctcacaaaattaactggccatggtggtgtgcgcctgtggtcccagctac
+tcaagaggctaagttggaaagatcgcttgagcctgggaggtcaaggctgc
+agtgagctgtgattgcaccactgcactccagtctgggtgatggagcaaaa
+ccctgtcttaaaaaataaaaataaaaaaGGTGACAGAGAAAATATTTGTA
+CATACGATAATACCTGGAATGTTAAAGCACTATAATTTTTTTAATGCTCA
+AAGGCTTAAATAGGCAACTCACggccgggcgtggtggctcacacctgtaa
+tcccagcactttgggaggctgaggcgggtggatcacgaggtcaggagatc
+gagaccatcctggctaacacagtgaaaccctgtctctacagactacaaaa
+aattagccaggcatggtggcacgtgcctgtagtctcagctactcgcgagg
+ctgaggcagaagaattgcttgaacccaggaggcggagattgcagtgagct
+gagatcctgacacgcactacagcctgggcaatagactgagactccatctc
+aaaaaaaaaaaaaaaaaaGGCAACTCagagaagaaatacaaagtaccacg
+tgaaaagatgcccaatctccaagtaatcagaaacatgacaggcaacaagg
+ggatattatttttttttaaatagcggcagagtcttgttatgttacccagg
+ctggtttagaactcctgggctcaagcagtcctcctgccttggccttccaa
+aagtgctgggattacaggccctaagccaccacacccggctgaggggacat
+aatttttcacccactatattatcacaaattaatatgattgccacagccaa
+ctttaatgagcatgcagacatagaagcactttcacacctcaggttacgag
+ttaaatttgtgaagcttttttttttttttttttttttttgtgatggagtc
+tcactcttttacccaggctggaatgcagtgatgcaatctcggctccctgc
+aacctccacctctgaggttcaagcgattctcccacgtcagcctcctgagt
+agctgggattacaggcacccgccaccatgcccggctaatttttgtatttt
+tagtagagacggggtttcaccgcgttggccaggctggtgtcaaacccctg
+actttaggtgatccgcccgcctcggcctcccaaagtgctaggattacagg
+tgtcagccactgctcctggcctgtgaagctgttttggaaggtgatttgct
+gcaagttttcaaaattaaaaatgcacaagcctaggccaggcacggtggct
+catgcctgtaatcacagtactttgggaggccgaggtgagcagatcacttc
+agcccaggagtttcagaccagcctgaccaacaaagtgagacctcgttgct
+acaagaaataaaaaattgggtggcacatgcctgtggtcccagctactctg
+aagggtgaagtgggaggactgcttgagcccaggaggtcaaggatgcagtg
+agccaagattatgccactgcactccagcctgggtgacagagggagaacat
+atctcaaaaaaaaaaaaaaaatgcacaaggcttttgcttcagtgattcca
+tttctaagactatatccaatgtacccaaatatgcacgtctgagatgttca
+ttggagtattggttgttaaaggaaacagctggagacaatctaaatgggga
+gacagtcagtacagctgtggtatatccatagtatgcatgctctacagttg
+ttaagagtggcaatggcctattcatctggacctagatagatgtcaaaggc
+acactgctaatatttaaaaagaagatctggaaaatatgtatagcatgGTG
+TATACATATAATTAGCCCATATAGGTACATGAAGTTCCTCAGGAGACTGG
+GAGGATGCACAGCCAGGTAAACCTGTAGAGCATGGAGACATTAGGTGGGA
+GGTGATGGAAAAGTCCCTCAGttttttttttttttgagacagtctcgctc
+tgttgcccaggctggagtgcagtggcatgatctcagctcactgcaacctt
+cacttcctaggttcaagcgattctcctacctcaacctaccaagtagctgg
+gattacaggcgcccgccaccacgctcagctaattttggtagttttagtag
+agatggggtttcaccatgttggccaggctggtcttgaactcctgacctca
+agtgatcctccccgccttggcctcccgaagtgctgggattacaggtgtga
+accactgtgcccagACCTTCATTTTGTTTGTATACATCTGTATTCATTGA
+ATCTTCTACAAGGTTTATTTATTCATGTATGCCTATtgttccggttatct
+attgttgcatgaaaaacaccccaaaacttaatagtgtaaaacagcagccc
+ctttattatgctcacaacttggtggtcagatttcaagcaagacccagagg
+cacaactcatctcgttccacagtggctggagcttcagctgaggtggctca
+aatggctggagAACACTTCCCTGCAGCAGAACCTACAACCATCTTCCTCC
+CCTTTCTGGAAAAGGTTTGTTTCTGAGGCTGGAGTCAGAGTCTTCAAACC
+AACAGCCAGAGATAACATTGCTAATTATGCCCCTTTCCTTGGTCTTTATT
+TGAAATGAAACGGTTCtgttaccggtagagggtcttgatgcaaattgtcc
+aggttcttggcattttgaacaaagaactggacaaaacgcacagcaaagca
+aggtaagaatgaagcagcaaaagcagagatttattgaaagtacatgccac
+agtgtgggagccggccaagcagcagcttaaacaccccctagaggtttccc
+attggccacttggtgttcaccccatgtaaatgaaccaacctcagtcagtc
+tgattggttgcaaccaatcagaggctgaagtgaagttacaaagttacact
+cctgtgcaaacgtctgattgcaaaaagcagccagtcagaggtaccttcaa
+tttcccatctgcccctcagaaaaggtgggcattggcaaagggagtagcct
+ctggtccttttgttacttatgcgtggaaagttggggtttttctttcgatt
+tagttctaggaagtcaaggtgaactggccttcagttccctgcctccagac
+cctattctgcctcaGTTCAAATACACAAAACCTAACAAATACCTATATGA
+CCACCTTCCACAACTAATCAATGGCAGTGTCTATTAGTTTGACTTTGTTT
+CTATTTTACAAGAAGCAAAAGCACCTCTggactctccactagagagctat
+gtgcagccactccagcatggtgctctcagggtaaccagacttcttacact
+agctccaagtgcaagttctcctagcaaacaagatagaggttgcaaggcct
+tttatgacctcaccctggaggtcacaccacatctgtatttcattgtattt
+cattggtagcagtcacaagctgcccagatacaaggcagagggacagatgc
+cccacttcttgatgggatgagtggcaaaaaaaaatctgtgaccatgttta
+aAACCCAGAAGATTTGGCTGTTAGAGATTTGTGAAGTTTTTAAAAGTTAA
+GAATTATTAAAACAAAAATAAAACCCAGGAGACAAGGTAGTGGAAGTGTG
+TCCCTCCCATTCACTGACCAAGGTGAGGGGACTCTAGTCCTTTGCTGCTG
+ACCTTCAGCCTCCCTTCCTCTTAAAAAGAGGTCCTAGTTGGGGAGCGATG
+GCTGAAGAGTTACCATAAAATACCAAGTAGGAGCGAggtgcggtggctca
+cgtctttaatcccagcagtttgggaggacaaggtgggaggatcgcatgag
+cccaggagttcaagacaaacctgggcaacatagcaaggctctgtctctac
+aaaaaaGGAAAAGAGTACAAAGTAGGGCCATTTAGTATGGTTTCATCTTT
+ATTAAAAGTCTTAAGTTTTAGATTTTTGAAGTTATCACCAATAAAATATC
+CAGTTGTGGTCTTGTGTTGAGTGAAAATGTTATTTAAATGCAGATATTTA
+AAATATACTACAATTTTTGTGCTATTTTAATTTTCTAGGAGCCTTAAAAA
+ATGTGTGGCTACtgaaactgtgccccaaagagttaaagaaatcagtaact
+aacagaaattcttgagtctgcaggatggcagataagaaacaactcgctgg
+ccaggtgcagtggctcacacctgtaatcccagcactttgagggattgacc
+cactgaagtgggtggattacatgaggtcaggagttcgaggcctggcaggt
+tggtgggcacctgtagtcccagctgcttgggaggctgaggcaggaaaatc
+acttgaacccgggaatcggaagttgcagtgagccgagatcaggctattgc
+actccagcctgggcgttgcagcgaaactcctactcaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaacaacttgctgaaatgctgaagaaatgctgaaactc
+cctccctataagataaaagaagaacaagcagaaatctgttggaaccaata
+acgctgactggagtctgcacagaatgagcttgctgacatcacagcctgaa
+ttttcaacacaggtttcatgctgtccctgaatttgcatgagacccattaa
+gtagcttgaagaggtaactgcgaaagcccaaggactttccacatctcccc
+tttccttccactaataatcacctactaatctcagaatccaccgcctgaac
+cttttctaataaaaataactgccttaaagccaacacggggagacagcctt
+gagcttgatattcctgtctccttgtgagtcgacttgcaatacaaagcttt
+tcttttttcagaaccacagtgtcatagtattagcttctagggtatcaggc
+tggaatgcactggtgcgattatggctcactgtagcctcaatctcctggac
+tcatgcagtcctcccacctcagcctcccaagcagctaggaccacaggcac
+ttgccaccacgcctggctaatttttgttttttttgtagaaatgggatctc
+actatgttgtccaggctggtcccgtgctcttgggctcaagtgatccttct
+gcctatgcctcccgaagtgctaggaAAAGCCTCCCAAACTGGAAAATATG
+GGATGGCTTCCCAGTTGTTAAAACACCCTGATTTGGGAGCTGATTGCTTA
+TAAACACTAAGAAAAAGCTAAGAGCTGAGTTCGCCTTCCCATTCTGTTCT
+CAGGTTTCTCTCCTTATAGAGAGGTTCTGATCATCTACAAGCTTTGCTAA
+ATCTGGGGTGTTTCTCTACTGATTTCCTAAATGTTTGTAGTCTTTTTTGT
+AAAATTGATGATTCAATTTTATTCTCCTCTGAAGTAACAATAGATGCAGA
+GTCTGACATTTCTTCAGCTTTGAAGAATCTGCATTTTCTCTCCTGATCTC
+AAAACCTGTAAGAAAAAGAAATTGCAGATATCACCCTGTCCAAGGAGAAA
+GAGGGGGGAAAATAAGAGTTGTATTAAAGTAGTAGAGAGAAAACAGAAAC
+TGCTAAATAGAATCCCAAAGCCTTTTATTCCAAGTAAGGCTGAATTTTTC
+TTTTCTTTCTTCCCGTTTCTTTCCAGTGAACACTCACCTCTCCTGGAGTC
+AAGTCATTGTTTCTTTCCTTTGGAATCCTGCTATTCCTGCACCCATGGCT
+CTTCTCTAGGCTCCAGTGGGAAGTACAGGTCAGGGTTTGGGACTAGATAT
+ACTGGTCATAAGAAATACAGGGAACATGATAGTCTGGGTCACACTGATTT
+TTCCTGAGTTCAAGCCGATTTCCAGGACAGATGGCCTCTCCATATTTATT
+TCCTTCTCAATTAGGATTATTTCACCTGGAGCCTCTAACAGGCAGCTGGC
+tttttttgagacagggtcttgcagtgtctcccaggctggactgcagtggc
+acaatctcaactcactgcagtcttgacctcccaggctcaagggatcctcc
+caccttagcctctggagtagctgggaccacaggcatgtgctaccatgccc
+tgataattaaaaaaaaaaactctgtagagagaagggctctctctgttgcc
+caggctggtcttgaactcctggctcaagcaatcctcttgcctcggcctcc
+caaagtgctaggattacaggtgtgagccactgtgcccagcATAACAGGCA
+GTTTTTCAACATTAGAACAAAATCTAGGAGTACGAAAGGCATACTGGAAA
+AATAATAAACAAACATTAGAACAAAAACAAAATAGGGGGAAGATCCTTTT
+GTGCTCAATTCAAAGCTATTCTCCTCCAATCTCTGGGAAGAGGAGTGAAT
+TAATTCTGCTAGTCAATGCACTGATTTAGTTTTACCTCATTTTTTGAATA
+TTTTGATAATAAAATTATCTAAGAACCAAAATATCAAGTTAATCTTCCTA
+AAATTCTGACTATATTAAAACTGAGAACTATTCTCTTATTGAATCCAAGA
+GAAGAGAGAGGTAAATGTGGTAGTTAAACTATGTCCTGGATTAATTTCAG
+TTAAGAGACTTTCAAATAAGAATTAGTATCTGAACTGGTTTGGTTGGCAA
+CCAGCAAAAACAATCTTTACATGTTTGTTTTAGCTGAAGCCTAGAAGTAG
+ATTGTCTTGATATTAACCAAAACAAATATCTAAGAGTGTTTCCATCAATC
+CAGACAATTAGTAAAATGGTCTCCAGTGTGGTCTCCCCTGTGTCCTGCCA
+TGCCTCCCCTCACTGACAAAAGTTTGGGTTGCACCCTCTTTCCAAGTTCT
+TTCCTCTCCCTCCTCATCTTGACAGTTTACTGGTCTGAAAAAAAAAATAG
+GTTGGTAAATAGTGATCTAATATGCAAATAGAGGAATATGTCTAAATATT
+AACATTATCAAACAATATTAGTAAGACAGTTTGGTTAATGTTAGTCCAAA
+GGAAAATTTAAACTCCAGAACATTTAATCAAAATATAAGTGGCGTAAAAT
+GTCTCATTTTATCTTTTCATGAGGAAAGGTAATATATTCCATATTAATAA
+AAATAAAATGCATTTCAAATGAAATGCCATTTAAATTTGCTATTTTGTTT
+ATGATTGGATTTCAAAGCTAGGAGTAGGATCAAAGAGCATGTGGTACAGG
+TAAAAGAAAACCCtaaatccagcgctttgggaggccgaggcgggtggatc
+acctgaggtcaggagttcaagaccagcctggccgacatggcaaaactcca
+tctctactaaaaatacaaaaattagccaggcatggtggcgtgtgcctgta
+atcccagctacccgggaggctgaggcaggagaatcgctggaacttgggca
+gaggctgcagtgagccttgactgcgccactgtactccagcctgggcgaca
+gagcaaggctctgtctcagaaaaaaagaaaaCCCTAAGTCATAGATCAAA
+GGAATGCTGTAGTCAAGTAAACGAGGGGAGAGACCAAAGCTGGGGGGAGT
+GGCAAGTAGCAAAGGCTTAGAGTGGCAGAAGCTCCCGGAGGCTGAATGTA
+CCCTAAGATGAAAGACAGGAAAAGCATCGATTTAAAATGACGGCTATGTT
+GCCCAGGCTGGTCTCAAaactcctgggctgaagcaatcctcctgcctcag
+catccctaataggtggggctacagttgcatgtcaccacaaccagttaatt
+tttaaaattttttttctgtagagacgaggtcttgccatgttgcccaggct
+ggtctcaaaatcctggcctcaagtgattcttccacctcagcctcccaaag
+tgctgggattacaggcgtgagccacagtacgtggccTAGTCTTGAAAGTC
+TTAACACTGTAGATTTCACCAAATGTCACTTTGAAAACCAGGCACAGATA
+ACTGGCCCCTTGAGTACAAAGGAATCTGTAAGAGCTAGTTAGGGAATGAA
+AGAAGTCCCAGAGACAGAGTCTAGTACCCATGAGACCTAAAACCAGGAGT
+GGTAAGGGTTCTTTGTCGAAGATTCAAATTTATTTTTCTCTGCAACAGTC
+ACGAAGTCACCTGCAGCTGAGGATGAGAAAACACAGTTAAGTCCTCACTT
+AACATCACTAATAcggtaagtcctcacttaacatcattgatagggtcttg
+gaaactgggacttaaagggaaaagacatataatgaaactaatttattttt
+gtcatcaaccttataacaaaatgtgctttcacttaagataacagtttcca
+acctatctaggacattgaggacttacAGTGTTAAGAAAGTAGAATCTGTA
+CTGGTTTCAAAGGCGCTTACTTCTCTTCACTACTTACTTTTCACCAAAGC
+CCTAAAGTAGCAGTTCTTAGTCTTTTTGGCGGTTTTTAGAACTTGATGAA
+AGCTATGAACCCACTTACTAGAacatacagatacacacacacacacacac
+acacacacacacacacacacacacacacaTCCAATTTTGCATACAGTATC
+AAAAGGTTTACAAAAATCTCCAAACCCATCCATGGATCCTCTGGAACTGC
+ATTGGCCAGTATGGTAATACTTGGCAAGACTAACTCCATTTTAAGTGCCC
+ATTGGctaccatcacagaaagttctattggatagcactgCTCCAGACATG
+GAGGCAGCTTAAGAACCCTGGCCCTggccgggtgcagtggctcacgcctg
+taatcccagcactttgggaggccaaggtgggcggatcacctgaggtcagg
+agttcaagagcagcctggccaacatggcaaaactctgtctctactaaaaa
+tacaaaaattagccgggtgtggtgcgtggtgcctataatcccagctactc
+gggaggctgaggcatgagaatcgcttgaacctgggaggcggaggttgcag
+tgagctgagatcccaccactgcactccagccggggcgatagagcgagact
+ccatctcgaaaaaacaacaaaaaaCCCCTACAAATCTGCTGGCCTGTTAA
+CACCACTCCTAGTCTAATACCAGCTAGTCTGTTTTCCACATACTGGCAGA
+TCACAAAGAATTGGAGGAGGACTACTACCACCACTGATTTTGAATAACCC
+TGAAAGTTCATCtttttttaaaaaattaaattattattGCTAttttttga
+gatgcagtcttgctgtcgcccaggctggagtgcagtggcacaatctcagt
+tcactgcaacctctgcctcccaggttcaagtgattctcctgccttagcct
+ccccagtagctggaaatacgggcgtgcgccaccatgcccggctaattttt
+ttgtatttttagtagagacgaggtttcaccgtgttaaccaggagatgatc
+tcgatctcctgacctcgtgatccgcctatcttggcttcccaaagtgctgg
+gattacaggcgtgagccagcgcacctagccTAAATTCATCTACTTTTAAG
+TACCTATAAATAGCATAAAATCAAAAGGACCTTAGATAGAAAATGATTAA
+TCCCTCATTCTCCCTATCTCAAGGTATGTGTAGTTCTGCAAACATTCCCA
+TGCCACAGATTCTGCAATAATAATCTGAGTGGCTTTTCTTTTTTGAGATA
+AGGCACACATTCAGGAACTTGCTGTGCATGCGtaacagctactatttatc
+ggattcatactatgtgccaggtactgttctaagcatcctgtgtagctccg
+ctcatttcatcctaacccagtgatatgaggtgaggtgcgtatagtagtcc
+ctcaaaacaaatgaggaaactgaagtttggggtttagtgagattacataa
+gttgcctgagattacatagtaaatgtcagagAAAAGTGGTTTTGAGGCTA
+GAGTCTTCTGCAATTGGTTATGAGTCTAGAATCTATGTCTCTTGAAATAG
+GAATGTCCAatgatcgtgccattgcacttcagcctgggcgacagagcaag
+accctatctcaaaaacaaaagaaCAGGAATGCCTAAAACCACCAGAATGG
+TCCTAGGGAGCAAACAAGGCTTTCCAAACTGGACCTTGAGTGCTATGGGG
+TCGCTGGCTCTGCATCTGCCACGACAGCCTGTGGATCTGTCATCTTCCCT
+GGAATAAAATTTTTAAAAAAggccaggcgtggtggctcacgcctgtaatc
+ccagcacagtgggaggctaaggcgggcagatcactcgaggtgaggaattt
+gagaccagcctggccaacatggtgaaaccccgtctctactaaaaatacaa
+aaattagccgggcgtggtggtgggcgcttgtaatcccggctactcaggag
+gctgaggcaggagaatcgcttgaacccgggagggggaggtttcagtgagc
+cgagactgcgccattgcactccagcctgggcaacaagagcgaaactccgt
+ctcggaaaaaaaaaaaaaagaaaaaaactaaaaTATCAGTACTCTTTTCA
+CTTAGTCATCACAAACCCCTTTAATCCCATATTACCCTCTACTATCATGG
+TAGCCTCACCTTTGACGACAGactagctgtgtgacccaagtaaatgactt
+cagtgccaccacctgtaggaaggggctgctaatagcatctgcttcatact
+aacgtgttttcaggatcgatctgcatataaacgctcaatacaCGGTAACT
+GATTGTCACATTCTATCCCAGGACGCTTCCATTTGCGGATCTCATGGCCC
+GGAGGACCTGGGCCGCCTCACAACTGGGCAGCCCCGCTCACCGACACAAA
+GCCCACAACCGCGCCCAATAGGGAATCGGCCCTGCGGCCCTCCTGCCACT
+CGCCCCCAACTATCACAGTCCACGGCGGAGCTGGAGGCAGATCCCGCCCT
+TGCAGGGCTGGGTAAGAGACTGAAACTTGGAGAATGAACTGCAGGCGCTG
+CACATCTCGGGCAGATTTAAAATTCGGTCTAAAATCGGAAGCAGGTGCCG
+CGAACCCAGACCCGAGCGCTCCTCTGGGACGTCCAGCCGCAGAAGCGAGC
+CCAAAGCCCAGCAGGGTTCTCCGCGGGACTCGGGGTTTCAGAACCGCCGG
+GCTCTTGGGCGCTCGCCCAGGGCGCACGCGCAGTCGCGAGGCCGCGCCGC
+GGACTGCATCTCCCAGCAGGCCCCGCGCAGCAGGCCACGCGGCGCCACTG
+ACTGGGCGGGCGGCTAGCTCCCTGGCCTCCCCGACATGCCGAGGAGCCCC
+TGGCTTCCGGAGCCGACGAGGCCGCAGGGGCCAATGGGACCATCTTCAGC
+CAGCCCAGAGTAGCCGAAGCGGGTGGGGCCTGGCTTGGGAAAGGATtcat
+ccggggaagctgattaacaattcagatttccgggtctcaccccgacactg
+acgcactggagagcgcgtggccctgggatctgcgttttcccaagcgctcc
+ggagtaattctaacccaggttGCCCGCCAGTCACAACGACCTCAGGCTTG
+TTTTCTTCGCTTGGATCCAGCTGCCCTGCCCCCAGTCACTCCCAGAATTT
+CAGGGCGCGCCCCGTGGCCCCGCCTCTCGTCTCCAATTGGTCCCTCGCTC
+ATCCAGTCCCCGTAGGCCAATCTTCCCTTCTCATTGGTAGGCGGTGAGTG
+TGTGGAGAAACCTGACCTAATGGGCGCTGGAGTTCGCAAAACGTGACCCG
+GAAATTGGTCACGAGCAGGCGCCGTGGGCTTGTGGACGCCTAACTTGCGC
+GCTGAGATTTCCGGCGTGGGAGCAGAGGTCTGAGTCTTGCGTGGGTCCTC
+TATATAGGGTGAGAAGCGTGGCGCTCGGTTCCTGCCTCGGGGAAGTCCTG
+GCGCAGATGGGCCACGGGGCCGGCGTGGCGGCGCCTGGGACCGACTGAGG
+CCTAGGCGCCGGAGCCGGCCGCGCCTGGGCTGGAGCGGGGCTCCTCGGCC
+TGGACTGGGAGCCCCCGGCCCCGGGCTCCTGCTGGCGCCGTCCAACCTTA
+CATGGGTTCAGGGCGCCTTCGTAGGCGGGCACGGCTGGTTTCGGGCTAAG
+GCGCTCTGGAGACCTGACGATGGCGTCGGGCCCGGGCTCCCAGGAACGGG
+AAGGGCTCCTGATAGTGAAGCTGGAGGAGGACTGCGCCTGGAGCCAGGAG
+CTGCCCCCACCTGACCCAGGACCGAGCCCCGAGGCCTCCCACTTGCGCTT
+CAGACGGTTCCGCTTCCAAGAGGCAGCTGGTCCCCGGGAAGCCCTCAGCC
+GGCTCCAAGAGCTTTGCCATGGGTGGCTTCGGCCTGAGATGCGCACGAAG
+GAGCAGATCTTGGAGCTGCTGGTGTTAGAGCAGTTCCTGACCATCCTGCC
+CCAGGAGATCCAGAGCAGGGTGCAGGAGCTGCATCCGGAGAGCGGCGAAG
+AAGCGGTGACCCTTGTGGAGGATATGCAGAGAGAGCTTGGGAGACTGAGA
+CAACAGGTGAGAGAGAGAGAGAGCTGTTTTATCTGTGGTTTGTTTAGCCC
+TGAGCACTGGGACATTGCGCCCCCGGTCGAATTCAAGTAAATTGCCCTGA
+GTAGACCTTACGTGGGGAAGAGGACTTGTGATTTAACCTGGAACACTCAT
+CCTCCAGATTTTCCCCCAAATGAACGAAAGCAGTGAAGAGTGCCCTGTTT
+CCACGCGGAGGCGGTGTCCCTGCAACAGTTAGTGTTAGCCAtggagttag
+atcgccagcgttcaaatcctcaatctgctagtactagctttgttactttg
+gcaagttacttgatctctttcggcctgttttcctattcgtaaaatgagga
+tattaacatactttctagggcttagagggagagcagcatgtaaagttgtg
+aacactactagcttatgagtgcttagtacttgttacctgttgttatGTTA
+GGGTCCACGGTCTGGTCTTCTCTGCAAAGCTGGGCCTCCGTTAATTGTGA
+ACTTTGAAAGATAATTTGGCACCGAGGCCCTGAGGTCATTGGTCCCCAGG
+GCTACCCCAATTTAGCCTATCCTATAGTGAGGAATAGAAGCACCTAGAAA
+AGGTGGGGAGAGCAAAAGGGAGTGAGGTGTATCTTAAGAGCTGTGTGGGG
+AAGGTGTGCTCTGGGAGTGGGCCCTTTCCCTAACCCCTCCCCCTGCACAT
+GGGATCAAAAAAGCCTTTAGTGTAAACCATTTTTCTGTTACCTGGGCCCA
+AAGGGATCGCCTGAGGTTCTCTGTTGAAGGTTTGCTCTCAGTATCCTATA
+CTAATTTCCCTTCCTCTTGGGCCCTGTTGTGATGATGAGTGATGTGGGTT
+GGTTCCCAGGTCACAAACCATGGGCGGGGAACAGAAGTGCTTTTGGAGGA
+GCCTTTGCCTCTGGAAACAGCACGAGAGTCACCGAGCTTCAAGCTGGAGC
+CAATGGAGACTGAGCGAAGCCCTGGCCCCAGGCTGCAGGAGCTGCTAGGC
+CCCAGCCCCCAAAGGGACCCCCAGGCTGTAAAGGAGAGGGGTGAGGCACA
+GTTATCTGGGCAGGTGGGAGGGAGGAGGGGCTTGGGGGTTGCCCCCGACA
+CTAGCTGGATGTAGCAATGATGCGAAGGAGAAGGAATTTCTGAAGATCAG
+GTTCTCACCTGTGGAATGAAAGACCTGCAGTTGGTGGTGTGGGTTCTCCT
+GGGGCTGGGGGAAGGGAAGGGAGTCTCAGTAGAGCCCTTTTTTATGCAGA
+ACAGAGGCGATTTAGAACCACTTGAATGACGCAGGGTTTGGAGTGCTACT
+CTTGGTACTCCTTCCCTCTCACCCTGTCATTTTGGATATCAGCTGATTAG
+GCCTCTGTGCAGTTTAGCGTCATTCCCAAAAGCAGAGGCTGGGTGTTGGG
+GAATGGATACTGTGTTTTAATAATCCTTGGGTTGCCAAGAGTTAGGAATG
+CCATTCTCATTATAATTTCTGTCACCTTCAGCATTATCTGCTCCCTGGCT
+TTCTCTTTTTCCTCCTGAAGGGAACATGGAAGACAAGGAGATGACTGGGC
+CCCAGGTGATGTGGAAGTTTCCATTGTCTCCCCCCAGCACCCTTCCTCCC
+CTGAGTGTTGGGGGTGGGGGTTCTCCATGTGGAAGGTCCTTTGTCCCTTA
+CCACAGCGTCTCCCCCACTGCTTTGTCTATTTCACACCTCACTTGGAGGC
+CTGATACCCTTCTTCCCCCCTGACATGTGCTTGGCATCCCTGGATTTTGC
+CCCTTTAACCCATGACTCTGCTTGAATTGTTCTTGGTGCATCAGGGGCTA
+AAGGAGATCTTGTGCTGTTTCAGTTGCCTGAGAGCTTAGAGGACGTGGCA
+ATGTACATCTCCCAGGAGGAGTGGGGGCATCAGGATCCTAGTAAGAGGGC
+CCTCTCCAGGGACACGGTGCAGGAGAGTTATGAGAATGTGGACTCACTGG
+GTAAGGACTTCTTTTCCAGGGATGATGACTGCGCCATTTCTGACCAGGGT
+CCTGCCCGTTATTCATTCACCTCCTGGACACAGACTCTGAGTTTTGCCAA
+GAAGCCTCCACAGGAGACTTCCCTTTGTCTAAAGTCCCCTGTACGAGAGT
+CATGTATCTGCCAAGTGGTACAGTTGGCACAGGCAGCCCGGGACTGGAGT
+CCCAGCTGCCAGAGCCTAAGGCGAGTCTGAGCCATGTGCACTTCCTAGGG
+CAGAGCAAACCCAATGCGGTGACAACCTGCCAGCATCACACACATGCAGT
+ATTCCAGGATGCTGGGGGGCTCTAAATGGTTGATTCCTTGCAATTTTCAG
+ATGCTTATTCTTATGAGCTCGCCAGTGTTTCCTGTGTTCCGTTAGTGTTT
+CTAGGCTCGTCCCCAAAGACAAAAATTTCAGGGGTAGTAGGATCAACATT
+CCAGCCTATCATCTCTCACAGCCCATAAAAATTCAGAAAGTGGGGAGGGT
+CTTGTGGAAATTTGGAAACAATGTATAGCTCCAAAGTAGGCCATATCATA
+AATTAAGATTTACCTATGTCTTGTACTGTACTCAGAGTTTTAAAATTATG
+CCTACGGaatatgacagactgacatatagttggatttaggtggaggatat
+gcttgtatttattgtacaattccctcaacttttctgtatgtatgagaatt
+cttttaataaaaaGTTGGGGAAGTCTTAACATAAAACAAGACTGTGTGTA
+CATTATGATTATACCTATGTTGAAACACACCAGTAGAAAGACTCACTggt
+gtggtggtggtagtcccagttactcaggaggctgaggggagaatcacctg
+agcccagtaggtcaaggctgcagtgagctatgatgatgccactgcacctc
+aaccaggtgacagagtgagactctgtttcaaaacaaacaagaCACACCGC
+ACATTGTTTCCATATATCAGGTTTGCCTAAAAAGTATCACAACTGTACAT
+TTGTTGACACTAATTCTGCAAAcgcaatcttgctcactgcaacctctgcc
+tcccgggttcaagtgattctcctgcctcagcctccagagtagctgggatt
+acaggcatgcgccaccacacccggctaattttttgtatttttagtagaga
+caggatttctccatgtaggtcaggctcatcttgaattcccgacctcaggt
+gatccacccgcctcccaaagtgctggaattacaggtgtgagccaccacac
+ccggccttttttttttttttttttttttttgaagtgagtctcactctgtt
+gcccaggctgctctggaacttctgggctcaagcagtcttcctgccttagt
+cAGGAAGTGTGCCACTGTACCAGTTTCCATATTACTTTTCACTGCTGTGA
+TGTCCAAAGTTGAACATGGCCCTTTTAGTGAGAGATGCTAAATAGGAAAA
+GATCAGATTACAGCTTGTTGGAATTAAACTTCTGTTGGAGTCCATGTTTG
+CTGGAGGTGGAGGTTTTTGTTTTTCTTTTTGGCACAGCATAGAAATGGCA
+CTTGTGGGTTTTAATCTCATGGTCCTCTTAGAGCCCTGGGTCCTTTTCTG
+ATTGTCTATTATGTTATATTTTCTTTCCCTGGAGTTGTCCGGTCAAATTT
+AGTTCTATTTTGTATTTATATGTAGAGACAAGGCCCTTTTATGATATTAA
+ATGGATTATTCAAGGAACTGACCATGTTCATTTTATAGTTATTTCAATTA
+CAGTAGTGTACATTCTCATTGCAAAAAAAAACATTCCAAGTACCATGaat
+atttaaaaaaaaaaaaaattggccgggcgcagtggctcacacctgtaatc
+ccagcactttgggaggccgaggcaggcagatcacttgaagtcaggagttc
+gagaccagcctggccaacatggtgaaactccatctctactaaaaatacaa
+aaattagccgggtgtggtggtgcacgcctgtaatcccagctacttgggag
+gctgaggcaggagaatcgcttgaacctaggaggcagaggttgcagtgagc
+ggagatcgtgccactgcactccagcctgggcgacagagtgagactctgtc
+tcaaaaaaaaaaaaaaaGTCTCCCTCCCCTAATTTCTTTCTCTAGAGGTA
+TCCACTGGGAACAGTTTGTGTATATTCCAAGTAACTGCTGTCAGATTTAT
+GGAGCATTCTGTATTTATCCACTGAGGGCAGGGAACAAGACTGTTTCCCT
+ACCCTGGTAGAGGAAAGTGGCAGTACAGAAATCTGTTTCTTTCATTGTGA
+ACAGAGTCTCACATTCCCAGTCAGGAGGTCCCAGGCACCCAGGTGGGACA
+AGGAGGAAAGCTATGGGATCCCAGTGTCCAGAGCTGCAAGGAGGGCCTGA
+GCCCCAGAGGCCCAGCTCCAGGTAAGGAATGAAGACAAGTGGCCTGCGCA
+GCAAGCAGCAAGGCTCTTGCAGTTAAGAGTGAGGCATTTtttggttttgt
+tttgttttgttttgagatggagtggcactcttgttgcccaggctggagtg
+caacagtgcgatctcggctcactgcaagctccgcctcccaggttcaagcg
+gttctcctgcctcagcctcccgagtagctgggattacaggcatgcgccac
+cacgcccagctaattttttgtatttttagtagagtcggggtttctccata
+ttggtcaggctggtctccctgacctcaggtgatccacccacctcggcctc
+ccaaagtgctgggatttacaagtgtgagccaccgcccccagcAGAGTAAG
+GCATTTGAGGATTTGGGTGCAGGGCCGGCCCAGCACAGCTGCTAGAGAGG
+TACATTACGTCCTTTGACCCTGCCATTCTCCATCCCAgtgaggcaagtga
+ggaacccagggtgcagagttcaaggaggcccttattctTGAGCTTACTTG
+TCCCACCCTACTCTCAGCCCTGCTCCATCCCACCCATTCCTGAAGGGCAG
+AATCGAGAGGCTCAGGTGGAAAGGAAAATTCTAAGACTGGTCTCGGCTCT
+GATTCCTTGACCAGTGGCCCGACCCTTTATCCTGATGCTTCTCCAGAGTG
+CTTTACCTTTAGGAGAGGATGGGATTCTGAGGTAGAAGCAGCCCTTCTGG
+GCTGCTGACCTAACAGGCAGCGGCAGACAGGTGGGATTTTCTTTTCTCCA
+GCATAGAAATAATGTACGGGTTTGGTTTCTCTCTCTCTACCAGGAGAAGA
+GAAATTTGAGAACCTGGAAGGTGTTCCGTCTGTATGCTCTGAGAACATCC
+ACCCTCAGGTGCTGCTTCCTGACCAGGCCCGAGGGGAGGTGCCCTGGAGT
+CCTGAGCTGGGAAGACCTCATGACCGGTCGCAAGGGGATTGGGCGCCTCC
+CCCAGAGGGTGGAATGGAGCAGGCCTTGGCAGGAGCCTCAAGTGGCAGAG
+AACTGGGGCGACCGAAGGAACTGCAGCCAAAGAAACTCCATTTATGTCCC
+TTGTGTGGCAAAAATTTCTCTAACAACTCAAACCTAATTAGGCACCAGAG
+AATACATGCAGCTGAAAGACTGTGTATGGGTGTGGACTGCACTGAAATCT
+TTGGTGGGAACCCACGTTTCCTGTCACTACACAGAGCACACCTGGGAGAG
+GAGGCCCACAAGTGCCTTGAATGTGGGAAATGCTTCAGTCAGAACACCCA
+TCTGACTCGCCACCAACGCACCCACACGGGTGAGAAGCCCTATCAGTGCA
+ACATTTGCGGAAAATGTTTCTCCTGCAACTCCAACCTCCACAGGCACCAG
+AGAACGCACACTGGGGAGAAGCCCTACAAGTGCCCTGAGTGTGGGGAGAT
+CTTTGCTCACAGTTCCAACCTCCTTCGGCACCAGAGAATTCACACTGGAG
+AGCGACCTTATAAGTGTCCCGAGTGTGGGAAAAGTTTCTCTCGGAGTTCA
+CACCTCGTCATTCACGAAAGAACTCATGAGAGAGAGAGACTTTACCCCTT
+CTCTGAGTGTGGGGAAGCTGTGAGTGACAGCACCCCCTTTCTTACAAACC
+ATGGAGCCCATAAGGCAGAGAAGAAGCTCTTTGAATGTTTGACTTGTGGG
+AAAAGCTTCCGGCAGGGCATGCACCTCACCAGACATCAGAGAACACACAC
+AGGAGAGAAACCGTATAAATGTACCCTTTGTGGGGAAAACTTCTCTCATA
+GATCCAATTTAATCAGGCACCAGAGAATCCACACAGGAGAAAAACCCTAT
+ACCTGTCATGAGTGCGGAGACAGCTTCTCTCACAGCTCCAATCGGATTCG
+CCACCTGAGAACGCATACGGGAGAGAGACCCTATAAATGTTCTGAATGTG
+GAGAAAGCTTCTCTCGGAGTTCCCGTCTTATGAGTCATCAGAGAACTCAC
+ACAGGTTAGTAACAGTGGGGTTTCTCTTTGCCCCAGGTGAGGTGGCATAT
+TCAGAGGAGCCTGTTGGCAAGAGCTGGTATTCCCTGCCCAGCCGACCAAA
+TGACCTCTGCATTCTTCAGGTAATGGGGGCTCATTGTGAGGGAGGTGCAG
+AGGCAGCAGAGGATTGGCATAAAACTGAAAAGGAGTTCTGTCTGCATGAG
+AAAGGATGGCAAGTCTCTGAGGTGACCTCAGGGTGGAATTCTCTGTTAAG
+TCCACCCTGCCCCAGGGTGCTCCTACCCTCTTGGTCTTTTTAAAGCCAAG
+GTGCGATTTGGGCACCTGACTGTCCAGTTTACCTTAACAAGTTTGGGAAT
+CCATGTGATGTTTTTGATACTTCTTCCTCATTTGGGACATTCAGTAGGAG
+CATTTGGGCTTCCGGGGCCCCTGAGACCAAAGAAGAGGGGCCAAGTACCC
+TGGGAAATCAGCTGAAGGTCAACAAAAGACTGGTTGTGAGTTGCAGCTGT
+CCCGAAGGCCCCAGTTGGGAAGCCATGGGCAGTCCAGATCAAGCCACCAC
+GTGCCCTACGATGGCCTAACAGGAGTGCCCATTGGCAGATTACACATGTA
+AATATGACCTCAGACAAAAAGGAACCAGAGGCCCAAGGGCAATAATAAGG
+TGGAATTTGCAGGTCAGCCCAGGAATTGGCAGAGGAAGTAGGTGTCTGAT
+AACCCTTTGTGGAGAATGAGATTCCCCCCACCTGTGTGAGAAAAATAAAC
+AGCTCTGGAGTCTTGTTCCTGACTCCAGAGGAACGAGAGCATTCCAGGAA
+AGAGAGATTCCCTGGAAAATTGAAAATGTGAATCCTAGGGGGAAATTGGG
+GATTGTGTCTTTCCCTGTTGAAAATGTTTGGATGGGAATAAATATCTTCA
+GGAAACATAAATGTCTGTGAGTCTTCAATGAAAGCCTCTGTCTAGACCCC
+CGAGTGTTGATCTGTCTCCCCTCTGCCTTGGTCAGAGGCCCTGCTTTCTC
+ATAGACTTACTGGGTTGGTCAGGAAGATGCTGACAAAGGAGGCAGCAGAC
+AGGCAGAGGCAGGTGAGGGCCTGGCAGCCTCCAGGCTGGGACTGCCATGT
+GGTAACAAAGGGTCAAGCCAAATGGCTGCTGGGGTGATGCTGTCATAGGG
+TCTCTAGAAAGTATTCTTTCCTTCTGTGGTCTATAGCAGTAAAAATGTTT
+TCAATTCTTTGTTTAGAATGTTTACATTCTTACTCAGTAGCTGAGGAAGA
+TCTGACTCTTAGAGAACAGGATATTTTGGTCTTGCAACTGATTTCCAGGG
+TGGAAGTTAAGATGGTCCCAGTATAACTGAGTTATTGATTATTAATGGTA
+GGAAGATATAGGAGATGGCGCAATTATTAAGGGAAAGCATTATATTtatt
+ttttggtagaggtggggtctcactatttgcccaggctggtcttgagttcc
+cgagctcaagccttcttcccatcttggcctctcaaagtgctgggattact
+agcatTGCATTTTAGAATGGCATATCAGAAATAGGAATTCTAGTAGTGTG
+TATCTGTGGGAAACGGGGGAGTATTCTAAGAGTAGGAAATCGGATGCCAG
+GAAAACACCTCAGGATACAGCCCCGGAGGAAGGTATCCAGCTGTTCTTCG
+GGTGAAAAAGATGAAGAAACAGTCCTTTGGGAACAGGCTGATGGATATAG
+CAACTTGAAGTCATGGAAACAGCGCTCCATTGATCCTTCTCTCAGCCCTG
+CCTCAGTTTAGTATGTGTTTTTCTTTGGTTGTCTGAGCCAGTTTTTTAAT
+ATCTCACTATTTCTCATTTCTGTAACTTCCTCTTAATCAGCTTGTTCACA
+GGAGGAGGGCAGTGGTGGTGTGGGGGTTGAGGGCAGGGAAGTGGAGGGTT
+AGGATTAGAGAGATCAGAGTAGGATCAACAGTGGTAGGAGCAGGACCACA
+CTCCAGTGGAGCAGTGCAGGGCCAGCCAGGCTGCTGATGTCATGAATTGG
+ATGGAATGTAAAGCTGGTGTTCCTACAAAGCACTCTGGTTAAGATGGCAG
+TTTATGTGGACAGAGACTGGAAAGCGCCCCTTCCATCTACTCTCCCTCCC
+TTGGTAACATCACCCACACAGATCTTATGATGTGGTCCAACTGGTGCTGC
+TCATACTTGGAACACTGCAGCTTGAAGCTGGGAAATGACTCTCAGGTATT
+TGCCATAAAAAGGCATTCCATTGGAACGCTTCACTCAAATCTTCAGTCTA
+GTTCCCCTTCTAGTAAACTTCACATGCTTAGCTGTTCTTGGCCTGTTTTA
+ATGAGATGACATCACAGAAAATAACTACATAAAGCAGCACTATGCCTGGC
+ATGTAAGAAAGTGCCAACTGTCGACAGATGATCCAAAAGATTTCCTTCTA
+AGCATCTAACACTGACTGAGGTCACTGAAGACCACACTGGCAGGAATTTC
+AGGGACTGATGACATCTCCTTCCCTTGTACTCATGTTTGAGAGAGTAGGT
+CTGATTCCCTTACTGCAGGCCCCCATGAGGTCtgatacggttcggctctg
+tgtccccacgcaaatctcatctctaattgttatccccatgtgtcaaggga
+gggacctggtgggaagtgcttgcatcatggggacggttttcccctatgct
+gttctcctgatactgaattctcccgagagctgatggttttaaaagtgtaa
+cagttcccccttcacttgcgtgcttgcttgttctctcttgccaccttgtg
+aagaaggtacctacttcccctttgccttccgccataattgtaagtttctt
+gaggcctccccagccacacagaactgagtcaattaaacctcttttgtttg
+taaattacgcagtctctgtatctttatagcagtgtgagaaCTAGGTCACT
+GCAAGAGATGTCCAAGTTAGTGCTTTTTCACATTAATACTTTGCCCACTA
+GGGCTCTTGTAAAAGAAGCCAAAACAGTTTGAGTGGCTTTTATGTCACAG
+GGAGACTAACCCTGGGACAATAAGGACCTCTAGCCTCTAAGTCCAAATGG
+GTGCAAAGAGGTCTTGGGAGATGTGGAGTGACCCTGAGCAGCAGCCACAC
+ATCCTTAGCAAAGGTAGCACATGAAACCAGCAGGGAGGCTGGTGGGTGAG
+AACCAGTGCCACATCTAAGCCCTGTGAAAAGGCCTGGCAGCGTCAGGCTG
+GGGAGCAATGACAACAAAGCCAGAGGTGGGACACAGACTGGAAGAATGTT
+TTAAAAGCACTGAATTTTTCAGAAAAATCCATCAGAAGTCACTTTAAAAG
+TTTTGATGGCTGTAATGAAAGAACTTTTGGGTCTCAGCACCATAATCTGA
+AATTTCAGGTTTTAGGCTCAGCACttttttgttttgttttgtttgagacg
+gagtctcgctctgtcacccaggctggagtgcagtggcacgatctcggctc
+actgcaagcttcgcctcccgggttcacgccattctcctgcctctgcctcc
+cgagtagctgggactacaggcgcccgccaccacgcctggctaattttttc
+tatttttagtagagaccgggtttcaccatgttagccaggatggtctcgat
+ctcctgacctcgtgatctgcccgcctcggcctcccaaagtgctgggatta
+caggcgtgagccaccgcgccccgccTAGACTCAGCACTTTTTAAAGAAGA
+GTGATTCATTACATTAACTGATACTACTTTGGAATGTGCAAAATCACCAC
+TGCTTTAAAACTTGTAATTTTTTCTAAGTGTTTCACAAGCATTTGAAACA
+ACTAAGTCACGTAAAGTGTCTTAATGTGTGTTACAGGAAAACCAACTAGC
+AAATTTCTTAGCACTAGGAGACTTAATTTTGGAGGTCAGGAACTCAGGAA
+TAGCTAGATGAATTCAAGCAAAATGCatttatttatttatttatttattt
+GAAATATTTTCTTTTACTCTTCAGTCTAGCTTGCAAGCACTCCCAATTAT
+TGACTTCTGTTCTTGAAAGGGCGGTTAATATTTCCTTCCCATCATATACT
+TTTTAATAAGACCAGCTAGACCTTGCCTGAGTGGTACAGTGAAGAGGCAC
+TGGGAATGATCTAGGTTAAGTTCAACAACGACAAAATGGTTGAGGAAAAA
+TGACTCAGATCACAAAAAAATTCTGATCTCCCAGTTAATGTTATTGCTCT
+CAATTAGCTTACAGAGACACCTTAAATGTCTCAAAAGATTCTGTCAGAAA
+TCCGGTGGCTCTCAAGCATCCCCAACGTGCTCCAAGGAGAGTAGTATTTC
+TCCAGGCAGCGAGAACGGGAAAGAAAAACATTAAGGAGTATCGTTCTGAA
+GTCCAGCGTATGTTTTTGGACATCATGAGGAATTGCTTGCCCTCCATTCC
+GTTCAGGGAGGCCAGTTCCCCACTCCCGAGGTGCTGCTGCCCTTGAGGGA
+GTTCTCGGCTCTCCTGGGCCTCCCGGCAGGAGTCCAGCCCCAGCACCCGG
+CGCAAGTGTGAGTGCCTGGACTTCTCGGAGAAGTTCCTATCCCCAGGAGT
+GATTTGCAGAACCAGAGACTCCCTTTTCAGGCTTGGGCAAAGCAGACGCC
+TCCTGCTCCGCATCGGCTCACACGCGGCCGGGCCCACGAGCCTCCTCCAA
+CCGCCGCCCCGGGCCTCGGGGCTGCCGCTCCCCTCAGCGTCGGCTCTGCC
+CCCAGAAGCGAAGGCCGCCCTGCGCCCGGTCCCGGCCTTTCCCTGCCCTC
+TGGCCGGTCCTCCTCCCGCGGCCGTCCCGGGACCTGTGCCCAGACCCCTG
+GGGCCACGATCACGCCCCAGCCGCCCAAGTCACCGCCCCTCCCCTCCCTT
+CCAGCGTTCCCGCCCGGGCGGTGTATGGTGGCTCCGGTGTATGGTGGTTC
+TCGCACGCACAGCCGCAGGGGTTTCCTCTCCTAGACTCGAGGCGGTGGCG
+CACCTGCACCCTCTAAAACTCCCCCGTCGGCCCTCGCGGTCTAGCGGGAG
+GCGCGGAGGGCCGAGCTGGGGTGCGTGCGAGCGGGCGCCAGGAAAGCGCG
+GGGCCGCCCTAGGGGCTAGGCCTTTCTTTAAACAGTGGGAGGCCCACGAA
+GTGTCTGAAGCCCGAGGCTCCCCTTTTTGTTTTAGTTCGCTCTCTTCTGG
+TAAGAGAATAAGGGTCGGGCAAGAATGGAGAGGGGACAGAAAAGGAAGGC
+AGGGCAACTGAAGAGGCAGAGTCAACGCAGAAGGCGAAGGGAGCCTGGAC
+CAGGGCAGGGCAGTGAGGACGAAGAGTGGAGAGGAGAGATCCAGGAGGTG
+GAGCGGTCAAGACTTACGTGGGCCGAGACCCGTCTAAAATCTCGTAGGAT
+GTCCCCCAGGGACACTAGCCTTGACCTGTCTTTCCTGCTCTTCTCCGCCA
+GAGGCCCCCAAGGCAACGGTCCAGGGACCTTGCAGCTTGCCTGGGAGATA
+CACGTGCCCACCGCAGAGACTGAGCCCCTGCTTCACAACTTTAAACCCAG
+CTCAAAAGTCACGCACTGTCCTCTCAGACACCTCCCCTGCTATCCAAGTC
+TCAAAGGCCCTCCCTATGCTCACTTTGGCTCCGGCCCTTACACATCCCAT
+GGTGGTTTGTTCTCATTCATTTTCTTGGTTATTCAGAGCTGAATCTCCAA
+CAACATGCTATTGTCTAGTACATGAAACAGTTAACAGGAAGTTTCCAGAA
+TCAATGAGTACTTTTGAAAACTGGGGTGACTCTCGGTCACTCTAGGAATT
+TATTATCACTAAAAAGAATGATGATGTTTGATGCAAAGACCCAAACTAAA
+AGGAACTAGAGAGCTGCCCAGAGTCCTCATCTGCCATCCCCCTCCACTTC
+CACAATCCATCCTGTCCCAGGCTTGGAAGGTCTTTCAAAAGAGGCAAAAC
+ATCAAGCAAAGAGTAATTACTACCTTCGCCCTCACCCAACCCCAGCTTGC
+AGTCATTATGGACTAATCTTAAAAAAAGAAAAAGTCAAGCTGCTTGATGT
+TAAAGGTCTCCCATCTTCCACCAGGCTGCAGACTGAATAAGGCAAGAAAG
+CACAAATCAAGCCTAAACTGAATGTAAAAAGGATGCCCAGTGGCAATGTT
+GATATATTTTTTCTACAAGTTCTGGGTAATAAATAAGGCACAAAAAAGAT
+AACTACTGAATTTACAAGGTGAAAATATCAGCAATCACTACTAATAAAAA
+AGGAACCCACTTACAGCAACAACAAACCTACCTAGGAACAATAAAAAAAA
+TGAGAACTCCATTAAATGAAAACTGCACTTACAATTTGAAAGGAGAGAAA
+AGTAATGTAAATTCTTTCCAATTTTACTTAAATTAGGAATAAATTCGCAG
+AGGGAGTTGGTGTCTGGAGGAGGCTTGAATAAATTTTATGCTGAAGTTGA
+CTTAAGATAGTAAGAATAGCTTGTATATTTTCAAACATGGAAAGTGGGCA
+TTTGCTTTTCATTAAAATTCACAggccgggcgcagtggctcacacccgta
+atcgcagcactttgggaggctgaggcaggcggatcacgaggtcaggagtt
+caagaccaacctgagaaacatggtgaaacctcgtctctactaaaaataca
+agtcaggtgtggtggcacgcgcctgtaatcccagctactcaggaggctga
+ggcagaattgcttgaacctgggaggtggaggttgcagcgagccaagatcg
+tgccactgcactccagcttgggtgatacagcgagactccatctcaaaaaa
+aaaaaaaaaaagagaaaTTCATATTAGCCAGTAATGAAAATGGCAAGGTA
+CTAGAGCAAGAGTGGACCCCAGTAGTTCTGTATTTAGTCACTAATTTTAT
+ACTATAATTGCCTAGTATTCACCAGTGTAACAGAATACCCATCTCAGAAA
+CAGAttcttttttttttttttttttttttttttgagacggagtctcgctc
+tgtcgcccaggctggagtgcagtggcgcgatctcggctcactgcaagctc
+cgcctcccaggttcacgccattttcctgtctcagcctcccgagtagctgg
+gactacaggcgcctgccactgcgcccggctaattttttgtatttttagta
+gaaacggggtttcaccatgttagccaagatggtctcgatctcctgacctc
+gtgatctgccctcctcggcctcccaaagtgctgggattacagccgtgagc
+caccgcgcccggccAGAAACAGATTCTTGAAGATAATATATGAGAAAGGA
+AACACTGAAAGCCAATAAGAGCTAATTATCCAAACAAAGCTTGTTATTTG
+CAAATATCAACTCACCTGACACCTTATATTAAATAGGGaacaaccataaa
+gataccattcttttggttacaaaattagcaaaaactaagagcttaacaat
+attcaatgttgggattggtgcattgggagaagtactttcaaaataatggt
+gggaatgtgaaagcaatttaacagcgtgtatcgcagctttttcaaaagtt
+cattctatttgacctggtagttcaactGATACGTTACATCCCCTGGTGGA
+GTATTAAAAAACCATCAAATGTGAGGTTAAGAGATTTTAATGACCTAAGG
+GAAACTCTCAGAAatagtgccgtatgatggttaaaagcctgagctttggc
+attaaacagaatttaagtctcacctctgctgtttaccagtttatgtgacc
+tttgtcgagttacttaatctctctaaatctgtttccttatgtatttgaaa
+agggaagtcattatTATGAAGACTAACATATATATACGATCCTATATACT
+CAATAAATGCTAACGTATTAGTAACAAACCATAAAATATGTTAAGACAGT
+AAGAGATAAGGTTTTATTTACAATGTAATCTGCCTATTTAAAAAATATAT
+GGTATACACCGAAGTGTTGAGGTTATCATTAGTCAATAGAATTGAGTGCT
+TTTTATCTTTTTTTATATATTCCCTATAATCAGCATGTTACTTTCACAGT
+AAGAGGAAAACAAACACTAAATAGGTAGTAACAGAGTTAAGAAAGCAGAG
+TGTGTTTTACCATTAAATTGAAAACCTAATTTATCCTTATCTTAAAGCTA
+ACTAGAACTAGTCAGCACAGTTTCTTTGTTATACGATATGATTACAAACT
+AATGCTTTTCGCAAAGGCATTCCACCTTAGATAATCTGGGACAATACTTC
+ATTATTCAGATCCTTGTGtaaaatttaaaaaaatgaatttatgaaacaca
+aatttaaataaatttaaaGAAACACAAATGTATTATTTTCAAACTGTAAA
+TTTTATAACCATTATATAAATGGGCACTGATATACAAAATAATGTCAGTT
+GCTAAAACAAGACAATTCACAGCTGGCCTACATCATATAATGGCAGAAAT
+CTTTAAACACAAAATCTAATGATTAGAACCAGAAGTTGAAGGCCCACTGA
+AGGAGTCCTTAATATTATGAGGCCTAGGTTTCAAAAAGCTACCAATTCTA
+GAATGGATTTTACTCTGGAACTGTTTCTTGACTATTTCTTGTTGCATCTC
+TTTCAGTGTGAAGTGGAATCTCTGAAACTCAGGTGTGGCATCAACAAAGT
+CAAGAAGGTAGTCCAAACTCTCTCTTACAGCAGATAATTTAAATTCAGCA
+GTCTGCTTCTCAGCTTCTCCTCCTTTTTGAACAACTTCCTTTGTTATTCC
+ACCTTTGGTTTTTAGGAGACAACCCTTTTCTTCATCTCCATTTAACCACA
+CCCTATCATCATCCAACTTAGTTTCCAACTCCCCACATTTTTCAAGAATT
+TCTCTATAATCCCCATGTTCTAAGCCTTGAAAATCATATTCAGGTTCCTT
+TTTGTAAAGAAGATTTTCCCATGCATTTGCTATGGTTATTTGTTTTACTT
+CTTCCCAACTTTTTGCCCAGTTAAAAATTGCACTTTTTATATTGTAGATT
+TTAATTTTGGAAACTCCTTTATCTCCTTTCTCTTGCTCATCATCACTTTC
+TTCAAATATTACAAGACTCTCTTCAAGTTGCTTCCATCTATACAGCCGTT
+TGCAGCTCAAGatcacaccttgattcattggttgaatcaaggttgaagtg
+ttatgggggaagaaCATACATTTTATTCGACCATCCTCACTGGTTAGGGA
+TTCAGAGGAAGGATGAGCCGGGCAACTGTCCAGAAGTAACAATGCCCTGA
+CGTCCTCGTCATGAAATCTTAGAACATTAAGTTGAAAATGTCGGACCTCA
+GGAACAAAGTTTTGAAAAAACCATTCTGAAAACAATTCTCTGGTGAACCA
+AACATCTTTACTGGGTTTATATATCACAGGCAATGTACTTGTGTCCTCTT
+TCACACTTTTGGGCAGTTTTGATTTTCCAATAATGATTGACTTTAATTTA
+TGAGTTCCGTCTGCATTTGCACATAAAAAGGCAGACAACCTTTCTTTGTT
+TATTTTCTTCCCTGGTAGGCAGATATCTTTCCTACTTGCCTGAGAATTTT
+CTGGCATTGACTTCCAAAAGAGGTCTGTTTCATCCCCACTGTATAGCTGA
+GCTAGACACAGTTTCTCCTCTTTGATTATCATGGACAGTTTTTGTCGAAA
+TGGCTCAACATTTTCAGAAACTGAACTTAGGACTTGTTCCCCACATCCTT
+TTCGGTTCCCAATTGCATGCCGATTTCGAAATCTAAAAAGCCAACCAGTG
+CTAGCTTTGAAATCTGTTCGCCCAAAACACCGTGCAAATCTCTCTGCAGC
+AGCCTGAAGCTCCACGCCTCTTACCGGAACACCGGCTGAGCGTTTCTGTT
+GGTACCACATGTAGACCGCATCATCTACATCACCATATTTGGCTCCCGTT
+GTCCTCTTTCTCTTCTCAGCCCCTACTAATGGCATGTCCTGCTTCAGTAC
+AAAGTCCAGAATTAACTTCTTATTTTTTTTAATGTCATAAAATGTTGACT
+TACTGATTCCAAATTCATCCATTACACTTTTAAGTGATCGTCCAGCTTCA
+ATTCTACTTAGAACCTTCATTTTCTCCTCCAAATTCAGTGTTGTATATTT
+CCCTCTCTTATTCATACTGAATTTAACTCTGAACCACCAACAGGAGAAAA
+CAAAGGGAAAAGCCTTAATGAATTGGCAAAAAAAAAACCCACATTTTTTA
+AACAAAACTTAGCTGAAAGCCCCAGAAGGCATGGGCATTGTATTGGAGGA
+TAATGGACTGAAGGGGCTAACCATGACTGAAGAGCTAGTCTAGAGGTGGA
+GGTCTTATGCACTCAGAAAGCTGCCAGTTGCAAAGTCCTGTCTGGCTCTT
+GCTCCTGCAAGCCATGAGTGATCATTTTTCAGAATGCCCCCTACCTCTCC
+TCTCTTTTGACAGATACAACAGCCTCAGTCAGGAATGACAGGAATACCTG
+CATACTTTCCCTAACTCAATACCGGAAAACGGACAATATGAAGAGAGGAG
+GGATGGAGCAAGATGTGCCCACAAGACAGGTGTGATAAGTTTCCATAAAA
+ACTGATGCTTCAGAAGAAGGGAGCGTGAAAGACTCAAAGGCAATGACAGA
+GTAATCTTGTGTGTAGCAGAGATGCAATGTGGCTTCTCCCCTTCCAAAAA
+GACCTGATTTTACCTCACTGCCAGAAAAGAGAATGGTGCTCAAATTGCTT
+TGTACATAGTGTTCACTGGGCAGCAGTTCATCTACCTGGATAAGGGCTCC
+GAGCTACAGGGACCCTGACATTGGGATGTATGGAGAGTTGGAATTCAGGA
+ACAGTTGTACCGAATCTTGAAGTGAAGAAGAAAGTAGTTTGTTGTACATA
+TGAATGAAATCCAACTTTTATTGCATTCAATATAGTATTGTCAAGCACCG
+TGCTTTAACTTGAATGTCTCTTGTGTTTGCCAAGGTAATATGTAAGTATG
+TAAATAATTTATTTGTCAGTGGCACTTTACCATTCTCAGATCTTCTTTCT
+TGGGAACATCTGATTTATTCTCAAGTGCTATTTTTCACTGAAACTGTTCT
+CTATTTGAGATATTATCAAGTTTCAGAATCACAGCAATTCTCAGAGATGA
+GCCCAAAAGTTTTACAAATATTTCACCATAGTTAAAAATTTTTAAAGATC
+TGTCCTTTCATTTGTTTTCCTAAATTTACACTATAAGTAACATACTTTTT
+ATATTTGAGATTTTGATTTCTCTTCAGTGTTTATTTTACTTAATTTGAAC
+CAAGACTCAACTTTTCCACAGAAGAAATCTAAAAGGTTTCTCTGCTGCTG
+TTTCTGATCAATTGTTTCTCATAAATCCTACTGGCAAACTCTTCTGTCCC
+TCTAGGCCCTCAAATACTCTTTTCGGGTCCTCCTGGTGCTCCCCAAAGCC
+ATTCCAGGTCCTTAGAAATGTCTTAGTCTAGATTAATTTCCTGGTTCTCA
+GTCCAGATACACAACCTCATGGGAAGAAACAAAAACTGCCACTTTTATCC
+ATTCCAGGTGCTACGAAGAAAGAAAAGTATGTCAGAGAAATAAGGGAAAT
+GGCTGGTATCTCAGTTATTCTTCCTCTTCTTTAGGGCAGAATCTGACTGG
+CCCATTCATTCCTCAACTACATAGAAttctctctctttttttttttgaga
+cagagtcttgctctgtcacccaggctggagtgcgatgccgccatctcggc
+tcactacaacctctgcctcccgggttcaagcaattctcctgcctcagctt
+cctgagtagctgggactacaggtgtgtgccaccacacccggctaattttt
+gtatttttttggtaaagaggatttcactatgttggccaggctggtctcga
+acttctgaactcatgatccgcccgcctcagcctcccaaagtgctgggatt
+acaggcgtgagccaccacacctggccCATAGAATTCTCTTAGGTCTCTCA
+TCTAAAAACCCAGAAGAGTCAGACCACTGGTTTTCCTGTAACATTCATTG
+CAAGAAATGCCAACTATGAGTTATAGAGCATGGAGAAGATTACAAGAGAA
+TATGGTAGTAATTAGGGGGTGGAGCCAATGGCAGGCTACGATCAAGCAAC
+TTTCTAAATGAGGCAACTATAATTAAGGCAGTTAGTAAGTGATAACTCAG
+ACATAAATCTTGGTTTATCTCTTTCACTTATAAATAGAAAAATAAAAAAG
+TATTTGCTAGCCAATAGCAGCACCATTAACTCAAGCTAGTCACCTAGCAA
+AAATATTCAGGCCACTATGACAGTTGTGTAGGTGTCTCAGAATTAATGTA
+TTTGCTTTCAATGCTTCTCAGCTGTGCCGTCGTCtttttttttttttttt
+ttttttgagatggggtctggttctgtcgcccaggctggagtgcagtgaca
+caatctcggctcactgcaacctctgcctccagggttcaggccattctcgt
+gcctcagcctcctaagtagctgggattacaggcacgcaccaccatgcccc
+gctaatttttatatttttagtacagacaaggttttgccatgttggccagg
+ctggtctcgaactcctgacctcaagtgatccacccacctaggcctcccaa
+agtgctgggattacaggtgtaagccactgcgcccagccACAGTCATCATT
+TCTAAAACAGTGCCCAAGCAAGGGGAGGTGAAACCAAAAGGAAAGGCTCA
+AGGAATGTTTGTGGGCTTCAAAGGATAAGCCACTATGGCAGCAAACCTCA
+CACAATGAAAATCACCAGTGCCTCTTATTCACTATTCACAATTTGTGCCT
+TGCTGCCTCTTTTTCCCATGAATCCCTTTTCCCTTTAACCAACTTCCTGT
+GTTATGAATCAGGCCTGTCAATGATATCCAAGGGCACTGCTTAGCACTGC
+TAGCAGAACTTCACTTATTCAACTTAATAAATTCTAATTATATATTCAGC
+ATTGGGCCAGGTGATGAGAATCTTAATGCTGATGGCGCTACTGTCCACTG
+GTTCTGATAGACTGAGAATATTTACTGCTGAAGAAATGAAGTCCCAACCT
+GGCTGAGATTTTAAGGAAATGAACCTACTTAGACACAAATTCAAGTGACT
+TAGGCAGATGCTCATTATTAAATCTGTTTATCTTTCTCTCTCACTTAAAA
+AGGATCAAGATCTATGCCTAAGAGGAGTTACATACCATCCCATCCAAAAG
+CAAAAATAGCATAATGGCCTGGTAATGGCCTCTCATCTTCATTCTCACCT
+TAAACTTACCTTAGATGAACTGCCATAGAAAGCAGCTCAGTCCAAAACGC
+TCAAATGGTGCTCCAGGATTTACTTttttgtattgttttgttttgttttt
+tgcgacggagtctcgctctgtcgcccaggctggaatgcagtggcgtgaac
+tcggctcactgcaagctccgcctcccgggttcacgccattctcctgcctc
+agcctcccgagtagctgggactacaggcgcccaccaccacgcccggctaa
+tttttttttgtattttttagtagagacggggtttcaccatgttagccagg
+atggtctcgatctcctgacctcatgatccgcccgcctcggcctcccaaag
+tgctgggattacaggcgtaagccaccgcgcccggccAGGATTTACTTTCT
+TAAATGCACTCTTTTCATTCCCATTCAAAGGACTCCAGTATAAGTGCCAC
+ATAAACTCGTTTTCTAACTTTTAAAACTCTTCCTCTAAATGCAGCCCAAC
+TCAGTAAAAACGTACCTAAGATCTCACAGTCTAATGTTTCCAGCTTTTAA
+AGCCTTTACTCCTACCCTTCCCTCTGCCTGGAAAGTGTCTCCATTCCCTG
+CTGTGGACAAAATCCCTCAAGGTCTTTTATAATTTCCCCCAACCCCAAAT
+CAACTTGGATTTTCTTGGAGTTCTCACAGCATTCAGTTTATGTCCTATTC
+TTACCCTTGTGTTACTGATATTCACGAAATTGCTCAGTCCTTTCAAGAGA
+TTGCTTAAGGACAAAGACTTCTTACTCAACTCTGCAATATTGGCTACACA
+TAGCTGACTTAATAAATAGTCCCTTGACTGGTATAAGCTGACGTTACAAA
+AACTGGTAATTCCGAAACCACTCATACTGGACTTATTAAATAATCCCTCA
+ACTGGTACAGACTGACATTACAAAAACGGATTAATTCAGAGATCACTGAA
+CACCCAAAACACTCAGATTCTTATAACTATGattcagtaaatatgtgtgg
+aatgcctatcttaccaggtgactatgttaggcgctgcatgagatataaga
+tgaaaacaaggttcccattttcCAgggaagaatactggagtggaaaacgc
+agaggataccacaacaggagagctatttccgattagcggccgccactgct
+gagctatgtgaccctgagcaagtcacttcttaggtctccgtttctctgtc
+aaggagagatagaaaaagaacctatttcacaggTTCAAACCTACCTCAAG
+AAAAAATAGTTGTGGGGAATGCGTCACGAGACCTAGAAAACGGTACAAAA
+CCCTCGGGGGGCCGCTGTTTCTGACCTAGCGAGTGGCCCGACCCGGACAA
+AATGCCTCTTCCTCGAGGAGGCGGCGACGAGCCCAGCAACAGCTCGAGCA
+CGGCCGGCCGGGCCGCGGGAAGCCCGAGAACGCGGCGCGCGCAGCTGGGA
+GGCGACCCTTACCCGGCGAGGCTCCCGGGACCAAACGCCGCCCGACAGCC
+ACGCAGAACAGACGCGGCAGTGCGACGCCTCCCCCACTGGGGACACGAGA
+CAGCGACAGCCACGCGGTGAGCCGGTACAAGGCCCTCTAGGCTTCAGCGG
+GTCTGGATACTCGGTGGCATTAACCCTTCCCTACCGCCGGGGAAGACAGC
+AGTTTCTCTGGCGAGGAAGTAGGCCGGGCTCAGGCGCCTTAGCCAGAGGG
+CGGGCCTGCGCCACCCTCGGAAAGCGTCACTTCCACTTCCGGCCGGCGCT
+CTGGCTCTGTACCTGGACAGGGCTGCGGTAGGCCAGCGGTGGGCTGGCGG
+TTGCGCTCCTCAGATCGGCGGCCTTTCGGGCGGTGGCTTGCGTTTGAGCC
+TCAGAAAGCGAGGAGCGGCCTCCACGGAAGCCAAGCTGGCCGAGGTAACC
+GAGAAGCGGCTTCCCCTATGGCTTCGACCCTGGAGCCGCTGGAGCGGCGG
+CGGCCGCAGGGAGGCAGCCATTTTCCGTAGGCGGTGGCCGCGGCGCTTCC
+GGGCCGCGCGGCTGGAGCCTGAGGCGGGGCCACCGTCGGGCACGAGAAAC
+CATTCTCTCCCCGCTTTTCGCAGCTGTATCCCAGAGGCGCGGCTGAAGCT
+CGCTGGGACACTGCCCGCTTGCCCAGTGCCCACGGGCACGCCTGTCGCAG
+ACACAGGCTGTGGCGAATCCGAGTGCTGGCGGGCAGCAGTGCCTGCAGCT
+GCGCCCGCAGACTCTTTCCCGCCTCCGCCGGCATTTCCGTGTCCGGCCGA
+TGTCATGCGGTCGGTTGAGCCTCAGGGCTAGCAGCTTCTACTGATGCAAA
+AACATAGGAAGTGTCTCTTTGCTTCTGGAACCGGGGTGGGCAGCAAGGAG
+CTGGCCACTTCTTTGAATACCGGTGGCATCCTGGGCAGAATTTCGGTGCC
+GTTTCTGCTGGCTCACTTCAGGAAAAGTGAGGCTCACGGCTCTCCTCAGC
+CCCCCTTAGAAGTCTAAATGACCTTTGGAGAAATACAAAGTCAGCAGAAA
+GTTTCACTTTCATCGTCACCAACTCCTGTTGGAGTTGATATTTCATAAAC
+ATCAGCGACAGAAAGAAAATACGACTTGATATTTTGTAAATAAAATATCC
+TTTTTTACAAGTTGATATTTTGTAAACAGAGGTCAGCTGTAATTTTCTCC
+AGATCAAGTAAGCACAGTTAAAAATTCATATAggcctggcgcggtgtttg
+acgcctgtaatcccagcactttgggaggccaagatgggtggatcacgagg
+tcaggagatcgagaccaccctggccaagatggtgaaaccctgtctctact
+aaaaacacaaaaattagccgggcatggtggcacgcgcctgtaatcccagc
+tagtcgggaggctgaggcaggagaatggcttcaaccggggaggtggaagt
+tgcagtgagctgagatcacgccactgcactccagcctgggtgacagggcg
+agactccatctcaaaaaaaaaaacaaaaTTCGTATAAATCATCTGCATGG
+CACCCTTTATGTGTGTTGCAAAGAATGATGAGCATCTTGTTGCTTACTTG
+GGAGACATTGTCTGAAAATAGGCTACTTTTTTACTTTCTgtagtaccccc
+tccccccactgtatctgggtttcacttacccgctgtcaactgccatccaa
+aaaatattaaatggaaaactccagaaataaacagttcataagttttaaat
+aacttttttttttttttttggagatggaatctcgttttgctgccctggct
+ggagtgccgtggcacagtctgagctcactgcagccttcacctcccgggtt
+caaacaattttcctgcctcagcctcctgggtagctgggactacaggcgcg
+cactaccacacctggctaatttttgtgtttacaataaagaaggtttcacc
+atgttggccaggctggtcttgaagtcctggtctcaggtgatccacccacg
+tcaggcctcccaaagtgctgggattacaggcatgagccacggcgcaccgc
+cagttttaaataactcttactacagtgttttattgttaatctcttattgt
+acctaatttataaattaaggtatcatagctatgtatacatagagaaaata
+gtataatgcagttagatgctgttgggggttttaggtattcacagaatgta
+ctggaacttaccccccttggagaagggatactactgTATTTTGATCTCAC
+CGTCTCAGCTCTTTTGCCAGTATTCCTACAATGGAAAATCTAAAATGTTG
+TTTTTTAAGGTGCCtttatttttagtttttaaattagagacaaagtcttg
+ctctaactcccaggctggagtgcagtgatgaggtcatggctcactgcaac
+cttgaattcctgggctcaggcgactctcccacctcagcctcctgagctag
+aactactggtgtgctctaccatcctggctattttttttttttttcttcaa
+attttgtgttttgtagagacggggtctcgctatgttgctcaggctggtct
+gaaactcctggctcaagtgatcctcccacctcggtctccaaaagtgctgg
+gaatgcaggcatgagccactgcacctggccTAAAATATTTTTAAAGTGAA
+GGCTTCCATCTTCACAAGAGGATGAAGGGTCATAAAAGTTGTACTCCCCT
+TACTAGAGACAGACTGGGATGATCTGTTGAAATTTAAGAGAATCTCAGAA
+TGTTTTCCTAATCTTATTTTCTCCTATTCTTTTCTTATGGGGAAGATGGG
+ATAGGAGGCACACCAGTTAAATCCTTGGAAAATCCCAAAATACCTTTCAG
+CCAGTGGGTGCCAATTTTCTTACCCACCAATCTTTCCTAAATTGTTTTCT
+TTTTTATAAAAAAGACAGTTGTCCACTGACATTTGTGTGTTTTGTGCTGT
+GCTTCAGCTGAATAATAGAAAAGGAGAAAAACAAAGGGCCTGCTAGTTGA
+TTTTGAAGGGAAGACAGGACACCTTTTCTGTTCTTCTTTCTCTCATAAGT
+CGCAAGTGATGAGGTTCATGTGAGTTTCTTATTGATACATACTTTTCTTT
+TTCTTGTCCTCAGTGCTTTTAGGAAGAAGATCCTTTTATTGCTTTTGTAC
+AAGACCAGACAGGATCTCATTTGTTAAACGTGGTACCAATTGGGTGTCTT
+AACACAGGAGCAGAACTTCCTAGAGCAGAATGATGATGGTAGATCTGAAA
+GTGGCTGCGTACTTGGACCCTCAGATCAGGGCTTTGTGGGAGACCAAGGG
+GCCTGCAAGAGAGAGCTCCGGTCAGAGTAAAAAATCTCCTCAAATGGACT
+GTCTCGATCCTAAGAGCTCTTGCTGGCACTTCCGGAATTTCACCTATGAT
+GAAGCAGGTGGACCCCGTGAGGCTGTCAGCAAACTTCAAGAATTATGTCA
+TCTATGGCTGAAGCCAGAGATCCACTCAAAAGAGCAGATACTGGAACTGC
+TGGTGCTGGAGCAGTTCCTGACTATTCTGCCCAGGGAGACACAGACCCAG
+ATGCAGAAGCACCATCCACAGAGCATTGAGGAGGCTGTGGCTCTGGTAGA
+ACACTTGCAGAGGGAATCTGGTCAAACATGGAATGGGGTGAGAAGAAAGA
+TTCCTGACATGTACAGTGAAATAGGATGCAGGTGGATATAGTAGAGATGG
+TGGCAGTTAGTTGAGAAATTAGATGGATTAGGTAGGTCATTGTTTGGTTT
+TTTTTTTAAGGACAGTTAAGGTGGGACTTGAAACTACAGGCCCACAGAAA
+AGTTCACAGGTTTCAGAGATTGTGGTAGATACTTCCCTGGCCTTAGAGAA
+AGAGAGTTGCTTTTGCCCTCTTTGGAGCCAGGGTGAATTGAGGGTGTTGG
+GCCTAGTCTGGCTTGGCCAAGGAGACAGGACTTAAGTACTTAGAAACAGA
+ATAAAAGGTAATAAAGAGTCAGGGAggctggatgcagtggctcacacctg
+taatctcagcactttaggaggctgaggcgggtagatcacctgaggtcagg
+agttcaagaccagcctggacagcatggtggaaccctctctctacaaaaat
+aaacaaattagctgggcatgatgaccggtgcctgtaatcccggctatcct
+cgaggctgaggagggagaatcatttgaacctgggaggttgcagtgagccg
+agatcgcaccattgcactccagcctgggcaacacagcaagactccatctc
+acaaaaaaaaaaaaaacaaaaaaaacaaaaaaaaaaCGggccgggtgcag
+tgactcacacctgtaattccagcactttgagaggccaaggcagacagatc
+ccctgagcccagcctgggcaacatggtgaaaccccgtctctacaaaaaac
+atgaaaattagccaggcatggtggcacacacctgtggtcccagttacttg
+ggaggctgagtcaggagaatcacctgagcccaggaggtggaggttgcagt
+gagctgagatggcaccattgcactcccttgggtgacagagtgagaacctg
+tcaaaaaaaaaaaaaaaaGGCAGATCCACAAGGAGAACACAGGAAAACAA
+GGACACTTAAAGAAAAGGAGAAATTggccaggttcggtggctcatgccta
+tatttcgaacactttagggggtcgcggtgggaggactgcttgagaccagc
+ctggggaacatagtgtgaccttgttgctatgaaaaaaaaaaagaaaataa
+gccaggctgatggcacatgcctctagtcccagcttcacaagaggttgagg
diff --git a/blat/test/badSplice/small2.fa b/blat/test/badSplice/small2.fa
new file mode 100644
index 0000000..786b634
--- /dev/null
+++ b/blat/test/badSplice/small2.fa
@@ -0,0 +1,109 @@
+>Y14441 1
+gctggctcgagcctctcctgctcagcaccatggctaagacccctagtgac
+catctgctgtccaccctggaggagctggtgccctatgacttcgagaagtt
+caagttcaagctgcagaacaccagtgtgcagaaggagcactccaggatcc
+cccggagccagatccagagagccaggccggtgaagatggccactctgctg
+gtcacctactatggggaagagtacgccgtgcagctcaccctgcaggtcct
+gcgggccatcaaccagcgcctgctggccgaggagctccacagggcagcca
+ttcaggaatattccacacaagaaaacggcacagatgattccgcagcgtcc
+agctccctgggggagaacaagcccaggagcctgaagactccagaccaccc
+cgaggggaacgaggggaacggccctcggccgtacgggggcggagctgcca
+gcctgcggtgcagccagcccgaggccgggagggggctgtcgaggaagccc
+ctgagcaaacgcagagagaaggcctcggagggcctggacgcgcagggcaa
+gcctcggacccggagcccggccctgccgggcgggagaagccccggcccct
+gcagggcgctagaggggggccaggccgaggtccggctgcgcagaaacgcc
+agctccgcggggaggctgcaggggctggcggggggcgccccggggcagaa
+ggagtgcaggcccttcgaagtgtacctgccctcgggaaagatgcgaccta
+gaagccttgaggtcaccatttctacaggggagaaggcgcccgcaaatcca
+gaaattctcctgactctagaggaaaagacagctgcgaatctggactcggc
+aacagaaccccgggcaaggcccactccggatggaggggcatctgcggacc
+tgaaggaaggccctggaaatccagaacattcggtcaccggaaggccacca
+gacacggctgcgagtccccgctgccacgcccaggaaggagacccagttga
+cggtacctgtgtgcgtgattcctgcagcttccccgaggcagtttctgggc
+acccccaggcctcaggcagccgctcacctggctgcccccggtgccaggac
+tcccatgaaaggaagagcccgggaagcctaagcccccagcccctgccaca
+gtgtaagcgccacctgaagcaggtccagctgctcttctgtgaggatcacg
+atgagcccatctgcctcatctgcagtctgagtcaggagcaccaaggccac
+cgggtgcgccccattgaggaggtcgccctggaacacaagaagaaaattca
+gaagcagctggagcatctgaagaagctgagaaaatcaggggaggagcagc
+gatcctatggggaggagaaggcagtgagctttctgaaacaaactgaagcg
+ctgaagcagcgggtgcagaggaagctggagcaggtgtactacttcctgga
+gcagcaagagcatttctttgtggcctcactggaggacgtgggccagatgg
+ttgggcagatcaggaaggcatatgacacccgcgtatcccaggacatcgcc
+ctgctcgatgcgctgattggggaactggaggccaaggagtgccagtcaga
+atgggaacttctgcaggacattggagacatcttgcacagggctaagacag
+tgcctgtccctgaaaagtggaccactcctcaagagataaaacaaaagatc
+caactcctccaccagaagtcagagtttgtggagaagagcacaaagtactt
+ctcagaaaccctgcgttcagaaatggaaatgttcaatgttccagagctga
+ttggcgctcaggcacatgctgttaatgtgattctggatgcagaaaccgct
+taccccaacctcatcttctctgatgatctgaagagtgttagacttggaaa
+caagtgggagaggctgcctgatggcccgcaaagatttgacagctgtatca
+ttgttctgggctctccgagtttcctctctggccgccgttactgggaagtg
+gaggttggagacaaaacagcatggatcctgggagcctgcaagacatccat
+aagcaggaaagggaacatgactctgtcgccagagaatggctactgggtgg
+tgataatgatgaaggaaaatgagtaccaggcgtccagcgttcccccgacc
+cgcctgctaataaaggagcctcccaagcgtgtgggcatcttcgtggacta
+cagagttggaagcatctccttttacaatgtgacagccagatcccacatct
+atacattcgccagctgctctttctctgggccccttcaacctatcttcagc
+cctgggacacgtgatggagggaagaacacagctcctctgactatctgtcc
+agtgggtggtcaggggcctgactgaatgcccaacactgcatctctcttcc
+tgcttctggccttgtatcttgcattcacactcaatagtcacggaatgccg
+actaggtgctagctgctatgggaaatgcaaaaataacaaaatagttactg
+tgcccacggagcctacccgattatagcagaggtaagttaggaacgaacat
+gttagtcaatccgggtgaagacatgtactgatgacacaccatggatttca
+gaggaggaagtacggagtcgttgcataatccgcccctggtgggtggcact
+ctcaggtgctcctgaacagaagatttggccctcattttccctcagaaccc
+cacggcaaggatatatgtccccttgttctctctgcttctgtcttgaggat
+atgggaagcctagagaaacgcaagcagactggattgggatagaagtattt
+gtgtacctggattaatgaactatga
+>BC101511 1
+gctcgagcctctcctgctcagcaccatggctaagacccctagtgaccatc
+tgctgtccaccctggaggagctggtgccctatgacttcgagaagttcaag
+ttcaagctgcagaacaccagtgtgcagaaggagcactccaggatcccccg
+gagccagatccagagagccaggccggtgaagatggccactctgctggtca
+cctactatggggaagagtacgccgtgcagctcaccctgcaggtcctgcgg
+gccatcaaccagcgcctgctggccgaggagctccacagggcagccattca
+ggaatattccacacaagaaaacggcacagacgattccgcagcgtccagct
+ccctgggggagaacaagcccaggagcctgaagactccagaccaccccgag
+gggaacgaggggaacggccctcggccgtacgggggcggggctgccagcct
+gcggtgcagccagcccgaggccgggagggggctgtcgaggaagcccctga
+gcaaacgcagagagaaggcatcggagggcctggacgcgcagggcaagcct
+cggacccggagcccggccctgccgggcgggagaagccccggcccctgcag
+ggcgctagaggggggccaggccgaggtccagctgcgcagaaacgccagct
+ccgcggggaggctgcaggggctggcggggggcgccccggggcagaaggag
+tgcaggcccttcgaagtgtacctgccctcgggaaagatgcgacctagaag
+ccttgaggtcaccatttctacaggggagaaggcgcccgcaaatccagaaa
+ttctcctgactctagaggaaaagacagctgcgaatctggactcggcaaca
+gaaccccgggcaaggcccactccggatggaggggcatctgcggacctgaa
+ggaaggccctggaaatccagaacattcggtcaccggaaggccaccagaca
+cggctgcgagtccccgttgccacgcccaggaaggagacccagttgacggt
+acctgtgtgcgtgattcctgcagcttccccgaggcagtttctgggcaccc
+ccaggcctcaggcagccgctcacctggctgcccccggtgccaggactccc
+atgaaaggaagagcccgggaagcctaagcccccagcccctgccacagtgt
+aagcgccacctgaagcaggtccagctgctcttctgtgaggatcacgatga
+gcccatctgcctcatctgcagtctgagtcaggagcaccaaggccaccggg
+tgcgccccattgaggaggtcgccctggaacacaagaagaaaattcagaag
+cagctggagcatctgaagaagctgagaaaatcaggggaggagcagcgatc
+ctatggggaggagaaggcagtgagctttctgaaacaaactgaagcgctga
+agcagcgggtgcagaggaagctggagcaggtgtactacttcctggaacag
+caggagcatttctttgtggcctcactggaggacgtgggccagatggttgg
+gcagatcaggaaggcatatgacacccgcgtatcccaggacatcgccctgc
+tcgacgcgctgattggggaactggaggccaaggagtgccagtcagaatgg
+gaacttctgcaggacattggagacatcttgcacagggctaagacagtgcc
+tgtccctgaaaagtggaccactcctcaagagataaaacaaaagatccaac
+tcctccaccagaagtcagagtttgtggagaagagcacaaagtacttctca
+gaaaccctgcgttcagaaatggaaatgttcaatgttccggagctgattgg
+cgctcaggcacatgctgttaatgtgattctggatgcagaaaccgcttacc
+ccaacctcatcttctctgatgatctgaagagtgttagacttggaaacaag
+tgggagaggctgcctgatggcccgcaaagatttgacagctgtatcattgt
+tctgggctctccgagtttcctctctggccgccgttactgggaggtggagg
+ttggagacaagacagcatggatcctgggagcctgcaagacatccataagc
+aggaaagggaacatgactctgtcgccagagaatggctactgggtggtgat
+aatgatgaaggaaaatgagtaccaggcgtccagcgttcccccgacccgcc
+tgctaataaaggagcctcccaagcgtgtgggcatcttcgtggactacaga
+gttggaagcatctccttttacaatgtgacagccagatcccacatctatac
+attcgccagctgctctttctctgggccccttcaacctatcttcagccctg
+ggacacgtgatggagggaagaacacagctcctctgactatctgtccagtg
+ggtggtcaggggcctgactgaatgcccaacactgcatctctcttcctgct
+tctggccttgtatcttgcattcacactcaatagtcacggaatgccgac
+
diff --git a/blat/test/badSplice/test b/blat/test/badSplice/test
new file mode 100755
index 0000000..b5b4b7d
--- /dev/null
+++ b/blat/test/badSplice/test
@@ -0,0 +1,4 @@
+blat -q=rna -fine chr16part.fa small2.fa small2.psl > small2.log
+pslReps -nohead small2.psl smallBest2.psl /dev/null
+awk '{print $10,$19}' smallBest2.psl
+echo 'see also small2.log'
diff --git a/blat/test/intron50k/expected/test1.psl b/blat/test/intron50k/expected/test1.psl
new file mode 100644
index 0000000..4dbbe72
--- /dev/null
+++ b/blat/test/intron50k/expected/test1.psl
@@ -0,0 +1,6 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+600	0	0	0	0	0	2	60200	+	query	600	0	600	chr16part	100000	10000	70800	3	200,199,201,	0,200,399,	10000,60200,70599,
diff --git a/blat/test/intron50k/expected/test2.psl b/blat/test/intron50k/expected/test2.psl
new file mode 100644
index 0000000..41b256b
--- /dev/null
+++ b/blat/test/intron50k/expected/test2.psl
@@ -0,0 +1,7 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+200	0	0	0	0	0	0	0	+	query	600	0	200	chr16part	100000	10000	10200	1	200,	0,	10000,
+464	4	0	0	2	132	3	12560	+	query	600	0	600	chr16part	100000	57772	70800	4	27,41,199,201,	0,52,200,399,	57772,57852,60200,70599,
diff --git a/blat/test/intron50k/expected/test3.psl b/blat/test/intron50k/expected/test3.psl
new file mode 100644
index 0000000..51b5e03
--- /dev/null
+++ b/blat/test/intron50k/expected/test3.psl
@@ -0,0 +1,8 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+200	0	0	0	0	0	0	0	+	query	600	0	200	chr16part	100000	10000	10200	1	200,	0,	10000,
+263	4	0	0	2	132	2	2360	+	query	600	0	399	chr16part	100000	57772	60399	3	27,41,199,	0,52,200,	57772,57852,60200,
+201	0	0	0	0	0	0	0	+	query	600	399	600	chr16part	100000	70599	70800	1	201,	399,	70599,
diff --git a/blat/test/intron50k/query.fa b/blat/test/intron50k/query.fa
new file mode 100644
index 0000000..9142708
--- /dev/null
+++ b/blat/test/intron50k/query.fa
@@ -0,0 +1,13 @@
+>query
+gagtcttgctctgtcacccaggctggatctcccctcactgtgggttcaag
+agattctcctgcctcagcctcccaagtagctgggactacaggcactctca
+cactgtcatgctggagtcaacctcccatttactctgatttttttttttaa
+agagatgagcccagcgctttggaaggccaaggcagggggatcacttgggc
+taatatgtttttacaagaatggatataaggtaaatggaaacaagattccg
+taagacgtgtgtatatgcaaaagatggtatttaaaacccaaggggaaaag
+gtggcccaacttataaatagttttgggactgttgacagttgagctggaaa
+acatagacttctgcctgacatatataaaaaataaactccatatatatata
+tacaaaaattagccgggtgtggtgcgtggtgcctataatcccagctactc
+gggaggctgaggcatgagaatcgcttgaacctgggaggcggaggttgcag
+tgagctgagatcccaccactgcactccagccggggcgatagagcgagact
+ccatctcgaaaaaacaacaaaaaacccctacaaatctgctggcctgttaa
diff --git a/blat/test/intron50k/target.fa b/blat/test/intron50k/target.fa
new file mode 100644
index 0000000..dfd24d7
--- /dev/null
+++ b/blat/test/intron50k/target.fa
@@ -0,0 +1,2001 @@
+>chr16part
+TTTTACttttttttttttaacgtcctttttttttctgcgggggggatgaa
+gtctcagtctgttgcccaggctggagtgcagcagcacgatctcagctcac
+tgtaacctctgcctcctgggttcaagtgattttcctgcctcaacctcttg
+agtggctgggattacagacatccaccaccatgcctggctaatttttgtat
+ttttagtagagatggggtttcaccatgttggccaggctggtcttgaactc
+ctgacctcaagtgatctgcctaccttggcatcccaaagtgctggaattac
+aggcatgagccaccatgccgggtcAGCTTTACTTTTTGATTTGATCTTTG
+GTTATGGAGGtgatgtggtttggctgtttgtctccaccaaatctcatgtt
+gaaatgtgattctcagtgttggaggtggcgcctggcaggtggtgtttagg
+tcatgggggtgggtccctcatgaatggcttggttccccccacacagtaat
+aagttaccatgagctctgattgttagagcctgggagcttccccttctccc
+ttttattccctctctcttcatgtgacacacctgtttccacttcaccttct
+gccatgattggaaacttcctgaggcctcaccagaagtaggtgcccacacc
+atgcttcttgtacagcctgcagaatcatgacccaaaaaaacttttcttta
+taaattacccagagtcaggtatttctttatagcagcgaaaacggactaac
+acaGAAGGCCTGGAGGCTGGTGAATGTTATCCATTCATTATAAATTATAT
+TAAATACCTTCTAGAAATAGAATGATCTTTGTCCTCTTCAATTCTTGTTT
+CTGCTTAAAGCATACTTTGGTTAATACTAATATTACTCATTCTGCTTTCT
+TGTGTTTGCTCATTCTCTCAGACTTTCTGAAATAGTTGACTTGGATGAAG
+GGCTCCTTCCCTCTGTATCAAGATCTTCCTTTTCAAAGCTTTCAGTATGT
+GAGAAAAAATTAgggcaggcaaggtggctcacgcctgtaatcccagcact
+ttgggaggcctaggctggtggatcacgacgtcaggagatcgagaccatcc
+tggctaacacggtgaaaccccgtctctactaaaaatacaaaaaaattatc
+caggcatggtggtgggcacctgcagtcccagttacttgggaggctgaggc
+aggagaatcacttgaacctgggaggtggaggctgcagtgagccaagatca
+cgctgctgcactccagcctggatgacagagtgagactctgtctaaaaaaa
+attaaaaaaaataaaaaaaaaaTAGAGTGTAATCTAACACCTAGAAAGAA
+CAGTCTACAggccgggcatggtggctcacgcctgtaatcccagcccttgg
+ggaggctgaagtaggcgcctgtaatcccagcctttggggaggccgaggta
+ggcggatcacctgaggtcaggagttcgagaccagactgaccaacatggtg
+aaaccgcatctctactaaaaatacaaaaaaaaatctgggcgtggtggtgg
+gttcttgtaataccagctactcaggaacctgcggtgggaggatcccttga
+gcctgggaagtggaggttgcagtgagtcgagattgtgttactgcactaca
+gcctgggcgacagtaagactctgtctcaaaaaaaaaaaaaGTGATTCTGT
+TTTTCAGTTTGTCTTTTGTCTATCTCACACACTTTTGTCTCTGCTCTTCC
+ACGTATATTTTTATCTACTAATTTTCACCTTTGAATGTCCCTCTTTTGAA
+GATGGGTGAGTGGGGCTTCCAGTTTTGTAAGGGATACTTGCGTTATGTTA
+GGATCCAGCCTAACATTTTCAGGAGGGTGTGTTTTGGGGAAGAGGTGTGC
+GTATTAATACCACAAGCCAGAGGATGACTCTAgtggacatttgtcagact
+ttgtggcttccaagcatctgggcccacttccaaagtttgtagagtcccct
+aatttatggatgttgttgggaagagagcccacctcccactatagaaataa
+gtacaccagaaacttgcttctgagtgtctctttcagctagaatgagagca
+agtgacaggctctctgcccatcagatatatctgccctgcatttgacacag
+agaaggggagacaaggaggaacttgctctgtcagtttgtaggcagccatt
+gtagggacatggattcctggagcgtgacgacagtaatgctaggggtagca
+gcgaatgtctgtgagaagtacatcagaaatgcaagctgcagcatctagtg
+cttggtggcagcagcactggtgtcctcactagctggcttggagtcatgat
+ttggggcactgttAACAGATGAATTTTTGTTGTTGTTGTAGTTttgtttt
+gttttgtttttgtttttgtagaaacggggtctcgctgtgttgcccagggt
+gatgttgaactcctggcctcaagcaatcctcctgtcttggcctcccaaag
+cgctgggacttcaggcatgagacaccacactcagccATAGACTCGTTTGT
+TAgttctcctaagaaacagagccaacaaaatatattgctaaagggtgggt
+ggggtgggtgggaaggtaagattttaaactctaaggaattggcacatgtg
+attgtggaggcttggcaagttcaaagtatgcagggtggaccagaaggctg
+tagacctagcgaagagctgatgttgttgcagcttgagtccaaaggcagtg
+ggttgactttttctattgtggccttcaactgattggataaggcccaccca
+cattatggaggctaatctggtgtactcaagttctattgatttaaatgtta
+atctcatcttaaaaatacTCCCCAAaaagaaaaataagaaagaaagaaag
+aaagaaggaaagaaagaggaaagaaaagagaaagaaagaaagagagagaa
+agaaagaaagaaagaggaaagaaaagaaagagaaagaaagagagagagag
+aaagaaagaaagaaagaaagaaagaaagaaagaaagaaagaaagaaagaa
+aagaaaagaaaagaaagagaagaaagaGggctgggcgcggtggctcacgc
+ctgtaatcccagcactttgagaggccgaggtgggtgggtcacgaggtcaa
+gaaatcaagaccatcctgggcaaaatggtgaaaccctgtctttactaaaa
+atacaaaaaattagctgggcgtggtggcgcgtgcctgtagtcccagctac
+tcgggaggctgaggcaggaaaatcactcgaacctgggaggtggaggttgc
+agtgagccgagattgcgccactgcactccagcctggcgacagagcgagac
+tccgtctcaaaaaaaaaaaaaaaagaaagaaagaaaGAGGCgccaggcgg
+ggtggttcacgcctgtaatcccaccactttgggaggctgaggtcaagaga
+tcgagaccattatggccaacaatgtgaaaccctgtctctactaaaaatac
+aaaaattagctgggcatggtggtacgtgcctgtagtcccagctactcggg
+aggctgaggcaggagaatctcttgaacccgggaggtggaggttgcagtga
+gttgagatcaaaccactgaactccagcctgatgacagagtgaaactccat
+ctcaaaaaaaaaaaaaaaaaaaaaaagagaaTGGGACAGAGAGAAGGTGA
+TTGGATTTATACATTGTAGCCAAGCATGTAGTGATAGCTTTGCTCAATCC
+TGGTTCCAAATACTCTGGTTCAACCAGCTATGGTGAAGGGGAGGTGGTAG
+AAACACGACTCCTGGGGCTCCACCACATTGTGCCTATGCAGATTAGGAAG
+CTCTATCCCAAGAAAAGGGCAAACCATGTGAGTTGCAGGGACATCCCCAA
+AGATGTCCATCCTAGGGGTCTAGAGTTCATAAATCACGGCATCCTGGATT
+CTCCTGGAGAAAACCTCCCTTACAATCAGACTACCCTTCATCTCAAACAt
+tttctttttccttttttttttttttttgagacagagtcttgctctattgc
+ccaggctggagtgcagtggcacgatctcggttcactgcaacatccacctc
+ctgggttcaagtaattattgtgcctcaccctcccaagtagctaggactac
+aggcacatgccaccatgcctggctaatttttgtatttttagtagagactg
+ggtttcaccatgatggccaggctggtctcgaacccctgaccttaggtgat
+ctgcccaccttggcttcccaaacttttgggttacaggcgtgagccactgt
+gcctgaccCCAAACATTTTCACGAATTAAGCCCATCTCAGTAATGTGCTC
+GTAACATTCCCTCCTGTAAAATGGAAAACACGAAGCATCACTAATGTCTT
+AAGATGACCAGGCAGAGGAAAGCAAGGGCTACACAGAAAACACGGAAGAG
+CCCCATATCTCAACAAAGGAAGTGATACTGCAAAGGATTTCATGACAGAA
+TTTCCACACCTGTGGGCACAGGAGCAGATCACAAGGTGAGGAGGTTTGTG
+GTTCCAAGGAATCTTGTCTGCGATTTATCTGTATCAGGATGGCTTCATTT
+CTAATATCTACAAGTTTTGGTCCAAGAGTTTTATCTAAACGTTAGATAAT
+ATTGAATGTCGTCGTTGTTTGGTCCAAAGGGGCCAAAATTAGGTGGGACA
+ATTATGTTCTTCTTGTCCCTAATGAGGCTCTCAGGGAATCTGGTCCCAGT
+GGCCAAAGGAGGTTCCTACAAATGCCTGCTCTGTGATTGCCCCAAACATT
+TACTTACACAGAGGACTAAGACCATGAGCCCCTACTCCTCACACACTCAG
+GACCCGCCTGTGTTTCCAAGACATTCCAACTCCCACAGTAAGTAGAAGCA
+TTGACCAGTTATGTAGAAATGAGGAACAACTGAGAGTGACAGCACCAACC
+TTCTCCAGGAAAGGTCGCAGAGGTGAACAATTAAGTATGTGTTGGCTCAG
+ATGTGAAGTTCTTTTAGGAATCTTCTTTGCTACATCATCCAGATACAGGA
+AGTAATGAGTAATGTACAGAGAAGTGAAGTACAGGAGTCCTGAATCCATC
+AGTTGTCACTTGAGATTAACCCAGTAATCATCAGTCATTCCTCCAGTCTC
+TTTATGAGCTGCTAACTAGTTGGGTGGGGAACTGAATGTACCAGAGACAC
+ACACATTCTCAGAGTCAGGCTATGTGTACGTGTCTGTGTGTTTTGTtttc
+ttttcttttttaatagagatggggtcttggtatgttgtccaggctggtct
+tgaactcctggcctcaagccatcttccctctttggccttccaaagttcta
+ggattacaggcatgagccaccatgcccagccTGTCTGTGTTTTCAACGTT
+AAATATGCAAAATAAGAATCAGTGAGTCGTCTAGGAAAAGCATCGTAACT
+GAGTGTTGGAAATTGGACGTATGGGTGAGGAGACCACATCCTGTTTTTGC
+AAGTTTGTGAATTGATTTGCAAACGTGGTTCTTCCTGGAGCCTCATCACA
+TCTTAACCACCCATGTGTATGTTTCTGAATTCACTGTCTTCTATGCAGCT
+GGGTCCAGACATATGAGAGGGACAAACCAGTGAGTGTCTCCGAGTTCCTC
+CTCTTGGGACTCTCCAGGCAGCCCCAGCAGCAGCATCTCCTCTTTGTGTT
+CTTCCTCAGCATGTACCTGGCCACTGTCCTGGGGAACCTGCTCATCATCC
+TGGCCATAAGCATAGACTCCCGCCTGCACACCCCCATGTACTTCTTCCTC
+AGCAACATGTCCTTTGTGGACAACTGCTTCTCCACCACCGTCCCCAAGAT
+GCTGGCCAATCACATACTCAGGACTCAAACCATCTCCTTCTCTGGCTGTC
+TCATGCAGATGTATTTTATCAGTGAGCTTGCTGACATGGACAATTTCCTC
+CTGGCTGTGATGGCCTATGACCGCTTTGTCGCCGTGTGCCGCCCCTTACA
+TTACACAGCAAAGATGACCCATCAGCTCTGTGCCCTGCTGGTCACTGGAT
+CATGGGTGGTTGCCAACTCGAATGCTCTGCTGCACACCCTGCTGATGGCT
+CGACTCTCATTCTGTGCAGACAACACCATCCCCCACATCTTCTGCGATGT
+GACTCCCCTCCTGAAACTCTCCTGTTCAGACACACACCTCAGTGAAGTGA
+TGATTCTTACTGAGGCTGCCCTAGTCACGATCACCCCATTTCTTTGCCTC
+CTGGCTTCCTATATGCACATCACCTGCGTTGTCCTGAGGGTCCCATCCAC
+AAAGGGAAGATGGAAAGCCTTCTCCACCTGTGGCTCCCACCTGGCTGTGG
+TTCTCCTCTTCTATGGCACCATCATGTCTCCATATTTCAGAACTTCATCC
+TCCCACTCAGCTCAGAGAGATATAGCAGCTGCTGTGAGGTTCACAGTGGT
+GACTCCCGTGATGAATCCTTTGATCTACAGCCTGAGGAACAAGGACATAA
+AAGGGGCTCTTGTAAAAGTGGTTGCTGTGAAATTTTTTTCTGTTCAATAA
+TGGTATAGGCTTAAGAAAGTCCTAGAAGGAGCTAATTTCTGAGATAATCG
+TTTATTTTTTCTACTGTGTGAAACTTAGCAttgtttgtttgtttgtttgt
+tttgagacggagtctctgtcacccaggctggagtggagtcgtgcgatttc
+ggctcactgtaacctttgcctcttgggttcaagataatctcctgcctcag
+cctcctgagtagatgagattacagatgtgtgccaccacaatttttttttt
+ttttgtatttttagtagagacggggtttcaccatgttggtcaggctggtc
+tcgagctcctgacctcaaatgatccacctgccttggcctctctaagtgct
+gggattacagatgtgagccaccgcacctggccAGCATTTGTTTTCATAAT
+AGAAACATCTGGTATCTATTTTGGGAGAACAAAACCCTGCATATAGACTC
+TTTAGGTTAAAGATGGAAAGAGAGATCCTTTAATTAAATGACCCGACAAT
+TCCAATtgtcaatgccctcctgccaaaacctagaaggaacacacctgtag
+ttcaataagttggatttactaattatataacaagggagaatacacagcat
+cagcatcgggaatagtgaggtgtctcaatagaagagtcctaaaaaggact
+tctgcttgtgtaatgttggtgaggaaataggaatgagtctgtgctctgga
+gtagatgccattacagaatagagataattctgaatgagtatctttttttt
+ttttttttttttttttgagacagagtctcactcagtcgcccaggctggag
+tgcagtagctcgatctccgctcactgcaagctccgccttctgggttcacg
+ccattctcctgcctcagcctcctgagtagctgggactacaggcgcccgcc
+accatgcccggctaatttttttgtattttttttagtagagagggggtttc
+accgtgttagccaggatggtctcgatttcctgacctggtgatccgcccgc
+ctcagcctcccaaagtgctgggattacaggcgtgagccaccacgcccggc
+catgaatgagtatcttaatatattttatctagaaggaaagaagaggccaa
+agctgtgattgccaaagaaatagcagtcactcatatcaaccaccataggg
+ggatgtttggtgatttttgtggctatgaccatgttcctgtttttgtgttg
+agacatcattacagaaaggtcttgctttgttttgctctagcacagtcagt
+gtggccttatctgataccgatgttctgtgaaattctctatgttgatcagg
+agaacacaaaaaccttgctgtgagggccaggccaactcctgtcagggttg
+tttactctttctcaCAACAGAGACCTTGACATGAACACATCTGATGGAAA
+GATCAGACATTTGTTGGGACAGGAAGGGGAGGATTGAttttattttattt
+tatttgagacggagtctcgctctcttgcccaggctggagtgcagtggcga
+gatctcggctcaccgcaacctctgtctaccaggttgaagtgattctcctg
+attcagcctcctgagtagatgggattacaggtgcgtgtcaccacgccagg
+ctaatttttgttatttttagtagagatgggttttcactgtgttagccagg
+atggtctcgatctcctgacctcgagatctgccagcctcggcctcccaaag
+tgctgggattacaggcgtgagccaccgtgcacggctGAAGGGAGGATTTA
+TTTAGCGTTCCAGAAAGCCCTAATTCTGCCACTCATTTGAGCTATTTTTA
+TTTTCTTATCTAACCTTTATGTATCACACATTACAGCAGGAATATGGGTA
+AGTTAAACAAGAAAAATATCTTCCACAGTCCCAAATATCCAGCCATATCA
+ATCAACTACATCTATTTTTTTACACTCTGTTCTGTGTCAATGCACATATA
+TATTTTTATTTAGATACTGATTTATATCCTGGTTTTTCACCTTTCATTTT
+ATAATAAAGCTTTTCCAAATCACTACATAGTCTCCACAATTTTATCTTAA
+TACTTTATATGTCTCCATCAAGTTCTCTAGCAAAAGACTCTTACTAATAA
+TTCTATTTCTAAATTAAAACATAAAGGAAATTTACTATTTAAGAGCGTGA
+TTTGAATTTTATTTGTAggccaggcgcagtggctcacgcctgtcatccca
+gcactttaggaggctgaggtgggcggattacctgaggtcaggagtttcag
+accagcctggccaatatggtaaaaccccgtctctactaaaaatacaaaaa
+ttagccgggtgtggtggcgtggtgcctataatcccagctactcgggaggc
+tgaggcaagagaattgcttgaccctgggaggcagaggttgcagtgagctg
+agatcacgccactgcactccagcctgggtgacagaccgagactgtctcaa
+aaaataaataaataaataaaaagaaaGCGATTGTAGAAAATAACAAAACT
+GACCAATTATGAAACTGGTTATTTTTTCCTTGTCTTTGACATTCAGCATT
+TCTTTCttttttctttttttttttttttttttttttgagaaggagtctcg
+ctctgtcgcccaggctagagtgcagtcttgcgatctcggctcactgcaag
+ctccgcctcctgggttcacgctattctcctgcctcaggctcccaagctgc
+tgggaatgcaggcgccggccaccacgcccggctaattttttttttttttt
+ttgtattactgagacagggtttcactgtgttagctacgatggtctcgatt
+tcctgactttgtgatccgcccgcctcaggctcccaagctgctgggaatgc
+aggcgtgagccaccacgcctggctAACAttcagcatttttactatgatgc
+atctgtttgtgggtctctttgtgtttatcttacttgaagtttactaagct
+tcctgtctgtatagattattatgttttaataaatttggggccgggcgcgg
+tggctcaagcctgtaatcccagcactttgggaggccgaggcgggtggatc
+acgaggtcaggagatcaagaccatcctggctaacacggtgaaaccccatc
+tccactaaaaatacaaaaaaattagctgggcgtgatggtgggcgcctgta
+gtcccagctactcgggaggctgaagcaggagaatggcgtgaactcgggag
+gtggaggttgcagtgagccaagaacgtgtcactgcactccagcctgaccg
+acagagtgagactccgtctcaaaaaataaaattaattaattaattaatta
+gggaaatttttagccattatttttccaaaattttttcctctcctttctct
+cttcttctggtactcccattgtgtgtatttggtgcacttaatgatgtcca
+catttctttgaagttatattcaCttgtcttttttttttttttttgagatg
+gagtcttgctctgtcacccaggctggatctcccctcactgtgggttcaag
+agattctcctgcctcagcctcccaagtagctgggactacaggcacTCTCA
+CACTGTCATGCTGGAGTCAACCTCCCATTTACTCTGATTTTTTTTTTTAA
+AGAGATGAGcccagcgctttggaaggccaaggcagggggatcacttgggc
+ccaggagtttgaggccatcatggacaacatagcaagaccgcgtttctaga
+aaaataaaaataaaaaaattagctgggtgaggtggcatgtccctgtagtc
+ccagatacttgggagagttaggcggaaggatctcttgagtctacgagttc
+agggctgtagtgagctatgatcacagctctgtactccagtctgcgcaaca
+gagtgagaccctgtttcttaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaG
+ATGTGGTCTCAGTAAGTTGCTCAGGCTGgtctctaactcctggattcaag
+gaatcctcccacctcagcttccaaagtagctgggactacacgcacatgcc
+accatgccgtcttgataatgttttttaaattttaaaaataattgtttttt
+gaaatggtatctcactctatagcccaggctagagtgcagtggcataatct
+cggctcactgcaactccacttcccgggttcaagcaatcctccttcctcag
+cctcctgagtagctgggactacagatgcctgccaccgcaactggctactt
+tttgtattattagtagagatggggtttcaccatgttggccaggctggcct
+tgaactcctgacctcaggtgatccacctgccttggcctcccaaagtgctg
+ggattataggcgttgagccactgcactcaaccaaatcttttttttttttt
+ttttcgtagacagggtctcactatgttgcccaggctggtcttgaactcct
+ggcctcaagccatcctcctgattcggcttcccaaagtgctgggattacag
+gtgtgagccactgcgcctggctTATTTTCTGTAGTTACTACTGGAATTGG
+ATCTTTGGTCTCTTACATTTTCCAACTCTCGCTCTACCGCTATATTGGGA
+AACTGTTCACTGTTGTTTACTTTTTCAACTTAACTGGTGATCAGGCTCCT
+TAGGTAACAGAACTTACTCATCCAACAACTTCCCAGGGGCTCTCGTGTTT
+GGGGGCGGCCCCTGGTCCTGGTCGGGGCGCTCCTCTCATTCCCACCCAGC
+CTCACTATTGCGGAAGGAAACCCTGCGGCCCATGTCCTGCCCTCTGGGAC
+ACTGGGTGCTGATTGACGGCAACCCTGACCGTGGGCACCTCCCCAGTCCA
+GGAGATGGTGTGGGTTGTGGTGGCTTCACCCACCTACACTTAAAAAAACA
+AAAagctactcaggaagctgaggcaggaggattgtttgagcctaggaggt
+ggaggttgcagtgagccaagatcgtcccactccagccttagcaacagagc
+cagtctcaactaaagaaaaaaGTGTCTCAGGTACCGTGCCATGGCTTCAT
+GAGAACTGATGTAACCCCCGACTCTGGGCAGGGCTGCCAAAGAGTGAGAG
+AGTGGAGACTCTCTCTCACCACTCACTTCCTGGCAGCTACTTTTCTGGAT
+GCATGGGCAGGTCCCCTACACATGAGATGGTGTGGGTTGTGGTGGCTTCA
+CCCACCTACACTTAAACGAAAagctactcaagaggttgaggcaggaagat
+cgcttgagcctagcaggcgggaggttgcagcgagccaagatcaccccact
+ccagccttatcaacagagccagtctcaaagaaaaaaTTAACTGTCTCGGG
+TACTGTGCCATGGCTGCATGAGGACTGATAAAATACCCGACTCTGGGCAG
+GGGTACCAAAGAGTGAGTGGAGACTCTCTCTCACCACTCACTTCCTGGCA
+GCTACTTTTCTGGGTGCACAGGCAGGTCCACTGCACATGGTAACAGCCTG
+CCGACTCTGGAAACACAGTTCAGGATCCCAGTCCTAGTGCACTGGTCAGA
+CTTTCAAATAAGCGAATAACGTTGTGGGCAGCCTGTTTTGTTCGCTTTGC
+TGGCTTTACAGGGTACTTCCTGTTGGCCTGAAATACAATGTTGGTAAAGA
+CAGTTTTTCTGTGGCCTTTCTCTGTTGTGGAGGATTTGTTGTTTTTAAAT
+TACGATTCAGGACTGAACTGTATCATAGAATGTCCTTCTTTCAGAATGCT
+TTGTGCCAAAACAAGAAACCTCAGAATTACATGTTAATAACAACAAACAA
+AACAAAAAAGACCAATAGGCAGAAGGCAAGAAACAAAAACTATTCTTTGT
+AGATGGTGTCATTTTACCAaaagttaacagaactaaaccaacaaactatt
+gaaaattaacaacagtgagatgactatacaaatatataattaaaaataac
+tttcccatgtaaaagcaataatcaactataaaaatataatggaaaaaact
+acaataacaaaattgtgtaaaacaagtgaagaaaattagaaaaattttca
+caggaatataatactctaataaatagaaaggcatgtttctggatgggaaa
+catacactataatttttcccaaatagcttataggatttctttattccaat
+caaaacaccaatgTATAACTTTTGGAAACCTAAAGCAAGCAAAACTGAAG
+AATCCCTAAATCGCACCACACGATCAGTCCGTAAAGGCACCGCTGGCCTT
+GCTTCTAGGCAGAGGACAGGAAGGTATGGATATCAAGAGGCTGAAGACAA
+TTAATACCCACTACAATGAAGACACCTGGAAACCTGTCTCTTGAGAGGCA
+ATGTGAGCTAACCACTGGAGACGTAATTTCTAATCATACAACACTTTGCC
+TTGTGAGGTAGTGACCACCCCATTGCCAAAGGTCTGATGACAGCATAGAG
+GGGACCTAAGCATATGGTAAGGTTATTGATGAGACATGGATCCAAGCCAA
+CTTTTTCCTGCCTCCAGGTTGACCCTTCCTCTCTGGGTCTTGGGGTTTCC
+TTCGTAGCACATGAGATCTGGGCTCAACAGAGGGACAAGATTCTGAAGAG
+CTTTTCTAGTGGTGGGGCTGGATGGCCCTGCCTGAGTAATCCAAACTTCT
+TTTAGCAAGGGAGAAGCATGAGACGGCTGCTGGAGAGATCAACAGCAGAA
+CAAAATACAATAAGAACAGTAGACACCTAAATTATGTTGTGAAAAGGAAT
+CTGTAAAAGTCAGTTTTATCACAAATTGTAAATATTATTGAAATTGATTG
+CAAATTTAGATCACATACAAATGAGAGTCTGACATTCAACTGTTTTCCTA
+TATTCCAAAGTAAACAATTCCTTTCAACACTCAAGACTTAAACAGGTATT
+CTTAGAGGGTTATATGAATTGCTATCAGAAGCTGTTGGCTAACAAGCCAG
+TAATTTGGTTCTTTCACCAGAACACAGTTCCAGATAAGCATCTTTGCACT
+ATTTCTCAAGTATGAATCCCCATGTGGGGGGAAAACGGATATACTTTCAA
+TAGACACAAGTCACTCTTTGCCTTCCAAGTAAGCAGACTCCAGATTCATC
+TTCAAAGTGTTGGGAAAGGGGATCTGTGACCTGTACATTATCATATAACT
+TCAAAAAGGAAAGCTCCTTAGTCCAAAAAGCCTAGATGCTGAGGTATAGC
+CCTTGAAATGTTTTCTTCCCTGTGAATTTTCTAGCAATTTGAGGTTTTAG
+CTAAGATGGGCATTTATCCAATTTTGGCAATAATGAGATTTTTACACATT
+TATACCTTTTTAGGCAGCTTGGGAATTCAGAACTACTTATGAAAGCTCTC
+AGGTTGAGGCAGCACCATCAGACCCAGAAAGGGTTCCCAGTATTACTTCT
+GCTTTCGGGTCTTACAGGCTGAGTGGGTTTTCTCATGCCGGGTACAGTTT
+GACAGCCGACCAAATCTTCTCCCACATTTTTTGCAACCATATGGTCTCTC
+AGCCTCATGACTCTGCAGATGAAGCACAAACTCCTCATTCTTTGGGAAGG
+TTTTCCCACATTCTGGACACTTAAATATCTTCTCCCTTATATGGATTCCT
+TCATGACGACTCCGATGAGAATTCTGACGGAAGTTTTTTCCACACTGAGA
+ACAGGAATAAGGTTTCTCTCCTGTATGAATTCGCTCATGTTTATTGAGGT
+TTGTTTTATGATTGAAGCTTTTCCCACAGTGATTACAGTCATAGGGTTTT
+TCTCCAGTGTGGGTCCTCTGGTGGGAAATGAGGTAAGAACTTTCATTAAA
+CTGTTTCCCACACAGTGGACAAGTGTACCATCTCCTTGTCCTCCGATTTC
+GAGTAAGGGCAATAATACTGATGTCTACATATTTTGAGAGTTCCTCTAGA
+GGAGTATCATTCTCAATGGTAACTAACAGATTTCTCATTTTCCTTTTTTG
+TGGAATGGATGTATTTAGTCGTTCCTTTTCCTGGTTATCGGGAGGCTGCT
+GAGAGACCAAGGAAGAATCCATTTCATCATCATCTGAAGACTTTTCTCTA
+TAATCTTCATTTTCTACAGGTTCCCTCTCAGGATCTTCACCTTCAGGATT
+ACTGCCATTGACTGCTGAAACAAAGAGAGAATTTAACAACTTCTGAGAGA
+TATCACAACACCAGGCAGGAAAAAACAAGTCAGGTTTCTTATGCCACAGC
+CACCTTGAACGTCAATCTGGGGAGTGGCGGATACTGCCGTCGCACTCCTT
+TTCCATACTTATTGAGGGTGGGATACATAACTGATAAATCTTTCCATCTA
+CCACAATGCAAGCACACTTTAAAGAAATAAAATGAGTGGGATTTCACTGA
+AAGACTTCAAATGTTTGTTCTCTTCATAGGTGTTAATTACTCGACAAGTT
+CATATTCACCTTATACTCTGTAGAGCACTCAGGTAAGGACTAGGGATGAA
+GACTATACATCTATACAGGGAACCACTCATCATCTTGAAGGAGTCTGGTA
+ACTGAATAGTAAGACGAACCACTTGTAGGTTTTCACTATATTAAATATTA
+TCACACTATTATAGCACTAAATAATATCATAATGTCTTACAATGAGAAAA
+TTGAAACAATTCCAATAAGCAAAATTAAAGAGGGCACAGCATATTCATAC
+AAAAGTTTATTATTggccaggcgtggtggctcacacctgtaatcccagca
+ctttgggaggtcaaggcgagcagatcacccaaggctgggagttcaagacc
+agcctgaccatcgtggagaaaccctgtctctactaaaaatacaaaataag
+ctgggcatggtggcacatgcctgtaatctcagctactagggaggctgagg
+caggagaatcacttgaaaccggaaggcagaggttgcagtgagccgagatc
+gcgccattgcactccagcctgggcaacaagagcgaatctgtctcaaaaca
+gaaaaaaGTTTATTATTTGGCAATTAAAGAGATTACTACaactaatgaag
+ctttgggattagaagtcagtagtgtttctctttgtgtaggaaaggaagta
+gtgagtgggtacagggcacaaaagggatttttgggatgctaagaaaagtc
+cattttgggtggtgcttagtgtgtacattttgtgaaaacttgagctatat
+atttacaattggtaggctttttctatatttccattatacttcagaaaaaa
+gtcaGTGTAAGCAGATTATAAAGACTGGGTAACAAAGTGAAAAAGAACCA
+TGCTGTGGATATACTTGTGTGACAAGGGACCCCTCAACTCAGGCCTACTG
+AGAGTCAAGGGTTCAAATCAACCACCAAGACATGGGGGCTGATCCTGAAG
+CTGGAGTTGGAATCTCTGCTGGATTCAGCAGTTTCACACCAATAGATTTT
+TTTTTATTTCACttttttttttttttggcagagatagggtcttgctatgt
+tgcctaggctggttttgcactcgtgtactcaagcaatcttcccaaagtgc
+tggggattacaggtgtaagcccccacacccagccTTAATTAttttttctt
+tctttttttttttttttttttgagatggagtctcgctttgtcgcccaggt
+tggagtgcaatggcaccatctcagttcactgcaagctccgcctcctgggt
+tcactccattctcctacctgagcctccccagtagctgggactacagacgt
+ccaccaccgcgcccagctaattttttgtatttatagtagagagagggttt
+catcgtgttagccaggatggtcttgatgatctcctgacctcgtgatccac
+ccgcctaggcctcccaaagtgctgggattacaggcatgagccactgcgcc
+cgaccTAATTATTCTTTTTAATCACTCCCTTAGGATAATGAAATGTCAAT
+TTTTACCATAGCTCTTGACATGAACTACCATTCTGCTTTCAAAAACAGCT
+CTACTAATTTCATGTGAATATTAACTTTacctaatcttgttagcattaaa
+ttttaaaatatttaataggtataaaatagtttctcattgtagttttactt
+tggattttcattatgcaaaataatctactgggttaaggcttttataaatg
+tatatctttgtcaatgatttcttGTCTAAATAATTTTTAACTCAACTCTT
+CCTCTTTAACTacacttggactgcttccaaccttgtgtttttacaaacaa
+taccacagtgaataatcttctttgtacatcatttcgaatgtgttctgttg
+ctatatctgtaggtcagatttccagaattgaactcctggaacaaaggata
+agatgggtagttacagatgcaattacccttatacagggactataccattt
+tatatgcccaccagcaatatacctgtttctcaacaacctcaccatcaatg
+tgtttttatttctataaatatgaaatacgcaaaatgttaattcactagag
+gcttaatttgcacttctttttgctcctgtcacgcaggctggagtgcagtg
+gcgtgatctcggctcactgcaacctccacctcctgggttcaagtgattct
+ccttcctcagcctcccgagtagctgggattataggcatgccccaccacat
+ccagctaatttttgtatttttagtaaaaatggggttttgccatgttggcc
+aggctggtctcaaaactcctgacctcaggtgatccacctgcctcggcctc
+ccaaagtgctgggattacaggcgtgagccaccatgcccCAGCCTTTTGTA
+CGTATTTGAATCTGTCAATCTTTTCTTTCAAGGCTTCTGGGCTTTTGAAT
+CTTAATTACAAAAACCTTCCTATCCCATGGTTATAAAGGAATCACTCATA
+TTTTCTAAATGTGCTTTTTATATTTGTTTTAAACATTTAAAATCTTTGAT
+CCATGTGGACTTTTTCTTGGTATGTAAAGTAAGGTACTAATTTATCAAGT
+GGCTGTCAGTCGTCCTAACACCTTTTATCAAAAAGTCCCCCTTtatggtt
+aggctttgtgtcctcgcccaaatctcatcttaaattgtaatcccacatgt
+caaggagacatcaggtgaaggtaactgagtcatgggcgggggggccttcc
+cccatgctattctcatgatagtgagttctcatgagatctgatggttttat
+aaggggctcttccccctttactcgtacttctccctcctgctgccttgtga
+agatgatgccttgcttcctcttgcctttgccatgattttaagtttctgga
+ggcctccccagccatgctgaactgtgagtcaattaaacctgtttccttta
+taaattaccaagtctcggacaattctttataccagtgtgaaaatggacga
+atacaCCAACTTTATCACACACTAAACTCCCATGTGTATTTGAGGCTATT
+TCGGGACTTTCTGAGATCACAGTCTTGTTCCAAGGGaaaaatgctattgg
+tattgttgaaaaaaaacacatcaaattaataaatcaacaagaggagaaat
+gacctttttatgatattgtctccctagccaaaaacatagtattttttttt
+tttgctttcgttgaaatctactcttgtcctttagccttgttttaaagttt
+cctcataaatttgcacatttcttgagtttattcctaagtatttaaacttt
+catgtttctattctaatggggccttccactgtatcttctaaatgacccca
+tttatatatgtgaaagccaatgatttctgtttattcactttatttcccac
+taccttagtgaatGGTCTCATTTTTTCCCATGAGAGTACTTAAGACAAAT
+AAATGTTCTTATTTTTAAGTTTTCTGATTACTCTGTTCTACCTAtaagga
+agtatctgttaactattttgttaaatgttcttataaaggagaggcttcaa
+ttttgtcaagtatcttttcagtaactatacaagtaaacaaatgatttttc
+tcctttatATATAAGAAATATTAATAGATTTGTAttatttctgttttttt
+aattattttttttgagatggagtcttgctctgtcccctaggctggagtac
+aatgatgtgatctcagctcactgcaacctctgcctcccgggttcaagtga
+ttctcctacctcagcctccagagtaactgggattacaagcacgcaccacc
+acacccagctaacttttgtatattttttttttagtagagatggggttttg
+ctatgttggacaggctggtctcaaactcctgacctcaggtatcacccgcc
+tttgcctcccaaagtgctgggattacagccgtgaaccactgtgcccagcA
+tggggactggatttcaacacgagatttggaggggacaaatatccaaacta
+tatcaGCAACCTTGCGTCAAAGGGGTAAAAACAAATTAAAATTGCATATT
+TTTTCTAGAAAACATTATACAGAccttcatattcataggttctgcatctg
+aggattcaaccaaccaaggattgaaaatatttgagagaaaaaaaaaggat
+ggttttgtctgtacatattcagtttttttgtcattccctaaacaatttag
+tataacaactatttatgtagcatttactttgtattaggtattataattga
+tctagaaataaaatatatggtaggatatgtgtggagtatatgtaaatgct
+acaccattttatataatgaatttgagcatccatggattttggtatctgag
+tgggggtcctggaaccaatcccccatgaataccaaggACAAGTGTatatc
+agaatttatggtataacctaaagtgatgctcataagagagctcatggctg
+taaaaacatgtattaatttagaaaaatgagaataataaagcctctgattc
+aaagttagaaaaacaataggataaatttaaaagaatgaaggtattaataa
+ataccaattagaaagtaatgagttaaaaatagaaaaaaactagtaagatt
+taagcaaaaataaaccaatttccatagagaaaattgaaattatcaaaaaa
+agactagccacctacccaagaaaagcaccagcctcagacagttccacaga
+aaattcttctaaacttttaaaaattaaataattcaaatgctaggaaaatt
+tccagagtatagaaaaagaaggttgggaggccaaggcgggcagatcacaa
+ggtcaggagattgagaccatcctggctaacatggtgaaaccctgtctcta
+ctaaaaatacaaaaaatcagccggacaaggtggcaggcacctgtagtccc
+agctactcgggaggctgaggcaggagaatggcatgaaccgcagggggcgg
+agactgcaggaagccaagatcgcaccactgcactccagcctaggtgacag
+cgagactccgtctcaaaaaaaaaaaagaaggaaacttccaaattcaaaca
+agagcgaaactctgtctcaaaaaaataaataaataaataaagaCAGAgaa
+atctgagccccagtgatggaggtggggcctagtcggaggtgtctgcatca
+tgtgggtagatcgctcatgaatggcttgatgccacctcaaaataataagt
+gatttctcactcttagttcactaacaatgtggctgtttaaaagagcctgg
+caccttcctactctctttcttcctctcttgccatgtgaagtctgctctcc
+ttcaaccatgagtagtttcttgaagccctcaccagaagcagacgctgacg
+ccatgcttcttgtacagcctacagaaaactgtgagccaaataaacctctt
+ttctttataaattacccagcctcaggtattcttttatagcagcacaaaat
+gtactaagacagttgcttaagagttttaaattttccaggtggaaggaact
+ttaatttactgatctttattattaatttctagttgtactgcattgtgaca
+gatcctactttatttctactccttggaatctgagtctttgtttgttgcct
+agtatttagtcaattttcttcaatcttgaaaaggtgtattctcctatcac
+agcacacagtagctataataagaattatcttactgaaaatctgtttaagt
+gttctacgtttttccttatttttacgtggttCACTTGGCCAACACACACA
+TTCTCTGTTTCCCTAGGTTATCAAGGACTGTTCTTTGATTCCTGCCACCA
+CAATGTTCAATCCGTTATAGTTTTTCCTTTGCAAAAATTGGTTAAATGTT
+ACTGTTTCAATTATCATCACCTATAAATTGATGGCTCCCCAATCCCTATA
+TCCTCACATCTGAACTCCAATCCCCAATTTCCAAATATCTGGAGGATAAT
+CTCATTTTATTTCCCATCATGGATTCAATCTCATCCAAAATCAATTCCAC
+CTTCTTCACTACTCTGCCCCGGGTCCAAATCTTACCTCAGTCTTGCGATA
+GCTCATTATACCTATAAAAATTTCACACTGCTTATCGTTTGATGAATGAC
+TTGTCTTACAAACCAAATTGGAAGATTACAAAAGGCAAGAATATAACATC
+TTCGTAACCTGATGAATACAATTCCAGAACCCAATCCTGCCTGAGGAAAA
+AACTAGTACATTTATGAAATGCTGGTAAATGACTAAGCTTAAGCCACCAG
+CTTCAGGGTACGGGTGGAGGAAGTGGGGAACAGAGGGTGAGGATTGGGTC
+TTAGGGGCCCTGAAGTGCATAGTCGAAGTGATCTTGGAGGCAATATATCC
+ACTAACCAGTCACCCAAAATAAATGCCAGCTCTGCCCAAGACTCAGGAAA
+AACTCAGTGTTAATAAATCTGATCTTTTTATCCTTTTCTCTAAAATAAAG
+AAGATATCACATAGAGCAACCTGCGGGAAATTAACTACACTCATTACATA
+CCAATACTTCTGACCATACGGTATAATTACAGCTAAGAGTTTGACAGTCA
+TAATGGATTTCTGTCACCCCAGGCAACTTCTAAAACCTATTCTCTGTACA
+ACTTCACCCTCAGAAACAAAAAGCCCTGAAGGCAAAGTAAAAAGTGTCCG
+GCACTCAGTAAAGACATTTGTGCGGGCCTCTGCCTCTAGGGTTGCAACAT
+TTCTAGAGAAAAGGTAAAGCATCTCTAAGCAAATTATAGAGAGGCTGCTG
+CTTGATCAGTTCATACACAGCACTGGGGGACACTTGTCAACTATTACTGG
+GAAATGAGGACAAATAAAGAATGCCCCATTCACCAACCATACACGGAATT
+CATTGACAAAATTATGAGAAATGCATCTAGGAGacagtacagccctgggc
+cattactgcaaattctgatgtcagattccctgagtccgaatccctgttcc
+cctacttacaactgtgtgaactttagcaaattttgtaacccctctctgcc
+tcagttctgtcacctgtaaggtggcagtaatttctataccactcagtatt
+actctgagaagtacatgagagaataaacacatgaaaagcatttggactag
+tgcctagcatgtaacagcatataagtgctcattaagtgttaaacattact
+TTCACCAATAGTGGAATATATTTTCACTTAGGCTAGTAGTCTTCACATCT
+ATTGAACATCAAAAAGGGGAGGGGGATTACAAGAGTTAGTCATGTGTTCA
+ATGAAAACATTCAAATATACCTGTTGAGAACAGAGTTCAGAAAATGGGTT
+CAGAACAGTTTCTATATCCACAGTTTCTATGTCTGCAGGTTTTCCCTACC
+TCTCCCCTCACTGCCCCCAAGATACAGGGAAAAATGGCCACCCACCCACA
+GCTGGAGTTCTGTGGCAAGGCTCTGCTACATTGAATAAAACAAAAGTAAA
+ATAAAATGTGTGTGTGCACATAGGCTTACCAGGTGTGAATCGTCCCCCAA
+AGCTAAAGAGATGAAGGACATGCTTTTCCCAAAGCAAACAACCTGAACAC
+ACAAAGGCTGTGATTTCTTACCCAGTAACATCATTTCCCCGACACTGCTG
+TCATCTTCCTTCTCTGACGTGAGTTGTTGAGTAGGATCCAAGCTCACACA
+TTCTTCCTGGCAGTGAAATACATTCAAATCCTCAAAGACCACCAGCTCCT
+GAAAGAGCAAGAGGCCCCTTTCATCTTAGTAACTGAGGTTCACTGACAGC
+CCTACTGGTAAGAAAAGCTGACACACAAAGATCAAGGGAAGGGATAGCAA
+GAGGGACCTATAAATCCCACAGAGGTGCAGCAAAGACAGGACAGCCAGGC
+TGAGAAGGGCTCAAGGAAAAAGCAGAAGAAAAACACCCAAGAAGGCCAAC
+TCCTAAGAATGTGTTTTTACACACAGGTTGGCCAAGCACGGAAGGTGATG
+GATTCAGGCAGTAAATGGGAAAACCAAACCCACCTCAGGGTTAGCTTTCA
+AATACAGAGACACTGTCTCTTGTTCCTTTTGGACTCCTTTGGGCAGAAGC
+TTCACCAAGGGACGAGGATGCACTGGGGAAAGAGGAAGGTTTAGTTAGTG
+AAAAACTCAGTGACTCTAACACAGAGACTCCCCATACCGCGAGGCCAGGC
+TGTCCTCATTCCTTTGACAGGTAACTCATGGCCTTTTCTGCTCCTGTGAG
+CCCTTATAGAGTTCAAGCCATAAACTCTAGGGTCTTGAACCTATGGCATC
+TCCCTGTTATGAAAAGAATGACTTCTCTAAGCACCTTTCAGAATTTCCCA
+TAGAGTATTACTAAAGGAGAGCTTAGGGCAACGTAAAGTGTGAAGATGCC
+CAGAAAAAGCACAAAATTTCTAAAATTCCACATCAACCTAACTCAATAAT
+TCATCTGATTTATCCTTAAAAGATATTTCCCTCAGAATGTTTGGGTAAAA
+CTGACACTACAGAAAGATGCACACTGTTTATTCTGTGGCCTTACTCACAC
+CCAGCACTTGAGAAGAACTTCCTCTTTCCAACACTAGAATTGACTCCTTT
+TCCAATATACACCATCCTAACTTGAATTTATAACTAACACAGAAACCTAT
+CTTAGACTCCAGTACCTCCTCCTCCTCTTCTAGTGAAACAAGCATGTGCT
+TCTCACCTCTGTTCTGAAGGCTTGAGCTCACATCTTTCATAATAACCAAG
+GTCTCCTTGACTTTCTGACTGGGCTGGACCAGGCTTGGCTTGGGCAAGAA
+GGTGAGGAAGTGCTCCAGCACTAGCTGGTGGATGGTCTTGGGCCCGTTAG
+TGGCATCTCGAAGTAGGTCTTGGCCCAGCTTGGAGTCTGGCGGAACTCTC
+AGTATAAAGGACTGCTTTGGCTTTGGGGGCATAGGAACCACTTTTGCAGC
+CATCATGCCTTGCAACCACACACCACACTCGTTTCGCGGGGCCTCCAGAG
+CCACCTCTTACTAGAGGAAATCTGCCAGAGAGCCAAGCTGTAGACAGAGA
+AACCAGGGATTACCCAAAAGACCAGGCACGGCATTACTGCACTCCAATAT
+GTGGCATGGCTGGTGAGGCTACATGAGATCTAAAGAAAACGACAGCTGGG
+ATAGGGAAATCATAACTGAAACGCAGTATTTGAACAAGATATGCTTAGGA
+AGATGTGAAAGGAAGATCCTGAGAATGAAAAACAGAGACTGTGCAAACCT
+CAAGTCCAAAGGGAAGGGAGTAAGGGTGGAGCGGAGAAGGCCAAGGTCCA
+GCCTCCTGAGAAATACAAAGTGTggccaggtaccggtggctcacacctgt
+aatcccagcactttggaaggccctggcgggtggatcgcttgagtccagga
+gttcaagaccagcctgggcaacacagcaagacaccgactccataaaaaaa
+aaaaaaattagctgggcgtggcgacacaagcctgtggtcccagctactgg
+ggagctgggaggattgcttgtgcccaggaggtcgaggctgcagtgaactg
+tgatcgcgccactgcactgcagtctgagcgacaaagcaagaccctgactc
+taaaaaaagaaaggaaaagagaaaggaaagaaggaggaagggaatcaggg
+aagagaaagaaaataaaaggaaaaagaaagaaaagacagaaagaaagaCG
+GTGTGTAAAACCCACCAGGAATAGGTTAAATCAGGCTTGGAGAAAGAGCA
+ATGGGCTAGAAGACAGGAAATCTGGGGTCAATACCGAGGACATCTGCCTA
+AAAGCAGGTTGGTCACTGAATCTGGCCATACTGTACCCCTCGAACCGAAG
+CTCCCTCCGGTGCCCTTTGGGCGGGGAGGCGGTTGGTGACTCTCCCGGGG
+AGCAGATGCAAGGCCGAGGAGGTGTCCACACACCGCCTGCCGACTCCTCT
+CCGCCGTCAAAGCTCTGCTGAGAGCGGCAGGCGACATCCCACTAAGGACC
+GCCGGGCCAGGCTCACTCTGGGGCCTCTTCCGCTGGTCAAGGAACACCTT
+TACCGTAAAGCTCAGCGTGCGCCCCTGCCTGAGGCGCTCACCAGGCTCCC
+TACCCGGCCTTGCTCCCTCAGCAACGGACACGCTCCGCTCCCCAGAGGCG
+GCCTCAGCCTGGTTCCCGCCCTCACGGAGCCCCTCACCTCTCGGGGCCTC
+TGCAGCCCCTGAGCGTTTGCTGGGGACGGCTCAGAGACTCAGGCTCCGGG
+AGAGATAGAAAAACTAGGCGCGAGCGGTCGAGCCCTCCCCTCGCCCTTCC
+GAGTGCCCTCACAGGTCGCCGGCGACTATTCGTTCGCGCCGCCGCCAGTT
+GAGGAGAACGGCAGGGACTCGGTGCCTTCTGGGAAGTCGGGCGCTCTGCG
+GCTGTGACGTCACAACCGGTGCCTTGTTTCCGGTGCAGAAGCCTGGTCTC
+CCCGTTCGGAGCCGGCAGTCTGCGCTTGAGACGTTAAGACTTGAGACAGG
+CCAGAGGAGCTCTCAGGGCCGGAGGGAGGCCAGGACGGCTGTAGCCTCTC
+TGTGGTTCTGCCTGGAAGACGGAAGGCAGGTGGTTGGCTCTAGTCATCCA
+CGACGGGCTGGCACCTCTCCAGCTGCGGCCAGTCTAACCCCAGGGCCTGC
+TGGGAAATGTAGTTCGAATGCAAACAACCAATGGACGACCGTCAGGCGCG
+GCGGTTGGGGCGGGGCAGGcccccccaccgccccaccccccgcccaccca
+gcgcccgcgctccccccaccccccaccccgccacccccctaccccgccac
+tcccccaccgccctactctccccaccccccacccccctactctccccacc
+ccccaccccccaccccgccaccccccacggcgccaccccccaacccccac
+ccccctactctccccacccccctactctccccacccccctactctcccca
+ccccctactctccccacccccctactctccccacccccccaccccctact
+ctccccacccccctactctccccacccccctactctccccacccccccac
+cccctaccctccccacccccccacccccctaccctccccacccccctacc
+ctccccacccccctaccctccccaccccccTACCCCGAGGCTTAAAGGAA
+GCAAGCTATCTCTCCGACCGGAAAATCAAGACGCCTCCGCGGTTTCCGCC
+TTTTACTGCGGTTCTCCAGTAAAAAGACTGCGGAGGCGGACAGGGTGTGG
+CCGCCATGGGACTCCGCCCCCGCTCTGGTGACTCCCATAGGTTAGAGATG
+GGGCACCGACATTGCCCACTCCAGCTTGCTAACTTCTACACTGCTGTCCG
+CACCGGCCGTCTTGTTTTTAAAGACATCTTAATTGCCCTTCTCCTACTGT
+CTCGGTTTCCTTTCTCAATTTCAGCTTCCTACGGAGGCCGAACAGAGTTT
+TGTGTTTGTGCGTTGTATCCACACTCGGTTCGTTCCCCAGTGACGCACTG
+ATCAGGGTTCGGACAACTTGTGGGCAGGGATGGCCTTATTTCTCGATGTA
+ATACCAGCCTCCAGAAAGTTGACAAAAGTAAAAATATAAATGAATGCCTC
+TTCTTAAAGTTAATTATACCTGACTAATGGCTGACGATGGCTTAAAATAT
+GTTACAAAGAAACGAGTATGAAAACTGTGTGGCACCAAGACATTCTAGAA
+AAATAAGGAATATCTGCCTTTTCAGATCAAAATTTACTAAAAAGCCTCCG
+TTAATCAAAGCATTATGGTTTGAATTATGAGGCAAAACAGATAACTGAGA
+TGTCTTGAAGTAAAATATAAACCTGTGTGATTGTATTTTTTAAGAACTTT
+TTCTTGACTCTGTTAACAAACAAGAAATAGACTGGAAGATAATTGTAAAG
+ATTAGCTACACAAAAGATTATACATTCCTAAGACAAAATGAACCCCTGCC
+AACTGACAAAAAGCAAAGGCAATGAGGAgctcttcccgagaggaggaaaa
+ctaattggtcattaacatttaaaaagatgcttaaccacactactagtcaa
+gATTATCACTTTTAAAGGGAACCACATTTTTCACCTATCAAACAATGAAG
+GTGGAGAAATAGGCACTCCTTTCGCTGGTAGTGTGGTGTGTGAAGTCATC
+TTGtaatatatattaaaattaaaaGTACAAGTATGTACCCTTTGACCTTC
+ACAATCTCATCTGTGAATCTGATGTCtacaaatttcttgtagaattcttt
+gtagtgacaaaaactagaaatgacatgcatgttcatacgtaaggaaagga
+gtaaattggtgcattcatactctggaaattacccagctatgaaaaagaat
+ggattggaactatatgtacacctggagggatggccataaaataTTACATG
+AAAAAGTTTCAGAGCTACATATATTATGCATAATTATATTTTTGGAACAA
+ACAAAACACCTTGTGTATGTTTGTGTTGAGGGATACACAATAGATTATTA
+AAATGGTTACTCATGGGATggccaggcgcagtggctcatgcctgtaatcc
+cagcactttgggaagccagaggtgggctgatcactggaggttaggagttc
+aagaccagcctggccaacatggggaaaccccatctgtactaaaaatacaa
+aaattagccgggcgtggtggcgggtgcctgtaatctcatctacttgggag
+gaggctgaagcacaagaattgcttgaacccaggaggtggaggtggacgtt
+acagtgagccaagatcgcaccactgcactccagcctgagtgacaGgcaca
+ccagcctgggcgacagagtagtaagactctgtctctaaataaatacgtaa
+aataaaaataaaaTGGTTACTCAGAGGGAGGGAATGGAAATGGAGAAAAG
+GGAGAGATTACACTTTTTTTTTATTGTGTCACTTCATTTAATGAGCACGT
+CAATTTGGTAACTAAAAATAATAAAACCTTAAAAAAAAATAGAACAATAg
+gccgggcatggtggctcatcccagcacttttggaggctgaggtgggcaga
+tcatctgaggtcaggagttcgagagcagcctaacatagtgaaacccgtct
+ctactaaaaaatacaaaattagccgggcgtggtgatgcatgcctataatc
+ccagctactcaggaggctgagacaggagaatcatttgaacctgggaggca
+gaggttgcagtgagctgagatcatgccactgcactccagcctgggtgaca
+gagcaagactccatcttgtgggggcggaaaaaaaagaaaaaagaaCGATA
+AAGATTTTTTAAAACAATTTGATGGAAAAAAAGAACGATAAAGATTTTTT
+AAAACAATTTGATGGAAAAAAAAGAACGAAAAAGATTTTTTAAAACAATT
+TGATGGAATCCTGTTTTTAGAATCTAATCCGTAAAATAAATGACATAAAT
+GGATTTGAAATGATACCATAAATTAAGGGTGTAAACACAATATGTATCTC
+TATAAATGCCTTTTAACATGAAAAGATGGCTATTGTCACATACAATTAAA
+GAAATGaaatttaaaataataattacaaaaataatattCAGTATTCTAAA
+AGCAAATTAATACAATTATTTAAGAGGGCAATATGACACTTCCTATTTTA
+AGAAGTAAACTGTTCATAAACTTTGTAATGGTCAATTCTCAACTCATTTT
+AAAGAAAAActcacgcctgtaatcccagcactttgggaggccgaggtggg
+cggatcatgaggtcagaagatcaagactatcctggccaacatggtgaaac
+cccgcctctactaaaaatacaaaaattagctgggtgtagaggtacacgcc
+tgtaatcccagctacttgggaggctgaggcaggagaatagcttgaaccag
+ggagttggaggttgcagtgagccaagattctgccactgcactccagctcg
+ggtgacagaaggagactccatctccaaaaaaaaaaaaaaaaaGGTTACAT
+CATGATATGTTTATACAGTGGAAGCCAACAGAACCATTGAAAAGAGATAC
+TTTAAGTGAAAAGGCAAGTTATAAAGCAGTATGTATAATAAGTCGTTTTA
+AAAATAAAATGTTAGGCtttttttttttgagatggagtcttgctctgttg
+cccaggctggagtgcagtggcgtggtctcggctcactgcaacctccatct
+cccaggttcaagcaattcttctgcctcagcctcctgagtagcagggacta
+ccggcgcccgccaccacacccagctaatttttgtatttttactagagacg
+ggggtttcaccatgttggccaggatggtctcgatctcttgacctcgtgat
+ctgcccgcctcggcctcccaaagtgttgggattacaggtgtgagccaccg
+cccccagccTAGGCTTTTTTTTTTTTTTTTTTAACTGGAGGAATATACAA
+TAACAAGAGTTAACAGTTGCTTTCTAGAAATGTTGGCCGGGGGGGAGGGA
+AAGAGAGTTAATATTGGTTGTCTCTAAGGAGTAGGATTAGAAGGAATTTG
+TCACTTTTTATGTTTTATAAATCCATACATTTTCAAATAACAAGTGTTCC
+TTTTGTAGTTGAAAAAAACAACTATTTGAAAGGTGAGTTAATTTAGTATC
+TGATCATCTAGGAGTAAAACTAAGTGAAGAAAGAATTTCCTATTTAAAAG
+ATCTTGaatgcaaatcaaaactataatgagataccacttcacacacacta
+gaattactataataaaaaataccataaaaatgttattggtgaggatgtgg
+agaaaatgaaaccctcctatattgctggtggtccagctactttggaaagg
+acctaaaatggtccagctactttggaaaacagtttggcagtttctttttt
+ttttttttttttttttgagacggagtctcgctctgtcgcccaggctggag
+tgcagtggcgggatctcggctcactgcaagctccgcctcccgggttcacg
+ccattctcctgcctcagcctcgtcagtagctggaactacaggcgcccacc
+accacgcccggctaatttttttttgtattcttagtagaaacggggtttca
+ccgtgttagccaggatggtctcgatctcctgaccttgtgatccgcctgcc
+tcggcctcccaaagtgttgggattacaggcgtgagccaccgcacccggcc
+ggcagtttcttaaaatagttaccatgtgaacaagcagttcaatttcaagg
+tataaactcaagagaaatggaaatgtgtgttcacacaataacgtgttcac
+actagcctaaaagtggaaacaacccaatgtcctgtaagtgatcagtggat
+gaacaagaagtgatatttacatgtaatcatataatggattattcagtgat
+aaaacaggatgaaagtagtgacacatgctgcaacgtggatgggccatgaa
+aacacactaagcaaaagaatcagtcgcaaaaaacacatatcgtatgattc
+cacttaacatcatatgtccagaataggcaaatccatagagacagaaagta
+gcctagtggtttacatgctctggggaatgggggagaatggggagtgactg
+ctaatacatatgataaaatgttctggtattagtggtgatatttatacaca
+caatgcatatactaagaaacactgaattttccactttaaaaggatgcatt
+ttatggtatggatttagagctccataaaATAACCACTAGGCAGAGAAATT
+TCATCAGACAGATTCAAATGTGTACTACCTAAAACATTTATGTTtttgtt
+ttccttttttaatttttttattttttgagacagggtgttgttctgttgcc
+gaggttggagtgcagtggcacaatctcggcttactgcagcctctgcctca
+aaggctcaagcaattctcctgcctcagcttccggagcagctgggactaca
+ggtgctcaccaccatgcctggctaatttttgtattttctggtagagacga
+ggtttcgccatgttgcccaggctggtctcgaaccctggatgcaagcgatc
+tgcccacctccggctcccaaagtgttgggattgcaggcgtgagccaccgc
+acccagccTAAAACATGTATGAAGAAGTACAGCAAAACACGAAGTTCAAT
+ATGTAGATTCCAAATAGCAAGTATTCAAAGGAACTGTACAATTTCCATAG
+AATGAAGCAAAAAGCAGAAATTCACATGGAAAAATTCACAGCCTCATTAA
+CAGGTAATGAAATAAAACAGAAGTAAGGCCTCATTACATCCCTATTAAAT
+CAGCAAAAAAATTTTAAATGGCAGTCATTGCTTTGGGCATGAAATATTTT
+AAAAATCTTTGCAAAGGATGGTATGGCAACCCGTAGGAAGCATTATCAGA
+TATTTCACATTCAGGAACCATTTTAGGAATAACACAGGAGAAAAAAATAT
+GTATATGGTGAGGTGGTGGAAAATATACACAAAGATATTCATGAAAAGCT
+TATAACAAGGGAGAATCGGGAATAAGACATGACCCACCGCAGGGAACAGC
+TAAGCCGTAGGTCATGTGAACTGTCCTGGGATGTGGATTACTCTTATAGA
+ATAAAACTCGTGGAGGAAAGCCCAGCAAGTTTACCTGCTCTCATCATAGC
+CATGGAGTATCTGAGTCTAATCTACACTCTAGTAGTGAAGACAGAGGAGT
+TGGCATAGGAGTTTGGAATTTAATCTTCATTTGAtttttttcttcttaca
+tccactttttggagacagggactcactctgttgcccaggctggattgccg
+tagtgcagtctcagttcactgctgcagcctcgatctcctgcgctcaagcc
+atcctcccacccccatccctatggctaatttttgtattttttgtagagac
+gggttttcgccacattgcccagctggtctcaatccctgggctcaggcgat
+ccacccgcctttgcctcccaaaatgctgagattacagatgtgagtcacca
+tgcccggccCCTTTACATCTCTTTAAATGAAGGACAAATGCACGGGATGT
+GTGTGAAGTAGAACCTAATATTCCACAACCCGCAGATTTTCCCATACAAA
+CCAAGACAGAATAATCTGACACTTGGAATACATGCCAAATGTTTTTCCAT
+ACAGTAGTCCCATCTGCTTCCTGAAATGCAGTCGGGAAATGGGATTCCAC
+AGTGATTGAGTGACAAATGCAAATGACCAGATTTTCTAATTTTTTTATTC
+ATGAGGCCCAGTCAATTCTCTTAAGAATCATggcccggcatggtggctca
+tgcctgtaatccctgcactttgggaggctgaggtgggtgcatcacctgag
+gtcaggagtttgagaccggcctggccaacatgatgaaacctcatgtctac
+taaaaatgcaaaaaattagccgggcatggtggcgggcgcctgtaatccca
+gctacttcggaggctgaggcaggagaatctcttgaacctgggaggcggag
+gttgcgagccaagattgcaccactgcactccagcctgggtgacaagagca
+aaactttgtctcaaaaaaaaaaaaaaaaaagaaTCATAggccgggcacag
+tggctcatgcctgtaatcccagcactttgggaggctgaggcgggtggatc
+acctgaggtcaggagttcgagaccagcctggctaacatggtgaaaccccc
+gtctctactaaaaatacaagaaaaccagcctggtgtggtggcacgcacct
+gtaatcccagctgctcaggaggctgaggcaggagaatcgcttgaacctgg
+gaggtggaggttgcagtgagctgagatcgtgccactgcactccagcctgg
+gccacagagcaagatttggtctcaaaaaaaaaaaaaaaaaaTCATAGTTC
+ATTAATCCAGGTACACAAATACTTCTATCCCAATCCAGTCTGCTTGCGTT
+TCTCTAGGCTTCCCATATCCTCAAGACAGAAGCAGAGAGAACAAGGGGAC
+ATATATCCTTGCCGTGGGGTTCTGAGGGAAAATGAGGGCCAAATCTTCTG
+TTCAGGAGCACCTGAGAGTGCCACCCACCAGGGGCGGATTATGCAACGAC
+TCCGTACTTCCTCCTCTGAAATCCATGGTGTGTCATCAGTACATGTCTTC
+ACCCGGATTGACTAACATGTTCGTTCCTAACTTACCTCTGCTATAATCGG
+GTAGGCTCCGTGGGCACAGTAACTATTTTGTTATTTTTGCATTTCCCATA
+GCAGCTAGCACCTAGTCGGCATTCCGTGACTATTGAGTGTGAATGCAAGA
+TACAAGGCCAGAAGCAGGAAGAGAGATGCAGTGTTGGGCATTCAGTCAGG
+CCCCTGACCACCCACTGGACAGATAGTCAGAGGAGCTGTGTTCTTCCCTC
+CATCACGTGTCCCAGGGCTGAAGATAGGTTGAAGGGGCCCAGAGAAAGAG
+CAGCTGGCGAATGTATAGATGTGGGATCTGGCTGTCACATTGTAAAAGGA
+GATGCTTCCAACTCTGTAGTCCACGAAGATGCCCACACGCTTGGGAGGCT
+CCTTTATTAGCAGGCGGGTCGGGGGAACGCTGGACGCCTGGTACTCATTT
+TCCTTCATCATTATCACCACCCAGTAGCCATTCTCTGGCGACAGAGTCAT
+GTTCCCTTTCCTGCTTATGGATGTCTTGCAGGCTCCCAGGATCCATGCTG
+TCTTGTCTCCAACCTCCACCTCCCAGTAACGGCGGCCAGAGAGGAAACTC
+GGAGAGCCCAGAACAATGATACAGCTGTCAAATCTTTGCGGGCCATCAGG
+CAGCCTCTCCCACTTGTTTCCAAGTCTAACACTCTTCAGATCATCAGAGA
+AGATGAGGTTGGGGTAAGCGGTTTCTGCATCCAGAATCACATTAACTGCA
+AAGAAAATTTGAATACCTAGGTAGGGGTCCATGGGCAACATCCCTACAGG
+GTTCTCCCCACCTGCAGGAAACAGGGACAGGGTAGTTCTTCTGGAACGTG
+GTAGGGGAGAGCACAGGGATCCAGCAGGCCAGGGCCACTTGCCTTGATCT
+GGGCACTTACCAGCATGTGCCTGAGCGCCAATCAGCTCCGGAACTACGGA
+GAAAAATCAGATAGGGAAAAAAATCCTGAGCATTAGCATTAAGAGGGGCT
+AAATTACACTGTCCTGACAACAAGGAAAGACAAGGAACCCCCTGCTTAGG
+GCCCTGCATGCTATGTTGGGTATAATCCCGTTCCTCCCAGGAACCCAGGC
+CATGTTGGGGACTGTGGTCTAATGAGTCAACTCAGTCAATGAGTCACGCA
+CAGAGCCTGGGGGGCCTGCCATGACCTTTCTCCTACCTTTGCTCCAGGTG
+TTTGGTTTTTTTTTTTGTCTTCTAAATAGGGCCCCTCAAGTCAACAGCAC
+AAGGGAACACTGCAACAACCCCAGGCCAGCACACACCATTACCGCTGGAC
+TCACCATTGAACATTTCCATTTCTGAACGCAGGGTTTCTAAAATGTGGGA
+AAGGGAGCAGAGAGAAGCTGGAGTTAGGTCCCTCAGCCAGGGACAGATGG
+AGGAGAGGTTGAAGGCAGGTCAGCAAGACCAGGGGAAGAGGAGGGAAGTG
+AGGGGCTCTGGGCTATGTGGATCTTAGGGAGGAAGTGAGCATGCACCTCC
+AATCTTCTCCCAAGCCCATCTACCTGAGAAGTACTTTGTGCTCTTCTCCA
+CAAACTCTGACTTCTGGTGGAGGAGTTGGATCTTTTGTTTTATCTCTTGA
+GGAGTGGTCCACTTTTCAGGGACAGGCACTGTCTTAGCCCTAGAGACAAA
+AGACTGTTGACCAGAGAAGGCCGGAGCGAGGGGGTGGCCCAAGTACCCGT
+GAGCTGGAAATGAACTACATTCTCCACAGGGCACACCTAGCCCAGCCTGA
+GCTACACAAAGAAAAGTCTTCCCTGGATTCAGAGGTCTAAATGCtggtcc
+tcaactttggccacagactgtcatgtactggggtgctttaaagacatgga
+tatcaaaaccacaAGGAGTTTTCAGAATGGACTTAAAATGACATTGATAT
+TATCTACTAGAATTATCTATGTCAAATTGATTATACACCCCTTTCTTTCT
+ATTGAAATAAAAAGATAATaaatgaaaaaaaaacacacacaacaaaatat
+cccttcacatccattagaatggctattataaaaacagcaacaacaGAAAA
+AAATAgaccaggtatggtggctcatgcctgtaatcctagcacttcaggag
+gccggggcagtgggatcgcttgagcccaggagttcaagtccagcttgggc
+aacatggcgaaaccctgtctctattaaaaatacaaaaaagtagccggaag
+tggtagcacatgcctgtagtcccagctactcaggatgccagctactcaga
+atcacccgagcccaggaagctgagcctgcagtgagctgtgactgtgccac
+tgctctccagccttagtgatgggagtgagaccttgtctcaagaagaaaag
+aaaggaaggaaggaagaaaggaaggaagggagggagggagggaaggaagg
+aaagagaaatggctgggcacggtggctcacgcctgcaatcccagcgcttt
+gggaggccaaggtgggtggatcacttgaggtcaggagtttgagaccagcc
+tggctaatatggtgaaaccctgtctaccaaaaaaattagctgggcatggt
+ggcacgctcctgtagtcccagctactagggaggctgaggtgggagaatcc
+cttgaacctgggaggcagaggttgtagtgagccaagatcgcgccactgca
+ctccagcctggatgacagagcaagacgctgtcttcaaaaaaaaagagaga
+gagagagagTGaaacagaagaaaataagtgatggcaaagatgtggagaaa
+ctggagcccctgtgtgctgctggtgggaatgtgaagcgatgcagcccctg
+tgagaattaggatggtggttcctcaaaaaaaattaaacacaggataacca
+catggtcccgcagttccacttctgggtaggtacccaaaataacaaagcag
+ggtctcaagcagatatttgtacacccttgttcatagcaacattattcaca
+aaccaaaagttagaagaagtcccgatatccatgaatggataagcaaaatg
+tatgaacacacactggactatgattcagccataaaaagaaaataaattct
+gatacacgttacaacacggatgaagcccgaagacattatgctaagtgaag
+aagccagacacaaaaggacaccgggattttgtaaagctcccaggtgattt
+taaggcttagccTCTTCCTGTCCCTTCCCTCCCCTCCCCTTCCTGCTGGG
+CTTAGCCCAGCTCCACTCCAAACAAGCTTCCCAAGGCCACCAGTAGGCCT
+GAAGGGGCAGCTTTCATCAGATGAACTGCACGGGACACAATGCACTCGGA
+AGGTTTCTTAGGGAGCCTCCATCTTGTTTCAGCAGGATGGGCTGAATTCA
+CCCTTCCCAGTCTGCAGCTCCATACCCGGCCAGCCTCCCTGCTGACCAGA
+TGCCCTTCTCCCTATCAAATCCAGAGAGGCTTTGGGAAGCTGCAGAAAAA
+AGGAGGAGTCTGGAATCACAGACCCCGGGGTTGGGAACATCTCCCTCCCA
+GGTCCCTTCTGGGACTGTCTCCCCCATATGCTTTCTGCAAGACACCCCAG
+GGTACACCACAGGACCTCGCTGTACCTGTGCAAGATGTCTCCAATGTCCT
+AGGAGAAAAAAGAAGGAAACTGTCGGTTACCAGGCTCCTAGTGGCTGGGC
+TGACTCCTGGCCTCTACTTCTGGGCTCCTGGACTTTTAGCTCCCCGCTGC
+ACTTACCAGGGCTCCCTGCCCTAGGGTGTCAGTGGAAGTGGAGCACCTTT
+CTTCAAGTCTAATTCTAACCACGGGAATTCAGGCATCCCAGGTGGCGAGG
+CCTGCAATGGAACGGCCCTCAAGCCCTGCTGATCCCTTCTGGGAAATGGC
+AGAGATCCCCTGGATACCAGGCCACCCTGGGCTCCTGAGAGACCTCATCA
+AAGGGGTCTGGGCACAAGAGGCACTGTGGGTCACCAAGACCAAGTCCTAT
+CCTAGGCCTTAGGGGCTTCACCCACTTGTTCCAGCACGGCTGATGGCAGA
+GCTGGGAGCCTGAGGCATCCTGATAGGCACAGGGGACCCAAGAAAGCCGG
+GCCCAGGCACACCCACCTGCAGAAGTTCCCATTCTGACTGGCACTCCTTG
+GCCTCCAGTTCCCCAATCAGCGCATCGAGCAGGGCGATGTCCTGGGATAC
+GCGGGTGTCATATGCCTTCCTGATCTGCCCAACCATCTGGCCCACGTCCT
+CCAGTGAGGCCACAAAGAAATGCTCTTGCTGCTCCAGGAAGTAGTACACC
+TGCTCCAGCTTCCTCTGCACCCGCTGCTTCAGCGCTTCAGTTTGTTTCTG
+GGGAGCAGAGGACAGGGAGGTATGGGGGTCTGTGCTGTGGGTGGACGTGG
+ATGTCCAGGAACCCCCAGAAGCCCACCTCCTGGAGGTGGATAAGAGGTGG
+GCTTATGCTGCCTCTTCAAGGCCTAGATTCCAGAGCAGGAGGCGATATTG
+TCTGGAACCTTCCAGAAAAGACTGAGCATGGCTGGGGCTAGCTCTGGGAA
+AATGTCCTTAAACCTGGtgttaaggtttaactgtgtcccttccaaaattt
+acacgttgaagccctaacccccagtactcagcatgtgatcttatttggag
+ataagagttcttgcagatgtaattagttaagatgtggtcctactgggatt
+gggtgggtccctaatccaatataaatgttgtcttataaaatggggaaatt
+tgggctgggtgcattggctcatgtctgtaatcccagcactttgggaggct
+gagttgggcagatcacttgagatcaggagttcgagaccagcctggccaac
+atggggaaactctgtctttactaaaaatacaaaaattagccaggagtggt
+ggcatgtgcctacagtcccagcaactcgggaggctgaggcaggagaattg
+cttcaactggggaggcgaaggtttgcagtgagccgagattgcaccactgc
+accccagcctggacgacggagtgagattccatctcaaaaaaaaaaaaaaa
+aaaaaaccctaaaaaacaaAAAAACCAGCccaggcacgatggctcacacc
+tgtaatcccagcactttgggaggccgaggcaggtggatcacctgaggtca
+ggagtttgagaccagcctggccaacacggtgaaatcccgtctctactaaa
+aatacaaaaattagccaggcgcggtggcaggcgcctgtaattccagccac
+taaggaggctgaggcaggagaattgcttgaacctcggaggtggaggttgg
+agcaagccaagatcgtgccactgtactccagcctgggtgacagagcgaga
+ctccatcttggaaacaaaacaaaaaaaCAGAGAGTAAATTATGAAGTTAA
+AAGTGTTCTTggccgggcgcagtggctcacatctgtaatcccagtacttt
+gggaggccaaggcgggcggatcacgagttcaggagttcgagaacagcctg
+accaacatggtgaaaccccatctctactaaaactacaaaaattagccagg
+catggtggcactcacctataatcccagctactcaggaggctgaggcagga
+gaatcgcttgaacccgggaggcagaggttgcagtgagccaagatcacacc
+actgcactacaacctgggtgacagagcgagactccgtcacaaaaaaagaa
+aGTGGCGTTCTCCTCCCTTTTCCTCAATCCCATCTTTCTGCAGTAGTCAC
+CGGCATAGGTTGCTCTCTACCATCTTCTGGTGAGTATGAGAAAGCATGAC
+AGGATCCTCAGAGGTGACCCCTGCCTGCTGGGGGTGGTCTCCCTCTACAG
+GGATGAGCTTACCCTTGGCTGCTGGTTACCCTCTGTCCCCTGAGAGGAGG
+TGGCCATCCCTGCTGCCCTGTGAACCACAGCAGAATCTCGGGGACCCCTG
+CTCACTCTTCCCACCTTCCTCCCAGGGACGGATGGGCCATCAGCCACCTC
+TGACCTTACCAGAAAGCTCACTGCCTTCTCCTCCCCATAGGATCGCTGCT
+CCTCCCCTGATTTTCTCAGCTTCTTCAGATGCTCCAGCTGCTTCTGAATT
+TTCTTCTGGAAAAACAGCACTTGTTGAAAAGCTTGAATTTGGCTCCTGCC
+ATCTTTAGCTGGTGCCAACTCTGGAGGGGAACATCTCCTTCTGGTAGCAA
+GGCTGAGGGTGCTGCTGCCAGCGGCATGGGGAGGGGTGCTCAGGAAAGAG
+GAGGGAGGAATGGCTGAATTGCCAAAGGCAGCAGAGCTGAGAGGCacttc
+ctctgagcctctggattcagccatacctgaagccagctccccctggatct
+ctgagcaacataaacctgtagctcccctctttgctggactggtttatatt
+gtgttcttgccatttccagcccaagaatgctggttaatgcaCCAACAACC
+CAGAGTTGTTGGGAAAATGAAGTAAGGCCCAGTGTGTCCAAGTGCCTGGC
+AGAGAAGAGCCCACAGGCAGGGAGTGCCTACCTTGTGTTCCAGGGCGACC
+TCCTCAATGGGGCGCACCCGGTGGCCTTGGTGCTCCTGACTCAGACTGCA
+GATGAGGCAGATGGGCTCATCGTGATCCTCACAGAAGAGCAGCTGGACCT
+GCTTCAGGTGGCGCTTACACTGTGGCAGGGGCTGGGGGCTTAGGCTTCCC
+GGGCTCTTCCTTTCATGGGAGTCCTGGCACCGGGGGCAGCCAGGTGAGCG
+GCTGCCTGAGGCCTGGGGGTGCCCAGAAACTGCCTCGGGGAAGCTGCAGG
+AATCACGCACACAGGTACCGTCAACTGGGTCTCCTTCCTGGGCGTGGCAG
+CGGGGACTCGCAGCCGTGTCTGGTGGCCTTCCTGGGGACATGCAGTGGAA
+AAACCCCCTGAATGGCAAACCCAAGTTGCTTACACAGAGGTATCACAAAG
+CACAGCGGACACAGCCCTTGCCTGAGATGTGCGAGTTCTCAGTTAGACTC
+TGCCCACTTCCTAGCTTGTCCTCCCCCGACTTCCATCCAGTGAGGAAGCA
+AACAGGCCACTGGGCCTGAGAGCTAAGGGCCAGACCTCAGACATTCCTGA
+GCCTTGGAATTCTTGGGCATTTATCCTAAAGAAAGACCCATGGCCTTGTG
+CTGTTCCTCCTGCACAGACATAGATCTAGCAGGTGATGCCAAGGAAAGAG
+ACATTCTGACCAGTGTTCCTTTGCCACTTGAACCCATCCCTGGCTGCCCA
+TAACGTgagtggaggcttccaggggatggtgacttgtgtacctcgctcct
+agctggatcccagcccctagcagagtacctggcaaatgcaagcatttgga
+aaatgagtattgaatgaaggaatAAATAGACCACTGCTCACATATGAGTT
+caataaccattaaatgaaagcaaagaaggggctgggtggtggctcatgcc
+tataatcccagtgctttgggaggccaaggtgggaggactgcttaagctca
+ggagtttgagaccagcctgggcaacatggcaagagcccacctctacaaaa
+aattaaaaaattagccaggtgtggtggtgcacacctctaatcccagctac
+ttgggaggctgagacaggaggattgcttgaacctaggaggttgatgctgc
+accactgcactccagcctgggcaacagagtaagatgccatcttaaaagaa
+aaagcaaagaaggggggcattatagggctaaagactggaactcatcatga
+agacctaacagttatgaatagctctactccaaGACTCTAATTGCAACTTC
+ATAAGCAGACATGCCACGAGATACAAGAAGAAATAGAAACACAAggccga
+gcgcagtggctcacgcctgtaatcccagcactttgggaggccgaggcggg
+tgggtcatgaggtcaggagttcaagaccagcctggccaagatggtgaaac
+cctgtctctactaaaaatacaaaaattagccggacgtggtggtgggcacc
+tgtaatcccagctactcgggaggctgaggcaggagaattgcttgaacccg
+ggaggcggagtttgcagtgagctgaagttgcgccactgcactccagtctg
+ggtgaccaagagagactccatctcaaaaaaaaaaaaaaaaaaaaaaagaa
+aTAGAAACACACTCAATCCTTTAGCCCCTGCTACCTCCTCCCACCTCACA
+GTGTCCCAGAAATTCACAGCACATCTGTAAATgagactgctagtagtcac
+cagaaattattctccctccttctctcgtgatagaattaattgtccacgtt
+tccctgtttccctgcctcccattgccccccaaatgccctgcatttctcag
+cctcctttgcagttaggtgtggctatttgacaataatatgaccaaaggga
+tgtaaatggaggtgtcacaagcagcttctagaaacttctagagctttccc
+gagggatactattcccctctgttcctccatcttgctgcctggcatgagga
+cgtcaccttctgagagcagaagcttgaggacaaacttggtgggacagagc
+aacagcaggaccccagggtcctggcccacggatctgcctgggaccgcctg
+tgtatcatttatgtgaaggaggcacaaacttcttttctgttgaggttact
+gttatttgggtgtttctattattcacaaccaaacataattttaaTGACTA
+CCTCAGCAGTAGATAGTTAGGACTTTAGCCAATAGGCTTTTCTTTCTGCT
+GAGAGAAAGGCAAATGGTAGAATCTCAACCCCATGATGATGCATTGCTGT
+GAGGTTATTGTGAGAGGGAGTATTTTTAACCAGTCTTCCCCAGATTTTCT
+ACCTGGTGTCCATAAACCCCTTGGATTCTAAAGATGGTCTTCAGAGTGTC
+CAAGAACTACCTGAAATTTGATGTGACATTTGTGAAGCTGTGCATATATG
+CATTTTTCAGGGTCTAAGCCTGCATCAGATTAACGAAGCGGCCCTAGAAG
+ACACCCAGGAATCCCAATGATATAAATACAGTGGGgacctggtgcagtgg
+tgcacacctgtaatcccagcagtttcggaggcaaagatgggaggattgtt
+tgagatcaggagttcgagaccaacctgggcaacatagcaagaccccatat
+ctaaaaaaaaaaaaaaaTTAAAAAAAATACAGTAGGGATAAAAGAAAATT
+AGGGGGGAAATACTTCAGTACTTTTCAGGTCACTATTCCTAAGGATGCTA
+GGTTTTCCAGATCCCAGGGTCCTTTCTCACTGGAAGACCCAGGGACTTCT
+GGATTTGAAGACTCATGCAGCATACCACATCCTTTCCCCTCCCAGGTCTC
+AGGGGTCCCTGGACTCCCAAttcttttttttttttttttttgagacagag
+ttttgctcttgtcgcccaggctagagtgcagtggcatgatcttggctcac
+tgcaacctctgcctcctcggttcaagcaattctcctgcctcgaagccttc
+tgagtagctgggattatggacacccgccaccacgcccagcaaatttagta
+tttttagtagagatggcgtttcaccatgttggcaggctggtctcgaactc
+ctcacctcaggtgatccgcccccattggcctcccaaagtgctgggattac
+aggtatgagccaccgcacccggccTGGACCCCCAATTCTATTTCTCCTCC
+TTGAGTGCTGTGATTTCTCCTCTCCAGCCAACAATGCATTGGAAAGTGTG
+TTCCATAggctgggtgtagtgactcacacctgaaatcctagcacttttag
+aggctaaggcgggggatcgcttgagcccaagagttcaaaaccagcctggg
+caacatagacagtcctcgtaactacaaaaaatacaaaaaaaaaaaaaaaa
+attaaccaggtgtggtggtgagcacctatagtctcagctacttggaaggc
+tgaggtgggaggatcgcttgagcctaggaggttgaggctgcagtaaactg
+tgctcacactactgcactccagcatgggagacagactgagactctgtctc
+aaaaaaaaaaaaaaaaaaaaaaaaggaaaGTGTGTTTCTGAATGCTGCCC
+CCACCACGAGCATGGAATTGTCACCTGGATAGCCTCGGTACCCTCTAAAC
+TGGTGGcatttttcttttacagtttttttttagtctctttacctataggg
+acagctgcttaaaaaaatccagatggcctggagcctcctgatcccttgcc
+aaaaaccagaggaagttaagatcagagcaaaaccagtgcaaactggaaga
+ggtgacttccagttaccttaagatcatttacacattgttataaggctaaa
+ggtccctcccctaaaagaagatggccagggttttgtgtccatgcgatgta
+ggaagaagcatgctggggacagcgcctgcacatatggaaccctgccctgg
+gcctgcttacctatctcccttcccctccctggactctaaaatcgccctgc
+ctcccatccctggcaagcagacgcctgcagaggtgagctccccttctcca
+ttctttggccactgataacacctgattgcctttttcaatcggacattctt
+tctttctttttttttccccccaaaatgtttaagagacagggtcttgctct
+gttgcccaggccggagtgcagtggcacatcctcagctcactgcagcctgg
+aactccctggctcaagcaatcctcctgcctcagcttcctgagtggctaga
+attacaggcgtgtgccaccatacccagctaattttttttttagttttgta
+gaagtggagtctggctacgttgctcaggctggtgtgcagtggcatgatct
+cagctcactgtagcctggaactccgtctgctcaagtgaacccgagcagct
+gggactacaggcgcgtgccactattgtattttgtagagatggggtctcac
+tgtgttgcctaggctagtatggaactcctggggtcaagagatcctcccgt
+gcaggcctctcaaagctctgggattacaggcgagagctaccacgccctgc
+ccaacctttgggtttttatttttttaatttcgtttatagagatggcgggg
+gtctcactacattcaccaggctggtctcaaagtcttggcctccagcaatc
+ctcccgccctggcctcccaaagcgctgggattacaggcatgagctatcgt
+gcccggccagccattctttctctgcagccgatataaagtaggaaagaaca
+caatttaccggtgacCGAATGTTCTGGATTTCCAGGGCCTTCCTTCAGGT
+CCGCAGATGCCCCTCCATCCGGAGTGGGCCTTGCCCGGGGTTCTGTTGCC
+GAGTCCAGATTCGCAGCTGTCTTTTCCTCTAGAGTCAGGAGAATTTCTGG
+ATTTGCGGGCGCCTTCTCCCCTGTAGAAATGGTGACCTCAAGGCTTCTAG
+GTCGCATCTTTCCCGAGGGCAGGTACACTTCGAAGGGCCTGCACTCCTTC
+TGCCCCGGGGCGCCCCCCGCCAGCCCCTGCAGCCTCCCCGCGGAGCTGGC
+GTTTCTGCGCAGCCGGACCTCGGCCTGGCCCCCCTCTAGCGCCCTGCAGG
+GGCCGGGGCTTCTCCCGCCCGGCAGGGCCGGGCTCCGGGTCCGAGGCTTG
+CCCTGCGCGTCCAGGCCCTCCGAGGCCTTCTCTCTGCGTTTGCTCAGGGG
+CTTCCTCGACAGCCCCCTCCCGGCCTCGGGCTGGCTGCACCGCAGGCTGG
+CAGCTCCGCCCCCGTACGGCCGAGGGCCGTTCCCCTCGTTCCCCTCGGGG
+TGGTCTGGAGTCTTCAGGCTCCTGGGCTTGTTCTCCCCCAGGGAGCTGGA
+CGCTGCGGAATCATCTGTGCCGTTTTCTTGTGTGGAATATTCTGGAAGGA
+CAACCAGATGCAAAATGATGAAGCTGTCCCACGTTTAGGGCCCAAGATTC
+AGGGCAGAGGAGAGAGAATCCCCTTGGATATTAAAGTTTAGAAATTGAGG
+AAAACAACGggccgggcgcggtggctcatgcctgtattcccggcactctg
+ggaggccgaggcgggaggatcacctgagatcaggagttcaagaccaacag
+ggtgaaaccccgtctctactaaaaatacaaaaatAagctgagcgtggtgg
+cgcatgcctgtaatcccagcttctccagaggccaaggtgggaggatcatt
+tgaggtcaggagttcgagaccagcctggccaacatggcaaaaccccgttc
+ctactaaaaataagaaactcagccagacgcggtggtgcgcacctgtagtc
+ccagctactcgggaggctgaggcatgagaatcgcttgagcccgggatgtg
+gaggttgcagtgagctgagatcgggccactgcactccagcctgagtgaca
+gagcaagactccatctcaaaaacaaaaGTTCAGGACTTCCTAGACTAGAC
+AATGGCAGTCAATTACCATTCAGTAAGAACATGCTTGATGTTGCTATGTA
+tttctctctctcttattttattttttgagacaggatcttgctctgttgcc
+ctgatgtgatctcagctcactgcaacctctgcctcccaggctcaagcaat
+cctctcacctcagcctgttttctgttttttcaatagctgaaaatacaggt
+gtgtgctaccacgcctggctcatttttttgtatttttggtagagacaggg
+tttcaccatgttgcccaagctggtctcaaactcctgagctctagcaatcc
+acccaccttagcctcccaaagtgctgagattatttataagtgtgagccac
+catgcctagccTATATTTCTCAAATAGTACTTTTCAAACGTTTTAAGCAG
+GACAACTGTTTCAAATAAGATCTTACACAGGTCAGCAAAACCCAGATTAT
+ACGCTTTAAAAATAAAAATAagccgggcacggtggcctatgtctgaaatc
+ccagcactttgggaggctgaggcgggaggatcacttgaggtcaggagttc
+gagaccagcctggccaacatggtgaaCAGCACTGAGAAGATTCTATACCA
+ACCCCGTTCATATGATTGCATAGCAATCCCTTTTTGCTAACCTAGAGATG
+TTTGTCTGACATGAGTATTAATCATAAATGTAGTGAAGAAGTCTCAAAGA
+ACAGGTGTTCCAGCTCCTGCCTTTCGTGACCCTGACCTGCTTCTTAAAAA
+ACCCATTAGGAGCCTGAAGGAAGTTTACTAACCCAGTTCCAAAGGCCAGA
+GTGAAGAAAGGGACGTTCCTGAACTAAAGTCATCTGGATTTTGGTAGACC
+TGAGACTCCCAATCCCCAGGTCAGAGTGAGCTGCTCTGAGCTCCTGGTCC
+CCTTTCCCACAAAGCAGCCAGCACTCAGCACTGGATGAGGAGGAGGCCTG
+GGCCCGCTTACCCTGAATGGCTGCCCTGTGGAGCTCCTCGGCCAGCAGGC
+GCTGGTTGATGGCCCGCAGGACCTGCAGGGTGAGCTGCACGGCGTACTCT
+TCCCCATAGTAGGTGACCAGCAGAGTGGCCATCTTCACCGGCCTGGCTCT
+CTGGATCTGGCTCCGGGGGATCCTGGAGTGCTCCTTCTGCACACTGGTGT
+TCTGCAGCTTGAACTTGAACTTCTCGAAGTCATAGGGCACCAGCTCCTCC
+AGGGTGGACAGCAGATGGTCACTAGGGGTCTTAGCCATGGTGCTGAGCAG
+GAGAGGCTCGAGCCAGCTGTCTGGCTTCTGGTAGGAAAAGAAGCCTCTGT
+CCTTGGTGAGCAAGAAAAGGCAGGTTGTGAAATAGCGGAAAAGGCACAGG
+AAATGCTCTGTGTCTTGGTGGGAACTGAGACTAAGGGTAAGGGTGTGTCC
+ATGCCGGCTGTGTTCTCTTCTTACAGGTTCAGAGGATTTTCCAGCTGGGA
+GGGCTCCATGCCTTGGCAGACATGTGCCCCCACACCCCTCCCAAACCCTG
+GACCTCGCCTCCACACTAGACCACAGACAGATGGGCAAGTCTGCAAGGGA
+AGGTCTGGGATTGGATTCCAGACACCCCCTCCAATCTTCCTTCCTGCCAG
+GATCTGGGGCTGGCAGAGCGGGTGAGTGGGAACAGAGAGGACTATGCTGA
+GGGCCCGCCCTGCTGGTCAACTGTTCTCCTCCAGACTCGGGGTTTCAGGG
+ACCTTCCAGAGCCAATGGCACAGGACGGGGGAAGGGGTGGGCACTGAATA
+CAGTCCTGTGAGCTTTGCCTTTCCTGGCCCAAGAAGGCAAGTGAGGCCAG
+AAGGGCACTGCCAGGAGATAACTCTTGCCATGCCATCACCCCTGTTGATC
+CGGTTCCAGTTGACTGGTTCTTCCAGCCACATGAAGGACTTGAAAAGCAA
+TGCCTGGACCACCAGCCTGACTCATCTGTTCCCAGAGCTGACTCAGTCCT
+CGCTCCCTGGAGCCAGAATGCTCTTCCGTGCACATTCATTGAACATTCTA
+GACAGTGTGCCAAGATGCTGGAGCTACACGGGTGAAAAGGCACGGGTGTC
+CTTCAGCTCATATGTGGTGCAGGGCCCCAGAGGTGGCTTTGAAGCTAACA
+GAAGTTACATGTTGGGggcagggcacagtggctaacgcctgtaatcccag
+cactttgggaggccgaggtgggtggatcacctcaggttgggagtacaaga
+ccagcctggccaacacagtaaaaccccatctctactaaaaatacaaaaat
+tagccaggcatggtggcacgcacctgtactcccagctactcaggaggctg
+aggcaggagaatcacttgaacatgggaggcagatgttgcagtgagccgag
+gttgcgccattgtactccaccttgggcgacagagcgggactttgtctcaa
+aaaaaataaataaatgaaaaaTTACATGTAGGGTGAACTGACTCCTCACT
+TACCTACTTCTGACCGTTGCATACCCTAAtttttttatttttagataggg
+tcttgctcagtcactcaggctggagtgcagtagtgggatcttggctcact
+gcaacttctgcctcctgggcttgagcaaccctccaacctcagcctcccaa
+gtagctgagactacaggtgcattccaccacatctggccaatttttgtatt
+ttttatagagacagggtctcactatgttgcgcaggctggtcttgaactcc
+tgatctcaagcgatccactcgctttggcctcccaaagtgctgggattaca
+ggtgtgagccactgcgcccggccAGAAGTTTTGTTaataatgcaatttac
+ccttcaccagcacttcatcggcaccagccaccactagctttataaacact
+tcctcctagaatctctgcagcaccctgcagggctgcgtttatcatccccc
+tgtgcagccaagaatctgtagcttagtgacttgcctagagccaAGATCCA
+AACGTCAAACCACTTCACAACATCGTCTCCTGCATGACAATAATTTGTGA
+TTTTACTGTTAATGACTACCCATGGATGTCACATTTCCAGCTGACCACTG
+AGGTCCAGGATGGGTCACTTCCACAGGTCAGTCACAACATTGCGACGCCT
+AGCTGAACACCCAGCTCTGGGTGTGAGCTCCTCTGTGTGTGCCCAGCCTG
+GGATTCAAGGCTTTGATGAGTTCTGGTTGGTTGAATTTAACTTACTGTCC
+AGCTGGTCCACCTGTTTCCTATTTCACAGAGTATTTGGTGTTTTTGCATT
+GTTTTCATAGCTGACAACAAACATGCAGTTTGCTAGATCTTTCTGAGCCC
+AAACCCAACATCTTCCCTAAAAAAAGGGTGAATTGggctgggtgtagtgg
+ctcacacctgcaatcccagcccttgggaggctgagacaggaggattactt
+aagcccaagagtttgagattagcctgggcaacataaggagaccctgcctc
+tacaaaaaatagaaaaaatattagctgggtgtggtggcacacactggtgg
+tccctgctgctactcaggaggctgaggtgggaagattgcttgagcctagg
+ttcaggctgcaatgagctgtgattgcaccactgctctccagcctgggtga
+cacagcaagacaccctgtctcaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+GTGGATGAAATGCACATTGATGGTGCAGACAGCAGATTTTTGGAATTTTT
+AGGCTGGGCCAGAAGAAGGGTGTTGAATGGGGTATCACTGGGGCCAGCAC
+CCGTCCCTGACTCTGGACGGTGGCAACCCAGCACCTCCCAGGCAGTCTCC
+CACTACCAGATGGAGAAAGGATGAGACTGTGCAGTGACGCTGTGGGTGCT
+GTGTGATCCCATCTCGTCTGGTCAGAAAACTCCTCGGAGCTGATACCAAA
+ACCCCATGACAGAATTGGGCAGGGAATGATACTTTCTGGTCTAAAGCAGG
+ATATTTTGCAATTGCGGTGACACGTTTTGCAACAGAGGCTGCTCTGAGGC
+AGGACTTCTGGAAGGCAGTGTTTTGATGCCACTTTGGACTTTCTAGGGCA
+AGGCAGGCTCACAAAGCTTTTGTTTGGAGGGGTTCCAGTAATTTCTCACA
+GTGAAAATAGAATTATTGCCCTTCTAACGTCATTTAAGTGTTTAATAATC
+AAAGTGGAATGGTCATGGGCTGTCTTGTGTGCCCCTGCCATTGGATGTGT
+GACCTTATTTGGGGTGACATGGCAAATCTAAACCCAACAAAGCTGCTGCA
+AAGGGTCTACTCTCGGCTATTACTCCTGGGAAATGTGCGGCTCAGACACC
+ACGACCTTCACTCCACTCCTGGTCACCAGGGGTTTCACTTTCTATGGCAT
+TTACTTCTGCACATTTTGGGATTTAAAAAAATGAAGATTGTATTACTTTC
+GTAATAAGCAAAAAAGATAGTTTTAAAAAGTCTTTCAgaccaggtgtggt
+ggcgcacgcctgtaatttcaacactttggaaggccgagacaggtggatca
+cttgaggtcaggagttccagaccagcctggccaacacggcaaaacctcgt
+ctctaatgaaaatacaaaaattagccaggtgaggtggcccgcgcctgtaa
+tcccaggtactccggaggctgaggtagaactgcttgaacctgggaggtgg
+aggtttcagtgagtcgagattgcatcactgcactccaggttgggcaacag
+agcaagattccgtatttaaaaaaaaaaaaaGTCTTTCACAATTAGCTTAA
+CTTCTAAGGGAGTATCAGTCCCGTGCCCCTAAACCATCATGATAAAGGAG
+GTATATAGtatttacttatttatttacttgatttattttgagacagagtc
+tcactcttatcacctgggctggagtgcagtggcaagatcatggcccactg
+caacctccgcctcccgggttcaagcgattctcctgcctctgcctcccgag
+tagctggcattacaggtgcccgccattacacccagctaattttttgtatt
+tttagtagagacggggtttcaccatgttggccaggctggtcttgaactcc
+tgaccttgtgattcgcccgcctcagcctcccaaagttctgggattacagg
+cgtgcgccaccgtgaccagccAACTATTTTTTCATAGATGATGAAATGTA
+GGCTTACAGGtagggtgaccaacacattttgtctaggagcaaaacccaat
+ttgcccagtcttagcactgaaagcctagttctgggaacgaccacagtccg
+gggaaattgggacaattgcccaccctGTTTAGATGGGTTAATTGACATAC
+TGAACACATGTCTAGCTAGGAAGAGGCACCACAGGGCcattcatttactc
+ttggagcacctgctgtatgccagatgctattctaggtactactgatacag
+aactgaacagaaaaaaacttcttgcagtgctcacattctTTTTTTTCTGA
+TATAAATGCCCTTCAGAAGAGGCCACAttcttttttttttttcgagatgg
+aatttcactcagtcgcccaggctggagggcagtagcgcaatctcgccact
+gcaacctctgcctccagtgtttgagcgatcctcctgcctcagcgtcccaa
+gtagttgggattataggtaccgacaaccacgcctggctaatttttgtatt
+tttagtagagacggggtttcaccatgttggccaggctggtcttaaactcc
+cggcctcaagtgatttacccacctcggcctcccaaagtgctgggattaca
+ggcgtgagctgctgcgcctggctCAGAAGATCCCGCAttttttttttttt
+gacggagtctagctatattgcccaggctggagtgcagtggtgctatctca
+gctcactgcaagctccacctcccgggttcacgccatcctcctgcctcagc
+ctcccgagtagctggaactacaggcgcctgccaccacgcccggctaattt
+ttgtatttttagtagagacggggtttcaccgtgttagccaggatggtctc
+gatctcctgaccttgtgatctgcccacctcggcctcccaaagtgctggga
+ttacaggcatgagccactgcgcccagccAAgagcccacattcttatagga
+aagtgtgaattgatataaacaaacaaatacacaatgtatcagggagtgat
+aagttgggggaaaaaacagcagaataatagggttagtgagtgcaggggat
+tggtttcatatttttttatttttatttatttatttagagacagagtctca
+ctctgtcacccaggctggagtgcagtggtgctatcttggctcactgcaac
+ttctgcctcccgggttcaagcaattctcctgcctcagcctcccaagtagt
+tgggattacaggctcacaccaccatgccaggctaatttttgtatttttag
+taaagacggggtttcaccatgttggccaggccagtctcaaacaactgacc
+tcaagtgatccaaccgccttggcctcccaaagtgctgtgattacaggcat
+gagccaccgtgccccctggtttcatattttaatagggcacttgaagaagg
+cttttgtgcttgaacagagacccaaaggaagaggagtaagccaggtattc
+attttgaggatgagcagtctttgcctatttacagagtgcaaaaggggtaa
+ctttgtgcttagtgtttgaggaagagtggtggctggagcagaggcacgga
+ggaggagtggatggaggggttagagagggagctggagtcccctatcaagt
+agcagggctcccaggacacagcaaggacttggctcttactctgagatgag
+gggacactggaaagtttgagcagagcagtgacataattggagttacgctt
+taaaagaaacattctgggccgggcgcggtggctcacacatataatccagc
+actttgggaagccaaggaaggtggatcacctgaggtcagaagttcgagat
+aagcctggccaacatggtgaaagcccgtctctactgaaaatacaaaaatt
+tgctgagtgtggtggtgatgtgcgcgtagtcccagctactctggaggctg
+aggtgaatcacctgaacctgggaggcggaggttgcagtgacctgtgatcg
+caccactgtactctggcctgggtgaaagagtgagactgtttcaaaaaaag
+aaagaaaagaaaagagaacactctggcttccataagagacaagagatgag
+aaaggtggaaacagagaggagaaagcaatctattgtcacaatgcaggaaa
+gcgactgcagggccctgaaccactgtggaggcagaagggtcagattctgg
+gtgattctgaaagcagggctgacatgataagggtagactggatactggcg
+ggtgtgaagatgcatctaagatacctgtttctggccagaTTTTACAAAGG
+GCCCTTGTTGCTACCTTAAGGAGTTAGTGTTGAATCCTGCAGCAGCTAAG
+AGCTTCTGCAGGATCTCCCTCTCAACTTGGACCAACCCACCTGCCGATCC
+CAGCCCAGATCAATGAGATCTGCTGCCCAGTCCCCTACGCAGATAACACT
+AATTGTAACTGATCTTTCTGAGGGCACCTCCTGAGCAGCTTGGAAACGGA
+GGGAGAGGAGAGGAAGCCAGCTTCCCAAAGTGGGGTGTGGCAGGTGGCCT
+TAACCCTGCTGAAGGGCTGCAGTCATGGGGCTCTGAATAGATCCCCACAC
+CACTCACCAATGAGCTTCATTTGGAAGGCGGTAACGTTAAACAAGAGGGT
+TTGTAAAAAATAAAGGCCTACACACATAATTTTTTCTGATTATTAAATCT
+AGGTGGAGAGTACGTGAGTATTCATGTTACTCTCTCAACTTTCTTGTGCT
+TAAAAATCTTAAAATAAAAACTTTAATACGCTCTGTCCTACCAATATTTA
+TAGGAACCTGACTAGCAGCCAGGCTTTGGACACGCAATCCCCGGCCACCA
+AAGGGCTGACAGGCTAGTGAAAGGGGCAGAAAAATAACAAAACTGTGTCT
+GGAAGGCAGCTACTCCCtttttttgtttgtttgttttttgagacgcagtc
+tcactctgtcgcccatgctggagtgcagtggcgcgatcttagctcactac
+atgtgcctccggggttcaagcgattctcctgcctcagcctcctgagtagc
+tgggactacaggcgcgcgccaccacgcccggctaatttttgtatttttta
+gtagagacagggtttcaccatattggtcaggctggtctcgaactcctgac
+ctcgcgatccgaccgcctcggcctcccaaagtggtgggattacaggcgtg
+agccaccgcgcccggccCTTTGTTTTCTTACCAACTAAGCAGCAGCACTG
+ACACTGTTTCCTTTGAGGTTCCGTTTGCTGAATCCTGCCCTCTAAGGTGC
+TCCGCCCTTCCACTCCCCGCCCCGTGCTGCTGTCATTCCCACGCCTCACC
+CTGTTTTGCAACTTCTTGTTTATGAGCCTGGAAGCCACGAAGTGGTGGGA
+AATACGAGATTCAAATATCTGGtggccgtgtgacgtgagtaaattactcg
+atttttctcagtttccatttcctatcaaatgggTTGTTCTGGGAATTCGG
+GGAAGTAACAGTGCCGGGAACCGCGGGAGGAACCGCCAGCTGCGTCCTCG
+GACGTCCCCAAAGCCCAGGGCGGCGACTGGCACGACTGTCAGGGGCGCGT
+CTGTTAAGAGGACAGGGGGTCCCGCCCCGGCACAGCCGTCTCCTCCAGGA
+CCCCTCCCGCCGACGCCCCACGGACCCCACGCCCGAGCGGAGACCGGCGC
+GAGTCCGGGGTCTCCGGTCCGGCAGCCCCTCCCTGGCCCGGCGCCCCAAA
+GGGAAGCGGCCTGGGGGAGGAGACGTGTGGAAAGAGCGGCAGAAGATAAA
+GAGGAAGTAGCGGTAGAGAATAAAAAGGAACTGTCCGCAGTGTGCCCGGA
+CGCGGGGAGGCGCTGGGGTCAAGCGAGACCCGACCTGCACGCAATTCCCG
+CCGGGGTCCCGGCCTGCCTGCGGGAGGGAAAGGACCCAGGGCGGCTTCTG
+CCAAAAGTGCGGCTTCTGCCGAAAGTGCGTCTTCTGCCGAGGGGCCCACA
+TAAGGCGCGACAGACACTCCAGCCCGACCCCGACGCCCCGCCCTCACGCA
+TGCACATGCGCGGAACACTCCCAGAAACACATCTCCCAGAGCGCCCCGGG
+AGCACGCGAGCCAATTGGAGGGCGGATTAGCGGGGGCCCACGTCTCCCAG
+AGGTCTCCGAGTCGCGGCTCTGTTGGTCTGATTGGCAGCCGCAACAGCCT
+ATAGCTGCTTTTCGCCGGAGGGGCCACGCGCCGTTTGCCGGGACTGAGCC
+GCTGTTGTCGCTGGTATCCCGGGAGCAGCGCCGGCAAGTGGAGTCGTCGT
+ATTCCGGGCGGCCCGCGGCCCACGGGGATGGGACGTCCCGGGGCTGTGCT
+GACCCCAAAACCCTTCCACACTTTATTAGCCTGTCGCCCTTCTttcatgt
+ttacagcaaatattttccgagtgcctaatgtgtcccacttactgtgccac
+gtgcgagggtgcacgtgtcaggcaagaTCGCTGTTCCAAGGAGGCTGAGA
+ACAAGTAAATGGTAATTACCAGTTATGACCAAAGCTGTGAAAGGAACAGA
+TACATCAGCCTAACAGCAGCACTGCCGTTTTCTCCCTTATAATCAGCAGA
+GGCGGGCTAGAGCAAGGATTCTCAAACTCTGCCCCCTCAGAACCCTAGAG
+TACGGTTGCTGAAACTTCTGTTTTTTCCTTTTGAACAAATCTAGTAACAT
+GCTGTGAGCCAGAGAGGTAATGGTTTGGCTCAAAGAAGGCACATGCATCT
+GGtttctttcttcttttttgagacggagtctcgctctgtcgtccaggctg
+gagtgcagtggcgccatctccgctcactgcaagctccgcctcgcgagttc
+acgccagtctcctgcctcagccttccgagtagctgggattacaggcgccc
+gccaccacgcccggctaattttcacgcccggctaattttttgtattttta
+gtagagacggggtttcaccatgttagccaggatggtctcgctctcctgac
+ctcgtgatccgcccgcttcggcctcccaaagtgctgggattacaggcgtg
+agccaccgcgcccggccCAGGTTTCTTATTTCAGGAGCTTCATAGGCATA
+GACCTCCCTCCTTCCCTCCTACCCCCTCCCCCCTCTCCCAACTAATGCCA
+GACCGGCCACTACTTTTTAACTGTTTTACATATTTAACCTTCAAGAAAGA
+TTTCCTTTGATCCAAGTGTATTGCAGCCCACAAAAAAGCTTGGAAACCCA
+GCTAGATGGTCTGTTTTTCTAGTTCCTACATTGGATTTAAGTCCTACCCA
+TCGAGACTACTGTCTTCAGGTAAGCATATCGAGGCTGTATTCACCTTCAT
+GGTGTTCTCAGGGGCACTTTCTTACACAAATGATGGTAATCATCCTAGAT
+CATTTCCCTGCCTGCCACACTTGCCAGTtagttagaaactgtaaacccct
+taaatgtctgtcaccagggcactggctgaatagctgagtaagttttggtg
+aatccattccttggactacactgcatccactgaaaacagtgcggtgaatt
+tctgtgtgctaatgtgcaaagatggtttatgtattattcagtggaaaaag
+cacatttgcactacagtgcagatagcatgatcccatgtttgtaaataaga
+gaaaaaaatgttaaaatttaagtatctggagggaaatgcaagaaataaat
+atgactacctttcaagagtagaattgggggtAGAAGTTGGCCTTTTCCCT
+CTATGTCATCTATACGTtttatttttttattttattattatttttttgag
+acggagtctcacgctgctgcccaggctggagtgcagtggcatgatctggg
+cttactgcgacctccgcctcccgggttcaagcaattttctgtctcagcct
+cctgagtagctgggattacaagcgcacgccaccacgcccggctaattttt
+gtatttttagttagagatggggtttcaccatgttggtcaggctggtctcg
+aacttctgaccttgtgttctgcccgcctcagcctcccaaagtgctcagat
+tacaggcgtgaaccagtatgcccggcGTTCAATGAGCATTTTTAAAGTTT
+TATGACTCATGAAACATAGTCCACAAATATATGCTCATTGTGAAATAGTA
+ACGGAAAATAAAATATGGCAAGCTAAATGTTAGAGGAGAAATTTCTTATT
+TTGCTCCATTACTTTTACAGCAGAAAAATTAAAAAATTTATTAGCTGAGA
+CTTTGTTTCACTGGGGTGCAGAAGATTAAACAAATGATTTTTAAAAGCAG
+ACTCTGCCCATAGAGAAAAAATATTCGAGGTTTCCAAAGTAGAATAAGTT
+TAAATTAGCAAGTCAAATAAGGAACCTTGAGCCAGTACCGAAGGAAACAC
+GTCCCAGACCTATCTCCAAacacacacacacacacacacacacacacaca
+cTGCAGGCATAACATTTATGCAGACAGACTGTTCTTTAGGGCATAATTGT
+CTCATGTCTCAATTCCTCTGAAGCTCCAGAGCAGAAACTGAAATTTTAAA
+AATGCAGTTGAGATAAACTGAAATGACTGACAGGCCATTTGCCAAGAAAA
+GCTTTGGTTCTTTGGAACAAAGACAGTGCCCATATCCCAGCCAACATCAG
+GTGGTATTTCTCTTTCTGTCCTGTAGAGGGCATCTTCATGTGTGGGCACC
+AGGGCTGCGGCTGGAACCACAGTGGACACCCCACGCTCCAAGGACAATCC
+TCTGCAGAAACCAGCAGCTGGAAACAATTCTTAATGCTGCAGGAAGTAGT
+TAGGAGAAAACGACTGTGTAAGTCAGAGCTAAAACTGGAGTTCAAAAACC
+ACAGAAAATATTTCCAAGGCTGTCTGTGAAGTGGGGATGTCAAAATACCA
+AAAATTACAGCTTTGGAACTGCAGTGGATGACCTTTAATTGATGCAGTTT
+ATAGGTGCTAAGTATTGTGTGTGCTTTACGTTGCCTCATGTGAGTGCTTC
+ATAGCAGGgtgtgacgctggccaagtgatatacctaccctctttgtccct
+gtttctatcaactgtaaaatgggggttctagagttgttgtgaagattaaa
+tgagctaatacacacaaagcaccaagaacaatgctggatacaaggtaaTA
+GGTGTTTCTTCCTAGACTTCACTATCCTCATGTGAGGTGGGTATGtttat
+ttatttatttggggacagggtctcgctctatcacccagactggagtgcag
+tgttgcaatcatggcttagctccctacagctttttaaatttaattattta
+ttattattatttttttgagatggagtctcactctgtcacccaggctggag
+tgcagtggcacgatctctgcttactgcaagctgggcctcccggattcaca
+ccattctcctgcctcagcctcctgagtagctgggactacaggcgcctgcc
+accacgcccagcatatttttgtatttttagtagaggcggggtttcaccgt
+gttagtcaggatggtctcgatctcctgaccttgtgatctgcccacctcgg
+cctcccaaagtgctgggattacaggcgtgagccaccgtgcctggcctcag
+ctccctacagctttgacctccccagctcaagtaatgtcccacttcagcct
+cccgagtagctgacactacaggaatgcaccatcatgTAtacctgtggtcc
+tagctacttgggaagctgaggtgggaagattgcCCCTGAAATAAGACTCT
+AGATACAGGTCCCTTTCTCTGAAATTTTTGAAACAAAACGCCTAATTCAA
+AAAAAGTtatttttggtagagacggggtctcactatgtttcccaggctga
+tctcaaacttgggttcaagccatcctccctcattggcctcccaaagtgtt
+gggattataggcaggagccactgtgcctgtccAaggtgggtgttgatata
+ttcaatttaacacagaaaacaggaagtttgtacacactgacttgcccaag
+gctacacaactacaaagagtcaggtagccaacattcagtctcaaggtctg
+tgtctgcagagctcaaggcctttcctttggctttgctgtctctTGGCATC
+TGGTAGcttagcagtcatcaagccaaccccgtcatgttacagaggaggac
+acaggcttccaggggaactgactgacttgagttctacacatcagtgcaga
+gctgggactagaattctgtccacctaactGTATTTGGAAGAAAGTTAAGT
+GCTATTGACTACACCTAATATCTGAAAGATAAAGGGAGAGGCAGAAGCAA
+GAATGAATAATGTggctgggcgcggtggctcacgcctttaatcccagcac
+tttgagaggccgaggcaggtggatcacgagatcaggagttcaagaccagc
+ctgaccaacatggtgaaactccatttctactaaaaatacaaaaattagcc
+gggcatggtagcgtgcgcctgtaaccccagctactaagtaggctgaggcg
+ggaggatcgattgaagccgggaggtggaggttgcagtgagccgagatcgc
+accattgcactccagcctgggcaacagagcgagactctgtcaaaaagaaa
+aaaaaaagaaTGAATAATTTTTAAAGCAGGCTGTGAAGAACTAAAAACAT
+GAGGACACGGAAATTCAGAAACACCCATTTCAATATGATTCCTTTCGGAT
+AACTTGAAGCCCAAACAGGATGGAAAATCACAGGCCAAAGTCACCTGAAG
+GAAGGCTGTCACCCATGACGGACAACCGGGATGTTGCTCTCCATTCATCC
+CAACGGCAGCAAAGTCTGTCCTGGAACATGGAATGGTTTCTTTATACAGA
+CAACTAAGACTGGCTCCAAGAGAAGAGTTGCTACCACTAACCCCTACATG
+CTGCCTTGAAAGAGTTGGTGGTAGGTGTTGGAAAATTAATCTgagtaatt
+aggaaacaaaatttgaaacaaagaatcccatgcacaatagtagcaaaacc
+cataaccagacatgataagaaatttgcaagacctataagaagaaaagtat
+ataggattacagaattttaaaagtcccagatcattgaagaaatacaccac
+agtcgtggatggaagagttaatattacaaatatatcatgcattcctaaat
+taatcaacaaattataagcaaacccaattgaaattgtaacgagatttttt
+ttttacatttttaaaaaaatgtgatcttgctatgttgcctgagctggtct
+caaacttctaagctcatgcgatcttcctgccttggcctctcaaaatgctg
+gcattacaagtgtgagccaccatgcccagccATAACAAGACtttcttttt
+tttttcagactgggtctcactgttgcccaggctggagtgcagtggcgtga
+tctcaggtcactgcaacctctgcctcccaggttcaagtgattctcctgcc
+tcagcctcccgagtagctgggattacaggtgcgccccaccatgcccagct
+aatttttgtatttttagtagagatgaggtttcgccatgttggccaggctg
+ttctgcccacctcaccctcccaaagtgctgggattacaggcatcagccac
+cgcaccaggctgcaagatgtttaagaatgggctttgacaagttgattttt
+aaaattcatagccaaaaaaattgtgaaaaaaatacagtggtgtgagatgt
+attgtaacagatataacaacaagctgtgaaaatacagtaaattagaacag
+taatatgtttttacaagaatggatataaggtaaatggaaacaagattccg
+taagacgtgtgtatatgcaaaagatggtatttaaaacccaaggggaaaag
+gtggcccaacttataaatagttttgggactgttgacagttgagctggaaa
+acatagacttctgcctgacatatataaaaaataaactccatatatatata
+tatatatatatatatatatatatatatttttttttttttttgagacggaa
+tgtcgctcttgtttcccaggctggagtgcaatggtgtgatctgggctcat
+tgcaacctctgcctcccaggttcaagtgattctcctgcctcagcctccca
+agtagctgggattacaggcatgtgccaccacacccggctaattttttgta
+tttttagtggagatgggttttcaccatgttgcccagactggtctcgaact
+cctgacctcgagtgatccacccgcctcggcctcccaaaatgctgggatta
+caaccatgagccaccgcacctggcccagatgatttaaagaaacacgaagt
+gtaatatctgtaaattTGTTTAAATTTCGCAGTGAGGAAGATCTTTCTTT
+Ttttttattttttatttttttattgatcattcttgggtgtttctcgcaga
+gggggacttggcagggccataggacaacagtggagggaaggtcagcagac
+aaacaagtgaacaaaggtctctggttttcctaggcagaggaccctgcggc
+cttctgcagtgtttgtgtccttgggtacttgagattagggagtggtgatg
+actcttaacgagcatgctgccttcaagcatctgtttaacaaagcacatct
+tgcactgcccttaatccatttaaccctgagtggacacagcacatgtttca
+gagagcacagggttgggggtaaggtcacagatcaacagtatcccaaggca
+gaagaatttttcttagtacagaacaaaatgaaaagtctcccatgtctact
+tttttctacacagacacagcaaccatctgatttctcaatcttttccccac
+ctttcccccttttctattccacaaaaccgccattgtcatcatggcccctt
+ctcaatgagctgttgggtacccctcccagacggggtggtggctgggcaaa
+ggggctcctcacttcccagaaggggcggccgggcaaaggcggccccccac
+cacccggacggggcggttgggcgggcggaggcaccccccacctccctccc
+ggacggggcggctggccgggcaggggctgaccccccacctctctcccgga
+cggggcggctggccgggcaggggctgaccccccacctccctcccggacgg
+ggcggctggCCGGGCGGGGGCTGACAGATCTTTCTAACCAAGATAAAAAA
+ACTGAAAAAGTTAAAAAATTCAGGTAAATAGAAAAATTAGAAAACTTCAG
+TATGACAAAAACAGCCATGAATATGGTTAAAAggctggatgcagtggctc
+atgcctgtaatccctgcactttgggaggccaaggtgggaggattgcttga
+gcctaggggtttgagtctccacaatgtaggcagaccccatctctaccctc
+cctcacaaaattaactggccatggtggtgtgcgcctgtggtcccagctac
+tcaagaggctaagttggaaagatcgcttgagcctgggaggtcaaggctgc
+agtgagctgtgattgcaccactgcactccagtctgggtgatggagcaaaa
+ccctgtcttaaaaaataaaaataaaaaaGGTGACAGAGAAAATATTTGTA
+CATACGATAATACCTGGAATGTTAAAGCACTATAATTTTTTTAATGCTCA
+AAGGCTTAAATAGGCAACTCACggccgggcgtggtggctcacacctgtaa
+tcccagcactttgggaggctgaggcgggtggatcacgaggtcaggagatc
+gagaccatcctggctaacacagtgaaaccctgtctctacagactacaaaa
+aattagccaggcatggtggcacgtgcctgtagtctcagctactcgcgagg
+ctgaggcagaagaattgcttgaacccaggaggcggagattgcagtgagct
+gagatcctgacacgcactacagcctgggcaatagactgagactccatctc
+aaaaaaaaaaaaaaaaaaGGCAACTCagagaagaaatacaaagtaccacg
+tgaaaagatgcccaatctccaagtaatcagaaacatgacaggcaacaagg
+ggatattatttttttttaaatagcggcagagtcttgttatgttacccagg
+ctggtttagaactcctgggctcaagcagtcctcctgccttggccttccaa
+aagtgctgggattacaggccctaagccaccacacccggctgaggggacat
+aatttttcacccactatattatcacaaattaatatgattgccacagccaa
+ctttaatgagcatgcagacatagaagcactttcacacctcaggttacgag
+ttaaatttgtgaagcttttttttttttttttttttttttgtgatggagtc
+tcactcttttacccaggctggaatgcagtgatgcaatctcggctccctgc
+aacctccacctctgaggttcaagcgattctcccacgtcagcctcctgagt
+agctgggattacaggcacccgccaccatgcccggctaatttttgtatttt
+tagtagagacggggtttcaccgcgttggccaggctggtgtcaaacccctg
+actttaggtgatccgcccgcctcggcctcccaaagtgctaggattacagg
+tgtcagccactgctcctggcctgtgaagctgttttggaaggtgatttgct
+gcaagttttcaaaattaaaaatgcacaagcctaggccaggcacggtggct
+catgcctgtaatcacagtactttgggaggccgaggtgagcagatcacttc
+agcccaggagtttcagaccagcctgaccaacaaagtgagacctcgttgct
+acaagaaataaaaaattgggtggcacatgcctgtggtcccagctactctg
+aagggtgaagtgggaggactgcttgagcccaggaggtcaaggatgcagtg
+agccaagattatgccactgcactccagcctgggtgacagagggagaacat
+atctcaaaaaaaaaaaaaaaatgcacaaggcttttgcttcagtgattcca
+tttctaagactatatccaatgtacccaaatatgcacgtctgagatgttca
+ttggagtattggttgttaaaggaaacagctggagacaatctaaatgggga
+gacagtcagtacagctgtggtatatccatagtatgcatgctctacagttg
+ttaagagtggcaatggcctattcatctggacctagatagatgtcaaaggc
+acactgctaatatttaaaaagaagatctggaaaatatgtatagcatgGTG
+TATACATATAATTAGCCCATATAGGTACATGAAGTTCCTCAGGAGACTGG
+GAGGATGCACAGCCAGGTAAACCTGTAGAGCATGGAGACATTAGGTGGGA
+GGTGATGGAAAAGTCCCTCAGttttttttttttttgagacagtctcgctc
+tgttgcccaggctggagtgcagtggcatgatctcagctcactgcaacctt
+cacttcctaggttcaagcgattctcctacctcaacctaccaagtagctgg
+gattacaggcgcccgccaccacgctcagctaattttggtagttttagtag
+agatggggtttcaccatgttggccaggctggtcttgaactcctgacctca
+agtgatcctccccgccttggcctcccgaagtgctgggattacaggtgtga
+accactgtgcccagACCTTCATTTTGTTTGTATACATCTGTATTCATTGA
+ATCTTCTACAAGGTTTATTTATTCATGTATGCCTATtgttccggttatct
+attgttgcatgaaaaacaccccaaaacttaatagtgtaaaacagcagccc
+ctttattatgctcacaacttggtggtcagatttcaagcaagacccagagg
+cacaactcatctcgttccacagtggctggagcttcagctgaggtggctca
+aatggctggagAACACTTCCCTGCAGCAGAACCTACAACCATCTTCCTCC
+CCTTTCTGGAAAAGGTTTGTTTCTGAGGCTGGAGTCAGAGTCTTCAAACC
+AACAGCCAGAGATAACATTGCTAATTATGCCCCTTTCCTTGGTCTTTATT
+TGAAATGAAACGGTTCtgttaccggtagagggtcttgatgcaaattgtcc
+aggttcttggcattttgaacaaagaactggacaaaacgcacagcaaagca
+aggtaagaatgaagcagcaaaagcagagatttattgaaagtacatgccac
+agtgtgggagccggccaagcagcagcttaaacaccccctagaggtttccc
+attggccacttggtgttcaccccatgtaaatgaaccaacctcagtcagtc
+tgattggttgcaaccaatcagaggctgaagtgaagttacaaagttacact
+cctgtgcaaacgtctgattgcaaaaagcagccagtcagaggtaccttcaa
+tttcccatctgcccctcagaaaaggtgggcattggcaaagggagtagcct
+ctggtccttttgttacttatgcgtggaaagttggggtttttctttcgatt
+tagttctaggaagtcaaggtgaactggccttcagttccctgcctccagac
+cctattctgcctcaGTTCAAATACACAAAACCTAACAAATACCTATATGA
+CCACCTTCCACAACTAATCAATGGCAGTGTCTATTAGTTTGACTTTGTTT
+CTATTTTACAAGAAGCAAAAGCACCTCTggactctccactagagagctat
+gtgcagccactccagcatggtgctctcagggtaaccagacttcttacact
+agctccaagtgcaagttctcctagcaaacaagatagaggttgcaaggcct
+tttatgacctcaccctggaggtcacaccacatctgtatttcattgtattt
+cattggtagcagtcacaagctgcccagatacaaggcagagggacagatgc
+cccacttcttgatgggatgagtggcaaaaaaaaatctgtgaccatgttta
+aAACCCAGAAGATTTGGCTGTTAGAGATTTGTGAAGTTTTTAAAAGTTAA
+GAATTATTAAAACAAAAATAAAACCCAGGAGACAAGGTAGTGGAAGTGTG
+TCCCTCCCATTCACTGACCAAGGTGAGGGGACTCTAGTCCTTTGCTGCTG
+ACCTTCAGCCTCCCTTCCTCTTAAAAAGAGGTCCTAGTTGGGGAGCGATG
+GCTGAAGAGTTACCATAAAATACCAAGTAGGAGCGAggtgcggtggctca
+cgtctttaatcccagcagtttgggaggacaaggtgggaggatcgcatgag
+cccaggagttcaagacaaacctgggcaacatagcaaggctctgtctctac
+aaaaaaGGAAAAGAGTACAAAGTAGGGCCATTTAGTATGGTTTCATCTTT
+ATTAAAAGTCTTAAGTTTTAGATTTTTGAAGTTATCACCAATAAAATATC
+CAGTTGTGGTCTTGTGTTGAGTGAAAATGTTATTTAAATGCAGATATTTA
+AAATATACTACAATTTTTGTGCTATTTTAATTTTCTAGGAGCCTTAAAAA
+ATGTGTGGCTACtgaaactgtgccccaaagagttaaagaaatcagtaact
+aacagaaattcttgagtctgcaggatggcagataagaaacaactcgctgg
+ccaggtgcagtggctcacacctgtaatcccagcactttgagggattgacc
+cactgaagtgggtggattacatgaggtcaggagttcgaggcctggcaggt
+tggtgggcacctgtagtcccagctgcttgggaggctgaggcaggaaaatc
+acttgaacccgggaatcggaagttgcagtgagccgagatcaggctattgc
+actccagcctgggcgttgcagcgaaactcctactcaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaacaacttgctgaaatgctgaagaaatgctgaaactc
+cctccctataagataaaagaagaacaagcagaaatctgttggaaccaata
+acgctgactggagtctgcacagaatgagcttgctgacatcacagcctgaa
+ttttcaacacaggtttcatgctgtccctgaatttgcatgagacccattaa
+gtagcttgaagaggtaactgcgaaagcccaaggactttccacatctcccc
+tttccttccactaataatcacctactaatctcagaatccaccgcctgaac
+cttttctaataaaaataactgccttaaagccaacacggggagacagcctt
+gagcttgatattcctgtctccttgtgagtcgacttgcaatacaaagcttt
+tcttttttcagaaccacagtgtcatagtattagcttctagggtatcaggc
+tggaatgcactggtgcgattatggctcactgtagcctcaatctcctggac
+tcatgcagtcctcccacctcagcctcccaagcagctaggaccacaggcac
+ttgccaccacgcctggctaatttttgttttttttgtagaaatgggatctc
+actatgttgtccaggctggtcccgtgctcttgggctcaagtgatccttct
+gcctatgcctcccgaagtgctaggaAAAGCCTCCCAAACTGGAAAATATG
+GGATGGCTTCCCAGTTGTTAAAACACCCTGATTTGGGAGCTGATTGCTTA
+TAAACACTAAGAAAAAGCTAAGAGCTGAGTTCGCCTTCCCATTCTGTTCT
+CAGGTTTCTCTCCTTATAGAGAGGTTCTGATCATCTACAAGCTTTGCTAA
+ATCTGGGGTGTTTCTCTACTGATTTCCTAAATGTTTGTAGTCTTTTTTGT
+AAAATTGATGATTCAATTTTATTCTCCTCTGAAGTAACAATAGATGCAGA
+GTCTGACATTTCTTCAGCTTTGAAGAATCTGCATTTTCTCTCCTGATCTC
+AAAACCTGTAAGAAAAAGAAATTGCAGATATCACCCTGTCCAAGGAGAAA
+GAGGGGGGAAAATAAGAGTTGTATTAAAGTAGTAGAGAGAAAACAGAAAC
+TGCTAAATAGAATCCCAAAGCCTTTTATTCCAAGTAAGGCTGAATTTTTC
+TTTTCTTTCTTCCCGTTTCTTTCCAGTGAACACTCACCTCTCCTGGAGTC
+AAGTCATTGTTTCTTTCCTTTGGAATCCTGCTATTCCTGCACCCATGGCT
+CTTCTCTAGGCTCCAGTGGGAAGTACAGGTCAGGGTTTGGGACTAGATAT
+ACTGGTCATAAGAAATACAGGGAACATGATAGTCTGGGTCACACTGATTT
+TTCCTGAGTTCAAGCCGATTTCCAGGACAGATGGCCTCTCCATATTTATT
+TCCTTCTCAATTAGGATTATTTCACCTGGAGCCTCTAACAGGCAGCTGGC
+tttttttgagacagggtcttgcagtgtctcccaggctggactgcagtggc
+acaatctcaactcactgcagtcttgacctcccaggctcaagggatcctcc
+caccttagcctctggagtagctgggaccacaggcatgtgctaccatgccc
+tgataattaaaaaaaaaaactctgtagagagaagggctctctctgttgcc
+caggctggtcttgaactcctggctcaagcaatcctcttgcctcggcctcc
+caaagtgctaggattacaggtgtgagccactgtgcccagcATAACAGGCA
+GTTTTTCAACATTAGAACAAAATCTAGGAGTACGAAAGGCATACTGGAAA
+AATAATAAACAAACATTAGAACAAAAACAAAATAGGGGGAAGATCCTTTT
+GTGCTCAATTCAAAGCTATTCTCCTCCAATCTCTGGGAAGAGGAGTGAAT
+TAATTCTGCTAGTCAATGCACTGATTTAGTTTTACCTCATTTTTTGAATA
+TTTTGATAATAAAATTATCTAAGAACCAAAATATCAAGTTAATCTTCCTA
+AAATTCTGACTATATTAAAACTGAGAACTATTCTCTTATTGAATCCAAGA
+GAAGAGAGAGGTAAATGTGGTAGTTAAACTATGTCCTGGATTAATTTCAG
+TTAAGAGACTTTCAAATAAGAATTAGTATCTGAACTGGTTTGGTTGGCAA
+CCAGCAAAAACAATCTTTACATGTTTGTTTTAGCTGAAGCCTAGAAGTAG
+ATTGTCTTGATATTAACCAAAACAAATATCTAAGAGTGTTTCCATCAATC
+CAGACAATTAGTAAAATGGTCTCCAGTGTGGTCTCCCCTGTGTCCTGCCA
+TGCCTCCCCTCACTGACAAAAGTTTGGGTTGCACCCTCTTTCCAAGTTCT
+TTCCTCTCCCTCCTCATCTTGACAGTTTACTGGTCTGAAAAAAAAAATAG
+GTTGGTAAATAGTGATCTAATATGCAAATAGAGGAATATGTCTAAATATT
+AACATTATCAAACAATATTAGTAAGACAGTTTGGTTAATGTTAGTCCAAA
+GGAAAATTTAAACTCCAGAACATTTAATCAAAATATAAGTGGCGTAAAAT
+GTCTCATTTTATCTTTTCATGAGGAAAGGTAATATATTCCATATTAATAA
+AAATAAAATGCATTTCAAATGAAATGCCATTTAAATTTGCTATTTTGTTT
+ATGATTGGATTTCAAAGCTAGGAGTAGGATCAAAGAGCATGTGGTACAGG
+TAAAAGAAAACCCtaaatccagcgctttgggaggccgaggcgggtggatc
+acctgaggtcaggagttcaagaccagcctggccgacatggcaaaactcca
+tctctactaaaaatacaaaaattagccaggcatggtggcgtgtgcctgta
+atcccagctacccgggaggctgaggcaggagaatcgctggaacttgggca
+gaggctgcagtgagccttgactgcgccactgtactccagcctgggcgaca
+gagcaaggctctgtctcagaaaaaaagaaaaCCCTAAGTCATAGATCAAA
+GGAATGCTGTAGTCAAGTAAACGAGGGGAGAGACCAAAGCTGGGGGGAGT
+GGCAAGTAGCAAAGGCTTAGAGTGGCAGAAGCTCCCGGAGGCTGAATGTA
+CCCTAAGATGAAAGACAGGAAAAGCATCGATTTAAAATGACGGCTATGTT
+GCCCAGGCTGGTCTCAAaactcctgggctgaagcaatcctcctgcctcag
+catccctaataggtggggctacagttgcatgtcaccacaaccagttaatt
+tttaaaattttttttctgtagagacgaggtcttgccatgttgcccaggct
+ggtctcaaaatcctggcctcaagtgattcttccacctcagcctcccaaag
+tgctgggattacaggcgtgagccacagtacgtggccTAGTCTTGAAAGTC
+TTAACACTGTAGATTTCACCAAATGTCACTTTGAAAACCAGGCACAGATA
+ACTGGCCCCTTGAGTACAAAGGAATCTGTAAGAGCTAGTTAGGGAATGAA
+AGAAGTCCCAGAGACAGAGTCTAGTACCCATGAGACCTAAAACCAGGAGT
+GGTAAGGGTTCTTTGTCGAAGATTCAAATTTATTTTTCTCTGCAACAGTC
+ACGAAGTCACCTGCAGCTGAGGATGAGAAAACACAGTTAAGTCCTCACTT
+AACATCACTAATAcggtaagtcctcacttaacatcattgatagggtcttg
+gaaactgggacttaaagggaaaagacatataatgaaactaatttattttt
+gtcatcaaccttataacaaaatgtgctttcacttaagataacagtttcca
+acctatctaggacattgaggacttacAGTGTTAAGAAAGTAGAATCTGTA
+CTGGTTTCAAAGGCGCTTACTTCTCTTCACTACTTACTTTTCACCAAAGC
+CCTAAAGTAGCAGTTCTTAGTCTTTTTGGCGGTTTTTAGAACTTGATGAA
+AGCTATGAACCCACTTACTAGAacatacagatacacacacacacacacac
+acacacacacacacacacacacacacacaTCCAATTTTGCATACAGTATC
+AAAAGGTTTACAAAAATCTCCAAACCCATCCATGGATCCTCTGGAACTGC
+ATTGGCCAGTATGGTAATACTTGGCAAGACTAACTCCATTTTAAGTGCCC
+ATTGGctaccatcacagaaagttctattggatagcactgCTCCAGACATG
+GAGGCAGCTTAAGAACCCTGGCCCTggccgggtgcagtggctcacgcctg
+taatcccagcactttgggaggccaaggtgggcggatcacctgaggtcagg
+agttcaagagcagcctggccaacatggcaaaactctgtctctactaaaaa
+tacaaaaattagccgggtgtggtgcgtggtgcctataatcccagctactc
+gggaggctgaggcatgagaatcgcttgaacctgggaggcggaggttgcag
+tgagctgagatcccaccactgcactccagccggggcgatagagcgagact
+ccatctcgaaaaaacaacaaaaaaCCCCTACAAATCTGCTGGCCTGTTAA
+CACCACTCCTAGTCTAATACCAGCTAGTCTGTTTTCCACATACTGGCAGA
+TCACAAAGAATTGGAGGAGGACTACTACCACCACTGATTTTGAATAACCC
+TGAAAGTTCATCtttttttaaaaaattaaattattattGCTAttttttga
+gatgcagtcttgctgtcgcccaggctggagtgcagtggcacaatctcagt
+tcactgcaacctctgcctcccaggttcaagtgattctcctgccttagcct
+ccccagtagctggaaatacgggcgtgcgccaccatgcccggctaattttt
+ttgtatttttagtagagacgaggtttcaccgtgttaaccaggagatgatc
+tcgatctcctgacctcgtgatccgcctatcttggcttcccaaagtgctgg
+gattacaggcgtgagccagcgcacctagccTAAATTCATCTACTTTTAAG
+TACCTATAAATAGCATAAAATCAAAAGGACCTTAGATAGAAAATGATTAA
+TCCCTCATTCTCCCTATCTCAAGGTATGTGTAGTTCTGCAAACATTCCCA
+TGCCACAGATTCTGCAATAATAATCTGAGTGGCTTTTCTTTTTTGAGATA
+AGGCACACATTCAGGAACTTGCTGTGCATGCGtaacagctactatttatc
+ggattcatactatgtgccaggtactgttctaagcatcctgtgtagctccg
+ctcatttcatcctaacccagtgatatgaggtgaggtgcgtatagtagtcc
+ctcaaaacaaatgaggaaactgaagtttggggtttagtgagattacataa
+gttgcctgagattacatagtaaatgtcagagAAAAGTGGTTTTGAGGCTA
+GAGTCTTCTGCAATTGGTTATGAGTCTAGAATCTATGTCTCTTGAAATAG
+GAATGTCCAatgatcgtgccattgcacttcagcctgggcgacagagcaag
+accctatctcaaaaacaaaagaaCAGGAATGCCTAAAACCACCAGAATGG
+TCCTAGGGAGCAAACAAGGCTTTCCAAACTGGACCTTGAGTGCTATGGGG
+TCGCTGGCTCTGCATCTGCCACGACAGCCTGTGGATCTGTCATCTTCCCT
+GGAATAAAATTTTTAAAAAAggccaggcgtggtggctcacgcctgtaatc
+ccagcacagtgggaggctaaggcgggcagatcactcgaggtgaggaattt
+gagaccagcctggccaacatggtgaaaccccgtctctactaaaaatacaa
+aaattagccgggcgtggtggtgggcgcttgtaatcccggctactcaggag
+gctgaggcaggagaatcgcttgaacccgggagggggaggtttcagtgagc
+cgagactgcgccattgcactccagcctgggcaacaagagcgaaactccgt
+ctcggaaaaaaaaaaaaaagaaaaaaactaaaaTATCAGTACTCTTTTCA
+CTTAGTCATCACAAACCCCTTTAATCCCATATTACCCTCTACTATCATGG
+TAGCCTCACCTTTGACGACAGactagctgtgtgacccaagtaaatgactt
+cagtgccaccacctgtaggaaggggctgctaatagcatctgcttcatact
+aacgtgttttcaggatcgatctgcatataaacgctcaatacaCGGTAACT
+GATTGTCACATTCTATCCCAGGACGCTTCCATTTGCGGATCTCATGGCCC
+GGAGGACCTGGGCCGCCTCACAACTGGGCAGCCCCGCTCACCGACACAAA
+GCCCACAACCGCGCCCAATAGGGAATCGGCCCTGCGGCCCTCCTGCCACT
+CGCCCCCAACTATCACAGTCCACGGCGGAGCTGGAGGCAGATCCCGCCCT
+TGCAGGGCTGGGTAAGAGACTGAAACTTGGAGAATGAACTGCAGGCGCTG
+CACATCTCGGGCAGATTTAAAATTCGGTCTAAAATCGGAAGCAGGTGCCG
+CGAACCCAGACCCGAGCGCTCCTCTGGGACGTCCAGCCGCAGAAGCGAGC
+CCAAAGCCCAGCAGGGTTCTCCGCGGGACTCGGGGTTTCAGAACCGCCGG
+GCTCTTGGGCGCTCGCCCAGGGCGCACGCGCAGTCGCGAGGCCGCGCCGC
+GGACTGCATCTCCCAGCAGGCCCCGCGCAGCAGGCCACGCGGCGCCACTG
+ACTGGGCGGGCGGCTAGCTCCCTGGCCTCCCCGACATGCCGAGGAGCCCC
+TGGCTTCCGGAGCCGACGAGGCCGCAGGGGCCAATGGGACCATCTTCAGC
+CAGCCCAGAGTAGCCGAAGCGGGTGGGGCCTGGCTTGGGAAAGGATtcat
+ccggggaagctgattaacaattcagatttccgggtctcaccccgacactg
+acgcactggagagcgcgtggccctgggatctgcgttttcccaagcgctcc
+ggagtaattctaacccaggttGCCCGCCAGTCACAACGACCTCAGGCTTG
+TTTTCTTCGCTTGGATCCAGCTGCCCTGCCCCCAGTCACTCCCAGAATTT
+CAGGGCGCGCCCCGTGGCCCCGCCTCTCGTCTCCAATTGGTCCCTCGCTC
+ATCCAGTCCCCGTAGGCCAATCTTCCCTTCTCATTGGTAGGCGGTGAGTG
+TGTGGAGAAACCTGACCTAATGGGCGCTGGAGTTCGCAAAACGTGACCCG
+GAAATTGGTCACGAGCAGGCGCCGTGGGCTTGTGGACGCCTAACTTGCGC
+GCTGAGATTTCCGGCGTGGGAGCAGAGGTCTGAGTCTTGCGTGGGTCCTC
+TATATAGGGTGAGAAGCGTGGCGCTCGGTTCCTGCCTCGGGGAAGTCCTG
+GCGCAGATGGGCCACGGGGCCGGCGTGGCGGCGCCTGGGACCGACTGAGG
+CCTAGGCGCCGGAGCCGGCCGCGCCTGGGCTGGAGCGGGGCTCCTCGGCC
+TGGACTGGGAGCCCCCGGCCCCGGGCTCCTGCTGGCGCCGTCCAACCTTA
+CATGGGTTCAGGGCGCCTTCGTAGGCGGGCACGGCTGGTTTCGGGCTAAG
+GCGCTCTGGAGACCTGACGATGGCGTCGGGCCCGGGCTCCCAGGAACGGG
+AAGGGCTCCTGATAGTGAAGCTGGAGGAGGACTGCGCCTGGAGCCAGGAG
+CTGCCCCCACCTGACCCAGGACCGAGCCCCGAGGCCTCCCACTTGCGCTT
+CAGACGGTTCCGCTTCCAAGAGGCAGCTGGTCCCCGGGAAGCCCTCAGCC
+GGCTCCAAGAGCTTTGCCATGGGTGGCTTCGGCCTGAGATGCGCACGAAG
+GAGCAGATCTTGGAGCTGCTGGTGTTAGAGCAGTTCCTGACCATCCTGCC
+CCAGGAGATCCAGAGCAGGGTGCAGGAGCTGCATCCGGAGAGCGGCGAAG
+AAGCGGTGACCCTTGTGGAGGATATGCAGAGAGAGCTTGGGAGACTGAGA
+CAACAGGTGAGAGAGAGAGAGAGCTGTTTTATCTGTGGTTTGTTTAGCCC
+TGAGCACTGGGACATTGCGCCCCCGGTCGAATTCAAGTAAATTGCCCTGA
+GTAGACCTTACGTGGGGAAGAGGACTTGTGATTTAACCTGGAACACTCAT
+CCTCCAGATTTTCCCCCAAATGAACGAAAGCAGTGAAGAGTGCCCTGTTT
+CCACGCGGAGGCGGTGTCCCTGCAACAGTTAGTGTTAGCCAtggagttag
+atcgccagcgttcaaatcctcaatctgctagtactagctttgttactttg
+gcaagttacttgatctctttcggcctgttttcctattcgtaaaatgagga
+tattaacatactttctagggcttagagggagagcagcatgtaaagttgtg
+aacactactagcttatgagtgcttagtacttgttacctgttgttatGTTA
+GGGTCCACGGTCTGGTCTTCTCTGCAAAGCTGGGCCTCCGTTAATTGTGA
+ACTTTGAAAGATAATTTGGCACCGAGGCCCTGAGGTCATTGGTCCCCAGG
+GCTACCCCAATTTAGCCTATCCTATAGTGAGGAATAGAAGCACCTAGAAA
+AGGTGGGGAGAGCAAAAGGGAGTGAGGTGTATCTTAAGAGCTGTGTGGGG
+AAGGTGTGCTCTGGGAGTGGGCCCTTTCCCTAACCCCTCCCCCTGCACAT
+GGGATCAAAAAAGCCTTTAGTGTAAACCATTTTTCTGTTACCTGGGCCCA
+AAGGGATCGCCTGAGGTTCTCTGTTGAAGGTTTGCTCTCAGTATCCTATA
+CTAATTTCCCTTCCTCTTGGGCCCTGTTGTGATGATGAGTGATGTGGGTT
+GGTTCCCAGGTCACAAACCATGGGCGGGGAACAGAAGTGCTTTTGGAGGA
+GCCTTTGCCTCTGGAAACAGCACGAGAGTCACCGAGCTTCAAGCTGGAGC
+CAATGGAGACTGAGCGAAGCCCTGGCCCCAGGCTGCAGGAGCTGCTAGGC
+CCCAGCCCCCAAAGGGACCCCCAGGCTGTAAAGGAGAGGGGTGAGGCACA
+GTTATCTGGGCAGGTGGGAGGGAGGAGGGGCTTGGGGGTTGCCCCCGACA
+CTAGCTGGATGTAGCAATGATGCGAAGGAGAAGGAATTTCTGAAGATCAG
+GTTCTCACCTGTGGAATGAAAGACCTGCAGTTGGTGGTGTGGGTTCTCCT
+GGGGCTGGGGGAAGGGAAGGGAGTCTCAGTAGAGCCCTTTTTTATGCAGA
+ACAGAGGCGATTTAGAACCACTTGAATGACGCAGGGTTTGGAGTGCTACT
+CTTGGTACTCCTTCCCTCTCACCCTGTCATTTTGGATATCAGCTGATTAG
+GCCTCTGTGCAGTTTAGCGTCATTCCCAAAAGCAGAGGCTGGGTGTTGGG
+GAATGGATACTGTGTTTTAATAATCCTTGGGTTGCCAAGAGTTAGGAATG
+CCATTCTCATTATAATTTCTGTCACCTTCAGCATTATCTGCTCCCTGGCT
+TTCTCTTTTTCCTCCTGAAGGGAACATGGAAGACAAGGAGATGACTGGGC
+CCCAGGTGATGTGGAAGTTTCCATTGTCTCCCCCCAGCACCCTTCCTCCC
+CTGAGTGTTGGGGGTGGGGGTTCTCCATGTGGAAGGTCCTTTGTCCCTTA
+CCACAGCGTCTCCCCCACTGCTTTGTCTATTTCACACCTCACTTGGAGGC
+CTGATACCCTTCTTCCCCCCTGACATGTGCTTGGCATCCCTGGATTTTGC
+CCCTTTAACCCATGACTCTGCTTGAATTGTTCTTGGTGCATCAGGGGCTA
+AAGGAGATCTTGTGCTGTTTCAGTTGCCTGAGAGCTTAGAGGACGTGGCA
+ATGTACATCTCCCAGGAGGAGTGGGGGCATCAGGATCCTAGTAAGAGGGC
+CCTCTCCAGGGACACGGTGCAGGAGAGTTATGAGAATGTGGACTCACTGG
+GTAAGGACTTCTTTTCCAGGGATGATGACTGCGCCATTTCTGACCAGGGT
+CCTGCCCGTTATTCATTCACCTCCTGGACACAGACTCTGAGTTTTGCCAA
+GAAGCCTCCACAGGAGACTTCCCTTTGTCTAAAGTCCCCTGTACGAGAGT
+CATGTATCTGCCAAGTGGTACAGTTGGCACAGGCAGCCCGGGACTGGAGT
+CCCAGCTGCCAGAGCCTAAGGCGAGTCTGAGCCATGTGCACTTCCTAGGG
+CAGAGCAAACCCAATGCGGTGACAACCTGCCAGCATCACACACATGCAGT
+ATTCCAGGATGCTGGGGGGCTCTAAATGGTTGATTCCTTGCAATTTTCAG
+ATGCTTATTCTTATGAGCTCGCCAGTGTTTCCTGTGTTCCGTTAGTGTTT
+CTAGGCTCGTCCCCAAAGACAAAAATTTCAGGGGTAGTAGGATCAACATT
+CCAGCCTATCATCTCTCACAGCCCATAAAAATTCAGAAAGTGGGGAGGGT
+CTTGTGGAAATTTGGAAACAATGTATAGCTCCAAAGTAGGCCATATCATA
+AATTAAGATTTACCTATGTCTTGTACTGTACTCAGAGTTTTAAAATTATG
+CCTACGGaatatgacagactgacatatagttggatttaggtggaggatat
+gcttgtatttattgtacaattccctcaacttttctgtatgtatgagaatt
+cttttaataaaaaGTTGGGGAAGTCTTAACATAAAACAAGACTGTGTGTA
+CATTATGATTATACCTATGTTGAAACACACCAGTAGAAAGACTCACTggt
+gtggtggtggtagtcccagttactcaggaggctgaggggagaatcacctg
+agcccagtaggtcaaggctgcagtgagctatgatgatgccactgcacctc
+aaccaggtgacagagtgagactctgtttcaaaacaaacaagaCACACCGC
+ACATTGTTTCCATATATCAGGTTTGCCTAAAAAGTATCACAACTGTACAT
+TTGTTGACACTAATTCTGCAAAcgcaatcttgctcactgcaacctctgcc
+tcccgggttcaagtgattctcctgcctcagcctccagagtagctgggatt
+acaggcatgcgccaccacacccggctaattttttgtatttttagtagaga
+caggatttctccatgtaggtcaggctcatcttgaattcccgacctcaggt
+gatccacccgcctcccaaagtgctggaattacaggtgtgagccaccacac
+ccggccttttttttttttttttttttttttgaagtgagtctcactctgtt
+gcccaggctgctctggaacttctgggctcaagcagtcttcctgccttagt
+cAGGAAGTGTGCCACTGTACCAGTTTCCATATTACTTTTCACTGCTGTGA
+TGTCCAAAGTTGAACATGGCCCTTTTAGTGAGAGATGCTAAATAGGAAAA
+GATCAGATTACAGCTTGTTGGAATTAAACTTCTGTTGGAGTCCATGTTTG
+CTGGAGGTGGAGGTTTTTGTTTTTCTTTTTGGCACAGCATAGAAATGGCA
+CTTGTGGGTTTTAATCTCATGGTCCTCTTAGAGCCCTGGGTCCTTTTCTG
+ATTGTCTATTATGTTATATTTTCTTTCCCTGGAGTTGTCCGGTCAAATTT
+AGTTCTATTTTGTATTTATATGTAGAGACAAGGCCCTTTTATGATATTAA
+ATGGATTATTCAAGGAACTGACCATGTTCATTTTATAGTTATTTCAATTA
+CAGTAGTGTACATTCTCATTGCAAAAAAAAACATTCCAAGTACCATGaat
+atttaaaaaaaaaaaaaattggccgggcgcagtggctcacacctgtaatc
+ccagcactttgggaggccgaggcaggcagatcacttgaagtcaggagttc
+gagaccagcctggccaacatggtgaaactccatctctactaaaaatacaa
+aaattagccgggtgtggtggtgcacgcctgtaatcccagctacttgggag
+gctgaggcaggagaatcgcttgaacctaggaggcagaggttgcagtgagc
+ggagatcgtgccactgcactccagcctgggcgacagagtgagactctgtc
+tcaaaaaaaaaaaaaaaGTCTCCCTCCCCTAATTTCTTTCTCTAGAGGTA
+TCCACTGGGAACAGTTTGTGTATATTCCAAGTAACTGCTGTCAGATTTAT
+GGAGCATTCTGTATTTATCCACTGAGGGCAGGGAACAAGACTGTTTCCCT
+ACCCTGGTAGAGGAAAGTGGCAGTACAGAAATCTGTTTCTTTCATTGTGA
+ACAGAGTCTCACATTCCCAGTCAGGAGGTCCCAGGCACCCAGGTGGGACA
+AGGAGGAAAGCTATGGGATCCCAGTGTCCAGAGCTGCAAGGAGGGCCTGA
+GCCCCAGAGGCCCAGCTCCAGGTAAGGAATGAAGACAAGTGGCCTGCGCA
+GCAAGCAGCAAGGCTCTTGCAGTTAAGAGTGAGGCATTTtttggttttgt
+tttgttttgttttgagatggagtggcactcttgttgcccaggctggagtg
+caacagtgcgatctcggctcactgcaagctccgcctcccaggttcaagcg
+gttctcctgcctcagcctcccgagtagctgggattacaggcatgcgccac
+cacgcccagctaattttttgtatttttagtagagtcggggtttctccata
+ttggtcaggctggtctccctgacctcaggtgatccacccacctcggcctc
+ccaaagtgctgggatttacaagtgtgagccaccgcccccagcAGAGTAAG
+GCATTTGAGGATTTGGGTGCAGGGCCGGCCCAGCACAGCTGCTAGAGAGG
+TACATTACGTCCTTTGACCCTGCCATTCTCCATCCCAgtgaggcaagtga
+ggaacccagggtgcagagttcaaggaggcccttattctTGAGCTTACTTG
+TCCCACCCTACTCTCAGCCCTGCTCCATCCCACCCATTCCTGAAGGGCAG
+AATCGAGAGGCTCAGGTGGAAAGGAAAATTCTAAGACTGGTCTCGGCTCT
+GATTCCTTGACCAGTGGCCCGACCCTTTATCCTGATGCTTCTCCAGAGTG
+CTTTACCTTTAGGAGAGGATGGGATTCTGAGGTAGAAGCAGCCCTTCTGG
+GCTGCTGACCTAACAGGCAGCGGCAGACAGGTGGGATTTTCTTTTCTCCA
+GCATAGAAATAATGTACGGGTTTGGTTTCTCTCTCTCTACCAGGAGAAGA
+GAAATTTGAGAACCTGGAAGGTGTTCCGTCTGTATGCTCTGAGAACATCC
+ACCCTCAGGTGCTGCTTCCTGACCAGGCCCGAGGGGAGGTGCCCTGGAGT
+CCTGAGCTGGGAAGACCTCATGACCGGTCGCAAGGGGATTGGGCGCCTCC
+CCCAGAGGGTGGAATGGAGCAGGCCTTGGCAGGAGCCTCAAGTGGCAGAG
+AACTGGGGCGACCGAAGGAACTGCAGCCAAAGAAACTCCATTTATGTCCC
+TTGTGTGGCAAAAATTTCTCTAACAACTCAAACCTAATTAGGCACCAGAG
+AATACATGCAGCTGAAAGACTGTGTATGGGTGTGGACTGCACTGAAATCT
+TTGGTGGGAACCCACGTTTCCTGTCACTACACAGAGCACACCTGGGAGAG
+GAGGCCCACAAGTGCCTTGAATGTGGGAAATGCTTCAGTCAGAACACCCA
+TCTGACTCGCCACCAACGCACCCACACGGGTGAGAAGCCCTATCAGTGCA
+ACATTTGCGGAAAATGTTTCTCCTGCAACTCCAACCTCCACAGGCACCAG
+AGAACGCACACTGGGGAGAAGCCCTACAAGTGCCCTGAGTGTGGGGAGAT
+CTTTGCTCACAGTTCCAACCTCCTTCGGCACCAGAGAATTCACACTGGAG
+AGCGACCTTATAAGTGTCCCGAGTGTGGGAAAAGTTTCTCTCGGAGTTCA
+CACCTCGTCATTCACGAAAGAACTCATGAGAGAGAGAGACTTTACCCCTT
+CTCTGAGTGTGGGGAAGCTGTGAGTGACAGCACCCCCTTTCTTACAAACC
+ATGGAGCCCATAAGGCAGAGAAGAAGCTCTTTGAATGTTTGACTTGTGGG
+AAAAGCTTCCGGCAGGGCATGCACCTCACCAGACATCAGAGAACACACAC
+AGGAGAGAAACCGTATAAATGTACCCTTTGTGGGGAAAACTTCTCTCATA
+GATCCAATTTAATCAGGCACCAGAGAATCCACACAGGAGAAAAACCCTAT
+ACCTGTCATGAGTGCGGAGACAGCTTCTCTCACAGCTCCAATCGGATTCG
+CCACCTGAGAACGCATACGGGAGAGAGACCCTATAAATGTTCTGAATGTG
+GAGAAAGCTTCTCTCGGAGTTCCCGTCTTATGAGTCATCAGAGAACTCAC
+ACAGGTTAGTAACAGTGGGGTTTCTCTTTGCCCCAGGTGAGGTGGCATAT
+TCAGAGGAGCCTGTTGGCAAGAGCTGGTATTCCCTGCCCAGCCGACCAAA
+TGACCTCTGCATTCTTCAGGTAATGGGGGCTCATTGTGAGGGAGGTGCAG
+AGGCAGCAGAGGATTGGCATAAAACTGAAAAGGAGTTCTGTCTGCATGAG
+AAAGGATGGCAAGTCTCTGAGGTGACCTCAGGGTGGAATTCTCTGTTAAG
+TCCACCCTGCCCCAGGGTGCTCCTACCCTCTTGGTCTTTTTAAAGCCAAG
+GTGCGATTTGGGCACCTGACTGTCCAGTTTACCTTAACAAGTTTGGGAAT
+CCATGTGATGTTTTTGATACTTCTTCCTCATTTGGGACATTCAGTAGGAG
+CATTTGGGCTTCCGGGGCCCCTGAGACCAAAGAAGAGGGGCCAAGTACCC
+TGGGAAATCAGCTGAAGGTCAACAAAAGACTGGTTGTGAGTTGCAGCTGT
+CCCGAAGGCCCCAGTTGGGAAGCCATGGGCAGTCCAGATCAAGCCACCAC
+GTGCCCTACGATGGCCTAACAGGAGTGCCCATTGGCAGATTACACATGTA
+AATATGACCTCAGACAAAAAGGAACCAGAGGCCCAAGGGCAATAATAAGG
+TGGAATTTGCAGGTCAGCCCAGGAATTGGCAGAGGAAGTAGGTGTCTGAT
+AACCCTTTGTGGAGAATGAGATTCCCCCCACCTGTGTGAGAAAAATAAAC
+AGCTCTGGAGTCTTGTTCCTGACTCCAGAGGAACGAGAGCATTCCAGGAA
+AGAGAGATTCCCTGGAAAATTGAAAATGTGAATCCTAGGGGGAAATTGGG
+GATTGTGTCTTTCCCTGTTGAAAATGTTTGGATGGGAATAAATATCTTCA
+GGAAACATAAATGTCTGTGAGTCTTCAATGAAAGCCTCTGTCTAGACCCC
+CGAGTGTTGATCTGTCTCCCCTCTGCCTTGGTCAGAGGCCCTGCTTTCTC
+ATAGACTTACTGGGTTGGTCAGGAAGATGCTGACAAAGGAGGCAGCAGAC
+AGGCAGAGGCAGGTGAGGGCCTGGCAGCCTCCAGGCTGGGACTGCCATGT
+GGTAACAAAGGGTCAAGCCAAATGGCTGCTGGGGTGATGCTGTCATAGGG
+TCTCTAGAAAGTATTCTTTCCTTCTGTGGTCTATAGCAGTAAAAATGTTT
+TCAATTCTTTGTTTAGAATGTTTACATTCTTACTCAGTAGCTGAGGAAGA
+TCTGACTCTTAGAGAACAGGATATTTTGGTCTTGCAACTGATTTCCAGGG
+TGGAAGTTAAGATGGTCCCAGTATAACTGAGTTATTGATTATTAATGGTA
+GGAAGATATAGGAGATGGCGCAATTATTAAGGGAAAGCATTATATTtatt
+ttttggtagaggtggggtctcactatttgcccaggctggtcttgagttcc
+cgagctcaagccttcttcccatcttggcctctcaaagtgctgggattact
+agcatTGCATTTTAGAATGGCATATCAGAAATAGGAATTCTAGTAGTGTG
+TATCTGTGGGAAACGGGGGAGTATTCTAAGAGTAGGAAATCGGATGCCAG
+GAAAACACCTCAGGATACAGCCCCGGAGGAAGGTATCCAGCTGTTCTTCG
+GGTGAAAAAGATGAAGAAACAGTCCTTTGGGAACAGGCTGATGGATATAG
+CAACTTGAAGTCATGGAAACAGCGCTCCATTGATCCTTCTCTCAGCCCTG
+CCTCAGTTTAGTATGTGTTTTTCTTTGGTTGTCTGAGCCAGTTTTTTAAT
+ATCTCACTATTTCTCATTTCTGTAACTTCCTCTTAATCAGCTTGTTCACA
+GGAGGAGGGCAGTGGTGGTGTGGGGGTTGAGGGCAGGGAAGTGGAGGGTT
+AGGATTAGAGAGATCAGAGTAGGATCAACAGTGGTAGGAGCAGGACCACA
+CTCCAGTGGAGCAGTGCAGGGCCAGCCAGGCTGCTGATGTCATGAATTGG
+ATGGAATGTAAAGCTGGTGTTCCTACAAAGCACTCTGGTTAAGATGGCAG
+TTTATGTGGACAGAGACTGGAAAGCGCCCCTTCCATCTACTCTCCCTCCC
+TTGGTAACATCACCCACACAGATCTTATGATGTGGTCCAACTGGTGCTGC
+TCATACTTGGAACACTGCAGCTTGAAGCTGGGAAATGACTCTCAGGTATT
+TGCCATAAAAAGGCATTCCATTGGAACGCTTCACTCAAATCTTCAGTCTA
+GTTCCCCTTCTAGTAAACTTCACATGCTTAGCTGTTCTTGGCCTGTTTTA
+ATGAGATGACATCACAGAAAATAACTACATAAAGCAGCACTATGCCTGGC
+ATGTAAGAAAGTGCCAACTGTCGACAGATGATCCAAAAGATTTCCTTCTA
+AGCATCTAACACTGACTGAGGTCACTGAAGACCACACTGGCAGGAATTTC
+AGGGACTGATGACATCTCCTTCCCTTGTACTCATGTTTGAGAGAGTAGGT
+CTGATTCCCTTACTGCAGGCCCCCATGAGGTCtgatacggttcggctctg
+tgtccccacgcaaatctcatctctaattgttatccccatgtgtcaaggga
+gggacctggtgggaagtgcttgcatcatggggacggttttcccctatgct
+gttctcctgatactgaattctcccgagagctgatggttttaaaagtgtaa
+cagttcccccttcacttgcgtgcttgcttgttctctcttgccaccttgtg
+aagaaggtacctacttcccctttgccttccgccataattgtaagtttctt
+gaggcctccccagccacacagaactgagtcaattaaacctcttttgtttg
+taaattacgcagtctctgtatctttatagcagtgtgagaaCTAGGTCACT
+GCAAGAGATGTCCAAGTTAGTGCTTTTTCACATTAATACTTTGCCCACTA
+GGGCTCTTGTAAAAGAAGCCAAAACAGTTTGAGTGGCTTTTATGTCACAG
+GGAGACTAACCCTGGGACAATAAGGACCTCTAGCCTCTAAGTCCAAATGG
+GTGCAAAGAGGTCTTGGGAGATGTGGAGTGACCCTGAGCAGCAGCCACAC
+ATCCTTAGCAAAGGTAGCACATGAAACCAGCAGGGAGGCTGGTGGGTGAG
+AACCAGTGCCACATCTAAGCCCTGTGAAAAGGCCTGGCAGCGTCAGGCTG
+GGGAGCAATGACAACAAAGCCAGAGGTGGGACACAGACTGGAAGAATGTT
+TTAAAAGCACTGAATTTTTCAGAAAAATCCATCAGAAGTCACTTTAAAAG
+TTTTGATGGCTGTAATGAAAGAACTTTTGGGTCTCAGCACCATAATCTGA
+AATTTCAGGTTTTAGGCTCAGCACttttttgttttgttttgtttgagacg
+gagtctcgctctgtcacccaggctggagtgcagtggcacgatctcggctc
+actgcaagcttcgcctcccgggttcacgccattctcctgcctctgcctcc
+cgagtagctgggactacaggcgcccgccaccacgcctggctaattttttc
+tatttttagtagagaccgggtttcaccatgttagccaggatggtctcgat
+ctcctgacctcgtgatctgcccgcctcggcctcccaaagtgctgggatta
+caggcgtgagccaccgcgccccgccTAGACTCAGCACTTTTTAAAGAAGA
+GTGATTCATTACATTAACTGATACTACTTTGGAATGTGCAAAATCACCAC
+TGCTTTAAAACTTGTAATTTTTTCTAAGTGTTTCACAAGCATTTGAAACA
+ACTAAGTCACGTAAAGTGTCTTAATGTGTGTTACAGGAAAACCAACTAGC
+AAATTTCTTAGCACTAGGAGACTTAATTTTGGAGGTCAGGAACTCAGGAA
+TAGCTAGATGAATTCAAGCAAAATGCatttatttatttatttatttattt
+GAAATATTTTCTTTTACTCTTCAGTCTAGCTTGCAAGCACTCCCAATTAT
+TGACTTCTGTTCTTGAAAGGGCGGTTAATATTTCCTTCCCATCATATACT
+TTTTAATAAGACCAGCTAGACCTTGCCTGAGTGGTACAGTGAAGAGGCAC
+TGGGAATGATCTAGGTTAAGTTCAACAACGACAAAATGGTTGAGGAAAAA
+TGACTCAGATCACAAAAAAATTCTGATCTCCCAGTTAATGTTATTGCTCT
+CAATTAGCTTACAGAGACACCTTAAATGTCTCAAAAGATTCTGTCAGAAA
+TCCGGTGGCTCTCAAGCATCCCCAACGTGCTCCAAGGAGAGTAGTATTTC
+TCCAGGCAGCGAGAACGGGAAAGAAAAACATTAAGGAGTATCGTTCTGAA
+GTCCAGCGTATGTTTTTGGACATCATGAGGAATTGCTTGCCCTCCATTCC
+GTTCAGGGAGGCCAGTTCCCCACTCCCGAGGTGCTGCTGCCCTTGAGGGA
+GTTCTCGGCTCTCCTGGGCCTCCCGGCAGGAGTCCAGCCCCAGCACCCGG
+CGCAAGTGTGAGTGCCTGGACTTCTCGGAGAAGTTCCTATCCCCAGGAGT
+GATTTGCAGAACCAGAGACTCCCTTTTCAGGCTTGGGCAAAGCAGACGCC
+TCCTGCTCCGCATCGGCTCACACGCGGCCGGGCCCACGAGCCTCCTCCAA
+CCGCCGCCCCGGGCCTCGGGGCTGCCGCTCCCCTCAGCGTCGGCTCTGCC
+CCCAGAAGCGAAGGCCGCCCTGCGCCCGGTCCCGGCCTTTCCCTGCCCTC
+TGGCCGGTCCTCCTCCCGCGGCCGTCCCGGGACCTGTGCCCAGACCCCTG
+GGGCCACGATCACGCCCCAGCCGCCCAAGTCACCGCCCCTCCCCTCCCTT
+CCAGCGTTCCCGCCCGGGCGGTGTATGGTGGCTCCGGTGTATGGTGGTTC
+TCGCACGCACAGCCGCAGGGGTTTCCTCTCCTAGACTCGAGGCGGTGGCG
+CACCTGCACCCTCTAAAACTCCCCCGTCGGCCCTCGCGGTCTAGCGGGAG
+GCGCGGAGGGCCGAGCTGGGGTGCGTGCGAGCGGGCGCCAGGAAAGCGCG
+GGGCCGCCCTAGGGGCTAGGCCTTTCTTTAAACAGTGGGAGGCCCACGAA
+GTGTCTGAAGCCCGAGGCTCCCCTTTTTGTTTTAGTTCGCTCTCTTCTGG
+TAAGAGAATAAGGGTCGGGCAAGAATGGAGAGGGGACAGAAAAGGAAGGC
+AGGGCAACTGAAGAGGCAGAGTCAACGCAGAAGGCGAAGGGAGCCTGGAC
+CAGGGCAGGGCAGTGAGGACGAAGAGTGGAGAGGAGAGATCCAGGAGGTG
+GAGCGGTCAAGACTTACGTGGGCCGAGACCCGTCTAAAATCTCGTAGGAT
+GTCCCCCAGGGACACTAGCCTTGACCTGTCTTTCCTGCTCTTCTCCGCCA
+GAGGCCCCCAAGGCAACGGTCCAGGGACCTTGCAGCTTGCCTGGGAGATA
+CACGTGCCCACCGCAGAGACTGAGCCCCTGCTTCACAACTTTAAACCCAG
+CTCAAAAGTCACGCACTGTCCTCTCAGACACCTCCCCTGCTATCCAAGTC
+TCAAAGGCCCTCCCTATGCTCACTTTGGCTCCGGCCCTTACACATCCCAT
+GGTGGTTTGTTCTCATTCATTTTCTTGGTTATTCAGAGCTGAATCTCCAA
+CAACATGCTATTGTCTAGTACATGAAACAGTTAACAGGAAGTTTCCAGAA
+TCAATGAGTACTTTTGAAAACTGGGGTGACTCTCGGTCACTCTAGGAATT
+TATTATCACTAAAAAGAATGATGATGTTTGATGCAAAGACCCAAACTAAA
+AGGAACTAGAGAGCTGCCCAGAGTCCTCATCTGCCATCCCCCTCCACTTC
+CACAATCCATCCTGTCCCAGGCTTGGAAGGTCTTTCAAAAGAGGCAAAAC
+ATCAAGCAAAGAGTAATTACTACCTTCGCCCTCACCCAACCCCAGCTTGC
+AGTCATTATGGACTAATCTTAAAAAAAGAAAAAGTCAAGCTGCTTGATGT
+TAAAGGTCTCCCATCTTCCACCAGGCTGCAGACTGAATAAGGCAAGAAAG
+CACAAATCAAGCCTAAACTGAATGTAAAAAGGATGCCCAGTGGCAATGTT
+GATATATTTTTTCTACAAGTTCTGGGTAATAAATAAGGCACAAAAAAGAT
+AACTACTGAATTTACAAGGTGAAAATATCAGCAATCACTACTAATAAAAA
+AGGAACCCACTTACAGCAACAACAAACCTACCTAGGAACAATAAAAAAAA
+TGAGAACTCCATTAAATGAAAACTGCACTTACAATTTGAAAGGAGAGAAA
+AGTAATGTAAATTCTTTCCAATTTTACTTAAATTAGGAATAAATTCGCAG
+AGGGAGTTGGTGTCTGGAGGAGGCTTGAATAAATTTTATGCTGAAGTTGA
+CTTAAGATAGTAAGAATAGCTTGTATATTTTCAAACATGGAAAGTGGGCA
+TTTGCTTTTCATTAAAATTCACAggccgggcgcagtggctcacacccgta
+atcgcagcactttgggaggctgaggcaggcggatcacgaggtcaggagtt
+caagaccaacctgagaaacatggtgaaacctcgtctctactaaaaataca
+agtcaggtgtggtggcacgcgcctgtaatcccagctactcaggaggctga
+ggcagaattgcttgaacctgggaggtggaggttgcagcgagccaagatcg
+tgccactgcactccagcttgggtgatacagcgagactccatctcaaaaaa
+aaaaaaaaaaagagaaaTTCATATTAGCCAGTAATGAAAATGGCAAGGTA
+CTAGAGCAAGAGTGGACCCCAGTAGTTCTGTATTTAGTCACTAATTTTAT
+ACTATAATTGCCTAGTATTCACCAGTGTAACAGAATACCCATCTCAGAAA
+CAGAttcttttttttttttttttttttttttttgagacggagtctcgctc
+tgtcgcccaggctggagtgcagtggcgcgatctcggctcactgcaagctc
+cgcctcccaggttcacgccattttcctgtctcagcctcccgagtagctgg
+gactacaggcgcctgccactgcgcccggctaattttttgtatttttagta
+gaaacggggtttcaccatgttagccaagatggtctcgatctcctgacctc
+gtgatctgccctcctcggcctcccaaagtgctgggattacagccgtgagc
+caccgcgcccggccAGAAACAGATTCTTGAAGATAATATATGAGAAAGGA
+AACACTGAAAGCCAATAAGAGCTAATTATCCAAACAAAGCTTGTTATTTG
+CAAATATCAACTCACCTGACACCTTATATTAAATAGGGaacaaccataaa
+gataccattcttttggttacaaaattagcaaaaactaagagcttaacaat
+attcaatgttgggattggtgcattgggagaagtactttcaaaataatggt
+gggaatgtgaaagcaatttaacagcgtgtatcgcagctttttcaaaagtt
+cattctatttgacctggtagttcaactGATACGTTACATCCCCTGGTGGA
+GTATTAAAAAACCATCAAATGTGAGGTTAAGAGATTTTAATGACCTAAGG
+GAAACTCTCAGAAatagtgccgtatgatggttaaaagcctgagctttggc
+attaaacagaatttaagtctcacctctgctgtttaccagtttatgtgacc
+tttgtcgagttacttaatctctctaaatctgtttccttatgtatttgaaa
+agggaagtcattatTATGAAGACTAACATATATATACGATCCTATATACT
+CAATAAATGCTAACGTATTAGTAACAAACCATAAAATATGTTAAGACAGT
+AAGAGATAAGGTTTTATTTACAATGTAATCTGCCTATTTAAAAAATATAT
+GGTATACACCGAAGTGTTGAGGTTATCATTAGTCAATAGAATTGAGTGCT
+TTTTATCTTTTTTTATATATTCCCTATAATCAGCATGTTACTTTCACAGT
+AAGAGGAAAACAAACACTAAATAGGTAGTAACAGAGTTAAGAAAGCAGAG
+TGTGTTTTACCATTAAATTGAAAACCTAATTTATCCTTATCTTAAAGCTA
+ACTAGAACTAGTCAGCACAGTTTCTTTGTTATACGATATGATTACAAACT
+AATGCTTTTCGCAAAGGCATTCCACCTTAGATAATCTGGGACAATACTTC
+ATTATTCAGATCCTTGTGtaaaatttaaaaaaatgaatttatgaaacaca
+aatttaaataaatttaaaGAAACACAAATGTATTATTTTCAAACTGTAAA
+TTTTATAACCATTATATAAATGGGCACTGATATACAAAATAATGTCAGTT
+GCTAAAACAAGACAATTCACAGCTGGCCTACATCATATAATGGCAGAAAT
+CTTTAAACACAAAATCTAATGATTAGAACCAGAAGTTGAAGGCCCACTGA
+AGGAGTCCTTAATATTATGAGGCCTAGGTTTCAAAAAGCTACCAATTCTA
+GAATGGATTTTACTCTGGAACTGTTTCTTGACTATTTCTTGTTGCATCTC
+TTTCAGTGTGAAGTGGAATCTCTGAAACTCAGGTGTGGCATCAACAAAGT
+CAAGAAGGTAGTCCAAACTCTCTCTTACAGCAGATAATTTAAATTCAGCA
+GTCTGCTTCTCAGCTTCTCCTCCTTTTTGAACAACTTCCTTTGTTATTCC
+ACCTTTGGTTTTTAGGAGACAACCCTTTTCTTCATCTCCATTTAACCACA
+CCCTATCATCATCCAACTTAGTTTCCAACTCCCCACATTTTTCAAGAATT
+TCTCTATAATCCCCATGTTCTAAGCCTTGAAAATCATATTCAGGTTCCTT
+TTTGTAAAGAAGATTTTCCCATGCATTTGCTATGGTTATTTGTTTTACTT
+CTTCCCAACTTTTTGCCCAGTTAAAAATTGCACTTTTTATATTGTAGATT
+TTAATTTTGGAAACTCCTTTATCTCCTTTCTCTTGCTCATCATCACTTTC
+TTCAAATATTACAAGACTCTCTTCAAGTTGCTTCCATCTATACAGCCGTT
+TGCAGCTCAAGatcacaccttgattcattggttgaatcaaggttgaagtg
+ttatgggggaagaaCATACATTTTATTCGACCATCCTCACTGGTTAGGGA
+TTCAGAGGAAGGATGAGCCGGGCAACTGTCCAGAAGTAACAATGCCCTGA
+CGTCCTCGTCATGAAATCTTAGAACATTAAGTTGAAAATGTCGGACCTCA
+GGAACAAAGTTTTGAAAAAACCATTCTGAAAACAATTCTCTGGTGAACCA
+AACATCTTTACTGGGTTTATATATCACAGGCAATGTACTTGTGTCCTCTT
+TCACACTTTTGGGCAGTTTTGATTTTCCAATAATGATTGACTTTAATTTA
+TGAGTTCCGTCTGCATTTGCACATAAAAAGGCAGACAACCTTTCTTTGTT
+TATTTTCTTCCCTGGTAGGCAGATATCTTTCCTACTTGCCTGAGAATTTT
+CTGGCATTGACTTCCAAAAGAGGTCTGTTTCATCCCCACTGTATAGCTGA
+GCTAGACACAGTTTCTCCTCTTTGATTATCATGGACAGTTTTTGTCGAAA
+TGGCTCAACATTTTCAGAAACTGAACTTAGGACTTGTTCCCCACATCCTT
+TTCGGTTCCCAATTGCATGCCGATTTCGAAATCTAAAAAGCCAACCAGTG
+CTAGCTTTGAAATCTGTTCGCCCAAAACACCGTGCAAATCTCTCTGCAGC
+AGCCTGAAGCTCCACGCCTCTTACCGGAACACCGGCTGAGCGTTTCTGTT
+GGTACCACATGTAGACCGCATCATCTACATCACCATATTTGGCTCCCGTT
+GTCCTCTTTCTCTTCTCAGCCCCTACTAATGGCATGTCCTGCTTCAGTAC
+AAAGTCCAGAATTAACTTCTTATTTTTTTTAATGTCATAAAATGTTGACT
+TACTGATTCCAAATTCATCCATTACACTTTTAAGTGATCGTCCAGCTTCA
+ATTCTACTTAGAACCTTCATTTTCTCCTCCAAATTCAGTGTTGTATATTT
+CCCTCTCTTATTCATACTGAATTTAACTCTGAACCACCAACAGGAGAAAA
+CAAAGGGAAAAGCCTTAATGAATTGGCAAAAAAAAAACCCACATTTTTTA
+AACAAAACTTAGCTGAAAGCCCCAGAAGGCATGGGCATTGTATTGGAGGA
+TAATGGACTGAAGGGGCTAACCATGACTGAAGAGCTAGTCTAGAGGTGGA
+GGTCTTATGCACTCAGAAAGCTGCCAGTTGCAAAGTCCTGTCTGGCTCTT
+GCTCCTGCAAGCCATGAGTGATCATTTTTCAGAATGCCCCCTACCTCTCC
+TCTCTTTTGACAGATACAACAGCCTCAGTCAGGAATGACAGGAATACCTG
+CATACTTTCCCTAACTCAATACCGGAAAACGGACAATATGAAGAGAGGAG
+GGATGGAGCAAGATGTGCCCACAAGACAGGTGTGATAAGTTTCCATAAAA
+ACTGATGCTTCAGAAGAAGGGAGCGTGAAAGACTCAAAGGCAATGACAGA
+GTAATCTTGTGTGTAGCAGAGATGCAATGTGGCTTCTCCCCTTCCAAAAA
+GACCTGATTTTACCTCACTGCCAGAAAAGAGAATGGTGCTCAAATTGCTT
+TGTACATAGTGTTCACTGGGCAGCAGTTCATCTACCTGGATAAGGGCTCC
+GAGCTACAGGGACCCTGACATTGGGATGTATGGAGAGTTGGAATTCAGGA
+ACAGTTGTACCGAATCTTGAAGTGAAGAAGAAAGTAGTTTGTTGTACATA
+TGAATGAAATCCAACTTTTATTGCATTCAATATAGTATTGTCAAGCACCG
+TGCTTTAACTTGAATGTCTCTTGTGTTTGCCAAGGTAATATGTAAGTATG
+TAAATAATTTATTTGTCAGTGGCACTTTACCATTCTCAGATCTTCTTTCT
+TGGGAACATCTGATTTATTCTCAAGTGCTATTTTTCACTGAAACTGTTCT
+CTATTTGAGATATTATCAAGTTTCAGAATCACAGCAATTCTCAGAGATGA
+GCCCAAAAGTTTTACAAATATTTCACCATAGTTAAAAATTTTTAAAGATC
+TGTCCTTTCATTTGTTTTCCTAAATTTACACTATAAGTAACATACTTTTT
+ATATTTGAGATTTTGATTTCTCTTCAGTGTTTATTTTACTTAATTTGAAC
+CAAGACTCAACTTTTCCACAGAAGAAATCTAAAAGGTTTCTCTGCTGCTG
+TTTCTGATCAATTGTTTCTCATAAATCCTACTGGCAAACTCTTCTGTCCC
+TCTAGGCCCTCAAATACTCTTTTCGGGTCCTCCTGGTGCTCCCCAAAGCC
+ATTCCAGGTCCTTAGAAATGTCTTAGTCTAGATTAATTTCCTGGTTCTCA
+GTCCAGATACACAACCTCATGGGAAGAAACAAAAACTGCCACTTTTATCC
+ATTCCAGGTGCTACGAAGAAAGAAAAGTATGTCAGAGAAATAAGGGAAAT
+GGCTGGTATCTCAGTTATTCTTCCTCTTCTTTAGGGCAGAATCTGACTGG
+CCCATTCATTCCTCAACTACATAGAAttctctctctttttttttttgaga
+cagagtcttgctctgtcacccaggctggagtgcgatgccgccatctcggc
+tcactacaacctctgcctcccgggttcaagcaattctcctgcctcagctt
+cctgagtagctgggactacaggtgtgtgccaccacacccggctaattttt
+gtatttttttggtaaagaggatttcactatgttggccaggctggtctcga
+acttctgaactcatgatccgcccgcctcagcctcccaaagtgctgggatt
+acaggcgtgagccaccacacctggccCATAGAATTCTCTTAGGTCTCTCA
+TCTAAAAACCCAGAAGAGTCAGACCACTGGTTTTCCTGTAACATTCATTG
+CAAGAAATGCCAACTATGAGTTATAGAGCATGGAGAAGATTACAAGAGAA
+TATGGTAGTAATTAGGGGGTGGAGCCAATGGCAGGCTACGATCAAGCAAC
+TTTCTAAATGAGGCAACTATAATTAAGGCAGTTAGTAAGTGATAACTCAG
+ACATAAATCTTGGTTTATCTCTTTCACTTATAAATAGAAAAATAAAAAAG
+TATTTGCTAGCCAATAGCAGCACCATTAACTCAAGCTAGTCACCTAGCAA
+AAATATTCAGGCCACTATGACAGTTGTGTAGGTGTCTCAGAATTAATGTA
+TTTGCTTTCAATGCTTCTCAGCTGTGCCGTCGTCtttttttttttttttt
+ttttttgagatggggtctggttctgtcgcccaggctggagtgcagtgaca
+caatctcggctcactgcaacctctgcctccagggttcaggccattctcgt
+gcctcagcctcctaagtagctgggattacaggcacgcaccaccatgcccc
+gctaatttttatatttttagtacagacaaggttttgccatgttggccagg
+ctggtctcgaactcctgacctcaagtgatccacccacctaggcctcccaa
+agtgctgggattacaggtgtaagccactgcgcccagccACAGTCATCATT
+TCTAAAACAGTGCCCAAGCAAGGGGAGGTGAAACCAAAAGGAAAGGCTCA
+AGGAATGTTTGTGGGCTTCAAAGGATAAGCCACTATGGCAGCAAACCTCA
+CACAATGAAAATCACCAGTGCCTCTTATTCACTATTCACAATTTGTGCCT
+TGCTGCCTCTTTTTCCCATGAATCCCTTTTCCCTTTAACCAACTTCCTGT
+GTTATGAATCAGGCCTGTCAATGATATCCAAGGGCACTGCTTAGCACTGC
+TAGCAGAACTTCACTTATTCAACTTAATAAATTCTAATTATATATTCAGC
+ATTGGGCCAGGTGATGAGAATCTTAATGCTGATGGCGCTACTGTCCACTG
+GTTCTGATAGACTGAGAATATTTACTGCTGAAGAAATGAAGTCCCAACCT
+GGCTGAGATTTTAAGGAAATGAACCTACTTAGACACAAATTCAAGTGACT
+TAGGCAGATGCTCATTATTAAATCTGTTTATCTTTCTCTCTCACTTAAAA
+AGGATCAAGATCTATGCCTAAGAGGAGTTACATACCATCCCATCCAAAAG
+CAAAAATAGCATAATGGCCTGGTAATGGCCTCTCATCTTCATTCTCACCT
+TAAACTTACCTTAGATGAACTGCCATAGAAAGCAGCTCAGTCCAAAACGC
+TCAAATGGTGCTCCAGGATTTACTTttttgtattgttttgttttgttttt
+tgcgacggagtctcgctctgtcgcccaggctggaatgcagtggcgtgaac
+tcggctcactgcaagctccgcctcccgggttcacgccattctcctgcctc
+agcctcccgagtagctgggactacaggcgcccaccaccacgcccggctaa
+tttttttttgtattttttagtagagacggggtttcaccatgttagccagg
+atggtctcgatctcctgacctcatgatccgcccgcctcggcctcccaaag
+tgctgggattacaggcgtaagccaccgcgcccggccAGGATTTACTTTCT
+TAAATGCACTCTTTTCATTCCCATTCAAAGGACTCCAGTATAAGTGCCAC
+ATAAACTCGTTTTCTAACTTTTAAAACTCTTCCTCTAAATGCAGCCCAAC
+TCAGTAAAAACGTACCTAAGATCTCACAGTCTAATGTTTCCAGCTTTTAA
+AGCCTTTACTCCTACCCTTCCCTCTGCCTGGAAAGTGTCTCCATTCCCTG
+CTGTGGACAAAATCCCTCAAGGTCTTTTATAATTTCCCCCAACCCCAAAT
+CAACTTGGATTTTCTTGGAGTTCTCACAGCATTCAGTTTATGTCCTATTC
+TTACCCTTGTGTTACTGATATTCACGAAATTGCTCAGTCCTTTCAAGAGA
+TTGCTTAAGGACAAAGACTTCTTACTCAACTCTGCAATATTGGCTACACA
+TAGCTGACTTAATAAATAGTCCCTTGACTGGTATAAGCTGACGTTACAAA
+AACTGGTAATTCCGAAACCACTCATACTGGACTTATTAAATAATCCCTCA
+ACTGGTACAGACTGACATTACAAAAACGGATTAATTCAGAGATCACTGAA
+CACCCAAAACACTCAGATTCTTATAACTATGattcagtaaatatgtgtgg
+aatgcctatcttaccaggtgactatgttaggcgctgcatgagatataaga
+tgaaaacaaggttcccattttcCAgggaagaatactggagtggaaaacgc
+agaggataccacaacaggagagctatttccgattagcggccgccactgct
+gagctatgtgaccctgagcaagtcacttcttaggtctccgtttctctgtc
+aaggagagatagaaaaagaacctatttcacaggTTCAAACCTACCTCAAG
+AAAAAATAGTTGTGGGGAATGCGTCACGAGACCTAGAAAACGGTACAAAA
+CCCTCGGGGGGCCGCTGTTTCTGACCTAGCGAGTGGCCCGACCCGGACAA
+AATGCCTCTTCCTCGAGGAGGCGGCGACGAGCCCAGCAACAGCTCGAGCA
+CGGCCGGCCGGGCCGCGGGAAGCCCGAGAACGCGGCGCGCGCAGCTGGGA
+GGCGACCCTTACCCGGCGAGGCTCCCGGGACCAAACGCCGCCCGACAGCC
+ACGCAGAACAGACGCGGCAGTGCGACGCCTCCCCCACTGGGGACACGAGA
+CAGCGACAGCCACGCGGTGAGCCGGTACAAGGCCCTCTAGGCTTCAGCGG
+GTCTGGATACTCGGTGGCATTAACCCTTCCCTACCGCCGGGGAAGACAGC
+AGTTTCTCTGGCGAGGAAGTAGGCCGGGCTCAGGCGCCTTAGCCAGAGGG
+CGGGCCTGCGCCACCCTCGGAAAGCGTCACTTCCACTTCCGGCCGGCGCT
+CTGGCTCTGTACCTGGACAGGGCTGCGGTAGGCCAGCGGTGGGCTGGCGG
+TTGCGCTCCTCAGATCGGCGGCCTTTCGGGCGGTGGCTTGCGTTTGAGCC
+TCAGAAAGCGAGGAGCGGCCTCCACGGAAGCCAAGCTGGCCGAGGTAACC
+GAGAAGCGGCTTCCCCTATGGCTTCGACCCTGGAGCCGCTGGAGCGGCGG
+CGGCCGCAGGGAGGCAGCCATTTTCCGTAGGCGGTGGCCGCGGCGCTTCC
+GGGCCGCGCGGCTGGAGCCTGAGGCGGGGCCACCGTCGGGCACGAGAAAC
+CATTCTCTCCCCGCTTTTCGCAGCTGTATCCCAGAGGCGCGGCTGAAGCT
+CGCTGGGACACTGCCCGCTTGCCCAGTGCCCACGGGCACGCCTGTCGCAG
+ACACAGGCTGTGGCGAATCCGAGTGCTGGCGGGCAGCAGTGCCTGCAGCT
+GCGCCCGCAGACTCTTTCCCGCCTCCGCCGGCATTTCCGTGTCCGGCCGA
+TGTCATGCGGTCGGTTGAGCCTCAGGGCTAGCAGCTTCTACTGATGCAAA
+AACATAGGAAGTGTCTCTTTGCTTCTGGAACCGGGGTGGGCAGCAAGGAG
+CTGGCCACTTCTTTGAATACCGGTGGCATCCTGGGCAGAATTTCGGTGCC
+GTTTCTGCTGGCTCACTTCAGGAAAAGTGAGGCTCACGGCTCTCCTCAGC
+CCCCCTTAGAAGTCTAAATGACCTTTGGAGAAATACAAAGTCAGCAGAAA
+GTTTCACTTTCATCGTCACCAACTCCTGTTGGAGTTGATATTTCATAAAC
+ATCAGCGACAGAAAGAAAATACGACTTGATATTTTGTAAATAAAATATCC
+TTTTTTACAAGTTGATATTTTGTAAACAGAGGTCAGCTGTAATTTTCTCC
+AGATCAAGTAAGCACAGTTAAAAATTCATATAggcctggcgcggtgtttg
+acgcctgtaatcccagcactttgggaggccaagatgggtggatcacgagg
+tcaggagatcgagaccaccctggccaagatggtgaaaccctgtctctact
+aaaaacacaaaaattagccgggcatggtggcacgcgcctgtaatcccagc
+tagtcgggaggctgaggcaggagaatggcttcaaccggggaggtggaagt
+tgcagtgagctgagatcacgccactgcactccagcctgggtgacagggcg
+agactccatctcaaaaaaaaaaacaaaaTTCGTATAAATCATCTGCATGG
+CACCCTTTATGTGTGTTGCAAAGAATGATGAGCATCTTGTTGCTTACTTG
+GGAGACATTGTCTGAAAATAGGCTACTTTTTTACTTTCTgtagtaccccc
+tccccccactgtatctgggtttcacttacccgctgtcaactgccatccaa
+aaaatattaaatggaaaactccagaaataaacagttcataagttttaaat
+aacttttttttttttttttggagatggaatctcgttttgctgccctggct
+ggagtgccgtggcacagtctgagctcactgcagccttcacctcccgggtt
+caaacaattttcctgcctcagcctcctgggtagctgggactacaggcgcg
+cactaccacacctggctaatttttgtgtttacaataaagaaggtttcacc
+atgttggccaggctggtcttgaagtcctggtctcaggtgatccacccacg
+tcaggcctcccaaagtgctgggattacaggcatgagccacggcgcaccgc
+cagttttaaataactcttactacagtgttttattgttaatctcttattgt
+acctaatttataaattaaggtatcatagctatgtatacatagagaaaata
+gtataatgcagttagatgctgttgggggttttaggtattcacagaatgta
+ctggaacttaccccccttggagaagggatactactgTATTTTGATCTCAC
+CGTCTCAGCTCTTTTGCCAGTATTCCTACAATGGAAAATCTAAAATGTTG
+TTTTTTAAGGTGCCtttatttttagtttttaaattagagacaaagtcttg
+ctctaactcccaggctggagtgcagtgatgaggtcatggctcactgcaac
+cttgaattcctgggctcaggcgactctcccacctcagcctcctgagctag
+aactactggtgtgctctaccatcctggctattttttttttttttcttcaa
+attttgtgttttgtagagacggggtctcgctatgttgctcaggctggtct
+gaaactcctggctcaagtgatcctcccacctcggtctccaaaagtgctgg
+gaatgcaggcatgagccactgcacctggccTAAAATATTTTTAAAGTGAA
+GGCTTCCATCTTCACAAGAGGATGAAGGGTCATAAAAGTTGTACTCCCCT
+TACTAGAGACAGACTGGGATGATCTGTTGAAATTTAAGAGAATCTCAGAA
+TGTTTTCCTAATCTTATTTTCTCCTATTCTTTTCTTATGGGGAAGATGGG
+ATAGGAGGCACACCAGTTAAATCCTTGGAAAATCCCAAAATACCTTTCAG
+CCAGTGGGTGCCAATTTTCTTACCCACCAATCTTTCCTAAATTGTTTTCT
+TTTTTATAAAAAAGACAGTTGTCCACTGACATTTGTGTGTTTTGTGCTGT
+GCTTCAGCTGAATAATAGAAAAGGAGAAAAACAAAGGGCCTGCTAGTTGA
+TTTTGAAGGGAAGACAGGACACCTTTTCTGTTCTTCTTTCTCTCATAAGT
+CGCAAGTGATGAGGTTCATGTGAGTTTCTTATTGATACATACTTTTCTTT
+TTCTTGTCCTCAGTGCTTTTAGGAAGAAGATCCTTTTATTGCTTTTGTAC
+AAGACCAGACAGGATCTCATTTGTTAAACGTGGTACCAATTGGGTGTCTT
+AACACAGGAGCAGAACTTCCTAGAGCAGAATGATGATGGTAGATCTGAAA
+GTGGCTGCGTACTTGGACCCTCAGATCAGGGCTTTGTGGGAGACCAAGGG
+GCCTGCAAGAGAGAGCTCCGGTCAGAGTAAAAAATCTCCTCAAATGGACT
+GTCTCGATCCTAAGAGCTCTTGCTGGCACTTCCGGAATTTCACCTATGAT
+GAAGCAGGTGGACCCCGTGAGGCTGTCAGCAAACTTCAAGAATTATGTCA
+TCTATGGCTGAAGCCAGAGATCCACTCAAAAGAGCAGATACTGGAACTGC
+TGGTGCTGGAGCAGTTCCTGACTATTCTGCCCAGGGAGACACAGACCCAG
+ATGCAGAAGCACCATCCACAGAGCATTGAGGAGGCTGTGGCTCTGGTAGA
+ACACTTGCAGAGGGAATCTGGTCAAACATGGAATGGGGTGAGAAGAAAGA
+TTCCTGACATGTACAGTGAAATAGGATGCAGGTGGATATAGTAGAGATGG
+TGGCAGTTAGTTGAGAAATTAGATGGATTAGGTAGGTCATTGTTTGGTTT
+TTTTTTTAAGGACAGTTAAGGTGGGACTTGAAACTACAGGCCCACAGAAA
+AGTTCACAGGTTTCAGAGATTGTGGTAGATACTTCCCTGGCCTTAGAGAA
+AGAGAGTTGCTTTTGCCCTCTTTGGAGCCAGGGTGAATTGAGGGTGTTGG
+GCCTAGTCTGGCTTGGCCAAGGAGACAGGACTTAAGTACTTAGAAACAGA
+ATAAAAGGTAATAAAGAGTCAGGGAggctggatgcagtggctcacacctg
+taatctcagcactttaggaggctgaggcgggtagatcacctgaggtcagg
+agttcaagaccagcctggacagcatggtggaaccctctctctacaaaaat
+aaacaaattagctgggcatgatgaccggtgcctgtaatcccggctatcct
+cgaggctgaggagggagaatcatttgaacctgggaggttgcagtgagccg
+agatcgcaccattgcactccagcctgggcaacacagcaagactccatctc
+acaaaaaaaaaaaaaacaaaaaaaacaaaaaaaaaaCGggccgggtgcag
+tgactcacacctgtaattccagcactttgagaggccaaggcagacagatc
+ccctgagcccagcctgggcaacatggtgaaaccccgtctctacaaaaaac
+atgaaaattagccaggcatggtggcacacacctgtggtcccagttacttg
+ggaggctgagtcaggagaatcacctgagcccaggaggtggaggttgcagt
+gagctgagatggcaccattgcactcccttgggtgacagagtgagaacctg
+tcaaaaaaaaaaaaaaaaGGCAGATCCACAAGGAGAACACAGGAAAACAA
+GGACACTTAAAGAAAAGGAGAAATTggccaggttcggtggctcatgccta
+tatttcgaacactttagggggtcgcggtgggaggactgcttgagaccagc
+ctggggaacatagtgtgaccttgttgctatgaaaaaaaaaaagaaaataa
+gccaggctgatggcacatgcctctagtcccagcttcacaagaggttgagg
diff --git a/blat/test/makefile b/blat/test/makefile
new file mode 100644
index 0000000..3afc84a
--- /dev/null
+++ b/blat/test/makefile
@@ -0,0 +1,20 @@
+all:  tThrowback tIntronMax
+
+tThrowback:
+	blat -verbose=0 throwback/target1.fa throwback/query1.fa throwback/test.psl
+	pslCheck -verbose=0 throwback/test.psl
+	blat -verbose=0 v29skips/ex1_database.fa v29skips/ex1_query.fa v29skips/ex1.psl
+	diff v29skips/ex1_reference.psl v29skips/ex1.psl
+	blat -verbose=0 v29skips/ex2_database.fa v29skips/ex2_query.fa v29skips/ex2.psl
+	diff v29skips/ex2_reference.psl v29skips/ex2.psl
+
+tIntronMax:
+	mkdir -p intron50k/out
+	blat -verbose=0 intron50k/target.fa intron50k/query.fa intron50k/out/test1.psl -minScore=190
+	diff intron50k/expected/test1.psl intron50k/out/test1.psl
+	blat -verbose=0 intron50k/target.fa intron50k/query.fa intron50k/out/test2.psl -minScore=190 -maxIntron=40000
+	diff intron50k/expected/test2.psl intron50k/out/test2.psl
+	blat -verbose=0 intron50k/target.fa intron50k/query.fa intron50k/out/test3.psl -minScore=190 -maxIntron=5000
+	diff intron50k/expected/test3.psl intron50k/out/test3.psl
+	rm -rf intron50k/out
+
diff --git a/blat/test/missBlastOut/C57_0005_A6_BB_5.fa b/blat/test/missBlastOut/C57_0005_A6_BB_5.fa
new file mode 100644
index 0000000..d56c9a6
--- /dev/null
+++ b/blat/test/missBlastOut/C57_0005_A6_BB_5.fa
@@ -0,0 +1,17 @@
+>C57_0005_A6_BB_5
+AATCCGATTGNGGTCTCCTGTTCCTTGGGAGGGTCTCCTCTGAGTGATTGCTTTGGACCA
+GACTACGTGTGTCTCTGTAAACACACAGATCTGTCGAGGTCGGATCGGACGGTATCGGAT
+TAGTCCAATTTATNAAAGACAGGANATCAGTGGNCCAGGNGTCATAGTTTTTGNCTCNGG
+NGGGGGANCGNTTTNGNCNGGTGNGCCNTTTNGGNTTGNCTNGGCGTCGGNCGGNGGCGN
+GGNCGTGGGTTGTGNNGTTTGNGGNTGGGCNNNGTGGGCCGNNTGNNNCNGNTGTANNTG
+GNTTCNGGNCNGCNNCGTTNGNGNCGGCCNGNCNGTNGTTNTTTCNNGNNTCCNTGTGGN
+GGTTCGGNGGCGGNCGTCTNTGNCGCGGNTCTTTNCNNTTGNTNNTGGCCCCGCGCGCGN
+TTNTTCNCGGGCNCNNNNNNNTGNNCGCGCGTGGNGGTTGAATCNTGGNTNTNTNGTCNG
+NTNTNGGCGGTNTNNCTNGGCGNCCCGGGNGNNNGTGGCNGGGGNNGCNGGGGGNNTCGA
+CGGGAGTGCCGCTCCGTCCCNNGCTTTCGGNNNGCGGCNGGNNNTTGGGGTTNCGGNNCC
+CGGCTANGGTTGNGCGTCTANTTCGNNGCNTTNGCCCNCCNNNGTTATTCNGNTTGGGGC
+GGCGNGNNNCGNCAGGNATNGGCNGNGNNGNTGTGGCGGNTNNGCAGNGNTTTTNCGGNC
+GCGGNGGCNTNGGGGGTTCCCGTTNCCTCATTTCCCNATTNGTCCNGCTNGGGTGTGGCA
+TGTGCGTGTTGNGGNNTTCNGGTGTGGTNGGTNCNGGNNTNCNGGNNCTGNGGGANGCCG
+TGGNNGGGGAGNNCGNCNATTNCNGCCTCGCNCNNCTCNGCNNGANGTGTGCNTTNCTTT
+NCGNGNGCGCGCGCGTGNGNGNGCGGGNGG 
diff --git a/blat/test/missBlastOut/genome.lst b/blat/test/missBlastOut/genome.lst
new file mode 100644
index 0000000..b532322
--- /dev/null
+++ b/blat/test/missBlastOut/genome.lst
@@ -0,0 +1,2 @@
+/cluster/data/mm6/nib/chr1.nib
+/cluster/data/mm6/nib/chr10.nib
diff --git a/blat/test/missBlastOut/out.blast b/blat/test/missBlastOut/out.blast
new file mode 100644
index 0000000..d11df6f
--- /dev/null
+++ b/blat/test/missBlastOut/out.blast
@@ -0,0 +1,76 @@
+BLASTN 2.2.11 [blat]
+
+Reference:  Kent, WJ. (2002) BLAT - The BLAST-like alignment tool
+
+Query= C57_0005_A6_BB_5
+         (930 letters)
+
+Database: blat15:17779 
+           23 sequences; 3,000,000,000 total letters
+
+Searching.done
+                                                                 Score    E
+Sequences producing significant alignments:                      (bits) Value
+
+chr10                                                                  82   7e-16
+chr1                                                                   65   6e-11
+chrUn_random                                                           60   2e-09
+
+
+
+>chr10 
+          Length = 130291745
+
+ Score = 82 bits (211), Expect = 7e-16
+ Identities = 42/42 (100%)
+ Strand = Minus / Plus
+
+Query: 92       agatctgtgtgtttacagagacacacgtagtctggtccaaag 51
+                ||||||||||||||||||||||||||||||||||||||||||
+Sbjct: 18438061 agatctgtgtgtttacagagacacacgtagtctggtccaaag 18438102
+
+
+
+>chr1 
+          Length = 195109612
+
+ Score = 65 bits (169), Expect = 6e-11
+ Identities = 45/51 (88%)
+ Strand = Plus / Plus
+
+Query: 2         atccgatt-gnggtctc-ctgttccttgggagggtctcctctgagtgattg 50
+                 |||||| | | |||||| ||||||||||||||||||||||| |||| ||||
+Sbjct: 171418581 atccgagtcgtggtctcgctgttccttgggagggtctcctcagagtaattg 171418631
+
+
+ Score = 65 bits (169), Expect = 6e-11
+ Identities = 45/51 (88%)
+ Strand = Plus / Plus
+
+Query: 2         atccgatt-gnggtctc-ctgttccttgggagggtctcctctgagtgattg 50
+                 |||||| | | |||||| ||||||||||||||||||||||| |||| ||||
+Sbjct: 171410442 atccgagtcgtggtctcgctgttccttgggagggtctcctcagagtaattg 171410492
+
+
+ Score = 60 bits (156), Expect = 2e-09
+ Identities = 32/33 (97%)
+ Strand = Plus / Plus
+
+Query: 18        ctgttccttgggagggtctcctctgagtgattg 50
+                 ||||||||||||||||||||||| |||||||||
+Sbjct: 170877574 ctgttccttgggagggtctcctcagagtgattg 170877606
+
+
+
+>chrUn_random 
+          Length = 81221341
+
+ Score = 60 bits (156), Expect = 2e-09
+ Identities = 32/33 (97%)
+ Strand = Minus / Plus
+
+Query: 50       caatcactcagaggagaccctcccaaggaacag 18
+                ||||||||| |||||||||||||||||||||||
+Sbjct: 54120615 caatcactctgaggagaccctcccaaggaacag 54120647
+
+  Database: blat15:17779
diff --git a/blat/test/missBlastOut/out.psl b/blat/test/missBlastOut/out.psl
new file mode 100644
index 0000000..1dc0f88
--- /dev/null
+++ b/blat/test/missBlastOut/out.psl
@@ -0,0 +1,10 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+45	3	0	1	0	0	2	2	+	C57_0005_A6_BB_5	930	1	50	chr1	195109612	171418580	171418631	3	8,8,33,	1,9,17,	171418580,171418589,171418598,
+45	3	0	1	0	0	2	2	+	C57_0005_A6_BB_5	930	1	50	chr1	195109612	171410441	171410492	3	8,8,33,	1,9,17,	171410441,171410450,171410459,
+32	1	0	0	0	0	0	0	+	C57_0005_A6_BB_5	930	17	50	chr1	195109612	170877573	170877606	1	33,	17,	170877573,
+42	0	0	0	0	0	0	0	-	C57_0005_A6_BB_5	930	50	92	chr10	130291745	18438060	18438102	1	42,	838,	18438060,
+32	1	0	0	0	0	0	0	-	C57_0005_A6_BB_5	930	17	50	chrUn_random	81221341	54120614	54120647	1	33,	880,	54120614,
diff --git a/blat/test/noHit19/noHit19.fa b/blat/test/noHit19/noHit19.fa
new file mode 100644
index 0000000..7f3527b
--- /dev/null
+++ b/blat/test/noHit19/noHit19.fa
@@ -0,0 +1,69 @@
+>BC018783.1 Homo sapiens zinc finger protein 480
+GTGGAGTGAAGGTCACGCCGCGGCGCGATTGACTTCTAAAGAGTCATGCTGTGATGAAAAAGCCCAGAAG
+AGAAGGAAGAGGAAAGCAAAGGAGTCAGGGATGGCTCTTCCTCAGGGACACTTAACATTCAGGGACGTGG
+CCATAGAATTCTCTCAGGCGGAGTGGAAATGCCTGGACCCTGCACAGAGGGCTTTATACAAGGATGTGAT
+GTTGGAGAACTACAGGAACCTGGTCTCCCTGGGAATCTCTCTTCCTGACCTGAATATTAACTCCATGTTG
+GAGCAAAGGAGGGAGCCCTGGTCTGGTGAGAGTGAAGTGAAAATAGCAAAAAATTCAGATGGGAGGGAGT
+GCATCAAAGGTGTGAACACAGGGAGCAGCTATGCATTGGGAAGCAATGCAGAAGACAAACCAATTAAAAA
+ACAACTTGGAGTATCCTTTCACTTACATCTGTCTGAACTGGAGCTATTTCCAGATGAAAGGGTAATAAAT
+GGATGTAATCAAGTTGAAAACTTTATCAACCACAGTTCCTCTGTTTCCTGTCTTCAAGAAATGTCTTCCA
+GTGTCAAAACCCCCATTTTTAATAGGAATGATTTTGATGATTCTTCATTTCTCCCACAAGAACAGAAAGT
+ACACCTTAGAGAAAAACCTTATGAATGTAATGAGCATAGCAAAGTCTTTAGAGTATCTTCCAGCCTTACT
+AAACATCAAGTAATCCATACTGTAGAGAAACCTTACAAATGTAATTCATGCGGCAAGGTCTTTAGTCGCA
+ATTCGCACCTTGCAGAACATTGTAGAATTCATACTGGAGAGAAACCTTACAAATGTAATGTCTGTGGCAA
+GGTTTTTAGTTACAATTCAAACTTTGCACGACATCAAAGAATTCATACCAGAGAGAAGCCGTATGAATGT
+AATGAATGTGGTAAAGTCTTCAGTAATAATTCTTACCTTGCACGACATCAAAGAATTCATGCTGAAGAGA
+AACCTTACAAATGTAATGAATGTGGTAAAGGCTTCAGTCATAAGTCATCTCTAGCAAATCATTGGAGAAT
+TTATACTGGAGAGAAGCCTTACAAATGTGATGAATGTGGCAAGGCCTTCTATAGGATTGCGCTCCTTGTA
+CGACATCAGAAAATTCATACTGGAGAGAAACCTTACAAATGTAATGAATGTGGAAAGGTCTTTATTCAAA
+ATTCGCACCTAGCACAACATTGGAGAATTCATACAGGAGAGAAACCTTACAAATGTAATGAATGTGGAAA
+AGTATTTAATCAACTTTCAAATCTTGCACGACATCGAAGAATTCATACTGGAGAGAAGCCTTACAAATGT
+AATGAATGTGGTAAAGCATTTAGTGAGTATTCAGGCCTTTCAGCCCATCTTGTAATCCACACTGGAGAGA
+AGCCTTACAAATGTAGTGAATGTGGCAAGGCATTCAGACACAAGTTATCACTAACCAATCATCAGAGAAT
+CCATACTGGAGAAAGACCTTACAAATGTAATGAATGTGGCAAGGTCTTCAATCGAATTGCACACCTTGCA
+CGACATCGGAAAATTCATACTGGAGAGAAACCTTACAAATGTAATGAGTGTGGCAAGGCCTTTAGTCGCA
+TTTCATACCTAGCACAACATTGGACAATTCATATGGGATAGAAACTACAAATGCAACAAATGCGTCAAAG
+AATTTAGTGTGCACTCAAGCCTTACTACCCATCTTTTATTCCATACTGCAAAGAAATTTTGCAAATGTAA
+AGAATATGACAAGGTCTTCAAACACAAGTTTTTCTAATAACTCATTAGAGAATTTATACTGGAGAGACTT
+CACAATTATAATAAATGTGTGGAAAAGTCTTCAAAAAAATTTCACACCTTGCAAAAGGAGATCTAAAAAA
+CACAATCAGAAATGACAAAGGGGACATTACCACCAACCCCACAGAAATACGAAAAACCCTCAAAGATTAC
+TATAAACACCTGTATGCACACAAACTAGAAAACCTAGAAAAAATTAATAAATTCCTTGAAAGATATAACC
+CCCCAAGATTGAACCAAGAAGAAATTGCATCCCTGAACAGACCAATAATGAGTTCCAAAATTTAATCACT
+AATTAAAAATCTATCAAACAAAACTCTGGACCAGACAGATTTATAGTTGAAGCCTACGAGATGTATAAAG
+AAAAGCTGTTACCAATCTTACTGAAACTGTTCAAAAACATGGATGCAGAGGGACTCCTCCCTATCTGATT
+CTATGAGGCCAGCATCATTCTAATACCAAAACCTGACAGGCACAATGAAAAAAGAAAACTTCAGGCTGGT
+ACTCCTGACGAATATAGGTGCCAAAATCCTCAGCAAAATACTAGTAAACCAAATCCATCTGCACATCAAA
+AAGCTAATCCAACATTATCAAGCAGGCTTTAGTGTTGGGCTGCAAGGTTGGTTCAGTATACACAAATCAA
+TAAATGTGATTTATCACATACACAGAACTAAAAACAAAAACCACATGACCATGATCATCTCTTTAGATGC
+AGAAAGGTTTTTAATAAAATTCAACATCCCTTCATTTTAAAAACCCTCAACAAATTACACATTGAGGGAA
+CATACTTCAATAAGAACCATCTATGCTGGACTCACAGCCAAATTAATACTGAACAAGCAAAAGCTGGAAG
+CATTCCCCTTGAGAACTGGAAAATGACAGGGATGACCACTCTCACCACTCCGATTCAACATAGTACTGGA
+AGTCCTAAGCTTAGTGATCAGGCAAGATAAAGATATGAAAGGCATATATAAATAGGAAGAGGGGAAGTCA
+GTTTCTCTTGCAGAAGATATAATTCTGTATTTAGAAAACCTGTTGTCTCTGCCCAAAGGCTCCTAGATCT
+GATAAACAACTTCAAAAAAGTTTCAGGATACAAAATCTGTGTACAAAAATTAGTTGCATTTCTATACACC
+AGTAATGTCCAAGCTATGAACCAAATCAAGAATGGAATCCCATTCACAGTAGCCACAAAAAGTATAAAAT
+ACCTAGGAATACAGCCAACCAGGTAAGTGAAAGATTTCTACAATGAGAATTACAAAGCAGTGCACAAAGA
+AATCAGAAACAATAAAAATTGAAAAATATCTCATGCTCATGGATAGGAAGAATCAGTATTGTTAAAATAC
+TGCCCAAAGCAATTTACAGAGCCAATGCTATTTCTATCAAACTACCAATGGCATTTTTCACAGAATCAGA
+AGAAAACATTCTGAAATTTATTTGGAACCAGAAAAGCCCAACCTAAATAGCAAAAGCAATCCTAAGCAAA
+AAGAGCAATGTTTGAGGTATCACACTACCCAACTTTAAACCATACTACAAGGCTACAGCAACTAAAACAG
+CATGGTACTGGTATAAAAAAAGACACATAGATCAATGGAATAGGTAAGAGAACCCAGAAATAAAGGCATA
+TACCTACAACCATGTGATCCTCAACAAAACTGACAAGCAATGAAGTAAGAACTTCATTCAATAAGTGGTG
+CTGGCATAACTGGCTAGCCATATGCAGGATATTGAAACTGGACCCCTATCCTTCACGATATACAAAAATC
+AACTCAAGATGGATTAAAGACTTAAATATAAAACCTAAAAGTATTAAATTCCTAGAAGAAAACCCAGGAA
+ATGCCATTCTGGACATAAGTGCTGGAAAAGACTTAATGATGAACACCCCAAAGCAATTGCAACAAAAACA
+AAAATTGACAAGTGGGACCTAATTAAACTAAATAACTTCTGCACAGCAAAAGAAGCTATTTGCAGACTAC
+AGAATGGGAGAAAATGTTTACAAACTGCATCTGACAAAGATCTAATCCAGAATCTATAAAGAACTCAAAC
+AAATCAACAATGAGAAAAACAACCCCATTAAAAACTGGGCAAAGGCCATGAATAGACCTTTCTCAAAAGA
+ATACATACATGTGGCAATAAGCATATGAAAAAAATGGTTAATATCGCTAATCATTAAGGAAATGCAATCA
+AAGCCACAATGAGATACCATCTCAGACCTGTCTGAATGGGTATTATCAGAATGGGTATTATTAAAAAATC
+AAAACATAGATGCTAGTGAGGCTGCAGAGAAAAGCAAATACTTATACACTGCTGGTGGGAATGTAAATTA
+ATTCAGCCATTGTGGAAAGCACTGCAGCGATTTCTCAAAGACATAAAAGCACATAGCATTCAACCCAGCA
+TCCCATTACTGGGTGTATACCTAAAGGAATATAATCATTCCACCATAAAGACAAACACTTGTATGTTCAT
+TGCAGCACTATTCTCAATAGCAAAGATGTGGAATCAACGTAAATGCCCATCAGCAGTAGACCAGATAAAG
+AAAATTTGGTACATATACACCATGGAATACTATGCAGCCATAAAAAAGAACAAGACTGTGTCCTTTACAG
+CAACATAGATGGAGCTGAGGCTCTTATCCTAAGTGAATTAATGCAGGAACAGAAAATGAAATATCCCATG
+TTCTCACTTATAAGTGGGAGCTAAACATTGATTACACATGGACTCAAAGAAGGGAACAGTAGACACGGGC
+TTATGGGTGGAGGTTGGGAAGAGGATGAAGATTGAATAACTGCCTGTTGGGTACTATGCTGATTACCTGG
+GGACAAAATTAACTGTACACCAAACTCCTGCAACATGCAGTTGACCCATGTACACATACTCCTTGAACCT
+AAAATAAAACATGAAAAAAAGCAAAAAAAAAAAAAAAAAAAA
diff --git a/blat/test/noHit19/noHit19.psl b/blat/test/noHit19/noHit19.psl
new file mode 100644
index 0000000..8813a4c
--- /dev/null
+++ b/blat/test/noHit19/noHit19.psl
@@ -0,0 +1,6 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+4687	2	0	0	0	0	4	20840	+	gi|17511870|gb|BC018783.1|	4732	26	4715	chr19	63811651	57495458	57520987	5	27,62,127,129,4344,	26,53,115,242,371,	57495458,57495487,57509217,57510898,57516643,
diff --git a/blat/test/small/expected.psl b/blat/test/small/expected.psl
new file mode 100644
index 0000000..9c4f4a5
--- /dev/null
+++ b/blat/test/small/expected.psl
@@ -0,0 +1,6 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+25	0	0	0	0	0	0	0	+	gnf1h07002_at_5	25	0	25	OR10A5	951	637	662	1	25,	0,	637,
diff --git a/blat/test/small/query.fa b/blat/test/small/query.fa
new file mode 100644
index 0000000..4a1f5af
--- /dev/null
+++ b/blat/test/small/query.fa
@@ -0,0 +1,2 @@
+>gnf1h07002_at_5
+TGCTGATCTTGTGTTCCTATACTCG
diff --git a/blat/test/small/target.fa b/blat/test/small/target.fa
new file mode 100644
index 0000000..5d523cc
--- /dev/null
+++ b/blat/test/small/target.fa
@@ -0,0 +1,21 @@
+>OR10A5 (HORDE #40:269)
+ATGGCTATAGGAAACTGGACAGAAATAAGTGAATTTATCCTCATGAGCTT
+CTCTTCCCTACCTACTGAAATACAGTCATTGCTCTTCCTGACATTTCTAA
+CTATCTATTTGGTTACTCTGAAGGGAAACAGCCTCATCATTCTGGTTACC
+CTAGCTGACCCCATGCTACACAGCCCCATGTACTTCTTCCTCAGAAACTT
+ATCTTTCCTGGAGATTGGCTTCAACCTAGTCATTGTGCCCAAAATGCTGG
+GGACCCTGCTTGCCCAGGACACAACCATCTCCTTCCTTGGCTGTGCCACT
+CAGATGTATTTCTTCTTCTTCTTTGGGGTAGCTGAATGCTTCCTCCTGGC
+TACCATGGCATATGACCGCTATGTGGCCATCTGCAGTCCCTTGCACTACC
+CAGTCATCATGAACCAAAGGACACGGGCCAAACTGGCTGCTGCTTCCTGG
+TTCCCAGGCTTTCCTGTAGCTACTGTGCAGACCACATGGCTCTTCAGTTT
+TCCATTCTGTGGCACCAACAAGGTGAACCACTTCTTCTGTGACAGCCCGC
+CTGTGCTGAAGCTGGTCTGTGCAGACACAGCACTGTTTGAGATCTACGCC
+ATCGTCGGAACCATTCTGGTGGTCATGATCCCCTGCTTGCTGATCTTGTG
+TTCCTATACTCGCATTGCTGCTGCTATCCTCAAGATCCCATCAGCTAAAG
+GGAAGCATAAAGCCTTCTCTACGTGCTCCTCACACCTCCTTGTTGTCTCT
+CTTTTCTATATATCTTCTAGCCTCACCTACTTCTGGCCTAAATCAAATAA
+TTCTCCTGAGAGCAAGAAGTTGTTATCATTATCCTACACTGTTGTGACTC
+CCATGTTGAACCCCATTATCTACAGCTTGAGAAATAGCGAGGTGAAGAAT
+GCCCTCAGCAGGACCTTCCACAAGGTCCTAGCCCTCAGAAACTGTATCCC
+A
diff --git a/blat/test/throwback/.cvsignore b/blat/test/throwback/.cvsignore
new file mode 100644
index 0000000..facec5d
--- /dev/null
+++ b/blat/test/throwback/.cvsignore
@@ -0,0 +1 @@
+test.psl
diff --git a/blat/test/throwback/query1.fa b/blat/test/throwback/query1.fa
new file mode 100644
index 0000000..3e8452d
--- /dev/null
+++ b/blat/test/throwback/query1.fa
@@ -0,0 +1,37 @@
+>A530054K11
+GTTCGTCATTAGAAAGGGCCATCGGACTCGAACTTCCTTATTCTTCCTTCAAACTTCACT
+CCTCAAATGTATGCAGTTGTCCTGCTCAGCGCTGCATCTGGATTTCTGAGATGGAGTTCG
+GTGCAGGGACCAGCGCCTTCTTTCAGGAAATGCTGTCATTCAGGGATGTGGCCATTGATT
+TCTCTGCAGAGGAGTGGGAATGCCTGGAGCCTGCTCAGTGGAATCTGTACAGGGACGTGA
+TGCTCGAGAACTACAGCAACCTTGTGTTCCTGGGTCTTGCTTCGTGTAAGCCACATCTGA
+TCACATGTCTGGAGCAAATACAAGAGCCTTCAGATGTGAAAAGAGGAGCAGCTACCTCTA
+TGCTCCGGGGAGAAAAATGTTATACGTGCAAAGAGTGTGGCAAAGTTTTTGAGTGGACCA
+AAGTGTTCCAAAATCATGAGATGCTTTATATAGGAATGAATCCCAACAAGTGTGAAGAAT
+GTGCCAGGTCCTTCCATAGTCCATCATTAAGTTCTGAAGAGAACAGAATTCATACAGGAG
+AAAAACCTTACAAATGTGAAGTTTGTGGCAAAGCCTTCTGCATTCCATTATTACTTTCTA
+AACACAAGAGAGTTCATACAGGAGAGAATCTCTACAAGTGTGAAGTGTGTGGCAAGGCCT
+TCCAACATCCATCAAGACTTTCCAGACATAAGAAGATTCATTCAGAAGAGAAACCATACA
+AGTGTGAAGTATGTGGAAAGGCCTTCCACTTTCCATCATTACTTTTGGTACACAAGAGAG
+TTCATACAGGAGAGAAACCATACAAATGTGAAATATGTGACAAAGCCTTCCATTATCCAT
+CAATACTCTCTAAACACAAGCGAATTCATACAGGAGAGAAACCATACAAATGTGAAGAAT
+GTGGCAAGGCCTTCCACATTTCATCATTTCTTTCTAAACACAAAATAATTCATAGAGGAG
+AAAAACCCTACAAGTGTGAGGTATGTGGCAAGGCCTTCCATTATCCATCAAGACTTTCCA
+ACCATAAGAAAATCCATTCAGGAGAGAAACCATTCAAGTGTGAAGTATGTGGGAAGGCCT
+TCCGCATTTTATCACTCCTTTCTAAGCACAAGATAATTCATACAGAAGAGAATCCTTACA
+AGTGTGAAGTATGTGGCAAGGCTTTCGATTATCCCTCAAGACTTTCTACCCATGCAAAAA
+TGCATACAGGAGAGAAACCATACAAGTGTGAAGTATGTCAAAAGGCTTTTCGTTCTCTGT
+CATCACTTTCTAAACACAAGAGAATTCATACAGAAGATAATTATTATAACAATGAATTAT
+GTGGCAAGGCCTTCATTTATCCTTCAAGACTCTCTAAACATAAGAGAATTTGTGCAGGAG
+AGAAGCCCTACAAGTGTGAAGTATGTGGCAAGGGCCATCCATGTTTCATCACTGCTTTCT
+AAACACAGGACAATTCATACAGGAGAAAAAACTCTATAAGTGTGAAGTATGTGGGAAGGC
+CTTTTATTATCCATCAAGACTTTCCAACCATAAGAAAATTCATACAGGAGAGAAACCATT
+CCAGTGTGAAGTATGTGGGAAGGCCTTCTGTTTTCCTTCATCACTATCTAAACACAAGAG
+AATTCACACAGGAGAGAAACCATACAAATGTAAAGAGTGTGGAAAGGCCTTCCGCTCTCT
+GTCCTCACTTTCTAAACACAAGGGAATTCACACAGGAGAGAAACCCTACAAGTGTGAAGA
+ATGTGGCAAGGCCTTCCATTATCCATCATTACTTTCTAAACACAAGATAATTCATACAGA
+AGAAAAACCTTACAAGTGTGACGTATGTGGCCAGGCATTCCATGTTCCATCAAAACTTTC
+TCATCACAAGATAATTCATACAGGAGAAAAACCCTACAAGTGTGAAGTGTGTGGCAAGGC
+CCTTCTGCATTCCATTATTACTTTCTAAACACAAGAGAGTTCATACAGGAGAGAATCCCT
+ATAACAGTCAAGTATGTAGCAAGGCCTTCGTTTATCCTTCAAAACTTTCTAAGCATAAGA
+AAGTTCGTAC
+
diff --git a/blat/test/throwback/target1.fa b/blat/test/throwback/target1.fa
new file mode 100644
index 0000000..4b5ef81
--- /dev/null
+++ b/blat/test/throwback/target1.fa
@@ -0,0 +1,2590 @@
+>/cluster/data/mm4/nib/chr13.nib:65483152-65612585
+ggccttgccacacacttcacactggtacggtttttctcctgtatgaattc
+tcttgtgtttagaaagaaatgatggataatagaaagccttcccacaatct
+tcacacttgtagggtttttctccagtatgaattcccttgtgtactaatag
+taatgatgcaatgtggaaggcctttccacatacatcacacttgtacggtt
+tctctcttgtatgaattttcttatgtttagaaagtcttgatggataatcg
+aaggccttcccacatacatcacaattgtatggtttctctcttttataaat
+tttcttatgtttaggaagtcttgaaggataaacaaagaacttgctacata
+cctcactgttatagtgattctcacctgtatgaattatcttgtgtttagaa
+agtaataatggaatgcagaaggtttttccacaaatctcacaactgtaggc
+tttttcaactttatgaattctcttgtgtttagaaagtgatgatggagaac
+agaaggcctttccacacacttcacacttgtatggtttctctccagtatgc
+atttttgtatggctaaaaagtcttgatggataatggaaggccttgtcaca
+cacttcacacttgtagggtttttttcctgtatgaataatcttgtgtttag
+aaagtagtgatgaataatggaaggccttgccacatacttcacacttgtag
+ggtttttctcctgtatgaattatcttgtgatgagaaagttttgatggaac
+atgaaatgcctggtcacatatgtcacacttatagggtttttctcctgtat
+gaattatcttgtgtttagaaagtaatgatggataatggaaggccttgcca
+caaacttcacacttgtagggtttttctcccgtatgaattttcttgtgtgc
+agatagtgatgatggaaatcggaaggccttcccacattctttacacttgt
+atggtttctctcctgtgtgaattctcttgtgtttagatagtgatggtgga
+aaacagaacgcctttccacatacttcacacttgtatggcttttctcctgt
+atgaattctcttatgcgtggaaagtcttgatggataatagaaggccttcc
+cacatacttcacacttatagagtttttctcctgtatgaattgtcctgtgt
+ttagaaagcagtgatgaaacatggaaggccttgccacatacttcacattt
+gtagggcttctctcctctacaaattttcttatgtttagaaagtcttgaag
+gataaacgaaggcattgctacataattcactgttataataattatctccc
+atatgaattctcctgtgtttagaaagtgatgacagagaacggaaagcctt
+ttcacatacttcacacttgtatggtttctctcctgtatgcatttttgcat
+gggtagaaagtcttgagggataatcgaaagccttgccacatacttcacac
+ttgtaaggattctcttctgtatgaattatcttgtgcttagaaaggagtga
+taaaatgcggaaggccttcccacatatttcacacttgtatggtttctcta
+ctgaatggattttcttatggttggaaagtcttgatggataatggaaggcc
+ttgccacatacctcacacttgtagggtttttctcctctatgaattatttt
+gtgtttagaaagaaatgatgaaatgtggaaggccttgccacattcttcac
+acttgtatggtttctctcctgtatgaattcgcttgtgtttagagagtatt
+gatggataatgaaaggccttgccacatacttcacacttgtatggtttttc
+tcctgtatgaactctcttgtgtaccaaaagtaatgatggaaagtggaagg
+cttttccacatacttcacacttgtatggtttctcttctgaatgaatcttc
+ttatgtctggaaagtcttgatggatgttggaaggccttgccacacacttc
+acacttgtagagattctctcctttatgaattatcttgtgtttagaaagta
+ataatggaatgcagaaggccttgccacaaacttcacatttgtaaggtttt
+tctcctgcatgaattgtgctctcttcagaacttaatgatggaatatggaa
+ggacttggcacgttcttcactcctgtagggcttcacttctaagtcaatta
+tctggtgattttgaaacactttggaccactcaaaaacttttccatattct
+ctgcattctgtggagaaacgattgagaaattaataaaagcagagtaaaat
+tctgtaaatttataatgtttctctttaaaaaccaacatttctcacttgtc
+ttgtcttacttgcacttgtctttataaatgataagctacattcatttttt
+tacacctgtattcaatgaagcctaatttaaaacagaagtggaaatcaagt
+agcctcccactgacaaaagaagaccatgacaacacagaaatggaaacaag
+ggaatgttaatcaaagtcaaatatgaaacaaaaacataaaattaacaaag
+aaaacccattatgttaacacaaatcagccccttacacaaatacagaaatt
+ttatgactagataaaagcaaagtataaaatagtctaactttgaaaacacc
+caaataaacaatatttctacatattttatatatatatatatatgagtatg
+atatacatacatgcattacaattttgtttcaaagttttgaaaaataaatt
+tcagtggttcaagaaagaagtttatgcatatcgttaggcttggtgggttt
+gcgcactatgtaaagatttttctgcctggtatctacttgccatccataca
+tggtactgtaatatttattctaagaatttcctttatcaagtttgtgtaaa
+gtttgtttccatgttattatctaacttgtcaataaaactgatcagctaat
+agaccagctctagagaagaaagagttagacatctgccagcccagggaaga
+agagacagagggagggcagggtgtggggtggaggatagggaaggaaagga
+gtcacttccagagagccatcaggtaaagacacctgaagcccagaaagcca
+gatcagtaacaaaaatgtaagtatcctgattattttgaggtagccagatt
+aagttagaagattagaattgatcattaactacccagtgattgtcttgtga
+atcttataaaaagtttctgtctcattcattttggagctagccagaaatag
+agacaaattttcacttttaaaaatgaatgtccatatatcttatataaaaa
+aaaaaacatccaagttaaagactacttagaaataacagagctttggctgt
+cctggagaacacaagttaatctaatggtggaaggaaacaaagcttatgag
+attcaaagcatccttaacattagataatttcctttcaaagaaaaagacag
+aaaaatatagctttaaaagatgatttttaccacaatactgtgtctcaatg
+gctttatattagatcttagaatttcccactctgttctctgatcccctcct
+cctgacacacctgggagcatagaggtagctgctcctcttttcacatctga
+aggctcttgtatttgctccagacatgtgaccagatatggcttagacgaag
+taagacctgtttgtggaaaaaggaaacaatattgttagagtattcacctc
+agaaataaaatgtcctttctaagactgtgtataagatagaagatacaata
+gaggaatatagaggattcatttttcccatgttttctgatgggcacaccag
+aatccttaggagaaacttaggacgtctgtgtcctgagcttcatgtccctt
+agttacaaggacaatttttaaaactgaagtgtgtgagagtctcagtaagg
+tgtaccacttctgttctaataaaaatgaaacatttaagagagttggggga
+agaggaaccaacaccagaagaaatagttttaaggtatataaataatgtta
+atttccttaagagcagccctatgaacctctctgttggaagcacaagcttc
+catgaggtactgtacaaagcgagcaactttcatgctgacagttaagagtt
+cttcatggaaatatgtagcaatggggaatgaggaaccagggatagccact
+ggaggcttccaggacccaatggggatgacattagcagaaatgaagagtaa
+gggggagacaaaacttgtagagaccacctccagtagataggcatggatcc
+ctgtcgatggatggggccacacacccatctcaaagtttttaactcagaaa
+tgttcctgtctaaaggaaagtcagggacaaaaaatggagcagagactgag
+ggaagggccatccagatactgccacacctggggattcatcctgtcttcag
+aaaccctaccccgacattgctgctttggccaagagtcccttgctttcagg
+aacctggtgtggctgtcccctgggatgttctgacggcacctgaacaatgc
+agaggcagatgctcatagccaaccatcagagtgagcttggggaccccagt
+gggggagctgagggaaggactggaggagcagagggggattcaacacctta
+ggaagaacaatgtcagcaggccagaccaccaagtgctcccagggactaga
+ccaccaactaaggagtgtacatccatggctccagatatataagcagcaga
+ggatggccttatctgacatcatggtaagggaggcccttggtcctgcggag
+gtttgatgccccagcgtagagggatgctggagaggtggccaggtgagact
+gagtttgtgggtagaggagcaaccttatagaggcaaaggggagggaggag
+aaggtagatgggatgggatggggtggggcggcttgtggagaagcaaacag
+gaagtgggatattatttgagatgtaaatgaatggaatgatgaattaaaac
+aacaacaacaacaaaaaaagttcttcatggacgctctcctcacccaggaa
+cacaagattgtcataattctccaacatcacattcctgtacagtttccact
+gagcaggatcaaggcattccctctcctctgcagagaaatcaatggccaca
+tccttgaatgacagcatttcctaaaaaacaaaacaaaacaaaaaaaggaa
+ataacacacattgttgggggttgatctggtgcttctatgtgctcaaatga
+tactataagatcttgtagccagaagacaagcaaaattctaacatactcca
+gtatttactgtgtaaaactagctccccaattttaaactattggttaaata
+aaactggcaacagtcaattatggggtgaaatagaggttggtagagcttca
+gtgaccaggctgggggtcaaggtaaggaacatgatgaggaaaaacaaaaa
+tagggaggagaaggggaagatgggaggacatgaggtctccattagacatg
+atagattaggaacaactcaggaaagactcaatcagcaaggaattgggaac
+acatctggggaagtagccagtctagctttaaaaaaatagattaggagtaa
+ttccccagtaattgaacaaaaaacaaataaataaatcatagtgttggtct
+cattcctttggaagctaagctgggatagacataactacaattaacttaca
+catcagattaattatcactatcaataataacataaatacaaagaggtatc
+atatgttctgtataaaatctaaaggtggctctgagtaagagctagaagca
+tttctgatatagggaagtaaaatccataaaatactactgatgtgatgcta
+ggggcaacacaggattcatctctaagggaagtggatgacagaaggtccga
+gaatcttgcatggtctaacacttttaaggaccatacactggagaacaagg
+acaactacagtagagtgtgctggggctggagagatggctcagcagttaag
+agcactggctactcttcgaaggacatggggttgattactatctcccacat
+ggccactcacaactgtctataactccagttacagaggatcagacattctc
+tcagacatgaaagcaatcctcctttactataaagcatagaagatctgtgc
+cagtgatttcaggcagacaagcacctggtataggtaagtcagtcagaagg
+cacaagaagtacggtcacacagcatgagagacttgtctatttatgactaa
+atcaataatttcctttcccatctgataagagtcttgcttttaaaaacagg
+attcctatgtgaatacagttgaccttcctcaaccttatttgtctgctaca
+acacacagaggaattttttttttttttttttttttttaggacagcatgaa
+aatctgtctagcttaagcagacaataccagaaaggagaaacctggatggg
+gctcctagaagcagcacccacttcctcattcgcaagcccattgcatgtct
+ctaacagtttcaagccaggtttctctcttcacataacccccatcccatgt
+ttccaggagagctggtgcccatctctgtgtgtactaataagcagcctcaa
+ctgttgttttcaacctctttcctgcctttcttctttttgatctgtgttca
+caaatctaacataatccatattttcacaaatgaccatattgcatgctgta
+acatcaccaaataatatcacaaattaagcagtgaattgaggagcagaaca
+gagagaaactgtgtaccttaatgtcctaagtcttttaattttatgtgtaa
+ttaattcattcaaattaaagatgttcacttgtaaccacattaagataacc
+tcaaaattaccaaaaagaagaatataaagaaaaataatgtattgagttaa
+ggaatatagagctgtttcataatggaaaagaatagaggaagctgttataa
+agtcagacacacaaaactaataaaacaacaattacttttgcagtatgtac
+gctgactggtaggtcatgcctgtatttttttcctataaaccatatgacca
+gatttcatagaaaaacaatataaaagatcacgctggtattttcattcact
+atcctacaagatttctagaaacatttgccaatacacattacttagacgaa
+cactaggaaccaaattttacaagtacaatcataaacttcatcaaagagta
+caaacatctcttaaaggtatgaagaaacatctcaatgccattaaagacaa
+tgaaaggaaatatataggaaatgttagacactgtgaaaataacaggcata
+gatgaaggagaaaaacctccaggcaatggcataaattgatcttcaaaagg
+ctataaaagaaaaaaacaataaacaactacaacaacaacaaaaggttgca
+aagagaatacagaacatcacaaaaacatccaccatgaccaagttggtttt
+atctcttaaatgcagagatagttcaccatatgcaagtgaataaatgcaaa
+aaatgacatagtcttatagacaataaacacatggtcatctcaagaggggc
+agaaaagtcttggacaaactccaatatgctttcagggtgtaagtgctaca
+gaatgtgagactagaggaatgtttcttcaagggaaggaatgtaaactctg
+ttttccatacaaagcttagagctgattactagtctacttagtcacttatg
+atatgtattttgctaactttgttcctctaggacatttaggtatgtttttt
+tgtgcttacagtactgaggtaattatcaccagaagagtttacacctaatt
+gtgctagtgcttgaatatgcctaaaacaaacaagtggacatcagattccc
+cccatttgaacaaacaactactagtgagttgtgttgggcagactgccttc
+ctgcctcccctgccttggtattctgctgcagggatgctgtttgcgagcat
+aagaaagggaatggagggtacatatgagtgcatggggaaattgggaagaa
+ttgtggggcaataattagggaagtagaagaacataaataggggtctgaaa
+gtaaccttgaaccttcaaccccagctccctaccagcctgcagtctctctt
+ggtaaaccccaatagtggtcaccctgatacctaaaccacacaaagactca
+acaaagaaagagtatttcaaccacttttcctcatgaatatttttttttct
+ttttttggtttttcgagacagggtttctctgtgtagccctggctgtcctg
+gcactcactttgtagaccaggctggcctcgaactcagaaatccgcctgcc
+atcaacattgtaaaaatggctatcttgccaaaagcaatctacagagtcaa
+tgcaatccccatcaaaattcccaactcaatttcttcaacgaattagaagg
+agcaatttgcaaattcatctggaataacaagaaacctaggatagcaaaaa
+gtcttctcaaggataaaagaacttctgcggaatcaacatgccagacctaa
+agctttactacagagcaattgtgataaaaactgcatggtactggtataga
+gacagacaagtagaccaatggaatagatattgaagacccagaaatgaacc
+cacacacctatggtcacttgatcttcgacaagggagctaaaaccatccag
+tggaagaaagcacagcattttcaacaattggtgcaggcacaactggttgt
+tatcgtgtagaagaatgcgaattgatccatacttatctccttgtactaag
+gtcaaatctaagtggatcaaggaacttcacataaaaccagagacactgaa
+acttatagaggagaaagtggggaaaagccttgaagatatgggcacagggg
+aaaaattcctgaacagaacagcaatggcttgtgctgtaagatcgagaatt
+gacaaatgggacctaatgaaactcgcaaagtttctgcaaggcaaaagaca
+ccgtcaataagacaaaaagaccaccaacagattgggaaaggatcgttacc
+tatcctaaatcagataggggactaatatccaacatatataaagaactcaa
+gaaggtggacttcagaaaatcaaataaccccattaaaaaatgtggctcag
+aactgaacaaagaattctcacctgaggaataccgaatggcagagaagcac
+ctgaaaaaatgttcaacatccttaatcatcagggaaatgcaaatcaaaac
+aaccctgagattccacctcacaccagtcagaatggctaagatcaaaaatt
+caggtgacagcagatgctggcgtggatgtggagaaagaggaacactcctc
+cattgttggtgggattgcaggcttgtacaaccacttctggaaatcagtct
+ggcggttcctcagaatattggacatagtactaccggaggatccagcaata
+cctctcctgggcatatatccagaagatgtcccaactggtaagaagaacac
+atgctccactatgttcatagcagccttatttataatagccagaagctgga
+aagaacccagatgcccctcaacagaggaatggatacagaaaatgtggtac
+atctacacaatggagtactactcagctattaaaaagaatgaatttatgaa
+attcctagccaaatggatggacctggagggcatcatcctgagtgaggtaa
+cacattcacaaaggaactcacacaatatgtactcactgataagtggatat
+tagccccaaacctaggatacccaagatataagatacaatttgctaaacac
+atgaaactcaagaagaatgaagactgaagtgtggacactatgcccctcct
+tagaagtgggaacaaaacacccatggaaggagttacagagacaaagtttg
+gagctgagatgaaaggatggaccatgtagaaactgccatatccagggatc
+caccgcataatcagcatccaaacgctgacaccattgcatacactagcaag
+attttatcgaaaggacccagatgtagctgtctcttgtgagactatgccgg
+ggcctagcaaacacagaagtggatgctcacagtcagctaatggatggatc
+acaggactcccaatggaggagctagagaaagtacccaaggagctaaaggg
+atctgcagccctataggtggaataacattatgaactaaccagtaccccgg
+agctcttgactctagctgcatatgtatcaaaagatggcctagtcggccat
+cactggaaagagaggcccattggacacgcaaactttatatgccccagtac
+agttgaacgccagggccaaaaagggggagtgggtgggtaggggagtgggg
+gtgggtgggtatgggggacttttggtatagcattggaaatataaatgagc
+taaatacctaataaaaaatggaaaaaaatccaaaaaaaaaaaaaatccgc
+ctgcctctgctcctgagtgctgggattaaaggtgtgcgccaccatgccca
+gctccttatgaatattgatgcaaaaatactcaataaaatgatcacaaacc
+aaatccaagaatacaccaaaaacataatccaccatgatcaagtagttttc
+atcccaggaatacagggatggttcaatatatgaaaatctgtcaacttact
+ccattatataaacaaaatgagacaaccaaaagttatatgaaaatctccaa
+tgctgagaaaccctttgagaaaaatcaaaaccccttcatgttaaaagtct
+tggagagatcagggatatgaggtgcatacctaaacataataaaagtaata
+tacagcaagccaatcttaagttaacatcaaattaaatggagagaaactta
+aagtatttacactaaaatcagggacaagacaaggctgtccactctctcca
+tgtctctataatatactacttgaagttctagccagagcaattagaaaatg
+aaaagagatcaaggggatacaatctggaaaagaaaaagtcaaagtatagc
+tatttacagataatatgatagtatatcagtgaccgcccccaataaacaaa
+caaaaaaactctaccagagaacttctagagctgataaataccttcagcaa
+agtggctggcatacaaaatcaactaaaaaataaattgccgggagtggtgg
+cacatgcctttaatcccagcacttgggaggcagagacaggcacgtttctg
+agttggaggccagcctggtctacagagtgagttccaggacagccagggga
+acacagagaaaccttgtctcgaaaaattaaaaaaaaaaaatcagtagctt
+tcctttatacaaaccataaacaggctaagaaagaaatcagggaaataata
+tcttcacaatatctgcaaataatataaaatatcttggtgtaactaagaaa
+tcaagtgaaagacctgtatgacaagaccttcaagtctctgaagaatgaat
+gtgaagaagatatcataagatagatttctcatgcacatgggtaagtagaa
+ttaacataatgataatggccatctcatcaaaagcaatctacagattcaat
+gcacttctcatcaaaattcccatacaattctttacagactttgaaagaac
+aattcacaacttcatattaaataagaacaaaaccaaaaaaaccacccagg
+atagaaaaaacagccctatacaagaaaaaactcgcacaggtattataatc
+cctgatttcaagctgaactacagagaaagagtaattaaagaaacctgtat
+ggtattggtacagaaatacacaggttgactgaggaaatcgaacagaagac
+cctgaaataacctacacacctctggacacttaaatttggacaaagaagcc
+aaaaccatataatggaaaagagaaagcatcttcaaaaaaatggtggcaat
+ctaactggatatctgcatgtagaagaacagaaatagattcatattcatca
+ctctgcacaaaactcaagtcctaggggatcaaaaaacctcaacataaaac
+cagatacacaggttggagagatggctcagcagttaagtgctctgactgct
+cttccagacgtcctgagttcacttcccagcaaccacatggtggctcacaa
+ccatctgtaatgggatctgatgcacttttctagtgtgtgtctgaagacag
+ctgcagtgcactcatataaataaaaaatatatctgtaaaaaaaccaaacc
+aacaaatactctaaatctctaaatctaagagaagagaaagtggggaatag
+ccttgaatgcattggtataggaacaacgttctgaacagaacaccagtaac
+taaggcactaaaataaacaatgagtgggatctcatgtaactagaaacctt
+ctgtaaagcaaaggacactgtcataatggcagccaccagaatggaaaaga
+ttttcagcaaccctaaatcccacagtgggctgacatcaattacataaaaa
+aaaaaaaaactcaagaagttggacaccagcaaaccaaataacccagttaa
+aaaatgggtacagagctaaacagagaattctcaacagagggaaacacttt
+aaaaaggttctttggtcatgaaggaaatacaaatcaaagtgactctgaga
+ttctaccttacagccacagcacatgcaggcaaggatataggtagggcatt
+ggaaacactccttggttacgggtgggaatgctaagttatataaaaactat
+ggaaatcaatgtggtggtttctcagaataatggggatagttctacctcaa
+gtctcagagagatcactcttgggcatatacccaaaagatgttctaccata
+ccacaaggacacttgctcaactacatttatagcagctctattcataacag
+ccagaaacaggaaacaacacagatatccctaagggacaaatggataaaga
+aattgttgttcattcatgcagcagaatattactcagctattaaaaacaag
+gatatcatgaaatttacaggcaaattgatataactagaaaatttagactt
+tttcaaaacttactttaagatagagttctcaaatgtttcaacctcccttc
+tagcccacataccagtggtaggggacaaaaaagataaatagaaaacaggg
+gttatggccctatttagaagtagttccttggggtagttccactctttgtt
+ctcaggatatcagtagtccagtccaattacaaaacatcaagcttgaatca
+ggacacatggcaagatccaacagaaagcacaaggaaccactgaattcata
+tgaaacagtagaagcagccaaaatcccacagaagttctttggtgcatttc
+tcgctatgtagtgaagaccagcagagctttgcaggtcctatcaatgcaga
+agcatcctctcactgtgtgtggggttctatttatcttctttctaaatatc
+acccaccttctcaagcatctgctctcagcaaaacatcacatgccctctga
+cgagacagcttccagcaaaacattacatgacacaactgaatttaaagaaa
+ctagaaacttgcacttcatcttcttgagtgacgtagtccaataaccaaaa
+ggatatgcataatagatactcacttataagtggatattagctacaaaaat
+agtcatgagacaatccacagatccagagacactaaataaaaaggagggcc
+caatggaggttgcttgattctcactcagaatggaattagtcatcataagt
+agatggagaggaaggggattgggaaggatatggggatgaaggatcaggtg
+tagggaaagcctgggagagaggggccaaaagaatgagtaaaatttggtgg
+tgggccaggttgaggaaggggatcatttatgtgatatgctggagatctgg
+gatgggagaggctcctgtgagcctataggggtgacactagttgagactcc
+taacattagggaagatgcaacctaaaatggttacctcctgtagccaggca
+gtactcccaggggagagatgaggatgccaaaccttcagctcaaaatgtgt
+cctgcctacaaaaagtgcatggacaaagatggaaaagagactgaggaaat
+agccaactaatgatgggcccaacgtggacagtttccatggataagaactt
+tcactgatactctgnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnctgaagtggaggttatccctgaccctgtttcctgac
+agtggaccctgagtcttgatctgggctgcctcatctagcttcattggaaa
+ggtatgtgtctactcctccagtgactacatgtgccagtaggggttggtcg
+gggaggaaggaagtggtgcatggggagaggggcaatgtgagggggtcctg
+ggagaagactggaggggcgggggctgtgattgggatgaaaagtagctaaa
+tacacaagtgaatggacaagaaagaaaagtgtccttgaactcactgacag
+aaatattttaaaggcagaaaatgacaacaacctgtccttcttgggtgtat
+tcctttcttcttttgatgaccatcaaaatcagtacaaatgaggtttctgc
+attcttttcatggccacttgacatgcacacagcccagaccagaaactgaa
+tgacatcacccaacgcaggacccttcagagtttcccagaacgacctgtct
+aacatgacaaggttgctgcctgagtctgttaaaatcagtgagtcgttcat
+tcataccatcactcacagtaacattaggatgaaatgaaaagagcctcgag
+gaaaagggcaggactgcaagcataggagactggactcctccctgaggaag
+aggaaggaaacccaccttgacagattactgcctggatggcagtgatacca
+catgtgacagacagtggtagatgtggttgtcattttccattggcagagtc
+agatgttctgaaaattttcaggtaaagtcagacagcccatggggtcagga
+cagaaaataacagaatagtcagagtacaaagaaaggctaacattccctgc
+tagtcaagcaaggcagagagaatgccccccaccctaaccgcttgcacagt
+aaatgtaagcaagatcctgatcttcatcaacataagtcgttaacaaaagg
+atgctagtgaactaccagattggtaaggttttaggattaggaagatatca
+agtggatggattcccttcaggtcacgggtgctcagaactaagagcaacag
+aagtaattattacacccaatacactatgctttaaaagtcttttaaaaaca
+aggggtctcaagtagcttgggctcacctgagttggctatgaaggagagaa
+tgactttgaactccaggattcctgactcctccccaaaacacagaaatgaa
+tgacacaataggctttagctcacttttctatcatggggctgattaataca
+aaatatatgactatttggtgtctgtaagtttatatatgagcaccctgctg
+taccctctctatgttgtaaggaatgtgttttggtgtacaaggtagcatgt
+gattcctgacttcatatactgttatatttttcctacagattagcatcatt
+aactaggaaatgtttatttattctagatatggttgcaaactcattgaaaa
+ttccagtagctaggacaaggtggtctgaagcccatgcttcctgacagtag
+acttgaatgctgtaagtcaggctccagctctggctcacaaacacttggtt
+tgactgaagagtgataatataagcaagatcccctgagataggggaggggc
+tgtggaggagaaatcctgaaccccacccccccacacacaaatacctgtgt
+gtattctgtgaatgcaaaactcttgtaaggagtctgtgggtgcagagtct
+gatggcccacgtggaagttcaccgaggggcagagcctagaattctgcagg
+ttcagggttagctgtcttaccttgggctggttttaccttcatggatagtc
+aatccttgcctcactttgtagtgggccatacagcttgtgacaatagataa
+aaacctcccagaatccactgactaggcagaacatgagcttctatcaaccc
+aaaagctaaaatctcatcagatggtatcttagacattgaaaatatctcca
+atgtctcatagtgcatgactccatcagactcacaccaatgaattttaaat
+tttccttggtcaatgacattatttgttctgtacaaccatgaaactgattc
+catgttggagtatggaatttggtttaaactaaatatatgttctcagatca
+tggctactcaaataactctggaataaactattctcttaaccctttaagag
+gagaactgtgcatttttgcatgaacataaacctactatgtgtaaaccata
+ataccccaagtatttccttccttccttccttccttccttccttccttcct
+tccttccttccttccttccttccttcctttctttctttctttctttcttt
+ctttctttctttctttctttctttctttctttctttctttctttctttct
+ttctttctttctttctttctttctttctttctttctttcagcattctttt
+gctgacataccagaagagaacatcatatccaaatatatatggttaggagc
+caacaagtgcttgctgggaattaaactcaggacctttggaagaacaggca
+gtgctcttaaccactgagccatctctccagccatatcttacagcttttca
+gatacagttgaaaaaattggagaattctttctaaaactattaagaagggt
+gtgtcactaaacctgaatgtcacattgagggacaaaggaaaatttaaaag
+agttcagacactgctgataacgtgaacacaaagatgaaaagcacgtgaag
+agacagcaatgtacagactctggcagattagagaaatgtacagatcctag
+tagattagagagcaatgcacagagcctggcagattagaaagcaatgcaca
+gagtctggcagattagaaagcaatgcacagagcctgacagatgagcagag
+ccatttcccccttccctttcagactttccaccccaccctgaggtctctca
+tcacaccaagtcgtctctcacatctgaaaaggagcccaaattttggacac
+aacacatactcagaactgttgaggtattattgtctagttattaatcttta
+gtgtaaaatcctatttatttggattttgcaaacagtgcttcataccaact
+acaagattattttgtgattttatagccatgtattgtcgcattcaggtcac
+aaaggtgtctatcagaaaatcttatttgaatcagggcatccatgagtcga
+acaattcgttccaaaggaactaacatcccacacgacagtttgccctccct
+cacaggattcttgctccttggacactaggaactttaggaagctgcttgag
+ctcaaaccagaagtagactctaggacataacatacagagggcgctacatg
+tccaagtgctctgtatgtcctgagaatctgactacagtcacgtgagaagg
+ggtcagctaggtaatgatgagtgcgctcttgtcagcatctcaggaacagg
+cagtcagcagacccagcctgcccttgccatcctgttgttttcagtcttct
+ccccttcaaacctgtgcccaggcgcagcggcccagcctaggtcagcagct
+tcctgcctcacaacaagcccgagccagctccctccgtgccctacctgcca
+ccctgcacagcccctcagacctgaaagatggcgctgctccctgcactaac
+ctccatgtcagaaatccagatgcagcgctgaggaggacaactgcacacat
+ttgaggagtgaagtttgaagaataaggaagttcgattccggcggcccttt
+ctgatgatgtcacaggacccgggactacatttcccacaagtcagttggaa
+ggatttacagggaaccccccccccccccccaagaggtcttgtgcattgcc
+tgccttgcagtccagctgtgggcagctgaagttggaaagaaccaggctgc
+cgcacgtggcagcaacagggaaagtgggcgtttaaaaaagtctttgtttg
+ccgggcagtggtggcgcacgcctttaatcccagcactcgggaggcagagg
+caggaggatttctgagttcgaggccagcctggtctacaaagtgagttcca
+ggacagccagagctacacagaaaaaccctgtctcaaaaaaaaaaaaaaaa
+aaaaaaaccaaaaaaaaaaaaaaaaaaagtctttggtcacagcacgcgat
+gttagcctgtgagctgagcttttcatagtaatgtttatcgcatttccttg
+ttatctctgttaaaacattgtgattttaaagcttcgattttttgttttgt
+tttgtttttttaaagtacagaactacttatggaatgttactaccgagtgg
+aaaattcatgctttcatggtttacttaaaatatgaaagcaggaagttaat
+ataagagtgggcattatctctttaagacgctatggaaaccatcccaggtg
+cttaagacagaattagaaatcaaactgagtcaccaccaagtgttttctga
+gcacttgctttcctcctctgaatctctcccaagaggaggggcagagctcc
+ttggatcacaatggtgagtgtactggctcttcaatttccctctgtgtttg
+gtttgatgttccttattgattttcctgtctccactgatcctgtcatcatt
+cacatttgataatacttgaacattactggtagctgccttgcacttccctc
+acttctcctaagcagaacactgagatagtttcccgtggaatccaaaggta
+tcagaaatatgctcatatcactgtaaaatgaggtgatgtattaaagaagt
+tagactggaaacttggagtattgagaattcccatcttttcgtaagaaagg
+tttattcctgtgtagttcatgcttgagttaaagctacaaatggcattaca
+gaaaagacttcatacttccctgaggcataataatttaaaagcaagctgtt
+tcagagcagagactgtgcaaaatccctatccaaatattcttctctaggga
+gtgtgtttgcctagggatcagaacagattccttaatttagaaaaactaga
+gtcaacaaacagtacattcacctggacatttgattggcatgtctgtttag
+aatgaggtcatgagtggtctgtcatccccctgatggctgtagtgaagggc
+attaccaacaaccagaaggacttaacatttctgagcatagttagttttcc
+aatatgtgtatgtgttgaggtttggtatgttgctatgtattgtaatacta
+aattctatatctgaaggtctaagcttaccatggacctctcacatttaaaa
+ggttctgttgtgcaaatcttgttccttgattgaaaactattagttaaatc
+aatttggctacagcttattcctagagggattagaggtaggtggcttttga
+cttacctggtacagggtgaagagagagaaggaaaaggtggaagaatagag
+gaggaggacgagttgtgattgggggtggggtgtaaaatgctgggagaaac
+attaagtacctgaagtacaccactgggaaggaagcaaagaaagcagaaga
+gtaaattagaggttgaaccccagtagttgtcaaagccagatgaaataacc
+tcaagtctgagcctcgtttacttgtaagctagtcagggataagcctttat
+gaaagaaaacatttaattggaactggcttacattttcagagagttagttc
+aatatcatcatggtagaaagcacggtaagctatgatgctggcagaaatga
+gagttctatatttttatctgcaggcagcagaaggggtctgtcttctgcat
+acagcaaggaagaggctctggtcaacaaagcttatttttataattaacta
+aattagtatctaacacaattacagatttgattgaatgactaatttgcatt
+tcataattatcctaaacagtttgaaacagtatctttcaaggcctggaact
+ttaggttacacttttaagtgaacagcttatgtctgatacagaaaacatgg
+ttgaaacataatataatgtattgtaatgtaaataactttaaatttgtatg
+aatatattaattctataccaatgtaatttatttggcctgttgatgctctc
+tagtgtaaacagattaaacaatctactctttcatcccattatttatgtac
+cccccttttcatattcattctccctccaccattttggccctagcacaaga
+tagaagagaaagaacagaagaaagaaaaagaaagagatccctgaatctaa
+ccgcttttactttgtttcctctgactaaaatcattgacctatccccctta
+aagaatgataaacttccattacccatggaacaaccaaaaatcacctaccc
+agactcttggaaattaggctgttttcccttaaaattgatgtacatacttt
+aatttttccaaacacatccatctgccaaatttcatttctttgattacctc
+tatctagaggtttttttctgtggcacgaaatagagcttgattacaaaaca
+tacacacaaacaaacaaacaaaaacacatattaatttttttctacatttt
+ttcaggttaagttttataaatattgaagtttctgatacatttgctactaa
+tcattgatctctcttctcatttcttaatggcaatggtcctggcaaacctg
+catgagattaaatatgatttacctatattggaagatctctgttccaggtg
+attagtgcactggctagttttgtgtcaacttgacacaagctggagttatc
+acagagaaaggagcttcagtagaggaaatgcctccatgagatccaggtgt
+aaggcattttcttgaaagatcccagtgaggagacccccactcaagtccca
+agatttcgtgtgcacccaaggaatcacgagagaccatcctgatgcaaaca
+cacaaggcagtttaatgacagagcttcagctgacatatatctctagcagg
+aaacagaggagtcgaccctgaggctcaaaagttaggtgtttatataggaa
+aaaagtcgggggataggggaaattggtgcagttacacacaattggacagt
+ataaacatcagcaaattgtacgtgcagatcaaggtaacagcaattctgaa
+gggcgcaggtgcttatctgtgtcagcagagcatatggataacatttaacc
+catgtcagaagggaggagacagtagaattgctaatcttgttatggctatt
+tctttgagaacagctaatattattttggtagctgcaggcttaataatttt
+gaccgctaaaactatgtttttacatttgtttactcagcttccttatttgg
+atctgcactttgcctgctagtacagtttggaaagttcttttcgaaggggg
+aaggtattgggtggtcttgaattcattttggatattacattcccaccccc
+cttttcccaggtacatttcaatcctgaaatgatatctcacttttgttaca
+gttactgatattgttgtctaagtatattaacttctactctacaattaagg
+atacatgggccaaaggttaagaacaaaaacaggataagaaggggtaggaa
+acaggactaggcagggacccttttgccacgcgctctggtcgagtcagctt
+gataagccgagaggcttgaaagctactctcgaggcaaaagagtttcatgg
+aaactcgctcctggagtttggcgtgctctctaaattttccattcccgcct
+tagtctagtggatggatccatgtgctctctttattataagtgccttttaa
+gattgaattctgacatagctaaaggcttctgccagtgttccaacattcct
+agaatgtccttgagctagacagtgacatttagaatagcctctggtattac
+actatcaataaaagccaagtggctcccatatacaggaatttacaatggtt
+taggaactagatcgggctgtggttttagagtattgcattattcatgaaat
+ggttaactagaacggaactccctagttagaaccatgacttgggtgtgaaa
+gcccttgtcctaggagagtaaagacctcacacctggcttctaagactata
+gctgagttacacccatacacacatatttacaatggcctaaggggaaggta
+gactatacaatagactaacataggaactatggcaagggcacgaagccctt
+gaccctggcttctaagattaaacgaatcttaggtggagccctttttgaac
+ccagttgttaacaatgaattctatcccgggtggttcccattagacctttt
+gtgtttgcattcctctgttttatgtaagattctggttacctcatttgtac
+cttgtgaatatgtcacccaacttccttattgtcttctgcataaaaagtct
+gatgctcgatttgacattacattcagatccaacacaacctctcctgtgtg
+catctgtttgtcaattcatctgacactttgtccactagagacccattcca
+cacagacaaaggggcccagagggtctgcagcaccctttcagcgaggcttg
+agggtctgggcgtgatgcaggtgcaggtagatcagatcttcgactagaac
+tggtgagatatctttggggtacccagctcgtttgctgtacccagttgtga
+ccagacttctttctgcaccaccagcaagcttttttttttttttttttttt
+ttttttggttttttcgagacagggtttctctgtgtagccctggctgtcct
+gggactcactttgtagatcagactggcctcgaactcagaaatccgcctgc
+ctctgcctcccgagtgctgggattaaaggcgtgcgccaccacgcccggtt
+tctctgcaagtcttttaacttagcatacagatcattattacaacaaaata
+tgggttcaaacacatcatttttagacagtgatggacatgggagccccata
+aaggatctcaaaaagagtaagactgaatcaagagggagtatttccagttc
+caaatggggcaaggggaaggagcaccaagtctgcaccagtcttcatggtt
+aattttgtcaaggtctcttttagagttctattaattctttctatctgtcc
+tgagctctgaggtctgtccacacaatgtaattttcatttgacctctaaat
+acttgaccacgccctgacttacctgggcaacaaaggcagggtcgtggagg
+gcctcagtagagccagcattccttctttgttcttatttctagataatggc
+tacatcacaacatttagatggatggaataggcagagctcctaccctcaag
+ctactaaattttgctttttttattttggccctttaataccttcttagaca
+aaaaattctttagaaaattgcattgtagatcaaatgttacacaaaatggg
+agttacagaacactgtcaataacaagtttaaagcagtgtttcattgtata
+tgctcattataattggaaagcaacagtttcatatggtcttgctttttgat
+agagcacactatggattgctgttgatatgcaggtgagggccagtgaaata
+taaggctagagtctgtgaatgggcaatgaaataggaaggaggggctaaga
+gtttcagagagagagagggcaggggatagacagaagaaggacagagaaga
+tggaggaagaggaccaaccagatccgtatggcttgaaatagccacaggta
+gctatgaatatcataaaagagcatagaataaaatagggcaatttgtccaa
+tctagatgggcagcttgtatcaatatcaagtggctctgagctgactgtgt
+agacgttttatgggttgaaattttactgttataaatctgactgataattt
+acaagcctctagagttttgattttactgggttaagggaattgtgacagct
+agccacagggagcagatgactgggaatgtgagcaggtttggaggcaggct
+tgtggggatagacatgggggcggggagaccaccacagccagagcatagca
+gcgatagcgtggattgatttttaattattacatgcaacagcacacctgtg
+gctttattcttggacttgaattttttttcttgaacaaaaaatttcacaag
+ccaatttctctttttagtgtaaccatgaaagctcattttattcctaatta
+tgcagcatttaattattattatgaggagtgggtacattctattcttcagt
+ctaactttattatctttctagcaaaacaactaaaactgtctcttaaaact
+ttcttctgactggacagtggtggtgcacgtctttaatcccagcacttggg
+aggcagaggcaggagttggaggccagcctggtctacagagtgagttccag
+gacagccagggctacacagagaaaccctgtctcaaaaaaccaaaaaccaa
+caacaaaaacaaacaaacaaaaaaacctttcttccaatgattatttgaat
+caaatcagaaattctgtaaaattattgtttcaacagaattaatttttgaa
+agtttgcctttttattgacctgtagaaaatctgctcagtagggtgggcta
+gatgttcaggattattatatcaatttaataatgaaaggacaggcttgtca
+gctgcaagaagcaatcctgagatgaagtcttattgggatctttcctcatt
+gagattccctatcacagatcatgcaaaaattgtgggccactccaaccaca
+atcaccagatcttctgacgtctataaaactaataaacaaattcaaatcaa
+tagtcagagccttgctcctcccatgatgctagagctcatggagttaacaa
+ctgagatacaagcattacttcttgacccctgtctacataaaatacaaaca
+taattcaaaacataatttaggtttattttgtctgggcacatgtatgtatg
+tatgtatgtatgtatgtatgtatgtatgtatgtatgtatatatgtatgta
+catttgtatgtgtggcagcacatgcatgaagatcagaggacaacattcag
+aggtaatttcccctttgtatttcataggtactgggaatactaacatgggt
+atggtcttgttggcagttaagtttgttccccaagtcatcatgctagcttt
+agccacaaatgtctaatcttaacatttcttcccttctccccaaccttact
+ttcatctcataaataaaataggctactcttataagtaaagcatttattgg
+gcttgtttacagtttcaaaagttttgtaagttatcattattgtagaaaac
+atattgtagggaacatggtggatagagacagatatattgatgctcaagaa
+gtagctgagaatcttacattttgatctatagttattaagaagagagcgac
+actacatctgagcttttgaaacctcaaatacaacccgtaatgacacatta
+ctccaacaatgccacacttctttatcctttcaaagaagtgctactgcctg
+atgactaagcattcaactctatgaacacttagagcaattcttactccaac
+cacaatacatgatgggaaacttatgacagcaggaacttaaagaagctcat
+catgttccatacacagtcaggaagcaggagattgatggatacttgccatc
+aacgtattttcttacactgcagcatttccagcacatgcttccaaccacaa
+tcaccaatcttctgacgtcaattaaactaatcaagaaattgagaatcaat
+agtcagaggcttgctcctcacatgatgctcgaattcatggagttaacaac
+tgagatacaagcattacttcttgacccctgtctacataaaatacaaacat
+aattcaaaacgtaatttaggattttgtctgggcacatttatgtatgtatg
+tatgtatgtatgtatgtatgtatgtatgtatgtatgtatgtacatgtgta
+tgtgtggcagcccatgcatgaagatcagaggacaacattcagaggtaatt
+acccctttgtattccatgggtacttggaatactaacatgggtataggtct
+tgttagcaactaagtttgttcccaaagtcatcatgctagctttagccaca
+aatgtctaatcttaacatttcttcccttctccccaaccttactttcaact
+cataaataaaataggctagaacttgaaaggtccataaaagatttaataat
+tacaacactatgaaagcccacagtccatgtgtcacgtgagactcaaggca
+atctcttatgtgtgagctcttacaacataagaacaagacactaattttac
+tactcactggtatagaataagtattcttattctaaaacagaagaaacaaa
+acacacccaggaaagatcagccccaaatccagagaacacacaatctgaca
+gctctacttttggcatgattgtgtgaatgattccaaagtctttacttacc
+acattgctcaatcttatatggtttctagtaagcaggaagcttttagtgta
+tgaagaagtgttaacatattatgaatatttaacatttgcattatttaact
+ccagtttgaactacctcgtgttgagatatataaaaagttcaataaatggt
+ttgcaacattttccacatgtggcatttcagtttcgtatgaattatgaggt
+gttttacaagttcttagtaagtacaaaagactttggaacattcttcacac
+ttgtgtggtttctctcatagatgaattcttgaatgttgtttaagaccaga
+agactggtaataggttttgccacattctccacaattataatgtttctctc
+cagtaggaattatccggtgttcagatcatgctttggaacttctgatgtat
+ttgccacattctttaggtttgtatgttttctctccaaaatgaatttttga
+tgatccctaaagtttgtgttgaacacttgtttgtacatattctttgtatt
+tgtaaatgtcaccacattatgagttaacgtgtgtaaacactggtgtatat
+ttatagaaaaggcttttccacattaaacgagtagaaaaaatctggcaaat
+tctaaagaagttgacttgcacttaacaattgtagggttttaacctgtgtg
+ttttctcttgtgttcagaaagtaattatggacaatagaggagcaggctac
+atacttcataattggagggtttgtctcccatatgatttctcttgtgattg
+gaagtccttgccacatgcttcacgctagtagggttggtttctctatggta
+ttttttattttttgggcaccaggcaacataccatcaattttaaaaataac
+ttatttattttatgtacatgagtgctctaactgcatgtacacctgcatac
+cagaatagggaaacagattccatcattcatggttgtgagcctgcatgtgg
+ttgccgggaattgaactcaggacagcacaattgaaattgcagccagatct
+cttaactgctgagccatgtctccagccccatgaattttcttatgcttgga
+aagtcgtgagggataatggaaggctttgccacacacttcacacttgtagg
+gtttttttcctgtatgaattaccttgtgtttagaaagtaatgatggataa
+tggaaggccttgccacataagtcacacttgtagggtttctctcctgtatg
+aatgatcttgtgtttagaaagtaatgatggataatagaaggctttgccac
+acacttcacacttgtacggattctctcctgtgtgaattctcttgtgttta
+gaaagtgaagatgcaaaacagaagacattcccacatacttcacacttgta
+gggtttctctcctgtatgaattttcttatggttggaaagttttgaaggat
+aatggaaggccttgccacatatatcacacttgtggggtttttctcctgta
+tgaatcatcttatgtttagaaagtaatgatgcataatggaaggccttgcc
+acataagtcacaattgtagggtttctctccagtgtgacttatcttgtgtt
+ttgcaagtattgatggaaaatggaaggccttgccacattcttcacacttg
+tagggtttctttcctgtatgatttctcttgtgtttagatagtgatgatga
+aaagcggaaggtcttcccacatatttcacacttgtatggcttctctcctg
+tatgaattatcctgtgtttagatagtgatgatgaaacatggaagtccttg
+ccacacacttcacactggtatggcttttctcctgtatgaattcgcttgtg
+tttagaaagtagtgatggataatggaaggccttgccacaatcttcacact
+tgtagggtttttctccagtatgcattcccttgtgtattagtagtaatgat
+ggaaagcggaaggcctttccacatacttcacacttgtatggtttctcttt
+tgtacgaactttcttatgcttagaaagttttgaaggataaacgaaggcct
+tgctacatacttgactgttatagggattctctcctgtatgaactctcttg
+tgtttagaaagtaataatggaatgcagaaggccttgccacacacttcaca
+cttgtagggtttttctcctgtatgaattatcttgtgatgagaaagttttg
+atggaacatggaatgcctggccacatacgtcacacttgtaaggtttttct
+tctgtatgaattatcttgtgtttagaaagtaatgatggataatggaaggc
+cttgccacattcttcacacttgtagggtttctctcctgtgtgaattctct
+tgtgtttagaaagtgaggacagagagcggaaggcctttccacactcttta
+catttgtatggtttctctcctgtgtgaattctcttgtgtttagatagtga
+tgaaggaaaacagaaggccttcccacatacttcacactggaatggtttct
+ctcctgtatgaattttcttatggttggaaagtcttgatggataataaaag
+gccttcccacatacttcacacttatagagtttttctcctgtatgaattgt
+cctgtgtttagaaagcagtgatgaaacatggaaggccttgccacatactt
+cacacttgtagggcttctctcctgcacaaattctcttatgtttagagagt
+cttgaaggataaatgaaggccttgccacataattcattgttataataatt
+atcttctgtatgaattctcttgtgtttagaaagtgatgacagagaacgaa
+aagccttttgacatacttcacacttgtatggtttctctcctgtatgcatt
+tttgcatgggtagaaagtcttgagggataatcgaaagccttgccacatac
+ttcacacttgtaaggattctcttctgtatgaattatcttgtgcttagaaa
+ggagtgataaaatgcggaaggccttcccacatacttcacacttgaatggt
+ttctctcctgaatggattttcttatggttggaaagtcttgatggataatg
+gaaggcctttctgcacacatacctcacacttgtagggtttttctcctcta
+tgaattattttggtgtttagaaagaaatgatgaaatgtggaaggtccttg
+ccacattcttcacatttgtatggtttctctcctgtatgaattcgcttgtg
+tttagagagtattgatggataatggaaggctttgtcacatatttcacatt
+tgtatggtttctctcctgtatgaactctcttgtgtaccaaaagtaatgat
+ggaaagtggaaggcctttccacatacttcacacttgtatggtttctcttc
+tgaatgaatcttcttatgtctggaaagtcttgatggatgttggaaggcct
+tgccacacacttcacacttgtagagattctctcctgtatgaactctcttg
+tgtttagaaagtaataatggaatgcagaaggccttgccacaaacttcaca
+tttgtaaggtttttctcctgtatgaattctgttctcttcagaacttaatg
+atggactatggaaggacctggcacattcttcacacttgttgggattcatt
+cctatataaagcatctcatgattttggaacactttggtccactcaaaaac
+tttgccacactctttgcacgtatacatttttcttcctggtgaggaatgat
+tgagaaattagtgaaggtagagcaaaattccgtaaatttataatgcttct
+ttttaataacatttactcatagttgcatttttttataaatgataagctat
+attcaaatttctaaacctgtattcaatgaagcctaagttaaatcacagaa
+atagtgaaaatcatgtcaccttccactaaaagaagagcatgaatctgtag
+aatatggaatcaaaaatattaatcaaaagaatattaaaatgtaagcaaaa
+catagtatcaactaagaaaacccattatgtaaatacaagttagctcctaa
+cagaaatacagaaattccatgactagataaaaacaaaatatagaatggtc
+tacctttgaatacaccagaacaaacaataattctatattctatattatat
+gaatataatatattaaatatatatgatatagatataaatatattagtata
+gagtttagtttatgaagttatcaataataaatttcaagggttcaagaaag
+aagtttatgcatatctttaggcatggtgggtttgagcagtatgtgaacat
+tatcctggtattattcaaacactgatttttctgcctcgtatctacttgcc
+atccacacatggtacgtaatatgtattctaagaatttctcttatgaagtt
+tgtgtaaatattgatcccattttattctctaacttgtcaagaaaactgac
+aagccaaaagaccaaatgtagagaggaaagagttggacatctgcaagccc
+agggaagaagagaacaggggtgaggggagaggaaggaaagggacgggagg
+gaaggaaaggattcactaggaggacagggtctggagagacatgatgtaaa
+gacacacaaagcccagagagccagactaatacaaaaatgcaagtatcctg
+agaattttgcctgggaggtagccagattaacttagatttgaactgatcat
+taactgtctggtaattgtcttgtgaatcttatcaaataaagattatagtt
+tcagggggctggtgagatggctcagtgggtaagagcacccgactgctctt
+ccgaaggtccggagttcaaatcccagcaaccacatggtggctcacaacca
+tctgtaacaagatctgactccctcttctggagtgtctgaagacagctaca
+gtgtacttacatataataaataaataaatctttaaaaaaaaataaatggg
+ttatgtgacaacaaaaaaaaaaaaaaaagattatagtttcagtccctttc
+attttggagctagccagggacagagacaaatcttcacttttaaaaatgta
+tgtacacatttttaaatgcatttttaatatcttatattaaaaaaataaac
+ttcctagttaaagactacttagaaataacagagctttggctgtcctggag
+aatgcaagttaatctcatggtggaagaaaacaaagcttatgagattcaaa
+gcatccttaacattagataatttcctttcaaagaaaatgacagaaaagta
+tagcttaaaaagatgatttttaccacaatattatgtcttaatggttgtat
+attagatcttagaatttttcactctgttctctgattccctcctcctgaca
+taccccggagcatagaggtagctgctcctcttttcacatctgaaggctct
+tgtatttgctccagacatgtgatcagatgtggcttacacgaagcaagacc
+tgtttgtgggaaaaagaaacaacattgttagggtattctcctggaaaata
+aaatggtcctttccagactgtgtatataatcaatgagaagatacaataga
+gaagtatagaggattcattcttcacatgttttctgatgggcacaccagag
+tccttaggagaaacttaagacttctgtgtcctgagcttcatgtcccttat
+ttcatgtccttatttataaggacaacttttaaaactgaagtgtttgacag
+tctctgtaaggtgtaccacttacgttctaataacagttagacttttatgg
+gggtgcagggaggaaccaacaccagaagaaatagttgtaaggtatataaa
+ttattccaaattttcttaaaagtagtcctataaacgatattgttggaagc
+acaggctcccatcagatactgtacaaaaggaggaagtttcatgctgacaa
+ttaatggaagctctccttacccaggaacacaaggttgctgtagttctcga
+gcatcacgtccctgtacagattccactgagcaggctccaggcattcccac
+tcctctgcagagaaatcaatggccacatccctgaatgacagcatttcctg
+gggaaaaaaaaaaaaaaaatatatatatatatatatatatatatataata
+acaaacactgttgggggttggtctggtgctgctatgtgttcaaatgctaa
+atctatactataagatctggctgccacaagacaagcaaagtctaaatgac
+agctgcatttattgtgtaaaccttgctctcaaatttaaaactattggtta
+aataaaactggcaacagctaattatgtagaaaaaaagggggtggtatggc
+ttcagtgatcaggctgggagtcaaagtaagaatcatgatgaggagaaaca
+aggagaaggggaaggcggcaggacatgagctctccattagacatgatgga
+tcagtagcatatgcccaactgaaatgacccacaaacccataggaaacatt
+gatggagcagaaataattcaggaaagtctcaatcagcaaggaattagaga
+gcacagctggagaagtagccagtctagctttagaaaaatagattaggcat
+tattcccaagtaattgagcaaaaaccaaataaataaatcatagtgtgagc
+ctcactcatttgaaagctaaactgggatagagacaaccaccaatttacct
+tatatactatgcgaattaaaatcatcaagaataacataaatacaaagagg
+catcatgtgcttctgcacagaagtctaaaggtggccctaagtgagaactg
+gaacgacttctgatataggcaagtaatatccctaaagttctcctcatctg
+ctgttgttttatgggacatggatgacagaaggtctgacaatcttctatgg
+tctaacacttttaaggaccatgaacaggagacaacaagggcaactacagt
+acagtgtgctggggctggagagatggctcagcagttaagagcactggcta
+ctcttcgaaggacatggggttaattactatctcccacatggccactcaca
+actgtctgtaactccagttacagaggatcagacaatctctcagacatgaa
+agcaaacctcctttactataaagcatagaagatctgtgcccgtgatttca
+ggcagacaagcacctggtataggtaagccagtcagaaggcacaagaagta
+cggtcacacagcatgagagacttgtctatttatgactacaataatgtcct
+ttcccatctgataagagtcttgcttttaaaaacaggattcttatgtgaat
+acaggttgaccttcttcaaccttatttgtttgctacaacatgaaaatctg
+tctagcttaagcagacaataccagaaaggaaaaacctggatggggatcct
+agaagcagcacccacttcctcattcgcaagccccttgcatgtctctaaca
+gtttcaagccaggtttctctcttcacataacccccatcccatggttccag
+gagagctggtgcccatctctgtgtgtagtaataacagcctcaactgttgc
+tttcaacctctttcctgcctttcttctttttgatctgtgttcacaaatct
+aacataatccatattttcacaaatgatcatattgcatgctgtaacatcac
+caaataatatcacaaattaagcagtgaattgaggagcagaacagagagaa
+actgtgtaccgcaatttcctaagtcttttacttatgtgtaattaattcat
+tcaaattaaagatgtttacttgtaaccacattaagataacctcaaaatta
+ccaaaaagaagaatataaagaaaaataatgtattgggttaaggaatatag
+agctgtttcataatggaaaagaatagaggaagctgttataaagtcagaca
+cacaaaactaataaaacaacaattacttttgcagtatgtacgctgactgg
+taggtcgtgcctgtattttttttcctataaaccatatgaccagatttcat
+agaaaaacaatatgagatcacgctggcatttctattcagtatcctacaag
+atttctagaaacatttgccaatacacattacttaggatgaacactaggaa
+acaaattttagaagtacaatcataaacttcatcaaagactacaaacaact
+cttaaaggtatgaagaaaaatctcaaagccattaaatacaatgaaaggaa
+atatataggaaatgttagacactgtgaaaataacaggcatagatgaagga
+gaacaacctccagggaatggcataagttgatcttcaaaaaggccataaaa
+gaaaaaaaacaatatacaacaacaagaacaaaagcttgccaagagaatat
+atagacacatcagaaatatccaccataaccaagttggttttatctcttaa
+atgcagggatagttcaacatatgcaagtgaataaatataagaaatcacat
+agtcttatatttttggttgtgagcctagcctttaatggctgagccatctc
+tccagcccaaaatgacatagtcttatagacaataaacacatggtcatttc
+aagaggggtaaaaaactccaatatgctttcagggtttaagtgctacagaa
+tgtgagactagagggatggttcttcaagggaaggaatgtaaactctgttt
+tccatacaaagcttagagctgattactagtctacttagtcacttatgata
+tgtattttgctaactttgttcctctaggacatttaggtatgttttttgtg
+cttacagtactgaggtaattattaccagaagagtttacaccttattgtgc
+tagtgcttgaatatgcctaaaacaaacaagtggacatcagattcctccca
+tttgaacaaacaactactagtgagttgtgttgggcagtgtggggagctgc
+cctcacattcaccgttgcaagatggcgctgacatcctgtgttctaagtgg
+taaacaaataatctgcgcatgtgccaagggtagttcttcactccatgtgc
+tctgccttccccgtgacgacaactcggccgatgggctgcagccaatcaag
+gagtaatacgtcctaggcggagaataattctccttaaaagggacggggtt
+tcgccattctcactcttgctctggctcttgcttcttgctcctaaagatgt
+aagcaatagagctcttgctctcttgcactcttgctcctgaagatgtaagc
+aataaagttttgccgcagaagattctggtttgctgcgtctttcctggccg
+gtcgcgaacgcgtgtaagagggcagacgaccttccttcctcccctgcctt
+ggtattctgctgcagggatgctgtttgggagcatatgaaagggaatggag
+ggtacatatgagtgcatggggaaattgggaagaattgtggggcaataatt
+agggaagtggaagaacataaatatggatctgaaagtaaccttggaccttc
+aaccccagctccctaccagcctgcagtccctctcgctaaacccagtagtg
+gtcatcctgatacctaaaccacacaaagactcaacaaagaaagagtattt
+caaccacttttccttatgaatattcacgcaaaaatactcaataaaatgat
+cacaaaccaaatccaagaatacaccaaaaacataatccaccatgattaag
+cagttttcatcccaggaatataggagtggttcaatatatgaaaatctgcc
+aacttattccattatataaacaaaatgagacaaccaaaagttatatgaca
+atctccaatgctgagaaaccctttgagaaaattcaaaaccccttcatgtt
+aaaagtcttggagcaatcagggatatgaggtgtatacctaaacataataa
+aagtacagcaagccaatcttaagttaacatcaacttaaatggaaagaaac
+ttaaagcaattacactaaaatcagggacaagacaagtcagtccactctct
+ccatgtctctataattatactacttgaagttctagccagagcaataagaa
+aatgaaaagaaatcaagtggatataatctggaaaagaaaaaatcaaagta
+tagctatttacagataatatgatagtatatcagtgacccccccaaaacaa
+acaaacaaataaacaaaaaaactctaccagagaacttgtagagctgataa
+attccttcagcaaagtggctggatacaaaattgtgggaagccacatacac
+cattacaagatggcgctggctactgctggctaccacccgtaagttcaggt
+aaacaaccaatgtacacatgtgtataagggttttgcaccaagtcacagtc
+catcccggggaatataaatgaggcaataaaagcacaaccaatcaggtata
+gatacgccactcctaggcctgtttaagcagtgccagttttggggctcggg
+gtctttctacttcgctatcaagctcttccaataaatgtgtgcagaagaat
+cctgtggctgcgtcttccttgctggcaagtcgggtgtccacaggtggtgc
+cgaaacccgggaaggaaacatcttcaggcacgagcaaagaccccctgtta
+cagggaggattcagaactgcatcacggggaaggaataacgtaagtctctg
+agaggtatgcttccctttggagtagatcctctaacagttgcctgtctcat
+tccagtcatctttatagtagtcctgattctgtgctattgccttaattgtc
+atcatccagggcacgagtgtgtttgctgggaagaaaaactgaaaccaggc
+acacgtccgctttggaaagtaattaaggcttatatacaggataagaagtg
+tgaaaaagagggacaaagactgttacaggaacatcaggaaagtatgtcag
+aaacagagaaagatgagagagcaggagtgcgtagaaaacaaaacctagaa
+aaggaaaagatgagccaaaggataaagaaaaaaaagaaaggaaagaggaa
+aggaaagggaaaaggaaaggaaaggaaaggaaaggaaaggaaaggaaaaa
+ggaaagaaaagagaaaggaaaggaaagaggataggaaaaaggaaaggaaa
+agaaaggaaaggaaaggaaaagaaaggaaggaaagaaaaaaggaaaaagg
+aaaagaaaggaaggaaagaaaggaaggaaagaaaagaaggaaagaaagga
+aggaaagaaaggattgagacgataaggttcctgggtaaatgggacaagtt
+aaggttcacggctttggtacaagttaaggttcatggctttgggacaagtt
+gcaccaagcaccatggggcattgaggtttgcagaggaacagagagtttta
+ctaaaaggggttttgccagtctggaagttagtgagaaattgcatagaaga
+taaagatgtggtgcagaactccagagaggtaatgaggtgttgaatcaggt
+gagagaggagcgctctcaattggtttgggcaagagggtctgtttgtgttt
+cctcaggatcatcaacaacagctgtgggtcccagaatggctgatcagagc
+aattcaaggcaagcagaactatgaggacgaggatgttcctgtggctggga
+atgctcccactagtgagaactgaagagctctgtgttcctgaaaaccatac
+tgttgacacattcaagtgtttccttaattctttacatctaatgcttcacg
+acctcttggcttacctctgcattttcctactttaaggagtgggtgggagt
+tgttctttttggcgctgccatatgctgtggattggtattaatgctttggt
+tggtttgcaagtttagatctcaacagaaacgtgacaacgtggccatcacc
+caagcactcatgaccattgaacaaggggcctcctctgaagtatggttatc
+catgctacataaataacaggcatttgagtccttagctataggaccccacg
+ggtctgtgtacccattgcactgggatgagtaagactcgatttccttgatc
+agcccttgcacatcgctgagggtatgcccattgcatacgataggttgatc
+atggtctgccaaaaacgagatccttcttgatcattgcgagctggagaggc
+tagcaactagatcattggattaggccataataataaaaaagggggagatg
+tgggaagccacatacgccattacaagatggagctggctactgctggccac
+cgcccgtaagttcaggtaaacaaccaatgtacacatgtgcataagggttt
+tgcaccaagtcacagcccatcctggggaatgtaaatgaggcaataaaagc
+acaaccaatcaggtatagatacgccactcctaggcctgtttaagcagtgc
+cagttttggggcttggggtctttcaccttcgctatcaagctcttccaata
+aatgtgtgcagaagaatcctgttgtggcgtcttccttgctggcgagtagg
+gcgtccacacaaaatcaactcaaaaaaaaaacaaaaaacaaaaaacaaaa
+attgctgggcatggtgcgcatgcctttaatcccagcacttgggaggcaga
+gacaggcaaatttctgagttcgaggccagcctggtctacagagtgagttc
+caggacagccagggctacacagaaaaaccctgtcttgaaaaattaaaaaa
+aaaaaacaaaaaacaatcagtagccctcctttatagaaaccataaacagg
+ctaaaaagaaatcagggaaataatactcttcacaatatccacaaataata
+taaaatatcctggtgtaattctaacaaatcaagtgaaagacctgtatgac
+aagaccctcacgtctccgaagaatgaatgtgaaggaaatatcataagata
+gaaagatttctcatgcataagggtaagtaggattaacacagtgaaaatgg
+ccatctcatcaaaaggaatctacagattcaatgcacttctcatcaaaatt
+cccatacaattctttacagactttgaaagaacaattctcaacttcatatt
+taaaaagaacaaaaaaacaaaaaaccaccaggatagataaaacagttctg
+tacaataaaagaactcccacgggtatcataatcactgatttcaagcagaa
+ctacagagaaagagtaattaaagaaacctgtatggtattggtatagaaac
+acacagattgaccaagggaattgatcagaagaccctgaaataacctacac
+acctctggacacgtaaattttgacaaagaagccaaaaccatacattggaa
+gagagaaagcatcttcaaaaaatggtggcaatctaactgtatgtctgcat
+gtagaagaacgcaaatagattcatattcatctctctgcacaaaactcaag
+tcctagtagatcaaaaaacctcaacataaaatcagatacacaggctggag
+atatggctcagcagttaagtgcactgactgctgttttagaggtcctgagt
+tcacttcccagcaaccacatggtggctcacaaccatctgtaatgggatct
+gatgcacttttctagtgtgtgtctgaagacacctgcaatgcactcatatc
+aataaaaaataaatctttaaaaaaacaaaccaacagatactctaaatcta
+atagaagagaaagtggggagtagccttgaatgcattggtataggaacaac
+ttcctgaagagaacaccaataactaaggcactaaaataaacaattaatga
+gtgggatctcatgcaactggaaaccttctgtaaagcaaaggacactgtca
+taatggcagcctccagaatgggaagattttcagcaaccctaaatcccaca
+gtgggctgatatccaattatatatatatatatatatatatatatattaaa
+aaaaactcaagaagttggacaccagcaaactaaataacccagttaaaaaa
+tgggtacagagctaagcagagaattctcagtagaggaatctctaatggct
+gagaaacacgttaaaaagtttctttggtcatcagggaaatgcaaatcaaa
+gtgactctgagattctaccttacacccacagcacatgcaggcaaggatat
+aggtagggcaatggaaacactccttgcttgctggtgggaatgctaagtta
+tataatcactatggaaatcaatgtggtggtttctcagaataatggggata
+gttttacctcaagtctcagagagatcactcttgggcatatacccaaaaga
+tgttctaccataccacaaggacacttgctcaactacatttgtagcagctt
+tattcataacagccagaaactggaaacaacacagatatccctaagggaca
+aatggataaggaaattgttattcatttacacagcagactattactcagct
+attaaaaacaaggatatcatgaagtttataggcaaattggtgtaacaaga
+aaacttagacttttttcaaaacttactttaagtagagttctcaaatgctt
+caaccttccttctagcccacataccagtggtaggggacaaaaaagataaa
+tagaaaacagggtttgtggccctatttagaagtagttccttggggtagtt
+cccatctttgttgtcaggatatcagcaattgtacttgctagttttgtgtc
+aacttaacacagctggagtcatcacagaaaaaggagcttcagttgaggaa
+atgcctccatgagatccaactgtaaggcattttctcaattagtgatcaag
+agggaaaggccccttgtgggtgggaccatctctgggctggtagtcttggg
+ttctataagagaacaggctgagcaagccaggggaagtaagccagtaaggc
+agtaaagtccatggtttctacatcagctgctgcaccctgacctgcttgag
+tttcaatcctgacttcgtgatgaacagcagtatggaagtgtaagccgaat
+aaaccccttcctccccaacttggttcttggtcatgatgtttgtgcaggaa
+tagaaaccccaactaagacagcagtacaatccaattacaaaacatcaagc
+atgaatcaggacacatggcaagatccaacagaaagcacaaggaaccactg
+aattcatatgaatcagtagaagcagccaaaatcccacagaagttctttgg
+tgcatttctctctatgtagtgaagaccagcagagctttgcaggtcctatc
+aatgcagaagcaccctctcactgtgtgtggggttctatttatcttctttc
+taaatatcacccaccttctcaagcatctgctctcagcaaaacatcacatg
+ccctctgacgagacagcttccagcaaaacattacatgacacaactgaatt
+taaagaaactagaaacttgcacttcatcttcctgagtgacatagtccaga
+accaaaaagatatgcataatatatactcacttataagtggatattagcta
+caaagataccctagagacaatccacagatccagacacactaaataaaaag
+gagggcccaatggagtttgcttgattctcactcagaatggaattagtcat
+cagaagtagatggagaggaaggggattgggaaggatatggggatgaagga
+tcaggtgtagggaaagcctgggagagaggggccaaaagaatgagtaaaat
+ttggtggtgggccaggttgaggaaggggatcatttatgtgatatgctgga
+gatctgggatgggagaggctcctgtgagcctataggggtgacactagttg
+agactcctaacattagggaagatgcaacctaaaatggttacctccttgta
+gccaggcagtactcccaggggagagatgaggatgccaaaccttcagctca
+aaatgtgtcctgcctacaaaaagtgcatggacaaagatggaaaagagact
+gaggaaatagccaactaatgatgggcccaacgtggacagtttccatggat
+aagaactttcactgatactctgttaggcttgcagacaagcctggtttaac
+tgtcgtctgagaggacccatccagcgactctctgaaacagatgcagagac
+ctacagtcaaacattattagccagagctgagggaatattgtagaagagtt
+ggggaaaggattgtgggattgggagagggtagggactccacaaaagacca
+acggagtcaactactaacctggacccttgtgggtttccagagagggaacc
+accaagcacagagcatacatggactagacccacagctcacctccacacat
+atgtagcacaaaggccgcttggccttcatatggatctcccaaagcctgaa
+gtggaggttatccctgaccctgtttcctgacagtggagcctgagtcgcga
+tctgggctgcctcacctagcttcattggaaaggtatgtgtctactcctcc
+agtgactacatgtgccagtaggggttggtcggggaggaaggaagtggtgc
+atggggagaggggcaatgggagggggtcctgggagaagactgggcggggg
+ggctgtgattgggatgaaaagtagctaaatacacaaatgaatggacaaga
+aagaagaaagaaaagtgtccttgaactcactgacagacatattttaaagg
+cagaaaatgacatcaacctgtgcttctcgggtgtattcctttcttctttt
+gatgcccatcaaaatcagtacaaatgaggtttctgcattcttttcatggc
+cacttgacatgcacacagcccagaccagaaactgaatgacatcacccaac
+acaggacccttcagagtttcccagaacgacctgtctaacataacaaggtt
+gctgcctgagtctgttaaaatgagtgagtcgattattcataccatcgctc
+acagtattagaatgaaatgaaaagagcctcgaggaaaagggcaggactgc
+aagcataggagactggactcctccctgaggaagaggaaggaaacccacct
+tgacagattactgcctggatggcggtgataccacatgtgacagacagtgg
+tagatgcagttgtcattttccattggcagagtcagatgttctgaaaactt
+tcaggtaaagtcagacagccccatggggtcaggacagaaaataatagaga
+atagtcagagtacaaagaaaggctaacattccctgctagtcaagcaaggc
+agagagaatgccccccaccctaactgcttgcacagtaaatgtaagcaaga
+tcctgatcttcaacacaagtcattaacaaaaggatgctagcaaaatacta
+gattggtaaggttttaggattaggaagatatcaagtggatggattctagt
+taggtcactggtgctcagaactgagagcaacagaagtaattactacaccc
+aatacagtatgctttaaaagtcttttaaatcaaggggtctcaagtagctt
+aggctcccctgagttggctatgaaggaaaggatgactttgaactccagga
+ttcctgattcctcccccaaaacacagagatgaatgacacaataggcttta
+gctcacttgtctatcatagggctgattaatagaaaatatacgactatttg
+gtgtctgtaagtttatatatgagcaccctgctgtaccctctctatgttgt
+aatgaatgtgttttggtgtacaaggtagcatgtgattcccgacttcatat
+actgttatattttccctaccgattagcatcattaactaggaaatgtttat
+ttattctagatgtggttgcaaactcattgaaaattccagtagctaggaca
+aggtggtctgaagcccatgcttcctgacagtagacttgaatgctgtaagt
+caggctccagctctggctcacaaacacttggtttgactgaagagtgataa
+tataagcaagatcccctgagataggggaggggctgtggaggagaaatcct
+gaaaacaaaaaacaaaaacaaaaaaccaaacagacaaaaaaacctgtgtg
+tattctgtgaatgcaaaactcttgtaaggagtctgtgggtgcagagtctg
+atggcccacgtggaagttcactgagaggcagagcctggaattctgcaggt
+ttagggttagctgtcttaccttgggctggttttaccttcagggtcagtcc
+ttgcctcactctgtagtcggccacacagcttgtgacaatagataaaaacc
+tcccagaatccactgactaggcagaacatgagcttctatcaatccaaaag
+ctaaaatctcatcagatggtatcttagacattgaaaatatctccaatgtc
+tcatagtgcatgcctctatcagactcacaccaatgtatttcaaattttcc
+ttggtcaatgacattatttgttctgtacaaccatgaaactggttccatgt
+tggagtatggaatttggtttaaactaaatctatgttcttagatcatggct
+actcaaatagctgtggactaaacaattctcttagccctttaagaggagaa
+ctgtgcatttttacatgaacataaacctactatgtgtaaatcataagacc
+ccaagagtgccacggcttttgaaatttatattacaacttttcaaaatatt
+tatttatttatttatatgagcattcttttgctgacataccagaagagaac
+atcagatccaataatagacggttgggagccaacaagtggttgctggaatt
+aaactcaggacctttggaagaataggcatgctcttaaccaataagccatc
+tctccttccctatcttacagcttttcaaatacagttgaaaaaattggaga
+attctttctaaaactattaagggtgtgtcactaaacctgaatgtcacatt
+gagggacaaaagaaaatttaaaagagttcagacactgctgataacgtgaa
+ctctaggaagaaaagcacgtgaagagacaacaatgtacagagtctggcag
+attagaaagcaatgcacagagcctggcagatgagcagaggcatttccccc
+ttccctttcagactttccagtgccaccctgtgatctctcatcaccccaag
+tcgtctctcacatctgaaaaggagtcaaaattttggacacaacacatact
+cagaactgttgaggtattattgtctagtgatttttaatctttagtgtaaa
+atcctatttatttggattgtgcaaacactggttcataccaactacaagat
+tattttgtggttttatagccatgtattgtcgcattcaggtcacaaaggtg
+tctatcagaaaatgtgatttgaatcagggcatccgtgagtctaacaattc
+attccaaaggaacaggaactaacatcccacacaacagtttgccctccctc
+acaggattcttgctccttggacactaggaactttaggaagctgtttgagc
+tcaaaccaggagtagtctccaggacataacatacagagggcgctacaagt
+ccaagtgctctgtatgccctgagaatctgactacagtcacgtgagaacgg
+gtcagctaggtaatgatgagtgcgctcccgtcagcatctcgggaacaggc
+agtcagcagacccagcctgcccttgccatcctgttgttttcaaccttctc
+cccttcaaacccgtgcccaggcgcagcggcccagcttaggtcagcacagc
+atctccaggtcagcagcttcctgcctctcaacaagcccgagccagctccc
+tccgtgccgtacctgccaccctgcacagcccctcagacctgaaagaaggc
+gctggtccctgcaccgaactccatctcagaaatccagatgcagcgctgag
+caggacaactgcatacatttgaggagtgaagtttgaaggaagaataagga
+agttcgagtccgatggccctttctaatgacgaaacaggaaccaggactac
+acttcccacaagtcagttggaaggacttacagggaccccacctaagatgt
+cttgtgcattgcctgccttgcggtccagctgtgggcagctgaagttggaa
+agaactaagctgcagcacatgggcagccacagggaaagtgggcttttaaa
+aaagtctttggttacagcaagcgatgttagcctgtgagctgagtttcaca
+gtaatgtttatcacatttccttgttatctctgctaaaacattgtgagatt
+aaagcttcgatctttctttcttttttttttttccccttggttttttaaag
+cacagatttacttatggaatattactaccgaatggaaaattcatgctttc
+attgtttatttaaaatatgaaagcaggaagttaatgtaggagtgggcatt
+atctctttaatatgctatcaaaaccatcccaggtgctgaagacagaatta
+gaaatcaaactgagtcaccacgaagtgttttctgagcacttgctttcctc
+ctctgaatctctcccaagaggaggggcagagctccttggatcacaatggt
+gtgtgtactggctcttcaatttccctctgtgtttggtttgatgttcctta
+ttgattttcctgtctccactgatcctgtcatcattcacatttgataatac
+ttgaacattactggtagctgccttgcacttccctcacttctcctaaacag
+aacaccgagatagttcctcctggaattcaaaggtatcagaaatatgttca
+tatcactgtaaaatgaggtcgatgtattaaagaagttagactggaaactt
+ggagtatggagaattcccatcttttcgtgggaaggtttattcctgtgtag
+ttcatgcttgagttaaagctacaaatggcattacagaaaagtcttcatac
+ttccctgaggcacaataattcaaagccaagctgtttcagagcagagactg
+tgcaaaatcccattccaatttttcttctctagggagtgtgtttgcctagg
+gatcagaacagattccttaacttagaaaaactagagtcaacaagcagtac
+attcacctggacatttgattggcatgtctgtttagaatgaggtcatgagt
+ggtctgtcatccccctgatggctgtagtgaagggcattgccaacaaccag
+aaggacttaacatttctgagcatagttagttttccaatatgtgtatgtgt
+tgaggtttggtatgttgctatgtattgtaatactaaattttatatctgaa
+ggtctaagcttaccatggacctctcacatttaaaaggttctgttgtgcaa
+accttgttccttgattgaaaactattagttaaatcaaatttggtacagcc
+tattactggaaggactagaagtaggtggcttttgagttaggtggtatggg
+gtggagaagagagagaaggaaaagaggccaggaaaaggaggaagaatggg
+tgaagaggatgagctgccatggggggggggtgtacatggctgggagaaac
+attaagtatctgaagtacaccactgggaaggtagccaagaaagcagttag
+aggaagagtaaattaggggttgaaccccagtacttgtcaaagccagatga
+aataacctcgagtctgaacctcttttacttgtaagctagttagggataag
+cccttatgaaagaaaacatttaattggaactggcttacattttcagagag
+tcagttcaatatcatcatggtagaaagcatggtaaggtttaggcagaaat
+gagaggtctacatttttatctgcaggcagcagaagggggtctgtcttctg
+catacagcaaggaagaggctctgggtcacactggccagactcaaccacat
+atatgagttatccaaacaacacctcctgacatgcttcctgtagaaagact
+atacctcaaatcaggccatacctcctaacagtacaacttcccatggacca
+agcatattcaaactatcagtgtctccttgttatacaataatcaaaccact
+aaagattagaatcagttcctcaggaaatagacaagattatgttttcaata
+aaaagatatagactgtgataactctagcttgtgtcaatttgacacaaaat
+caaccagtccgatggccatgtaattcattaccagatttgtgaaacctttc
+agaagcaaggctaataaaccctttcctccccaacttgcttcttggtcatg
+atgtttgtgcagggatagaaaccatgactaagataatttggtactaggaa
+tggggtattcatttgacaacctgactatgttttggggaggactgtggaaa
+gattttggaacttttcgctagaagatccattttgtgttaagtgctctgtg
+gtatgttctataggagcttggaaaataatgttaagaagagtgcagaagat
+ggaggcctggcttgtgaaatttcagagggaatattaaagactcttatcag
+aaaaaaaaagaaaagaaagaaagaaagaaagctgagcaagccagtggagg
+caagccaataagaaacatccctccatggcctctgcatcagctcctgcttc
+ttggcctgcttgagttccagtcctcacttcctttggtgatgaacagaagt
+gtggaggtgtaaactgaataaaccctttcctccccaacttgtttcttggt
+caagatgtttgtgcaggaatagaaaccctgactaagacaattagttacca
+ttgtctaaataacagtctttattcagaatcatctgaaataagtttttata
+tgcaaaagaagtttctctgcatattgagaactatattaagaggtttagaa
+aaatctgatataaacatgagagttctgatttgacttctgactctgaatta
+tgttacttatgttttctgatttataacctgcttctcctgatttattgcca
+tctgtgtaaaaggtaggagctttcgaaaatattgttcatctcaataactg
+aggaagaatccaattagtctgtgtgtgtgtgtgtgtggtttgttgttgtt
+tttgcttttgtggggttttttttgttaatttcttcccccccaaaattatt
+gcaagttccttgccaatccttattgattacctataatgtgataacttcag
+cattagtgtaaggcactgcaatctatgatgggtttattcttggtaattga
+tgaagtgttattctccctctcataatcaaattaaaaaattttctgtatat
+gtttgtaactttttgctctgtttatgtgtttgaaatatctattctaatat
+attatcttttctatatatgagaattcctgtgagggaatgaaagaagccaa
+aaataacacaatctagtttgggattcaagcagtcatcctatatctctttt
+ctaccagagtcaattattttttagattcagcagataattttcatggagta
+cttaagtttgcatcaccttgtaaaatttgaaataaatccccacctcttac
+atccaatccaattgtgggccttagctaattgttgttttaacaaaatctca
+attgtttgattttaccaatgaacacttgggagtcagatgccagggcgaaa
+gcctgatatctcagcgaggcagagaaagcaccttgctgacattctttctc
+agctgatttatctcagaaggaatcctctttctctcatgcctttttaaaca
+acctcctccaaaaataatgtccctcttcctatttcctatgtgtttatcaa
+tcagtccgtcctcctgtctctcttacactctctgctctttccttaataat
+cttatgtttggttcctgtcaatttgttgcatctgaaaggaaataaaactg
+taattcatgtaatgtatgttaaatagcccaaagagttgtttctgagcttt
+gaaacctggggctgagaacatagcagaacagaccaggacatgcccgggca
+agcccatcgcctccctagctcccacccctctgacctaagttaaatgttac
+aggctgctgatgtttaaatggaccaatcatgtgaaaccgcgccaattcct
+cccccagccccactccttttctataaaaccccctagcttccaagcctctt
+ggtcgaatccactgtctcctgttatgtgagatacgtttctacccggagct
+ccgccattaaaaacctcttgttgttacatcaaggtgttgtgttctattcg
+tgattcttgggtgcacgccgaatcgggagctgagtgggggtttccccact
+gagttctttcatttggnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnaccagttctggtattctgtattctggcagctgcc
+actgcggaccgtaaggaccctagtggctgtgggaagacgacggtctattt
+ccccacaggctgcacccttggaagacattccgagggagaccctggagtgc
+ccggggtacggaacagtcaggaggacctggctgttgtctggcagagtgaa
+gaagagtgagtgctcttcctgccagaggagtggagcggaatcccactcca
+tcagaggtagcgtttggctggttgtgtaagtccagacgcagacgagtgtg
+cttggatgtcttagtgttttccgtctctgtcattgtgttgtgtttactct
+tattcttcactatgggacagaccgtgtctactcctttatctttaactaag
+gaccattggacggacgttagggctagaggacaaaatttgtcagtaaaagt
+gaagaaaaagccatggatgactttctgttcctcagaatggcctgtttttg
+gagtaggttggccagcagaaggaactttttacttacctaccataagggct
+gtgaaggccattgtttttcaggaagggccagggtcgcatccagaccaaca
+accgtacatcatggtatgggaggacttggcacgttacccacccccgtggg
+ttcgcccattcctcccgcctctccgccctggcaccaagattctagccatc
+cgagaaaatggtgagaaagagaaaccgaaaccaccgctcgggggagatga
+tgatcgcagcacaccagtgacgaaaccccccaagatctatccagagattg
+aagaaccccctgagtggcccgacacccctcaacccccaccgtatgctccc
+cagccccaacctttagctccttcgggacccctgcctcaggccccggccgg
+aggagggggtccctcccacaggaacaaggagtcggcgaggagtcacccct
+gaggggcctgcggattcaaccgtggcgctccccctcagggctattggggc
+tcctcctgccgatccaaatagtctacagcccctacagtattggccttttt
+cctcttctgacctttataactggaaagctaatcacccccctttttcagaa
+aaccctgcaggactcactgggttggttgaatcattaatgtattcacacca
+gccgacctgggatgactgccagcagcttctgcagactctattctacaacc
+gaggagagagagaggattctcctcgaggctcggaaaaacgtccgagatga
+ggctgggcgccctgtccaaactccagctgagatagatgaaggatttccgc
+taacccggccccgatgggattataatacggcatcaggtagggaacgactg
+tccaattatcgccgggtcctagtggcgggtctcagaggtgctgcccgtca
+gcccacgaatctggccaaggtaagagaggttatgcagggagcgactgagc
+ccccctcagtcttccttgaaaggctcatggaggcttataggagatatacc
+ccattcgaccccacgtctgagggtcaaagggcctcagtaattatggcctt
+cattggccagtcagctcctgacattaggaagaagttacagcgaattgagg
+gcttgcaggattacaccataagggatgtagttagagaggcagagaaagtg
+tatcataggagagaaacagaagatgaaaagttagagagagagaaaagaga
+gaaaagagaagaggaggataggagagacaggaggcaagaaaaggttttga
+ctaggatcctggccgcagtaggagaaagagataatggaagaagaggtaga
+cagtcagggaacctgggagacaaaaggcagcagggaccaaggagacccag
+agaaggcgggcagcgcctggagaggaaccaatgcgcgtattgcaaggaaa
+tgggccactggaagagcgactgtccgaaaaaaaaataagaggtaaaggtg
+ctttctcttggggaagatgaagactagggggaacggggctcggctcccct
+ccccgagcctagggtaactttagaagtggaggggacccctgtggactttc
+tagttgacacaggagccgaattttcagtactcaaaacacctctaggaaaa
+gtaaagaaaaatgaaaaaatcttggtgatcggggccacgggacaaaaatc
+gtatccatggaccacatcccgagtagtagacatagggcgaaatcgagtaa
+ctcattcgtttctagtcattccagagtgtcctatgcctttattggggaga
+gacttactaaccaagttaaaagcacaaataactttcacctctcatcgacc
+ggaggttttctggggaataaaagcaccccagactctagagctgtctttac
+aactaggggaggaatatcgactttaccaaaataaagtaaagccccctgag
+ggattacaggactggttgaattgataccctcaggcgtgggcagagacggg
+aggagtggggatggcaaaactggtcccccctgtggtgattgaacttaagt
+ccggggccacccctataggggtccgacaatatcccatgagcagagaagct
+caagagggtatacgcccccaaatcaacaaactgctccaacaagggatttt
+ggtcccatgcaaatccccttggaacactcctctacttccagtaaaaaaac
+cagggaccagggactatcgtccagtacaggaccttagagaagtcaacaag
+agagttcaggacatacaccccacgggtgccaaatccttataacctcctca
+gcaccttgccacctggtcggacatggtacacagtcctggatctcaaagac
+gcttttttctgtttgaggttacaccccaacagccagcccttgttcgcttt
+cgaatggcgagactccgagagtggacaagccggacagctcacatggacga
+ggctgcctcagggattcaagaactcgcccactttgttcgatgaagcccta
+caccgagatcttgctcttttccgagccaataacccacaggtgactcttct
+gcaatatgtagatgacctgctcctagctgcagaaacactcgaggactgtg
+aaattgggaccccaaaacctcctgggcgagttaggtaagctggggtatcg
+ggcctctgctaaaaaggctcagtaatgccagatagaagtgacctacctag
+gatatgtcttgagagatggacaaaggtggctcacagaagccagaaaacaa
+gctgttatgcagatcccgacccccaaccactgctcgccaggtaagagagt
+tcctggggaccgccgggttttgcagactctggattcccggatttgccaca
+ctggcagctctcttgtatccactaaccaaagagaaaggggaattcacctg
+gaccagagaacatcagctagcctttgaaactctcaaaaaggcactgctgc
+aggctccggcattggccctgccagatttaaacaaacctttcaccctatac
+attgatgaaagaaatggagtggcaaggggattccttacccaggttttggg
+accatggaagcgcccggtagcctacttatcaaagaaactggacgctgtgg
+ccagtggatggccctcctgcctgcgagcgatagcagccacagctgtgcta
+gtaaaagatgctgacaaactgactatgggccagaatnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnntgctagtgtatgcaatggtgtcagcgtttggatgctgat
+tatggggcccacacacctatggtcacttgatcttcgacaagggagctaaa
+accatccagtggaagaaagacggcattttcaacaattggtgctggcacaa
+ctggttgttatcgtgtagaagaatgcgaatcgatccatacttatctcctt
+gtactaaggtcaaatctaagtggatcaaggaacttcacataaaaccagag
+acactgaaacttatagaggagaaagtggggaaaagccttgaagatatggg
+cacaggggaaaaattcctgaacagaacagcaatggcttgtgctgtaagat
+cgagaattgacaaatgggacctaatgaaactccaaggtgttgtgttctat
+tcgtgattcttgggtgcatgccgaatcgggagctgagtgggggtttcccc
+actgagttctttcacatcctctgcctcttgacctatggttgactttattt
+taaccttgcatacattattcaaggagatagctcttggattaaaggcatct
+gctaggactgagccacagcacatctagaaatgggattttcctgtaaataa
+cagaattggagcttaacagtgtgatcagattcctttcaacatttctccat
+tttttttttgtctaaataaaaagggcatggttttaatgcaaacacagtaa
+aacatatttaataaagctatttgtgctaagctttccaacatgctgagctt
+ggttgtatttggaagtcttcttttttttttttttttttttatggtttttc
+cgagacagagtttctctgtgtagccctggctgtcctggaactcactttgt
+agacccggctggcctcgaactcagaaatctgcctgcctctgcctcctgag
+tgcggggattaaaggcgtgcgccaccacacctggctgtatttggaaggct
+taagactaagtatttttgaattcaaaattctgaaaaatgtgtatttaagt
+ctcatatggaatcagcaatttgattgtcctgagcagttcatagtccaaag
+ctgatttttgggaggtgtttgtcagcttagtagcaatcatgcttaggtag
+aacacagtattcaacccaaagttgtccatagtttgtgcagaacttggcgc
+cagaatcttcaaaaatattttctcaatggtagttaactggctagttttgt
+gtcaacttgactcagctggagttatcacagaaaggagcttcagttaagga
+aatgcctccataagatccaatggtaaggcattttctcaattagtgatcaa
+gggggaaaggccccttgtaggtgggaccatctctgggctggtagtcttgg
+gttctataagagagcaggctatgcaagccaggggaagcaagccagtaaag
+aacatccctccatggcctctgcatcagctcctgcttcctgacctgcttga
+tttccagtcctgaatttcttagtgatgaacagtatggaagtgtaagccgt
+atggaagtgtaagccatatggaagtgtaagccatatggaagtgtaagccc
+ttcctccccaacttgcttcttgattatgatgttttgtccaggaatagaaa
+ccctaagacaaattggtaccagcatagtgggttattcctgtgacaacctg
+accatgttttggggaggactgtggaaggactttggaacattgggctatgt
+cacagaccctgtgggtccctttgtctgcgtggaacgggtctctggggcag
+gtgggcaaagcattggcaggtgacagacagactaacaggtgagattgtgt
+agaatctgaatgtattgtcacaaagtgaacaccaatcttatatagtacag
+aaaatacaaagggtagcaggcaaagtacattgaaattacctgatacaaaa
+caaaggaatgacttcaaaaggatttataggaaccaggtacaaggttacag
+taaagataaagcagtcctgcttaggggcagcttagtgacaggtaaggatt
+tcacactctagtgctatacatttgaaccttatgaaggctagcaccagagg
+ggttctgctcttggcagacctcatgaataatgcaatatcacaacccccct
+atctcctagaccttgataaattcctatatgagtgtaaattttaagtaact
+ggagaatctccatttgtcagaagaattcactgacttgcttctaatatgta
+atgtagcctgcactgaagatttctatctcagtgggattccctggctcttt
+cgtggtattccttgtttgcatgcaatttgttactgtccttagtaaacacc
+ttgtagactagctctgagccactggctccgtcttttgtaatgcttaatta
+gttactgaataggttaacttccttactgcattcttacaggattctaagct
+ctgcttctgggagcttggaacactggggagacttaactatctcagaattt
+aatcttaaaaagcttttataataaaataatactaaaagagagttcgtagt
+tccatacaccagactaactcgggaatagggtatgagtatatgggtaaatg
+agaatgccaaagctccaagacgtgagtttccttgaaactcttttcctcgt
+gagtggctccaaggcttttcagcagatttgaccagtgtgcttggcaggac
+tagaatgatccactctgtgttaagagctctgtcagatgatgtgtaggagc
+ttggaagataaggttgagaactgtgcagaagatggaggcctggcttgtga
+aatttcagaggggaaaattaaggactctttttcagggccattgctatttt
+ggagtttgattattctgtggttctggttagctggggctgaagaatcagct
+gtgattaacaagataccagaactactaaagcaaaaactttgcattactgg
+gactattgatgctggttagctggagctaagaaattagtggtgattaagaa
+gagaccagcatcattgaggtgatatcttctgggagtgtttttctgaaagc
+acaaagaggctgtgttccagaaatagccaaggtggtactcctgcagcagc
+aggacttggtaaggtgtaagggtgacccatatggtactggttttgaagtc
+atgaaggggtcacgcagagcagctgaggctcggcactgtgagaggccatg
+gaaggccattggtgaaggtgcagcctcagttgcaattgttggcccaccac
+tgaaggggtcatgcagtgttttggagatgccagtaccatgagatgaccac
+caagaacagcagcagtggagtacaggcatctggagcctagaggacaacgt
+gtgctacaaagggcatggctggagaagtgacccaagcccttggaggatcc
+cagacattggatggttggagattgatttttgcttttgattgtgactgtgc
+cctgttattttcagtcttgaaggaagaaactattttagtgaagcccacag
+ttaaaagacttttaattgtaaaaagactttggattttaaaagagatggat
+attttaaagagattgaaattttaagaatatataaagactgtgggacattg
+aaagttatttagacattggggatgaataagaatgtaagggttgaggctta
+ctagtgatgtgtttgtgtgtcaagttgacaaggggtcaattgtactagct
+ggttttgtgagtcaacttgacacagctggagttatcacagaaaaagaagc
+ttcagttgaggaaatgccttcatgagatccaactgtaaggcattttctca
+attagtgatcaagggggaaaggcttcttgtgggtgggaccatctctgggc
+tggtagtcttgggttctgtaagagagcaggctgagcaagccaggggaagc
+aagccagtaaagaatatccctccatggactctgcatcagctcctgctccc
+tgacctgcttgagttccagtcctgacttctttcagtgatgaacagcaatg
+tggaaatgtaagttgaataaaccctttcctccccaactgcttcttggtca
+tgatgtttgtgcaggaatagaaaccctgactaagacagtgttaccacagt
+ccagctggattctgcattgcagggccccattatcttcttggagacctaac
+aggttagtgttaggaatagtctcagtttactgtaaaaaaacttacacatg
+taaccatcatattaagcaattccctgaaacacttgaagaccacaatatga
+taagtacatgtgaggtacataaattttgttcctagtcgcctgcttcagac
+tcaaacatgaaaacacatacatgaatctaggtgaagcttatgactagaat
+ttgctagtactctatgttacaagaattattaacccctataaaccagtgta
+aaaacacaaaatccagctattatatttataaactataagactagattgaa
+cagctctatcactatgctaactttttccccagctataagacccttgctac
+ttgcagtttctccttgttatacatggttctgctctatttctcttcctcct
+tttcctccccctcctactcttcttactcctctgtcctctcttcttttttt
+ctcctccttccttccccagatcttcaaggcctcttgtccctccttttcct
+tccactgcccagtcataggctctagcctttatttgaccagttaagaatgg
+gcaaatgattcgcatgacatcacctgagtatgtgatcaactgcttgtcaa
+agggtagctcctcttgaggaagcagaattaacaccagaatacaaacagaa
+tccaggcaacccacaacacttccccctttttgtccaataagaaaggctct
+ccctcagatatacattgaacactactataacaattatgcaaattataaac
+tatgatacacacttaccgatccattccatgatatttgtcaatgtagataa
+agtaatctaccatctatcctcccttaaaaagttacaattctgtgcctgaa
+ttatgttttatttaacttgtattcccatctgacatccatccttataaatc
+tagatcatcttccttaatgctaaacaacttaagtttgattatgagattat
+gactagtcttcaattccatcagagatctgagaataaattatatactacct
+gaatctgtaggaagcacaaagacatagcttataaagctatactttgtgga
+gtcagctgactgcctggacagtcccttaatttcttataacattggagcat
+ctgtcttcagacttctggcccagaaccatctaacagtccttaagtgaagc
+aggaattatggaggactagcttatgctgtcttggcaaagcttattagtca
+actatcccacatctgtttgtcctttttggacagtatttttgtctgcatat
+ggattagagcaatttttgtaaagtggctactttgtcatgattgaagcaac
+tcagcccggaggtaatgctgctcaatatcttcctggaagtggaatgggaa
+cactgtcaggagcacacctgtttcgtagtcaaatgaaataatattaaatg
+acatattctatggatctctgatgctgatacttttgaagacgatctaaata
+tgtagcagaactgaattggtgaacattcattatgcttagctattcattat
+ttgaataatcttgaaaacacttattgtaattaattaaattagaatcggat
+atggccatgagttttactatctgactattaacttacattacttaatcatc
+ttaaacagtttgtaatggcagtgattgcaaggactgggtgtaagcctttg
+tgttttgtttttttttaaagattttatttatttaatttatatgatgagta
+tactgtagctatctttagacacaccagaagaggacatcagatcctgttac
+tgatggttgtaagccaccatgtagttgctgggtattgaactcaggacctt
+tggaagaacaacagtcaatgctcttaactactgagccatccctctagccc
+ccaagcctttgtattcttatttgagttgcataggcacaatacctatctaa
+gagtaacaatatcaattttaaattttgtatcaatatacaaaaatttatcc
+taatgaaatccttaaacctgtgtcaatatataaattctgtaccaatgtaa
+gaaatgaaaacttcaatttggcatcaaatataaaggtttctaccaatgta
+agattatggctatacaatgatttaagagtaaatttaatatcctgtgtcta
+tttgtcttttcccccttttttctttccatccccctctcctttactcaaga
+aggaagggtagagaagaggaaaggaaaaagaaatccccgagtctaaactc
+tctttcttccctgtccaaaagttacaatacttgcaggttatcccttgaaa
+tgacagcataattataatttataaaatatcagaaccatccaccagaacct
+aaggggttgggatgaagatcttcttttgcttccttctagctgaatcaggg
+tgaattcccttctgggggcccaaaggaaaataggaaaattggctttgtca
+aaggagggctctcatttgctttccagtctctttgtgctgagaaagttcat
+gccttatctaaagtcctgactgtaacagtctgaaaggctgaatgggtggt
+ctagctgttctggaaatatcctggaagcaagtctttagaggaaaccatct
+caatgtatttgagtacatcaagcaagaagctgaatgtctttcagcagctg
+tagtttttttccaattatagcattaaaaaaaaataaggttaataaagcac
+tatgtaatctatctctggggtgggtctttgttgctcacttttgcctatta
+aactcagctctagcacatatctttaatccaagagctcaattaggtcaact
+ccagataaggggcagaggaaacaaccagcaggcagagagggaacgttgag
+taaacagaaaaagtaccattgaggagaagactatttaaggcagcatggag
+aaggggaaagagccttttccctctggaacattggtggagtaggaaggtga
+gctggctgttttctcttcctctttgggatagcaggctttcaccacagctt
+aaggctcctatgtcttagttattaaaattgaactgctgctattttttgtt
+tttaaaacaacattttggtcctctaacttgtggcaagatcccacccacag
+atggagagatcactccagctagacagagaagctaacagattttgaaaatc
+atctgggatgtcctcaaagagaaagttaaggatgggagctaccacagtag
+aacagttgacaaccttgcacagtgctcctttggatcacttgagcaaatga
+agcaaatgaagagctaattgacttacctgagattggctcaatatagatta
+taattattatcattttggtatttcatactgttctcttaatggctaaagtg
+gttttttatactgctacatccactccagtagtgacaagcacaaaaggctc
+caaaaacctgggcgctgtccccaggcgaaaaggtcacggaaacttagttt
+cctggagccatggcatcctgtataacgagtgatccaatgtccttgctttt
+gttggtagatctatgtgctttcccttaatattgctttattacaagtgctc
+ctaaggattgaattttttgacatatagctaagttagattctaggcagacc
+ttgatccgactctgggcatggatagctaagtcacagccctacacaggaat
+ttaccattatctaggaagaaggaagtttgtgatcttaggaggaaccagag
+tagatacttagaactatagatagctgagttatacccatatacaagtattt
+acaaaggcctagggggaaggtagactatacaatagactagaataggaact
+atggcaagggcacgaagtccctgacttctaagattaagtgaaccttaggt
+gggactgcttttgattcccagttgttaacattgaattttatcccagttgg
+ttcctgccagtcctttgtaggcactcctctgttttgtgtcagatatacct
+tgcctgctatgatatccaactcctttgctttctgtattataaaactgatg
+gttgtttgagacaaattacattcagatccatactcccttgtgtctgtttg
+tcaccctattcccgccaactctatgcccatctgccagaacccctgattcc
+catggattgaggggggccgactaggcccagtccatggcactatacctgtt
+caaaaataaccctatagagatttaggaaaaagatacgaactatgtaatga
+taggataaaagccttaggaggaaaatggagagtcttttgttttttaattt
+aaaattttttattattggatattttctttaaatacatttcaaatgctatc
+ctgaaactcccctataccctccccatgccctgctcccctacccacccact
+cccatttcttggccctggcattccccggtactggggcagataaaggggcc
+tctcttcctagtgactgccaactagtccatcttctgctacatatgcagct
+agagacacaagctccgggggtattggttagttcatattgttgttccacct
+agggttgcagactctttcacctccttgggtgctttctctagctgaaaatg
+gaaagtcttgtaaatgaatatgaccaaaatactccgattcagacaaagga
+atttaagcaagccttaaaaagatttaatatcaaaatattcagacacagac
+tggaatttacacaaaacttagaaagagaaataaataaaaataagaagaat
+attcagtaagggaaagaagaatttagataagagcctaccatgccaccaca
+taatgaaactgaaaaggggtagcccaaagttgttagaaaccaactttagt
+tggcaatcttgtttagtaaatcaattcccagccatccctgccattgcttg
+atgtacacatgaacaaagtggccatgttggcaagatgtgttcatgcttcg
+gttcaaaaacatggtaattcactcaccaaggctgacctggctacagctgc
+tgctggatgccacatctgccatcaccagagaccaaaactgagccccagat
+gtagcaccattcactgaagtgaccagccagcaatacattggagagcttct
+tccatgggaaaaaaagacattttgttcttactggagtagatacttattct
+ggttatgcatttgcctttcctatacatgatccttctggccaaactacaat
+ttatgaccttataaagtgacttatccattgtcatggtattctacacagta
+tgtcttctgaccaagaaacacatttcacacccaaagaattgccacagcag
+ggccccatgatcatggaatccactggtcttaccttgtacaccaccatcct
+gaagtgagatgacatgacagagaaatggaatgtccttttgaagacacagt
+gatagcaccaaataggtggcaggagcatgaatggctaaaacagggttctc
+cagaaagcagtatatgctttgaatcagtattccgtacatggtacagtgtc
+tcccatagctgggaatcatgggtccaggaatcaaggggtagaaagggaac
+aggtccacttactatcatgcctagtgacccactagcaacgtttttacttc
+ctgttcccacaccccaaacttctgctggcctagaagttttgatcccagag
+gtaggacagtaggcctggtgtaaccagagacagagcactgcctgcctcac
+aggaggcctgctctaacctgggacacacagttcaccctggttccagtgag
+gcctgccccaatcctggacacccagaccagttaacaccaaacaaccagat
+ggcaaatgaaaagcagaagaacataactcacaggaggcattgcaatttgg
+caccatcaggacccagttctcctattacagcaatccctggataccctaac
+acaccttaaattccatctcatgaagatgatagagggaggcccttaaagag
+gatataagtaattcccttaaaaaaaaataaaagaaggttctctgctcctc
+cctgtttcagagacagctgcatcttcccatgaggaccagcttgattctgt
+agacgtgatgatgacattctgtgttaatggatttggccatattgggcacc
+tggttatcagggctgccttctgttctgcagctacaaagtggagactgttg
+ccatcaatgacaccttcattaacctcaactaaattgtctacatattacag
+tatgacccatggcaagttcaatgacacagtcaaggctgagaatggcaagc
+ttgtcatcaatgggaaggccaacatcatcttccaggagtgagatcccact
+aatagcaaatgggtggtgctggtgctgactatgttgtggagtctacgggt
+gtcttcaccaccatggaaaaggccagagctcactttaagggtgggatcaa
+aagggtcatcatcttcaccctttctgccgatgcctccatgtttgtgatgg
+ctatgaactacaagaaatatgacaactccctcaagattgtcagcaatcca
+tcctgtactaccaactacttagaccccttggccaggtcatccatgacaac
+tttggcatagtggaagggctcatgaccatggtctatgccatcactgcaat
+tcagaagactatggatggcccctctggaaaggggtggtgtaatggctatg
+gggctgcccagaacttcatccctgcatcaactggtgctggcaaggctgtg
+ggcaagttaattccagagttggtatggccatctgtgttactattcctaac
+atatccagtgtggatttgacatgccacctggagaaacctgccatatatta
+tggcataaagaagttagtgatgcaggcatctgatggcccactgaagggca
+tcctgggctacactaaggaccaacttgtctcctgtgacttcaacagtaac
+tcccactcattcacctttgattctggggctggcattgctctcaatgacaa
+ctttgttaaactcagttcctagaatgacaatgaatatggctatagcaaca
+gggtggaggacctcaagggctacatggcctcctaggagtaagaaatagta
+agaaactattcacccaagcaaggacattgagagcaagtgagaggctctca
+gttgctgaggagtccctgtcctactcggtctccaacactgagcatctcca
+tcccagttaacatcccagacccccataataacaggaaaggcttagggagc
+cctaccatcttgaataccatcaataaagttcactgcacccactgcataaa
+aaaaaaagaaaaagaaaaaggagagaaagaaaaatacagtcaaacaggta
+gaagtccttaaagaggaaagaaataaatatcttaaagaaatacaggaaaa
+tacaatcaaataggtgacggaaatgaacaaaagagtccaagacataaaaa
+tggaaatagaaaatttaaagaaagagaaagaggggtggggccagatcaag
+ccaggttggagcaagcagggccagagtgagcagaagccctaattccaatt
+cccagcaaccacatgatggctcacaatcatctgtatagatatagtgtact
+cacatatataaaataaataaaatcttttttaaaaagtgaaaaaaatcaca
+catggaggcatccctggggatgcaaaacctaagaaagacaacagatacta
+cagacacaaggaccaccagccaaataaaagagatggaagaacgaatatct
+agtatagacgataccataggagatattgatacaccaatcaaagaaactga
+caaacggaaaaagttcctaactcaaaacatccagaaaatttagggcaaaa
+tgaaaaaatacaaacctaatataatagaaatagaagaggaagaacattcc
+cagttcaaacagccagaaaacatcttcagcaaaattatagaagaaaactt
+tcctaatctaaagaaagagatggtcataaacataaacgaagcctacagaa
+caccaaatcaattggaccagaaaataaaatcttcttaccccacaaaaatg
+aaaaacatcaaatgtacaaaagaatgaaagcacattaaaaattttaaggg
+actagggtaaattatcagacctatcagaatgacacatgacttctcaacag
+atactctaaaatccagaagatctcagacagatatcttacaggtcctaaaa
+gaccacagaagccagaccagacaactatacccagcaaatattcaatcaca
+atagatggagaaaccaatatactcatgacaaaactaaacttaataatatc
+tttctactattccatttgtacagacacacacacatgcgcgtgcacacaca
+cacacacacacagagagagagagagagagagaaagagagagagagagaga
+accatttccaagaactaaataacaagaactaacaaccattggtcaataat
+atctcttaataccaaaaatctcaatttctcaataaaatgaaataggctaa
+cagaaggatatgtaaacaggatccatccctctcctgcctataagaaacac
+actttagcaacaaggatagacactacctcaaagtatagggctggggaaaa
+gttttcctagcaaacagtccctgaaccaagctagagtggcaataaaatca
+actttcaaacaaaaggaatcaaaagagatgggggaaaggacacttcatac
+tcatcaaaagaaaaatctaccacgaaggaagtttcaattctgaacattgt
+tgccacaaatgcaagggtaccacattcataaaaccttactaaagctcaaa
+acaaatactgagtcccacataataatcataggagacttcaacacctcacc
+tcacatcaatggacagttcatcaaaacagaaactaaacatagatacaatt
+aaactaacaaaagttaggaaccaaatgtatttatcagataactacagaac
+atttcacgccaaaacaaaatataccttcctctcagcacctcatataacct
+tctccaaaactgaccatacatctggacacagaacaagccgcaacagatac
+aagaatattgaaacaaaccatgcattctatcaaactaccacagaacaagg
+ttggatttccacaacaacagaaacaacagaaatcacacatactcaaggaa
+actgagcaactgtttacacaatgataacttagagaagaaatacactaaaa
+atttgaagtctttctagaatttaatgaaaatgaagacacagtatacctat
+tcccatgggacacagagttactttgggaaagcagtattaatatgaaaaat
+atttagcagaattcatagcattaagtgccttcataaagaaattggaaata
+tattagcaacataacagcacacctgaaaactctagaacaaaaagaaacaa
+acacacccaagaggagttgatggccggaaagaggtaaactcaaggcctaa
+atcagccaattagaacaaagagaacaatacaaggaatcatgaaaaccaag
+agctggttctttgagaaaatcaacatgatagacaaatgcttagtcaaact
+aaaagacacacagccagtatccaaatcaatagaatcagagatgaaaagga
+agacataaaattgaggaaattcactaagttatcagatcttactacaaatg
+catatacacaaaaaaactggaaaacatagacaaaatggataattttatag
+acagataccacataccaaagttaaatgaagatcaggtaagctattccata
+acccattagaaataaaagcattcattaacaaaacaaaacaatacaaacaa
+acaaaaaagtgagggccagatgttgttagttcagaattctacctacctat
+ctacctaccttccttccttttttttttttttttaagattaatttattatt
+ataagtgcactgtagctgtcttcaaaagcaccggaagagggcaacagatc
+tcattataggtggttgtgaaccattatgtggttgcttggatttgaactca
+ggaccatttggaagagcagtcagtgctcttaactgctgagccatctctcc
+agccctctactagtctttcaaagaagaactaataccaaatactccccaaa
+ctatttcaaaaaatagaaacaggaggaacactaccttaatcattctatga
+ggccacagtaaccctgatacataaactacacaaagactcaacaaggaaag
+agaacttaagatccattttacttatgaacattgatgcaaaaatactcaat
+aaaattttcacaaactgaatccaaaaatacaacaaaagcattcagcatga
+tcaaataagcctcatcccagggacatagggatggcccactatataaaaat
+ccatcaaagtaatccacagattcaaagaatttcaatataaacaaaccaaa
+agggggttaaaaaaatcatatgatcatctcattagatgatgaaaaagcct
+ttaataaaatccaacaaccctccaagtcttggaaagagcaagactttgag
+gtacataccgaaatggaacaaaagcaatgtacagcaaaccactatccaat
+atcaaaataaatggaatgaagcagcaattgcactaaaatcaggtagaaga
+caaggctgaacactctctatccattaaatatagtcactgaagtaatagtt
+agagccacaagacaacaaaaggtgatcaaggggattaaaattggaaagga
+agaagtcaaggcatcactattaatggatggcatgatagtatacataagtg
+accccgaaaattctaccagagaagtcctagagctgagaaacaacttcagc
+aaagtggctgtacataaaattaactcaaagatatcagtgacctttcttca
+tgcaaatgataaaaatattctgagaaagaaattagggaaacaatatcctt
+cacaatacctacaaataatataaaatcgcttgatgtaaatctaatcaagc
+aagtgaaagttctgtatgacaataatttcaagtacctgaataaataaatt
+gaagaagatatcagaagatgtaaagatcttccatggtcatggataacaag
+gattaacaaggtgaaaatggtcatcttaccaaaagcaatctatggtttaa
+aaggaatccccatcaaaattccaattctttatagaccttgaaagagcaac
+tttcaattccatatggaaaaacaaaaaataataatagccaaaacaatcct
+gagccataaaataacttcagaaggaatcaccattcctgacctcaagctgt
+actacagaggaattgtgattaaagagtgtacggttttggtacaaagacag
+ccaggtcgatgagtactatagaatcgaaaaatcaaaaataaagctacaca
+catagagtcttgatttttgaaaaagaaaccaaaaccatacaataaatgaa
+agcttcttcaataaatggtgatgggctaactggcctgcatgtagaagaat
+gaaaatagatccctattcatcaccttgtacaaagttcaagtccaagtgga
+tcaaggacctcaacataaaaccagatatacggaatctcatagaagagaaa
+gtaggaaagagcctagaactcattggtacaggggaaatttcctgaatgga
+atgccaatgactcaggctctaagatcaacaattgacagatggggcctcag
+gaaactgaaaagcttctgtaaggcaaaggacagtgtcagtaggagaaatc
+agcaacctatagatagggaacaaatcttcactaacctacatccaataccc
+aaaatatatagagaactcaaggagataacctccaaaacaacaaatgactc
+gattaaaaaatggggtccaccaatgaaggagctagagaaagtaccaaaga
+agctaaagggatctgcaaccctataggtggaacaacattatgaactaacc
+agtaccccggagctcttgactctagctgcatatgcatcaaaagatggcct
+agtcggccatcactggaaagagaggcccattggacacgcaaactttatat
+gccccagtacaggggaacgccagggccataaaaggggagtgggtgggtag
+gggagagggggtgggtggctatgggggacttttggtatagcattgcaaat
+gtaaatgagcgaaatacctaataaaaaatggaaaaaaaaatggggtccaa
+gaactttataaaaggacatactagtttacttctttgtgaatcagagaaaa
+aaagagtcactcccatagaaaacacacaccggatgaagtggaaaatgcct
+acatcacctttagatggatggaataggcagagctcctaccctcaagctac
+taacttctccttatttatttatttttgccttttaataccttcttagacaa
+aaattctttagaaaattccattgttgattaaatgttacacaaaatgggag
+ttacagaacactgtcattgacaagtttaaagcagtgtttcattctatatg
+ctcataataatttgaaagcaacagtttcatatgatcttgctttttgatag
+agcacactatggattgctgttgatatgcaggtgagggccagtgaaatata
+aggctagagtctgtgaatgggcagtgaaataggaagatggagctaagagt
+ttcagagagagaggacaggggaaagacagaaggacagagaagatggagga
+agaggaccaaccagatccatgtggcttgaaatagtcacaggtagctatga
+atatcataaaagagcatagaataaaatagggcaatgtgtccaatctaggt
+gggcagcttgtatcaatatcaattgctctgagttgattgtgtagacgttt
+tgtgggttgaaattttgctgttataaatctaggtttattttgtctgggtg
+tatgtatgtatgtatgtatgtatgtatgtatgtatgtatgtatgtcagcc
+aatgcgtgaagatcagaggacaacattcagagataattacccctttgcat
+ttcattgtactgggaatactaacatgggtacaggttttgttggcaattaa
+gtttgttcccaaagtcatcatgctagctttagccacaaagctttaatctt
+aacatttcttcccttttctccaaccttactttcatctcataaataaaata
+acaacttgaaaggtccatacaagatttaataattacaacactatgaaagc
+tcacagtccatgtgtcacatgacactcaaggcaatctctttgtgtgagct
+cttacaacataagaacaagagactacttttactactcactggtatagaat
+aagtattcttattctaaaacagaagaaacaaaagacacccaggaaagatc
+agccccaaatccagagaacaaacatacaatctgacagctctacttttggc
+atgattgtgtgaatgattccaaagtctttacttaccacacattgcttact
+cttatctggtttctattcagcagggagcttttagtgtctgaagaagtgtt
+aacatattatgaatatttaacatttgtattatttcactcccatttgaact
+actttgtgttgagaaatataagaaagtttaataaagggtttgcaacattt
+tccacatgtggcatttcagtttcgtatgaattatgaggtgtttcacaaat
+tcttagtaagtacaaaagaccttggaacattcttcacacttgtgtggttt
+cactcacagatgaattcttgaatgttgtttaagaccagaagactggtaat
+aggttttgccacattctccacaattgtaatgtttctctccagtaggaatt
+atccggtgttcagatcatgctttggaacttctgatgtatttgccacattc
+tttagatttgtatgttttcttgacaaaatgaatttttgatgatcactaaa
+gtttttgttgaacacttggacatattctttgtatttgtaaatgttgccac
+attatgagttaacttgtgtaaacactggtgtatatttgtagaaaagtctt
+ttccacattaaacgagtatgaaaaatctggcaaattctacaggagttcac
+ttgcacttaacaattgtagggtttctaacctgtgtgtattctcctgtgtt
+cagaaagtaattatggacaatagaggaacaggctacatacttcctaattg
+gagggtttctctcccatatgatttctcttgtggttagaaaatagttctgg
+acattggaagtccttgccacatgcttccactaatagggttggtttgtctc
+tggtatattttacttttagtcaccaggcaacatactatcaattttgtaaa
+taacatttattttatgtacatgagtgctctgcctgcatgtacccctgcat
+acgagaatagggaaacagattccatcatacatgactgtgagccagcatgt
+ggttgccggaacttgaacccaggacagcacaattgaaagtgcagccagtt
+ctcttaactgctgagccatgtctccagccccatgaattttcttatgcttg
+gaaagtcgtgagggataatggaaggctttgccacatacttcacacttgag
+ggttttttttcctgtatgaattaccttgtgtttagtaagtaatgatggat
+aatggaaggccttgtcacatacgtcacacttgtagggtttctctcctgca
+tgaattttcttatggctggaaagttttgaaggataatggaaggccttgcc
+acatatatcacttgtgggggttttcttctgtatgactcatcttatattta
+gaaagtaatgatgagtaatggaaggccttgccttataagtcacaattgta
+gggtttctctccagtgtgacttatcttgtgtttccaaagtactgacggaa
+aatggaaggccttgccacattcctcacacttgtagggtttcttccctgta
+tgatttctcttgtgtttagatagtgatgatgaaaagcggaaggtcatccc
+acatacttcacagttgtatggcttctctcccatatgaattatcccgtgtt
+tagatagtgatgatgaaacatggaagtccttgccacacacttcacactgg
+tatggtttttctcctgtatgaattcacttgtgtttagaaagtagtgatgg
+ataatggaagtccttgccacaatattcacacttgtagggtttttctccag
+tatgcattctcttgtgtattagtagtaatgatgggaagtggcgcgacttt
+ccacatattaacacttgtatggtttctcttttgtacaaattttcttatgc
+ttagaaagtcttaaaggataaatgaaggccttgttatatacttgactgtt
+atagggattctctcctgtatgaactctcttgtgtttagaaactaataatg
+gaatgcagaaggccttgccacatacttcacacttgtagggtttttctcct
+gtctgaattattttgtgatgagaaagtttggatggaacatggaacgcctg
+gccacatatgtcagacttgtagggtttttcttccttatgaattatcttgt
+gtttagaaagtgatgacagagaacggaaagcattttgacatacttcacat
+ttgtatggtttctctcttgtatgcatttttgcatgggtagaaagtcttga
+gggataatcgaaagccttgccacatacttcacacttgtaaggattctctt
+cggtatgaattatcttgtgcttagaaaggagtgataaaatgcggaaggcc
+ttcccacatacttcacacttgtatggtttctcttctgaatggattttctt
+atggttggaaagtcttgatggataatggaaggccttgccacatacctcac
+acttgtggggtttttctcctctatgaattattttgtgatgagaaagtttt
+gatggaacatgaaacgcctggtcacatatatcacacttatagggtttttc
+tcctgtatgaattatcttgtgtttagaaagtaatgatggataatggaagg
+ccttgccacattcttcacatttgtagggtttctctcctgtgtgaattctc
+ttgtgtttagaaagtgaggacagagagcggaaggcctttccacactcttt
+acatttgtatggtttctctcctgtgtgaattctcttgtgtttagatagtg
+atgaaggaaaacagaaggccttcccacatacttcacactggaatggtttc
+tctcctgtatgaattttcttatggttggaaagtcttgatggataataaaa
+ggccttcccacatacttcacacttatagagtttttctcctgtatgaattg
+tcctgtgtttagaaagtagtgatgcaacatggaaggccttgccacatact
+tcacacttgtagggcttctctcctgcacaaattttcttatgtttagaaag
+tcttgaaggataaatgaaggccttgccacataattcactgttatagtaat
+tgtcttttgtatgaattctcttgtgtttagaaaatgatgacagagaacgg
+aaagccttttgacatacttcacacttgtatggtttctctcttgtatgcat
+ttctgcatggttagaaagtcttgagggataatcgaaagccttgccacata
+cttcacacttgtaaggattctcttctgtatgaattatcttgtgcttagaa
+aggagtgataaaatgcggaaggccttcccacatacttcacacttgaatgg
+tttctctcctgaatggattttcttatggttggaaagtcttgatggataat
+ggaaggccttgccacatacctcacacttgtagggtttttctcctctatga
+attattttgtgtttagaaagaaatgatgaaatgtggaaggccttgccaca
+ttcttcacacttgtatggtttctctcctgtatgaattcgcttgtgtttag
+aaaatattgatggataatggaaggctttgccacatactgtacacttgtat
+ggtttctctcctgtatgaactctcttgtgtaccaaaagtaatgatggaaa
+gtggaaggcttttccacatacttcacacttgtatggtttctcttctgaat
+gaatcttcttatgtctggaaagtcttgatggatgttggaaggccttgcca
+cacacttcacacttgtagagattctctcctttatgaattatcttgtgttt
+agaaagtaataatggaatgcagaaggccttgccacaaacttcacatttgt
+aaggtttttctcctgcatgaattctgttctcttcagaacttaatgatgga
+ctatggaaggacttggcacattcttcacacttgtagtaattcattcctaa
+atcaagcatctggtgattttgaaacacttttgtccactcagagactttgc
+cacactctttgcacttatagcattttctttctggtgaggaatgattgaga
+aattagtgaaggtagagcaaaattccgtaaatttataatgcttcttttta
+ataacaaacatttactcatagttgcatttttttataaatgataacctata
+ttcaaatttctaaacctgtattcaatgaagcctaagttaaatcacagaat
+aagtgaaaatcatgtcaccttgtactaaaagaagagcatgactgtttaga
+acatggaaccaaaaatattaatcaaaagaatattaaaatgtaagcaaaac
+ataatatcagctaagaaaacccattatgtatatacaaatcagctcctaac
+agaaatacagaaatctcataactagataaagacaaaatatagaatggtct
+acctttgaatacaccagaacaaacaatatttctatattctatattatata
+atatattaaatatatatgatatagatataaatatattagtatagagttta
+gtttatgaagttatcaataataaattttcaagagttcaagaaagaagctt
+atgcatatctttaggcatggtgggtttgagcagtatgtgaacattatcct
+ggtattattcaaacactgatttttctgcctcatatctacttgccatccac
+acatgatacgtaatatgtattctaagaatttctcttatgaagtttgtgta
+aatattgatcccatttcagtctctaacttgccaagaaaactgacaagcca
+aaagaccaactgtagagaggaaagagttggacatctgcaagcccagggaa
+gaagagaaggctggggctgggggaggagaagaagaaggagagggacagga
+gggaaggaaaggattcacctggaggacggggtctggagagacataatgta
+aagacacacaaagcccagagagccagactaatacaaaaatgcaagtatcc
+tgagaattttggctgggaggtagccagattaacttagattagaactgatc
+attaattgccaggtaattgtcttgtgaatcttatcaaataaatcttatag
+tttcagtccctttcattttggagctaggcagggacagagacaaatcttca
+cttttaagaatgtatgtacacatttttaaatgcattttttatattttata
+ttaaaaaataaacatcagagttaaagactacttagaaataacagatcttt
+ggctgtcctggggaacacaagttaatatcatggtggaagaaaacaaagct
+tatgagattcaaagcatccttaacattagataatttcctttcaaagaaaa
+agacagaaaagtatagctttaaaagatgatttataccacaatattatgtc
+ttaatggctttatattagatcttagaatttcccactctgttctctgattc
+cctcctcctaacacacccgggagcatagaggtagccgctcctcttttcac
+atctgaaggctcttgtatttgctccagacatgtgaccagatatggcttag
+acgaagcaagacctgtttgtgggaaaaggaaacaacattgttagggtatt
+ttcctggaaaataaaatggtcctttccagactgtgtatataatcaatgag
+atgatacaatagaggaatatagaggattcatttttcatatgttttctgat
+gggcacaccagagtccttaggagaaacttaggacttctgtgtcctgagct
+tcatatcccttatttcatgtccttatttataagtacaacttttaaaactg
+aagtgtgtgacagtctctgtaaggtgtaccacttacattctaataacact
+gagacttatggggatgcagggaggaaccaacaccagaagaaatagttgta
+aggtatataaataattctaaattttcttaaaaatagtcctataaacgata
+ttgttggaagcacaggctcccatcagatactgtacaaaaggaggaatttc
+atgctgacaattaatgaaagctctccttacccaggaacacaaggttgctg
+taattctccagcatcacgtccctgtacagatccaactgagcaggctccag
+gcattcccactcctctgcagagaaatcaatggccacatccctgaatgaca
+gcatttcctgaaaaaaagagagagggagagagagagagagaatgaatgag
+aataacacacctttgggatttggtctggtgctgctatgtgttcaaatgct
+aaatctatactaaagatctggctcccacaagacaaacaaattctaaacaa
+cccctgcatttactgtgtaaaccctgctctcaaatttaaaactattagtt
+aaataaaactggcaacagccaattatgtagaaaaatggagggtactatgg
+cttcaatgatcaggctgggagtcaaagtaagaatcatgatgaaagtcggg
+ctatacagagacaccctgtctcaaaaaccaaagggggaaaaaagaatcac
+gatgaggagaaacagggagaaggggaagacgggaggacatgaggtctcca
+tgagacatgatggatcagtagcatatgcccaactgaagtgatccctaaac
+ccccaggaaacactgatggagcagaaataattcaggaaagtctcaatcat
+caaggaattagggagcacagctggagaagtagccagtctagctttagaaa
+aatagattaggcattattcccaagtaattgagcaaaagccaaataaataa
+atcatagtgtgagcctcactcatttggaagctaaactgggatagagacaa
+ccacaattaacttatatactatgcgaattagaaccatcaagaataacata
+aatacaaagaggcatcatgtgcttcttcacagaagtctaaaggtggccct
+aagtgagaactggaacgacttctgatataggtaagtaatatccctaaagt
+tctcctcatctgctgttgttttatgggacatggatgacagaaggtctgac
+aatcttctatggtctaacacttttaaggaccataaacaggagacaacaag
+ggcaactatagtacagtgtgctgaggctggagagatggctcagcagttaa
+gagcactggctactcttcgaaggacatggggttgattactacatcccaca
+tggccactcacaactgtctataactccagttacagaggatcagacaatct
+ctcagacatgaaagcaatcctcctttactataaagcatagaagatctgtg
+cccgtgatttcaggcagacaagcacctggtataggtaagtcagtcagaag
+gcacaagaagtacggtcacacagcatgagagacttgtctatttatgacta
+aaacaataatgtcctttcccatctgataagagtcttgcttttaaaatcag
+gattcctatgtgaatacagttgaccttatttgtctgctacaacccacaga
+gggaatgttttctttctttgtttgtttgtttttaggacagcatgaaaacc
+tgtctagcttaagcagacaataccagaaaggagaaacctggatggggctc
+ctagaagcaggacccacttcctctttcgcaagccccttgcgtgtcttaaa
+agtttcaagccaggttccttttttaacataaaccccatcccatgtttcca
+ggagagctggtgcctgtctgtttgtgtactaataagcagcctcaactgtt
+gttttcaacctctttcctgcctttcttctttttgatctgtgttcacaaat
+ctaacataatccatatttttacaaatgaccatattgcatgcagtaacatc
+accaaataataccacaaattaagcagtgaattgaggagcagaacagagag
+aaactgtgtgccgcaatttcctaagtcttttacttttatgtgtaattaat
+tcattcaaattaaagatgttcatttgtgaccacattaagataacctcaaa
+attaccaaaaagaagaatataaagaaaaataatgtattgggttaaggaat
+atagagatgtttcataatggataagaatagaggaaggaataggaatagag
+tcagacacacaaaattaataaaacaacaattacttttgcagtatgtacgc
+tgactggtaggtcatgcctgtatttttttcctataaaccatatgaccaga
+tttcatagaaaaacaatataaaacatcacgctggaatttccattcagtat
+cctacaagatttctagaaacatttgccaatacacattacttaggatgaac
+actaggaaccaaattttagaagtacaatcataaacttcatcaaagactac
+aaacatctcttaaaggtatgaagaaacatctcaatgccattaaagacaat
+gaaaggaaatatataggaaatgttagacacggtgataacaacaggcatag
+atgaaggagaacaacctccagacaatggcataaattgatcttcaaaaagg
+ctataaaagaaaaaaaaatatacaacaacaacaaaactttgcaaagagaa
+tatagacacatgtcagaaatatccaccatgaccaagttggctttatctct
+taaatgcagggatagttcaccatatgcaagcgaataaatgcaaaaaatga
+catagtcttatagacaataaacacatggtcatttcaagaggggcagaaaa
+gtcttggacaaactccaatatgctttcagggtgtaagtgctacagaatgt
+gagactagaggaatgtttcttcaagggaaggaatgtaaactctgttttcc
+atacaaagcttagagctgattactagtctacttagtcacttatgatatgt
+attttgctaactttgttcctctaggcacatttaggtatgtttttttgtgc
+ttacagtactgaggtaattatcaccagaagagtttacacctaattgtgct
+agtgcttgaatatgcctaaaacaatcaagtggacatcagattccccccat
+ttgaacaagcaactactagtgagttgtgttgggcagactgccttccttcc
+tcccctgccttggtattctgctgcagggatgctgtttgcgagcataagaa
+agggaatggaggttacatatgagtgcatggggaaattgggaagaattgtg
+gggcaataattagggaagtggaagaacataaataggggtctgaaagtaac
+cttgaaccttcaaccccagctccctaccagactgcagtctctcttggtaa
+acccaatagtggtcaccctgatacctaaaccacacaaagactcaagaaag
+aaagagtatttcaaccacttttcctcatgaatatttttttttcttttttt
+ggtttttcgagacagggtttctctgtgtagccctggctgtcctggcactc
+actttgtagaccaggctggcctcgaacctagaaatccgcctgcctctgcc
+tcctgagtgctgggattaaaggtgtgcgccaccacgcccagctccttatg
+aatattgatgcaaaaatactcaataaaatgatcacaaaccaaatccaaga
+atacaccaaaaacataatccaccatgaagtagtcttcatcccaggaatac
+aggggtggttcaatatatgacaatctgtcaatttactccattatataaac
+aaaatgagacaaccaaaagttatatgacaatctccaatgctgagaaaccc
+tttgagaaaattcaaaaccccttcatgttaaaagtcttggagagatcagg
+gatatgaggtgcatacctaaacataataaaagtaatatacagcaagccaa
+tcttaagttaacatcaacttaaatggagagaaacttaaagcaattacact
+aaaatcagggacaagacaaggctgtccactctctccatgtctctataaca
+tattacttgatatatacttgaatatatagccagagcaataagaaaaggaa
+aagagatcaaggggatacaatctggaaaagaaaaatgcaaagtatagcta
+tttacagataatatgatagtatatcagtgacacccccaacaaacaaacaa
+acaaacaaacaaacaaaaaactctaccagagaacttgtagagctgataaa
+tcccttcagcaaagtggctggataaaaaaaatcaactaaaaaaaaaaatt
+gctgggcatggttgtgcatgcctttaatcccagtacttgggatgcagaca
+caggcaaatttctgagttccaggacagccaggggaacacagagaaaccct
+gccttgagaaattaaaaaaaaaaaatcagtaacctttttttatacaaacc
+ataaagaggctaaaaaagaaatcagggaaataatacccttcacaatatct
+gcaaataatataaaatgtcttggtgtaactctaacaaatcaagtgaaaga
+gctgtatgacaagaccttcatgtctctgaagaatgaatgtgaaggatata
+ccgtaagatagaaagatttctcatgcacatgggtaagtagtattaacaca
+gtgaaaatggccatctcatcaaaggcaatctatagattcaatgcacttct
+catcaaaattcccatacaattctttacagactttgaaagaacaattctca
+acttcatattaaaaaagaacaaaaaaacaactcccccccccccagaatag
+aaaaaacagtcctatacaacaaaagaactcccacaggtatcataatccct
+gatttcaagcagaactacagagaaagagtaatgaaagaaacctgtatggt
+attggtatagaaacacacagattgaccaagggaattgatcagaagactct
+gaaataaccaatacacctctggacacgtaaattatgacaaagaagccaaa
+atcatacattggaagagagaaagcatcttcaaaaaatggtggcaatctaa
+ctggatatctgcatgtagaagaacacaaatagattcatattcatcactct
+gcacaaaactcaagtcctagtggatcaaaaaacctcaacataaaaccaga
+tacacaggttggagagatggctcagcagttaagtgctctgactgctcttc
+cagacgttctgacttcaaatcccagcaaccacatagtggctcacaacgat
+ctgtaatgggatctgatgcacttttctaatgtgtgtctgaagagagctgc
+agtgcactcatataaatacaaaataaaactgtaaaaaaccaaaccaacaa
+atactctaagtctaatagaagaggaagtggggagtagccttgaatgcatt
+ggtataggaacaacttactgaacagaacactaataactaaggcactaaaa
+taaacaattaatgagtgggatctcatgcaactggaaaccttctgtaaagc
+aaaggacactgtcatattgacagcctccagaatgggaagattttcagcaa
+cccaaaatctcacagtgggctgatatgcaattatattaaaaaactcaaga
+agttggacagcagcaaacccaataacccagttaaaaaatgggtacagagc
+taagcagagaattctcaacagagggaaacactttaacaagtttctttggt
+catcagggaaatgcaaatcaaagtgactctgagattctaccttacaccca
+cagcacatgcaggcaaggatataggtagggcaatggaaacactccttgct
+tgctggtgggaatgctaagttatataatcactatggaaatcaatgtggag
+gtttctcagaataatggggatagctcttcctcaagtctcagagagatcac
+tcttgggcatatacccaaaagatgtcctaccataccacaaggacacttgc
+tcaactatatttgtagcagctttattcatatcagccagaaactggaaaca
+acacagatatccctaagggacaatggataaagaaattgttattcatttac
+acagcagactattactcagctattaaaaacaaggatatcatgaagattac
+aggcaaattgatggaactagaaaacgtagacttttttcaaaacttacttt
+aagtagagttctcaaatgtttcaaccttctttctagcccacataccagtg
+gttggggacaaaaaagataaatagaaaacaggggttatggccctatttag
+aagtagttccttggggtagttccaatatttgttgtcaggatatcagcaat
+tgtactcgagatagttatgtgtcaacttaacacagctggagtcatcacag
+aaaaaggagcttcaattgaggaaatgcctccatgagatccaactgtaagg
+cattttctcaattagtgatcaagccccttatgggggaccatctctaggct
+ggtaatcttggttctataagagagcaggctgagcaagccaggggaagcaa
+gccagtaaggaacaaccctctatggcctctgcatcagctcctgcttcctg
+acctgcttgagttccagtcctgacgtccttggtgatgaacagcagtatgg
+aagtgtaagccgaataaaccccttcctccccaaattgcttcttggtcatg
+atgttttgtacaggaatagaaaccctgacaaagtcaaattggtaccagca
+tagtggggtattcctgtgacaacctaaccgtgttttgggaacaactgtgg
+aaggactttggaaatttgggcttgaagatccattcattgttaagagctgt
+cagatgttgtgtaggagcttggaagataatgttgagaactgtgcagaaga
+tggaggcctggcttgtgaaatttcagagggaaaattaaagaccctgttca
+gggccattgctattttgattgtggatattctgtacttctggttagttggg
+gttgaagaatcagctgtgattaacaagataccagaactaccaaagcaaaa
+actttgcattactgggactactgatgctggttagctggagctaagaaatt
+agtggtgattaagaagagaccagcatcattgaggaaacatcatctgggaa
+gtgttttctcaaagcacaaagaggctgtgttccagagatagccaaggttg
+tactcctgctgcagcaggacttggtaacgtgtaagggtcacccatgtggt
+actggttttaaaggcatgaaggggtcacgcagagcagctgaggctcggca
+ctgtgagaggccatggaagtccattggtgaaggtgcagccacagttgcaa
+ttgtcggcccaccattgaagaggtcatgcagtgttttggagatgccagta
+ccatgagatgaccaccaagaacagcagcagtggagtacaggcatctggag
+cctagaggacaacgcgtgtgctacaacgggcatagctggagaagtgaccc
+aaacccttggaggatcccagaagatcgtgagttggatcccagacattgga
+tggttggagattgatttttgcttttgattgtgactgtgccctgttatttt
+cagtcttgaaggaagaaactattttagtggagcccacagttaagagaatt
+ttaattgtaaaaagactttggcttataaaagatattggacattttaaagc
+gattgacttttaatgttttaaacttggggatgaataagaaactaagggtt
+gaggtttactagtgatgtgtttgtgtgtcaagttgacaaggggtcaattg
+tactggctagttttgtgtcaacttgacacagctggagttatcacagaaaa
+aggagcttcagttgaggaaatgcctccatgagatccaactgtaaggcatt
+ttctcaattagtgatcaagggggaaaggccccttgtgggtgggaccatct
+ctgggctggtaatcttggttttataagagagcaggctgagcaagccaggg
+gaagtaagccagtaaggaacatcctcccatggtctctgcatcagctcctg
+ctccctgacctgcttaagtttcagtcctgacttccttggtgatgaacagc
+actatggaagtgtaagccaaataaacctcttcctccccaacttgcttctt
+ggtcatgatgtttgtgcaggaatacaaaccccgactaagacagcagtcca
+gtccaattacaaaacatcaagcatgaatcaggacacatagcaagatccaa
+cagaaagcacaaggaaccactgaattcatatgaatcagtagaagcagcca
+aaatcccacagaagttctttggtgcatttctctctatgtagtgaagacca
+gcagagctttgcaggtcctatcaatgcagaagcatcctctcattgtctgt
+ggggtgctatttatcttctttctaaatatcacccacgttctcaagcatct
+gctctcagcaaaacatcacatgccctctgacgagacagcttccagcaaaa
+cattacgtgacacaactgaatttaaagaaactagaaacttgcacttcatc
+ttcctgagtgacttagcccagaaccaaaaggatatgcataatatatactc
+acttataagtggatattagctacgaagatatccatgatacaatcaacaga
+cccagacacactaaataaaaaggagggcccaatggaggatgcttgattct
+cactcttcctgagtgtacaatcatgaaactgattccatgttagagtatgg
+aatttggtttaaactaaatctatgtcctcagatcatggctactcaaattg
+ctctgtactaaactattctcttaacctttcaagaggagaactgtgcattt
+ttgaatgatcataaacatactatgtgtaaaccataagaccgaaagtattt
+ttctttctttctttctttctttctttctttctttctttctttctttcttt
+ctttcttttctttctttgagcattcttttgctgacacaccagaagagaac
+atcagatccaattatagatagtcgggagccaccaagtggttgctgggaat
+taaactcaggacctttggaagaacagccagatatcttaaccactgagcca
+tctctccagttctatcttacagcttttcaaatacagttgaaaaacttggg
+agaattttttctaaaactattaagaagggtgtgtcagtaaacatgaatgt
+cacattaagggataaaggaaaatttaagagagttcagacaatgctgataa
+catgaacacaaagaagaaaagcaagtgaagagacaacaatgtacagactc
+tggcagattagagagcaatgtacagatccttgcagattagagtgcaatgt
+acagagcctggaagatgagcagagccatttcccccttccctttcagactt
+tctagccccccctgccatttctcatcacaccaagtcaagtctctcacatc
+tgaaaaggagtcaaaattttggacacaacacatactcagaattgttgagg
+tattattgtctagtgatttttaatctttagtgtaaaatcctatttatttg
+gattgtgcaaacactggttcataccaactacaagattattttgtggtttt
+atatcccatgtattgtcgcattcaggtcacaaaggtgtctattagaaaat
+cttatttgaatcagggcatccgtgagtctaacaattcgttccaaaggaac
+aggaactaacatcccacacaacagtttgccctccctcacaggattcttgc
+tccttggacactaggaactttaggaagctgtttgagcacaaaccaggagt
+ggtgtccaagacataacgtatagagggtgctacatgtcaagtgctctgta
+tgtcctgagaatctgactacagtcacgtgagaacgggccagctaggtaat
+gatgagtgcgctcttgtcagcatctcaggaacaggcaggcagctgaccca
+gcctgcccttgccatcctgttgttttcagtcttttccccttcaaacccgt
+gcccaggcgcagcggcccagcctaggtcagcacagcatctccaggtcagc
+agcttcttgcctctcaataagcccgagccagctccctccgtgccctacct
+gccaccctgcacagcccctcagacctgaaagatggcgctgctccctgcac
+caacctccatgtcagaaatccagatgtagtgctgaggacaactgcataca
+tttgaggagtgaagtttgaagaaagactaaggaagctcgattccgagggc
+cctttctgatgacctcacaagggacgggactacacttcccacaagtcagt
+tggaaggacttacagggacccacagaagaggtcttgtgcattgcctgcct
+tgcagcccagctctgggcagctgaagttagaaaaaaacaggctgcagcat
+gtgggcagccacagggaaattgggctttaaaaaaagtctttggtcacagc
+acgcgatgttagcctgtgagctgagtttcacagtaatgtttatcgcattt
+ccttgttatctcttctaaaacattgtgagtttaaagctcggatctttttt
+gttgttattgttgtttttggttttttaaaaagcacatctctacttattag
+catcttactacggagtggaaaattaatgctttcatggtttacttaaaata
+tgaaaaaggaagataatgtaagagtgggcattatctctttaagatgttat
+cgaaaccatcccaggtacttaagacagaattagaaatcaaagtgagtcac
+caccaagtattttctgagcacttgctttcctcctctgaatctctcccaag
+aggaggggcacagctcctaggatcacaatggtgtgtgtactggctcttca
+atttccctctgtgtttggtttgatgttctttattgattttcctgtctcca
+ctgatcctgtcatcattcacatttgataatacttgaacattactggtagc
+tgccttgtactttccctcacttctcctaagcagaacactgagatcgttcc
+tcctggaatataaaggtgtcagaaatatgttcatatcactgtaaaacgag
+gtcgatgtattaaagaagttagactggaaacttggagtattgagaattcc
+catcttttcgtgggaaggtttattcctgtgtagttcatgcttgagttaaa
+gctacaaatggcattacagaaaagatttcatacttccctgaggcacaata
+attcaaaagcaagctgtttcagagcagagactgtgcgaaatccctaagta
+ataaaaggattgtctctgaatcctttgggtgagagcaaggatttaaggta
+aacttcctttaagaagcattagttaataaaatactttccacttaggaaac
+aatatacactgaaagattaaaactcttggcttcgaagtatagaagcagaa
+acaataaaaatttttcttacataaggtaaagttacattagccatacctag
+aggcaaaattttctagtgattacagttcacctgaagcaaaactctttgaa
+tttaagcattattttaaacatctgaatagatctgcaacactgttaaaaag
+aaattttcttggacacagggaaaaactttctcaggcactgtttgcaaaac
+acaagaaggccacaagccgctctggggctgcccagagccctgcattgact
+caaaggtaaaatactttttttaatctgagcatcttggccctcctgtaata
+aggaccaattctagaggaacaatgtaaccgtctacgcctctaaagtttga
+tactctttcttaagatgacttacagttaaaatgttcttcacaactttagt
+gttgtgaaaaaattgcccgtactgcagtttcctgccaggcagcaactata
+gccaaagtgattgtctaatctattcacaaagacaaacataactagataac
+tctgtcacagttttgtatgaagtgagctgtattagtgctttcaaaagatg
+attactcttgtaataatcttaattaacaatatatgggtgagtagaaaatc
+ttaaatttgcaatgaaactgcaggctgaagtcagtggaactctggcagtt
+ttaaccataatttttaagtttcttgtgcaaggttaggataatacctacaa
+cccttgggaaagcaaaacccaagtttaaaaaacaatttatcatctttaaa
+atcaatattagaagcattactatcccattacgaagtttggatgccaatta
+atacttatgaatacctattaaagcaagctttactgctttaataaagaggc
+attgttttagatcttatcttaaattttactatttaggataggaaccacat
+taattattatctaaactagaaatatctttagaaacccagcctcttggcct
+gctttatgccacgtgtcggaaggactctaaacttgagttatcaaatttaa
+cactaaccatctatagcaatgtaacaattattaatcttaaccaacaactt
+atgagctggatgtgaaaacatgcagagcacattatcaataaaaaagaacc
+aaatgaagcagttacatttagaccaatcagagaatattaatttttctagc
+tacaatcatagaataaaaggcactttaccattctcaaacacattagtcag
+aaaccatttatcagcttttttactccgaaactaagaggctgtgcactcgc
+ccttatttcctaaaacgaacagtttttccagcaggggccctcctgccacg
+gtgtctgattcctggctgaaacacgtggcagctctcggctttgcagataa
+agttttttataccatctttattatccaacataaaacatagaacattcatt
+catacagactggacacgaacatacatgaattgaacacgagaacaagattg
+gtgcaccagacattagacaagacacaaaagggaacagagtactcctgcta
+taaggcccagagagaaatttctctctgctttttggaacattttcctccct
+catgatgcagtttttattaactgcggcaatccgcctgattattaatttcc
+ttttaataaaccctttcttttctcacgcctaatgtagcttcggagagcca
+cggcctaccgcctgttacccagctcctcttaagcttcactgctgaaccta
+agtgaaccagcgctcgggtttaacgctgtctcagcttagcccataccttc
+tccggtatgaatttcctttatcctttaattatttcatggagctccgaacc
+agcagtgtgctcttccaaaaatcctttgccgtttctcagtcccgcgttgg
+ttcgccaaatgttgtgtccagccagcagaccacaacctgggttctagcct
+ggaaaggcattttggaaacctggaagagaagaggggctaggtggcgagat
+aaagaaatgcagctaagacagttattctgatcaaagctcaattttactgt
+tccgcatgcaattataaagcaggggaaggggggccgattcctgccaatta
+atcttggggtccaatagcagggtgaccacgtgcacggctcagaacagcaa
+agccgcaggtccagcagtgggcgtggcagaacgaatgagcaggaagctcc
+acccctgagcaagcaggtttcaggctgggggaggggagactacacctatc
+caattcttcttctctagggagtgtgtttgcctagggatcagaacagattc
+ctcaacttagaaaaactagagtcaacaagcagtacattcacctggacatt
+tgattggcatgtctgtttagagtgacatcatgagtggtatgtcctccccc
+tgaagactgcagtgaagggtcttgtcagcaaccacaaggatttaacaaag
+ctgagcatagttagttttccaatatgtgtatgtgttgaggtttggtatgt
+tactatgtattgtaatactaaattctatattcgaagttctaagcttacca
+tggacctcttacatttaaaaggttctgttatgcaaaccttgttccttgat
+tgaaaactcttagttaaatcaaattcggtacagtctattactggagggat
+tagaggtaggtggcttctgagttacctggtacggggtggagaagagagag
+aaggaaaaaggccaggaaaagaaggaagaatgggggaagaggacgagctg
+ccatgggggcaagggggtggtgcatggccgggagaaacatcaagtatctg
+aagtacaccactgggaaggtagccaagaaagcagttagaggaagagtaaa
+ttaggggttgaaccccagtacttgtcaaagccagatgaaataacctcgag
+tctgaacctcgtttacttgtaagctagtcagggataagcccttatgaaag
+aaaatatttaattggaactggcttacattttcagagagtcagttcaatat
+cgtcatggtagaaagcatggtaaggtttaggcagaaatgtgaggtctaca
+tttttatctgcaggcagcagaagggggtctgtcttctgcatacagcaagg
+aagaggctctgggtcacactggccagactcgactttatatatgagatatc
+aaagccccacctcctgtcatgcttcctgtagtaagactataccacaaacg
+aggccatacctcctaacagtaccacttcctatggaccaagcatgttcaaa
+ctagcactgtctccttgtcatacaataataaaaccactaaagattagact
+cacttcctcaggaaatagacaagactacgttttcaataaaaagacgtaga
+atgaatgaaaggatgcaagacaaaaagaccatcctgcaacctataagaaa
+cacacttaaacttcagctatcacctcagagaaatgttttataaaaatatt
+ttccaagcaaatggacctcagatgcaagctgttgtagctattctcacatg
+tccaaaatagaattcaaaccaaaattaatcaaacacaaactaatcaaaca
+gagaggaacagtttaaattcatcaaaggaaagatccacaaagatgatgtt
+tcaattcttaacatccacatcacaaatgcaagaacactcacgtctgtaag
+agaaacattacctgcataataccacattggccctaacctcattggagagt
+tcaatacccgattctcaccaattgtcaggttatccagcccaaagctaaac
+ccaaaaacaccatcactgacgatcattaaaacacatcgacctggagggta
+tctacagaacctcttgcccaaaaccgaaagaatacaccttcttttcagct
+cccatggaacttcctctcaaattgagtacatacttggtcacaaagcaact
+ctttccaggcacaaagaaattgaaataacccactaattctgttcatatca
+ccatggattagacctgaatttcaagaacaaaagaaacccttttcttcatc
+tccttcttattttgtttgtttgtttgtttgttttatgagacagggtttct
+ctgtgtagcccttgctgtcctggaattctgtagacaaggctgacctcgaa
+ctaagaggttcacctacctctgcctcccagtgctgggatcaaaggtgtgt
+gccacaacgcccggctcaaaagaaactcttaagaataaagggaagctaaa
+caactctctcctgaatgaaaatagactatcaaagaacagctaaggccaat
+aatccttaattattccacaacaatagaaatagagataacttttccaaact
+cattttaagaagctacagcagccctgatacccaaaccacacagagagtca
+atgaagaaatggaattgcaaattaccaatataaacatagatttaaaaaaa
+tgctcaatatagttctttcaaatccaatctaggaacacatcaaagatgtt
+atacaagatgaccaagtaggattcctcccagacatgaagggaaggttcca
+tatttaaaaaaaaaaaatcagttagtgtaatgtaccatataaacaaactt
+gaaaccacataatcatctcatttcacaccaaaaaaaaaaaaacctttgac
+aagattcaacacaacttaaggataaaagtcttagaaagagaagacataca
+atggacatagctaaatataatacaggtgatttacatcaagcctttagtca
+atgtcttagtcagggtttatattcttgcacaaaatatcatgaccaagaag
+caagttggggaggaaagggattattcagcttacacttccacattgctgtt
+catcaccaaaggaagtcaggacaggaactcacacagggcagaaacctgga
+ggcaggagctgatgcagagctcagtttgatggaaggtgctgctttgcctt
+gctcagcttgctttcttatagaacccacaaataccagcccagcgatggca
+ccacccacaatgggccctcctacccttgatcactaattcagaaaatgcct
+tacagatagatctcatagagcctttcctcaagggagcctcctttttctgt
+aataactccagcttatgtcatgttgacacacaaaaccagccagtacagtc
+aacatcaaactgaatgtagacaatctcaaagcaatttccgtaaagtcagg
+aataaggcaaggttcttcactccctccatatgtattcaatacatatttga
+agttgtagctagagtaattataacactgaacagaacaaggggatccagat
+aaaaaaaggcagaagtcaaagtatcatttgcagagggatataaactacaa
+atggattgagaaaacataatcaggggaacaacaccttttacactagccac
+aaataatataaaatatcatgtgtaaattcttccaggaaaatttaagactt
+gtttgacaaaaatgccatatctttgaaaaaaataggttgaagaatatacc
+agaaagtggtattgtcatactctctaggtccctcaaactttggaataatg
+acacagaaacttgctaatattattttatcttaggccttagctggctacct
+cacagtgagcacatcaaaattaacctgagtattctaggccacatctgcca
+catgacctcttacttttcactcagtcctggcacctgttcctttcacctca
+atatggtgctggagaatcaacctggaaactgattcctctcacagagcctc
+tctctgcccccaaagtgacatcattcctctccagcctcagctattggcca
+ccatttctttattgagacaatcccaaggcaagagagataggtttgcaaaa
+cactgatgcaggtaatgagccattaaaataacaacaccaaagtccataca
+tcacccagttctatgctggtagagaaatcaattcatgaataatacaaaga
+aaacctttatatagtgtacaaaattctatcccaatatctctcccatttag
+tccaatggatggctttttctctgacatcaataaattatatataagaagat
+aaattttacatactattaggtgttgtgtctggccagcagactacaacctg
+ggttctagcctggaaaggcattttggaaacctggaagagaagaggggcta
+ggtggcgagagaaaagaatgtagccaagacagttactctgatcaaggctc
+aaattttattgttgcaacactagttatgaaggaaatgggaggggacccga
+ttcccgccgaataatctctggtccagtagaaaggtgcacgtgtgtggctc
+cgcaggttccagcagtgggcgtggcagaacgaatgagcaggaagctccac
+cccgagcaagcaggtttcaggctaggggaggggagactacaattaggtaa
+gaattacattcacaatatctagtccatttgtgtttcgcaaccttgaagaa
+agtactccaccacttgacgagtcaaagttctatacctgaattactttcca
+ccataactcgaattgccaacctaaaatatatccttttaaatcttaaagca
+ctttcttcaatgctaaataatttagttatagttgatattataactatcta
+gagttcatcctaatcagagatctgacactgataaatagcagctgagaaaa
+caggaagtacagaacaaggaacatccaataatatagaaatggcagagact
+agccgggcagtggtggcgcacacctttaatccctgcactcaggaggcaga
+ggcaggcagatttctgagttcgaggtcagcctggtctacaaagtgagttc
+caggacagccagggctacacagagaaaccctgtctcgaaaaagacaaaca
+aacaaacaatcaaacaaacaaaaaggcagaggctgctagctgcctggaca
+gtcacctaacatttgtctgcaacattagggcatccatcttcatcccagaa
+gcctggagtacctaacaggattcttgaaaagcagggatatagaagaatat
+tcatactttgttactgcaaaatcaactttccaatgttctatttggccaaa
+cattggacgacatgctgtgagtcatctatgcaatcagagttttttgacca
+gtgatttagctttgccatatttaaagaagactgtagatggaggttctgag
+taggcagacattgcttgtttgctgctatttatttgtttacatttgaaaat
+ggctacaggtgggtaaacaaagcttatttttgtaattaactaaacaagta
+cctaacacaattacaggtttgattgaatgactactaacttgcatttcata
+attatcctaaacagtttgaaagagtaactttcaaggcctggaactttaga
+ttacatttttaagtgaacagcttatgtctgatacataaaacatggttgaa
+atataaaataatgtattgtaatataaataactttaaatttgtttgaatat
+attaatctataccaatgtaatttatttggcctgttgatgctctttagtgt
+aaacaaattaaactatctaccctttcatcctattatttatgtatcccctt
+ttcattttcattccccctccaccattttggccctagcacaagatagaaga
+gaaagaagaacagaagaaagaaaaagaaagagatccctgaatctaatcgc
+tttttctttgcttcctctctgactaaaaccattaacatctattgaccaat
+cccccttaaaggatgataaacttccattacccatggaacaaccaaaaatc
+acccacccagactcttggaaatgaggctgttttctcttgaaattgatgta
+catattttaatttttccaaacacatccatctgcctaatttcatttctttg
+gttacctctaggggttttctgtggctggaaatagagcttgattacaaaac
+aaacacacaaacaaacaaactaaaacacatattaatttttttttacattt
+ttcaggttaacttttataaaaatttgaagtttctaatacatttgccatta
+atcattggtctatcttctcatttcttaatgtcaatagtcctggcaaacct
+gcatgagattaaatatgatttacctatattggaagacctctgtttcaggt
+gattagtgtactgccttgttttgtgtcaacttgacacaagctggagttat
+cacaaagaaaggagctttagttgaggaaatgcctccatgagatccagatg
+tggggcattttctcaattagtgaccaacaggggaaggcccaagactaccc
+tgggctggtagtcttgggttctataagaaagaaagctgagcaagccagtg
+gaggcaagccaataagaaaaacatctctccatggcctctgcatctgctcc
+tgcttcctgacttgcttgagttccagtcctgaattcctttggtgatgaac
+agcagtgtggaagtgttaactgaataaatcctttcctccccaacttgttt
+cttggtcaagatgtttgtgcaggaatagaaaccctgactaagacaattag
+ttactgttgtataaataacagtctttattctgaatcatctgaaataagtt
+tttatatgcaaaagaaatttctctgcatattgagagcaactatattaaga
+ggtttagaaaaatctgatataaacatgagaattctgacttgattactgac
+tctgaatatgttacttatgttttctgatttataacctgcttctcctgatt
+tattgccatctgtgtaaaaggtaggagctttcgaaattagtgttcatctc
+aataactgaagaagaatccaattagttttttgttgttgttgttgtgtggt
+ttgttgttgtttttgcttttttggtattttttgttaatttcttccccccc
+aaaattattgcaagctccttgccaatccttattgattacctataatgtga
+taatttcagcaatagtgttaggcactgcaaactctgatggggttattctt
+ggtgattgatgaagtgttattctccctctcataatcaaattaaaaatttt
+tctgtatatgtttgtgtacttttttgctctgtttatgtgtttgaaatatc
+tattgtaagatattatcttttctgtacataagaattcctgagggagaatg
+aaagaagccaaaaataacacaatttagtttaggatccaagcagtcatcct
+atatctcttttctaccagagtcaattattttttagattcagcagataatt
+tcttggagtatttaagtttgcatcaccttgtaaaatttgacataaatccc
+caactcttacatccaatccaattgtgggccttagctaattgttgttttaa
+caaaatctcaattgtttgattttaccaatgaacacttgggagtcagatgc
+cagggcgaaagcctgatatctcagcgaggcagagaaagcaccttgctgac
+attctttctcagctgatttatctcagaaggaatcctctttctcccatgcc
+tttttaaacaacctcctccaaaatgaatgtccctcctcctatttcctatg
+tgtttatcaatcagtctgtcctcctgtctctcttactctctctgctcttt
+ccttagtaatcttatgtttggttcctgtcaatttgttgcatcctctgcct
+cttggcctatggttgactttatttcactgtgcttacattattcaaagaga
+tagctcttggattaaaggcatgtgctaggactgagccacagcacatctag
+aaatgggattttcttgtaaataacaaaattggagcttaacagtgtgatca
+gattccttgcaacatttctccatttttttgtctaaataaaaagggcatgg
+ttttaatgcaaacacagtaaaacaatacataataaagctatttctgctaa
+gttttccaacatgctgagtttggttgtatttggacaccttaagattaagt
+atttttgaattcaaaattctgaaaaatgtgtatttaagtctcatatggaa
+ccagcaatttgattgtcctgagcagttcatagtccaaagctgatttttgg
+gaggtgtttgtcagctttgtagcaatcatgcctaggtagaacacagtatt
+caacccaaagatgtccatagtttgtgcagaacttggaatcagaatcttca
+aaagtagtttctcaatggttagtgttaccacagtccagctggattctgcc
+ttgcagggcccgattatcttcttggagacctaacaggttagtgttaggaa
+tcgtcaaagtttactgtagaaaacttaaacatgtaaatgtcatattcagc
+aattccctgaatcatttgaagaccacaatatgataagtacatctgaggta
+cataaattttgttcctagttgcctgcttcagactcaaacatgaaaacaca
+tacatgaatctaggtgaagcttatgactagaatttgctagtactctatgt
+tacaagaattattaaccccataaacgggtgtaaaagcacaaaatccagct
+attatattcataaactgtaagtctagattgaacagctctatcactatgct
+aactttttccccagctataagacccttgctacttgcagtttctccttgtt
+atacatggttctgctccatttctcttcctccttttcctccccctcctact
+cttcttactcctctgtcctctcttcttcttttctcctccttccttcccca
+gatcttcaagtcctcttgtccctccttttccttcgcactgcccagtcata
+ggctctagcctttatttgaccagttaagaatgggcaaatgattcacatga
+tatcacctgagtatgtgatcaactgcttgtcaaagggtagtatctcttga
+ggaagcagaattagcaccagaatacaaacagaatccaggcaacccacaac
+acttccccctttttgtccaataagaaaggctctccctcagatatacattg
+aacactaccataacaattatgcaaattataaactatgatacacacttacc
+gtccattccatgatatttgtcaatgtagataaagtaatctaccatctatc
+ctcccttaaaaagtttacaattctgtgcctgaattatgttttatttaact
+tgtattcccatctgacatccatccttataaatctagatcatcttccttaa
+tgctaaacaacttaagtttgattatgagattatgactagtcttcaattcc
+atcagagatctgagaataaattatatactacctgaatctgtaggaagcac
+aaagacatagcttataaagctatactttgtggagtcagctgactgcctgg
+acagtcccttaatttcttataacattggagcatctgtcttcagacttctg
+gcccagaaccatctaacagcccttaagtgaagcaggaattatgaaggact
+agcttacagtgtattggcaaagctcattagtcaaccatcccacatctgtt
+tgtcctttttggacagtatttttgtctgcatatggattagagcaattttt
+gtaaagtggctactttgtcatgagtgaagcagctcagcccggaggtaatg
+ctgctcaatatcttcctggaagtggaatgggaacactgtcaggagcacac
+ctgtttcatagtcaaatgaaataatattaaatgacatattctatggatct
+ctgatgcttttgaagaccatctaaatatgtagtataactgaattgctcac
+tctaggggacgccctgagcgaggggaaggactgcaggagtccttctggga
+agggaagtgaagagttgggagtctttctaggttatgcacttccccgactt
+ttttgcatttctgagttggttttctttgtcctttagaatatgggcatttg
+tcagtgtgtgtttgggtttttttggttgttgttgtttttgtctgttttcg
+ggcatttgtcagtgtgtgggtgtgtgtatgtgtctgtctcctgttttcca
+tgatattggacgataggacagactgtaatgatcccccctaagtttgacct
+tagaccactggactgaagttagatcaagggcccataatctttcagtagaa
+attaagaagggaccttggcagactttttgcgcttccaagtggcttttaat
+gtaaaatggccactagaggagacttttgatttgactcatatctttcaagt
+taaagccattgtttttcagagcggacctgggtcccatttggatcaacagc
+cttaccttgtctagaattcaccgccaaaaatcaaactatagattccccgt
+gtgtctcagagccaccccccaccccacccccgctactcccatatgcacgg
+gtgtggcgccacagcattgctgacaacagtggaggcagcagtgaggaccc
+tgactagactactgacctttctggcctggctgtgagagggcactaagggc
+ttgcccttccaagccacttaactcctcctcctgctgctctggctccaagg
+aagagtgctcagcccctagcccaaacaaaactgaaaccacaggctccttt
+gctttctgtataataaaactgatgcttgctttgagacaaattacattcag
+atccacactcccttgtgtctgtcatcccattcccaccaactctatgccca
+tctgccagaaccccggattcccacggattggggggcggggggactaggcc
+cactctgttgcactatacctgttcagaaataatcctatagagatgtagaa
+aaaggatacgaactatgtattgataggataaaagccttaggaggaaaatg
+gagagtcttttattttttaattttttattattgaatattttctttatata
+catttcaaatgatatcctgaaagttccctataccctcccccctgccctat
+tcccctaccctcccattcccacttcttggccctggcattcccctgtcctg
+gggcatataaaggggcctctcttcccagtgatggccgactaggccatctt
+ctgctacgtatgcagatagagacacgagctctggggatataggttagttc
+atatttttgttccacctagggttgcagaccccttcagctctttgggtgct
+ttctctagccgaaaatggagagtcttataaatgaaaatgatgaaaatact
+cagactcagacaaaggaatttaagcaagcgttaaaaagacttacaaaata
+ctcagacacagactagaatttacacgaaacttagaaagacatagaaataa
+gaataaaaaaatattcagtcagggacagaagaatttagataagagcctac
+catgccaccacgtaatgaaactgaaaaggggtagcccaaagttgttagaa
+accaactttagcaggcaatattgtttagtaaatcaattcccagccatccc
+tgccattgcttgatgtgcacatgaacaaactggccatcttggcaagatgt
+gtttatgcttgggttcaaaaacatggtaattcactcaccaaggctaacct
+ggctacagctgctgcaagatgccacatttgccatcaccagagaccaaaac
+tgagccccagatgtagcaccattcactgaggtgaccagccagcaatacat
+tggagagcttcttccatgggaaaaaaagacattttgttcttattggagta
+gatacttattctggttatgcatttgcctttcctatacatgatccttctgg
+ccaaactacaatttttgaccttataaagtgacttatccattgtcatggta
+ttctacacagtatgtcttctgaccaagaaactcatttcacagccaaaaaa
+gtgccacagcaggtccccatgatcatagaatcctctggtcttaccttgca
+caccaccatcctgaagtaagatgacctgacagagagatggaatgtccttt
+tgaagacacagtaatagcaccaaataggtggcaggagcatggatggctag
+aacagggttcttcagaaagcagtatatgctttgaatcagtatcccataga
+tggtacagtatctccaatagctgggaatcatgggtccaggaatcaagggg
+tagaaagggaacaggtccacttactatcatgcctagtgacccactagcaa
+cgtttttacttcctgttcccacaccccaaagttctgctggcctagaagtt
+ttggtcccagaggtaggacagtaggcctggtgtaaccagagacagagctg
+cctgcctcacaggaggcctgctctaacctgggacacacagttcaccctgg
+ttccagtgaggcctgctccaatcctggacacccaggccagttaacacaaa
+acaaccagatggcaaatgaaaagcagaataacataactcacagaaggcat
+tgcaatttggcaccatcaggactcagctctcctattacagcaatccctgg
+ataccctaacacacctgaagtgcaaggttcagaccttaaattccatctca
+tgaagatgatagagggaggcccttaaagaggatataagtaattcccttaa
+aaaaaataaaagaaggttctctgctcctccctgttccagagacagctgca
+tcttcccatgaagggccagcttgattctgtagacgtgatgatgacattct
+gtgttaatggatttggccatatggggcacctggttaccagggctgccttc
+tgttctgcagctacaaagtggagactgttgccatcagtgacaccttcatt
+gacctcaactaaattgtctacatattacagtatgacccatggcaagttca
+atgacacagtcaaggctgagaatggcaagcttgtcatcaatgggaaggcc
+aacatcatcttccaggagtgagatcccactaatagcaaatgggtggtgct
+ggtgctgactatgttgtggagtctacgggtgtcttcaacaccatcgagaa
+ggccagagctcactttaagggtgggatcaaaagggtcatcatcttcaccc
+gttctgctgatgccccctgtttgtgatggctatgaactacaagaaatatg
+acaactccctcaagattgtcagcaacccatcctgtactaccaactactta
+gaccccctggacagatcatccatgacaactttggcatagtggaagggctc
+atgaccatggtctatgccatcactgctattcagaagactatggatggccc
+gtctggaaagcggtggtgtgatggctatggggctgcccagaacttcatcc
+ctgcatacactggtgctgacaaggctgtgggcaaggtcatccacagagct
+ggtatggccatttgtgttactattcctaacatatccagtgtggatctgac
+atgccacctggagaaacctgccatgtatgatgacatatagaaggtggtga
+cgcaggcatttgatggcccactgaagggcatcctgggctacactaaggac
+caacttgtctcctgtgacttcaacagtaactcccactcctccaactttga
+ttctggagctgccattgctctcaatgacaaatttgtaaaactcggttcct
+agaatgacaatgaatatggctacagcaacagggtagaggacctcaagggg
+ctacatggcctcctaggaaataagaaatagtaagaaactattcacccaag
+caaggacactgaaagcaagagagaggctctcagttgctaggagtccctgt
+cctacatggtctccaacactgagcatctccatccctgtttccatcccaga
+cccccataataacaggaaaggcttagggagccctaccatcttgaatacta
+tcaataaagttcactgcaccccctgcataaaaaaaaaagaaaaaggaaag
+aaaggaaaatacagtcaaacaggtagaagtccttaaagaggaaagaaata
+tatatcttaaagaaatacaggaaaatacaatcaaataggtgaaggaaatg
+aacaaaacagtccaagacataaaaatggaaatagaaaagttaaatcgaga
+gaaaaagggggtggggccagagcaagccagattggagcaagtagggccag
+agtgagcagaggtcctaagtccaattcccagcaaccacatgatggctcac
+aaccatctgtacatgtacagtgtactcatatacataaaataaagaaatct
+tttttaaaaagtgaaaaaaaatcacacatggaggcaaccctggagatgga
+aaacctaagaaagacaacaggaactacagacacaagcaccaccagcaaat
+tccaagagatggaagaacgaatctccagtgtagacgataccataggagat
+attgatacaccagtcaaagaaactgacaaatggaaaaagttcctaactca
+aaacatccagaaaatttagggcacaatgaaaaaaacaaacctaataataa
+tagaaatagaagaggaagaacattcccagttcaaagagccagaaaatatc
+ttcaataaaattatagaagaaaacgttcctaatctaaagaaagagatgat
+cataaacataaaggaagcctacagaacaccaaatagattggaccagaaaa
+taaaatcttctccccacacaaaaatcaaaaacatcaaatgtacaaaacaa
+acaaagcatattaaaatttttaagggactagggtaaattatcagacctat
+cagaatgacacatgacttctcaacagatactctaaaatccagaagatctg
+ggacagatgtcttacaggtccaaaaagaccacagaagccagaccagacaa
+atatacccagtannnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+nnnnnnnnnnnnnnnnnnnnnnnnnnaaagtagggaaaaacctcgaagat
+acgggtacaggggaaaaattcctgaatagaacagcaatggcttgtgctgt
+aagatcgagaattgacagatgggacctcataaagttgcaaagcttctgca
+aagcaaaagacactgtcagtaagacaaaaagaccaccaacagattgggaa
+aggatctttacctatcctaaatcagataggggactaatatccaatatata
+taaataactcaagaaggtggacttcagaaaatcaaataaccccattaaaa
+aatggggctcagaactgcacaaagaattctcacctgaggaatactgaatg
+gcagagaagccacctgaaaaaatgttcaacatccttaatcatcagggaaa
+tgcaaatcaaaacaaccctgagattccatctcacaccagtcagaatggct
+aagatcaaaacttcaggtgacagcagatgctggcaaggatgtggagaaag
+aggaacactcctccattgttggtgggattgcaagcttgtacaaccactct
+ggaaatcagtctggcggttcctcagaaaaatggacatagtactacctgag
+gatacagcaatacctcttctgggcatatatacagaagatgttctaactgg
+taagaaggacacatactccactatgttcatagcagccttatttataatag
+ccagaagactgaaagaacacagatgcccctcaacagaggaatggataaaa
+aaaaaaatgtggtacatttacacaattttgggatagctattaaaaagaat
+gaatttaaaaagttcctaggcaaatggatggacctggagggcatcatcct
+gagtgaggtaacacaatcacaaaggaactcacacaatatgtactcactga
+taagtggatattatcccagaaacttaggatacccaagatataagatacaa
+tttgctaaacgcatgaaactcaagaacaaagaccaaagtgtggacactgt
+gccccttcttagaattgggaacaaaacacccatcgaaggagttacagagg
+caaagtttgaagctgtgacgaaaggatggaccatctagagactgccatat
+ccagggattcatcccataatcagcttccaaacgctgacaccattgcatac
+actagcaagattttgatgaaaggacacagatatagctgtctcttgtgaga
+ctatgccagggcctagcaaacacagaagtggatgctcacagtcagctatt
+ggatggatcacagggcccccaatggaggaactagagaaagtacccaagga
+ggtaaagggctctgcaaccctataggtggaacaacattatgaactaacca
+gtaccctggagctcttgactctagctgcatacatatcaaaagatggccta
+gtcggctatcactggaaagagaggaccattggacttgcgcactttatatg
+ccccagtacaggagaatgccagggccaaaaattgggagtgggtgggtatg
+ggagtgggtgggagggtatgggggacttttgggatagcattggaaatgta
+aatgaggaaaatacctaagaaaaaatattaaaaaaaaaaaggaaagcaga
+aagaaaagtgtccttgtactcactgacatatatattttaaaggtagaaaa
+tgacaaaaaagcctgtgcttctcgggtgtattcctttcttcttttgatga
+ccatcaaaatcagtacaaatgaggtttctgcattttttttttcatggcct
+cttgacatgcacacagccgagaccaggaactgaatgacatcacccaacac
+aggacccttcagagtttcccagaatgacctgtctaacatgacagggttcc
+tgcctgagtctgttaaaatcagtgagtcgatcatttataccatcactcac
+agtaacattaggatgaaatgaaaagagcctggaggaaaagggcaggactg
+caagcataggagactggactcctccctgaggaagaggaaggaaacccacc
+ttgacagattactgcctggatggcggagataccacatgtgacagacagta
+gtagatgcagttgtcattttccattggcagagtcagatgttctgaaaact
+ttcaggtaaagtcagacagccccatggggtcaggacagaaaataacagag
+aacagtcagaacacaaagaaagctaacattctctgctagtcaagcaaggc
+agagagaatgccccaccctaaccgcttgcacagtaaatgtaagcaagatc
+ctgatcttcaacacaagtcattaacaaaaagatgctagtgaactattaga
+ttggtaaggttttgggattaggaagatatcgagtggatggattcctgtca
+ggtcactggtgctcagaactgagagcaatagaagtaattactacacccaa
+tacagtatgttttaaaagtcttttaaaaacaagttgtctcatgtagctta
+ggctaacttgaattggctatgaaggagaggatgactttgaactctaggat
+tcctgactcctccccaaaacacagagatgaatcacacaataggctttagc
+tcacttttctatcatggggctgattaatacaaaatatacgactatttgga
+gcctgtaaggttatatatgagcaccctgctgtaccctctctatgttgtaa
+ggaatgtgttttggtgtacaaggtagcatgtgattcctgacttcatatac
+tgttatatttttcctaccgattagcatattaactaggaaatgtttattta
+ttctagatatggttgcaaactcattgaaaattccagtagctaggtcaagg
+tggtctgaagcctatgcttcctgactgtagacttgaatgctgtaagtcag
+gctccagctctggctcacaaacacttggtttgactgaagagtgataatat
+aagcaagatcccctgagatagggggaggggctgtggaggataaatcctga
+acctaccccccccacacacacacaaatacctatgtgtattctgtgaatgc
+aaaactcttgtaaggagtctgtgtgtgcagagtctgatggcccacgtgga
+agttcaccgaggggcagagcctggaattctgcaggttcagggttagctgt
+cttaccttgggctggttttaccttcatggatagtcagtccttgcctcact
+ctgtagtgggccacacagcttgtgacaatagataaaaacctcccagaatc
+cactgactaggcagaacatgagcttctatcaatccaaaagctaaaatctc
+atcagatggtatcttagacattgaaaatatctccaatgtctcagagtgca
+tgcctatttcagactcaaaccaatgtattttaaactttccttggtcaatg
+acattatttgttctgtacaatcatgaaactgattcaatgttggaatatga
+aatttggtttaaattaaatctatgttctcagatcatggctactcaaatag
+ctctggactaatctattctcttaacccttcaagaggagaactgtgcattt
+ttgcatgaacataaacctactatgtgtaaatcataagaccccaagtattt
+atttatttatttacttatgtatttatgtatataagcattcttttgctgac
+ataccagaagagaacatcagattcaattagagatggtcaggagccacgaa
+gtggttgctgggaattaaactcatgacctctggaagaacagccagtgctc
+ttaaccactgagccatctctccagtccaatcttacagcttttcaaataca
+gttgaaaaacttggagaattctttctaaaactattaacggtgtgtcagta
+aacctgaatgtcatattgagggacaaaggaaaatttaagagagttcagac
+aatgctgataacgtgaacacaaagaagaaaagcacgtgaagagacaacaa
+tgtacagagtctggcagattagagagcaatgtacagatcgtgacagagta
+gagagcaatgtacagagcctggcagattacagatgaacagagccatttcc
+cccttccctttcagactttccagccccaccctgccatttctcatcacacc
+aagtcatctctcacatctgaaaaggagtccaaattttggacacaacacat
+actcagaactgttgaggtattattgtctagtgatttttaatctttagtgt
+aaaatcctatttatttggattgtgcaaacactggtttataccaactacaa
+gattattttgtgcttttatagtcaggtattgtcgcattcaggtcacaaag
+gtgtctattagaaaatcttatttgaatcagggcatccacgagtcgaacaa
+ttcattccaaaggaacaggaactaacatcccacacaacagtttgccctcc
+ctcacaggattcttgctccttggacactaggaactttaggaagctttttg
+agctcaaactaggagtagtctccaggacataacctacagagggtgctgga
+tgtccaagtgctctgtatgccctgagaatctgactacggtcacgtgagaa
+cgggccagctaggtaatgatgagcgcgctcccgttagcatctcaggcaga
+ggcagtcagcagacccagcctgcccttgccatcctgttgttttcaaccgt
+atccccttcaaacccgtgcccagacacagcggtccgcctcggtcagcata
+gcacctccaggtcagcagcttcttgcctcacaaaaagcatgagccagctc
+cctccgtgccctacctgccaccctgcacagccccttatacctgaaaagtg
+gcgctgctccctgcactaacctccatctcagaaatctagatgcagctttg
+agtaggacaactgcatacatttgaggagtgaagtttgaagaaagaataag
+gaagcacgagtccgagggccctttctgatgacg
diff --git a/blat/test/urchProt/prot.fa b/blat/test/urchProt/prot.fa
new file mode 100644
index 0000000..7e227f1
--- /dev/null
+++ b/blat/test/urchProt/prot.fa
@@ -0,0 +1,16 @@
+>tgDNAH6
+fsygyeylgnsgrlvitpltdrcyltltgalhlkfggapagpagtgktettkdlgkalaiqtvvfncsdqldfmamg
+kflkglassgawacfdefnridievlsvvaqqittiqkaqqqrvdrfvfegveialkascavfitmnpgyagrtelp
+dnlkalfrpvammvpdyamiaeislysfgfyeakvlskkitstfklsseqlssqdhydfgmravktvisaagnlkre
+npkmaedlivlrairdvnvpkflqddlklfngivsdlfpkikeepidygeldasirkhcsklslkdvdgfvtkciql
+yettvvrhglmlvgpagsgktmcyevlkraltflrgkeavgggnyetvhtyivnpksitmgqlygefdllthewtdg
+ilsslirfgsssmdedsrwyifdgpvdavwienmntvlddnkklclssgeiikltefqrmifevadlavaspatvsr
+cgmvylepsilglkpfvecwlkklpdaiyphkdrlqalfddfleesiefmranckeivssidsnltlnllklldcff
+tpfvpredkddgdaplpqekmdriieliepwfifsliwtvggtvdtdgrtkfdgflrekmkkgniqllmpeegmvfd
+yklddggiskrpsrdddedeegankqicwkhwmsgiaevqispdmqysdiivptsdsvrgahlldmlltnkkqvicv
+gdtgtgktmtisdkllksmpakyisnfisfsartsanqtqdlidskldkrrkgvfgpplgkhfilfiddlnmpalev
+ygaqppielvrqwmdhkgwydrkqigafrelvdigfccamgppgggrnpvtarlmrhfnyvsfiemqrkskvrifst
+ilnswlasnaslkeyanqtvnaaidvyetiitqllptpakshytfnlrdlskvfqgmlmadsskiedlsqllrlwhh
+encrvfqdrlvnnqdrewfsgyleekitkdfgckmdevnprqpmlygdfmianvdnkiyaeitdqekmvnvmeeyle
+dynqvntavmrlvlfedatkhvcrisrvirqplgnalllgvggsgrqsltrlaahmaeydlfqielsknygvnewre
+dlktillkaglenkaivflfsdtqiksesfledinnilnsgdvpnly
diff --git a/blat/test/urchProt/works.fa b/blat/test/urchProt/works.fa
new file mode 100644
index 0000000..9dd73d9
--- /dev/null
+++ b/blat/test/urchProt/works.fa
@@ -0,0 +1,9 @@
+>works
+AKLPVKKVKDLRLHKEDFETLKIIGRGAFGEVAVVKLKNSD
+DVFAMKLLNKWEMLKRAETACFVEERDVLVHGDSRWITNLHYAFQDDDXX
+YLVMDYYSGGDLLTLISKFDDRLPEDMARFYVAEMVLAIDSVHMLRYVHR
+DIKPDNVLLDKHGHIRLADFGSCLRMLPDNTXXXXXXXXXXXXXXXXXLQ
+AMEDGKGRYGPECDWWSLGVCMYEMLFGETPFYAESLVETYGKIMNHKXQ
+FDFPPETEEISEDAKDLILSLICSAEARLGRNGLQDFKDHPFFNDIDWQN
+IRNSEXPYVPDVKSATDTSNFDVDEADLRNSEVLPPSSHAAFTGNHLPFL
+GYTFT
diff --git a/blat/test/v29skips/.cvsignore b/blat/test/v29skips/.cvsignore
new file mode 100644
index 0000000..d7031dd
--- /dev/null
+++ b/blat/test/v29skips/.cvsignore
@@ -0,0 +1 @@
+ex?.psl
diff --git a/blat/test/v29skips/ex1_database.fa b/blat/test/v29skips/ex1_database.fa
new file mode 100644
index 0000000..4745a66
--- /dev/null
+++ b/blat/test/v29skips/ex1_database.fa
@@ -0,0 +1,58 @@
+>FnaSCA2
+ACCCCCGAGAAAGCAACCCAGCGCGCCGCCCGCTCCTCACGTGTCCCTCCCGGCCCCGGGGCCACCTCACGTTCTGCTTC
+CGTCTGACCCCTCCGACTTCCGGTAAAGAGTCCCTATCCGCACCTCCGCTCCCACCCGGCGCCTCGGCGCGCCCGCCCTC
+CGATGCGCTCAGCGGCCGCAGCTCCTCGGAGTCCCGCGGTGGCCACCGAGTCTCGCCGCTTCGCCGCAGCCAGGTGGCCC
+GGGTGGCGCTCGCTCCAGCGGCCGGCGCGGCGGAGCGGGCGGGGCGGCGGTGGCGCGGCCCCGGGACCGTATCCCTCCGC
+CGCCCCTCCCCCGCCCGGCCCCGGCCCCCCTCCCTCCCGGCAGAGCTCGCCTCCCTCCGCCTCAGACTGTTTTGGTAGCA
+ACGGCAACGGCGGCGGCGCGTTTCGGCCCGGCTCCCGGCGGCTCCTTGGTCTCGGCGGGCCTCCCCGCCCCTTCGTCGTC
+GTCCTTCTCCCCCTCGCCAGCCCGGGCGCCCCTCCGGCCGCGCCAACCCGCGCCTCCCCGCTCGGCGCCCGTGCGTCCCC
+GCCGCGTTCCGGCGTCTCCTTGGCGCGCCCGGCTCCCGGCTGTCCCCGCCCGGCGTGCGAGCCGGTGTATGGGCCCCTCA
+CCATGTCGCTGAAGCCCCAGCAGCAGCAGCAGCAGCAGCAGCAACAGCAGCAGCAGCAACAGCAGCAGCAGCAGCAGCAG
+CAGCCGCCGCCCGCGGCTGCCAATGTCCGCAAGCCCGGCGGCAGCGGCCTTCTAGCGTCGCCCGCCGCCGCGCCTTCGCC
+GTCCTCGTCCTCGGTCTCCTCGTCCTCGGCCACGGCTCCCTCCTCGGTGGTCGCGGCGACCTCCGGCGGCGGGAGGCCCG
+GCCTGGGCAGAGGTCGAAACAGTAACAAAGGACTGCCTCAGTCTACGATTTCTTTTGATGGAATCTATGCAAATATGAGG
+ATGGTTCATATACTTACATCAGTTGTTGGCTCCAAATGTGAAGTACAAGTGAAAAATGGAGGTATATATGAAGGAGTTTT
+TAAAACTTACAGTCCGAAGTGTGATTTGGTACTTGATGCCGCACATGAGAAAAGTACAGAATCCAGTTCGGGGCCGAAAC
+GTGAAGAAATAATGGAGAGTATTTTGTTCAAATGTTCAGACTTTGTTGTGGTACAGTTTAAAGATATGGACTCCAGTTAT
+GCAAAAAGAGATGCTTTTACTGACTCTGCTATCAGTGCTAAAGTGAATGGCGAACACAAAGAGAAGGACCTGGAGCCCTG
+GGATGCAGGTGAACTCACAGCCAATGAGGAACTTGAGGCTTTGGAAAATGACGTATCTAATGGATGGGATCCCAATGATA
+TGTTTCGATATAATGAAGAAAATTATGGTGTAGTGTCTACGTATGATAGCAGTTTATCTTCGTATACAGTGCCCTTAGAA
+AGAGATAACTCAGAAGAATTTTTAAAACGGGAAGCAAGGGCAAACCAGTTAGCAGAAGAAATTGAGTCAAGTGCCCAGTA
+CAAAGCTCGAGTGGCCCTGGAAAATGATGATAGGAGTGAGGAAGAAAAATACACAGCAGTTCAGAGAAATTCCAGTGAAC
+GTGAGGGGCACAGCATAAACACTAGGGAAAATAAATATATTCCTCCTGGACAAAGAAATAGAGAAGTCATATCCTGGGGA
+AGTGGGAGACAGAATTCACCGCGTATGGGCCAGCCTGGATCGGGCTCCATGCCATCAAGATCCACTTCTCACACTTCAGA
+TTTCAACCCGAATTCTGGTTCAGACCAAAGAGTAGTTAATGGAGGTGTTCCCTGGCCATCGCCTTGCCCATCTCCTTCCT
+CTCGCCCACCTTCTCGCTACCAGTCAGGTCCCAACTCTCTTCCACCTCGGGCAGCCACCCCTACACGGCCGCCCTCCAGG
+CCCCCCTCGCGGCCATCCAGACCCCCGTCTCACCCCTCTGCTCATGGTTCTCCAGCTCCTGTCTCTACTATGCCTAAACG
+CATGTCTTCAGAAGGGCCTCCAAGGATGTCCCCAAAGGCCCAGCGACATCCTCGAAATCACAGAGTTTCTGCTGGGAGGG
+GTTCCATATCCAGTGGCCTAGAATTTGTATCCCACAACCCACCCAGTGAAGCAGCTACTCCTCCAGTAGCAAGGACCAGT
+CCCTCGGGGGGAACGTGGTCATCAGTGGTCAGTGGGGTTCCAAGATTATCCCCTAAAACTCATAGACCCAGGTCTCCCAG
+ACAGAACAGTATTGGAAATACCCCCAGTGGGCCAGTTCTTGCTTCTCCCCAAGCTGGTATTATTCCAACTGAAGCTGTTG
+CCATGCCTATTCCAGCTGCATCTCCTACGCCTGCTAGTCCTGCATCGAACAGAGCTGTTACCCCTTCTAGTGAGGCTAAA
+GATTCCAGGCTTCAAGATCAGAGGCAGAACTCTCCTGCAGGGAATAAAGAAAATATTAAACCCAATGAAACATCACCTAG
+CTTCTCAAAAGCTGAAAACAAAGGTATATCACCAGTTGTTTCTGAACATAGAAAACAGATTGATGATTTAAAGAAATTTA
+AGAATGATTTTAGGTTACAGCCAAGTTCTACTTCTGAATCTATGGATCAACTACTAAACAAAAATAGAGAGGGAGAAAAA
+TCAAGAGATTTGATCAAAGACAAAATTGAACCAAGTGCTAAGGATTCTTTCATTGAAAATAGCAGCAGCAACTGTACCAG
+TGGCAGCAGCAAGCCGAATAGCCCCAGCATTTCCCCTTCAATACTTAGTAACACGGAGCACAAGAGGGGACCTGAGGTCA
+CTTCCCAAGGGGTTCAGACTTCCAGCCCAGCATGTAAACAAGAGAAAGACGATAAGGAAGAGAAGAAAGACGCAGCTGAG
+CAAGTTAGGAAATCAACATTGAATCCCAATGCAAAGGAGTTCAACCCACGTTCCTTCTCTCAGCCAAAGCCTTCTACTAC
+CCCAACTTCACCTCGGCCTCAAGCACAACCTAGCCCATCTATGGTGGGTCATCAACAGCCAACTCCAGTTTATACTCAGC
+CTGTTTGTTTTGCACCAAATATGATGTATCCAGTCCCAGTGAGCCCAGGCGTGCAACCTTTATACCCAATACCTATGACG
+CCCATGCCAGTGAATCAAGCCAAGACATATAGAGCAGTACCAAATATGCCCCAACAGCGGCAAGACCAGCATCATCAGAG
+TGCCATGATGCACCCAGCGTCAGCAGCGGGCCCACCGATTGCAGCCACCCCACCAGCTTACTCCACGCAATATGTTGCCT
+ACAGTCCTCAGCAGTTCCCAAATCAGCCCCTTGTTCAGCATGTGCCACATTATCAGTCTCAGCATCCTCATGTCTATAGT
+CCTGTAATACAGGGTAATGCTAGAATGATGGCACCACCAACACACGCCCAGCCTGGTTTAGTATCTTCTTCAGCAACTCA
+GTACGGGGCTCATGAGCAGACGCATGCGATGTATGCATGTCCCAAATTACCATACAACAAGGAGACAAGCCCTTCTTTCT
+ACTTTGCCATTTCCACGGGCTCCCTTGCTCAGCAGTATGCGCACCCTAACGCTACCCTGCACCCACATACTCCACACCCT
+CAGCCTTCAGCTACCCCCACTGGACAGCAGCAAAGCCAACATGGTGGAAGTCATCCTGCACCCAGTCCTGTTCAGCACCA
+TCAGCACCAGGCCGCCCAGGCTCTCCATCTGGCCAGTCCACAGCAGCAGTCAGCCATTTACCACGCGGGGCTTGCGCCAA
+CTCCACCCTCCATGACACCTGCCTCCAACACGCAGTCGCCACAGAATAGTTTCCCAGCAGCACAACAGACTGTCTTTACG
+ATCCATCCTTCTCACGTTCAGCCGGCGTATACCAACCCACCCCACATGGCCCACGTACCTCAGGCTCATGTACAGTCAGG
+AATGGTTCCTTCTCATCCAACTGCCCATGCGCCAATGATGCTAATGACGACACAGCCACCCGGCGGTCCCCAGGCCGCCC
+TCGCTCAAAGTGCACTACAGCCCATTCCAGTCTCGACAACAGCGCATTTCCCCTATATGACGCACCCTTCAGTACAAGCC
+CACCACCAACAGCAGTTGTAAGGCTGCCCTGGAGGAACCGAAAGGCCAAATTCCCTCCTCCCTTCTACTGCTTCTACCAA
+CTGGAAGCACAGAAAACTAGAATTTCATTTATTTTGTTTTTAAAATATATATGTTGATTTCTTGTAACATCCAATAGGAA
+TGCTAACAGTTCACTTGCAGTGGAAGATACTTGGACCGAGTAGAGGCATTTAGGAACTTGGGGGCTATTCCATAATTCCA
+TATGCTGTTTCAGAGTCCCGCAGGTACCCCAGCTCTGCTTGCCGAAACTGGAAGTTATTTATTTTTTAATAACCCTTGAA
+AGTCATGAACACATCAGCTAGCAAAAGAAGTAACAAGAGTGATTCTTGCTGCTATTACTGCTAAAAAAAAAAAAAAAAAA
+A
diff --git a/blat/test/v29skips/ex1_query.fa b/blat/test/v29skips/ex1_query.fa
new file mode 100644
index 0000000..d7f68ae
--- /dev/null
+++ b/blat/test/v29skips/ex1_query.fa
@@ -0,0 +1,58 @@
+>genomicMrnaSCA2
+ACCCCCGAGAAAGCAACCCAGCGCGCCGCCCGCTCCTCACGTGTCCCTCCCGGCCCCGGGGCCACCTCACGTTCTGCTTC
+CGTCTGACCCCTCCGACTTCCGGTAAAGAGTCCCTATCCGCACCTCCGCTCCCACCCGGCGCCTCGGCGCGCCCGCCCTC
+CGATGCGCTCAGCGGCCGCAGCTCCTCGGAGTCCCGCGGTGGCCACCGAGTCTCGCCGCTTCGCCGCAGCCAGGTGGCCC
+GGGTGGCGCTCGCTCCAGCGGCCGGCGCGGCGGAGCGGGCGGGGCGGCGGTGGCGCGGCCCCGGGACCGTATCCCTCCGC
+CGCCCCTCCCCCGCCCGGCCCCGGCCCCCCTCCCTCCCGGCAGAGCTCGCCTCCCTCCGCCTCAGACTGTTTTGGTAGCA
+ACGGCAACGGCGGCGGCGCGTTTCGGCCCGGCTCCCGGCGGCTCCTTGGTCTCGGCGGGCCTCCCCGCCCCTTCGTCGTC
+CTCCTTCTCCCCCTCGCCAGCCCGGGCGCCCCTCCGGCCGCGCCAACCCGCGCCTCCCCGCTCGGCGCCCGCGCGTCCCC
+GCCGCGTTCCGGCGTCTCCTTGGCGCGCCCGGCTCCCGGCTGTCCCCGCCCGGCGTGCGAGCCGGTGTATGGGCCCCTCA
+CCATGTCGCTGAAGCCCCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAACAGCAGCAGCAGCAGCAGCAG
+CAGCAGCCGCCGCCCGCGGCTGCCAATGTCCGCAAGCCCGGCGGCAGCGGCCTTCTAGCGTCGCCCGCCGCCGCGCCTTC
+GCCGTCCTCGTCCTCGGTCTCCTCGTCCTCGGCCACGGCTCCCTCCTCGGTGGTCGCGGCGACCTCCGGCGGCGGGAGGC
+CCGGCCTGGGCAGAGGTCGAAACAGTAACAAAGGACTGCCTCAGTCTACGATTTCTTTTGATGGAATCTATGCAAATATG
+AGGATGGTTCATATACTTACATCAGTTGTTGGCTCCAAATGTGAAGTACAAGTGAAAAATGGAGGTATATATGAAGGAGT
+TTTTAAAACTTACAGTCCGAAGTGTGATTTGGTACTTGATGCCGCACATGAGAAAAGTACAGAATCCAGTTCGGGGCCGA
+AACGTGAAGAAATAATGGAGAGTATTTTGTTCAAATGTTCAGACTTTGTTGTGGTACAGTTTAAAGATATGGACTCCAGT
+TATGCAAAAAGAGATGCTTTTACTGACTCTGCTATCAGTGCTAAAGTGAATGGCGAACACAAAGAGAAGGACCTGGAGCC
+CTGGGATGCAGGTGAACTCACAGCCAATGAGGAACTTGAGGCTTTGGAAAATGACGTATCTAATGGATGGGATCCCAATG
+ATATGTTTCGATATAATGAAGAAAATTATGGTGTAGTGTCTACGTATGATAGCAGTTTATCTTCGTATACAGTGCCCTTA
+GAAAGAGATAACTCAGAAGAATTTTTAAAACGGGAAGCAAGGGCAAACCAGTTAGCAGAAGAAATTGAGTCAAGTGCCCA
+GTACAAAGCTCGAGTGGCCCTGGAAAATGATGATAGGAGTGAGGAAGAAAAATACACAGCAGTTCAGAGAAATTCCAGTG
+AACGTGAGGGGCACAGCATAAACACTAGGGAAAATAAATATATTCCTCCTGGACAAAGAAATAGAGAAGTCATATCCTGG
+GGAAGTGGGAGACAGAATTCACCGCGTATGGGCCAGCCTGGATCGGGCTCCATGCCATCAAGATCCACTTCTCACACTTC
+AGATTTCAACCCGAATTCTGGTTCAGACCAAAGAGTAGTTAATGGAGGTGTTCCCTGGCCATCGCCTTGCCCATCTCCTT
+CCTCTCGCCCACCTTCTCGCTACCAGTCAGGTCCCAACTCTCTTCCACCTCGGGCAGCCACCCCTACACGGCCGCCCTCC
+AGGCCCCCCTCGCGGCCATCCAGACCCCCGTCTCACCCCTCTGCTCATGGTTCTCCAGCTCCTGTCTCTACTATGCCTAA
+ACGCATGTCTTCAGAAGGGCCTCCAAGGATGTCCCCAAAGGCCCAGCGACATCCTCGAAATCACAGAGTTTCTGCTGGGA
+GGGGTTCCATATCCAGTGGCCTAGAATTTGTATCCCACAACCCACCCAGTGAAGCAGCTACTCCTCCAGTAGCAAGGACC
+AGTCCCTCGGGGGGAACGTGGTCATCAGTGGTCAGTGGGGTTCCAAGATTATCCCCTAAAACTCATAGACCCAGGTCTCC
+CAGACAGAACAGTATTGGAAATACCCCCAGTGGGCCAGTTCTTGCTTCTCCCCAAGCTGGTATTATTCCAACTGAAGCTG
+TTGCCATGCCTATTCCAGCTGCATCTCCTACGCCTGCTAGTCCTGCATCGAACAGAGCTGTTACCCCTTCTAGTGAGGCT
+AAAGATTCCAGGCTTCAAGATCAGAGGCAGAACTCTCCTGCAGGGAATAAAGAAAATATTAAACCCAATGAAACATCACC
+TAGCTTCTCAAAAGCTGAAAACAAAGGTATATCACCAGTTGTTTCTGAACATAGAAAACAGATTGATGATTTAAAGAAAT
+TTAAGAATGATTTTAGGTTACAGCCAAGTTCTACTTCTGAATCTATGGATCAACTACTAAACAAAAATAGAGAGGGAGAA
+AAATCAAGAGATTTGATCAAAGACAAAATTGAACCAAGTGCTAAGGATTCTTTCATTGAAAATAGCAGCAGCAACTGTAC
+CAGTGGCAGCAGCAAGCCGAATAGCCCCAGCATTTCCCCTTCAATACTTAGTAACACGGAGCACAAGAGGGGACCTGAGG
+TCACTTCCCAAGGGGTTCAGACTTCCAGCCCAGCATGTAAACAAGAGAAAGACGATAAGGAAGAGAAGAAAGACGCAGCT
+GAGCAAGTTAGGAAATCAACATTGAATCCCAATGCAAAGGAGTTCAACCCACGTTCCTTCTCTCAGCCAAAGCCTTCTAC
+TACCCCAACTTCACCTCGGCCTCAAGCACAACCTAGCCCATCTATGGTGGGTCATCAACAGCCAACTCCAGTTTATACTC
+AGCCTGTTTGTTTTGCACCAAATATGATGTATCCAGTCCCAGTGAGCCCAGGCGTGCAACCTTTATACCCAATACCTATG
+ACGCCCATGCCAGTGAATCAAGCCAAGACATATAGAGCAGTACCAAATATGCCCCAACAGCGGCAAGACCAGCATCATCA
+GAGTGCCATGATGCACCCAGCGTCAGCAGCGGGCCCACCGATTGCAGCCACCCCACCAGCTTACTCCACGCAATATGTTG
+CCTACAGTCCTCAGCAGTTCCCAAATCAGCCCCTTGTTCAGCATGTGCCACATTATCAGTCTCAGCATCCTCATGTCTAT
+AGTCCTGTAATACAGGGTAATGCTAGAATGATGGCACCACCAACACACGCCCAGCCTGGTTTAGTATCTTCTTCAGCAAC
+TCAGTACGGGGCTCATGAGCAGACGCATGCGATGTATGCATGTCCCAAATTACCATACAACAAGGAGACAAGCCCTTCTT
+TCTACTTTGCCATTTCCACGGGCTCCCTTGCTCAGCAGTATGCGCACCCTAACGCTACCCTGCACCCACATACTCCACAC
+CCTCAGCCTTCAGCTACCCCCACTGGACAGCAGCAAAGCCAACATGGTGGAAGTCATCCTGCACCCAGTCCTGTTCAGCA
+CCATCAGCACCAGGCCGCCCAGGCTCTCCATCTGGCCAGTCCACAGCAGCAGTCAGCCATTTACCACGCGGGGCTTGCGC
+CAACTCCACCCTCCATGACACCTGCCTCCAACACGCAGTCGCCACAGAATAGTTTCCCAGCAGCACAACAGACTGTCTTT
+ACGATCCATCCTTCTCACGTTCAGCCGGCGTATACCAACCCACCCCACATGGCCCACGTACCTCAGGCTCATGTACAGTC
+AGGAATGGTTCCTTCTCATCCAACTGCCCATGCGCCAATGATGCTAATGACGACACAGCCACCCGGCGGTCCCCAGGCCG
+CCCTCGCTCAAAGTGCACTACAGCCCATTCCAGTCTCGACAACAGCGCATTTCCCCTATATGACGCACCCTTCAGTACAA
+GCCCACCACCAACAGCAGTTGTAAGGCTGCCCTGGAGGAACCGAAAGGCCAAATTCCCTCCTCCCTTCTACTGCTTCTAC
+CAACTGGAAGCACAGAAAACTAGAATTTCATTTATTTTGTTTTTAAAATATATATGTTGATTTCTTGTAACATCCAATAG
+GAATGCTAACAGTTCACTTGCAGTGGAAGATACTTGGACCGAGTAGAGGCATTTAGGAACTTGGGGGCTATTCCATAATT
+CCATATGCTGTTTCAGAGTCCCGCAGGTACCCCAGCTCTGCTTGCCGAAACTGGAAGTTATTTATTTTTTAATAACCCTT
+GAAAGTCATGAACACATCAGCTAGCAAAAGAAGTAACAAGAGTGATTCTTGCTGCTATTACTGCTAAAAAAAAAAAAAAA
+AAAA
diff --git a/blat/test/v29skips/ex1_reference.psl b/blat/test/v29skips/ex1_reference.psl
new file mode 100644
index 0000000..506312a
--- /dev/null
+++ b/blat/test/v29skips/ex1_reference.psl
@@ -0,0 +1,6 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+4478	3	0	0	1	3	0	0	+	genomicMrnaSCA2	4484	0	4484	FnaSCA2	4481	0	4481	2	699,3782,	0,702,	0,699,
diff --git a/blat/test/v29skips/ex2_database.fa b/blat/test/v29skips/ex2_database.fa
new file mode 100644
index 0000000..fdb88f8
--- /dev/null
+++ b/blat/test/v29skips/ex2_database.fa
@@ -0,0 +1,54 @@
+>FnaDOCK5
+CATGAGAAAGGAAATCGGCTTTAGAATCCGGGACATGTGGTATAACCTGGGTCCCCACAAAATCAAATTCATCCCATCCA
+TGGTGGGTCCCATTCTGGAGGTCACTCTGACCCCTGAAGTAGAGCTCCGGAAAGCCACAATCCCCATTTTCTTTGATATG
+ATGCAGTGTGAGTTCAATTTCAGTGGAAATGGCAATTTCCATATGTTTGAGAATGAGCTGATCACAAAGCTGGACCAGGA
+GGTAGAAGGGGGCAGAGGAGACGAACAATACAAGGTTCTTCTGGAAAAACTGCTCCTAGAACATTGCCGGAAACACAAAT
+ACCTCTCCAGCTCTGGGGAGGTCTTCGCCCTCCTGGTCAGCAGCCTCTTAGAGAACCTGCTGGACTATAGAACCATCATC
+ATGCAAGATGAGAGCAAGGAGAACCGTATGAGCTGCACTGTGAACGTGCTGAACTTTTATAAAGAAAAGAAGAGAGAGGA
+CATATACATAAGATATCTGTACAAGCTTCGAGATTTGCACCGAGACTGTGAGAACTACACAGAAGCTGCCTACACGCTTC
+TCTTGCACGCTGAGCTTCTGCAGTGGTCTGACAAGCCCTGTGTGCCTCATTTGCTTCAGAGGGACAGTTACTATGTTTAT
+ACCCAGCAAGAGCTTAAAGAGAAGCTGTATCAAGAAATCATATCATATTTCGACAAAGGCAAAATGTGGGAGAAGGCCAT
+CAAGCTGAGCAAAGAGTTGGCTGAGACTTACGAAAGCAAAGTATTTGACTACGAGGGCCTTGGCAACCTCCTGAAAAAAA
+GGGCCTCATTTTATGAGAACATCATTAAGGCAATGAGGCCTCAGCCTGAATACTTTGCTGTTGGATACTATGGACAGGGC
+TTTCCTTCTTTCCTACGGAATAAAATCTTCATCTATCGGGGAAAGGAGTATGAGAGGCGAGAGGACTTCAGCCTGAGGTT
+GTTAACCCAGTTCCCCAATGCGGAGAAGATGACCAGTACCACGCCTCCTGGGGAAGACATCAAGTCGTCCCCCAAGCAGT
+ACATGCAGTGCTTCACTGTAAAGCCAGTGATGAGCTTGCCGCCCAGCTACAAGGATAAACCTGTTCCAGAGCAGATCTTA
+AACTACTACAGAGCCAATGAAGTGCAGCAGTTCAGATACTCCCGGCCGTTCCGGAAAGGAGAAAAGGATCCAGACAATGA
+ATTTGCTACGATGTGGATTGAACGGACCACGTATACGACTGCATATACCTTTCCTGGGATTCTCAAGTGGTTTGAAGTCA
+AACAGATTTCAACAGAAGAGATCAGTCCTCTGGAGAATGCCATCGAAACCATGGAGCTGACCAACGAGAGGATCAGCAAC
+TGTGTTCAGCAGCATGCCTGGGACCGGTCCCTCTCTGTGCACCCTCTCTCCATGCTGCTCAGTGGCATCGTGGACCCGGC
+CGTCATGGGGGGCTTCTCCAACTATGAAAAGGCTTTTTTTACAGAAAAGTACTTGCAGGAGCATCCTGAAGACCAGGAGA
+AGGTTGAGCTGCTAAAGCGACTAATAGCATTACAGATGCCCCTGCTAACAGAAGGGATCCGCATCCATGGGGAGAAACTC
+ACAGAGCAGCTGAAGCCGCTGCATGAGCGGTTGTCTTCTTGCTTCCGGGAACTCAAGGAGAAAGTAGAAAAGCACTATGG
+GGTTATAACACTGCCACCCAACTTGACGGAGAGGAAGCAAAGCCGCACGGGGTCTATTGTGCTCCCCTACATCATGTCTT
+CTACTCTGCGGAGGTTGTCCATCACCTCAGTCACTTCCTCTGTGGTTTCCACCTCTTCAAACTCGTCTGACAATGCTCCT
+TCCAGACCGGGATCTGATGGCTCAATCTTGGAGCCACTTTTGGAGCGCAGGGCCTCGTCAGGTGCCAGAGTTGAAGATCT
+GTCCCTTAGAGAGGAGAACAGCGAGAACCGGATCAGCAAGTTTAAGAGAAAAGACTGGAGTCTGAGCAAGTCCCAGGTCA
+TTGCAGAGAAAGCACCAGAACCCGATTTGATGAGCCCAACCAGAAAAGCACAAAGGCCAAAGAGTCTCCAGTTGATGGAT
+AATCGGCTATCACCATTTCACGGTTCTTCACCTCCTCAGTCAACACCCTTGAGCCCACCTCCACTCACTCCCAAAGCCAC
+CAGGACCCTAAGCTCCCCATCGTTGCAGACAGATGGAATCGCGGCCACTCCTGTCCCACCTCCACCTCCCCCCAAAAGCA
+AGCCCTATGAAGGCAGCCAGAGGAACTCCACTGAGCTCGCTCCCCCACTGCCTGTCCGAAGAGAAGCCAAAGCACCACCC
+CCTCCACCTCCAAAGGCTCGGAAGTCTGGCATCCCTACTTCCGAGCCTGGATCCCAGTAAGGATCTTGCCCTCCCTGCAA
+CACCGAGTGCCTTAGACAGCTGCTGCCTGAGAACTGGCCTCCAGCCGGTGTCCTCATTCCATGGGGCTCCCTGCTGACTG
+CATTTCCTGATCTGGGATGATGTTTACCAGCCCAAAACCAGTCATGTTCTTCCAAAAGCTTCTCTTTGATAGAATTTTGA
+GGCCATGCCACCTCCCTTCCAGTCCACATGGAATTCCAGAATCAGTCACAGCCTCTGATTTTTTCCAAGAAGAGATTGCC
+TTCACCATTGTTAAATGTCAGCCTGTACGGCAGAGACATGGTGGTCTGCACAAGCCTGGACAAGTTCTTCCATATTGATG
+GTGGAGCAACCCCTGTAATCTACTCCTTGGAAGGATTTTTTGCTTTGCTTATGAAAAGCTGTGCTTGAGACTTAGGTACT
+TTTCTCACGTGGACACACTGATCCCATCCCATATTGCATCTTTGAAGAGATGGATATCAAGTACACTTTGGTAGCTGAAA
+TAATCATATCTTTCTGATGTCTATTGTATCTCCTTTGAGGAAAAGAACACACATTTTTAATGGAGATTGGCTGCTTTCAG
+GTATGTGTGTCTATCATTGAAAGAGCATGGACTCAAACATCAGCCCTGAGTTCTTGAGTCCACCCAACTCCCATCTTCTT
+GTGGCACAGGAAAGCTGCCCTCTCCCTCTCCCACCACACTCCTGACTAATGGCCTTCACTGCGTCGCAGTCACTCCTTCC
+CTACGGACTTCTTTGAAGCTCTTCCTTTTGCACATACGGCTTTTTTTTTTTGTCCTATTACCTCCTCTGAGCGCAAATCA
+CTGGCTACAAGGGACTTACCAGTCTGGATTCAGCAGTTTCTTTTCTAAAACCCATTTGGGTGACTCAGCAGCCGCATCTG
+CTACCTGATTTTATCCTGGAGAATACAGTGCAATATTTCTCTTTGATTATTTATTCCTCTTGATTGTGGAATTAATTTGA
+TTGCTTGCTAATGGTACTAGTAGTACTCCTTTCAGAAGAAAAAATGGAGCGATTTAGGTGACCAAATATTACATACATAA
+ATAGCCACATGAAGTTTTAGACGTTTGGACTTGAAGCCTCAAAGATCAACCAACCAGTCCCCTTATTTAGTAAATAAGGA
+AATTGAGGCTACACACAGAAAATTGTGCTACAGATTATTACTAATAACCCAGCTTGCTAAATTAGGCTATACCTAGGTAA
+TCTCTAGAAGACAACTCTGACAGACTCTTTAATATTTACCCCTGGTTGGAACAATATTTGAAATGTCCCGGATATTTCTA
+TGCTACTTAGATATTTGTGGCAAAGCAGAAAGCTTTTTGACTGTGAAGGCAGAGGTCAGCACTGGGGGAAACTTGCTGGT
+GGTCTCTCCCACAACCTTGCCCAGAGTCCTTTCCACTAAGGAGGTGAAGAGAACAGAGAAAGAGATTTCCATTTCTGCTG
+CCAGAGCTGGTATTTGCCTGCCTGATTCTCTGTGTTTCCTGTTTCACCGCCACCCTTTCAGGAGAGAACTACACCAGTTC
+ATCATGAGGGTCAGGGAAGCAAAAGCTCTCAGATGTGTCCAGGGCGTTACTTAAGAAATGAGTATGCAGATTCTGGAAGG
+GGTGTGGAAAAGGTGATCCTTTACCCCCACCCAGGAAAACCTGCATTGTGCTAGCATGGAAAAATCATGGGCTTTGGAAT
+TAAACCCATTTGGTGGAATTAAACCCATTTGGTTTCAAATCCCAGTTATGACATCTGTTAACTTTGCAAACTCACAAAAA
+TTATTTGAAATTAAAAAAAAAAAAAA
diff --git a/blat/test/v29skips/ex2_query.fa b/blat/test/v29skips/ex2_query.fa
new file mode 100644
index 0000000..440e869
--- /dev/null
+++ b/blat/test/v29skips/ex2_query.fa
@@ -0,0 +1,54 @@
+>genomicMrnaDOCK5
+CATGAGAAAGGAAATCGGCTTTAGAATCCGGGACATGTGGTATAACCTGGGTCCCCACAAAATCAAATTCATCCCATCCA
+TGGTGGGTCCCATTCTGGAGGTCACTCTGACCCCTGAAGTAGAGCTCCGGAAAGCCACAATCCCCATTTTCTTTGATATG
+ATGCAGTGTGAGTTCAATTTCAGTGGAAATGGCAATTTCCATATGTTTGAGAATGAGCTGATCACAAAGCTGGACCAGGA
+GGTAGAAGGGGGCAGAGGAGACGAACAATACAAGGTTCTTCTGGAAAAACTGCTCCTAGAACATTGCCGGAAACACAAAT
+ACCTCTCCAGCTCTGGGGAGGTCTTCGCCCTCCTGGTCAGCAGCCTCTTAGAGAACCTGCTGGACTATAGAACCATCATC
+ATGCAAGATGAGAGCAAGGAGAACCGTATGAGCTGCACTGTGAACGTGCTGAACTTTTATAAAGAAAAGAAGAGAGAGGA
+CATATACATAAGATATCTGTACAAGCTTCGAGATTTGCACCGAGACTGTGAGAACTACACAGAAGCTGCCTACACGCTTC
+TCTTGCACGCTGAGCTTCTGCAGTGGTCTGACAAGCCCTGTGTGCCTCATTTGCTTCAGAAGGACAGTTACTATGTTTAT
+ACCCAGCAAGAGCTTAAAGAGAAGCTGTATCAAGAAATCATATCATATTTCGACAAAGGCAAAATGTGGGAGAAGGCCAT
+CAAGCTGAGCAAAGAGTTGGCTGAGACTTACGAAAGCAAAGTATTTGACTACGAGGGCCTTGGCAACCTCCTGAAAAAAA
+GGGCCTCATTTTATGAGAACATCATTAAGGCAATGAGGCCTCAGCCTGAATACTTTGCTGTTGGATACTATGGACAGGGC
+TTTCCTTCTTTCCTACGGAATAAAATCTTCATCTATCGGGGAAAGGAGTATGAGAGGCGAGAGGACTTCAGCCTGAGGTT
+GTTAACCCAGTTCCCCAATGCGGAGAAGATGACCAGTACCACGCCTCCTGGGGAAGACATCAAGTCGTCCCCCAAGCAGT
+ACATGCAGTGCTTCACTGTAAAGCCAGTGATGAGCTTGCCGCCCAGCTACAAGGATAAACCTGTTCCAGAGCAGATCTTA
+AACTACTACAGAGCCAATGAAGTGCAGCAGTTCAGATACTCCCGGCCGTTCCGGAAAGGAGAAAAGGATCCAGACAATGA
+ATTTGCTACGATGTGGATTGAACGGACCACGTATACGACTGCATATACCTTTCCTGGGATTCTCAAGTGGTTTGAAGTCA
+AACAGATTTCAACAGAAGAGATCAGTCCTCTGGAGAATGCCATCGAAACCATGGAGCTGACCAACGAGAGGATCAGCAAC
+TGTGTTCAGCAGCATGCCTGGGACCGGTCCCTCTCTGTGCACCCTCTCTCCATGCTGCTCAGTGGCATCGTGGACCCGGC
+CGTCATGGGGGGCTTCTCCAACTATGAAAAGGCTTTTTTTACAGAAAAGTACTTGCAGGAGCATCCTGAAGACCAGGAGA
+AGGTTGAGCTGCTAAAGCGACTAATAGCATTACAGATGCCCCTGCTAACAGAAGGGATCCGCATCCATGGGGAGAAACTC
+ACAGAGCAGCTGAAGCCGCTGCATGAGCGGTTGTCTTCTTGCTTCCGGGAACTCAAGGAGAAAGTAGAAAAGCACTATGG
+GGTTATAACACTGCCACCCAACTTGACGGAGAGGAAGCAAAGCCGCACGGGGTCTATTGTGCTCCCCTACATCATGTCTT
+CCACTCTGCGGAGGTTGTCCATCACCTCAGTCACTTCCTCTGTGGTTTCCACCTCTTCAAACTCGTCTGACAATGCTCCT
+TCCAGACCGGGATCTGATGGCTCAATCTTGGAGCCACTTTTGGAGCGCAGGGCCTCGTCAGGTGCCAGAGTTGAAGATCT
+GTCCCTTAGAGAGGAGAACAGCGAGAACCGGATCAGCAAGTTTAAGAGAAAAGACTGGAGTCTGAGCAAGTCCCAGGTCA
+TTGCAGAGAAAGCACCAGAACCCGATTTGATGAGCCCAACCAGAAAAGCACAAAGGCCAAAGAGTCTCCAGTTGATGGAT
+AATCGGCTATCACCATTTCACGGTTCTTCACCTCCTCAGTCAACACCCTTGAGCCCACCTCCACTCACTCCCAAAGCCAC
+CAGGACCCTAAGCTCCCCATCGTTGCAGACAGATGGAATCGCGGCCACTCCTGTCCCACCTCCACCTCCCCCCAAAAGCA
+AGCCCTATGAAGGCAGCCAGAGGAACTCCACTGAGCTCGCTCCCCCACTGCCTGTCCGAAGAGAAGCCAAAGCACCACCC
+CCTCCACCTCCAAAGGCTCGGAAGTCTGGCATCCCTACTTCCGAGCCTGGATCCCAGTAAGGATCTTGCCCTCCCTGCAA
+CACCGAGTGCCTTAGACAGCTGCTGCCTGAGAACTGGCCTCCAGCCGGTGTCCTCATTCCATGGGGCTCCCTGCTGACTG
+CATTTCCTGATCTGGGATGATGTTTACCAGCCCAAAACCAGTCATGTTCTTCCAAAAGCTTCTCTTTGATAGAATTTTGA
+GGCCATGCCACCTCCCTTCCAGTCCACATGGAATTCCAGAATCAGTCACAGCCTCTGATTTTTTCCAAGAAGAGATTGCC
+TTCACCATTGTTAAATGTCAGCCTGTACGGCAGAGACATGGTGGTCTGCACAAGCCTGGACAAGTTCTTCCATATTGATG
+GTGGAGCAACCCCTGTAATCTACTCCTTGGAAGGATTTTTTGCTTTGCTTATGAAAAGCTGTGCTTGAGACTTAGGTACT
+TTTCTCACGTGGACACACTGATCCCATCCCATATTGCATCTTGGAAGAGATGGATATCAAGTACACTTTGGTAGCTGAAA
+TAATCATATCTTTCTGATGTCTATTGTATCTCCTTTGAGGAAAAGAACACACATTTTTAATGGAGATTGGCTGCTTTCAG
+GTATGTGTGTCTATCATTGAAAGAGCATGGACTCAAACATCAGCCCTGAGTTCTTGAGTCCACCCAACTCCCATCTTCTT
+GTGGCACAGGAAAGCTGCCCTCTCCCTCTCCCACCACACTCCTGACTAATGGCCTTCACTGCGTCGCAGTCACTCCTTCC
+CTACGGACTTCTTTGAAGCTCTTCCTTTTGCACATACGGCTTTTTTTTTTTTTTTTTTTTTTTGTCCTATTACCTCCTCT
+GAGCGCAAATCACTGGCTACAAGGGACTTACCAGTCTGGATTCAGCAGTTTCTTTTCTAAAACCCATTTGGGTGACTCAG
+CAGCCGCATCTGCTACCTGATTTTATCCTGGAGAATACAGTGCAATATTTCTCTTTGATTATTTATTCCTCTTGATTGTG
+GAATTAATTTGATTGCTTGCTAATGGTACTAGTAGTACTCCTTTCAGAAGAAAAAATGGAGCGATTTAGGTGACCAAATA
+TTACATACATAAATAGCCACATGAAGTTTTAGACGTTTGGACTTGAAGCCTCAAAGATCAACCAACCAGTCCCCTTATTT
+AGTAAATAAGGAAATTGAGGCTACACACAGAAAATTGTGCTACAGATTATTACTAATAACCCAGCTTGCTAAATTAGGCT
+ATACCTAGGTAATCTCTAGAAGACAACTCTGACAGACTCTTTAATATTTACCCCTGGTTGGAACAATATTTGAAATGTCC
+CAGATATTTCTATGCTACTTAGATATTTGTGGCAAAGCAGAAAGCTTTTTGACTGTGAAGGCAGAGGTCAGCACTGGGGG
+AAACTTGCTGGTGGTCTCTCCCACAACCTTGCCCAGAGTCCTTTCCACTAAGGAGGTGAAGAGAACAGAGAAAGAGATTT
+CCATTTCTGCTGCCAGAGCTGGTATTTGCCTGCCTGATTCTCTGTGTTTCCTGTTTCACCGCCACCCTTTCAGGAGAGAA
+CTACACCAGTTCATCATGAGGGTCAGGGAAGCAAAAGCTCTCAGATGTGTCCAGGGCGTTACTTAAGAAATGAGTATGCA
+GATTCTGGAAGGGGTGTGGAAAAGGTGATCCTTTACCCCCACCCAGGAAAACCTGCATTGTGCTAGCATGGAAGAATCAT
+GGGCTTTGGAATTAAACCCATTTGGTGGAATTAAACCCATTTGGTTTCAAATCCCAGTTATGACATCTGTTAACTTTGCA
+AACTCACAAAAATTATTTGAAATTA
diff --git a/blat/test/v29skips/ex2_reference.psl b/blat/test/v29skips/ex2_reference.psl
new file mode 100644
index 0000000..4c6a86a
--- /dev/null
+++ b/blat/test/v29skips/ex2_reference.psl
@@ -0,0 +1,6 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+4168	5	0	0	1	12	0	0	+	genomicMrnaDOCK5	4185	0	4185	FnaDOCK5	4186	0	4173	2	3171,1002,	0,3183,	0,3171,
diff --git a/gfClient/AB000095.fa b/gfClient/AB000095.fa
new file mode 100644
index 0000000..63942ed
--- /dev/null
+++ b/gfClient/AB000095.fa
@@ -0,0 +1,49 @@
+>AB000095
+cggccgagcccagctctccgagcaccgggtcggaagccgcgacccgagcc
+gcgcaggaagctgggaccggaacctcggcggacccggccccacccaactc
+acctgcgcaggtcaccagcaccctcggaacccagaggcccgcgctctgaa
+ggtgacccccctggggaggaaggcgatggcccctgcgaggacgatggccc
+gcgcccgcctcgccccggccggcatccctgccgtcgccttgtggcttctg
+tgcacgctcggcctccagggcacccaggccgggccaccgcccgcgccccc
+tgggctgcccgcgggagccgactgcctgaacagctttaccgccggggtgc
+ctggcttcgtgctggacaccaacgcctcggtcagcaacggagctaccttc
+ctggagtcccccaccgtgcgccggggctgggactgcgtgcgcgcctgctg
+caccacccagaactgcaacttggcgctagtggagctgcagcccgaccgcg
+gggaggacgccatcgccgcctgcttcctcatcaactgcctctacgagcag
+aacttcgtgtgcaagttcgcgcccagggagggcttcatcaactacctcac
+gagggaagtgtaccgctcctaccgccagctgcggacccagggctttggag
+ggtctgggatccccaaggcctgggcaggcatagacttgaaggtacaaccc
+caggaacccctggtgctgaaggatgtggaaaacacagattggcgcctact
+gcggggtgacacggatgtcagggtagagaggaaagacccaaaccaggtgg
+aactgtggggactcaaggaaggcacctacctgttccagctgacagtgact
+agctcagaccacccagaggacacggccaacgtcacagtcactgtgctgtc
+caccaagcagacagaagactactgcctcgcatccaacaaggtgggtcgct
+gccggggctctttcccacgctggtactatgaccccacggagcagatctgc
+aagagtttcgtttatggaggctgcttgggcaacaagaacaactaccttcg
+ggaagaagagtgcattctagcctgtcggggtgtgcaaggcccctccatgg
+aaaggcgccatccagtgtgctctggcacctgtcagcccacccagttccgc
+tgcagcaatggctgctgcatcgacagtttcctggagtgtgacgacacccc
+caactgccccgacgcctccgacgaggctgcctgtgaaaaatacacgagtg
+gctttgacgagctccagcgcatccatttccccagtgacaaagggcactgc
+gtggacctgccagacacaggactctgcaaggagagcatcccgcgctggta
+ctacaaccccttcagcgaacactgcgcccgctttacctatggtggttgtt
+atggcaacaagaacaactttgaggaagagcagcagtgcctcgagtcttgt
+cgcggcatctccaagaaggatgtgtttggcctgaggcgggaaatccccat
+tcccagcacaggctctgtggagatggctgtcgcagtgttcctggtcatct
+gcattgtggtggtggtagccatcttgggttactgcttcttcaagaaccag
+agaaaggacttccacggacaccaccaccacccaccacccacccctgccag
+ctccactgtctccactaccgaggacacggagcacctggtctataaccaca
+ccacccggcccctctgagcctgggtctcaccggctctcacctggccctgc
+ttcctgcttgccaaggcagaggcctgggctgggaaaaactttggaaccag
+actcttgcctgtttcccaggcccactgtgcctcagagaccagggctccag
+cccctcttggagaagtctcagctaagctcacgtcctgagaaagctcaaag
+gtttggaaggagcagaaaacccttgggccagaagtaccagactagatgga
+cctgcctgcataggagtttggaggaagttggagttttgtttcctctgttc
+aaagctgcctgtccctaccccatggtgctaggaagaggagtggggtggtg
+tcagaccctggaggccccaaccctgtcctcccgagctcctcttccatgct
+gtgcgcccagggctgggaggaaggacttccctgtgtagtttgtgctgtaa
+agagttgctttttgtttatttaatgctgtggcatgggtgaagaggagggg
+aagaggcctgtttggcctctctgtcctctcttcctcttcccccaagattg
+agctctctgcccttgatcagccccaccctggcctagaccagcagacagag
+ccaggagaggctcagctgcattccgcagcccccacccccaaggttctcca
+acatcacagcccagcccacccactgggtaataaaagtggtttgtggaaa
diff --git a/gfClient/AB000220.fa b/gfClient/AB000220.fa
new file mode 100644
index 0000000..f0ab943
--- /dev/null
+++ b/gfClient/AB000220.fa
@@ -0,0 +1,39 @@
+>AB000220
+ggactgcgaaaggagcagggttgcggagctagggctccagcctgcggccg
+cgcattcttgcgtctggccagccgcgagctctaagggtcggccccgcccg
+gtccgcccccgcggctccctgccaggctctcgcgggcgcgctcggggtgg
+ggcctcgcggctggcggagatgcggccggggctgcgcggtggtgatgcga
+gcctgctgggcggcgcgccggggcagccggagccgcgcgccgcggcgctg
+taatcggacaccaagagcgctcgcccccggcctccggccactttccattc
+actccgaggtgcttgattgagcgacgcggagaagagctccgggtgccgcg
+gcactgcagcgctgagattcctttacaaagaaactcagaggaccgggaag
+aaagaatttcacctttgcgacgtgctagaaaataaggtcgtctgggaaaa
+ggactggagacacaagcgcatccaaccccggtagcaaactgatgactttt
+ccgtgctgatttctttcaacctcggtattttcccttggatattaacttgc
+atatctgaagaaatggcattccggacaatttgcgtgttggttggagtatt
+tatttgttctatctgtgtgaaaggatcttcccagccccaagcaagagttt
+atttaacatttgatgaacttcgagaaaccaagacctctgaatacttcagc
+ctttcccaccatcctttagactacaggattttattaatggatgaagatca
+ggaccggatatatgtgggaagcaaagatcacattctttccctgaatatta
+acaatataagtcaagaagctttgagtgttttctggccagcatctacaatc
+aaagttgaagaatgcaaaatggctggcaaagatcccacacacggctgtgg
+gaactttgtccgtgtaattcagactttcaatcgcacacatttgtatgtct
+gtgggagtggcgctttcagtcctgtctgtacttacttgaacagagggagg
+agatcagaggaccaagttttcatgattgactccaagtgtgaatctggaaa
+aggacgctgctctttcaaccccaacgtgaacacggtgtctgttatgatca
+atgaggagcttttctctggaatgtatatagatttcatggggacagatgct
+gctatttttcgaagtttaaccaagaggaatgcggtcagaactgatcaaca
+taattccaaatggctaagtgaacctatgtttgtagatgcacatgtcatcc
+cagatggtactgatccaaatgatgctaaggtgtacttcttcttcaaagaa
+aaactgactgacaataacaggagcacgaaacagattcattccatgattgc
+tcgaatatgtcctaatgacactggtggactgcgtagccttgtcaacaagt
+ggaccactttcttaaaggcgaggctggtgtgctcggtaacagatgaagac
+ggcccagaaacacactttgatgaattagaggatgtgtttctgctggaaac
+tgataacccgaggacaacactagtgtatggcatttttacaacatcaagct
+cagttttcaaaggatcagccgtgtgtgtgtatcatttatctgatatacag
+actgtgtttaatgggccttttgcccacaaagaagggcccaatcatcagct
+gatttcctatcagggcagaattccatatcctcgccctggaacttgtccag
+gaggagcatttacacccaatatgcgaaccaccaaggagttcccagatgat
+gttgtcacttttattcggaaccatcctctcatgtacaattccatctaccc
+aatccacaaaaggcctttgattgttcgtattggcactgactacaagtaca
+
diff --git a/gfClient/gfClient.c b/gfClient/gfClient.c
new file mode 100644
index 0000000..bdb55d0
--- /dev/null
+++ b/gfClient/gfClient.c
@@ -0,0 +1,174 @@
+/* gfClient - A client for the genomic finding program that produces a .psl file. */
+/* Copyright 2001-2003 Jim Kent.  All rights reserved. */
+#include "common.h"
+#include "linefile.h"
+#include "aliType.h"
+#include "fa.h"
+#include "genoFind.h"
+#include "psl.h"
+#include "options.h"
+#include "fuzzyFind.h"
+
+
+static struct optionSpec optionSpecs[] = {
+    {"prot", OPTION_BOOLEAN},
+    {"q", OPTION_STRING},
+    {"t", OPTION_STRING},
+    {"minIdentity", OPTION_FLOAT},
+    {"minScore", OPTION_INT},
+    {"dots", OPTION_INT},
+    {"out", OPTION_STRING},
+    {"maxIntron", OPTION_INT},
+    {"nohead", OPTION_BOOLEAN},
+    {NULL, 0}
+};
+
+/* Variables that can be overridden by command line. */
+int dots = 0;
+int minScore = 30;
+double minIdentity = 90;
+char *outputFormat = "psl";
+char *qType = "dna";
+char *tType = "dna";
+
+void usage()
+/* Explain usage and exit. */
+{
+printf(
+  "gfClient v. %s - A client for the genomic finding program that produces a .psl file\n"
+  "usage:\n"
+  "   gfClient host port seqDir in.fa out.psl\n"
+  "where\n"
+  "   host is the name of the machine running the gfServer\n"
+  "   port is the same as you started the gfServer with\n"
+  "   seqDir is the path of the .nib or .2bit files relative to the current dir\n"
+  "       (note these are needed by the client as well as the server)\n"
+  "   in.fa is a fasta format file.  May contain multiple records\n"
+  "   out.psl where to put the output\n"
+  "options:\n"
+  "   -t=type     Database type.  Type is one of:\n"
+  "                 dna - DNA sequence\n"
+  "                 prot - protein sequence\n"
+  "                 dnax - DNA sequence translated in six frames to protein\n"
+  "               The default is dna\n"
+  "   -q=type     Query type.  Type is one of:\n"
+  "                 dna - DNA sequence\n"
+  "                 rna - RNA sequence\n"
+  "                 prot - protein sequence\n"
+  "                 dnax - DNA sequence translated in six frames to protein\n"
+  "                 rnax - DNA sequence translated in three frames to protein\n"
+  "   -prot       Synonymous with -d=prot -q=prot\n"
+  "   -dots=N   Output a dot every N query sequences\n"
+  "   -nohead   Suppresses psl five line header\n"
+  "   -minScore=N sets minimum score.  This is twice the matches minus the \n"
+  "               mismatches minus some sort of gap penalty.  Default is 30\n"
+  "   -minIdentity=N Sets minimum sequence identity (in percent).  Default is\n"
+  "               90 for nucleotide searches, 25 for protein or translated\n"
+  "               protein searches.\n"
+  "   -out=type   Controls output file format.  Type is one of:\n"
+  "                   psl - Default.  Tab separated format without actual sequence\n"
+  "                   pslx - Tab separated format with sequence\n"
+  "                   axt - blastz-associated axt format\n"
+  "                   maf - multiz-associated maf format\n"
+  "                   sim4 - similar to sim4 format\n"
+  "                   wublast - similar to wublast format\n"
+  "                   blast - similar to NCBI blast format\n"
+  "                   blast8- NCBI blast tabular format\n"
+  "                   blast9 - NCBI blast tabular format with comments\n"
+  "   -maxIntron=N  Sets maximum intron size. Default is %d\n",
+                        gfVersion, ffIntronMaxDefault);
+exit(-1);
+}
+
+
+struct gfOutput *gvo;
+
+void gfClient(char *hostName, char *portName, char *tSeqDir, char *inName, 
+	char *outName, char *tTypeName, char *qTypeName)
+/* gfClient - A client for the genomic finding program that produces a .psl file. */
+{
+struct lineFile *lf = lineFileOpen(inName, TRUE);
+static bioSeq seq;
+FILE *out = mustOpen(outName, "w");
+enum gfType qType = gfTypeFromName(qTypeName);
+enum gfType tType = gfTypeFromName(tTypeName);
+int dotMod = 0;
+char databaseName[256];
+struct hash *tFileCache = gfFileCacheNew();
+
+snprintf(databaseName, sizeof(databaseName), "%s:%s", hostName, portName);
+
+gvo = gfOutputAny(outputFormat,  round(minIdentity*10), qType == gftProt, tType == gftProt,
+	optionExists("nohead"), databaseName, 23, 3.0e9, minIdentity, out);
+gfOutputHead(gvo, out);
+while (faSomeSpeedReadNext(lf, &seq.dna, &seq.size, &seq.name, qType != gftProt))
+    {
+    int conn = gfConnect(hostName, portName);
+    if (dots != 0)
+        {
+	if (++dotMod >= dots)
+	    {
+	    dotMod = 0;
+	    fputc('.', stdout);
+	    fflush(stdout);
+	    }
+	}
+    if (qType == gftProt && (tType == gftDnaX || tType == gftRnaX))
+        {
+	gvo->reportTargetStrand = TRUE;
+	gfAlignTrans(&conn, tSeqDir, &seq, minScore, tFileCache, gvo);
+	}
+    else if ((qType == gftRnaX || qType == gftDnaX) && (tType == gftDnaX || tType == gftRnaX))
+        {
+	gvo->reportTargetStrand = TRUE;
+	gfAlignTransTrans(&conn, tSeqDir, &seq, FALSE, minScore, tFileCache, 
+		gvo, qType == gftRnaX);
+	if (qType == gftDnaX)
+	    {
+	    reverseComplement(seq.dna, seq.size);
+	    close(conn);
+	    conn = gfConnect(hostName, portName);
+	    gfAlignTransTrans(&conn, tSeqDir, &seq, TRUE, minScore, tFileCache,
+	    	gvo, FALSE);
+	    }
+	}
+    else if ((tType == gftDna || tType == gftRna) && (qType == gftDna || qType == gftRna))
+	{
+	gfAlignStrand(&conn, tSeqDir, &seq, FALSE, minScore, tFileCache, gvo);
+	conn = gfConnect(hostName, portName);
+	reverseComplement(seq.dna, seq.size);
+	gfAlignStrand(&conn, tSeqDir, &seq, TRUE,  minScore, tFileCache, gvo);
+	}
+    else
+        {
+	errAbort("Comparisons between %s queries and %s databases not yet supported",
+		qTypeName, tTypeName);
+	}
+    gfOutputQuery(gvo, out);
+    }
+if (out != stdout)
+    printf("Output is in %s\n", outName);
+gfFileCacheFree(&tFileCache);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, optionSpecs);
+if (argc != 6)
+    usage();
+if (optionExists("prot"))
+    qType = tType = "prot";
+qType = optionVal("q", qType);
+tType = optionVal("t", tType);
+if (sameWord(tType, "prot") || sameWord(tType, "dnax") || sameWord(tType, "rnax"))
+    minIdentity = 25;
+minIdentity = optionFloat("minIdentity", minIdentity);
+minScore = optionInt("minScore", minScore);
+dots = optionInt("dots", 0);
+outputFormat = optionVal("out", outputFormat);
+/* set global for fuzzy find functions */
+setFfIntronMax(optionInt("maxIntron", ffIntronMaxDefault));
+gfClient(argv[1], argv[2], argv[3], argv[4], argv[5], tType, qType);
+return 0;
+}
diff --git a/gfClient/gfRange.as b/gfClient/gfRange.as
new file mode 100644
index 0000000..eff60a3
--- /dev/null
+++ b/gfClient/gfRange.as
@@ -0,0 +1,10 @@
+table gfRange
+"A range of bases found by genoFind."
+    (
+    int qStart;		"Start in query"
+    int qEnd;		"End in query"
+    string tName;	"Target name"
+    int tStart;		"Start in target"
+    int tEnd;		"End in target"
+    int hitCount;	"Number of hits"
+    )
diff --git a/gfClient/makefile b/gfClient/makefile
new file mode 100644
index 0000000..66ffa66
--- /dev/null
+++ b/gfClient/makefile
@@ -0,0 +1,15 @@
+include ../inc/common.mk
+
+L += -lm $(SOCKETLIB)
+MYLIBDIR = ../lib/$(MACHTYPE)
+MYLIBS =  $(MYLIBDIR)/jkOwnLib.a $(MYLIBDIR)/jkweb.a 
+
+O = gfClient.o
+X = gfClient
+
+gfClient: $O $(MYLIBS)
+	${CC} ${COPT} ${CFLAGS} -o ${DESTDIR}${BINDIR}/$X $O $(MYLIBS) $L
+	${STRIP} ${DESTDIR}${BINDIR}/$X${EXE}
+
+clean::
+	rm -f ${O}
diff --git a/gfClient/repeat.fa b/gfClient/repeat.fa
new file mode 100644
index 0000000..78289f4
--- /dev/null
+++ b/gfClient/repeat.fa
@@ -0,0 +1,7 @@
+>alu
+tttcttttctttttttgaaatggagtctcgctctgtcgccccggctggag
+tgcagtggcgcgatctcggctcactgcaagctctgtctcctgggttcatg
+ccattctcctgcctcagcctcccgagtagctgggactacaggtgcccacc
+accacactcggctaattttttgtatttttagtagagacggggtttcactg
+tgttagccaggatggtctcgatcttctgacctcgtgatctgcccgcctcg
+gcctcccaaagtgctgggattacagatgtgagccaccgca
diff --git a/gfClient/test1.fa b/gfClient/test1.fa
new file mode 100644
index 0000000..4387eec
--- /dev/null
+++ b/gfClient/test1.fa
@@ -0,0 +1,11 @@
+>chr22:35790985-35791449
+ctcgggctcggaggaggcaccggcgggctcaggggccgtgggaggtgccg
+ggccggcagcagctgtgacctcaggcggtgcccgcttgctggtggctgcc
+gactcgggagggagggacaggtcgagcacctccggctcgcgccagctggg
+ggcggatgggctcacggtctcggggaggagcttggggggcgtgtcgtcgg
+ggtcagaggactgtggtgtaggcgaggggcagccggaggagccagagctg
+cgggcgtcgtagggggcggcgggggcggccagaagtagcccagggcccgg
+ggctgaggcctcagccttgccgggggacggggctaccaggggggcgggcg
+gaggcttgtacagcgcaaaggcgccgaacttcatgtggcggatctgtgta
+cgcaggacgctctcgctgaacttcttgctcttgcctataacgcggttccg
+cgaggggactttggg
diff --git a/gfClient/test2.fa b/gfClient/test2.fa
new file mode 100644
index 0000000..a9d5a84
--- /dev/null
+++ b/gfClient/test2.fa
@@ -0,0 +1,7 @@
+>test1
+ctcgggctcggaggaggcaccggcgggctcaggggccgtgggaggtgccg
+gactcgggagggagggacaggtcgagcacctccggctcgcgccagctggg
+ggtcagaggactgtggtgtaggcgaggggcagccggaggagccagagctg
+ggctgaggcctcagccttgccgggggacggggctaccaggggggcgggcg
+cgcaggacgctctcgctgaacttcttgctcttgcctataacgcggttccg
+cgaggggactttggg
diff --git a/gfClient/test3.fa b/gfClient/test3.fa
new file mode 100644
index 0000000..39fa99d
--- /dev/null
+++ b/gfClient/test3.fa
@@ -0,0 +1,9 @@
+>chr1:6691869-6692269
+catgcaccaccacgcctggctaattttttgtatttttagtagagacgggg
+tttcaccatggccaggctggtgttgaactcctaacctcaggtgatctgcc
+cgcctcagccccccagaatgctaggattacaggcgtgagccacagcgccc
+agccagaaggaaggcttccctgaccaggaatcgaacccgggtcgtgatgg
+cgagcgcggaatcctaaccactagactaccagggagtgtcctaaaaactt
+ttaaaaaatggattacagttccattgaaactcactaattactcataaata
+cttttgaaaagcattttataacgaactttgttgcagtctggggtgtggat
+ggaactttgttgcagagatactcctttaaatcaggattaagtccagcact
diff --git a/gfServer/AB000095.fa b/gfServer/AB000095.fa
new file mode 100644
index 0000000..63942ed
--- /dev/null
+++ b/gfServer/AB000095.fa
@@ -0,0 +1,49 @@
+>AB000095
+cggccgagcccagctctccgagcaccgggtcggaagccgcgacccgagcc
+gcgcaggaagctgggaccggaacctcggcggacccggccccacccaactc
+acctgcgcaggtcaccagcaccctcggaacccagaggcccgcgctctgaa
+ggtgacccccctggggaggaaggcgatggcccctgcgaggacgatggccc
+gcgcccgcctcgccccggccggcatccctgccgtcgccttgtggcttctg
+tgcacgctcggcctccagggcacccaggccgggccaccgcccgcgccccc
+tgggctgcccgcgggagccgactgcctgaacagctttaccgccggggtgc
+ctggcttcgtgctggacaccaacgcctcggtcagcaacggagctaccttc
+ctggagtcccccaccgtgcgccggggctgggactgcgtgcgcgcctgctg
+caccacccagaactgcaacttggcgctagtggagctgcagcccgaccgcg
+gggaggacgccatcgccgcctgcttcctcatcaactgcctctacgagcag
+aacttcgtgtgcaagttcgcgcccagggagggcttcatcaactacctcac
+gagggaagtgtaccgctcctaccgccagctgcggacccagggctttggag
+ggtctgggatccccaaggcctgggcaggcatagacttgaaggtacaaccc
+caggaacccctggtgctgaaggatgtggaaaacacagattggcgcctact
+gcggggtgacacggatgtcagggtagagaggaaagacccaaaccaggtgg
+aactgtggggactcaaggaaggcacctacctgttccagctgacagtgact
+agctcagaccacccagaggacacggccaacgtcacagtcactgtgctgtc
+caccaagcagacagaagactactgcctcgcatccaacaaggtgggtcgct
+gccggggctctttcccacgctggtactatgaccccacggagcagatctgc
+aagagtttcgtttatggaggctgcttgggcaacaagaacaactaccttcg
+ggaagaagagtgcattctagcctgtcggggtgtgcaaggcccctccatgg
+aaaggcgccatccagtgtgctctggcacctgtcagcccacccagttccgc
+tgcagcaatggctgctgcatcgacagtttcctggagtgtgacgacacccc
+caactgccccgacgcctccgacgaggctgcctgtgaaaaatacacgagtg
+gctttgacgagctccagcgcatccatttccccagtgacaaagggcactgc
+gtggacctgccagacacaggactctgcaaggagagcatcccgcgctggta
+ctacaaccccttcagcgaacactgcgcccgctttacctatggtggttgtt
+atggcaacaagaacaactttgaggaagagcagcagtgcctcgagtcttgt
+cgcggcatctccaagaaggatgtgtttggcctgaggcgggaaatccccat
+tcccagcacaggctctgtggagatggctgtcgcagtgttcctggtcatct
+gcattgtggtggtggtagccatcttgggttactgcttcttcaagaaccag
+agaaaggacttccacggacaccaccaccacccaccacccacccctgccag
+ctccactgtctccactaccgaggacacggagcacctggtctataaccaca
+ccacccggcccctctgagcctgggtctcaccggctctcacctggccctgc
+ttcctgcttgccaaggcagaggcctgggctgggaaaaactttggaaccag
+actcttgcctgtttcccaggcccactgtgcctcagagaccagggctccag
+cccctcttggagaagtctcagctaagctcacgtcctgagaaagctcaaag
+gtttggaaggagcagaaaacccttgggccagaagtaccagactagatgga
+cctgcctgcataggagtttggaggaagttggagttttgtttcctctgttc
+aaagctgcctgtccctaccccatggtgctaggaagaggagtggggtggtg
+tcagaccctggaggccccaaccctgtcctcccgagctcctcttccatgct
+gtgcgcccagggctgggaggaaggacttccctgtgtagtttgtgctgtaa
+agagttgctttttgtttatttaatgctgtggcatgggtgaagaggagggg
+aagaggcctgtttggcctctctgtcctctcttcctcttcccccaagattg
+agctctctgcccttgatcagccccaccctggcctagaccagcagacagag
+ccaggagaggctcagctgcattccgcagcccccacccccaaggttctcca
+acatcacagcccagcccacccactgggtaataaaagtggtttgtggaaa
diff --git a/gfServer/AB000220.fa b/gfServer/AB000220.fa
new file mode 100644
index 0000000..f0ab943
--- /dev/null
+++ b/gfServer/AB000220.fa
@@ -0,0 +1,39 @@
+>AB000220
+ggactgcgaaaggagcagggttgcggagctagggctccagcctgcggccg
+cgcattcttgcgtctggccagccgcgagctctaagggtcggccccgcccg
+gtccgcccccgcggctccctgccaggctctcgcgggcgcgctcggggtgg
+ggcctcgcggctggcggagatgcggccggggctgcgcggtggtgatgcga
+gcctgctgggcggcgcgccggggcagccggagccgcgcgccgcggcgctg
+taatcggacaccaagagcgctcgcccccggcctccggccactttccattc
+actccgaggtgcttgattgagcgacgcggagaagagctccgggtgccgcg
+gcactgcagcgctgagattcctttacaaagaaactcagaggaccgggaag
+aaagaatttcacctttgcgacgtgctagaaaataaggtcgtctgggaaaa
+ggactggagacacaagcgcatccaaccccggtagcaaactgatgactttt
+ccgtgctgatttctttcaacctcggtattttcccttggatattaacttgc
+atatctgaagaaatggcattccggacaatttgcgtgttggttggagtatt
+tatttgttctatctgtgtgaaaggatcttcccagccccaagcaagagttt
+atttaacatttgatgaacttcgagaaaccaagacctctgaatacttcagc
+ctttcccaccatcctttagactacaggattttattaatggatgaagatca
+ggaccggatatatgtgggaagcaaagatcacattctttccctgaatatta
+acaatataagtcaagaagctttgagtgttttctggccagcatctacaatc
+aaagttgaagaatgcaaaatggctggcaaagatcccacacacggctgtgg
+gaactttgtccgtgtaattcagactttcaatcgcacacatttgtatgtct
+gtgggagtggcgctttcagtcctgtctgtacttacttgaacagagggagg
+agatcagaggaccaagttttcatgattgactccaagtgtgaatctggaaa
+aggacgctgctctttcaaccccaacgtgaacacggtgtctgttatgatca
+atgaggagcttttctctggaatgtatatagatttcatggggacagatgct
+gctatttttcgaagtttaaccaagaggaatgcggtcagaactgatcaaca
+taattccaaatggctaagtgaacctatgtttgtagatgcacatgtcatcc
+cagatggtactgatccaaatgatgctaaggtgtacttcttcttcaaagaa
+aaactgactgacaataacaggagcacgaaacagattcattccatgattgc
+tcgaatatgtcctaatgacactggtggactgcgtagccttgtcaacaagt
+ggaccactttcttaaaggcgaggctggtgtgctcggtaacagatgaagac
+ggcccagaaacacactttgatgaattagaggatgtgtttctgctggaaac
+tgataacccgaggacaacactagtgtatggcatttttacaacatcaagct
+cagttttcaaaggatcagccgtgtgtgtgtatcatttatctgatatacag
+actgtgtttaatgggccttttgcccacaaagaagggcccaatcatcagct
+gatttcctatcagggcagaattccatatcctcgccctggaacttgtccag
+gaggagcatttacacccaatatgcgaaccaccaaggagttcccagatgat
+gttgtcacttttattcggaaccatcctctcatgtacaattccatctaccc
+aatccacaaaaggcctttgattgttcgtattggcactgactacaagtaca
+
diff --git a/gfServer/gfServer.c b/gfServer/gfServer.c
new file mode 100644
index 0000000..53c87c0
--- /dev/null
+++ b/gfServer/gfServer.c
@@ -0,0 +1,1027 @@
+/* gfServer - set up an index of the genome in memory and
+ * respond to search requests. */
+/* Copyright 2001-2003 Jim Kent.  All rights reserved. */
+#include "common.h"
+#include <signal.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "portable.h"
+#include "net.h"
+#include "dnautil.h"
+#include "dnaseq.h"
+#include "nib.h"
+#include "twoBit.h"
+#include "fa.h"
+#include "dystring.h"
+#include "errabort.h"
+#include "memalloc.h"
+#include "genoFind.h"
+#include "options.h"
+#include "trans3.h"
+#include "log.h"
+#include "internet.h"
+
+
+static struct optionSpec optionSpecs[] = {
+    {"canStop", OPTION_BOOLEAN},
+    {"log", OPTION_STRING},
+    {"logFacility", OPTION_STRING},
+    {"mask", OPTION_BOOLEAN},
+    {"maxAaSize", OPTION_INT},
+    {"maxDnaHits", OPTION_INT},
+    {"maxGap", OPTION_INT},
+    {"maxNtSize", OPTION_INT},
+    {"maxTransHits", OPTION_INT},
+    {"minMatch", OPTION_INT},
+    {"repMatch", OPTION_INT},
+    {"seqLog", OPTION_BOOLEAN},
+    {"ipLog", OPTION_BOOLEAN},
+    {"stepSize", OPTION_INT},
+    {"tileSize", OPTION_INT},
+    {"trans", OPTION_BOOLEAN},
+    {"syslog", OPTION_BOOLEAN},
+    {NULL, 0}
+};
+
+
+int maxNtSize = 40000;
+int maxAaSize = 8000;
+
+int minMatch = gfMinMatch;	/* Can be overridden from command line. */
+int tileSize = gfTileSize;	/* Can be overridden from command line. */
+int stepSize = 0;		/* Can be overridden from command line. */
+boolean doTrans = FALSE;	/* Do translation? */
+boolean allowOneMismatch = FALSE; 
+int repMatch = 1024;    /* Can be overridden from command line. */
+int maxDnaHits = 100;   /* Can be overridden from command line. */
+int maxTransHits = 200; /* Can be overridden from command line. */
+int maxGap = gfMaxGap;
+boolean seqLog = FALSE;
+boolean ipLog = FALSE;
+boolean doMask = FALSE;
+boolean canStop = FALSE;
+
+void usage()
+/* Explain usage and exit. */
+{
+errAbort(
+  "gfServer v %s - Make a server to quickly find where DNA occurs in genome.\n"
+  "To set up a server:\n"
+  "   gfServer start host port file(s)\n"
+  "   Where the files are in .nib or .2bit format\n"
+  "To remove a server:\n"
+  "   gfServer stop host port\n"
+  "To query a server with DNA sequence:\n"
+  "   gfServer query host port probe.fa\n"
+  "To query a server with protein sequence:\n"
+  "   gfServer protQuery host port probe.fa\n"
+  "To query a server with translated dna sequence:\n"
+  "   gfServer transQuery host port probe.fa\n"
+  "To query server with PCR primers\n"
+  "   gfServer pcr host port fPrimer rPrimer maxDistance\n"
+  "To process one probe fa file against a .nib format genome (not starting server):\n"
+  "   gfServer direct probe.fa file(s).nib\n"
+  "To test pcr without starting server:\n"
+  "   gfServer pcrDirect fPrimer rPrimer file(s).nib\n"
+  "To figure out usage level\n"
+  "   gfServer status host port\n"
+  "To get input file list\n"
+  "   gfServer files host port\n"
+  "Options:\n"
+  "   -tileSize=N size of n-mers to index.  Default is 11 for nucleotides, 4 for\n"
+  "               proteins (or translated nucleotides).\n"
+  "   -stepSize=N spacing between tiles. Default is tileSize.\n"
+  "   -minMatch=N Number of n-mer matches that trigger detailed alignment\n"
+  "               Default is 2 for nucleotides, 3 for protiens.\n"
+  "   -maxGap=N   Number of insertions or deletions allowed between n-mers.\n"
+  "               Default is 2 for nucleotides, 0 for protiens.\n"
+  "   -trans  Translate database to protein in 6 frames.  Note: it is best\n"
+  "           to run this on RepeatMasked data in this case.\n"
+  "   -log=logFile keep a log file that records server requests.\n"
+  "   -seqLog    Include sequences in log file (not logged with -syslog)\n"
+  "   -ipLog     Include user's IP in log file (not logged with -syslog)\n"
+  "   -syslog    Log to syslog\n"
+  "   -logFacility=facility log to the specified syslog facility - default local0.\n"
+  "   -mask      Use masking from nib file.\n"
+  "   -repMatch=N Number of occurrences of a tile (nmer) that trigger repeat masking the tile.\n"
+  "               Default is %d.\n"
+  "   -maxDnaHits=N Maximum number of hits for a dna query that are sent from the server.\n"
+  "               Default is %d.\n"
+  "   -maxTransHits=N Maximum number of hits for a translated query that are sent from the server.\n"
+  "               Default is %d.\n"
+  "   -maxNtSize=N Maximum size of untranslated DNA query sequence\n"
+  "               Default is %d\n"
+  "   -maxAaSize=N Maximum size of protein or translated DNA queries\n"
+  "               Default is %d\n"
+  "   -canStop If set then a quit message will actually take down the\n"
+  "            server\n"
+  ,	gfVersion, repMatch, maxDnaHits, maxTransHits, maxNtSize, maxAaSize
+  );
+
+}
+
+void genoFindDirect(char *probeName, int fileCount, char *seqFiles[])
+/* Don't set up server - just directly look for matches. */
+{
+struct genoFind *gf = NULL;
+struct lineFile *lf = lineFileOpen(probeName, TRUE);
+struct dnaSeq seq;
+int hitCount = 0, clumpCount = 0, oneHit;
+ZeroVar(&seq);
+
+if (doTrans)
+    errAbort("Don't support translated direct stuff currently, sorry");
+
+gf = gfIndexNibsAndTwoBits(fileCount, seqFiles, minMatch, maxGap, 
+	tileSize, repMatch, FALSE,
+	allowOneMismatch, stepSize);
+
+while (faSpeedReadNext(lf, &seq.dna, &seq.size, &seq.name))
+    {
+    struct lm *lm = lmInit(0);
+    struct gfClump *clumpList = gfFindClumps(gf, &seq, lm, &oneHit), *clump;
+    hitCount += oneHit;
+    for (clump = clumpList; clump != NULL; clump = clump->next)
+	{
+	++clumpCount;
+	printf("%s ", seq.name);
+	gfClumpDump(gf, clump, stdout);
+	}
+    gfClumpFreeList(&clumpList);
+    lmCleanup(&lm);
+    }
+lineFileClose(&lf);
+genoFindFree(&gf);
+}
+
+void genoPcrDirect(char *fPrimer, char *rPrimer, int fileCount, char *seqFiles[])
+/* Do direct PCR for testing purposes. */
+{
+struct genoFind *gf = NULL;
+int fPrimerSize = strlen(fPrimer);
+int rPrimerSize = strlen(rPrimer);
+struct gfClump *clumpList, *clump;
+time_t startTime, endTime;
+
+startTime = clock1000();
+gf = gfIndexNibsAndTwoBits(fileCount, seqFiles, minMatch, maxGap, 
+	tileSize, repMatch, FALSE,
+	allowOneMismatch, stepSize);
+endTime = clock1000();
+printf("Index built in %4.3f seconds\n", 0.001 * (endTime - startTime));
+
+printf("plus strand:\n");
+startTime = clock1000();
+clumpList = gfPcrClumps(gf, fPrimer, fPrimerSize, rPrimer, rPrimerSize, 0, 4*1024);
+endTime = clock1000();
+printf("Index searched in %4.3f seconds\n", 0.001 * (endTime - startTime));
+for (clump = clumpList; clump != NULL; clump = clump->next)
+    {
+    /* Clumps from gfPcrClumps have already had target->start subtracted out 
+     * of their coords, but gfClumpDump assumes they have not and does the 
+     * subtraction; rather than write a new gfClumpDump, tweak here: */
+    clump->tStart += clump->target->start;
+    clump->tEnd += clump->target->start;
+    gfClumpDump(gf, clump, stdout);
+    }
+printf("minus strand:\n");
+startTime = clock1000();
+clumpList = gfPcrClumps(gf, rPrimer, rPrimerSize, fPrimer, fPrimerSize, 0, 4*1024);
+endTime = clock1000();
+printf("Index searched in %4.3f seconds\n", 0.001 * (endTime - startTime));
+for (clump = clumpList; clump != NULL; clump = clump->next)
+    {
+    /* Same as above, tweak before gfClumpDump: */
+    clump->tStart += clump->target->start;
+    clump->tEnd += clump->target->start;
+    gfClumpDump(gf, clump, stdout);
+    }
+
+genoFindFree(&gf);
+}
+
+int getPortIx(char *portName)
+/* Convert from ascii to integer. */
+{
+if (!isdigit(portName[0]))
+    errAbort("Expecting a port number got %s", portName);
+return atoi(portName);
+}
+
+struct sockaddr_in sai;		/* Some system socket info. */
+
+/* Some variables to gather statistics on usage. */
+long baseCount = 0, blatCount = 0, aaCount = 0, pcrCount = 0;
+int warnCount = 0;
+int noSigCount = 0;
+int missCount = 0;
+int trimCount = 0;
+
+void dnaQuery(struct genoFind *gf, struct dnaSeq *seq, 
+	int connectionHandle, char buf[256])	
+/* Handle a query for DNA/DNA match. */
+{
+struct gfClump *clumpList = NULL, *clump;
+int limit = 1000;
+int clumpCount = 0, hitCount = -1;
+struct lm *lm = lmInit(0);
+
+if (seq->size > gf->tileSize + gf->stepSize + gf->stepSize)
+     limit = maxDnaHits;
+clumpList = gfFindClumps(gf, seq, lm, &hitCount);
+if (clumpList == NULL)
+    ++missCount;
+for (clump = clumpList; clump != NULL; clump = clump->next)
+    {
+    struct gfSeqSource *ss = clump->target;
+    sprintf(buf, "%d\t%d\t%s\t%d\t%d\t%d", 
+	clump->qStart, clump->qEnd, ss->fileName,
+	clump->tStart-ss->start, clump->tEnd-ss->start, clump->hitCount);
+    netSendString(connectionHandle, buf);
+    ++clumpCount;
+    if (--limit < 0)
+	break;
+    }
+gfClumpFreeList(&clumpList);
+lmCleanup(&lm);
+logDebug("%lu %d clumps, %d hits", clock1000(), clumpCount, hitCount);
+}
+
+void transQuery(struct genoFind *transGf[2][3], aaSeq *seq, 
+	int connectionHandle, char buf[256])	
+/* Handle a query for protein/translated DNA match. */
+{
+struct gfClump *clumps[3], *clump;
+int isRc, frame;
+char strand;
+struct dyString *dy  = newDyString(1024);
+struct gfHit *hit;
+int clumpCount = 0, hitCount = 0, oneHit;
+struct lm *lm = lmInit(0);
+
+sprintf(buf, "tileSize %d", tileSize);
+netSendString(connectionHandle, buf);
+for (frame = 0; frame < 3; ++frame)
+    clumps[frame] = NULL;
+for (isRc = 0; isRc <= 1; ++isRc)
+    {
+    strand = (isRc ? '-' : '+');
+    gfTransFindClumps(transGf[isRc], seq, clumps, lm, &oneHit);
+    hitCount += oneHit;
+    for (frame = 0; frame < 3; ++frame)
+        {
+	int limit = maxTransHits;
+	for (clump = clumps[frame]; clump != NULL; clump = clump->next)
+	    {
+	    struct gfSeqSource *ss = clump->target;
+	    sprintf(buf, "%d\t%d\t%s\t%d\t%d\t%d\t%c\t%d", 
+		clump->qStart, clump->qEnd, ss->fileName,
+		clump->tStart-ss->start, clump->tEnd-ss->start, clump->hitCount,
+		strand, frame);
+	    netSendString(connectionHandle, buf);
+	    dyStringClear(dy);
+	    for (hit = clump->hitList; hit != NULL; hit = hit->next)
+	        dyStringPrintf(dy, " %d %d", hit->qStart, hit->tStart - ss->start);
+	    netSendLongString(connectionHandle, dy->string);
+	    ++clumpCount;
+	    if (--limit < 0)
+		break;
+	    }
+	gfClumpFreeList(&clumps[frame]);
+	}
+    }
+if (clumpCount == 0)
+    ++missCount;
+freeDyString(&dy);
+lmCleanup(&lm);
+logDebug("%lu %d clumps, %d hits", clock1000(), clumpCount, hitCount);
+}
+
+void transTransQuery(struct genoFind *transGf[2][3], struct dnaSeq *seq, 
+	int connectionHandle, char buf[256])	
+/* Handle a query for protein/translated DNA match. */
+{
+struct gfClump *clumps[3][3], *clump;
+int isRc, qFrame, tFrame;
+char strand;
+struct trans3 *t3 = trans3New(seq);
+struct dyString *dy  = newDyString(1024);
+struct gfHit *hit;
+int clumpCount = 0, hitCount = 0, oneCount;
+
+sprintf(buf, "tileSize %d", tileSize);
+netSendString(connectionHandle, buf);
+for (qFrame = 0; qFrame<3; ++qFrame)
+    for (tFrame=0; tFrame<3; ++tFrame)
+	clumps[qFrame][tFrame] = NULL;
+for (isRc = 0; isRc <= 1; ++isRc)
+    {
+    struct lm *lm = lmInit(0);
+    strand = (isRc ? '-' : '+');
+    gfTransTransFindClumps(transGf[isRc], t3->trans, clumps, lm, &oneCount);
+    hitCount += oneCount;
+    for (qFrame = 0; qFrame<3; ++qFrame)
+	{
+	for (tFrame=0; tFrame<3; ++tFrame)
+	    {
+	    int limit = maxTransHits;
+	    for (clump = clumps[qFrame][tFrame]; clump != NULL; clump = clump->next)
+		{
+		struct gfSeqSource *ss = clump->target;
+		sprintf(buf, "%d\t%d\t%s\t%d\t%d\t%d\t%c\t%d\t%d", 
+		    clump->qStart, clump->qEnd, ss->fileName,
+		    clump->tStart-ss->start, clump->tEnd-ss->start, clump->hitCount,
+		    strand, qFrame, tFrame);
+		netSendString(connectionHandle, buf);
+		dyStringClear(dy);
+		for (hit = clump->hitList; hit != NULL; hit = hit->next)
+		    {
+		    dyStringPrintf(dy, " %d %d", hit->qStart, hit->tStart - ss->start);
+		    }
+		netSendLongString(connectionHandle, dy->string);
+		++clumpCount;
+		if (--limit < 0)
+		    break;
+		}
+	    gfClumpFreeList(&clumps[qFrame][tFrame]);
+	    }
+	}
+    lmCleanup(&lm);
+    }
+trans3Free(&t3);
+if (clumpCount == 0)
+    ++missCount;
+logDebug("%lu %d clumps, %d hits", clock1000(), clumpCount, hitCount);
+}
+
+static void pcrQuery(struct genoFind *gf, char *fPrimer, char *rPrimer, 
+	int maxDistance, int connectionHandle)
+/* Do PCR query and report results down socket. */
+{
+int fPrimerSize = strlen(fPrimer);
+int rPrimerSize = strlen(rPrimer);
+struct gfClump *clumpList, *clump;
+int clumpCount = 0;
+char buf[256];
+
+clumpList = gfPcrClumps(gf, fPrimer, fPrimerSize, rPrimer, rPrimerSize, 0, maxDistance);
+for (clump = clumpList; clump != NULL; clump = clump->next)
+    {
+    struct gfSeqSource *ss = clump->target;
+    safef(buf, sizeof(buf), "%s\t%d\t%d\t+", ss->fileName, 
+        clump->tStart, clump->tEnd);
+    netSendString(connectionHandle, buf);
+    ++clumpCount;
+    }
+gfClumpFreeList(&clumpList);
+
+clumpList = gfPcrClumps(gf, rPrimer, rPrimerSize, fPrimer, fPrimerSize, 0, maxDistance);
+
+for (clump = clumpList; clump != NULL; clump = clump->next)
+    {
+    struct gfSeqSource *ss = clump->target;
+    safef(buf, sizeof(buf), "%s\t%d\t%d\t-", ss->fileName, 
+        clump->tStart, clump->tEnd);
+    netSendString(connectionHandle, buf);
+    ++clumpCount;
+    }
+gfClumpFreeList(&clumpList);
+netSendString(connectionHandle, "end");
+logDebug("%lu PCR %s %s %d clumps\n", clock1000(), fPrimer, rPrimer, clumpCount);
+}
+
+
+static jmp_buf gfRecover;
+static char *ripCord = NULL;	/* A little memory to give back to system
+                                 * during error recovery. */
+
+static void gfAbort()
+/* Abort query. */
+{
+freez(&ripCord);
+longjmp(gfRecover, -1);
+}
+
+static void errorSafeSetup()
+/* Start up error safe stuff. */
+{
+pushAbortHandler(gfAbort); // must come before memTracker
+memTrackerStart();
+ripCord = needMem(64*1024); /* Memory for error recovery. memTrackerEnd frees */
+}
+
+static void errorSafeCleanup()
+/* Clean up and report problem. */
+{
+memTrackerEnd();
+popAbortHandler();  // must come after memTracker
+}
+
+static void errorSafeCleanupMess(int connectionHandle, char *message)
+/* Clean up and report problem. */
+{
+errorSafeCleanup();
+logError("Recovering from error via longjmp");
+netSendString(connectionHandle, message);
+}
+
+static void errorSafeQuery(boolean doTrans, boolean queryIsProt, 
+	struct dnaSeq *seq, struct genoFind *gf, struct genoFind *transGf[2][3], 
+	int connectionHandle, char *buf)
+/* Wrap error handling code around index query. */
+{
+int status;
+errorSafeSetup();
+status = setjmp(gfRecover);
+if (status == 0)    /* Always true except after long jump. */
+    {
+    if (doTrans)
+       {
+       if (queryIsProt)
+	    transQuery(transGf, seq, connectionHandle, buf);
+       else
+	    transTransQuery(transGf, seq, 
+		connectionHandle, buf);
+       }
+    else
+	dnaQuery(gf, seq, connectionHandle, buf);
+    errorSafeCleanup();
+    }
+else    /* They long jumped here because of an error. */
+    {
+    errorSafeCleanupMess(connectionHandle, 
+    	"Error: gfServer out of memory. Try reducing size of query.");
+    }
+}
+
+static void errorSafePcr(struct genoFind *gf, char *fPrimer, char *rPrimer, 
+	int maxDistance, int connectionHandle)
+/* Wrap error handling around pcr index query. */
+{
+int status;
+errorSafeSetup();
+status = setjmp(gfRecover);
+if (status == 0)    /* Always true except after long jump. */
+    {
+    pcrQuery(gf, fPrimer, rPrimer, maxDistance, connectionHandle);
+    errorSafeCleanup();
+    }
+else    /* They long jumped here because of an error. */
+    {
+    errorSafeCleanupMess(connectionHandle, 
+    	"Error: gfServer out of memory."); 
+    }
+}
+
+boolean badPcrPrimerSeq(char *s)
+/* Return TRUE if have a character we can't handle in sequence. */
+{
+unsigned char c;
+while ((c = *s++) != 0)
+    {
+    if (ntVal[c] < 0)
+        return TRUE;
+    }
+return FALSE;
+}
+
+void startServer(char *hostName, char *portName, int fileCount, 
+	char *seqFiles[])
+/* Load up index and hang out in RAM. */
+{
+struct genoFind *gf = NULL;
+static struct genoFind *transGf[2][3];
+char buf[256];
+char *line, *command;
+struct sockaddr_in fromAddr;
+socklen_t fromLen;
+int readSize;
+int socketHandle = 0, connectionHandle = 0;
+int port = atoi(portName);
+time_t curtime;
+struct tm *loctime;
+char timestr[256];
+
+netBlockBrokenPipes();
+
+curtime = time (NULL);           /* Get the current time. */
+loctime = localtime (&curtime);  /* Convert it to local time representation. */
+strftime (timestr, sizeof(timestr), "%Y-%m-%d %H:%M", loctime); /* formate datetime as string */
+								
+logInfo("gfServer version %s on host %s, port %s  (%s)", gfVersion, 
+	hostName, portName, timestr);
+if (doTrans)
+    {
+    uglyf("starting translated server...\n");
+    logInfo("setting up translated index");
+    gfIndexTransNibsAndTwoBits(transGf, fileCount, seqFiles, 
+    	minMatch, maxGap, tileSize, repMatch, NULL, allowOneMismatch, 
+	doMask, stepSize);
+    }
+else
+    {
+    uglyf("starting untranslated server...\n");
+    logInfo("setting up untranslated index");
+    gf = gfIndexNibsAndTwoBits(fileCount, seqFiles, minMatch, 
+    	maxGap, tileSize, repMatch, NULL, allowOneMismatch, stepSize);
+    }
+logInfo("indexing complete");
+
+/* Set up socket.  Get ready to listen to it. */
+socketHandle = netAcceptingSocket(port, 100);
+if (socketHandle < 0)
+    errAbort("Fatal Error: Unable to open listening socket on port %d.", port);
+
+logInfo("Server ready for queries!");
+printf("Server ready for queries!\n");
+int connectFailCount = 0;
+for (;;)
+    {
+    ZeroVar(&fromAddr);
+    fromLen = sizeof(fromAddr);
+    connectionHandle = accept(socketHandle, (struct sockaddr*)&fromAddr, &fromLen);
+    if (connectionHandle < 0)
+        {
+	warn("Error accepting the connection");
+	++warnCount;
+        ++connectFailCount;
+        if (connectFailCount >= 100)
+	    errAbort("100 continuous connection failures, no point in filling up the log in an infinite loop.");
+	continue;
+	}
+    else
+	{
+	connectFailCount = 0;
+	}
+    if (ipLog)
+	{
+        if (fromAddr.sin_family == AF_INET)
+	    {
+	    char dottedQuad[17];
+	    internetIpToDottedQuad(ntohl(fromAddr.sin_addr.s_addr), dottedQuad);
+	    logInfo("gfServer version %s on host %s, port %s connection from %s", 
+		gfVersion, hostName, portName, dottedQuad);
+	    }
+	}
+    readSize = read(connectionHandle, buf, sizeof(buf)-1);
+    if (readSize < 0)
+        {
+	warn("Error reading from socket: %s", strerror(errno));
+	++warnCount;
+	close(connectionHandle);
+	continue;
+	}
+    if (readSize == 0)
+        {
+	warn("Zero sized query");
+	++warnCount;
+	close(connectionHandle);
+	continue;
+	}
+    buf[readSize] = 0;
+    logDebug("%s", buf);
+    if (!startsWith(gfSignature(), buf))
+        {
+	++noSigCount;
+	close(connectionHandle);
+	continue;
+	}
+    line = buf + strlen(gfSignature());
+    command = nextWord(&line);
+    if (sameString("quit", command))
+        {
+	if (canStop)
+	    break;
+	else
+	    logError("Ignoring quit message");
+	}
+    else if (sameString("status", command))
+        {
+	sprintf(buf, "version %s", gfVersion);
+	netSendString(connectionHandle, buf);
+	sprintf(buf, "type %s", (doTrans ? "translated" : "nucleotide"));
+	netSendString(connectionHandle, buf);
+	sprintf(buf, "host %s", hostName);
+	netSendString(connectionHandle, buf);
+	sprintf(buf, "port %s", portName);
+	netSendString(connectionHandle, buf);
+	sprintf(buf, "tileSize %d", tileSize);
+	netSendString(connectionHandle, buf);
+	sprintf(buf, "stepSize %d", stepSize);
+	netSendString(connectionHandle, buf);
+	sprintf(buf, "minMatch %d", minMatch);
+	netSendString(connectionHandle, buf);
+	sprintf(buf, "pcr requests %ld", pcrCount);
+	netSendString(connectionHandle, buf);
+	sprintf(buf, "blat requests %ld", blatCount);
+	netSendString(connectionHandle, buf);
+	sprintf(buf, "bases %ld", baseCount);
+	netSendString(connectionHandle, buf);
+	if (doTrans)
+	    {
+	    sprintf(buf, "aa %ld", aaCount);
+	    netSendString(connectionHandle, buf);
+	    }
+	sprintf(buf, "misses %d", missCount);
+	netSendString(connectionHandle, buf);
+	sprintf(buf, "noSig %d", noSigCount);
+	netSendString(connectionHandle, buf);
+	sprintf(buf, "trimmed %d", trimCount);
+	netSendString(connectionHandle, buf);
+	sprintf(buf, "warnings %d", warnCount);
+	netSendString(connectionHandle, buf);
+	netSendString(connectionHandle, "end");
+	}
+    else if (sameString("query", command) || 
+    	sameString("protQuery", command) || sameString("transQuery", command))
+        {
+	boolean queryIsProt = sameString(command, "protQuery");
+	char *s = nextWord(&line);
+	if (s == NULL || !isdigit(s[0]))
+	    {
+	    warn("Expecting query size after query command");
+	    ++warnCount;
+	    }
+	else
+	    {
+	    struct dnaSeq seq;
+            ZeroVar(&seq);
+
+	    if (queryIsProt && !doTrans)
+	        {
+		warn("protein query sent to nucleotide server");
+		++warnCount;
+		queryIsProt = FALSE;
+		}
+	    else
+		{
+		buf[0] = 'Y';
+		if (write(connectionHandle, buf, 1) == 1)
+		    {
+		    seq.size = atoi(s);
+		    seq.name = NULL;
+		    if (seq.size > 0)
+			{
+			++blatCount;
+			seq.dna = needLargeMem(seq.size+1);
+			if (gfReadMulti(connectionHandle, seq.dna, seq.size) != seq.size)
+			    {
+			    warn("Didn't sockRecieveString all %d bytes of query sequence", seq.size);
+			    ++warnCount;
+			    }
+			else
+			    {
+			    int maxSize = (doTrans ? maxAaSize : maxNtSize);
+
+			    seq.dna[seq.size] = 0;
+			    if (queryIsProt)
+				{
+				seq.size = aaFilteredSize(seq.dna);
+				aaFilter(seq.dna, seq.dna);
+				}
+			    else
+				{
+				seq.size = dnaFilteredSize(seq.dna);
+				dnaFilter(seq.dna, seq.dna);
+				}
+			    if (seq.size > maxSize)
+				{
+				++trimCount;
+				seq.size = maxSize;
+				seq.dna[maxSize] = 0;
+				}
+			    if (queryIsProt)
+				aaCount += seq.size;
+			    else
+				baseCount += seq.size;
+                            if (seqLog && (logGetFile() != NULL))
+				{
+                                FILE *lf = logGetFile();
+                                faWriteNext(lf, "query", seq.dna, seq.size);
+				fflush(lf);
+				}
+			    errorSafeQuery(doTrans, queryIsProt, &seq, gf, 
+				    transGf, connectionHandle, buf);
+			    }
+			freez(&seq.dna);
+			}
+		    netSendString(connectionHandle, "end");
+		    }
+		}
+	    }
+	}
+    else if (sameString("pcr", command))
+        {
+	char *f = nextWord(&line);
+	char *r = nextWord(&line);
+	char *s = nextWord(&line);
+	int maxDistance;
+	++pcrCount;
+	if (s == NULL || !isdigit(s[0]))
+	    {
+	    warn("Badly formatted pcr command");
+	    ++warnCount;
+	    }
+	else if (doTrans)
+	    {
+	    warn("Can't pcr on translated server");
+	    ++warnCount;
+	    }
+	else if (badPcrPrimerSeq(f) || badPcrPrimerSeq(r))
+	    {
+	    warn("Can only handle ACGT in primer sequences.");
+	    ++warnCount;
+	    }
+	else
+	    {
+	    maxDistance = atoi(s);
+	    errorSafePcr(gf, f, r, maxDistance, connectionHandle);
+	    }
+	}
+    else if (sameString("files", command))
+        {
+	int i;
+	sprintf(buf, "%d", fileCount);
+	netSendString(connectionHandle, buf);
+	for (i=0; i<fileCount; ++i)
+	    {
+	    sprintf(buf, "%s", seqFiles[i]);
+	    netSendString(connectionHandle, buf);
+	    }
+	}
+    else
+        {
+	warn("Unknown command %s", command);
+	++warnCount;
+	}
+    close(connectionHandle);
+    connectionHandle = 0;
+    }
+close(socketHandle);
+}
+
+void stopServer(char *hostName, char *portName)
+/* Send stop message to server. */
+{
+char buf[256];
+int sd = 0;
+
+sd = netMustConnectTo(hostName, portName);
+sprintf(buf, "%squit", gfSignature());
+mustWriteFd(sd, buf, strlen(buf));
+close(sd);
+printf("sent stop message to server\n");
+}
+
+int statusServer(char *hostName, char *portName)
+/* Send status message to server arnd report result. */
+{
+char buf[256];
+int sd = 0;
+int ret = 0;
+
+/* Put together command. */
+sd = netMustConnectTo(hostName, portName);
+sprintf(buf, "%sstatus", gfSignature());
+mustWriteFd(sd, buf, strlen(buf));
+
+for (;;)
+    {
+    if (netGetString(sd, buf) == NULL)
+	{
+	warn("Error reading status information from %s:%s",hostName,portName);
+	ret = -1;
+        break;
+	}
+    if (sameString(buf, "end"))
+        break;
+    else
+        printf("%s\n", buf);
+    }
+close(sd);
+return(ret); 
+}
+
+void queryServer(char *type, 
+	char *hostName, char *portName, char *faName, boolean complex, boolean isProt)
+/* Send simple query to server and report results. */
+{
+char buf[256];
+int sd = 0;
+bioSeq *seq = faReadSeq(faName, !isProt);
+int matchCount = 0;
+
+/* Put together query command. */
+sd = netMustConnectTo(hostName, portName);
+sprintf(buf, "%s%s %d", gfSignature(), type, seq->size);
+mustWriteFd(sd, buf, strlen(buf));
+
+if (read(sd, buf, 1) < 0)
+    errAbort("queryServer: read failed: %s", strerror(errno));
+if (buf[0] != 'Y')
+    errAbort("Expecting 'Y' from server, got %c", buf[0]);
+mustWriteFd(sd, seq->dna, seq->size);
+
+if (complex)
+    {
+    char *s = netRecieveString(sd, buf);
+    printf("%s\n", s);
+    }
+
+for (;;)
+    {
+    if (netGetString(sd, buf) == NULL)
+        break;
+    if (sameString(buf, "end"))
+	{
+	printf("%d matches\n", matchCount);
+	break;
+	}
+    else if (startsWith("Error:", buf))
+       {
+       errAbort("%s", buf);
+       break;
+       }
+    else
+	{
+        printf("%s\n", buf);
+	if (complex)
+	    {
+	    char *s = netGetLongString(sd);
+	    if (s == NULL)
+	        break;
+	    printf("%s\n", s);
+	    freeMem(s);
+	    }
+	}
+    ++matchCount;
+    }
+close(sd);
+}
+
+void pcrServer(char *hostName, char *portName, char *fPrimer, char *rPrimer, int maxSize)
+/* Do a PCR query to server daemon. */
+{
+char buf[256];
+int sd = 0;
+
+/* Put together query command and send. */
+sd = netMustConnectTo(hostName, portName);
+sprintf(buf, "%spcr %s %s %d", gfSignature(), fPrimer, rPrimer, maxSize);
+mustWriteFd(sd, buf, strlen(buf));
+
+/* Fetch and display results. */
+for (;;)
+    {
+    if (netGetString(sd, buf) == NULL)
+        break;
+    if (sameString(buf, "end"))
+	break;
+    else if (startsWith("Error:", buf))
+	{
+	errAbort("%s", buf);
+	break;
+	}
+    else
+	{
+        printf("%s\n", buf);
+	}
+    }
+close(sd);
+}
+
+
+void getFileList(char *hostName, char *portName)
+/* Get and display input file list. */
+{
+char buf[256];
+int sd = 0;
+int fileCount;
+int i;
+
+/* Put together command. */
+sd = netMustConnectTo(hostName, portName);
+sprintf(buf, "%sfiles", gfSignature());
+mustWriteFd(sd, buf, strlen(buf));
+
+/* Get count of files, and then each file name. */
+if (netGetString(sd, buf) != NULL)
+    {
+    fileCount = atoi(buf);
+    for (i=0; i<fileCount; ++i)
+	{
+	printf("%s\n", netRecieveString(sd, buf));
+	}
+    }
+close(sd);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+char *command;
+
+gfCatchPipes();
+dnaUtilOpen();
+optionInit(&argc, argv, optionSpecs);
+command = argv[1];
+if (optionExists("trans"))
+    {
+    doTrans = TRUE;
+    tileSize = 4;
+    minMatch = 3;
+    maxGap = 0;
+    repMatch = gfPepMaxTileUse;
+    }
+tileSize = optionInt("tileSize", tileSize);
+stepSize = optionInt("stepSize", tileSize);
+if (optionExists("repMatch"))
+    repMatch = optionInt("repMatch", 0);
+else
+    repMatch = gfDefaultRepMatch(tileSize, stepSize, doTrans);
+minMatch = optionInt("minMatch", minMatch);
+maxDnaHits = optionInt("maxDnaHits", maxDnaHits);
+maxTransHits = optionInt("maxTransHits", maxTransHits);
+maxNtSize = optionInt("maxNtSize", maxNtSize);
+maxAaSize = optionInt("maxAaSize", maxAaSize);
+seqLog = optionExists("seqLog");
+ipLog = optionExists("ipLog");
+doMask = optionExists("mask");
+canStop = optionExists("canStop");
+if (argc < 2)
+    usage();
+if (optionExists("log"))
+    logOpenFile(argv[0], optionVal("log", NULL));
+if (optionExists("syslog"))
+    logOpenSyslog(argv[0], optionVal("logFacility", NULL));
+
+if (sameWord(command, "direct"))
+    {
+    if (argc < 4)
+        usage();
+    genoFindDirect(argv[2], argc-3, argv+3);
+    }
+else if (sameWord(command, "pcrDirect"))
+    {
+    if (argc < 5)
+        usage();
+    genoPcrDirect(argv[2], argv[3], argc-4, argv+4);
+    }
+else if (sameWord(command, "start"))
+    {
+    if (argc < 5)
+        usage();
+    startServer(argv[2], argv[3], argc-4, argv+4);
+    }
+else if (sameWord(command, "stop"))
+    {
+    if (argc != 4)
+	usage();
+    stopServer(argv[2], argv[3]);
+    }
+else if (sameWord(command, "query"))
+    {
+    if (argc != 5)
+	usage();
+    queryServer(command, argv[2], argv[3], argv[4], FALSE, FALSE);
+    }
+else if (sameWord(command, "protQuery"))
+    {
+    if (argc != 5)
+	usage();
+    queryServer(command, argv[2], argv[3], argv[4], TRUE, TRUE);
+    }
+else if (sameWord(command, "transQuery"))
+    {
+    if (argc != 5)
+	usage();
+    queryServer(command, argv[2], argv[3], argv[4], TRUE, FALSE);
+    }
+else if (sameWord(command, "pcr"))
+    {
+    if (argc != 7)
+        usage();
+    pcrServer(argv[2], argv[3], argv[4], argv[5], atoi(argv[6]));
+    }
+else if (sameWord(command, "status"))
+    {
+    if (argc != 4)
+	usage();
+    if (statusServer(argv[2], argv[3]))
+	{
+	exit(-1);
+	}
+    }
+else if (sameWord(command, "files"))
+    {
+    if (argc != 4)
+	usage();
+    getFileList(argv[2], argv[3]);
+    }
+else
+    {
+    usage();
+    }
+return 0;
+}
diff --git a/gfServer/makefile b/gfServer/makefile
new file mode 100644
index 0000000..da5bcef
--- /dev/null
+++ b/gfServer/makefile
@@ -0,0 +1,29 @@
+include ../inc/common.mk
+
+L += -lm $(SOCKETLIB)
+MYLIBDIR = ../lib/$(MACHTYPE)
+MYLIBS =  $(MYLIBDIR)/jkOwnLib.a $(MYLIBDIR)/jkweb.a 
+
+O = gfServer.o
+X = gfServer
+
+gfServer: $O $(MYLIBS)
+	${CC} ${COPT} ${CFLAGS} -o ${DESTDIR}${BINDIR}/$X $O $(MYLIBS) $L
+	${STRIP} ${DESTDIR}${BINDIR}/$X${EXE}
+
+test:
+	${MKDIR} tests/output
+	$X direct tests/input/mCrea.mrna tests/input/hCreaGeno.nib \
+		tests/input/mCreaGeno.nib > tests/output/testNib
+	$X direct tests/input/mCrea.mrna tests/input/creaGeno.2bit \
+		>tests/output/testTwoBit
+	cd tests && ./testProtNib output/testProtNib
+	cd tests && ./testProtTwoBit output/testProtTwoBit
+	cd tests && ./testTransNib output/testTransNib
+	cd tests && ./testTransTwoBit output/testTransTwoBit
+	cd tests && ./testPcr output/testPcr
+	diff -r -x CVS tests/expected tests/output
+	rm -r tests/output
+
+clean::
+	rm -fr ${O} tests/output
diff --git a/gfServer/repeat.fa b/gfServer/repeat.fa
new file mode 100644
index 0000000..13c3a8b
--- /dev/null
+++ b/gfServer/repeat.fa
@@ -0,0 +1,7 @@
+>chr22:35801390-35801679
+tttcttttctttttttgaaatggagtctcgctctgtcgccccggctggag
+tgcagtggcgcgatctcggctcactgcaagctctgtctcctgggttcatg
+ccattctcctgcctcagcctcccgagtagctgggactacaggtgcccacc
+accacactcggctaattttttgtatttttagtagagacggggtttcactg
+tgttagccaggatggtctcgatcttctgacctcgtgatctgcccgcctcg
+gcctcccaaagtgctgggattacagatgtgagccaccgca
diff --git a/gfServer/test1.fa b/gfServer/test1.fa
new file mode 100644
index 0000000..7e33f66
--- /dev/null
+++ b/gfServer/test1.fa
@@ -0,0 +1,11 @@
+>test1.nib:0-456
+ctcgggctcggaggaggcaccggcgggctcaggggccgtgggaggtgccg
+ggccggcagcagctgtgacctcaggcggtgcccgcttgctggtggctgcc
+gactcgggagggagggacaggtcgagcacctccggctcgcgccagctggg
+ggcggatgggctcacggtctcggggaggagcttggggggcgtgtcgtcgg
+ggtcagaggactgtggtgtaggcgaggggcagccggaggagccagagctg
+cgggcgtcgtagggggcggcgggggcggccagaagtagcccagggcccgg
+ggctgaggcctcagccttgccgggggacggggctaccaggggggcgggcg
+gaggcttgtacagcgcaaaggcgccgaacttcatgtggcggatctgtgta
+cgcaggacgctctcgctgaacttcttgctcttgcctataacgcggttccg
+cgaggg
diff --git a/gfServer/test1.nib b/gfServer/test1.nib
new file mode 100644
index 0000000..2e04ff3
Binary files /dev/null and b/gfServer/test1.nib differ
diff --git a/gfServer/test2.fa b/gfServer/test2.fa
new file mode 100644
index 0000000..537a443
--- /dev/null
+++ b/gfServer/test2.fa
@@ -0,0 +1,7 @@
+>test1.nib:0-465
+ctcgggctcggaggaggcaccggcgggctcaggggccgtgggaggtgccg
+gactcgggagggagggacaggtcgagcacctccggctcgcgccagctggg
+ggtcagaggactgtggtgtaggcgaggggcagccggaggagccagagctg
+ggctgaggcctcagccttgccgggggacggggctaccaggggggcgggcg
+cgcaggacgctctcgctgaacttcttgctcttgcctataacgcggttccg
+cgaggggactttggg
diff --git a/gfServer/test3.fa b/gfServer/test3.fa
new file mode 100644
index 0000000..cd87899
--- /dev/null
+++ b/gfServer/test3.fa
@@ -0,0 +1,9 @@
+>/cse/guests/kent/oo.18/nib/chr1.nib:6691869-6692269
+catgcaccaccacgcctggctaattttttgtatttttagtagagacgggg
+tttcaccatggccaggctggtgttgaactcctaacctcaggtgatctgcc
+cgcctcagccccccagaatgctaggattacaggcgtgagccacagcgccc
+agccagaaggaaggcttccctgaccaggaatcgaacccgggtcgtgatgg
+cgagcgcggaatcctaaccactagactaccagggagtgtcctaaaaactt
+ttaaaaaatggattacagttccattgaaactcactaattactcataaata
+cttttgaaaagcattttataacgaactttgttgcagtctggggtgtggat
+ggaactttgttgcagagatactcctttaaatcaggattaagtccagcact
diff --git a/gfServer/tests/expected/testNib b/gfServer/tests/expected/testNib
new file mode 100644
index 0000000..42fb9f1
--- /dev/null
+++ b/gfServer/tests/expected/testNib
@@ -0,0 +1,24 @@
+Counting tiles in tests/input/hCreaGeno.nib
+Counting tiles in tests/input/mCreaGeno.nib
+Adding tiles in tests/input/hCreaGeno.nib
+Adding tiles in tests/input/mCreaGeno.nib
+Done adding
+mCreaMrna 3-355 tests/input/mCreaGeno.nib 2365-2717, hits 32
+mCreaMrna 1352-1583 tests/input/mCreaGeno.nib 7040-7271, hits 21
+mCreaMrna 660-869 tests/input/mCreaGeno.nib 4268-4477, hits 19
+mCreaMrna 365-563 tests/input/mCreaGeno.nib 3311-3509, hits 18
+mCreaMrna 360-558 tests/input/hCreaGeno.nib 1155-1353, hits 15
+mCreaMrna 1086-1218 tests/input/mCreaGeno.nib 6215-6347, hits 12
+mCreaMrna 968-1089 tests/input/mCreaGeno.nib 4818-4939, hits 11
+mCreaMrna 1229-1350 tests/input/mCreaGeno.nib 6523-6644, hits 11
+mCreaMrna 662-871 tests/input/hCreaGeno.nib 2046-2255, hits 8
+mCreaMrna 561-649 tests/input/mCreaGeno.nib 3674-3762, hits 8
+mCreaMrna 888-965 tests/input/mCreaGeno.nib 4620-4697, hits 7
+mCreaMrna 968-1089 tests/input/hCreaGeno.nib 2596-2717, hits 5
+mCreaMrna 1122-1210 tests/input/hCreaGeno.nib 4411-4499, hits 5
+mCreaMrna 1237-1303 tests/input/hCreaGeno.nib 5027-5093, hits 4
+mCreaMrna 1397-1550 tests/input/hCreaGeno.nib 5390-5544, hits 4
+mCreaMrna 213-268 tests/input/hCreaGeno.nib 407-462, hits 3
+mCreaMrna 885-940 tests/input/hCreaGeno.nib 2398-2453, hits 3
+mCreaMrna 575-597 tests/input/hCreaGeno.nib 1573-1595, hits 2
+mCreaMrna 1588-1606 tests/input/mCreaGeno.nib 4092-4103, hits 8
diff --git a/gfServer/tests/expected/testPcr b/gfServer/tests/expected/testPcr
new file mode 100644
index 0000000..f52cc1b
--- /dev/null
+++ b/gfServer/tests/expected/testPcr
@@ -0,0 +1,18 @@
+Counting tiles in input/testPcr.2bit
+Done adding
+plus strand:
+0-0 input/testPcr.2bit:22_50k_plus 25003-25982, hits 0
+minus strand:
+0-0 input/testPcr.2bit:22_1k_minus 0-979, hits 0
+Counting tiles in input/testPcr.2bit
+Done adding
+plus strand:
+0-0 input/testPcr.2bit:22_50k_plus 25058-25938, hits 0
+minus strand:
+0-0 input/testPcr.2bit:22_1k_minus 55-935, hits 0
+Counting tiles in input/testPcr.2bit
+Done adding
+plus strand:
+0-0 input/testPcr.2bit:22_1k_minus 55-935, hits 0
+minus strand:
+0-0 input/testPcr.2bit:22_50k_plus 25058-25938, hits 0
diff --git a/gfServer/tests/expected/testProtNib b/gfServer/tests/expected/testProtNib
new file mode 100644
index 0000000..8ef5b6b
--- /dev/null
+++ b/gfServer/tests/expected/testProtNib
@@ -0,0 +1,38 @@
+tileSize 4
+149	221	input/hCreaGeno.nib	680	752	18	+	0
+ 149 680 153 684 157 688 161 692 165 696 169 700 173 704 177 708 181 712 185 716 189 720 193 724 197 728 201 732 205 736 209 740 213 744 217 748
+3	47	input/mCreaGeno.nib	860	904	11	+	0
+ 3 860 7 864 11 868 15 872 19 876 23 880 27 884 31 888 35 892 39 896 43 900
+298	338	input/hCreaGeno.nib	1464	1504	10	+	0
+ 298 1464 302 1468 306 1472 310 1476 314 1480 318 1484 322 1488 326 1492 330 1496 334 1500
+255	291	input/mCreaGeno.nib	1608	1644	9	+	0
+ 255 1608 259 1612 263 1616 267 1620 271 1624 275 1628 279 1632 283 1636 287 1640
+343	379	input/hCreaGeno.nib	1676	1712	8	+	0
+ 343 1676 347 1680 351 1684 355 1688 359 1692 367 1700 371 1704 375 1708
+226	250	input/hCreaGeno.nib	800	824	6	+	0
+ 226 800 230 804 234 808 238 812 242 816 246 820
+152	220	input/mCreaGeno.nib	1424	1492	17	+	1
+ 152 1424 156 1428 160 1432 164 1436 168 1440 172 1444 176 1448 180 1452 184 1456 188 1460 192 1464 196 1468 200 1472 204 1476 208 1480 212 1484 216 1488
+293	337	input/mCreaGeno.nib	2072	2116	11	+	1
+ 293 2072 297 2076 301 2080 305 2084 309 2088 313 2092 317 2096 321 2100 325 2104 329 2108 333 2112
+338	378	input/mCreaGeno.nib	2172	2212	10	+	1
+ 338 2172 342 2176 346 2180 350 2184 354 2188 358 2192 362 2196 366 2200 370 2204 374 2208
+252	292	input/hCreaGeno.nib	864	904	10	+	1
+ 252 864 256 868 260 872 264 876 268 880 272 884 276 888 280 892 284 896 288 900
+117	149	input/mCreaGeno.nib	1224	1256	8	+	1
+ 117 1224 121 1228 125 1232 129 1236 133 1240 137 1244 141 1248 145 1252
+2	34	input/hCreaGeno.nib	136	168	7	+	1
+ 2 136 6 140 10 144 14 148 18 152 22 156 30 164
+122	146	input/hCreaGeno.nib	524	548	6	+	1
+ 122 524 126 528 130 532 134 536 138 540 142 544
+49	117	input/mCreaGeno.nib	1100	1168	17	+	2
+ 49 1100 53 1104 57 1108 61 1112 65 1116 69 1120 73 1124 77 1128 81 1132 85 1136 89 1140 93 1144 97 1148 101 1152 105 1156 109 1160 113 1164
+50	118	input/hCreaGeno.nib	384	452	17	+	2
+ 50 384 54 388 58 392 62 396 66 400 70 404 74 408 78 412 82 416 86 420 90 424 94 428 98 432 102 436 106 440 110 444 114 448
+383	415	input/mCreaGeno.nib	2348	2380	8	+	2
+ 383 2348 387 2352 391 2356 395 2360 399 2364 403 2368 407 2372 411 2376
+223	251	input/mCreaGeno.nib	1536	1564	7	+	2
+ 223 1536 227 1540 231 1544 235 1548 239 1552 243 1556 247 1560
+380	408	input/hCreaGeno.nib	1780	1808	7	+	2
+ 380 1780 384 1784 388 1788 392 1792 396 1796 400 1800 404 1804
+18 matches
diff --git a/gfServer/tests/expected/testProtTwoBit b/gfServer/tests/expected/testProtTwoBit
new file mode 100644
index 0000000..95040ac
--- /dev/null
+++ b/gfServer/tests/expected/testProtTwoBit
@@ -0,0 +1,38 @@
+tileSize 4
+149	221	input/creaGeno.2bit:hCreaGeno	680	752	18	+	0
+ 149 680 153 684 157 688 161 692 165 696 169 700 173 704 177 708 181 712 185 716 189 720 193 724 197 728 201 732 205 736 209 740 213 744 217 748
+3	47	input/creaGeno.2bit:mCreatGeno	860	904	11	+	0
+ 3 860 7 864 11 868 15 872 19 876 23 880 27 884 31 888 35 892 39 896 43 900
+298	338	input/creaGeno.2bit:hCreaGeno	1464	1504	10	+	0
+ 298 1464 302 1468 306 1472 310 1476 314 1480 318 1484 322 1488 326 1492 330 1496 334 1500
+255	291	input/creaGeno.2bit:mCreatGeno	1608	1644	9	+	0
+ 255 1608 259 1612 263 1616 267 1620 271 1624 275 1628 279 1632 283 1636 287 1640
+343	379	input/creaGeno.2bit:hCreaGeno	1676	1712	8	+	0
+ 343 1676 347 1680 351 1684 355 1688 359 1692 367 1700 371 1704 375 1708
+226	250	input/creaGeno.2bit:hCreaGeno	800	824	6	+	0
+ 226 800 230 804 234 808 238 812 242 816 246 820
+152	220	input/creaGeno.2bit:mCreatGeno	1424	1492	17	+	1
+ 152 1424 156 1428 160 1432 164 1436 168 1440 172 1444 176 1448 180 1452 184 1456 188 1460 192 1464 196 1468 200 1472 204 1476 208 1480 212 1484 216 1488
+293	337	input/creaGeno.2bit:mCreatGeno	2072	2116	11	+	1
+ 293 2072 297 2076 301 2080 305 2084 309 2088 313 2092 317 2096 321 2100 325 2104 329 2108 333 2112
+252	292	input/creaGeno.2bit:hCreaGeno	864	904	10	+	1
+ 252 864 256 868 260 872 264 876 268 880 272 884 276 888 280 892 284 896 288 900
+338	378	input/creaGeno.2bit:mCreatGeno	2172	2212	10	+	1
+ 338 2172 342 2176 346 2180 350 2184 354 2188 358 2192 362 2196 366 2200 370 2204 374 2208
+117	149	input/creaGeno.2bit:mCreatGeno	1224	1256	8	+	1
+ 117 1224 121 1228 125 1232 129 1236 133 1240 137 1244 141 1248 145 1252
+2	34	input/creaGeno.2bit:hCreaGeno	136	168	7	+	1
+ 2 136 6 140 10 144 14 148 18 152 22 156 30 164
+122	146	input/creaGeno.2bit:hCreaGeno	524	548	6	+	1
+ 122 524 126 528 130 532 134 536 138 540 142 544
+50	118	input/creaGeno.2bit:hCreaGeno	384	452	17	+	2
+ 50 384 54 388 58 392 62 396 66 400 70 404 74 408 78 412 82 416 86 420 90 424 94 428 98 432 102 436 106 440 110 444 114 448
+49	117	input/creaGeno.2bit:mCreatGeno	1100	1168	17	+	2
+ 49 1100 53 1104 57 1108 61 1112 65 1116 69 1120 73 1124 77 1128 81 1132 85 1136 89 1140 93 1144 97 1148 101 1152 105 1156 109 1160 113 1164
+383	415	input/creaGeno.2bit:mCreatGeno	2348	2380	8	+	2
+ 383 2348 387 2352 391 2356 395 2360 399 2364 403 2368 407 2372 411 2376
+380	408	input/creaGeno.2bit:hCreaGeno	1780	1808	7	+	2
+ 380 1780 384 1784 388 1788 392 1792 396 1796 400 1800 404 1804
+223	251	input/creaGeno.2bit:mCreatGeno	1536	1564	7	+	2
+ 223 1536 227 1540 231 1544 235 1548 239 1552 243 1556 247 1560
+18 matches
diff --git a/gfServer/tests/expected/testTransNib b/gfServer/tests/expected/testTransNib
new file mode 100644
index 0000000..d804f0a
--- /dev/null
+++ b/gfServer/tests/expected/testTransNib
@@ -0,0 +1,94 @@
+tileSize 4
+452	528	input/mCreaGeno.nib	2348	2424	16	+	0	0
+ 452 2348 456 2352 464 2360 468 2364 472 2368 476 2372 480 2376 484 2380 488 2384 492 2388 496 2392 500 2396 508 2404 512 2408 516 2412 524 2420
+122	186	input/mCreaGeno.nib	1104	1168	14	+	0	0
+ 122 1104 126 1108 130 1112 138 1120 142 1124 146 1128 150 1132 158 1140 162 1144 166 1148 170 1152 174 1156 178 1160 182 1164
+123	187	input/hCreaGeno.nib	388	452	12	+	0	0
+ 123 388 127 392 131 396 139 404 143 408 147 412 151 416 167 432 171 436 175 440 179 444 183 448
+296	320	input/mCreaGeno.nib	1540	1564	5	+	0	0
+ 296 1540 300 1544 308 1552 312 1556 316 1560
+1	117	input/mCreaGeno.nib	788	904	26	+	0	1
+ 1 788 5 792 9 796 13 800 17 804 25 812 29 816 33 820 37 824 41 828 45 832 49 836 57 844 61 848 65 852 69 856 73 860 77 864 81 868 85 872 89 876 93 880 97 884 101 888 109 896 113 900
+321	361	input/mCreaGeno.nib	1604	1644	8	+	0	1
+ 321 1604 325 1608 333 1616 337 1620 341 1624 345 1628 353 1636 357 1640
+223	291	input/hCreaGeno.nib	684	752	6	+	0	1
+ 223 684 227 688 235 696 259 720 271 732 287 748
+372	396	input/hCreaGeno.nib	1468	1492	4	+	0	1
+ 372 1468 376 1472 388 1484 392 1488
+413	433	input/hCreaGeno.nib	1676	1696	3	+	0	1
+ 413 1676 425 1688 429 1692
+222	290	input/mCreaGeno.nib	1424	1492	13	+	0	2
+ 222 1424 226 1428 230 1432 234 1436 238 1440 242 1444 246 1448 250 1452 258 1460 270 1472 274 1476 278 1480 286 1488
+408	448	input/mCreaGeno.nib	2172	2212	9	+	0	2
+ 408 2172 412 2176 420 2184 424 2188 428 2192 432 2196 436 2200 440 2204 444 2208
+367	403	input/mCreaGeno.nib	2076	2112	7	+	0	2
+ 367 2076 371 2080 375 2084 387 2096 391 2100 395 2104 399 2108
+187	219	input/mCreaGeno.nib	1224	1256	6	+	0	2
+ 187 1224 191 1228 199 1236 203 1240 211 1248 215 1252
+68	88	input/hCreaGeno.nib	132	152	3	+	0	2
+ 68 132 72 136 84 148
+322	358	input/hCreaGeno.nib	864	900	3	+	0	2
+ 322 864 350 892 354 896
+229	289	input/mCreaGeno.nib	1432	1492	13	+	1	0
+ 229 1432 233 1436 237 1440 241 1444 245 1448 249 1452 253 1456 257 1460 261 1464 265 1468 273 1476 281 1484 285 1488
+362	406	input/mCreaGeno.nib	2072	2116	9	+	1	0
+ 362 2072 366 2076 370 2080 378 2088 382 2092 390 2100 394 2104 398 2108 402 2112
+411	447	input/mCreaGeno.nib	2176	2212	7	+	1	0
+ 411 2176 415 2180 419 2184 423 2188 427 2192 431 2196 443 2208
+71	87	input/hCreaGeno.nib	136	152	3	+	1	0
+ 71 136 75 140 83 148
+452	528	input/mCreaGeno.nib	2348	2424	18	+	1	1
+ 452 2348 456 2352 460 2356 468 2364 472 2368 476 2372 480 2376 484 2380 488 2384 492 2388 496 2392 500 2396 504 2400 508 2404 512 2408 516 2412 520 2416 524 2420
+122	178	input/mCreaGeno.nib	1104	1160	14	+	1	1
+ 122 1104 126 1108 130 1112 134 1116 138 1120 142 1124 146 1128 150 1132 154 1136 158 1140 162 1144 166 1148 170 1152 174 1156
+123	179	input/hCreaGeno.nib	388	444	11	+	1	1
+ 123 388 127 392 131 396 135 400 139 404 143 408 147 412 151 416 167 432 171 436 175 440
+300	320	input/mCreaGeno.nib	1544	1564	4	+	1	1
+ 300 1544 304 1548 308 1552 316 1560
+1	117	input/mCreaGeno.nib	788	904	25	+	1	2
+ 1 788 5 792 9 796 17 804 25 812 29 816 33 820 37 824 41 828 45 832 49 836 53 840 61 848 65 852 69 856 73 860 77 864 81 868 85 872 89 876 93 880 97 884 101 888 105 892 113 900
+325	361	input/mCreaGeno.nib	1608	1644	7	+	1	2
+ 325 1608 329 1612 337 1620 341 1624 345 1628 349 1632 357 1640
+227	291	input/hCreaGeno.nib	688	752	6	+	1	2
+ 227 688 235 696 247 708 259 720 271 732 287 748
+409	433	input/hCreaGeno.nib	1672	1696	4	+	1	2
+ 409 1672 413 1676 425 1688 429 1692
+372	396	input/hCreaGeno.nib	1468	1492	3	+	1	2
+ 372 1468 384 1480 392 1488
+0	116	input/mCreaGeno.nib	788	904	25	+	2	0
+ 0 788 4 792 8 796 12 800 16 804 28 816 32 820 36 824 40 828 44 832 52 840 56 844 64 852 68 856 72 860 76 864 80 868 84 872 88 876 92 880 96 884 100 888 104 892 108 896 112 900
+218	290	input/hCreaGeno.nib	680	752	18	+	2	0
+ 218 680 222 684 226 688 230 692 234 696 238 700 242 704 246 708 250 712 254 716 258 720 262 724 266 728 270 732 274 736 278 740 282 744 286 748
+367	407	input/hCreaGeno.nib	1464	1504	10	+	2	0
+ 367 1464 371 1468 375 1472 379 1476 383 1480 387 1484 391 1488 395 1492 399 1496 403 1500
+324	360	input/mCreaGeno.nib	1608	1644	9	+	2	0
+ 324 1608 328 1612 332 1616 336 1620 340 1624 344 1628 348 1632 352 1636 356 1640
+412	448	input/hCreaGeno.nib	1676	1712	8	+	2	0
+ 412 1676 416 1680 420 1684 424 1688 428 1692 436 1700 440 1704 444 1708
+295	319	input/hCreaGeno.nib	800	824	6	+	2	0
+ 295 800 299 804 303 808 307 812 311 816 315 820
+221	289	input/mCreaGeno.nib	1424	1492	17	+	2	1
+ 221 1424 225 1428 229 1432 233 1436 237 1440 241 1444 245 1448 249 1452 253 1456 257 1460 261 1464 265 1468 269 1472 273 1476 277 1480 281 1484 285 1488
+362	406	input/mCreaGeno.nib	2072	2116	11	+	2	1
+ 362 2072 366 2076 370 2080 374 2084 378 2088 382 2092 386 2096 390 2100 394 2104 398 2108 402 2112
+407	447	input/mCreaGeno.nib	2172	2212	10	+	2	1
+ 407 2172 411 2176 415 2180 419 2184 423 2188 427 2192 431 2196 435 2200 439 2204 443 2208
+321	361	input/hCreaGeno.nib	864	904	10	+	2	1
+ 321 864 325 868 329 872 333 876 337 880 341 884 345 888 349 892 353 896 357 900
+186	218	input/mCreaGeno.nib	1224	1256	8	+	2	1
+ 186 1224 190 1228 194 1232 198 1236 202 1240 206 1244 210 1248 214 1252
+67	103	input/hCreaGeno.nib	132	168	8	+	2	1
+ 67 132 71 136 75 140 79 144 83 148 87 152 91 156 99 164
+191	215	input/hCreaGeno.nib	524	548	6	+	2	1
+ 191 524 195 528 199 532 203 536 207 540 211 544
+118	186	input/mCreaGeno.nib	1100	1168	17	+	2	2
+ 118 1100 122 1104 126 1108 130 1112 134 1116 138 1120 142 1124 146 1128 150 1132 154 1136 158 1140 162 1144 166 1148 170 1152 174 1156 178 1160 182 1164
+452	528	input/mCreaGeno.nib	2348	2424	17	+	2	2
+ 452 2348 456 2352 460 2356 464 2360 468 2364 472 2368 476 2372 480 2376 488 2384 496 2392 500 2396 504 2400 508 2404 512 2408 516 2412 520 2416 524 2420
+119	187	input/hCreaGeno.nib	384	452	17	+	2	2
+ 119 384 123 388 127 392 131 396 135 400 139 404 143 408 147 412 151 416 155 420 159 424 163 428 167 432 171 436 175 440 179 444 183 448
+292	320	input/mCreaGeno.nib	1536	1564	7	+	2	2
+ 292 1536 296 1540 300 1544 304 1548 308 1552 312 1556 316 1560
+449	477	input/hCreaGeno.nib	1780	1808	7	+	2	2
+ 449 1780 453 1784 457 1788 461 1792 465 1796 469 1800 473 1804
+46 matches
diff --git a/gfServer/tests/expected/testTransTwoBit b/gfServer/tests/expected/testTransTwoBit
new file mode 100644
index 0000000..3647e99
--- /dev/null
+++ b/gfServer/tests/expected/testTransTwoBit
@@ -0,0 +1,94 @@
+tileSize 4
+452	528	input/creaGeno.2bit:mCreatGeno	2348	2424	16	+	0	0
+ 452 2348 456 2352 464 2360 468 2364 472 2368 476 2372 480 2376 484 2380 488 2384 492 2388 496 2392 500 2396 508 2404 512 2408 516 2412 524 2420
+122	186	input/creaGeno.2bit:mCreatGeno	1104	1168	14	+	0	0
+ 122 1104 126 1108 130 1112 138 1120 142 1124 146 1128 150 1132 158 1140 162 1144 166 1148 170 1152 174 1156 178 1160 182 1164
+123	187	input/creaGeno.2bit:hCreaGeno	388	452	12	+	0	0
+ 123 388 127 392 131 396 139 404 143 408 147 412 151 416 167 432 171 436 175 440 179 444 183 448
+296	320	input/creaGeno.2bit:mCreatGeno	1540	1564	5	+	0	0
+ 296 1540 300 1544 308 1552 312 1556 316 1560
+1	117	input/creaGeno.2bit:mCreatGeno	788	904	26	+	0	1
+ 1 788 5 792 9 796 13 800 17 804 25 812 29 816 33 820 37 824 41 828 45 832 49 836 57 844 61 848 65 852 69 856 73 860 77 864 81 868 85 872 89 876 93 880 97 884 101 888 109 896 113 900
+321	361	input/creaGeno.2bit:mCreatGeno	1604	1644	8	+	0	1
+ 321 1604 325 1608 333 1616 337 1620 341 1624 345 1628 353 1636 357 1640
+223	291	input/creaGeno.2bit:hCreaGeno	684	752	6	+	0	1
+ 223 684 227 688 235 696 259 720 271 732 287 748
+372	396	input/creaGeno.2bit:hCreaGeno	1468	1492	4	+	0	1
+ 372 1468 376 1472 388 1484 392 1488
+413	433	input/creaGeno.2bit:hCreaGeno	1676	1696	3	+	0	1
+ 413 1676 425 1688 429 1692
+222	290	input/creaGeno.2bit:mCreatGeno	1424	1492	13	+	0	2
+ 222 1424 226 1428 230 1432 234 1436 238 1440 242 1444 246 1448 250 1452 258 1460 270 1472 274 1476 278 1480 286 1488
+408	448	input/creaGeno.2bit:mCreatGeno	2172	2212	9	+	0	2
+ 408 2172 412 2176 420 2184 424 2188 428 2192 432 2196 436 2200 440 2204 444 2208
+367	403	input/creaGeno.2bit:mCreatGeno	2076	2112	7	+	0	2
+ 367 2076 371 2080 375 2084 387 2096 391 2100 395 2104 399 2108
+187	219	input/creaGeno.2bit:mCreatGeno	1224	1256	6	+	0	2
+ 187 1224 191 1228 199 1236 203 1240 211 1248 215 1252
+68	88	input/creaGeno.2bit:hCreaGeno	132	152	3	+	0	2
+ 68 132 72 136 84 148
+322	358	input/creaGeno.2bit:hCreaGeno	864	900	3	+	0	2
+ 322 864 350 892 354 896
+229	289	input/creaGeno.2bit:mCreatGeno	1432	1492	13	+	1	0
+ 229 1432 233 1436 237 1440 241 1444 245 1448 249 1452 253 1456 257 1460 261 1464 265 1468 273 1476 281 1484 285 1488
+362	406	input/creaGeno.2bit:mCreatGeno	2072	2116	9	+	1	0
+ 362 2072 366 2076 370 2080 378 2088 382 2092 390 2100 394 2104 398 2108 402 2112
+411	447	input/creaGeno.2bit:mCreatGeno	2176	2212	7	+	1	0
+ 411 2176 415 2180 419 2184 423 2188 427 2192 431 2196 443 2208
+71	87	input/creaGeno.2bit:hCreaGeno	136	152	3	+	1	0
+ 71 136 75 140 83 148
+452	528	input/creaGeno.2bit:mCreatGeno	2348	2424	18	+	1	1
+ 452 2348 456 2352 460 2356 468 2364 472 2368 476 2372 480 2376 484 2380 488 2384 492 2388 496 2392 500 2396 504 2400 508 2404 512 2408 516 2412 520 2416 524 2420
+122	178	input/creaGeno.2bit:mCreatGeno	1104	1160	14	+	1	1
+ 122 1104 126 1108 130 1112 134 1116 138 1120 142 1124 146 1128 150 1132 154 1136 158 1140 162 1144 166 1148 170 1152 174 1156
+123	179	input/creaGeno.2bit:hCreaGeno	388	444	11	+	1	1
+ 123 388 127 392 131 396 135 400 139 404 143 408 147 412 151 416 167 432 171 436 175 440
+300	320	input/creaGeno.2bit:mCreatGeno	1544	1564	4	+	1	1
+ 300 1544 304 1548 308 1552 316 1560
+1	117	input/creaGeno.2bit:mCreatGeno	788	904	25	+	1	2
+ 1 788 5 792 9 796 17 804 25 812 29 816 33 820 37 824 41 828 45 832 49 836 53 840 61 848 65 852 69 856 73 860 77 864 81 868 85 872 89 876 93 880 97 884 101 888 105 892 113 900
+325	361	input/creaGeno.2bit:mCreatGeno	1608	1644	7	+	1	2
+ 325 1608 329 1612 337 1620 341 1624 345 1628 349 1632 357 1640
+227	291	input/creaGeno.2bit:hCreaGeno	688	752	6	+	1	2
+ 227 688 235 696 247 708 259 720 271 732 287 748
+409	433	input/creaGeno.2bit:hCreaGeno	1672	1696	4	+	1	2
+ 409 1672 413 1676 425 1688 429 1692
+372	396	input/creaGeno.2bit:hCreaGeno	1468	1492	3	+	1	2
+ 372 1468 384 1480 392 1488
+0	116	input/creaGeno.2bit:mCreatGeno	788	904	25	+	2	0
+ 0 788 4 792 8 796 12 800 16 804 28 816 32 820 36 824 40 828 44 832 52 840 56 844 64 852 68 856 72 860 76 864 80 868 84 872 88 876 92 880 96 884 100 888 104 892 108 896 112 900
+218	290	input/creaGeno.2bit:hCreaGeno	680	752	18	+	2	0
+ 218 680 222 684 226 688 230 692 234 696 238 700 242 704 246 708 250 712 254 716 258 720 262 724 266 728 270 732 274 736 278 740 282 744 286 748
+367	407	input/creaGeno.2bit:hCreaGeno	1464	1504	10	+	2	0
+ 367 1464 371 1468 375 1472 379 1476 383 1480 387 1484 391 1488 395 1492 399 1496 403 1500
+324	360	input/creaGeno.2bit:mCreatGeno	1608	1644	9	+	2	0
+ 324 1608 328 1612 332 1616 336 1620 340 1624 344 1628 348 1632 352 1636 356 1640
+412	448	input/creaGeno.2bit:hCreaGeno	1676	1712	8	+	2	0
+ 412 1676 416 1680 420 1684 424 1688 428 1692 436 1700 440 1704 444 1708
+295	319	input/creaGeno.2bit:hCreaGeno	800	824	6	+	2	0
+ 295 800 299 804 303 808 307 812 311 816 315 820
+221	289	input/creaGeno.2bit:mCreatGeno	1424	1492	17	+	2	1
+ 221 1424 225 1428 229 1432 233 1436 237 1440 241 1444 245 1448 249 1452 253 1456 257 1460 261 1464 265 1468 269 1472 273 1476 277 1480 281 1484 285 1488
+362	406	input/creaGeno.2bit:mCreatGeno	2072	2116	11	+	2	1
+ 362 2072 366 2076 370 2080 374 2084 378 2088 382 2092 386 2096 390 2100 394 2104 398 2108 402 2112
+321	361	input/creaGeno.2bit:hCreaGeno	864	904	10	+	2	1
+ 321 864 325 868 329 872 333 876 337 880 341 884 345 888 349 892 353 896 357 900
+407	447	input/creaGeno.2bit:mCreatGeno	2172	2212	10	+	2	1
+ 407 2172 411 2176 415 2180 419 2184 423 2188 427 2192 431 2196 435 2200 439 2204 443 2208
+67	103	input/creaGeno.2bit:hCreaGeno	132	168	8	+	2	1
+ 67 132 71 136 75 140 79 144 83 148 87 152 91 156 99 164
+186	218	input/creaGeno.2bit:mCreatGeno	1224	1256	8	+	2	1
+ 186 1224 190 1228 194 1232 198 1236 202 1240 206 1244 210 1248 214 1252
+191	215	input/creaGeno.2bit:hCreaGeno	524	548	6	+	2	1
+ 191 524 195 528 199 532 203 536 207 540 211 544
+119	187	input/creaGeno.2bit:hCreaGeno	384	452	17	+	2	2
+ 119 384 123 388 127 392 131 396 135 400 139 404 143 408 147 412 151 416 155 420 159 424 163 428 167 432 171 436 175 440 179 444 183 448
+118	186	input/creaGeno.2bit:mCreatGeno	1100	1168	17	+	2	2
+ 118 1100 122 1104 126 1108 130 1112 134 1116 138 1120 142 1124 146 1128 150 1132 154 1136 158 1140 162 1144 166 1148 170 1152 174 1156 178 1160 182 1164
+452	528	input/creaGeno.2bit:mCreatGeno	2348	2424	17	+	2	2
+ 452 2348 456 2352 460 2356 464 2360 468 2364 472 2368 476 2372 480 2376 488 2384 496 2392 500 2396 504 2400 508 2404 512 2408 516 2412 520 2416 524 2420
+449	477	input/creaGeno.2bit:hCreaGeno	1780	1808	7	+	2	2
+ 449 1780 453 1784 457 1788 461 1792 465 1796 469 1800 473 1804
+292	320	input/creaGeno.2bit:mCreatGeno	1536	1564	7	+	2	2
+ 292 1536 296 1540 300 1544 304 1548 308 1552 312 1556 316 1560
+46 matches
diff --git a/gfServer/tests/expected/testTwoBit b/gfServer/tests/expected/testTwoBit
new file mode 100644
index 0000000..69eb8f4
--- /dev/null
+++ b/gfServer/tests/expected/testTwoBit
@@ -0,0 +1,21 @@
+Counting tiles in tests/input/creaGeno.2bit
+Done adding
+mCreaMrna 3-355 tests/input/creaGeno.2bit:mCreatGeno 2365-2717, hits 32
+mCreaMrna 1352-1583 tests/input/creaGeno.2bit:mCreatGeno 7040-7271, hits 21
+mCreaMrna 660-869 tests/input/creaGeno.2bit:mCreatGeno 4268-4477, hits 19
+mCreaMrna 365-563 tests/input/creaGeno.2bit:mCreatGeno 3311-3509, hits 18
+mCreaMrna 360-558 tests/input/creaGeno.2bit:hCreaGeno 1155-1353, hits 15
+mCreaMrna 1086-1218 tests/input/creaGeno.2bit:mCreatGeno 6215-6347, hits 12
+mCreaMrna 968-1089 tests/input/creaGeno.2bit:mCreatGeno 4818-4939, hits 11
+mCreaMrna 1229-1350 tests/input/creaGeno.2bit:mCreatGeno 6523-6644, hits 11
+mCreaMrna 662-871 tests/input/creaGeno.2bit:hCreaGeno 2046-2255, hits 8
+mCreaMrna 561-649 tests/input/creaGeno.2bit:mCreatGeno 3674-3762, hits 8
+mCreaMrna 888-965 tests/input/creaGeno.2bit:mCreatGeno 4620-4697, hits 7
+mCreaMrna 968-1089 tests/input/creaGeno.2bit:hCreaGeno 2596-2717, hits 5
+mCreaMrna 1122-1210 tests/input/creaGeno.2bit:hCreaGeno 4411-4499, hits 5
+mCreaMrna 1237-1303 tests/input/creaGeno.2bit:hCreaGeno 5027-5093, hits 4
+mCreaMrna 1397-1550 tests/input/creaGeno.2bit:hCreaGeno 5390-5544, hits 4
+mCreaMrna 213-268 tests/input/creaGeno.2bit:hCreaGeno 407-462, hits 3
+mCreaMrna 885-940 tests/input/creaGeno.2bit:hCreaGeno 2398-2453, hits 3
+mCreaMrna 575-597 tests/input/creaGeno.2bit:hCreaGeno 1573-1595, hits 2
+mCreaMrna 1588-1606 tests/input/creaGeno.2bit:mCreatGeno 4092-4103, hits 8
diff --git a/gfServer/tests/input/crea.mrna b/gfServer/tests/input/crea.mrna
new file mode 100644
index 0000000..0ea0d3b
--- /dev/null
+++ b/gfServer/tests/input/crea.mrna
@@ -0,0 +1,47 @@
+>hCreaMrna
+CCGGCTCCCATTCCGGCTCCAGCCTCCAATCCGACCCCCATTTCGGCTGCAGCCTCGGACCTAGCTCCGG
+CCCTCGGTCTATCCGGTTGCATCCTCCCTCCCTGTTCCGGATCTTATCTTGCGCCAGCGCCTACTCCAGG
+ATCCCGTAGCCAGACCTCAAGCCATGGCTGGTCCCTTCTCCCGTCTGCTGTCCGCCCGCCCGGGACTCAG
+GCTCCTGGCTTTGGCCGGAGCGGGGTCTCTAGCCGCTGGGTTTCTGCTCCGACCGGAACCTGTACGAGCT
+GCCAGTGAACGACGGAGGCTGTATCCCCCGAGCGCTGAGTACCCAGACCTCCGAAAGCACAACAACTGCA
+TGGCCAGTCACCTGACCCCAGCAGTCTATGCACGGCTCTGCGACAAGACCACACCCACTGGTTGGACGCT
+AGATCAGTGTATCCAGACTGGCGTGGACAACCCTGGCCACCCCTTCATCAAGACTGTGGGCATGGTGGCT
+GGAGATGAGGAGACCTATGAGGTATTTGCTGACCTGTTTGACCCTGTGATCCAAGAGCGACACAATGGAT
+ATGACCCCCGGACAATGAAGCACACCACGGATCTAGATGCCAGTAAAATCCGTTCTGGCTACTTTGATGA
+GAGGTATGTATTGTCCTCTAGAGTCAGAACTGGCCGAAGCATCCGAGGACTCAGTCTGCCTCCAGCTTGC
+ACTCGAGCAGAGCGACGAGAGGTGGAACGTGTTGTGGTGGATGCACTGAGTGGCCTGAAGGGTGACCTGG
+CTGGACGTTACTATAGGCTCAGTGAGATGACAGAGGCTGAACAGCAGCAGCTTATTGATGACCACTTTCT
+GTTTGATAAGCCTGTGTCCCCGTTGCTGACTGCAGCAGGAATGGCTCGAGACTGGCCAGATGCTCGTGGA
+ATTTGGCACAACAATGAGAAGAGCTTCCTGATCTGGGTGAATGAGGAGGATCATACACGGGTGATCTCCA
+TGGAGAAGGGTGGTAACATGAAGAGAGTGTTTGAAAGATTCTGCCGAGGCCTCAAAGAGGTGGAGAGACT
+TATCCAAGAACGTGGCTGGGAGTTCATGTGGAATGAGCGTTTGGGATACATCTTGACCTGTCCATCTAAC
+CTGGGCACTGGACTTCGGGCAGGAGTGCACATCAAACTGCCCCTGCTAAGCAAAGATAGCCGCTTCCCAA
+AGATCCTGGAGAACCTAAGACTCCAAAAACGTGGTACTGGAGGAGTGGACACTGCTGCTACAGGCGGTGT
+CTTTGATATTTCTAATTTGGACCGACTAGGCAAATCAGAGGTGGAGCTGGTGCAACTGGTCATCGATGGA
+GTAAACTATTTGATTGATTGTGAACGGCGTCTGGAGAGAGGCCAGGATATCCGCATCCCCACACCTGTCA
+TCCACACCAAGCATTAACTCCCCATCGCCAGCTGATGACTCAAGATTCCCAGGAGTTTTGCTCATTCTAA
+TGATGGCCCATTCTACTTGCTCTGGACCTGCCCCCGCATCCCCTGCCTCCATCCTAGTAAAAAAAAAAAA
+>mCreaMrna
+TGCTCTGGCTGGCTCCTTGCTTCGCTGCGCTTCTCCTGCAGCCTGGTAGGCACCGGCTGCCACTTCAGCT
+tcagccttcatcgtgacccctattttggctccagtctccgacccagctccgtcctctctctacccggttg
+CATCTTCCCTCCTAGTTCCTGACTTGCACCAGATCCTGCTCTGAATCTTTGTAGCCGCATCCCCAAGCCA
+tggctggtcccttctcccgtctgctgtctgcccgccctggactcaggctcctggctttggctggagctgg
+GTCTCTCACCGCCGGGATTCTGCTCCGCCCGGAATCTGTAGGAGCTGCCGCTGCTGAACGGAGGAGACTG
+tatcccccgagcgctgagtacccagacctccgaaagcacaacaactgcatggccagtcacctgaccccag
+CAGTCTATGCACGGCTCTGCGACAAGACCACACCCACTGGTTGGACACTAGATCAGTGCATCCAGACTGG
+agtggacaaccctggccaccccttcatcaagactgtgggcatggtggctggagatgaggagacctatgag
+GTATTTGCTGAACTGTTTGACCCTGTGATCCAAGAGCGGCATAATGGATATGACCCCAGAACAATGAAGC
+acaccactgaccttgatgccagtaaaattcgttctggctactttgatgagaggtatgtattgtcttcaag
+AGTCAGAACTGGCCGAAGTATCAGGGGACTCAGTCTCCCTCCAGCCTGCACTCGGGCAGAGCGAAGAGAG
+gtagaacgtgttgtggtggatgctctgagtggcctgaagggtgacctggctggacggtactataggctca
+GTGAGATGACGGAGGCCGAACAGCAGCAGCTTATTGATGACCATTTTCTGTTTGATAAACCTGTGTCCCC
+attgctgactgcagcaggaatggctcgagactggcctgatgctcgagggatctggcacaacaatgagaag
+AGTTTCTTGATCTGGGTGAATGAGGAGGACCACACACGGGTCATCTCTATGGAGAAAGGCGGCAACATGA
+agagagtgtttgaaagattctgccggggcctcaaagaggtggagaagctgatccaggaacgaggctggga
+GTTCATGTGGAATGAGCGTTTAGGCTACATCTTGACCTGTCCATCTAACCTGGGCACTGGACTTCGGGCA
+ggagtccacatcaaactgccactgctgagcaaagataaccgcttcccaaagatcctggagaacctaagac
+TGCAAAAGCGTGGAACTGGAGGAGTGGACACTGCTGCTACAGGCAGCGTCTTTGACATCTCTAATTTGGA
+tcgacttggcaagtcagaggtggagctggtgcagctcgtcatcgatggggtgaactatttgattgactgt
+GAACGGCGTCTGGAGAGAGGACAGGATATTCGAATCCCTCCACCTCTTGTCCACAGCAAACATTAACTCC
+ccatccccagcggatgagtcaagacccccaggacttctgcatatttaacagtggcccagtctacttgccc
+TGGACCTGCCTCTCTCCCTGTCCTAGTAAAGACTCCACATTATGTTGCAaaaaaaaaaaaaaaaaa
diff --git a/gfServer/tests/input/creaGeno.2bit b/gfServer/tests/input/creaGeno.2bit
new file mode 100644
index 0000000..c0f112f
Binary files /dev/null and b/gfServer/tests/input/creaGeno.2bit differ
diff --git a/gfServer/tests/input/hCrea.mrna b/gfServer/tests/input/hCrea.mrna
new file mode 100644
index 0000000..739a6b8
--- /dev/null
+++ b/gfServer/tests/input/hCrea.mrna
@@ -0,0 +1,23 @@
+>hCreaMrna
+CCGGCTCCCATTCCGGCTCCAGCCTCCAATCCGACCCCCATTTCGGCTGCAGCCTCGGACCTAGCTCCGG
+CCCTCGGTCTATCCGGTTGCATCCTCCCTCCCTGTTCCGGATCTTATCTTGCGCCAGCGCCTACTCCAGG
+ATCCCGTAGCCAGACCTCAAGCCATGGCTGGTCCCTTCTCCCGTCTGCTGTCCGCCCGCCCGGGACTCAG
+GCTCCTGGCTTTGGCCGGAGCGGGGTCTCTAGCCGCTGGGTTTCTGCTCCGACCGGAACCTGTACGAGCT
+GCCAGTGAACGACGGAGGCTGTATCCCCCGAGCGCTGAGTACCCAGACCTCCGAAAGCACAACAACTGCA
+TGGCCAGTCACCTGACCCCAGCAGTCTATGCACGGCTCTGCGACAAGACCACACCCACTGGTTGGACGCT
+AGATCAGTGTATCCAGACTGGCGTGGACAACCCTGGCCACCCCTTCATCAAGACTGTGGGCATGGTGGCT
+GGAGATGAGGAGACCTATGAGGTATTTGCTGACCTGTTTGACCCTGTGATCCAAGAGCGACACAATGGAT
+ATGACCCCCGGACAATGAAGCACACCACGGATCTAGATGCCAGTAAAATCCGTTCTGGCTACTTTGATGA
+GAGGTATGTATTGTCCTCTAGAGTCAGAACTGGCCGAAGCATCCGAGGACTCAGTCTGCCTCCAGCTTGC
+ACTCGAGCAGAGCGACGAGAGGTGGAACGTGTTGTGGTGGATGCACTGAGTGGCCTGAAGGGTGACCTGG
+CTGGACGTTACTATAGGCTCAGTGAGATGACAGAGGCTGAACAGCAGCAGCTTATTGATGACCACTTTCT
+GTTTGATAAGCCTGTGTCCCCGTTGCTGACTGCAGCAGGAATGGCTCGAGACTGGCCAGATGCTCGTGGA
+ATTTGGCACAACAATGAGAAGAGCTTCCTGATCTGGGTGAATGAGGAGGATCATACACGGGTGATCTCCA
+TGGAGAAGGGTGGTAACATGAAGAGAGTGTTTGAAAGATTCTGCCGAGGCCTCAAAGAGGTGGAGAGACT
+TATCCAAGAACGTGGCTGGGAGTTCATGTGGAATGAGCGTTTGGGATACATCTTGACCTGTCCATCTAAC
+CTGGGCACTGGACTTCGGGCAGGAGTGCACATCAAACTGCCCCTGCTAAGCAAAGATAGCCGCTTCCCAA
+AGATCCTGGAGAACCTAAGACTCCAAAAACGTGGTACTGGAGGAGTGGACACTGCTGCTACAGGCGGTGT
+CTTTGATATTTCTAATTTGGACCGACTAGGCAAATCAGAGGTGGAGCTGGTGCAACTGGTCATCGATGGA
+GTAAACTATTTGATTGATTGTGAACGGCGTCTGGAGAGAGGCCAGGATATCCGCATCCCCACACCTGTCA
+TCCACACCAAGCATTAACTCCCCATCGCCAGCTGATGACTCAAGATTCCCAGGAGTTTTGCTCATTCTAA
+TGATGGCCCATTCTACTTGCTCTGGACCTGCCCCCGCATCCCCTGCCTCCATCCTAGTAAAAAAAAAAAA
diff --git a/gfServer/tests/input/hCreaGeno.nib b/gfServer/tests/input/hCreaGeno.nib
new file mode 100644
index 0000000..ec296eb
Binary files /dev/null and b/gfServer/tests/input/hCreaGeno.nib differ
diff --git a/gfServer/tests/input/mCrea.mrna b/gfServer/tests/input/mCrea.mrna
new file mode 100644
index 0000000..62047c2
--- /dev/null
+++ b/gfServer/tests/input/mCrea.mrna
@@ -0,0 +1,24 @@
+>mCreaMrna
+TGCTCTGGCTGGCTCCTTGCTTCGCTGCGCTTCTCCTGCAGCCTGGTAGGCACCGGCTGCCACTTCAGCT
+tcagccttcatcgtgacccctattttggctccagtctccgacccagctccgtcctctctctacccggttg
+CATCTTCCCTCCTAGTTCCTGACTTGCACCAGATCCTGCTCTGAATCTTTGTAGCCGCATCCCCAAGCCA
+tggctggtcccttctcccgtctgctgtctgcccgccctggactcaggctcctggctttggctggagctgg
+GTCTCTCACCGCCGGGATTCTGCTCCGCCCGGAATCTGTAGGAGCTGCCGCTGCTGAACGGAGGAGACTG
+tatcccccgagcgctgagtacccagacctccgaaagcacaacaactgcatggccagtcacctgaccccag
+CAGTCTATGCACGGCTCTGCGACAAGACCACACCCACTGGTTGGACACTAGATCAGTGCATCCAGACTGG
+agtggacaaccctggccaccccttcatcaagactgtgggcatggtggctggagatgaggagacctatgag
+GTATTTGCTGAACTGTTTGACCCTGTGATCCAAGAGCGGCATAATGGATATGACCCCAGAACAATGAAGC
+acaccactgaccttgatgccagtaaaattcgttctggctactttgatgagaggtatgtattgtcttcaag
+AGTCAGAACTGGCCGAAGTATCAGGGGACTCAGTCTCCCTCCAGCCTGCACTCGGGCAGAGCGAAGAGAG
+gtagaacgtgttgtggtggatgctctgagtggcctgaagggtgacctggctggacggtactataggctca
+GTGAGATGACGGAGGCCGAACAGCAGCAGCTTATTGATGACCATTTTCTGTTTGATAAACCTGTGTCCCC
+attgctgactgcagcaggaatggctcgagactggcctgatgctcgagggatctggcacaacaatgagaag
+AGTTTCTTGATCTGGGTGAATGAGGAGGACCACACACGGGTCATCTCTATGGAGAAAGGCGGCAACATGA
+agagagtgtttgaaagattctgccggggcctcaaagaggtggagaagctgatccaggaacgaggctggga
+GTTCATGTGGAATGAGCGTTTAGGCTACATCTTGACCTGTCCATCTAACCTGGGCACTGGACTTCGGGCA
+ggagtccacatcaaactgccactgctgagcaaagataaccgcttcccaaagatcctggagaacctaagac
+TGCAAAAGCGTGGAACTGGAGGAGTGGACACTGCTGCTACAGGCAGCGTCTTTGACATCTCTAATTTGGA
+tcgacttggcaagtcagaggtggagctggtgcagctcgtcatcgatggggtgaactatttgattgactgt
+GAACGGCGTCTGGAGAGAGGACAGGATATTCGAATCCCTCCACCTCTTGTCCACAGCAAACATTAACTCC
+ccatccccagcggatgagtcaagacccccaggacttctgcatatttaacagtggcccagtctacttgccc
+TGGACCTGCCTCTCTCCCTGTCCTAGTAAAGACTCCACATTATGTTGCAaaaaaaaaaaaaaaaaa
diff --git a/gfServer/tests/input/mCrea.pep b/gfServer/tests/input/mCrea.pep
new file mode 100644
index 0000000..2cc2ab4
--- /dev/null
+++ b/gfServer/tests/input/mCrea.pep
@@ -0,0 +1,7 @@
+>mCreaPep
+MAGPFSRLLSARPGLRLLALAGAGSLTAGILLRPESVGAAAAERRRLYPPSAEYPDLRKHNNCMASHLTP
+AVYARLCDKTTPTGWTLDQCIQTGVDNPGHPFIKTVGMVAGDEETYEVFAELFDPVIQERHNGYDPRTMK
+HTTDLDASKIRSGYFDERYVLSSRVRTGRSIRGLSLPPACTRAERREVERVVVDALSGLKGDLAGRYYRL
+SEMTEAEQQQLIDDHFLFDKPVSPLLTAAGMARDWPDARGIWHNNEKSFLIWVNEEDHTRVISMEKGGNM
+KRVFERFCRGLKEVEKLIQERGWEFMWNERLGYILTCPSNLGTGLRAGVHIKLPLLSKDNRFPKILENLR
+LQKRGTGGVDTAATGSVFDISNLDRLGKSEVELVQLVIDGVNYLIDCERRLERGQDIRIPPPLVHSKH
diff --git a/gfServer/tests/input/mCreaGeno.nib b/gfServer/tests/input/mCreaGeno.nib
new file mode 100644
index 0000000..150b973
Binary files /dev/null and b/gfServer/tests/input/mCreaGeno.nib differ
diff --git a/gfServer/tests/input/testPcr.2bit b/gfServer/tests/input/testPcr.2bit
new file mode 100644
index 0000000..21e5428
Binary files /dev/null and b/gfServer/tests/input/testPcr.2bit differ
diff --git a/gfServer/tests/testPcr b/gfServer/tests/testPcr
new file mode 100755
index 0000000..b033a91
--- /dev/null
+++ b/gfServer/tests/testPcr
@@ -0,0 +1,3 @@
+gfServer pcrDirect CCTGAAGGCATCAGTGTACCCCAGGAATGCCCAA CTCATGAGTGGCTCCTAAAGCAGCTGCGTGG input/testPcr.2bit | grep -v seconds > $1 
+gfServer pcrDirect tggtgagagggggaaggtttt ggagctctgacatctgggttctg input/testPcr.2bit | grep -v seconds >> $1 
+gfServer pcrDirect GGAGCTCTGACATCTGGGTTCTGGA tggtgagagggggaaggttttcttt input/testPcr.2bit | grep -v seconds >> $1 
diff --git a/gfServer/tests/testProtNib b/gfServer/tests/testProtNib
new file mode 100755
index 0000000..4a17f5c
--- /dev/null
+++ b/gfServer/tests/testProtNib
@@ -0,0 +1,4 @@
+gfServer start -trans localhost 17768 -canStop input/mCreaGeno.nib input/hCreaGeno.nib > /dev/null 2>&1 &
+sleep 1
+gfServer protQuery localhost 17768 input/mCrea.pep > $1
+gfServer stop localhost 17768 > /dev/null
diff --git a/gfServer/tests/testProtTwoBit b/gfServer/tests/testProtTwoBit
new file mode 100755
index 0000000..6e56f0b
--- /dev/null
+++ b/gfServer/tests/testProtTwoBit
@@ -0,0 +1,4 @@
+gfServer start -trans localhost 17768 -canStop input/creaGeno.2bit >/dev/null &
+sleep 1
+gfServer protQuery localhost 17768 input/mCrea.pep > $1
+gfServer stop localhost 17768 > /dev/null
diff --git a/gfServer/tests/testTransNib b/gfServer/tests/testTransNib
new file mode 100755
index 0000000..6c0541d
--- /dev/null
+++ b/gfServer/tests/testTransNib
@@ -0,0 +1,4 @@
+gfServer start -trans localhost 17768 -canStop input/mCreaGeno.nib input/hCreaGeno.nib > /dev/null 2>&1 &
+sleep 1
+gfServer transQuery localhost 17768 input/mCrea.mrna > $1
+gfServer stop localhost 17768 > /dev/null
diff --git a/gfServer/tests/testTransTwoBit b/gfServer/tests/testTransTwoBit
new file mode 100755
index 0000000..87f0aad
--- /dev/null
+++ b/gfServer/tests/testTransTwoBit
@@ -0,0 +1,4 @@
+gfServer start -trans localhost 17768 -canStop input/creaGeno.2bit >/dev/null &
+sleep 1
+gfServer transQuery localhost 17768 input/mCrea.mrna > $1
+gfServer stop localhost 17768 > /dev/null
diff --git a/hg/pslPretty/input/S1.lst b/hg/pslPretty/input/S1.lst
new file mode 100644
index 0000000..7b7f7e4
--- /dev/null
+++ b/hg/pslPretty/input/S1.lst
@@ -0,0 +1,18 @@
+/cluster/data/hg16/nib/chr1.nib
+/cluster/data/hg16/nib/chr10.nib
+/cluster/data/hg16/nib/chr10_random.nib
+/cluster/data/hg16/nib/chr11.nib
+/cluster/data/hg16/nib/chr12.nib
+/cluster/data/hg16/nib/chr13.nib
+/cluster/data/hg16/nib/chr13_random.nib
+/cluster/data/hg16/nib/chr14.nib
+/cluster/data/hg16/nib/chr15.nib
+/cluster/data/hg16/nib/chr15_random.nib
+/cluster/data/hg16/nib/chr16.nib
+/cluster/data/hg16/nib/chr17.nib
+/cluster/data/hg16/nib/chr17_random.nib
+/cluster/data/hg16/nib/chr18.nib
+/cluster/data/hg16/nib/chr18_random.nib
+/cluster/data/hg16/nib/chr19.nib
+/cluster/data/hg16/nib/chr19_random.nib
+/cluster/data/hg16/nib/chr1_random.nib
diff --git a/hg/pslPretty/input/S2.lst b/hg/pslPretty/input/S2.lst
new file mode 100644
index 0000000..ac638e9
--- /dev/null
+++ b/hg/pslPretty/input/S2.lst
@@ -0,0 +1 @@
+/cluster/bluearc/hg/mrnaHg16/mrna050.fa
diff --git a/hg/pslPretty/input/test1.psl b/hg/pslPretty/input/test1.psl
new file mode 100644
index 0000000..58b97a9
--- /dev/null
+++ b/hg/pslPretty/input/test1.psl
@@ -0,0 +1 @@
+408	180	0	0	0	0	0	0	+	AK128780	2182	274	1947	chr1	246127941	360887	364708	17	69,40,14,10,102,67,51,38,16,40,4,39,18,18,41,5,16,	274,406,450,464,477,1538,1629,1680,1721,1742,1782,1789,1829,1848,1877,1926,1931,	360887,360956,360996,361014,361024,364288,364378,364430,364468,364484,364526,364530,364569,364587,364642,364683,364692,
diff --git a/hg/pslPretty/makefile b/hg/pslPretty/makefile
new file mode 100644
index 0000000..5fd0dcd
--- /dev/null
+++ b/hg/pslPretty/makefile
@@ -0,0 +1,28 @@
+include ../../inc/common.mk
+
+
+L += -lm
+MYLIBDIR = ../../lib/$(MACHTYPE)
+MYLIBS =  $(MYLIBDIR)/jkweb.a
+
+O = pslPretty.o
+
+pslPretty: $O $(MYLIBS)
+	${CC} ${COPT} ${CFLAGS} -o ${DESTDIR}${BINDIR}/pslPretty $O $(MYLIBS) $L
+
+test:: testRna testDnax
+
+testRna::
+	${MKDIR} test/output
+	pslPretty -long -axt test/input/rna.psl test/input/hCrea.geno test/input/hCrea.mrna test/output/rna.axt
+
+testDnax::
+	${MKDIR} test/output
+	pslPretty -long -axt test/input/dnax.psl test/input/mCrea.geno test/input/hCrea.geno test/output/dnax.axt
+
+testOld:: 
+	${MKDIR} output
+	pslPretty -long -axt input/test1.psl input/S1.lst input/S2.lst output/test1.axt
+
+clean::
+	rm -f ${O}
diff --git a/hg/pslPretty/pslPretty.c b/hg/pslPretty/pslPretty.c
new file mode 100644
index 0000000..994528e
--- /dev/null
+++ b/hg/pslPretty/pslPretty.c
@@ -0,0 +1,746 @@
+/* pslPretty - Convert PSL to human readable output. */
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "options.h"
+#include "dystring.h"
+#include "dlist.h"
+#include "fa.h"
+#include "nib.h"
+#include "twoBit.h"
+#include "psl.h"
+#include "axt.h"
+
+
+void usage()
+/* Explain usage and exit. */
+{
+errAbort(
+  "pslPretty - Convert PSL to human readable output\n"
+  "usage:\n"
+  "   pslPretty in.psl target.lst query.lst pretty.out\n"
+  "options:\n"
+  "   -axt - save in something like Scott Schwartz's axt format\n"
+  "          Note gaps in both sequences are still allowed in the\n"
+  "          output which not all axt readers will expect\n"
+  "   -dot=N Put out a dot every N records\n"
+  "   -long - Don't abbreviate long inserts\n"
+  "   -check=fileName - Output alignment checks to filename\n" 
+  "It's a really good idea if the psl file is sorted by target\n"
+  "if it contains multiple targets.  Otherwise this will be\n"
+  "very very slow.   The target and query lists can either be\n"
+  "fasta, 2bit or nib files, or a list of fasta, 2bit and/or nib files\n"
+  "one per line\n");
+}
+
+int dot = 0;
+boolean doShort = FALSE;
+struct axtScoreScheme *ss = NULL;
+
+struct seqFilePos
+/* Where a sequence is in a file. */
+    {
+    struct filePos *next;	/* Next in list. */
+    char *name;	/* Sequence name. Allocated in hash. */
+    char *file;	/* Sequence file name, allocated in hash. */
+    long pos; /* Position in fa file/size of nib. */
+    bool isNib;	/* True if a nib file. */
+    bool isTwoBit;  /* True if a two bit file. */
+    struct twoBitFile *tbf;	/* Open two bit file. */
+    };
+
+boolean isFa(char *file)
+/* Return TRUE if looks like a .fa file. */
+{
+FILE *f = mustOpen(file, "r");
+int c = fgetc(f);
+fclose(f);
+return c == '>';
+}
+
+void addNib(char *file, struct hash *fileHash, struct hash *seqHash)
+/* Add a nib file to hashes. */
+{
+struct seqFilePos *sfp;
+char root[128];
+int size;
+FILE *f = NULL;
+splitPath(file, NULL, root, NULL);
+AllocVar(sfp);
+hashAddSaveName(seqHash, root, sfp, &sfp->name);
+sfp->file = hashStoreName(fileHash, file);
+sfp->isNib = TRUE;
+nibOpenVerify(file, &f, &size);
+sfp->pos = size;
+}
+
+void addTwoBit(char *file, struct hash *fileHash, struct hash *seqHash)
+/* Add a nib file to hashes. */
+{
+struct seqFilePos *sfp;
+struct twoBitFile *tbf = twoBitOpen(file);
+struct twoBitIndex *index;
+for (index = tbf->indexList; index != NULL; index = index->next)
+    {
+    AllocVar(sfp);
+    hashAddSaveName(seqHash, index->name, sfp, &sfp->name);
+    sfp->file = hashStoreName(fileHash, file);
+    sfp->isTwoBit = TRUE;
+    sfp->tbf = tbf;
+    }
+}
+
+
+void addFa(char *file, struct hash *fileHash, struct hash *seqHash)
+/* Add a fa file to hashes. */
+{
+struct lineFile *lf = lineFileOpen(file, TRUE);
+char *line, *name;
+char *rFile = hashStoreName(fileHash, file);
+
+while (lineFileNext(lf, &line, NULL))
+    {
+    if (line[0] == '>')
+        {
+	struct seqFilePos *sfp;
+	line += 1;
+	name = nextWord(&line);
+	if (name == NULL)
+	   errAbort("bad line %d of %s", lf->lineIx, lf->fileName);
+	AllocVar(sfp);
+	hashAddSaveName(seqHash, name, sfp, &sfp->name);
+	sfp->file = rFile;
+	sfp->pos = lineFileTell(lf);
+	}
+    }
+lineFileClose(&lf);
+}
+
+
+void hashFileList(char *fileList, struct hash *fileHash, struct hash *seqHash)
+/* Read file list into hash */
+{
+if (twoBitIsFile(fileList))
+    addTwoBit(fileList, fileHash, seqHash);
+else if (endsWith(fileList, ".nib"))
+    addNib(fileList, fileHash, seqHash);
+else if (isFa(fileList))
+    addFa(fileList, fileHash, seqHash);
+else
+    {
+    struct lineFile *lf = lineFileOpen(fileList, TRUE);
+    char *row[1];
+    while (lineFileRow(lf, row))
+        {
+	char *file = row[0];
+	if (twoBitIsFile(file))
+	    addTwoBit(file, fileHash, seqHash);
+	else if (endsWith(file, ".nib"))
+	    addNib(file, fileHash, seqHash);
+	else
+	    addFa(file, fileHash, seqHash);
+	}
+    lineFileClose(&lf);
+    }
+}
+
+struct cachedFile
+/* File in cache. */
+    {
+    struct cachedFile *next;	/* next in list. */
+    char *name;		/* File name (allocated here) */
+    FILE *f;		/* Open file. */
+    };
+
+FILE *openFromCache(struct dlList *cache, char *fileName)
+/* Return open file handle via cache.  The simple logic here
+ * depends on not more than N files being returned at once. */
+{
+static int maxCacheSize=32;
+int cacheSize = 0;
+struct dlNode *node;
+struct cachedFile *cf;
+
+/* First loop through trying to find it in cache, counting
+ * cache size as we go. */
+for (node = cache->head; !dlEnd(node); node = node->next)
+    {
+    ++cacheSize;
+    cf = node->val;
+    if (sameString(fileName, cf->name))
+        {
+	dlRemove(node);
+	dlAddHead(cache, node);
+	return cf->f;
+	}
+    }
+
+/* If cache has reached max size free least recently used. */
+if (cacheSize >= maxCacheSize)
+    {
+    node = dlPopTail(cache);
+    cf = node->val;
+    carefulClose(&cf->f);
+    freeMem(cf->name);
+    freeMem(cf);
+    freeMem(node);
+    }
+
+/* Cache new file. */
+AllocVar(cf);
+cf->name = cloneString(fileName);
+cf->f = mustOpen(fileName, "rb");
+dlAddValHead(cache, cf);
+return cf->f;
+}
+
+struct dnaSeq *readSeqFromFaPos(struct seqFilePos *sfp,  FILE *f)
+/* Read part of FA file. */
+{
+struct dnaSeq *seq;
+fseek(f, sfp->pos, SEEK_SET);
+if (!faReadMixedNext(f, TRUE, "", TRUE, NULL, &seq))
+    errAbort("Couldn't faReadNext on %s in %s\n", sfp->name, sfp->file);
+return seq;
+}
+
+
+void readCachedSeqPart(char *seqName, int start, int size, 
+     struct hash *hash, struct dlList *fileCache, 
+     struct dnaSeq **retSeq, int *retOffset, boolean *retIsPartial)
+/* Read sequence hopefully using file cashe. If sequence is in a nib
+ * file just read part of it. */
+{
+struct seqFilePos *sfp = hashMustFindVal(hash, seqName);
+FILE *f = openFromCache(fileCache, sfp->file);
+if (sfp->isNib)
+    {
+    *retSeq = nibLdPartMasked(NIB_MASK_MIXED, sfp->file, f, sfp->pos, start, size);
+    *retOffset = start;
+    *retIsPartial = TRUE;
+    }
+else if (sfp->isTwoBit)
+    {
+    *retSeq = twoBitReadSeqFrag(sfp->tbf, seqName, start, start+size);
+    *retOffset = start;
+    *retIsPartial = TRUE;
+    }
+else
+    {
+    *retSeq = readSeqFromFaPos(sfp, f);
+    *retOffset = 0;
+    *retIsPartial = FALSE;
+    }
+}
+
+void axtOutString(char *q, char *t, int size, int lineSize, 
+	struct psl *psl, FILE *f)
+/* Output string side-by-side in Scott's axt format. */
+{
+int i;
+static int ix = 0;
+int qs = psl->qStart, qe = psl->qEnd;
+int ts = psl->tStart, te = psl->tEnd;
+int score = axtScoreSym(ss, size, q, t);
+
+if (psl->strand[0] == '-')
+    reverseIntRange(&qs, &qe, psl->qSize);
+
+if (psl->strand[1] == '-')
+    reverseIntRange(&ts, &te, psl->tSize);
+
+if (psl->strand[1] != 0)
+    fprintf(f, "%d %s %d %d %s %d %d %c%c %d\n", ++ix, psl->tName, ts+1, 
+            te, psl->qName, qs+1, qe, psl->strand[1], psl->strand[0], score);
+else
+    fprintf(f, "%d %s %d %d %s %d %d %c %d\n", ++ix, psl->tName, psl->tStart+1, 
+            psl->tEnd, psl->qName, qs+1, qe, psl->strand[0], score);
+if (strlen(t) != size)
+    warn("size of T %ld and Q %d differ on line %d\n",(long)strlen(t), size, ix);
+for (i=0; i<size ; i++) 
+    fputc(t[i],f);
+fputc('\n',f);
+if (strlen(q) != size)
+    warn("size of T %ld and Q %d differ on line %d\n",(long)strlen(q), size, ix);
+for (i=0; i<size ; i++) 
+    fputc(q[i],f);
+fputc('\n',f);
+fputc('\n',f);
+}
+
+void prettyOutString(char *q, char *t, int size, int lineSize, 
+	struct psl *psl, FILE *f)
+/* Output string side-by-side. */
+{
+int oneSize, sizeLeft = size;
+int i;
+char tStrand = (psl->strand[1] == '-' ? '-' : '+');
+
+fprintf(f, ">%s:%d%c%d of %d %s:%d%c%d of %d\n", 
+	psl->qName, psl->qStart, psl->strand[0], psl->qEnd, psl->qSize,
+	psl->tName, psl->tStart, tStrand, psl->tEnd, psl->tSize);
+while (sizeLeft > 0)
+    {
+    oneSize = sizeLeft;
+    if (oneSize > lineSize)
+        oneSize = lineSize;
+    mustWrite(f, q, oneSize);
+    fputc('\n', f);
+
+    for (i=0; i<oneSize; ++i)
+        {
+	if (toupper(q[i]) == toupper(t[i]) && isalpha(q[i]))
+	    fputc('|', f);
+	else
+	    fputc(' ', f);
+	}
+    fputc('\n', f);
+
+    if (oneSize > lineSize)
+        oneSize = lineSize;
+    mustWrite(f, t, oneSize);
+    fputc('\n', f);
+    fputc('\n', f);
+    sizeLeft -= oneSize;
+    q += oneSize;
+    t += oneSize;
+    }
+}
+
+void fillShortGapString(char *buf, int gapSize, char gapChar, int shortSize)
+/* Fill in buf with something like  ---100--- (for gapSize 100
+ * and shortSize 9 */
+{
+char gapAsNum[16];
+int gapNumLen;
+int dashCount, dashBefore, dashAfter;
+sprintf(gapAsNum, "%d", gapSize);
+gapNumLen = strlen(gapAsNum);
+dashCount = shortSize - gapNumLen;
+dashBefore = dashCount/2;
+dashAfter = dashCount - dashBefore;
+memset(buf, gapChar, dashBefore);
+memcpy(buf+dashBefore, gapAsNum, gapNumLen);
+memset(buf+dashBefore+gapNumLen, gapChar, dashAfter);
+buf[shortSize] = 0;
+}
+
+void fillSpliceSites(char *buf, int gapSize, char *gapSeq, int shortSize)
+/* Fill in buf with something like  gtcag...cctag */
+{
+int minDotSize = 3;	  /* Minimum number of dots. */
+int dotSize = minDotSize; /* Actual number of dots. */
+int seqBefore, seqAfter, seqTotal;
+
+if (shortSize - dotSize > gapSize)
+    dotSize =  shortSize - gapSize;
+seqTotal = shortSize - dotSize;
+seqBefore = seqTotal/2;
+seqAfter = seqTotal - seqBefore;
+memcpy(buf, gapSeq, seqBefore);
+memset(buf+seqBefore, '.', dotSize);
+memcpy(buf+seqBefore+dotSize, gapSeq + gapSize - seqAfter, seqAfter);
+buf[shortSize] = 0;
+}
+
+
+void writeInsert(struct dyString *aRes, struct dyString *bRes, char *aSeq, int gapSize)
+/* Write out gap, possibly shortened, to aRes, bRes. */
+{
+int minToAbbreviate = 16;
+if (doShort && gapSize >= minToAbbreviate)
+    {
+    char abbrevGap[16];
+    char abbrevSeq[16];
+    fillSpliceSites(abbrevSeq, gapSize, aSeq, 15);
+    dyStringAppend(aRes, abbrevSeq);
+    fillShortGapString(abbrevGap, gapSize, '-', 15);
+    dyStringAppend(bRes, abbrevGap);
+    }
+else
+    {
+    dyStringAppendN(aRes, aSeq, gapSize);
+    dyStringAppendMultiC(bRes, '-', gapSize);
+    }
+}
+
+
+void writeGap(struct dyString *aRes, int aGap, char *aSeq, struct dyString *bRes, int bGap, char *bSeq)
+/* Write double - gap.  Something like:
+ *     ....123.... or --c
+ *     ...4123....    ag-  */
+
+{
+char abbrev[16];
+int minToAbbreviate = 16;
+if (doShort && (aGap >= minToAbbreviate || bGap >= minToAbbreviate))
+    {
+    fillShortGapString(abbrev, aGap, '.', 13);
+    dyStringAppend(aRes, abbrev);
+    fillShortGapString(abbrev, bGap, '.', 13);
+    dyStringAppend(bRes, abbrev);
+    }
+else
+    {
+#ifdef OLD
+    dyStringAppendMultiC(aRes, '-', aGap);
+    dyStringAppendN(bRes, bSeq, aGap);
+    dyStringAppendN(aRes, aSeq, bGap);
+    dyStringAppendMultiC(bRes, '-', bGap);
+#endif /* OLD */
+    dyStringAppendMultiC(aRes, '-', bGap);
+    dyStringAppendN(bRes, bSeq, bGap);
+    dyStringAppendN(aRes, aSeq, aGap);
+    dyStringAppendMultiC(bRes, '-', aGap);
+    }
+}
+
+int smallSize = 8;	/* What our definition of 'small' is */
+int tinySize = 3;
+
+int boolify(int i)
+/* Convert 0 to 0 and nonzero to 1 */
+{
+return (i != 0 ? 1 : 0);
+}
+
+int total_rnaCount;
+int total_rnaPerfect;
+int total_missSmallStart = 0;
+int total_missLargeStart = 0;
+int total_missSmallEnd = 0;
+int total_missLargeEnd = 0;
+int total_missSmallMiddle = 0;
+int total_missLargeMiddle = 0;
+int total_weirdSplice = 0;
+int total_doubleGap = 0;
+int total_jumpBack = 0;
+
+boolean isIntron(char strand, char *start, char *end)
+/* See if it look like an intron. */
+{
+if (strand == '+')
+    {
+    if (start[0] != 'g' || end[-2] != 'a' || end[-1] != 'g')
+	return FALSE;
+    return (start[1] == 't' || start[1] == 'c');
+    }
+else
+    {
+    if (start[0] != 'c' || start[1] != 't' || end[-1] != 'c')
+	return FALSE;
+    return (end[-2] == 'a' || end[-2] == 'g');
+    }
+}
+
+void outputCheck(struct psl *psl, struct dnaSeq *qSeq, int qOffset,
+	struct dnaSeq *tSeq, int tOffset, FILE *f)
+/* Output quality check info to file */
+{
+int sizePolyA = 0;
+int qSize = psl->qSize;
+int i;
+int missSmallStart = 0;
+int missLargeStart = 0;
+int missSmallEnd = 0;
+int missLargeEnd = 0;
+int missSmallMiddle = 0;
+int missLargeMiddle = 0;
+int weirdSplice = 0;
+int doubleGap = 0;
+int jumpBack = 0;
+int diff;
+int totalProblems = 0;
+char strand = psl->strand[0];
+
+if (strand == '+')
+    {
+    for (i=1; i<=qSize; ++i)
+	{
+	if (qSeq->dna[qSize - i - qOffset] == 'a')
+	    ++sizePolyA;
+	else
+	    break;
+	}
+    }
+else
+    {
+    for (i=0; i<qSize; ++i)
+	{
+	if (qSeq->dna[i - qOffset] == 't')
+	    ++sizePolyA;
+	else
+	    break;
+	}
+    }
+if (psl->qStart > tinySize)
+    {
+    if (psl->qStart <= smallSize)
+	{
+	missSmallStart = psl->qStart;
+	++totalProblems;
+	}
+    else
+	{
+	missLargeStart = psl->qStart;
+	++totalProblems;
+	}
+    }
+diff = psl->qSize - psl->qEnd - sizePolyA;
+if (diff > tinySize)
+    {
+    if (diff <= smallSize)
+	{
+	missSmallEnd = diff;
+	++totalProblems;
+	}
+    else
+	{
+	missLargeEnd = diff;
+	++totalProblems;
+	}
+    }
+for (i=0; i<psl->blockCount-1; ++i)
+    {
+    int nextT = psl->tStarts[i+1];
+    int nextQ = psl->qStarts[i+1];
+    int sz = psl->blockSizes[i];
+    int t = psl->tStarts[i] + sz;
+    int q = psl->qStarts[i] + sz;
+    int dq = nextQ - q;
+    int dt = nextT - t;
+    if (dq < 0 || dt < 0)
+	{
+	++jumpBack;
+	++totalProblems;
+	}
+    else 
+	{
+	if (dq > 0 && dt > 0)
+	    {
+	    ++doubleGap;
+	    ++totalProblems;
+	    }
+	if (dq > tinySize)
+	    {
+	    if (dq > smallSize)
+		{
+		++missLargeMiddle;
+		++totalProblems;
+		}
+	    else
+		{
+		++missSmallMiddle;
+		++totalProblems;
+		}
+	    }
+	if (dq == 0 && dt >=30)
+	    {
+	    char *dna = tSeq->dna - tOffset;
+	    if (!isIntron(strand, dna + t, dna + nextT))
+		{
+		++weirdSplice;
+		++totalProblems;
+		}
+	    }
+	}
+    }
+fprintf(f, "%2d %9s %s ", totalProblems, psl->qName, psl->strand);
+fprintf(f, "%4dS ", missLargeStart);
+fprintf(f, "%2ds ", missSmallStart);
+fprintf(f, "%4dE ", missLargeEnd);
+fprintf(f, "%2de ", missSmallEnd);
+fprintf(f, "%2dM ", missLargeMiddle);
+fprintf(f, "%2dm ", missSmallMiddle);
+fprintf(f, "%2dW ", weirdSplice);
+fprintf(f, "%2dG ", doubleGap);
+fprintf(f, "%2dJ ", jumpBack);
+fprintf(f, "\n");
+
+total_missSmallStart += boolify(missSmallStart);
+total_missLargeStart += boolify(missLargeStart);
+total_missSmallEnd += boolify(missSmallEnd);
+total_missLargeEnd += boolify(missLargeEnd);
+total_missSmallMiddle += boolify(missSmallMiddle);
+total_missLargeMiddle += boolify(missLargeMiddle);
+total_weirdSplice += boolify(weirdSplice);
+total_doubleGap += boolify(doubleGap);
+total_jumpBack += boolify(jumpBack);
+++total_rnaCount;
+if (totalProblems == 0)
+    ++total_rnaPerfect;
+}
+
+void prettyOne(struct psl *psl, struct hash *qHash, struct hash *tHash,
+	struct dlList *fileCache, FILE *f, boolean axt, FILE *checkFile)
+/* Make pretty output for one psl.  Find target and query
+ * sequence in hash.  Load them.  Output bases. */
+{
+static char *tName = NULL, *qName = NULL;
+static struct dnaSeq *tSeq = NULL, *qSeq = NULL;
+struct dyString *q = newDyString(16*1024);
+struct dyString *t = newDyString(16*1024);
+int blockIx;
+int qs, ts;
+int lastQ = 0, lastT = 0, size;
+int qOffset = 0;
+int tOffset = 0;
+boolean qIsPartial = FALSE;
+boolean tIsPartial = FALSE;
+
+if (qName == NULL || !sameString(qName, psl->qName))
+    {
+    freeDnaSeq(&qSeq);
+    freez(&qName);
+    qName = cloneString(psl->qName);
+    readCachedSeqPart(qName, psl->qStart, psl->qEnd-psl->qStart, 
+    	qHash, fileCache, &qSeq, &qOffset, &qIsPartial);
+    if (qIsPartial && psl->strand[0] == '-')
+	    qOffset = psl->qSize - psl->qEnd;
+    }
+if (tName == NULL || !sameString(tName, psl->tName) || tIsPartial)
+    {
+    freeDnaSeq(&tSeq);
+    freez(&tName);
+    tName = cloneString(psl->tName);
+    readCachedSeqPart(tName, psl->tStart, psl->tEnd-psl->tStart, 
+	tHash, fileCache, &tSeq, &tOffset, &tIsPartial);
+    }
+if (tIsPartial && psl->strand[1] == '-')
+    tOffset = psl->tSize - psl->tEnd;
+if (psl->strand[0] == '-')
+    reverseComplement(qSeq->dna, qSeq->size);
+if (psl->strand[1] == '-')
+    reverseComplement(tSeq->dna, tSeq->size);
+for (blockIx=0; blockIx < psl->blockCount; ++blockIx)
+    {
+    qs = psl->qStarts[blockIx] - qOffset;
+    ts = psl->tStarts[blockIx] - tOffset;
+
+    /* Output gaps except in first case. */
+    if (blockIx != 0)
+        {
+	int qGap, tGap, minGap;
+	qGap = qs - lastQ;
+	tGap = ts - lastT;
+	minGap = min(qGap, tGap);
+	if (minGap > 0)
+	    {
+	    writeGap(q, qGap, qSeq->dna + lastQ, t, tGap, tSeq->dna + lastT);
+	    }
+	else if (qGap > 0)
+	    {
+	    writeInsert(q, t, qSeq->dna + lastQ, qGap);
+	    }
+	else if (tGap > 0)
+	    {
+	    writeInsert(t, q, tSeq->dna + lastT, tGap);
+	    }
+	}
+    /* Output sequence. */
+    size = psl->blockSizes[blockIx];
+    dyStringAppendN(q, qSeq->dna + qs, size);
+    lastQ = qs + size;
+    dyStringAppendN(t, tSeq->dna + ts, size);
+    lastT = ts + size;
+    if(q->stringSize != t->stringSize)
+        {
+//        printf("%d BLK %s q size %d t size %d diff %d qs size %d ts size %d\n",blockIx, psl->qName, q->stringSize, t->stringSize, q->stringSize - t->stringSize, qSeq->size, tSeq->size );
+        }
+    }
+
+if (checkFile != NULL)
+    {
+    outputCheck(psl, qSeq, qOffset, tSeq, tOffset, checkFile);
+    }
+if (psl->strand[0] == '-' && !qIsPartial)
+    reverseComplement(qSeq->dna, qSeq->size);
+if (psl->strand[1] == '-' && !tIsPartial)
+    reverseComplement(tSeq->dna, tSeq->size);
+
+if(q->stringSize != t->stringSize)
+    {
+ //   printf("AF %s q size %d t size %d qs size %d ts size %d\n",psl->qName, q->stringSize, t->stringSize, qSeq->size, tSeq->size );
+    }
+//assert(q->stringSize == t->stringSize);
+if (axt)
+    axtOutString(q->string, t->string, min(q->stringSize,t->stringSize), 60, psl, f);
+else
+    prettyOutString(q->string, t->string, min(q->stringSize,t->stringSize), 60, psl, f);
+dyStringFree(&q);
+dyStringFree(&t);
+if (qIsPartial)
+    freez(&qName);
+if (tIsPartial)
+    freez(&tName);
+}
+
+void pslPretty(char *pslName, char *targetList, char *queryList, 
+	char *prettyName, boolean axt, char *checkFileName)
+/* pslPretty - Convert PSL to human readable output. */
+{
+struct hash *fileHash = newHash(0);  /* No value. */
+struct hash *tHash = newHash(20);  /* seqFilePos value. */
+struct hash *qHash = newHash(20);  /* seqFilePos value. */
+struct dlList *fileCache = newDlList();
+struct lineFile *lf = pslFileOpen(pslName);
+FILE *f = mustOpen(prettyName, "w");
+FILE *checkFile = NULL;
+struct psl *psl;
+int dotMod = dot;
+
+if (checkFileName != NULL)
+    checkFile = mustOpen(checkFileName, "w");
+/* fprintf(stderr,"Scanning %s\n", targetList); */
+hashFileList(targetList, fileHash, tHash);
+/* fprintf(stderr,"Scanning %s\n", queryList); */
+hashFileList(queryList, fileHash, qHash);
+/* fprintf(stderr,"Converting %s\n", pslName); */
+while ((psl = pslNext(lf)) != NULL)
+    {
+    if (dot > 0)
+        {
+	if (--dotMod <= 0)
+	   {
+	   fprintf(stderr,"."); /* stderr flushes itself */
+	   dotMod = dot;
+	   }
+	}
+    prettyOne(psl, qHash, tHash, fileCache, f, axt, checkFile);
+    pslFree(&psl);
+    }
+if (dot > 0)
+    fprintf(stderr,"\n");
+if (checkFile != NULL)
+    {
+    fprintf(checkFile,"missLargeStart: %d\n", total_missLargeStart);
+    fprintf(checkFile,"missSmallStart: %d\n", total_missSmallStart);
+    fprintf(checkFile,"missLargeEnd: %d\n", total_missLargeEnd);
+    fprintf(checkFile,"missSmallEnd: %d\n", total_missSmallEnd);
+    fprintf(checkFile,"missLargeMiddle: %d\n", total_missLargeMiddle);
+    fprintf(checkFile,"missSmallMiddle: %d\n", total_missSmallMiddle);
+    fprintf(checkFile,"weirdSplice: %d\n", total_weirdSplice);
+    fprintf(checkFile,"doubleGap: %d\n", total_doubleGap);
+    fprintf(checkFile,"jumpBack: %d\n", total_jumpBack);
+    fprintf(checkFile,"perfect: %d\n", total_rnaPerfect);
+    fprintf(checkFile,"total: %d\n", total_rnaCount);
+    }
+lineFileClose(&lf);
+carefulClose(&f);
+carefulClose(&checkFile);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+static boolean axt;
+optionHash(&argc, argv);
+axt = optionExists("axt");
+dot = optionInt("dot", dot);
+doShort = !optionExists("long");
+if (argc != 5)
+    usage();
+ss = axtScoreSchemeDefault();
+pslPretty(argv[1], argv[2], argv[3], argv[4], axt, optionVal("check", NULL));
+return 0;
+}
diff --git a/hg/pslPretty/test/input/dnax.psl b/hg/pslPretty/test/input/dnax.psl
new file mode 100644
index 0000000..d17bb89
--- /dev/null
+++ b/hg/pslPretty/test/input/dnax.psl
@@ -0,0 +1,7 @@
+psLayout version 3
+
+match	mis- 	rep. 	N's	Q gap	Q gap	T gap	T gap	strand	Q        	Q   	Q    	Q  	T        	T   	T    	T  	block	blockSizes 	qStarts	 tStarts
+     	match	match	   	count	bases	count	bases	      	name     	size	start	end	name     	size	start	end	count
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+2260	349	0	0	33	3519	35	3010	++	hCreaGeno	6896	55	6183	mCreatGeno	7854	2234	7853	38	63,4,65,15,10,42,129,45,72,79,248,103,51,13,298,133,257,8,8,14,10,6,9,13,5,7,14,11,13,198,163,184,81,14,52,10,75,87,	55,118,122,212,236,313,394,523,968,1040,1120,1557,1689,1750,1995,2354,2528,2802,2889,2924,2977,3008,3095,3116,3131,3255,3412,3628,3749,4341,4987,5325,5551,5639,5712,5864,6017,6096,	2234,2298,2303,2387,2410,2486,2562,2694,3119,3192,3271,3672,3804,3862,4219,4573,4750,5028,5086,5135,5193,5273, [...]
+2137	321	0	0	24	3603	25	3092	--	hCreaGeno	6896	121	6182	mCreatGeno	7854	2302	7852	27	87,20,48,63,35,184,63,164,190,18,24,13,14,14,258,132,317,105,248,72,71,12,12,56,134,39,65,	714,805,1137,1270,1352,1388,1641,1746,2358,3013,3088,3134,3470,3958,4110,4410,4585,5237,5529,5784,5856,6093,6293,6313,6369,6545,6710,	2,97,426,543,616,651,1115,1200,1476,2056,2133,2178,2416,2705,2846,3149,3319,4080,4336,4590,4663,4893,5071,5100,5159,5330,5487,
diff --git a/hg/pslPretty/test/input/hCrea.geno b/hg/pslPretty/test/input/hCrea.geno
new file mode 100644
index 0000000..edc0255
--- /dev/null
+++ b/hg/pslPretty/test/input/hCrea.geno
@@ -0,0 +1,100 @@
+>hCreaGeno
+CATGCCACATCCCCGGGGCGGGAGGGGGCTACATCCCCGGCTTTAGACGCGCGAGTCTCAGGTCCCGCTA
+ATTACCTGGCGGGTGCTGCCCACCCCTGCCCTCGCGCACCTAGCGCGTGGCAGCGGGAAGGCGGGGCCTG
+GGGGAGCCCCACCCCTGGAGACTGCGGCTGGGGCCTCCCTCTCCTCCGCCCGCCCGCCTGCCACTAGCTC
+ATTGCGCCTCTCCTGCAGTCTGATTGGGCACCGGCTCCCATTCCGGCTCCAGCCTCCAATCCGACCCCCA
+TTTCGGCTGCAGCCTCGGACCTAGCTCCGGCCCTCGGTCTATCCGGTTGCATCCTCCCTCCCTGTTCCGG
+ATCTTATCTTGCGCCAGCGCCTACTCCAGGATCCCGTAGCCAGACCTCAAGCCATGGCTGGTCCCTTCTC
+CCGTCTGCTGTCCGCCCGCCCGGGACTCAGGCTCCTGGCTTTGGCCGGAGCGGGGTCTCTAGCCGCTGGG
+TTTCTGCTCCGACCGGAACCTGTACGAGCTGCCAGTGAACGACGGAGGCTGTATCCCCCGAGGTAACAGT
+GCCTGAGGCGCGGGAGGAGGCGGGGGCAGGAGGTGATGGGAACGAAGGTGCGGGTAGAAGTGAGAATCCG
+GGCAACAGAGAAGGGCTATAATCACGAAGGCCCTGGAGCTGGAGGGCTGTGCAGTCTGCAGACCTCAGTG
+GGGTGGGGGTGGGGGCCAAAACCATAAAGCAAGAACATTCCTGGGGACCTGCCAAGACCAGCTCTGGCCC
+TACGAGTTCTAGCTGCACTGGCTGCCCAAATCCCTAATTGTAAAGCCAGGAACTATCCTTTTCGCTCCCC
+TCCATCTCCTTCCCTCATTTCCTCAATTCCTCTCCTTAGGCTTTTCCCCTCCTCCATCCGTAGTGTTGTG
+TCATGGGAGGAAAGAACTGAGCAGATCTGAAGAAACTGAGCTGGCCAGCCAGAGGCAACTAGAACTATTA
+GGAAAGCATAGACTCTGAAAGTCCCTAAAGAGATTACCAAGGTTTACCCTCTTTCTAATTCCCCTCCTCC
+CGCGGAGCAAAGCCAGACATGGCCAACTGGACAGCTCCCAGGTAACTGCACTAGGTCTAGGCGTCTGTGA
+CCCTCCCTCCATGGTTACTGGGTACCCCCTCCCCAGCGCTGAGTACCCAGACCTCCGAAAGCACAACAAC
+TGCATGGCCAGTCACCTGACCCCAGCAGTCTATGCACGGCTCTGCGACAAGACCACACCCACTGGTTGGA
+CGCTAGATCAGTGTATCCAGACTGGCGTGGACAACCCTGGCCACCCCTTCATCAAGACTGTGGGCATGGT
+GGCTGGAGATGAGGAGACCTATGAGGTAGGGGGTCCCCAGAGTCTCCCTGATGATCCAATTCATCTTCCC
+AGTAATCCCAGCTCCTTTCCCTTAAAGACCTCTCACTTTCCCCCAAGACTCTGAGCCCCCCATACTTAAG
+TTTTCTGAACCAGTGAAATCAATGCACAATTGAAGTCTGGGGAGGGATTCCCTCTCCTTAACCATCTCTC
+CCTCTTAACTCCCCTTAGGTATTTGCTGACCTGTTTGACCCTGTGATCCAAGAGCGACACAATGGATATG
+ACCCCCGGACAATGAAGCACACCACGGATCTAGATGCCAGTAAAGTGAGTTCAAATATCCCACTTCTGAT
+TTGCATTGCCTGTGTACAACACTCTGTATCTCCAACCCCTTCACCTTATTTCCTGACTCATGGTCATTAT
+ACTGCTGAGCTTTTAATCTTAATGTAAGGAAAGAATCATATCTTAAGGGGCAGCATATATGGAGATGGAA
+GGATAGATAAGAATGACCATGACCCAAGGTGGGTGGTTTGGGGACGGGTCTGCAATGCCCCCTTCAATTC
+CAGTGCTTTCCCAAAGGGCCTCTTCTTCCAATGCATGCAGGAAGAATGCACACAGAGTCCTCTAATGCCT
+AAGGAAGGTCTCTCCTTTCCCAGGGGCCCTCAGTTCCCACCGTGTTTCTGTGACTTACATTCATTTCCCT
+TATCTCCCAGATCCGTTCTGGCTACTTTGATGAGAGGTATGTATTGTCCTCTAGAGTCAGAACTGGCCGA
+AGCATCCGAGGACTCAGTCTGCCTCCAGCTTGCACTCGAGCAGAGCGACGAGAGGTGGAACGTGTTGTGG
+TGGATGCACTGAGTGGCCTGAAGGGTGACCTGGCTGGACGTTACTATAGGCTCAGTGAGATGACAGAGGC
+TGAACAGCAGCAGCTTATTGATGTGAGGGCCTTAAGAGGGTGCTGGTTGGTGGGAGCAGATGGGGAAGGC
+TGGGCCAGATGAGACATGGGCTCTGAAAGGCCCAGGGGCCACCATGAAGATTCTTAACCCAAGTCCCGTT
+ACTCTTCCCAGGACCACTTTCTGTTTGATAAGCCTGTGTCCCCGTTGCTGACTGCAGCAGGAATGGCTCG
+AGACTGGCCAGATGCTCGTGGAATTTGGTATGAAGCTGCTCATTACCTCTTTTGTCTTCATGCCCTCATA
+AATGCTTTTTTTCCCTCTATCTCTCCCAATTCTTGCCTTGCCTCTTGATCACTGTCCCTCTCCGGCCCTC
+AGGCACAACAATGAGAAGAGCTTCCTGATCTGGGTGAATGAGGAGGATCATACACGGGTGATCTCCATGG
+AGAAGGGTGGTAACATGAAGAGAGTGTTTGAAAGATTCTGCCGAGGCCTCAAAGAGGTTAGAGAAGACTA
+TGTAGGGGAGCTAGGTGGGAGGACATAAGGAAAACCAAAGAGTAGCATAAATAGATTATGTAATTTACCA
+ACCAACCCAGGACATGTCTTATAGTAAAAAGGACTATCTAGGACTCACTCCAGGACTAAAGGTGTAAACC
+AGCTGGGACCATACTGGGAAAACCAGGACATGTGGTCACACTAAGATTAGGAAAAGAAAGAGTGTCAGGA
+ATCTTAGGAAGTGAACAAGGCTTTTGACAGAGAGTGCAAAGAAGGAATAAATGAGATGGCACGTCAGTGC
+CTGGGATGTGTGCAGTGGGATGGTGAGGTGTGCAGATAAGGAAAACATTCGAGCTTAGATTGATGTTGGC
+GGGGAGAGGTTGCTGTGTTCATGACTCTAATATAACCACCCAGTTCTGAGACAAGGTAGGCCTTGACTCT
+GGATTCTATCATTCTTGTTAAAGTTTCGGGTCTAGGCTTTAAGTTGAGAGTTCGGAGAGAGACTGGGGAA
+GGTGGAGGATAGAATGGTTCGAGTTCTAGAATATGTGGCTCTAGATGAGAGGTTGAACTGAATCATCAAT
+CCTACATGGATTGGGTCTCCGTATTCAAGTCTACATTAGAAATCCCCATAAACTCAATTCAATTCTTACT
+GTATGTTCTCAAACATACAGTTCTATTTTAGGTTTGCAAAGAAAAAGAGCTCCTCTTTTAGATTCTGAGA
+AGTTTCTACTATTTTTGGCAAGTAATAGATAACATATTCTGACTATGAGTGGGtagggaagtacctttaa
+attatatgcctcagtttcctcatctgtaaaattgggataatgagattttctacattttaggttgttgtgg
+ggattaagtgaaatacaggtaaagtacttggtccacagtaagtgcttaataagtgttaaagtgttagctg
+caatattattCTGGATGGAAGAGTTTCCCCCCATGTTCAGCATGTAAGATATCCCCTATGGCATGGTTCC
+TTCTGAACTATAAAGAGGATCCCTTTACTCATGTTGGGTTGTGGTCTTTGTGACCATCATTCTGCTAGAT
+CCCTTGTCTCTTGAACTCTAATAGTCATCTTCATGACTACATGGTTAAGTGAAGCCAAACGCCTTCCCCC
+CGCCCCCTATTCCTATGAATCTGGCTTTTCTGCTCTGTTTTCATCTTTCTCTGCATTCACACAGGTGCTC
+CGTTCACAGCTAACAGAATGTTATCTTACCTCTTCCTGGCAAAGCTTACACCTTCATCTTCTGTCTGAAG
+GGACCCTTCTAAGCTCTAGGCTCATTAGCAAAGCAAAGATAATCGATGCATGCAGACCTCATTGAATAAT
+CAGTCATCTCTCAGTTCAGTTTACCACCTCTGTTCATTTCCCTAGATCATCCTTAATACACCACTCCTTC
+GAGTTTTCTTCTTCCACATAAGATATTTTTTCACAATCTCATTATTATGCACATCATAATTTTGCATCAT
+GCATGCATGAAAACAATAACAAACCTTTTTCATTTAAAAAAAGACCAATGTCATTCATTCACAGCCAAGT
+TTCTGTTCTAGACATATTTCTAGTGTTCTTGTGGGTCTAGCTAAGGGAGGGTCCAGGGTTAATGAAATAT
+CCCTGATTTTTCGTTAACAAAACCTTTGTGGACTCAGGTGGAGAGACTTATCCAAGAACGTGGCTGGGAG
+TTCATGTGGAATGAGCGTTTGGGATACATCTTGACCTGTCCATCTAACCTGGGCACTGGACTTCGGGCAG
+GAGTGCACATCAAACTGCCCCTGCTAAGCAAAGTAAAGGAGTTGTGGGGTTACAGAGGGGTGTGAGTAAG
+GAAGGGTGGGTTGTGGATGGGGAGGGAGTGGACCCTTTGGAAAGGAGCCAAACATGTTGTGGCTAAAGGG
+TCAGAGGACAggccaggcacagtggctcatgcctctaatcccaacacttgggaggccaaggcaggcagat
+tacttgagcccaggagttcaagaccagcctgggcaacctggtgaaaccccatctctacctacaaatacaa
+aagttagctgggtgtagtggaggctgaggtgagaggatcacttaagcctgggaagtcgaggcttcagtga
+gctgtgatcactccagcctgggtgacagagagagaccctgtctaaaaaaaattaaaaaagaaaaaagaaa
+aaaGGAAAAAAAAAGTTCAGGAGACAGAGCTCTGAGCAGGTTCAGGGCTCTTTCAGGTAGGACCTAGTCT
+CTGCCTCTATTGACCCTGCTCCCAATCCCTATCTCCTCTCTAGGATAGCCGCTTCCCAAAGATCCTGGAG
+AACCTAAGACTCCAAAAACGTGGTACTGGAGGAGTGGACACTGCTGCTACAGGCGGTGTCTTTGATATTT
+CTAATTTGGACCGACTAGGCAAATCAGAGGTGAGATCCTAAGGGATTAGGACAAGGAGAGGTATAGGTCT
+GCGAGGGCCGAAATATGGCAGTGAGTGAGCCTCCGGGATGTAACATAATCTGAAATGAAATTCAGGTTGA
+GTGGGAGGCAATTGGAAATGAGCAGGCAAGTCAGTCAGTGATAAAGAAAAACTCAGACTGTAGGAAGCAG
+ATCAAAGATTAGTGTCCCTTAGGTGGAGCTGGTGCAACTGGTCATCGATGGAGTAAACTATTTGATTGAT
+TGTGAACGGCGTCTGGAGAGAGGCCAGGATATCCGCATCCCCACACCTGTCATCCACACCAAGCATTAAC
+TCCCCATCGCCAGCTGATGACTCAAGATTCCCAGGAGTTTTGCTCATTCTAATGATGGCCCATTCTACTT
+GCTCTGGACCTGCCCCCGCATCCCCTGCCTCCATCCTAGTAAAGACTCCTTGCTATGCTGCAGCTGTCTG
+TGTTACTTCTAATGGTGGGGTGAGGAGGGAGCAGCCTTCAGGAAATGAAAAGAGGCAGTGGGATTATTTA
+TGATGGAAAGAGACTCCAGATATGGCAACCCAGGAACACTGATTCTCAGGTGGGTGGAAAGCATTAACAT
+TTTACCCATATTCCTCATCAGCTTCTGAAAATAATCAGGATGCACTTCTGTTTGCACTTTATTCATTATG
+ACTTAAGATTTCTCTCCCCACAATCTCCTTCTACTGTAGAGACAGGCTCATAGCAGGTGGCCAAGGAAGC
+TGATAGTCAATACCAGGGACCAGGAAGGTCGTGACCAGTCCTGGAGGCCCCAGGCTGTACTTCGACCTAT
+AATAGACAGGGAATGGGAGTAATATCACAACTCAGCTCTCCAGGAGCATTGATACTTGGAAATTAGCGCT
+CTGCCTGTAGACTCCTTCACTCCAGGGATCTCCCTGGGTGCACTCTAAGAGCCAGACAGCACCAAATTAG
+GGGTTTGATTCTGGGTCAGGAGATGGAGGATCAAGCTGTGCAGCTGGGAACTCACCTTGCTGTTCTGGGC
+TCTCCTTTCCCTCATGTTGGGCCCATGCAACTGCTCGTCGCTGCTCAGGACTCAGAAAGGCCATTTGCTC
+AGGAGTGACAGCCACAGCCTGAGCACTGGTGAGACTAGATAGTTGGATGGGACTAAACACCACCTGAGGG
+CAGGGGTAGGAATCAGTGCATGCATGTAGTCCCCATTGGGCCCTGGCTCTCCTGTGGTCACCCCAGTCCA
+TTAATACTTACAGCAAATTTAGGAGGAGGGATGACAGAAATGGCAAGAGGAGTAACGCCCTGGATCTGTC
+CCCGCAGCAGTGCTGAAAGAGCCAGGTCTGGGATCCCAGCTGTTGAAGCAAGTGGCATCCAAACATTGTC
+TTAGACTGACCTTCCCTCTCTTCAAACCTATAGACCTTCTCTAACTACTCCCAAAGTGCCCTATCATAGA
+CCTTCCCCAATATGTCTCTAGCCCCTTATTTAAACACCCTCAGGCCCCCACCTTAAGAATTGCAGGGCAG
+TCTTCCATCCAGTCCACCCATGGTATAGAAACCAAACCAACTTGCACCAGCAGTGGCCCAGCTCCCCACC
+TGCTATGGTGCCAATTTCAGTGAAGATCTCAGGCCCCCAGTTACTGATTGGGCCAAACCCACCAGGCAGT
+ACAAGTAGGTGGGCCAGAACCTCCAGTTGTTCCTCAGAGCACTGCAGATGCAGGGTGCCGAGGAAGAGAG
+CTGCTTGGCTGTAGAACAGTGGGAAGGAAGGAAGAA
diff --git a/hg/pslPretty/test/input/hCrea.mrna b/hg/pslPretty/test/input/hCrea.mrna
new file mode 100644
index 0000000..739a6b8
--- /dev/null
+++ b/hg/pslPretty/test/input/hCrea.mrna
@@ -0,0 +1,23 @@
+>hCreaMrna
+CCGGCTCCCATTCCGGCTCCAGCCTCCAATCCGACCCCCATTTCGGCTGCAGCCTCGGACCTAGCTCCGG
+CCCTCGGTCTATCCGGTTGCATCCTCCCTCCCTGTTCCGGATCTTATCTTGCGCCAGCGCCTACTCCAGG
+ATCCCGTAGCCAGACCTCAAGCCATGGCTGGTCCCTTCTCCCGTCTGCTGTCCGCCCGCCCGGGACTCAG
+GCTCCTGGCTTTGGCCGGAGCGGGGTCTCTAGCCGCTGGGTTTCTGCTCCGACCGGAACCTGTACGAGCT
+GCCAGTGAACGACGGAGGCTGTATCCCCCGAGCGCTGAGTACCCAGACCTCCGAAAGCACAACAACTGCA
+TGGCCAGTCACCTGACCCCAGCAGTCTATGCACGGCTCTGCGACAAGACCACACCCACTGGTTGGACGCT
+AGATCAGTGTATCCAGACTGGCGTGGACAACCCTGGCCACCCCTTCATCAAGACTGTGGGCATGGTGGCT
+GGAGATGAGGAGACCTATGAGGTATTTGCTGACCTGTTTGACCCTGTGATCCAAGAGCGACACAATGGAT
+ATGACCCCCGGACAATGAAGCACACCACGGATCTAGATGCCAGTAAAATCCGTTCTGGCTACTTTGATGA
+GAGGTATGTATTGTCCTCTAGAGTCAGAACTGGCCGAAGCATCCGAGGACTCAGTCTGCCTCCAGCTTGC
+ACTCGAGCAGAGCGACGAGAGGTGGAACGTGTTGTGGTGGATGCACTGAGTGGCCTGAAGGGTGACCTGG
+CTGGACGTTACTATAGGCTCAGTGAGATGACAGAGGCTGAACAGCAGCAGCTTATTGATGACCACTTTCT
+GTTTGATAAGCCTGTGTCCCCGTTGCTGACTGCAGCAGGAATGGCTCGAGACTGGCCAGATGCTCGTGGA
+ATTTGGCACAACAATGAGAAGAGCTTCCTGATCTGGGTGAATGAGGAGGATCATACACGGGTGATCTCCA
+TGGAGAAGGGTGGTAACATGAAGAGAGTGTTTGAAAGATTCTGCCGAGGCCTCAAAGAGGTGGAGAGACT
+TATCCAAGAACGTGGCTGGGAGTTCATGTGGAATGAGCGTTTGGGATACATCTTGACCTGTCCATCTAAC
+CTGGGCACTGGACTTCGGGCAGGAGTGCACATCAAACTGCCCCTGCTAAGCAAAGATAGCCGCTTCCCAA
+AGATCCTGGAGAACCTAAGACTCCAAAAACGTGGTACTGGAGGAGTGGACACTGCTGCTACAGGCGGTGT
+CTTTGATATTTCTAATTTGGACCGACTAGGCAAATCAGAGGTGGAGCTGGTGCAACTGGTCATCGATGGA
+GTAAACTATTTGATTGATTGTGAACGGCGTCTGGAGAGAGGCCAGGATATCCGCATCCCCACACCTGTCA
+TCCACACCAAGCATTAACTCCCCATCGCCAGCTGATGACTCAAGATTCCCAGGAGTTTTGCTCATTCTAA
+TGATGGCCCATTCTACTTGCTCTGGACCTGCCCCCGCATCCCCTGCCTCCATCCTAGTAAAAAAAAAAAA
diff --git a/hg/pslPretty/test/input/hCrea.pep b/hg/pslPretty/test/input/hCrea.pep
new file mode 100644
index 0000000..3cc44d1
--- /dev/null
+++ b/hg/pslPretty/test/input/hCrea.pep
@@ -0,0 +1,7 @@
+>hCreaPep
+MAGPFSRLLSARPGLRLLALAGAGSLAAGFLLRPEPVRAASERRRLYPPSAEYPDLRKHNNCMASHLTPA
+VYARLCDKTTPTGWTLDQCIQTGVDNPGHPFIKTVGMVAGDEETYEVFADLFDPVIQERHNGYDPRTMKH
+TTDLDASKIRSGYFDERYVLSSRVRTGRSIRGLSLPPACTRAERREVERVVVDALSGLKGDLAGRYYRLS
+EMTEAEQQQLIDDHFLFDKPVSPLLTAAGMARDWPDARGIWHNNEKSFLIWVNEEDHTRVISMEKGGNMK
+RVFERFCRGLKEVERLIQERGWEFMWNERLGYILTCPSNLGTGLRAGVHIKLPLLSKDSRFPKILENLRL
+QKRGTGGVDTAATGGVFDISNLDRLGKSEVELVQLVIDGVNYLIDCERRLERGQDIRIPTPVIHTKH
diff --git a/hg/pslPretty/test/input/mCrea.geno b/hg/pslPretty/test/input/mCrea.geno
new file mode 100644
index 0000000..093abe5
--- /dev/null
+++ b/hg/pslPretty/test/input/mCrea.geno
@@ -0,0 +1,114 @@
+>mCreatGeno
+GAATTCATCAAGGGATAAATCCATTAATTAGAGTAGAGCCCTTTTGAGCTTTTTGCAATAGCTGGTAATT
+AACCAAACCCCAATACATGAGCCAGTAAAGAACATTTCTTATCGAAAAAGAATTGATGATACTGATGATA
+TGAAAGCTTATTTACGCATATGTTACTGTTGACCTTGAATCTTCATTTAGGAGTTTGAGTGCCCCCATTT
+GTTCTCTATAATTTTGGGAACCTAGGAATTGTCCTAGTTAGATGCCTCATCTTACTGAAACCTCTGCCCC
+AGGCTTCCTGAATTGATAGAGATAGATTCTAAGAGCAGAATCTACAAAGAATCAGTGATAGTTAGGGCTC
+AGACTCATTCCTCTTCTACCACTCCAACCCTGGGAGCGAGTAATTACCGCAGCTCCCAGCTGTAAACAGC
+CTCCAGCGACCCCACTGGCATACTGAGCCTCACAAAGAATTTAAAAAGTGCACAAATCGATGAGCCCTCT
+TGGAAGAGCTATTGTTTCCCATAGGAAGGCATTTNCCAAATTTGAATGACTTCTCTGTACCCTGGCTGCC
+TTTACTTCTTCTGTTAGCCTCTCTTCCCACACCCCACTCCTGAACACCTTCTCAGCCAAATAATAGCCCA
+ATTGCTCTCGAAGACTATCTCCTCCTTTTATCTGGGTAAATATCNCCATCCCAAGTAATTATATCACTTA
+CTCATACCTCNCCTTACCTGGATATGAACACCCACAGCACAGGTAACATTTTTTTTCCCTCTCCAAAAAT
+AAGGAAGTTCCACCAGTAGATCTCTATCTTGGAAAATGTGTTATGTTACCAAGAGAAGAGGCTTAAGTAA
+TGGAGCCAAAAGTGAAATGGATTCTTTCTAAGGATACNCACCAATGAGAAAGGTCAGAAAGGAGACATAT
+GGGGTGGGGACTTGAGGGAAATAATTAATGTATATAGTTGGGCCAGTGGGGATTATGAAGGGTAATTCTT
+TTTCCCAAGTACTTTCTTACAACTTCCAAATATCTTACTGTCTTCTGGAACATCAGGAAGCTGAAGGTAG
+ACATATTAANNNCAATATGTCTGCTTTTGCTTTGGCTGGCCCTCCGCACCCAAACCTCAGGTCTCTATCT
+CAGCTTCAGCTTTCATTCCCCTTCCCAATATGTCTGCTTTGCTTTGGCTGGCCCTCCGCACCCAAACCTC
+AGGTCTCTATCTCAGCTTCAGCTTTCATTCCCCTTCCTGCACTAATAAAAGTCAAGTTGCTCCTAGCCCA
+GCACGTAGCTGTGGAAACAAACCCTCTTGAGTCTGAGTATGCACTTCGCAAAAGAGAGAGCGGACCAGGA
+AGAAGACAGAGACTCCCTGATGACCTTATGCCCTTGGATACTACCAGCCTTCACACTCCAGTTTAAACTG
+CCTTAGCAAGCCAAGAGAGGAAGCACGAGTGGTTCGGGAGACCTGTGCCTGCCTGTTCCATTCCACACCC
+AGTCATCTCACCAGACCCTCCTCCTCTCTTTATATTCCCCCTCCAGTCCTAGGAACTGCCAGCTGCAGAG
+AAGAAGGAAGAGAAGGAAGAAGAAACTCACCATTCCCTGCCCAACCCCAGCCCCACACCCAGAGCAATCA
+ACAGGTAGGCTTTCAGACACTACTCAGGAAGAGTCCTTCGAACAGCAAACAGATTTAAGCCTGGAAAAGA
+AGAAGAGAAATAAAAGATCAAAGGTGAAGCAGGGGTTAGAGTAGAGGAAAAAAAGAAAAAAAAAGCAGGT
+CCCCAATGAGAGGCAGGAAATAGCCAAGCTGAAGACTTGGAGGCAGTGAGTTTGGGAGACAGGATTCTTA
+AGGGATCCTTTCTCGACCTTATTAGGAAAGCATAGGTGTAGCTGGAGTTCCCTGGTGCTTCCTGGTTCTT
+AGGGAAGGTGACTTGAGGCTGTGCTGTCTTTCCCCTGAGCTCGCTCAGTCTTCCTCCTCTATCTGTTTAT
+TCTGTGGTTTTCCTGCGGCTGACTCTCCTGGGGAAAATGGAGAGATGGCGTGCAGATCGAATTCAATTCA
+GAAAAGAGGCTGGGCAATGTCAACCTCCCCACCCCCACCCCCAAAACCCAGAAATAGACGGATTGGTTTC
+AGATTTAAACAGAGAGGGTATGAAAGAAGGGGGGTTTCAGGTTCGGGAATCCCCGTGGTGCTGTCCTCTA
+CTTAGTGCTGAAATCTGACACCCTCATCCTTGGTGGGCGTCTGTCTCCAGCCTCAGGGAGTAAATCTCCA
+GTCTTCTTAATTACCTGGCTAGTGCTACCCAACCCCACCCCCGCACACCTAGCGCGGTGGCAGGCGGGAA
+GGCGGAGCCTGAGTGAGCCCCACCCCTGGAGACTGCGGCTGGGGCCTCCCTCTGCTCTGGCTGGCTCCTT
+GCTTCGCTGCGCTTCTCCTGCAGCCTGGTAGGCACCGGCTGCCACTTCAGCTTCAGCCTTCATCGTGACC
+CCTATTTTGGCTCCAGTCTCCGACCCAGCTCCGTCCTCTCTCTACCCGGTTGCATCTTCCCTCCTAGTTC
+CTGACTTGCACCAGATCCTGCTCTGAATCTTTGTAGCCGCATCCCCAAGCCATGGCTGGTCCCTTCTCCC
+GTCTGCTGTCTGCCCGCCCTGGACTCAGGCTCCTGGCTTTGGCTGGAGCTGGGTCTCTCACCGCCGGGAT
+TCTGCTCCGCCCGGAATCTGTAGGAGCTGCCGCTGCTGAACGGAGGAGACTGTATCCCCCGAGGTATTAG
+AGCCTGAGATGCACGAGGTGGGGGCTGGGGGTGGTAGTGGTGGTGATGGGAACCGAACAGGTAGAGAGGA
+TAACCTGAGCAAAAGATAGGCCTCGAAGATGGATTTCCTGTACAGTTTGGAGATCCTAGCCCTGTAATGG
+AAGAACATGTCTAAGGACATGTCACCCGATGTCACTGCCTCCACACCAGCTTTACCTTTGCAAATTCTAG
+GTTCACCCACTGCCCAAATCCTTTTTGGATGACTAGAAGCTTTTTTTTTTTTTTTTTTTTTTTAATCTCG
+ACCTATTCTCCTTGTTCTCCCGAATTCTCCTGAGTCTCTCCCCTCCCCCATCTCTAATGTTATGCTCACT
+AGAGAAAAGCAACTCTGTAGACAAGGGGGAATTGAGGTGTTAGAACTATTAGGAAAGAAAAGACCCTGGA
+AATCCCTGAAGAGATTATCAAGATTTAGCCTACCTCTAATTCCCCCTCCTTCCAATAAGCAAAGCCAGAC
+ATGGCTCACTGGACAGCTCCCAGCTGACATCAGTAGGTCTAGGCTCCTGTGCCCTCCCTCCATGGTTACT
+GGGTACCCCCTTCCCAGCGCTGAGTACCCAGACCTCCGAAAGCACAACAACTGCATGGCCAGTCACCTGA
+CCCCAGCAGTCTATGCACGGCTCTGCGACAAGACCACACCCACTGGTTGGACACTAGATCAGTGCATCCA
+GACTGGAGTGGACAACCCTGGCCACCCCTTCATCAAGACTGTGGGCATGGTGGCTGGAGATGAGGAGACC
+TATGAGGTAGGGGGCCCCTCAGAAATCCCAGTTCCTTCCTCCTAAAGATCCCTCATGTCTGTTCCCTCAA
+GACTCTGGATTGTCTATACTCAAACGTTCTGATCCAGTGATATCAATCTACAACTCAAGTGTTTCTTCTT
+TATAATCGCCTCTTCCTCTTAACTCCTTTTCAGGTATTTGCTGAACTGTTTGACCCTGTGATCCAAGAGC
+GGCATAATGGATATGACCCCAGAACAATGAAGCACACCACTGACCTTGATGCCAGTAAAGTGAGCCAAAT
+GTGACACTTCCGATATGTGCAGCCTTGTGCACAATGTTCTGTATCTCCAATCATTACACCTTGTTTCCTG
+ACTCAGGGTTAGACTGCTGAGCTTTGTATATTGATAAGAGAAAGAATTGCATATCTTGAAGTATAGCAGA
+TAGGAGGACGTAGTGGATAAGAGTCTGGATAATGGAGTTGAGGAGAATCTGATCAAAGTACAAAATGGTG
+AAAGAATTTTTAAGAAGTGACTATGTCCTGGCTGGGTGTGGTGGCTCACACCTGTAATCTCAGCTCTCAG
+ACGGCTCAGAAGAGCACTCCTCCCTCCACCAAAAAAAAAAAAAAAAAGGCTGTACCCAAAGTGAGAAATG
+TGGAGAAATGACCACAGTGTTTTCAGTTAGCATGCCTGTCCAATGTGTCTTCCTTCTGGCACCTGCTTTA
+TAATCCCCAAGAGTTCCCACCTGCTGTGTTTCTATGATTTATAGTCATTTCTCTTATTCCTCAGATTCGT
+TCTGGCTACTTTGATGAGAGGTATGTATTGTCTTCAAGAGTCAGAACTGGCCGAAGTATCAGGGGACTCA
+GTCTCCCTCCAGCCTGCACTCGGGCAGAGCGAAGAGAGGTAGAACGTGTTGTGGTGGATGCTCTGAGTGG
+CCTGAAGGGTGACCTGGCTGGACGGTACTATAGGCTCAGTGAGATGACGGAGGCCGAACAGCAGCAGCTT
+ATTGATGTGAGGGCCTTGACAGGGAACGGGATTGTGGAAAAAGAGGTGGAGGGGAGAGTGGACCAGAAAA
+GGTAGATGGCCTGGATGGTACTGTGAGAATTCTTAGACCCAATCCCTTTATTCTCCTCAGGACCATTTTC
+TGTTTGATAAACCTGTGTCCCCATTGCTGACTGCAGCAGGAATGGCTCGAGACTGGCCTGATGCTCGAGG
+GATCTGGTATGGAGCCAACACACTTTTTTGGTTTTTTTTTTCCCCCTTGTATGTGCAAAGTTTTTTCTCC
+ATCTACCCCAGTGCTTGTCTTGCCCACTGATGGCTATACCTATCCTGCCCTCAGGCACAACAATGAGAAG
+AGTTTCTTGATCTGGGTGAATGAGGAGGACCACACACGGGTCATCTCTATGGAGAAAGGCGGCAACATGA
+AGAGAGTGTTTGAAAGATTCTGCCGGGGCCTCAAAGAGGTTGGAGAAGGGTATACCAGGGAGCTAGGGGA
+GAGGAAATGAGAAATACCACACAGCAGCATAGCTAGATCGGCTATATCACTTGTCAGTCAACCCAGAGTA
+TTTCTGATAGTAGAAAGGGTCATTATCATGCTAGGATAATAGTTACAAACCAGGGCCGTCCTTGGNAAAC
+CAGGGCATATAGTTACTCTAAAAATAGAAAGAGTGTCAGTAACCTAAGGAAGGAAATAAAGCATAATCTT
+TGCCAAGTAATGAAAAGAAGGAACCAATGATCAGCAAGCCAGTGCCGGGGTAGGTGGTATGAGGTAGTAT
+GTGCAGTTAAGGAGAACGTTTGAGCCTGGACTGATGGAAGGCGTGAGAGATTGGTTTGTTCATGATACAT
+CACCAAGTTCTGANCAAGGCTCACCTTGGCTCTGGAGATCTGATCCTTGATGTATTTTCTTGTATCTACA
+GTTTTATTTTTGGACTTGTAAAGAAAGGGTGCTTCTCTTTTAGATTCTAGCCAGGAAGCTCACACTATTT
+TCGGCAAGGAATGGATAATGTTCTATGAGTAGCATAGAGAAATACTCTTTAATTATATGACTCTGTTTAT
+TTGTCTATAAAGTTGAGGACTAAATGAAATAATGTAGGCAGAGGAATTGTTCTATAATAAGTGTTAGCTT
+TACGATGTAAAAATCTCCATGCTTGTGATTCCTTCTGAGTTACAGAGCATCATCTTTAGGTAGTGTGGTC
+TTTGTGTCTATTGCTCTGGCAGGCCCCTGTCTCTTCCATCCTAATAGTCATTATGGTGGTCAGGAAAGCA
+AGAACATCTCTTGAAGTCCCCCTCTTCTCACATGTACCTGTGAATCTGGCTTCTCTGCTGTACCTTCTCA
+TGTCTCCCTGCTCTATTATCCATGTTCCTTTTATAGCTAAGAGTAGGCTCTCCTGCCTTAGCACCTCGTT
+TCTGTCCAAAGGGACCCTTTGTCAAAGATGTAATTGATGCATGAGAACTCCCTGTCCTGTTTACTACTTC
+TATTCATTTCCCAAGTCACTCTTAATGTATCATTCTCCAAAGCTTCTTCTACGAACAATCTATCTGCCAC
+AATCTTATCAGCATGCATATAATGCAACATCCAAGTGTCCTTCCATGTGCAATGACAATAAGTTTTAACA
+ACAACAAAGAGCATGTCATTCATCGATCGTCAAGTTTCTCGTTGTAGACATAGTTCTAGAATGTCTGTGG
+GGCTAAGAGGGATCCCTCCCTCCCTGATTTTTCACAACAGAACCTCTGTTGACACAGGTGGAGAAGCTGA
+TCCAGGAACGAGGCTGGGAGTTCATGTGGAATGAGCGTTTAGGCTACATCTTGACCTGTCCATCTAACCT
+GGGCACTGGACTTCGGGCAGGAGTCCACATCAAACTGCCACTGCTGAGCAAAGTAAAGGATATGTGGGGC
+TAGAGGGGGTGTAAGAAGGGGGACTTGGAAGGGGGTGGAGGAGACACTCTAAAAAGAGCCAGTCCTAAGG
+GCTTATGGCTAGTGGGCCAAGGGTAGGAGCAGTCTCAGAAACTATTGACATGCCCCTGATCTTTACCTTG
+CATCTAGGATAACCGCTTCCCAAAGATCCTGGAGAACCTAAGACTGCAAAAGCGTGGAACTGGAGGAGTG
+GACACTGCTGCTACAGGCAGCGTCTTTGACATCTCTAATTTGGATCGACTTGGCAAGTCAGAGGTGAGGT
+CTTATGAATCAGGTTAAGAGGTTGAGATAAGGCAGTGAGTGAGCCTCAGGAACATAATAGAATCTGAAGC
+AATGGTCAGGTTGAGTGGGGTAGGGAAGAGAAAACGAGTTTTCAGAGATGGAAGAGCTAAAGAAACTCAG
+GTCAGGCAAGGTGGTCTGTGCTTTTAATACCAGCAGAAGCAAGACAGATCTCTGTGAGTCTCAGGCCAGC
+CAGGGCTACATAATGAGATCCTGTCACAAAAACTGAAAAAAGAAAAAGAAGGAAAAGAAGGAAGGAGGGA
+AGGAAGGAAGGGAGAGAGAGAGAGAGGGAGGGAGAGAGAGGAAGAGAGAGAGATTAAGAGAAGCTCGGGT
+ACACCGGGAAGCAGGGATCAAGGACTGTGTTCTTCAGGTGGAGCTGGTGCAGCTCGTCATCGATGGGGTG
+AACTATTTGATTGACTGTGAACGGCGTCTGGAGAGAGGACAGGATATTCGAATCCCTCCACCTCTTGTCC
+ACAGCAAACATTAACTCCCCATCCCCAGCGGATGAGTCAAGACCCCCAGGACTTCTGCATATTTAACAGT
+GGCCCAGTCTACTTGCCCTGGACCTGCCTCTCTCCCTGTCCTAGTAAAGACTCCACATTATGTTGCAGCT
+GTCTGTGTTATTTCTATTGGTGTGGTGAGGAGGAAGTAGGAAATGAAAAGAAACAGTGAGGTTATTCATG
+ATGGCAAGAGGCGTATATGCCAGGAGCACAGTTCTCAGGTGGGTGGAATGCATTGGAATTTTACCCACAA
+TCCTCATCCACTTACTGAGAATAATTAGTATGCACTTCCATTTACAAGTTGTTCAGTATGATGTAAATTT
+TCTCCCTCAACTGAAGGAACAGTTATCATAATAGGTGGCCAAAAAAAATGCTGACGGGGCAATGCCAGGG
+CCCAGGAGGCTTGGAACCAGTCGTAGAGACCCCAGGCTGAGTTTCGACCTAGAATGAGACAAGGAATGGG
+AGGAAAAAAAATCACAGTTCCGTTCCCCAGGAGCCTTTGATGTTTCAAATTTAGCTCTGTGTATAGATCC
+CTCTACTCCAGAGATTCTCCTGTGTGGGGTCTGAGGACCAGACAGCACCAAGTTAGGACTTAGATGGACT
+CTGGGTCAGATGACAGCTTATCAAACTATGCAGTTGGTAACGTACCCAGCTGCTCTGGGATCTCCTTCCC
+TTCGTGTTGGGCCC
diff --git a/hg/pslReps/makefile b/hg/pslReps/makefile
new file mode 100644
index 0000000..28b93d9
--- /dev/null
+++ b/hg/pslReps/makefile
@@ -0,0 +1,18 @@
+include ../../inc/common.mk
+
+
+L += -lm
+MYLIBDIR = ../../lib/$(MACHTYPE)
+MYLIBS =  $(MYLIBDIR)/jkweb.a
+
+
+O = pslReps.o 
+
+pslReps: $O $(MYLIBS)
+	${CC} ${COPT} ${CFLAGS} -o ${DESTDIR}${BINDIR}/pslReps${EXE} $O $(MYLIBS) $L
+
+lib:
+	cd ../../lib && ${MAKE}
+
+clean::
+	rm -f ${O}
diff --git a/hg/pslReps/pslReps.c b/hg/pslReps/pslReps.c
new file mode 100644
index 0000000..edc7ccd
--- /dev/null
+++ b/hg/pslReps/pslReps.c
@@ -0,0 +1,429 @@
+/* pslReps - analyse repeats and generate list of best alignments
+ * from a genome wide, sorted by mRNA .psl alignment file.
+ */
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "memalloc.h"
+#include "psl.h"
+#include "options.h"
+#include "obscure.h"
+#include "sqlNum.h"
+
+
+/* command line */
+static struct optionSpec optionSpecs[] = {
+    {"minAli", OPTION_FLOAT},
+    {"nearTop", OPTION_FLOAT},
+    {"minCover", OPTION_FLOAT},
+    {"minNearTopSize", OPTION_INT},
+    {"ignoreSize", OPTION_BOOLEAN},
+    {"sizeMatters", OPTION_BOOLEAN},  /* opposite of ignore size, for compat */
+    {"noIntrons", OPTION_BOOLEAN},
+    {"singleHit", OPTION_BOOLEAN},
+    {"nohead", OPTION_BOOLEAN},
+    {"ignoreNs", OPTION_BOOLEAN},
+    {"coverQSizes", OPTION_STRING},
+    {NULL, 0}
+};
+
+double minAli = 0.93;
+double nearTop = 0.01;
+double minCover = 0.0;
+boolean ignoreNs = FALSE; /* Ignore the n's when calculating coverage score, other
+			     wise n's count as mismatches. */
+boolean ignoreSize = FALSE;
+boolean noIntrons = FALSE;
+boolean singleHit = FALSE;
+boolean noHead = FALSE;
+boolean quiet = FALSE;
+int minNearTopSize = 30;
+char *coverQSizeFile = NULL;
+
+void usage()
+/* Print usage instructions and exit. */
+{
+errAbort(
+    "pslReps - analyse repeats and generate genome wide best\n"
+    "alignments from a sorted set of local alignments\n"
+    "usage:\n"
+    "    pslReps in.psl out.psl out.psr\n"
+    "where in.psl is an alignment file generated by psLayout and\n"
+    "sorted by pslSort, out.psl is the best alignment output\n"
+    "and out.psr contains repeat info\n"
+    "options:\n"
+    "    -nohead don't add PSL header\n"
+    "    -ignoreSize Will not weigh in favor of larger alignments so much\n"
+    "    -noIntrons Will not penalize for not having introns when calculating\n"
+    "              size factor\n"
+    "    -singleHit  Takes single best hit, not splitting into parts\n"
+    "    -minCover=0.N minimum coverage to output.  Default is 0.\n"
+    "    -ignoreNs Ignore 'N's when calculating minCover.\n"
+    "    -minAli=0.N minimum alignment ratio\n"
+    "               default is 0.93\n"
+    "    -nearTop=0.N how much can deviate from top and be taken\n"
+    "               default is 0.01\n"
+    "    -minNearTopSize=N  Minimum size of alignment that is near top\n"
+    "               for alignment to be kept.  Default 30.\n"
+    "    -coverQSizes=file Tab-separate file with effective query sizes.\n"
+    "                     When used with -minCover, this allows polyAs\n"
+    "                     to be excluded from the coverage calculation\n");
+}
+
+/* hash table of query name to sizes */
+struct hash* coverQSizes = NULL;
+
+void loadCoverQSizes(char* coverQSizeFile)
+/* load coverage query sizes */
+{
+struct lineFile *lf = lineFileOpen(coverQSizeFile, TRUE);
+char *row[2];
+coverQSizes = hashNew(0);
+
+while (lineFileNextRowTab(lf, row, ArraySize(row)))
+    {
+    int qSize = sqlSigned(row[1]);
+    hashAdd(coverQSizes, row[0], intToPt(qSize));
+    }
+
+lineFileClose(&lf);
+}
+
+int calcMilliScore(struct psl *psl)
+/* Figure out percentage score. */
+{
+return 1000-pslCalcMilliBad(psl, TRUE);
+}
+
+int intronFactor(struct psl *psl)
+/* Figure bonus for having introns.  An intron is worth 3 bases... 
+ * An intron in this case is just a gap of 0 bases in query and
+ * 30 or more in target. */
+{
+int i, blockCount = psl->blockCount;
+int ts, qs, te, qe, sz;
+int bonus = 0;
+if (blockCount <= 1)
+    return 0;
+sz = psl->blockSizes[0];
+qe = psl->qStarts[0] + sz;
+te = psl->tStarts[0] + sz;
+for (i=1; i<blockCount; ++i)
+    {
+    qs = psl->qStarts[i];
+    ts = psl->tStarts[i];
+    if (qs == qe && ts - te >= 30)
+        bonus += 3;
+    sz = psl->blockSizes[i];
+    qe = qs + sz;
+    te = ts + sz;
+    }
+if (bonus > 10) bonus = 10;
+return bonus;
+}
+
+int sizeFactor(struct psl *psl)
+/* Return a factor that will favor longer alignments. */
+{
+int score;
+if (ignoreSize) return 0;
+score = 4*round(sqrt(psl->match + psl->repMatch/4));
+if (!noIntrons)
+    score += intronFactor(psl);
+return score;
+}
+
+int calcSizedScore(struct psl *psl)
+/* Return score that includes base matches and size. */
+{
+int score = calcMilliScore(psl) + sizeFactor(psl);
+return score;
+}
+
+boolean uglyTarget(struct psl *psl)
+/* Return TRUE if it's the one we're snooping on. */
+{
+return sameString(psl->qName, "AF103731");
+}
+
+
+boolean closeToTop(struct psl *psl, int *scoreTrack)
+/* Returns TRUE if psl is near the top scorer for at least 20 bases. */
+{
+int milliScore = calcSizedScore(psl);
+int threshold = round(milliScore * (1.0+nearTop));
+int i, blockIx;
+int start, size, end;
+int topCount = 0;
+char strand = psl->strand[0];
+
+for (blockIx = 0; blockIx < psl->blockCount; ++blockIx)
+    {
+    start = psl->qStarts[blockIx];
+    size = psl->blockSizes[blockIx];
+    end = start+size;
+    if (strand == '-')
+	reverseIntRange(&start, &end, psl->qSize);
+    for (i=start; i<end; ++i)
+	{
+	if (scoreTrack[i] <= threshold)
+	    {
+	    if (++topCount >= minNearTopSize)
+		return TRUE;
+	    }
+	}
+    }
+return FALSE;
+}
+
+boolean passMinCoverage(struct psl *psl)
+/* Does this psl have enough bases aligned to pass the minCover filter. */
+{
+int qSize = psl->qSize;
+if (coverQSizes != NULL)
+    {
+    struct hashEl *hel = hashLookup(coverQSizes, psl->qName);
+    if (hel != NULL)
+        qSize = ptToInt(hel->val);
+    }
+
+if(ignoreNs)
+    return (psl->match + psl->repMatch >= minCover * (qSize - psl->nCount));
+else
+    return (psl->match + psl->repMatch >= minCover * qSize);
+}
+
+boolean passFilters(struct psl *psl, int *scoreTrack)
+/* Return TRUE if this psl passes the millScore, minCoverage and
+   closeToTop thresholds.  If scoreTrack is NULL then closeToTop
+   threshold is skipped. */
+{
+int milliMin = 1000*minAli;
+if (calcMilliScore(psl) >= milliMin && 
+    (scoreTrack == NULL || closeToTop(psl, scoreTrack)) &&
+    passMinCoverage(psl))
+    return TRUE;
+return FALSE;
+}
+
+void processBestMulti(char *acc, struct psl *pslList, FILE *bestFile, FILE *repFile)
+/* Find psl's that are best anywhere along their length. */
+{
+struct psl *psl;
+int qSize;
+int *repTrack = NULL;
+int *scoreTrack = NULL;
+int milliScore;
+int goodAliCount = 0;
+int bestAliCount = 0;
+int milliMin = 1000*minAli;
+
+
+if (pslList == NULL)
+    return;
+qSize = pslList->qSize;
+AllocArray(repTrack, qSize+1);
+AllocArray(scoreTrack, qSize+1);
+
+for (psl = pslList; psl != NULL; psl = psl->next)
+    {
+    int blockIx;
+    char strand = psl->strand[0];
+    milliScore = calcMilliScore(psl);
+    if (milliScore >= milliMin)
+	{
+	++goodAliCount;
+	milliScore += sizeFactor(psl);
+	for (blockIx = 0; blockIx < psl->blockCount; ++blockIx)
+	    {
+	    int start = psl->qStarts[blockIx];
+	    int size = psl->blockSizes[blockIx];
+	    int end = start+size;
+	    int i;
+	    if (strand == '-')
+	        reverseIntRange(&start, &end, psl->qSize);
+	    if (start < 0 || end > qSize)
+		{
+		warn("Odd: qName %s tName %s qSize %d psl->qSize %d start %d end %d",
+		    psl->qName, psl->tName, qSize, psl->qSize, start, end);
+		if (start < 0)
+		    start = 0;
+		if (end > qSize)
+		    end = qSize;
+		}
+	    for (i=start; i<end; ++i)
+		{
+		repTrack[i] += 1;
+		if (milliScore > scoreTrack[i])
+		    scoreTrack[i] = milliScore;
+		}
+	    }
+	}
+    }
+/* Print out any alignments that are within 2% of top score. */
+for (psl = pslList; psl != NULL; psl = psl->next)
+    {
+    if(passFilters(psl, scoreTrack))
+	{
+	pslTabOut(psl, bestFile);
+	++bestAliCount;
+	}
+    }
+
+
+/* Print out run-length-encoded repeat info.  */
+    {
+    int runVal = repTrack[0];
+    int curVal;
+    int runSize = 1;
+    int packetCount = 0;
+    int *packetSize = NULL;
+    int *packetVal = NULL;
+    int i;
+
+    AllocArray(packetSize, qSize);
+    AllocArray(packetVal, qSize);
+
+    repTrack[qSize] = -1;	/* Sentinal value to simplify RLC loop. */
+    fprintf(repFile, "%s\t%d\t%d\t", acc, bestAliCount, goodAliCount);
+
+    for (i=1; i<=qSize; ++i)
+	{
+	if ((curVal = repTrack[i]) != runVal)
+	    {
+	    packetSize[packetCount] = runSize;
+	    packetVal[packetCount] = runVal;
+	    ++packetCount;
+	    runSize = 1;
+	    runVal = curVal;
+	    }
+	else
+	    {
+	    ++runSize;
+	    }
+	}
+    fprintf(repFile, "%d\t", packetCount);
+    for (i=0; i<packetCount; ++i)
+	fprintf(repFile, "%d,", packetSize[i]);
+    fprintf(repFile, "\t");
+    for (i=0; i<packetCount; ++i)
+	fprintf(repFile, "%d,", packetVal[i]);
+    fprintf(repFile, "\n");
+
+    carefulCheckHeap();
+    freeMem(packetSize);
+    freeMem(packetVal);
+    }
+
+carefulCheckHeap();
+freeMem(repTrack);
+freeMem(scoreTrack);
+}
+
+void processBestSingle(char *acc, struct psl *pslList, FILE *bestFile, FILE *repFile)
+/* Find single best psl in list. */
+{
+struct psl *bestPsl = NULL, *psl;
+int bestScore = 0, score, threshold;
+
+for (psl = pslList; psl != NULL; psl = psl->next)
+    {
+    score = pslScore(psl);
+    if (score > bestScore)
+        {
+	bestScore = score;
+	bestPsl = psl;
+	}
+    }
+threshold = round((1.0 - nearTop)*bestScore);
+for (psl = pslList; psl != NULL; psl = psl->next)
+    {
+    if (pslScore(psl) >= threshold && passFilters(psl, NULL))
+        pslTabOut(psl, bestFile);
+    }
+}
+
+void doOneAcc(char *acc, struct psl *pslList, FILE *bestFile, FILE *repFile)
+/* Process alignments of one piece of mRNA. */
+{
+if (singleHit)
+    processBestSingle(acc, pslList, bestFile, repFile);
+else
+    processBestMulti(acc, pslList, bestFile, repFile);
+}
+
+void pslReps(char *inName, char *bestAliName, char *repName)
+/* Analyse inName and put best alignments for eacmRNA in estAliName.
+ * Put repeat info in repName. */
+{
+struct lineFile *in = pslFileOpen(inName);
+FILE *bestFile = mustOpen(bestAliName, "w");
+FILE *repFile = mustOpen(repName, "w");
+int lineSize;
+char *line;
+char *words[32];
+int wordCount;
+struct psl *pslList = NULL, *psl = NULL;
+char lastName[512];
+int aliCount = 0;
+quiet = sameString(bestAliName, "stdout") || sameString(repName, "stdout");
+if (coverQSizeFile != NULL)
+    loadCoverQSizes(coverQSizeFile);
+
+if (!quiet)
+    printf("Processing %s to %s and %s\n", inName, bestAliName, repName);
+ if (!noHead)
+     pslWriteHead(bestFile);
+strcpy(lastName, "");
+while (lineFileNext(in, &line, &lineSize))
+    {
+    if (((++aliCount & 0x1ffff) == 0) && !quiet)
+        {
+	printf(".");
+	fflush(stdout);
+	}
+    wordCount = chopTabs(line, words);
+    if (wordCount == 21)
+	psl = pslLoad(words);
+    else if (wordCount == 23)
+	psl = pslxLoad(words);
+    else
+	errAbort("Bad line %d of %s\n", in->lineIx, in->fileName);
+    if (!sameString(lastName, psl->qName))
+	{
+	doOneAcc(lastName, pslList, bestFile, repFile);
+	pslFreeList(&pslList);
+	safef(lastName, sizeof(lastName), "%s", psl->qName);
+	}
+    slAddHead(&pslList, psl);
+    }
+doOneAcc(lastName, pslList, bestFile, repFile);
+pslFreeList(&pslList);
+lineFileClose(&in);
+fclose(bestFile);
+fclose(repFile);
+if (!quiet)
+    printf("Processed %d alignments\n", aliCount);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, optionSpecs);
+if (argc != 4)
+    usage();
+minAli = optionFloat("minAli", minAli);
+nearTop = optionFloat("nearTop", nearTop);
+minCover = optionFloat("minCover", minCover);
+minNearTopSize = optionInt("minNearTopSize", minNearTopSize);
+ignoreSize = optionExists("ignoreSize");
+if (optionExists("sizeMatters"))
+    warn("warning: -sizeMatters is deprecated and is now the default");
+noIntrons = optionExists("noIntrons");
+singleHit = optionExists("singleHit");
+noHead = optionExists("nohead");
+ignoreNs = optionExists("ignoreNs");
+coverQSizeFile = optionVal("coverQSizes", NULL);
+pslReps(argv[1], argv[2], argv[3]);
+return 0;
+}
diff --git a/hg/pslSort/makefile b/hg/pslSort/makefile
new file mode 100644
index 0000000..0b12592
--- /dev/null
+++ b/hg/pslSort/makefile
@@ -0,0 +1,19 @@
+include ../../inc/common.mk
+
+
+L += -lm
+MYLIBDIR = ../../lib/$(MACHTYPE)
+MYLIBS =  $(MYLIBDIR)/jkweb.a
+
+O = pslSort.o
+
+pslSort: $O $(MYLIBS)
+	${CC} ${COPT} ${CFLAGS} -o ${DESTDIR}${BINDIR}/pslSort $O $(MYLIBS) $L
+
+
+lib:
+	cd ../lib && ${MAKE}
+	cd ../../lib && ${MAKE}
+
+clean::
+	rm -f ${O} pslSort
diff --git a/hg/pslSort/old.as b/hg/pslSort/old.as
new file mode 100644
index 0000000..cba5c32
--- /dev/null
+++ b/hg/pslSort/old.as
@@ -0,0 +1,18 @@
+
+table psc
+"mRNA alignment basic info"
+    (
+    uint score;  "Matches minus mismatches"
+    char[12] qAcc;  "mRNA accession"
+    uint qStart; "Start of alignment in mRNA"
+    uint qEnd; "End of alignment in mRNA"
+    uint qSize; "Total mRNA size"
+    char[12] tAcc; "Genomic accession"
+    uint tStart; "Start of alignment in genomic"
+    uint tEnd; "End of alignment in genomic"
+    uint tSize; "Total genomic size"
+    string blockSizes; "Size of each block."
+    string qBlockStarts; "Start of each block in mRNA"
+    string tBlockStarts; "Start of each block in genomic"
+    )
+    
diff --git a/hg/pslSort/pslSort.c b/hg/pslSort/pslSort.c
new file mode 100644
index 0000000..74cd23a
--- /dev/null
+++ b/hg/pslSort/pslSort.c
@@ -0,0 +1,397 @@
+/* pslSort - merge and sort psCluster .psl output files. */
+#include "common.h"
+#include "portable.h"
+#include "linefile.h"
+#include "memalloc.h"
+#include "localmem.h"
+#include "options.h"
+#include "psl.h"
+
+
+boolean nohead = FALSE; /* No header for psl files?  Command line option. */
+
+void usage()
+/* Explain usage and exit. */
+{
+errAbort(
+   "pslSort - merge and sort psCluster .psl output files\n"
+   "usage:\n"
+   "  pslSort dirs[1|2] outFile tempDir inDir(s)\n"
+   "This will sort all of the .psl files in the directories\n"
+   "inDirs in two stages - first into temporary files in tempDir\n"
+   "and second into outFile.  The device on tempDir needs to have\n"
+   "enough space (typically 15-20 gigabytes if processing whole genome)\n"
+   "  pslSort g2g[1|2] outFile tempDir inDir(s)\n"
+   "This will sort a genome to genome alignment, reflecting the\n"
+   "alignments across the diagonal.\n"
+   "\n"
+   "Adding 1 or 2 after the dirs or g2g will limit the program to\n"
+   "only the first or second pass repectively of the sort\n"
+   "\n"
+   "Options:\n"
+   "   -nohead - do not write psl header:\n"
+   "   -verbose=N Set verbosity level, higher for more output. Default 1\n"
+   );
+}
+
+void makeMidName(char *tempDir, int ix, char *retName)
+/* Return name of temp file of given index. */
+{
+sprintf(retName, "%s/tmp%d.psl", tempDir, ix);
+}
+
+struct midFile
+/* Info on an intermediate file - a sorted chunk. */
+    {
+    struct midFile *next;	/* Next in list. */
+    struct lineFile *lf;        /* Associated file. */
+    struct psl *psl;            /* Current record. */
+    };
+
+struct psl *nextPsl(struct lineFile *lf)
+/* Read next line from file and convert it to psl.  Return
+ * NULL at eof. */
+{
+char *line;
+int lineSize;
+char *words[32];
+int wordCount;
+
+if (!lineFileNext(lf, &line, &lineSize))
+    {
+    //warn("File %s appears to be incomplete\n", lf->fileName);
+    return NULL;
+    }
+wordCount = chopTabs(line, words);
+if (wordCount == 21)
+    {
+    return pslLoad(words);
+    }
+else if (wordCount == 23)
+    {
+    return pslxLoad(words);
+    }
+else
+    {
+    warn("Bad line %d of %s", lf->lineIx, lf->fileName);
+    return NULL;
+    }
+}
+
+
+struct psl *nextLmPsl(struct lineFile *lf, struct lm *lm)
+/* Read next line from file and convert it to psl.  Return
+ * NULL at eof. */
+{
+char *line;
+int lineSize;
+char *words[32];
+int wordCount;
+
+if (!lineFileNext(lf, &line, &lineSize))
+    return NULL;
+wordCount = chopTabs(line, words);
+if (wordCount == 21)
+    {
+    return pslLoadLm(words, lm);
+    }
+else if (wordCount == 23)
+    {
+    return pslxLoadLm(words, lm);
+    }
+else
+    {
+    warn("Bad line %d of %s", lf->lineIx, lf->fileName);
+    return NULL;
+    }
+}
+
+
+
+
+void pslSort2(char *outFile, char *tempDir)
+/* Do second step of sort - merge all sorted files in tempDir
+ * to final. */
+{
+char fileName[512];
+struct slName *tmpList, *tmp;
+struct midFile *midList = NULL, *mid;
+int aliCount = 0;
+FILE *f = mustOpen(outFile, "w");
+
+
+if (!nohead)
+    pslWriteHead(f);
+tmpList = listDir(tempDir, "tmp*.psl");
+if (tmpList == NULL)
+    errAbort("No tmp*.psl files in %s\n", tempDir);
+for (tmp = tmpList; tmp != NULL; tmp = tmp->next)
+    {
+    sprintf(fileName, "%s/%s", tempDir, tmp->name);
+    AllocVar(mid);
+    mid->lf = pslFileOpen(fileName);
+    slAddHead(&midList, mid);
+    }
+verbose(1, "writing %s", outFile);
+fflush(stdout);
+/* Write out the lowest sorting line from mid list until done. */
+for (;;)
+    {
+    struct midFile *bestMid = NULL;
+    if ( (++aliCount & 0xffff) == 0)
+	{
+	verboseDot();
+	fflush(stdout);
+	}
+    for (mid = midList; mid != NULL; mid = mid->next)
+	{
+	if (mid->lf != NULL && mid->psl == NULL)
+	    {
+	    if ((mid->psl = nextPsl(mid->lf)) == NULL)
+		lineFileClose(&mid->lf);
+	    }
+	if (mid->psl != NULL)
+	    {
+	    if (bestMid == NULL || pslCmpQuery(&mid->psl, &bestMid->psl) < 0)
+		bestMid = mid;
+	    }
+	}
+    if (bestMid == NULL)
+	break;
+    pslTabOut(bestMid->psl, f);
+    pslFree(&bestMid->psl);
+    }
+printf("\n");
+fclose(f);
+
+/* The followint really shouldn't be necessary.... */
+for (mid = midList; mid != NULL; mid = mid->next)
+    lineFileClose(&mid->lf);
+
+printf("Cleaning up temp files\n");
+for (tmp = tmpList; tmp != NULL; tmp = tmp->next)
+    {
+    sprintf(fileName, "%s/%s", tempDir, tmp->name);
+    remove(fileName);
+    }
+}
+
+int calcMilliScore(struct psl *psl)
+/* Figure out percentage score. */
+{
+int milliScore = psl->match + psl->repMatch - psl->misMatch -
+	2*psl->qNumInsert - 4*psl->tNumInsert;
+
+milliScore *= 1000;
+milliScore /= (psl->qEnd - psl->qStart);
+return milliScore;
+}
+
+
+void reverseRange(unsigned *pStart, unsigned *pEnd, unsigned size)
+/* Reverse strand that range occupies. */
+{
+int start, end;
+start = size - *pEnd;
+end = size - *pStart;
+*pStart = start;
+*pEnd = end;
+}
+
+void reverseStartList(unsigned *oldList, unsigned *newList, 
+	unsigned *sizes, int count, int newSize)
+/* Reverse order and strand of start blocks. */
+{
+int i, revI;
+
+for (i=0; i<count; ++i)
+    {
+    revI = count-1-i;
+    newList[i] = newSize - (oldList[revI] + sizes[revI]);
+    }
+}
+
+void reverseSizeList(unsigned *oldList, unsigned *newList, int count)
+/* Reverse order of size list. */
+{
+int i, revI;
+for (i=0; i<count; ++i)
+    {
+    revI = count-1-i;
+    newList[i] = oldList[revI];
+    }
+}
+
+struct psl *mirrorLmPsl(struct psl *psl, struct lm *lm)
+/* Reflect a psl into local memory. */
+{
+struct psl *p = lmCloneMem(lm, psl, sizeof(*psl));
+p->qNumInsert = psl->tNumInsert;
+p->tNumInsert = psl->qNumInsert;
+p->qBaseInsert = psl->tBaseInsert;
+p->tBaseInsert = psl->qBaseInsert;
+p->qName = lmCloneString(lm, psl->tName);
+p->tName = lmCloneString(lm, psl->qName);
+p->qSize = psl->tSize;
+p->tSize = psl->qSize;
+p->qStart = psl->tStart;
+p->tStart = psl->qStart;
+p->qEnd = psl->tEnd;
+p->tEnd = psl->qEnd;
+p->blockSizes = lmCloneMem(lm, psl->blockSizes, psl->blockCount*sizeof(psl->blockSizes[0]));
+p->qStarts = lmCloneMem(lm, psl->tStarts, psl->blockCount*sizeof(psl->tStarts[0]));
+p->tStarts = lmCloneMem(lm, psl->qStarts, psl->blockCount*sizeof(psl->tStarts[0]));
+if (p->strand[0] == '-')
+    {
+    reverseStartList(psl->qStarts, p->tStarts, p->blockSizes, p->blockCount, p->tSize);
+    reverseStartList(psl->tStarts, p->qStarts, p->blockSizes, p->blockCount, p->qSize);
+    reverseSizeList(psl->blockSizes, p->blockSizes, p->blockCount);
+    }
+return p;
+}
+
+boolean selfFile(char *path)
+/* Return TRUE if of form XX_XX.psl */
+{
+char dir[256], root[128], ext[128];
+char *a, *b;
+
+splitPath(path, dir, root, ext);
+a = root;
+b = strchr(a, '_');
+if (b == NULL)
+    return FALSE;
+*b++ = 0;
+return sameString(a, b);
+}
+
+
+void pslSort(char *command, char *outFile, char *tempDir, char *inDirs[], int inDirCount)
+/* Do the two step sort. */
+{
+int i;
+struct slName *fileList = NULL, *name;
+char *inDir;
+struct slName *dirDir, *dirFile;
+char fileName[512];
+int fileCount;
+int totalFilesProcessed = 0;
+int filesPerMidFile;
+int midFileCount = 0;
+FILE *f;
+struct lineFile *lf;
+boolean doReflect = FALSE;
+boolean suppressSelf = FALSE;
+boolean firstOnly = endsWith(command, "1");
+boolean secondOnly = endsWith(command, "2");
+
+if (startsWith("dirs", command))
+    ;
+else if (startsWith("g2g", command))
+    {
+    doReflect = TRUE;
+    suppressSelf = TRUE;
+    }
+else
+    usage();
+
+
+if (!secondOnly)
+    {
+    makeDir(tempDir);
+    /* Figure out how many files to process. */
+    for (i=0; i<inDirCount; ++i)
+	{
+	inDir = inDirs[i];
+	dirDir = listDir(inDir, "*.psl");
+	if (slCount(dirDir) == 0)
+	    dirDir = listDir(inDir, "*.psl.gz");
+	if (slCount(dirDir) == 0)
+	    errAbort("No psl files in %s\n", inDir);
+	verbose(1, "%s with %d files\n", inDir, slCount(dirDir));
+	for (dirFile = dirDir; dirFile != NULL; dirFile = dirFile->next)
+	    {
+	    sprintf(fileName, "%s/%s", inDir, dirFile->name);
+	    name = newSlName(fileName);
+	    slAddHead(&fileList, name);
+	    }
+	slFreeList(&dirDir);
+	}
+    verbose(1, "%d files in %d dirs\n", slCount(fileList), inDirCount);
+    slReverse(&fileList);
+    fileCount = slCount(fileList);
+    filesPerMidFile = round(sqrt(fileCount));
+    // if (filesPerMidFile > 20)
+	// filesPerMidFile = 20;  /* bandaide! Should keep track of mem usage. */
+    verbose(1, "Got %d files %d files per mid file\n", fileCount, filesPerMidFile);
+
+    /* Read in files a group at a time, sort, and write merged, sorted
+     * output of one group. */
+    name = fileList;
+    while (totalFilesProcessed < fileCount)
+	{
+	int filesInMidFile = 0;
+	struct psl *pslList = NULL, *psl;
+	int lfileCount = 0;
+	struct lm *lm = lmInit(256*1024);
+
+	for (filesInMidFile = 0; filesInMidFile < filesPerMidFile && name != NULL;
+	    ++filesInMidFile, ++totalFilesProcessed, name = name->next)
+	    {
+	    boolean reflectMe = FALSE;
+	    if (doReflect)
+		{
+		reflectMe = !selfFile(name->name);
+		}
+	    verbose(2, "Reading %s (%d of %d)\n", name->name, totalFilesProcessed+1, fileCount);
+	    lf = pslFileOpen(name->name);
+	    while ((psl = nextLmPsl(lf, lm)) != NULL)
+		{
+		if (psl->qStart == psl->tStart && psl->strand[0] == '+' && 
+		    suppressSelf && sameString(psl->qName, psl->tName))
+		    {
+		    continue;
+		    }
+		++lfileCount;
+		slAddHead(&pslList, psl);
+		if (reflectMe)
+		    {
+		    psl = mirrorLmPsl(psl, lm);
+		    slAddHead(&pslList, psl);
+		    }
+		}
+	    lineFileClose(&lf);
+	    }
+	slSort(&pslList, pslCmpQuery);
+	makeMidName(tempDir, midFileCount, fileName);
+	verbose(1, "Writing %s\n", fileName);
+	f = mustOpen(fileName, "w");
+	if (!nohead)
+	    pslWriteHead(f);
+	for (psl = pslList; psl != NULL; psl = psl->next)
+	    {
+	    pslTabOut(psl, f);
+	    }
+	fclose(f);
+	pslList = NULL;
+	lmCleanup(&lm);
+	verbose(2, "lfileCount %d\n", lfileCount);
+	++midFileCount;
+	}
+    }
+if (!firstOnly)
+    pslSort2(outFile, tempDir);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionHash(&argc, argv);
+
+nohead = optionExists("nohead");
+
+if (argc < 5)
+    usage();
+pslSort(argv[1], argv[2], argv[3], &argv[4], argc-4);
+return 0;
+}
diff --git a/inc/ace.h b/inc/ace.h
new file mode 100644
index 0000000..5b6c0f3
--- /dev/null
+++ b/inc/ace.h
@@ -0,0 +1,79 @@
+/* ace - a format written by phrap, read by consed.
+ *
+ * This file contains routines to read such files.
+ * Note that though the coordinates are one based and
+ * closed on disk, they get converted to our usual half
+ * open zero based in memory.  */
+
+#ifndef ACE_H
+#define ACE_H
+
+#ifndef LINEFILE_H
+#include "linefile.h"
+#endif 
+
+#ifndef DNASEQ_H
+#include "dnaseq.h"
+#endif
+
+struct aceAS
+/* This contains an AS entry. */
+    {
+    int contigs;
+    int reads;
+    };
+
+struct aceCO
+/* This contains a CO entry. */
+    {
+    char *contigName;
+    int bases;
+    int reads;
+    struct dnaSeq *seq;
+    };
+
+struct aceAF
+/* This contains an AF entry. */
+    {
+    struct aceAF *next;
+    char *readName;
+    int startPos;
+    };
+
+struct aceRD
+/* This contains an RD entry. */
+    {
+    struct aceRD *next;
+    char *readName;
+    int bases;
+    struct dnaSeq *seq;
+    };
+
+struct ace
+/* This contains information about one ace element. */
+    {
+    struct ace *next;
+    struct aceAS aceAS;
+    struct aceCO aceCO;
+    struct aceAF *afList;
+    struct aceRD *rdList;
+    };
+
+void aceFree(struct ace **pEl);
+/* Free an ace. */
+
+void aceFreeList(struct ace **pList);
+/* Free a list of dynamically allocated ace's */
+
+struct ace *aceRead(struct lineFile *lf);
+/* Read in from .ace file and return it.
+ * Returns NULL at EOF. */
+
+boolean aceCheck(struct ace *ace, struct lineFile *lf);
+/* Return FALSE if there's a problem with ace. */
+
+void aceWrite(struct ace *ace, FILE *f);
+/* Output ace to ace file. */
+
+#endif /* ACE_H */
+
diff --git a/inc/aliType.h b/inc/aliType.h
new file mode 100644
index 0000000..2a338f2
--- /dev/null
+++ b/inc/aliType.h
@@ -0,0 +1,32 @@
+/* aliType - some definitions for type of alignment. */
+
+#ifndef ALITYPE_H
+#define ALITYPE_H
+
+enum gfType
+/* Types of sequence genoFind deals with. */
+    {
+    gftDna = 0,		/* DNA (genomic) */
+    gftRna = 1,		/* RNA */
+    gftProt = 2,         /* Protein. */
+    gftDnaX = 3,		/* Genomic DNA translated to protein */
+    gftRnaX = 4,         /* RNA translated to protein */
+    };
+
+char *gfTypeName(enum gfType type);
+/* Return string representing type. */
+
+enum gfType gfTypeFromName(char *name);
+/* Return type from string. */
+
+enum ffStringency
+/* How tight of a match is required. */
+    {
+    ffExact = 0,	/* Only an exact match will do. */
+
+    ffCdna = 1,		/* Near exact.  Tolerate long gaps in target (genomic) */
+    ffTight = 2,        /* Near exact.  Not so tolerant of long gaps in target. */
+    ffLoose = 3,        /* Less exact. */
+    };
+
+#endif /* ALITYPE_H */
diff --git a/inc/annoColumn.h b/inc/annoColumn.h
new file mode 100644
index 0000000..79b11c2
--- /dev/null
+++ b/inc/annoColumn.h
@@ -0,0 +1,26 @@
+/* annoColumn -- def. of column plus flag for inclusion in output of annoGratorQuery framework */
+#ifndef ANNOCOLUMN_H
+#define ANNOCOLUMN_H
+
+#include "common.h"
+#include "asParse.h"
+
+struct annoColumn
+/* A column as defined by autoSql, and whether it is currently set to be included in output. */
+    {
+    struct annoColumn *next;
+    struct asColumn *def;
+    boolean included;
+    };
+
+struct annoColumn *annoColumnsFromAsObject(struct asObject *asObj);
+/* Create a list of columns from asObj; by default, all are set to be included in output.
+ * Callers: do not modify any column's def! */
+
+struct annoColumn *annoColumnCloneList(struct annoColumn *list);
+/* Shallow-copy a list of annoColumns.  Callers: do not modify any column's def! */
+
+void annoColumnFreeList(struct annoColumn **pList);
+/* Shallow-free a list of annoColumns. */
+
+#endif//ndef ANNOCOLUMN_H
diff --git a/inc/annoFilter.h b/inc/annoFilter.h
new file mode 100644
index 0000000..42126ca
--- /dev/null
+++ b/inc/annoFilter.h
@@ -0,0 +1,79 @@
+/* annoFilter -- autoSql-driven data filtering for annoGratorQuery framework */
+
+#ifndef ANNOFILTER_H
+#define ANNOFILTER_H
+
+#include "common.h"
+#include "asParse.h"
+
+enum annoFilterOp
+/* Types of filtering actions; most use a value defined elsewhere in annoFilter. */
+// NOTE: would be nice to have set ops, afInSet & afNotInSet
+    {
+    afNoFilter,		// Any column value passes filter
+    afMatch,		// Stringish column value must match given value(s)
+    afNotMatch,		// Stringish column value must not match given value(s)
+    afLT,		// Numeric column value is less than a given value
+    afLTE,		// Numeric column value is less than or equal to a given value
+    afEqual,		// Numeric column value equals a given value
+    afNotEqual,		// Numeric column value does not equal a given value
+    afGTE,		// Numeric column value is greater than or equal to a given value
+    afGT,		// Numeric column value is greater than a given value
+    afInRange,		// Numeric column value falls within fully-closed [given min, given max]
+    };
+
+union aNumber
+    {
+    long long anInt;
+    long double aDouble;
+    };
+
+struct annoFilter
+/* A filter on a row or specific column of data: operand and value(s). This info can tell the
+ * UI what filtering options to offer and what their current values are; and it tells the
+ * annoStreamer what filters to apply. */
+    {
+    struct annoFilter *next;
+    boolean (*filterFunc)(struct annoFilter *self, char **row, int rowSize);
+				// If non-NULL, pass whole row to this function.
+    char *label;		// Option label for UI
+    int columnIx;		// If filterFunc is NULL, index of column in row
+    enum asTypes type;		// Data type (determines which filter operations are applicable)
+    enum annoFilterOp op;	// Action to be performed
+    void *values;		// Depending on op: name(s) to match, thresholds to compare, etc.
+    boolean isExclude;		// True if we are excluding items that pass, false if including.
+    boolean rightJoin;		// A la SQL: if this filter fails, discard primary row.
+    boolean hasMinMax;		// True if we know the allowable range for numeric thresholds
+				// so e.g. UI can enforce limits
+    union aNumber min;		// Lowest valid threshold value
+    union aNumber max;		// Highest valid threshold value
+    };
+
+struct annoFilter *annoFiltersFromAsObject(struct asObject *asObj);
+/* Translate a table's autoSql representation into a list of annoFilters that make
+ * sense for the table's set of fields. */
+
+boolean annoFilterRowFails(struct annoFilter *filterList, char **row, int rowSize,
+			   boolean *retRightJoin);
+/* Apply filters to row, using autoSql column definitions to interpret
+ * each word of row.  Return TRUE if any filter fails (or passes, if isExclude).
+ * Set retRightJoin to TRUE if a rightJoin filter has failed. */
+
+boolean annoFilterWigValueFails(struct annoFilter *filterList, double value,
+				boolean *retRightJoin);
+/* Apply filters to value.  Return TRUE if any filter fails (or passes, if isExclude).
+ * Set retRightJoin to TRUE if a rightJoin filter has failed. */
+
+struct annoFilter *annoFilterCloneList(struct annoFilter *list);
+/* Copy a list of annoFilters. */
+
+void annoFilterFreeList(struct annoFilter **pList);
+/* Free a list of annoFilters. */
+
+enum annoFilterOp afOpFromString(char *string);
+/* Translate string (e.g. "afNotEqual") into enum value (e.g. afNotEqual). */
+
+char *stringFromAfOp(enum annoFilterOp op);
+/* Translate op into a string.  Do not free result. */
+
+#endif//ndef ANNOFILTER_H
diff --git a/inc/annoFormatTab.h b/inc/annoFormatTab.h
new file mode 100644
index 0000000..2cab5d4
--- /dev/null
+++ b/inc/annoFormatTab.h
@@ -0,0 +1,11 @@
+/* annoFormatTab -- collect fields from all inputs and print them out, tab-separated. */
+
+#ifndef ANNOFORMATTAB_H
+#define ANNOFORMATTAB_H
+
+#include "annoFormatter.h"
+
+struct annoFormatter *annoFormatTabNew(char *fileName);
+/* Return a formatter that will write its tab-separated output to fileName. */
+
+#endif//ndef ANNOFORMATTAB_H
diff --git a/inc/annoFormatter.h b/inc/annoFormatter.h
new file mode 100644
index 0000000..d228382
--- /dev/null
+++ b/inc/annoFormatter.h
@@ -0,0 +1,54 @@
+/* annoFormatter -- aggregates, formats and writes output from multiple sources */
+
+#ifndef ANNOFORMATTER_H
+#define ANNOFORMATTER_H
+
+#include "annoOption.h"
+#include "annoRow.h"
+#include "annoStreamer.h"
+
+// The real work of aggregating and formatting data is left to
+// subclass implementations.  The purpose of this module is to provide
+// an interface for communication with other components of the
+// annoGratorQuery framework, and simple methods shared by all
+// subclasses.
+
+struct annoFormatter
+/* Generic interface to aggregate data fields from multiple sources and write
+ * output. */
+    {
+    struct annoFormatter *next;
+
+    // Public methods
+    struct annoOption *(*getOptions)(struct annoFormatter *self);
+    void (*setOptions)(struct annoFormatter *self, struct annoOption *options);
+    /* Get and set output options */
+
+    void (*initialize)(struct annoFormatter *self, struct annoGratorQuery *query);
+    /* Initialize output (header, etc) and set query pointer */
+
+    void (*formatOne)(struct annoFormatter *self, struct annoRow *primaryRow,
+		      struct slRef *gratorRowList);
+    /* Aggregate all sources' data for a single primarySource item into output. */
+
+    void (*close)(struct annoFormatter **pSelf);
+    /* End of input; finish output, close connection/handle and free self. */
+
+    // Private members -- callers are on the honor system to access these using only methods above.
+    struct annoOption *options;
+    struct annoGratorQuery *query;
+    };
+
+// ---------------------- annoFormatter default methods -----------------------
+
+struct annoOption *annoFormatterGetOptions(struct annoFormatter *self);
+/* Return supported options and current settings.  Callers can modify and free when done. */
+
+void annoFormatterSetOptions(struct annoFormatter *self, struct annoOption *newOptions);
+/* Free old options and use clone of newOptions. */
+
+void annoFormatterFree(struct annoFormatter **pSelf);
+/* Free self. This should be called at the end of subclass close methods, after
+ * subclass-specific connections are closed and resources are freed. */
+
+#endif//ndef ANNOFORMATTER_H
diff --git a/inc/annoGrator.h b/inc/annoGrator.h
new file mode 100644
index 0000000..5bc625a
--- /dev/null
+++ b/inc/annoGrator.h
@@ -0,0 +1,55 @@
+/* annoGrator -- annoStreamer that integrates genomic annotations from two annoStreamers */
+
+// Subclasses of annoGrator can add new columns of output such as predicted function given
+// a variant and a gene; the base class simply intersects by position, returning
+// all rows from its internal data source that overlap the position of primaryRow.
+// The interface to an annoGrator is almost the same as the interface to an annoStreamer,
+// *except* you call integrate() instead of nextRow().
+
+#ifndef ANNOGRATOR_H
+#define ANNOGRATOR_H
+
+#include "annoStreamer.h"
+
+struct annoGrator
+/* annoStreamer that can integrate an internal annoStreamer's data
+ * with data from a primary source. */
+    {
+    struct annoStreamer streamer;	// external annoStreamer interface
+
+    // Public method that makes this a 'grator:
+    struct annoRow *(*integrate)(struct annoGrator *self, struct annoRow *primaryRow,
+				 boolean *retRJFilterFailed);
+    /* Integrate internal source's data with single row of primary source's data */
+
+    // Private members -- callers are on the honor system to access these using only methods above.
+    struct annoStreamer *mySource;	// internal source
+    struct annoRow *qHead;		// head of FIFO queue of rows from internal source
+    struct annoRow *qTail;		// head of FIFO queue of rows from internal source
+    char *prevPChrom;			// for detection of unsorted input from primary
+    uint prevPStart;			// for detection of unsorted input from primary
+    boolean eof;			// stop asking internal source for rows when it's done
+    boolean haveRJIncludeFilter;	// TRUE if some filter has !isExclude && rightJoin;
+					// if TRUE and there are no overlapping rows, then RJ fail
+    };
+
+#endif//ndef ANNOGRATOR_H
+
+// ---------------------- annoGrator default methods -----------------------
+
+struct annoRow *annoGratorIntegrate(struct annoGrator *self, struct annoRow *primaryRow,
+				    boolean *retRJFilterFailed);
+/* Given a single row from the primary source, get all overlapping rows from internal
+ * source, and produce joined output rows.  If retRJFilterFailed is non-NULL and any
+ * overlapping row has a rightJoin filter failure (see annoFilter.h),
+ * set retRJFilterFailed and stop. */
+
+struct annoGrator *annoGratorNew(struct annoStreamer *mySource);
+/* Make a new integrator of columns from mySource with (positions of) rows passed to integrate().
+ * mySource becomes property of the new annoGrator. */
+
+void annoGratorSetQuery(struct annoStreamer *vSelf, struct annoGratorQuery *query);
+/* Set query (to be called only by annoGratorQuery which is created after streamers). */
+
+void annoGratorClose(struct annoStreamer **pSelf);
+/* Free self (including mySource). */
diff --git a/inc/annoGratorQuery.h b/inc/annoGratorQuery.h
new file mode 100644
index 0000000..0a5cfc2
--- /dev/null
+++ b/inc/annoGratorQuery.h
@@ -0,0 +1,44 @@
+/* annoGratorQuery -- framework for integrating genomic annotations from many sources */
+
+#ifndef ANNOGRATORQUERY_H
+#define ANNOGRATORQUERY_H
+
+#include "annoFormatter.h"
+#include "annoGrator.h"
+#include "hash.h"
+#include "twoBit.h"
+
+struct annoGratorQuery
+/* Representation of a complex query: multiple sources, each with its own filters,
+ * output data and means of integration, aggregated and output by a formatter. */
+    {
+    // Private members -- callers are on the honor system to leave these alone. Use functions below.
+    char *assemblyName;			// Usually a UCSC db name like "hg19".
+    struct hash *chromSizes;		// Assembly seq sizes, must be valid for all inputs
+    struct twoBitFile *tbf;		// Assembly sequence, must be valid for all inputs
+    struct annoStreamer *primarySource;	// Annotations to be integrated with other annos.
+    struct annoGrator *integrators;	// Annotations & methods for integrating w/primary
+    struct annoFormatter *formatters;	// Writers of output collected from primary & intg's
+    boolean csAllocdHere;		// internal use only.
+    };
+
+struct annoGratorQuery *annoGratorQueryNew(char *assemblyName, struct hash *chromSizes,
+					   struct twoBitFile *tbf,
+					   struct annoStreamer *primarySource,
+					   struct annoGrator *integrators,
+					   struct annoFormatter *formatters);
+/* Create an annoGratorQuery from all of its components, and introduce components to each other.
+ * Either chromSizes or tbf may be NULL.  integrators may be NULL.
+ * All other inputs must be non-NULL. */
+
+void annoGratorQuerySetRegion(struct annoGratorQuery *query, char *chrom, uint rStart, uint rEnd);
+/* Set genomic region for query; if chrom is NULL, position is whole genome. */
+
+void annoGratorQueryExecute(struct annoGratorQuery *query);
+/* For each annoRow from query->primarySource, invoke integrators and
+ * pass their annoRows to formatters. */
+
+void annoGratorQueryFree(struct annoGratorQuery **pQuery);
+/* Close and free all inputs and outputs; free self. */
+
+#endif//ndef ANNOGRATORQUERY_H
diff --git a/inc/annoOption.h b/inc/annoOption.h
new file mode 100644
index 0000000..0fc7ca9
--- /dev/null
+++ b/inc/annoOption.h
@@ -0,0 +1,22 @@
+/* annoOption -- optionSpec-style param plus its value */
+
+#ifndef ANNOOPTION_H
+#define ANNOOPTION_H
+
+#include "options.h"
+
+struct annoOption
+/* A named and typed option and its value. */
+    {
+    struct annoOption *next;
+    struct optionSpec spec;
+    void *value;
+    };
+
+struct annoOption *annoOptionCloneList(struct annoOption *list);
+/* Return a newly allocated copy of list. */
+
+void annoOptionFreeList(struct annoOption **pList);
+/* Free the same things that we clone above. */
+
+#endif//ndef ANNOOPTION_H
diff --git a/inc/annoRow.h b/inc/annoRow.h
new file mode 100644
index 0000000..01b57cd
--- /dev/null
+++ b/inc/annoRow.h
@@ -0,0 +1,47 @@
+/* annoRow -- basic data interchange unit of annoGratorQuery framework. */
+
+#ifndef ANNOROW_H
+#define ANNOROW_H
+
+#include "common.h"
+
+enum annoRowType { arUnknown, arWords, arWig, arVcf };
+
+// stub in order to avoid problems with circular .h references:
+struct annoStreamer;
+
+struct annoRow
+/* Representation of a row from a database table or file.  The chrom, start and end
+ * facilitate intersection by position.  If type is arWords, then data is an array
+ * of strings corresponding to columns in the autoSql definition provided by the
+ * source of the annoRow.  If type is arWig, then data is an array of floats.
+ * rightJoinFail is true if this row failed a filter marked as rightJoin, meaning it
+ * can knock out the primary row (see annoFilter.h). */
+    {
+    struct annoRow *next;
+    char *chrom;
+    uint start;
+    uint end;
+    void *data;
+    boolean rightJoinFail;
+    };
+
+struct annoRow *annoRowFromStringArray(char *chrom, uint start, uint end, boolean rightJoinFail,
+				       char **wordsIn, int numCols);
+/* Allocate & return an annoRow with data cloned from wordsIn. */
+
+struct annoRow *annoRowWigNew(char *chrom, uint start, uint end, boolean rightJoinFail,
+			      float *values);
+/* Allocate & return an annoRowWig, with clone of values; length of values is (end-start). */
+
+struct annoRow *annoRowClone(struct annoRow *rowIn, struct annoStreamer *source);
+/* Allocate & return a single annoRow cloned from rowIn.
+ * numCols is used only if rowIn->type is arWords. */
+
+void annoRowFree(struct annoRow **pRow, struct annoStreamer *source);
+/* Free a single annoRow. */
+
+void annoRowFreeList(struct annoRow **pList, struct annoStreamer *source);
+/* Free a list of annoRows. */
+
+#endif//ndef ANNOROW_H
diff --git a/inc/annoStreamVcf.h b/inc/annoStreamVcf.h
new file mode 100644
index 0000000..a1c0de2
--- /dev/null
+++ b/inc/annoStreamVcf.h
@@ -0,0 +1,12 @@
+/* annoStreamVcf -- subclass of annoStreamer for VCF files */
+
+#ifndef ANNOSTREAMVCF_H
+#define ANNOSTREAMVCF_H
+
+#include "annoStreamer.h"
+
+struct annoStreamer *annoStreamVcfNew(char *fileOrUrl, boolean isTabix, int maxRecords);
+/* Create an annoStreamer (subclass) object from a VCF file, which may
+ * or may not have been compressed and indexed by tabix. */
+
+#endif//ndef ANNOSTREAMVCF_H
diff --git a/inc/annoStreamer.h b/inc/annoStreamer.h
new file mode 100644
index 0000000..6024482
--- /dev/null
+++ b/inc/annoStreamer.h
@@ -0,0 +1,103 @@
+/* annoStreamer -- returns items sorted by genomic position to successive nextRow calls */
+
+#ifndef ANNOSTREAMER_H
+#define ANNOSTREAMER_H
+
+#include "annoColumn.h"
+#include "annoFilter.h"
+#include "annoRow.h"
+
+// The real work of fetching and filtering data is left to subclass
+// implementations.  The purpose of this module is to provide an
+// interface for communication with other components of the
+// annoGratorQuery framework, and simple methods shared by all
+// subclasses.
+
+// stub in order to avoid problems with circular .h references:
+struct annoGratorQuery;
+
+struct annoStreamer
+/* Generic interface to configure a data source's filters and output data, and then
+ * retrieve data, which must be sorted by genomic position.  Subclasses of this
+ * will do all the actual work. */
+    {
+    struct annoStreamer *next;
+
+    // Public methods
+    struct asObject *(*getAutoSqlObject)(struct annoStreamer *self);
+    /* Get autoSql representation (do not modify or free!) */
+
+    void (*setRegion)(struct annoStreamer *self, char *chrom, uint rStart, uint rEnd);
+    /* Set genomic region for query (should be called only by annoGratorQuerySetRegion) */
+
+    char *(*getHeader)(struct annoStreamer *self);
+    /* Get the file header as a string (possibly NULL, possibly multi-line). */
+
+    struct annoFilter *(*getFilters)(struct annoStreamer *self);
+    void (*setFilters)(struct annoStreamer *self, struct annoFilter *newFilters);
+    /* Get and set filters */
+
+    struct annoColumn *(*getColumns)(struct annoStreamer *self);
+    void (*setColumns)(struct annoStreamer *self, struct annoColumn *newColumns);
+    /* Get and set output fields */
+
+    struct annoRow *(*nextRow)(struct annoStreamer *self);
+    /* Get next item's output fields from this source */
+
+    void (*close)(struct annoStreamer **pSelf);
+    /* Close connection to source and free self. */
+
+    void (*setQuery)(struct annoStreamer *self, struct annoGratorQuery *query);
+    /* For use by annoGratorQuery only: hook up query object after creation */
+
+    // Public members -- callers are on the honor system to access these read-only.
+    struct annoGratorQuery *query;	// The query object that owns this streamer.
+    enum annoRowType rowType;
+    int numCols;
+    struct annoFilter *filters;
+    struct annoColumn *columns;
+
+    // Private members -- callers are on the honor system to access these using only methods above.
+    boolean positionIsGenome;
+    char *chrom;
+    uint regionStart;
+    uint regionEnd;
+    struct asObject *asObj;
+    };
+
+// ---------------------- annoStreamer default methods -----------------------
+
+struct asObject *annoStreamerGetAutoSqlObject(struct annoStreamer *self);
+/* Return parsed autoSql definition of this streamer's data type. */
+
+void annoStreamerSetRegion(struct annoStreamer *self, char *chrom, uint rStart, uint rEnd);
+/* Set genomic region for query; if chrom is NULL, position is genome.
+ * Many subclasses should make their own setRegion method that calls this and
+ * configures their data connection to change to the new position. */
+
+struct annoFilter *annoStreamerGetFilters(struct annoStreamer *self);
+/* Return supported filters with current settings.  Callers can modify and free when done. */
+
+void annoStreamerSetFilters(struct annoStreamer *self, struct annoFilter *newFilters);
+/* Free old filters and use clone of newFilters. */
+
+struct annoColumn *annoStreamerGetColumns(struct annoStreamer *self);
+/* Return supported columns with current settings.  Callers can modify and free when done. */
+
+void annoStreamerSetColumns(struct annoStreamer *self, struct annoColumn *columns);
+/* Free old columns and use clone of newColumns. */
+
+void annoStreamerInit(struct annoStreamer *self, struct asObject *asObj);
+/* Initialize a newly allocated annoStreamer with default annoStreamer methods and
+ * default filters and columns based on asObj.
+ * In general, subclasses' constructors will call this first; override nextRow, close,
+ * and probably setRegion and setQuery; and then initialize their private data. */
+
+void annoStreamerFree(struct annoStreamer **pSelf);
+/* Free self. This should be called at the end of subclass close methods, after
+ * subclass-specific connections are closed and resources are freed. */
+
+void annoStreamerSetQuery(struct annoStreamer *self, struct annoGratorQuery *query);
+/* Set query (to be called only by annoGratorQuery which is created after streamers). */
+
+#endif//ndef ANNOSTREAMER_H
diff --git a/inc/apacheLog.h b/inc/apacheLog.h
new file mode 100644
index 0000000..df53afd
--- /dev/null
+++ b/inc/apacheLog.h
@@ -0,0 +1,43 @@
+/* apacheLog - stuff to parse out apache web server logs, currently
+ * just the access log. */
+
+#ifndef APACHELOG_H
+#define APACHELOG_H
+
+struct apacheAccessLog
+/* Parsed out apache access log line */
+    {
+    struct apacheAccessLog *next;
+    char *buf;		/* All memory for apacheAccessLog fields is allocated at once here. */
+    char *ip;		/* IP Address: dotted quad of numbers, or xxx.com. */
+    char *dash1;	/* Unknown, usually a dash */
+    char *dash2;	/* Unknown, usually a dash */
+    char *timeStamp;	/* Time stamp like 23/Nov/2003:04:21:08 */
+    char *timeZone;	/* Extra number after timeStamp, usually -0800 */
+    char *method;	/* GET/POST etc. */
+    char *url;		/* Requested URL */
+    char *httpVersion;  /* Something like HTTP/1.1 */
+    int status;		/* Status code - 200 is good! */
+    char *num1;		/* Some number, I'm not sure what it is. */
+    char *referrer;	/* Referring URL, may be NULL. */
+    char *program;	/* Requesting program,  often Mozilla 4.0 */
+    time_t tick;	/* Unix tick (seconds since 1970) - derived from timeStamp. */
+    int runTime;	/* Overall time (optional) in milliseconds */
+    };
+
+struct apacheAccessLog *apacheAccessLogParse(char *line, 
+	char *fileName, int lineIx);
+/* Return a apacheAccessLog from line.  Return NULL if there's a parsing 
+ * problem, but don't abort. */
+
+void apacheAccessLogFree(struct apacheAccessLog **pLl);
+/* Free up apacheAccessLog. */
+
+time_t apacheAccessLogTimeToTick(char *timeStamp);
+/* Convert something like 27/Aug/2009:09:25:32 to Unix timestamp (seconds since 1970).
+ * On error returns zero. */
+
+int apacheAccessLogCmpTick(const void *va, const void *vb);
+/* Compare items to sort by tick (which tracks timestamp) */
+
+#endif /* APACHELOG_H */
diff --git a/inc/asParse.h b/inc/asParse.h
new file mode 100644
index 0000000..68b5c8e
--- /dev/null
+++ b/inc/asParse.h
@@ -0,0 +1,120 @@
+/* asParse - parse out an autoSql .as file. */
+
+#ifndef ASPARSE_H
+#define ASPARSE_H
+
+enum asTypes
+/* Different low level types (not including lists and objects) */
+   {
+   t_double,   /* double precision floating point. */
+   t_float,    /* single precision floating point. */
+   t_char,     /* character or fixed size character array. */
+   t_int,      /* signed 32 bit integer */
+   t_uint,     /* unsigned 32 bit integer */
+   t_short,    /* signed 16 bit integer */
+   t_ushort,   /* unsigned 16 bit integer */
+   t_byte,     /* signed 8 bit integer */
+   t_ubyte,    /* unsigned 8 bit integer */
+   t_off,      /* 64 bit integer. */
+   t_string,   /* varchar/char * (variable size string up to 255 chars)  */
+   t_lstring,     /* variable sized large string. */
+   t_object,   /* composite object - object/table - forms lists. */
+   t_simple,   /* simple composite object - forms arrays. */
+   t_enum,     /* enumerated symbolic values */
+   t_set,      /* set of symbolic values */
+   };
+
+char *asTypesIntSizeDescription(enum asTypes type);
+/* Return description of integer size.  Do not free. */
+
+int asTypesIntSize(enum asTypes type);
+/* Return size in bytes of any integer type - short, long, unsigned, etc. */
+
+boolean asTypesIsUnsigned(enum asTypes type);
+/* Return TRUE if it's any integer type - short, long, unsigned, etc. */
+
+boolean asTypesIsInt(enum asTypes type);
+/* Return TRUE if it's any integer type - short, long, unsigned, etc. */
+
+boolean asTypesIsFloating(enum asTypes type);
+/* Return TRUE if it's any floating point type - float or double. */
+
+struct asTypeInfo
+    {
+    enum asTypes type;		   /* Numeric ID of low level type. */
+    char *name;                    /* Text ID of low level type. */
+    bool isUnsigned;               /* True if an unsigned int of some type. */
+    bool stringy;                  /* True if a string or blob. */
+    char *sqlName;                 /* SQL type name. */
+    char *cName;                   /* C type name. */
+    char *listyName;               /* What functions that load a list are called. */
+    char *nummyName;               /* What functions that load a number are called. */
+    char *outFormat;		   /* Output format for printf. %d, %u, etc. */
+    char *djangoName;              /* Django type name */
+    };
+
+struct asColumn
+/* Info on one column/field */
+    {
+    struct asColumn *next;           /* Next column. */
+    char *name;                    /* Column name. */
+    char *comment;		   /* Comment string on column. */
+    struct asTypeInfo *lowType;   /* Root type info. */
+    char *obName;                  /* Name of object or table. */
+    struct asObject *obType;       /* Name of composite object. */
+    int fixedSize;		   /* 0 if not fixed size, otherwise size of list. */
+    char *linkedSizeName;          /* Points to variable that holds size of list. */
+    struct asColumn *linkedSize;     /* Column for linked size. */
+    bool isSizeLink;               /* Flag to tell if have read link. */
+    bool isList;                   /* TRUE if a list. */
+    bool isArray;                  /* TRUE if an array. */
+    struct slName *values;         /* values for symbolic types */
+    };
+
+struct asObject
+/* Info on whole asObject. */
+    {
+    struct asObject *next;
+    char *name;			/* Name of object. */
+    char *comment;		/* Comment describing object. */
+    struct asColumn *columnList;  /* List of columns. */
+    bool isTable;	        /* True if a table. */
+    bool isSimple;	        /* True if a simple object. */
+    };
+
+struct dyString *asColumnToSqlType(struct asColumn *col);
+/* Convert column to a sql type spec in returned dyString */
+
+char *asTypeNameFromSqlType(char *sqlType);
+/* Return the autoSql type name (not enum) for the given SQL type, or NULL.
+ * Don't attempt to free result. */
+
+struct asObject *asParseFile(char *fileName);
+/* Parse autoSql .as file. */
+
+struct asObject *asParseText(char *text);
+/* Parse autoSql from text (as opposed to file). */
+
+void asObjectFree(struct asObject **as);
+/* free a single asObject */
+
+void asObjectFreeList(struct asObject **as);
+/* free a list of asObject */
+
+void asColumnFree(struct asColumn **as);
+/* free a single asColumn */
+
+void asColumnFreeList(struct asColumn **as);
+/* free a list of asColumn */
+
+struct asColumn *asColumnFind(struct asObject *as, char *name);
+/* Return column of given name from object, or NULL if not found. */
+
+boolean asCompareObjs(char *name1, struct asObject *as1, char *name2, struct asObject *as2, int numColumnsToCheck,
+ int *retNumColumnsSame, boolean abortOnDifference);
+/* Compare as-objects as1 and as2 making sure several important fields show they are the same name and type.
+ * If difference found, print it to stderr.  If abortOnDifference, errAbort.
+ * Othewise, return TRUE if the objects columns match through the first numColumnsToCheck fields. 
+ * If retNumColumnsSame is not NULL, then it will be set to the number of contiguous matching columns. */
+
+#endif /* ASPARSE_H */
diff --git a/inc/axt.h b/inc/axt.h
new file mode 100644
index 0000000..5ab86d1
--- /dev/null
+++ b/inc/axt.h
@@ -0,0 +1,272 @@
+/* AXT - A simple alignment format with four lines per
+ * alignment.  The first specifies the names of the
+ * two sequences that align and the position of the
+ * alignment, as well as the strand.  The next two
+ * lines contain the alignment itself including dashes
+ * for inserts.  The alignment is separated from the
+ * next alignment with a blank line. 
+ *
+ * This file contains routines to read such alignments.
+ * Note that though the coordinates are one based and
+ * closed on disk, they get converted to our usual half
+ * open zero based in memory. 
+ *
+ * This also contains code for simple DNA alignment scoring
+ * schemes. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef AXT_H
+#define AXT_H
+
+#ifndef LINEFILE_H
+#include "linefile.h"
+#endif 
+
+#ifndef DNASEQ_H
+#include "dnaseq.h"
+#endif
+
+#ifndef CHAIN_H
+#include "chain.h"
+#endif
+
+struct axt
+/* This contains information about one xeno alignment. */
+    {
+    struct axt *next;
+    char *qName;		/* Name of query sequence. */
+    int qStart, qEnd;		/* Half open zero=based coordinates. */
+    char qStrand;		/* Is this forward or reverse strand + or - */
+    char *tName;		/* Name of target. */
+    int tStart, tEnd;		/* Target coordinates. */
+    char tStrand;               /* Target strand - currently always +. */
+    int score;	                /* Score.  Zero for unknown.  Units arbitrary. */
+    int symCount;               /* Size of alignments. */
+    char *qSym, *tSym;          /* Alignments. */
+    int frame;			/* If non-zero then translation frame. */
+    };
+
+void axtFree(struct axt **pEl);
+/* Free an axt. */
+
+void axtFreeList(struct axt **pList);
+/* Free a list of dynamically allocated axt's */
+
+struct axt *axtRead(struct lineFile *lf);
+/* Read in next record from .axt file and return it.
+ * Returns NULL at EOF. */
+
+struct axt *axtReadWithPos(struct lineFile *lf, off_t *retOffset);
+/* Read next axt, and if retOffset is not-NULL, fill it with
+ * offset of start of axt. */
+
+boolean axtCheck(struct axt *axt, struct lineFile *lf);
+/* Return FALSE if there's a problem with axt. */
+
+void axtWrite(struct axt *axt, FILE *f);
+/* Output axt to axt file. */
+
+int axtCmpQuery(const void *va, const void *vb);
+/* Compare to sort based on query position. */
+
+int axtCmpTarget(const void *va, const void *vb);
+/* Compare to sort based on target position. */
+
+int axtCmpScore(const void *va, const void *vb);
+/* Compare to sort based on score. */
+
+int axtCmpTargetScoreDesc(const void *va, const void *vb);
+/* Compare to sort based on target name and score descending. */
+
+struct axtScoreScheme
+/* A scoring scheme or DNA alignment. */
+    {
+    struct scoreMatrix *next;
+    int matrix[256][256];   /* Look up with letters. */
+    int gapOpen;	/* Gap open cost. */
+    int gapExtend;	/* Gap extension. */
+    char *extra;        /* extra parameters */
+    };
+
+void axtScoreSchemeFree(struct axtScoreScheme **pObj);
+/* Free up score scheme. */
+
+struct axtScoreScheme *axtScoreSchemeDefault();
+/* Return default scoring scheme (after blastz).  Do NOT axtScoreSchemeFree
+ * this. */
+
+struct axtScoreScheme *axtScoreSchemeSimpleDna(int match, int misMatch, int gapOpen, int gapExtend);
+/* Return a relatively simple scoring scheme for DNA. */
+
+struct axtScoreScheme *axtScoreSchemeRnaDefault();
+/* Return default scoring scheme for RNA/DNA alignments
+ * within the same species.  Do NOT axtScoreSchemeFree
+ * this. */
+
+struct axtScoreScheme *axtScoreSchemeFromBlastzMatrix(char *text, int gapOpen, int gapExtend);
+/* return scoring schema from a string in the following format */
+/* 91,-90,-25,-100,-90,100,-100,-25,-25,-100,100,-90,-100,-25,-90,91 */
+
+struct axtScoreScheme *axtScoreSchemeRnaFill();
+/* Return scoreing scheme a little more relaxed than 
+ * RNA/DNA defaults for filling in gaps. */
+
+struct axtScoreScheme *axtScoreSchemeProteinDefault();
+/* Returns default protein scoring scheme.  This is
+ * scaled to be compatible with the blastz one.  Don't
+ * axtScoreSchemeFree this. */
+
+struct axtScoreScheme *axtScoreSchemeProteinRead(char *fileName);
+/* read in blosum-like matrix */
+
+struct axtScoreScheme *axtScoreSchemeRead(char *fileName);
+/* Read in scoring scheme from file. Looks like
+    A    C    G    T
+    91 -114  -31 -123
+    -114  100 -125  -31
+    -31 -125  100 -114
+    -123  -31 -114   91
+    O = 400, E = 30
+ * axtScoreSchemeFree this when done. */
+
+struct axtScoreScheme *axtScoreSchemeReadLf(struct lineFile *lf );
+/* Read in scoring scheme from file. Looks like
+    A    C    G    T
+    91 -114  -31 -123
+    -114  100 -125  -31
+    -31 -125  100 -114
+    -123  -31 -114   91
+    O = 400, E = 30
+ * axtScoreSchemeFree this when done. */
+
+void axtScoreSchemeDnaWrite(struct axtScoreScheme *ss, FILE *f, char *name);
+/* output the score dna based score matrix in meta Data format to File f,
+name should be set to the name of the program that is using the matrix */
+
+int axtScoreSym(struct axtScoreScheme *ss, int symCount, char *qSym, char *tSym);
+/* Return score without setting up an axt structure. */
+
+int axtScore(struct axt *axt, struct axtScoreScheme *ss);
+/* Return calculated score of axt. */
+
+int axtScoreFilterRepeats(struct axt *axt, struct axtScoreScheme *ss);
+/* Return calculated score of axt. do not score gaps if they are repeat masked*/
+
+int axtScoreUngapped(struct axtScoreScheme *ss, char *q, char *t, int size);
+/* Score ungapped alignment. */
+
+int axtScoreDnaDefault(struct axt *axt);
+/* Score DNA-based axt using default scheme. */
+
+int axtScoreProteinDefault(struct axt *axt);
+/* Score protein-based axt using default scheme. */
+
+boolean axtGetSubsetOnT(struct axt *axt, struct axt *axtOut,
+			int newStart, int newEnd, struct axtScoreScheme *ss,
+			boolean includeEdgeGaps);
+/* Return FALSE if axt is not in the new range.  Otherwise, set axtOut to
+ * a subset that goes from newStart to newEnd in target coordinates. 
+ * If includeEdgeGaps, don't trim target gaps before or after the range. */
+
+void axtSubsetOnT(struct axt *axt, int newStart, int newEnd, 
+	struct axtScoreScheme *ss, FILE *f);
+/* Write out subset of axt that goes from newStart to newEnd
+ * in target coordinates. */
+
+int axtTransPosToQ(struct axt *axt, int tPos);
+/* Convert from t to q coordinates */
+
+void axtSwap(struct axt *axt, int tSize, int qSize);
+/* Flip target and query on one axt. */
+
+struct axtBundle
+/* A bunch of axt's on the same query/target sequence. */
+    {
+    struct axtBundle *next;
+    struct axt *axtList;	/* List of alignments. */
+    int tSize;			/* Size of target. */
+    int qSize;			/* Size of query. */
+    };
+
+void axtBundleFree(struct axtBundle **pObj);
+/* Free a axtBundle. */
+
+void axtBundleFreeList(struct axtBundle **pList);
+/* Free a list of gfAxtBundles. */
+
+void axtBlastOut(struct axtBundle *abList, 
+	int queryIx, boolean isProt, FILE *f, 
+	char *databaseName, int databaseSeqCount, double databaseLetterCount, 
+	char *blastType, char *ourId, double minIdentity);
+/* Output a bundle of axt's on the same query sequence in blast format.
+ * The parameters in detail are:
+ *   ab - the list of bundles of axt's. 
+ *   f  - output file handle
+ *   databaseSeqCount - number of sequences in database
+ *   databaseLetterCount - number of bases or aa's in database
+ *   blastType - blast/wublast/blast8/blast9/xml
+ *   ourId - optional (may be NULL) thing to put in header
+ */
+
+struct axt *axtAffine(bioSeq *query, bioSeq *target, struct axtScoreScheme *ss);
+/* Return alignment if any of query and target using scoring scheme.  This does
+ * dynamic program affine-gap based alignment.  It's not suitable for very large
+ * sequences. */
+
+boolean axtAffineSmallEnough(double querySize, double targetSize);
+/* Return TRUE if it is reasonable to align sequences of given sizes
+ * with axtAffine. */
+
+
+struct axt *axtAffine2Level(bioSeq *query, bioSeq *target, struct axtScoreScheme *ss);
+/* 
+
+   Return alignment if any of query and target using scoring scheme. 
+   
+   2Level uses an economical amount of ram and should work for large target sequences.
+   
+   If Q is query size and T is target size and M is memory size, then
+   Total memory used M = 30*Q*sqrt(T).  When the target is much larger than the query
+   this method saves ram, and average runtime is only 50% greater, or 1.5 QT.  
+   If Q=5000 and T=245,522,847 for hg17 chr1, then M = 2.2 GB ram.  
+   axtAffine would need M=3QT = 3.4 TB.
+   Of course massive alignments will be painfully slow anyway.
+
+   Works for protein as well as DNA given the correct scoreScheme.
+  
+   NOTES:
+   Double-gap cost is equal to gap-extend cost, but gap-open would also work.
+   On very large target, score integer may overflow.
+   Input sequences not checked for invalid chars.
+   Input not checked but query should be shorter than target.
+   
+*/
+
+void axtAddBlocksToBoxInList(struct cBlock **pList, struct axt *axt);
+/* Add blocks (gapless subalignments) from (non-NULL!) axt to block list. 
+ * Note: list will be in reverse order of axt blocks. */
+
+void axtPrintTraditional(struct axt *axt, int maxLine, struct axtScoreScheme *ss, 
+	FILE *f);
+/* Print out an alignment with line-breaks. */
+
+void axtPrintTraditionalExtra(struct axt *axt, int maxLine,
+			      struct axtScoreScheme *ss, FILE *f,
+			      boolean reverseTPos, boolean reverseQPos);
+/* Print out an alignment with line-breaks.  If reverseTPos is true, then
+ * the sequence has been reverse complemented, so show the coords starting
+ * at tEnd and decrementing down to tStart; likewise for reverseQPos. */
+
+double axtIdWithGaps(struct axt *axt);
+/* Return ratio of matching bases to total symbols in alignment. */
+
+double axtCoverage(struct axt *axt, int qSize, int tSize);
+/* Return % of q and t covered. */
+
+void axtOutPretty(struct axt *axt, int lineSize, FILE *f);
+/* Output axt in pretty format. */
+
+#endif /* AXT_H */
+
diff --git a/inc/bPlusTree.h b/inc/bPlusTree.h
new file mode 100644
index 0000000..cb59fb1
--- /dev/null
+++ b/inc/bPlusTree.h
@@ -0,0 +1,114 @@
+/* bptFile - B+ Trees.  These are a method of indexing data similar to binary trees, but 
+ * with many children rather than just two at each node. They work well when stored on disk,
+ * since typically only two or three disk accesses are needed to locate any particular
+ * piece of data.  This implementation is *just* for disk based storage.  For memory
+ * use the rbTree instead. Currently the implementation is just useful for data warehouse
+ * type applications.  That is it implements a function to create a b+ tree from bulk data
+ * (bptFileCreate) and a function to lookup a value given a key (bptFileFind) but not functions
+ * to add or delete individual items.
+ *
+ *
+ * The layout of the file on disk is:
+ *    header
+ *    root node
+ *    (other nodes)
+ * In general when the tree is first built the higher level nodes are stored before the
+ * lower level nodes.  It is possible if a b+ tree is dynamically updated for this to
+ * no longer be strictly true, but actually currently the b+ tree code here doesn't implement
+ * dynamic updates - it just creates a b+ tree from a sorted list.
+ *
+ * Each node can be one of two types - index or leaf.  The index nodes contain pointers
+ * to child nodes.  The leaf nodes contain the actual data. 
+ *
+ * The layout of the file header is:
+ *       <magic number>  4 bytes - The value bptSig (0x78CA8C91)
+ *       <block size>    4 bytes - Number of children per block (not byte size of block)
+ *       <key size>      4 bytes - Number of significant bytes in key
+ *       <val size>      4 bytes - Number of bytes in value
+ *       <item count>    8 bytes - Number of items in index
+ *       <reserved2>     4 bytes - Always 0 for now
+ *       <reserved3>     4 bytes - Always 0 for now
+ * The magic number may be byte-swapped, in which case all numbers in the file
+ * need to be byte-swapped. 
+ *
+ * The nodes start with a header:
+ *       <is leaf>       1 byte  - 1 for leaf nodes, 0 for index nodes.
+ *       <reserved>      1 byte  - Always 0 for now.
+ *       <count>         2 bytes - The number of children/items in node
+ * This is followed by count items.  For the index nodes the items are
+ *       <key>           key size bytes - always written most significant byte first
+ *       <offset>        8 bytes - Offset of child node in index file.
+ * For leaf nodes the items are
+ *       <key>           key size bytes - always written most significant byte first
+ *       <val>           val sized bytes - the value associated with the key.
+ * Note in general the leaf nodes may not be the same size as the index nodes, though in
+ * the important case where the values are file offsets they will be.
+ */
+
+#ifndef BPLUSTREE_H
+#define BPLUSTREE_H
+
+struct bptFile
+/* B+ tree index file handle. */
+    {
+    struct bptFile *next;	/* Next in list of index files if any. */
+    char *fileName;		/* Name of file - for error reporting. */
+    struct udcFile *udc;			/* Open file pointer. */
+    bits32 blockSize;		/* Size of block. */
+    bits32 keySize;		/* Size of keys. */
+    bits32 valSize;		/* Size of values. */
+    bits64 itemCount;		/* Number of items indexed. */
+    boolean isSwapped;		/* If TRUE need to byte swap everything. */
+    bits64 rootOffset;		/* Offset of root block. */
+    };
+
+struct bptFile *bptFileOpen(char *fileName);
+/* Open up index file - reading header and verifying things. */
+
+void bptFileClose(struct bptFile **pBpt);
+/* Close down and deallocate index file. */
+
+struct bptFile *bptFileAttach(char *fileName, struct udcFile *udc);
+/* Open up index file on previously open file, with header at current file position. */
+
+void bptFileDetach(struct bptFile **pBpt);
+/* Detach and free up bptFile opened with bptFileAttach. */
+
+boolean bptFileFind(struct bptFile *bpt, void *key, int keySize, void *val, int valSize);
+/* Find value associated with key.  Return TRUE if it's found. 
+*  Parameters:
+*     bpt - file handle returned by bptFileOpen
+*     key - pointer to key string
+*     keySize - size of key.  Normally just strlen(key)
+*     val - pointer to where to put retrieved value
+*     valSize - size of memory buffer that will hold val.  Should match bpt->valSize.
+*/
+
+void bptFileTraverse(struct bptFile *bpt, void *context,
+    void (*callback)(void *context, void *key, int keySize, void *val, int valSize) );
+/* Traverse bPlusTree on file, calling supplied callback function at each
+ * leaf item. */
+
+
+void bptFileCreate(
+	void *itemArray, 	/* Sorted array of things to index. */
+	int itemSize, 		/* Size of each element in array. */
+	bits64 itemCount, 	/* Number of elements in array. */
+	bits32 blockSize,	/* B+ tree block size - # of children for each node. */
+	void (*fetchKey)(const void *va, char *keyBuf),  /* Given item, copy key to keyBuf */ 
+	bits32 keySize,					 /* Size of key */
+	void* (*fetchVal)(const void *va), 		 /* Given item, return pointer to value */
+	bits32 valSize, 				 /* Size of value */
+	char *fileName);                                 /* Name of output file. */
+/* Create a b+ tree index file from a sorted array. */
+
+void bptFileBulkIndexToOpenFile(void *itemArray, int itemSize, bits64 itemCount, bits32 blockSize,
+	void (*fetchKey)(const void *va, char *keyBuf), bits32 keySize,
+	void* (*fetchVal)(const void *va), bits32 valSize, FILE *f);
+/* Create a b+ tree index from a sorted array, writing output starting at current position
+ * of an already open file.  See bptFileCreate for explanation of parameters. */
+
+#define bptFileHeaderSize 32
+#define bptBlockHeaderSize 4
+
+#endif /* BPLUSTREE_H */
diff --git a/inc/bamFile.h b/inc/bamFile.h
new file mode 100644
index 0000000..4563773
--- /dev/null
+++ b/inc/bamFile.h
@@ -0,0 +1,148 @@
+/* bamFile -- interface to binary alignment format files using Heng Li's samtools lib. */
+
+#ifndef BAMFILE_H
+#define BAMFILE_H
+
+#include "dnaseq.h"
+#include "dystring.h"
+
+#ifdef USE_BAM
+
+// bam.h is incomplete without _IOLIB set to 1, 2 or 3.  2 is used by Makefile.generic:
+#ifndef _IOLIB
+#define _IOLIB 2
+#endif
+#include "bam.h"
+#include "sam.h"
+
+#else // no USE_BAM
+typedef struct { } bam1_t;
+typedef struct { } bam_index_t;
+typedef struct { } samfile_t;
+typedef int (*bam_fetch_f)(const bam1_t *b, void *data);
+
+#define COMPILE_WITH_SAMTOOLS "%s: in order to use this functionality you must " \
+    "install the samtools library (<A HREF=\"http://samtools.sourceforge.net\" " \
+    "TARGET=_BLANK>http://samtools.sourceforge.net</A>) and recompile kent/src with " \
+    "USE_BAM=1 in your environment " \
+    "(see <A HREF=\"http://genomewiki.ucsc.edu/index.php/Build_Environment_Variables\" " \
+    "TARGET=_BLANK>http://genomewiki.ucsc.edu/index.php/Build_Environment_Variables</A>)."
+
+#endif // USE_BAM
+
+struct bamChromInfo
+    {
+    struct bamChromInfo *next;
+    char *name;		/* Chromosome name */
+    bits32 size;	/* Chromosome size in bases */
+    };
+
+boolean bamFileExists(char *bamFileName);
+/* Return TRUE if we can successfully open the bam file and its index file. */
+
+samfile_t *bamOpen(char *fileOrUrl, char **retBamFileName);
+/* Return an open bam file as well as the filename of the bam. */
+
+void bamFetchAlreadyOpen(samfile_t *samfile, bam_index_t *idx, char *bamFileName, 
+			 char *position, bam_fetch_f callbackFunc, void *callbackData);
+/* With the open bam file, return items the same way with the callbacks as with bamFetch() */
+/* except in this case use an already-open bam file and index (use bam_index_load and free() for */
+/* the index). It seems a little strange to pass the filename in with the open bam, but */
+/* it's just used to report errors. */
+
+void bamFetch(char *fileOrUrl, char *position, bam_fetch_f callbackFunc, void *callbackData,
+	samfile_t **pSamFile);
+/* Open the .bam file, fetch items in the seq:start-end position range,
+ * and call callbackFunc on each bam item retrieved from the file plus callbackData.
+ * This handles BAM files with "chr"-less sequence names, e.g. from Ensembl. 
+ * The pSamFile parameter is optional.  If non-NULL it will be filled in, just for
+ * the benefit of the callback function, with the open samFile.  */
+
+void bamClose(samfile_t **pSamFile);
+/* Close down a samefile_t */
+
+boolean bamIsRc(const bam1_t *bam);
+/* Return TRUE if alignment is on - strand. */
+
+INLINE int bamUnpackCigarElement(unsigned int packed, char *retOp)
+/* Given an unsigned int containing a number of bases and an offset into an
+ * array of BAM-enhanced-CIGAR ASCII characters (operations), store operation 
+ * char into *retOp (retOp must not be NULL) and return the number of bases. */
+{
+#ifdef USE_BAM
+// decoding lifted from samtools bam.c bam_format1_core(), long may it remain stable:
+#define BAM_DOT_C_OPCODE_STRING "MIDNSHP=X"
+int n = packed>>BAM_CIGAR_SHIFT;
+int opcode = packed & BAM_CIGAR_MASK;
+if (opcode >= strlen(BAM_DOT_C_OPCODE_STRING))
+    errAbort("bamUnpackCigarElement: unrecognized opcode %d. "
+	     "(I only recognize 0..%lu [" BAM_DOT_C_OPCODE_STRING "])  "
+	     "Perhaps samtools bam.c's bam_format1 encoding changed?  If so, update me.",
+	     opcode, (unsigned long)(strlen(BAM_DOT_C_OPCODE_STRING)-1));
+*retOp = BAM_DOT_C_OPCODE_STRING[opcode];
+return n;
+#else // no USE_BAM
+errAbort(COMPILE_WITH_SAMTOOLS, "bamUnpackCigarElement");
+return 0;
+#endif// USE_BAM
+}
+
+void bamGetSoftClipping(const bam1_t *bam, int *retLow, int *retHigh, int *retClippedQLen);
+/* If retLow is non-NULL, set it to the number of "soft-clipped" (skipped) bases at
+ * the beginning of the query sequence and quality; likewise for retHigh at end.
+ * For convenience, retClippedQLen is the original query length minus soft clipping
+ * (and the length of the query sequence that will be returned). */
+
+void bamUnpackQuerySequence(const bam1_t *bam, boolean useStrand, char *qSeq);
+/* Fill in qSeq with the nucleotide sequence encoded in bam.  The BAM format 
+ * reverse-complements query sequence when the alignment is on the - strand,
+ * so if useStrand is given we rev-comp it back to restore the original query 
+ * sequence. */
+
+char *bamGetQuerySequence(const bam1_t *bam, boolean useStrand);
+/* Return the nucleotide sequence encoded in bam.  The BAM format 
+ * reverse-complements query sequence when the alignment is on the - strand,
+ * so if useStrand is given we rev-comp it back to restore the original query 
+ * sequence. */
+
+UBYTE *bamGetQueryQuals(const bam1_t *bam, boolean useStrand);
+/* Return the base quality scores encoded in bam as an array of ubytes. */
+
+void bamUnpackCigar(const bam1_t *bam, struct dyString *dyCigar);
+/* Unpack CIGAR string into dynamic string */
+
+char *bamGetCigar(const bam1_t *bam);
+/* Return a BAM-enhanced CIGAR string, decoded from the packed encoding in bam. */
+
+void bamShowCigarEnglish(const bam1_t *bam);
+/* Print out cigar in English e.g. "20 (mis)Match, 1 Deletion, 3 (mis)Match" */
+
+void bamShowFlagsEnglish(const bam1_t *bam);
+/* Print out flags in English, e.g. "Mate is on '-' strand; Properly paired". */
+
+int bamGetTargetLength(const bam1_t *bam);
+/* Tally up the alignment's length on the reference sequence from
+ * bam's packed-int CIGAR representation. */
+
+bam1_t *bamClone(const bam1_t *bam);
+/* Return a newly allocated copy of bam. */
+
+void bamShowTags(const bam1_t *bam);
+/* Print out tags in HTML: bold key, no type indicator for brevity. */
+
+char *bamGetTagString(const bam1_t *bam, char *tag, char *buf, size_t bufSize);
+/* If bam's tags include the given 2-character tag, place the value into 
+ * buf (zero-terminated, trunc'd if nec) and return a pointer to buf,
+ * or NULL if tag is not present. */
+
+void bamUnpackAux(const bam1_t *bam, struct dyString *dy);
+/* Unpack the tag:type:val part of bam into dy */
+
+struct bamChromInfo *bamChromList(samfile_t *fh);
+/* Return list of chromosomes from bam header. We make no attempty to normalize chromosome names to UCSC format,
+   so list may contain things like "1" for "chr1", "I" for "chrI", "MT" for "chrM" etc. */
+
+void bamChromInfoFreeList(struct bamChromInfo **pList);
+/* Free a list of dynamically allocated bamChromInfo's */
+
+#endif//ndef BAMFILE_H
diff --git a/inc/bandExt.h b/inc/bandExt.h
new file mode 100644
index 0000000..63f2ba9
--- /dev/null
+++ b/inc/bandExt.h
@@ -0,0 +1,42 @@
+/* bandExt - banded Smith-Waterman extension of alignments. 
+ * An aligner might first find perfectly matching hits of
+ * a small size, then extend these hits as far as possible
+ * while the sequences perfectly match, then call on routines
+ * in this module to do further extensions allowing small
+ * gaps and mismatches. */
+
+#ifndef BANDEXT_H
+#define BANDEXT_H
+
+#ifndef LOCALMEM_H
+#include "localmem.h"
+#endif
+
+boolean bandExt(boolean global, struct axtScoreScheme *ss, int maxInsert,
+	char *aStart, int aSize, char *bStart, int bSize, int dir,
+	int symAlloc, int *retSymCount, char *retSymA, char *retSymB, 
+	int *retRevStartA, int *retRevStartB);
+/* Try to extend an alignment from aStart/bStart onwards.
+ * If global is set it will always go to end (aStart+aSize-1,
+ * bStart+bSize-1).  Set maxInsert to the maximum gap size allowed.  
+ * 3 is often a good choice.  aStart/aSize bStart/bSize describe the
+ * sequence to extend through (not including any of the existing
+ * alignment. Set dir = 1 for forward extension, dir = -1 for backwards. 
+ * retSymA and retSymB should point to arrays of characters of
+ * symAlloc size.  symAlloc needs to be aSize*2 or so.  The
+ * alignment is returned in the various ret values.  The function
+ * overall returns TRUE if an extension occurred, FALSE if not. */
+
+struct ffAli *bandExtFf(
+	struct lm *lm,	/* Local memory pool, NULL to use global allocation for ff */
+	struct axtScoreScheme *ss, 	/* Scoring scheme to use. */
+	int maxInsert,			/* Maximum number of inserts to allow. */
+	struct ffAli *origFf,		/* Alignment block to extend. */
+	char *nStart, char *nEnd,	/* Bounds of region to extend through */
+	char *hStart, char *hEnd,	/* Bounds of region to extend through */
+	int dir,			/* +1 to extend end, -1 to extend start */
+	int maxExt);			/* Maximum length of extension. */
+/* Extend a gapless alignment in one direction.  Returns extending
+ * ffAlis, not linked into origFf, or NULL if no extension possible. */
+
+#endif /* BANDEXT_H */
diff --git a/inc/base64.h b/inc/base64.h
new file mode 100644
index 0000000..d2c21c1
--- /dev/null
+++ b/inc/base64.h
@@ -0,0 +1,30 @@
+/* Base64 encoding and decoding.
+ * by Galt Barber */
+
+#ifndef BASE64_H
+#define BASE64_H
+
+#define B64CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+
+char *base64Encode(char *input, size_t inplen);
+/* Use base64 to encode a string.  Returns one long encoded
+ * string which need to be freeMem'd. Note: big-endian algorithm.
+ * For some applications you may need to break the base64 output
+ * of this function into lines no longer than 76 chars.
+ */
+
+boolean base64Validate(char *input);
+/* Return true if input is valid base64.
+ * Note that the input string is changed by 
+ * eraseWhiteSpace(). */
+
+char *base64Decode(char *input, size_t *returnSize);
+/* Use base64 to decode a string.  Return decoded
+ * string which will be freeMem'd. Note: big-endian algorithm.
+ * Call eraseWhiteSpace() and check for invalid input 
+ * before passing in input if needed.  
+ * Optionally set retun size for use with binary data.
+ */
+
+#endif /* BASE64_H */
+
diff --git a/inc/basicBed.h b/inc/basicBed.h
new file mode 100644
index 0000000..30fd522
--- /dev/null
+++ b/inc/basicBed.h
@@ -0,0 +1,281 @@
+/* basicBed.h contains the basic interface to Browser Extensible Data (bed) files and tables.
+ * The idea behind bed is that the first three fields are defined and required.
+ * A total of 15 fields are defined, and the file can contain any number of these.
+ * In addition after any number of defined fields there can be custom fields that
+ * are not defined in the bed spec.
+ *
+ * There's additional bed-related code in src/hg/inc/bed.h.  This module contains the
+ * stuff that's independent of the database and other genomic structures. */
+
+#ifndef BASICBED_H
+#define BASICBED_H
+
+#include "psl.h"
+#include "asParse.h"
+
+struct bed
+/* Browser extensible data */
+    {
+    struct bed *next;  /* Next in singly linked list. */
+    char *chrom;	/* Human chromosome or FPC contig */
+    unsigned chromStart;	/* Start position in chromosome */
+    unsigned chromEnd;	/* End position in chromosome */
+    char *name;	/* Name of item */
+
+    /* The following items are not loaded by   the bedLoad routines. */
+    int score; /* Score - 0-1000 */  /* Should be uint but there are still some ct users with neg values, .as DOES say uint */
+    char strand[2];  /* + or -.  */
+    unsigned thickStart; /* Start of where display should be thick (start codon for genes) */
+    unsigned thickEnd;   /* End of where display should be thick (stop codon for genes) */
+    unsigned itemRgb;    /* RGB 8 bits each */
+    unsigned blockCount; /* Number of blocks. */
+    int *blockSizes;     /* Comma separated list of block sizes.  */
+    int *chromStarts;    /* Start positions inside chromosome.  Relative to chromStart*/
+
+
+    int expCount;	/* Experiment count */
+    int *expIds;		/* Comma separated list of Experiment ids */
+    float *expScores;	/* Comma separated list of Experiment scores. */
+    };
+
+#define bedKnownFields 15	/* Maximum known fields in bed */
+
+#define BB_MAX_CHROM_STRING 32  /* Maximum string length for chromosome length */
+
+struct bed3
+/* Browser extensible data - first three fields */
+    {
+    struct bed3 *next;  /* Next in singly linked list. */
+    char *chrom;	/* Human chromosome or FPC contig */
+    unsigned chromStart;	/* Start position in chromosome */
+    unsigned chromEnd;	/* End position in chromosome */
+    };
+
+struct bed3 *bed3New(char *chrom, int start, int end);
+/* Make new bed3. */
+
+struct bed4
+/* Browser extensible data - first four fields */
+    {
+    struct bed4 *next;  /* Next in singly linked list. */
+    char *chrom;	/* Human chromosome or FPC contig */
+    unsigned chromStart;	/* Start position in chromosome */
+    unsigned chromEnd;	/* End position in chromosome */
+    char *name;	/* Name of item */
+    };
+
+
+void bedStaticLoad(char **row, struct bed *ret);
+/* Load a row from bed table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+
+struct bed *bedLoad(char **row);
+/* Load a bed from row fetched with select * from bed
+ * from database.  Dispose of this with bedFree(). 
+ * This loads first four fields. */
+
+struct bed *bedCommaIn(char **pS, struct bed *ret);
+/* Create a bed out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new bed */
+
+void bedFree(struct bed **pEl);
+/* Free a single dynamically allocated bed such as created
+ * with bedLoad(). */
+
+void bedFreeList(struct bed **pList);
+/* Free a list of dynamically allocated bed's */
+
+void bedOutput(struct bed *el, FILE *f, char sep, char lastSep);
+/* Print out bed.  Separate fields with sep. Follow last field with lastSep. */
+
+#define bedTabOut(el,f) bedOutput(el,f,'\t','\n');
+/* Print out bed as a line in a tab-separated file. */
+
+#define bedCommaOut(el,f) bedOutput(el,f,',',',');
+/* Print out bed as a comma separated list including final comma. */
+
+/* --------------- End of AutoSQL generated code. --------------- */
+
+int bedCmp(const void *va, const void *vb);
+/* Compare to sort based on chrom,chromStart. */
+
+int bedCmpEnd(const void *va, const void *vb);
+/* Compare to sort based on chrom,chromEnd. */
+
+int bedCmpScore(const void *va, const void *vb);
+/* Compare to sort based on score - lowest first. */
+
+int bedCmpPlusScore(const void *va, const void *vb);
+/* Compare to sort based on chrom, chromStart and score - lowest first. */
+
+int bedCmpSize(const void *va, const void *vb);
+/* Compare to sort based on size of element (end-start == size) */
+
+int bedCmpChromStrandStart(const void *va, const void *vb);
+/* Compare to sort based on chrom,strand,chromStart. */
+
+struct bedLine
+/* A line in a bed file with chromosome, start position parsed out. */
+    {
+    struct bedLine *next;	/* Next in list. */
+    char *chrom;                /* Chromosome parsed out. */
+    int chromStart;             /* Start position (still in rest of line). */
+    char *line;                 /* Rest of line. */
+    };
+
+struct bedLine *bedLineNew(char *line);
+/* Create a new bedLine based on tab-separated string s. */
+
+void bedLineFree(struct bedLine **pBl);
+/* Free up memory associated with bedLine. */
+
+void bedLineFreeList(struct bedLine **pList);
+/* Free a list of dynamically allocated bedLine's */
+
+int bedLineCmp(const void *va, const void *vb);
+/* Compare to sort based on chrom,chromStart. */
+
+void bedSortFile(char *inFile, char *outFile);
+/* Sort a bed file (in place, overwrites old file. */
+
+struct bed *bedLoad3(char **row);
+/* Load first three fields of bed. */
+
+struct bed *bedLoad5(char **row);
+/* Load first five fields of bed. */
+
+struct bed *bedLoad6(char **row);
+/* Load first six fields of bed. */
+
+struct bed *bedLoad12(char **row);
+/* Load all 12 fields of bed. */
+
+struct bed *bedLoadN(char *row[], int wordCount);
+/* Convert a row of strings to a bed. */
+
+struct bed *bedLoadNAllChrom(char *fileName, int numFields, char* chrom);
+/* Load bed entries from a tab-separated file that have the given chrom.
+ * Dispose of this with bedFreeList(). */
+
+struct bed *bedLoadNAll(char *fileName, int numFields);
+/* Load all bed from a tab-separated file.
+ * Dispose of this with bedFreeList(). */
+
+struct bed *bedLoadAll(char *fileName);
+/* Determines how many fields are in a bedFile and load all beds from
+ * a tab-separated file.  Dispose of this with bedFreeList(). */
+
+void bedLoadAllReturnFieldCount(char *fileName, struct bed **retList, int *retFieldCount);
+/* Load bed of unknown size and return number of fields as well as list of bed items.
+ * Ensures that all lines in bed file have same field count. */
+
+void bedOutputN(struct bed *el, int wordCount, FILE *f, char sep, char lastSep);
+/* Write a bed of wordCount fields. */
+
+void bedOutputNitemRgb(struct bed *el, int wordCount, FILE *f,
+	char sep, char lastSep);
+/* Write a bed of wordCount fields, interpret column 9 as RGB. */
+
+#define bedTabOutNitemRgb(el,wordCount, f) bedOutputNitemRgb(el,wordCount,f,'\t','\n')
+/* Print out bed as a line in a tab-separated file. Interpret
+   column 9 as RGB */
+
+#define bedTabOutN(el,wordCount, f) bedOutputN(el,wordCount,f,'\t','\n')
+/* Print out bed as a line in a tab-separated file. */
+
+#define bedCommaOutN(el,wordCount, f) bedOutputN(el,wordCount,f,',',',')
+/* Print out bed as a comma separated list including final comma. */
+
+int bedTotalBlockSize(struct bed *bed);
+/* Return total size of all blocks. */
+
+int bedTotalThickBlockSize(struct bed *bed);
+/* Return total size of all thick blocks. */
+
+int bedStartThinSize(struct bed *bed);
+/* Return total size of all blocks before thick part. */
+
+int bedEndThinSize(struct bed *bed);
+/* Return total size of all blocks after thick part. */
+
+int bedBlockSizeInRange(struct bed *bed, int rangeStart, int rangeEnd);
+/* Get size of all parts of all exons between rangeStart and rangeEnd. */
+
+struct bed *bedFromPsl(struct psl *psl);
+/* Convert a single psl to a bed structure */
+
+void makeItBed12(struct bed *bedList, int numFields);
+/* If it's less than bed 12, make it bed 12. The numFields */
+/* param is for how many fields the bed *currently* has. */
+
+struct bed *cloneBed(struct bed *bed);
+/* Make an all-newly-allocated copy of a single bed record. */
+
+struct bed *cloneBedList(struct bed *bed);
+/* Make an all-newly-allocated list copied from bed. */
+
+struct bed *bedListNextDifferentChrom(struct bed *bedList);
+/* Return next bed in list that is from a different chrom than the start of the list. */
+
+struct bed *lmCloneBed(struct bed *bed, struct lm *lm);
+/* Make a copy of bed in local memory. */
+
+struct bed *bedCommaInN(char **pS, struct bed *ret, int fieldCount);
+/* Create a bed out of a comma separated string looking for fieldCount
+ * fields. This will fill in ret if non-null, otherwise will return a
+ * new bed */
+
+struct hash *readBedToBinKeeper(char *sizeFileName, char *bedFileName, int wordCount);
+/* Read a list of beds and return results in hash of binKeeper structure for fast query
+ * See also bedsIntoKeeperHash, which takes the beds read into a list already, but
+ * dispenses with the need for the sizeFile. */
+
+int bedParseRgb(char *itemRgb);
+/*	parse a string: "r,g,b" into three unsigned char values
+	returned as 24 bit number, or -1 for failure */
+
+long long bedTotalSize(struct bed *bedList);
+/* Add together sizes of all beds in list. */
+
+int bedSameStrandOverlap(struct bed *a, struct bed *b);
+/* Return amount of block-level overlap on same strand between a and b */
+
+boolean bedExactMatch(struct bed *oldBed, struct bed *newBed);
+/* Return TRUE if it's an exact match. */
+
+boolean bedCompatibleExtension(struct bed *oldBed, struct bed *newBed);
+/* Return TRUE if newBed is a compatible extension of oldBed, meaning
+ * all internal exons and all introns of old bed are contained, in the 
+ * same order in the new bed. */
+
+struct rbTree *bedToRangeTree(struct bed *bed);
+/* Convert bed into a range tree. */
+
+void bedIntoRangeTree(struct bed *bed, struct rbTree *rangeTree);
+/* Add all blocks in bed to range tree.  For beds without blocks,
+ * add entire bed. */
+
+int bedRangeTreeOverlap(struct bed *bed, struct rbTree *rangeTree);
+/* Return number of bases bed overlaps with rangeTree. */
+
+struct bed *bedThickOnly(struct bed *in);
+/* Return a bed that only has the thick part. (Which is usually the CDS). */
+
+struct bed *bedThickOnlyList(struct bed *inList);
+/* Return a list of beds that only are the thick part of input. */
+
+char *bedAsDef(int bedFieldCount, int totalFieldCount);
+/* Return an autoSql definition for a bed of given number of fields. 
+ * Normally totalFieldCount is equal to bedFieldCount.  If there are extra
+ * fields they are just given the names field16, field17, etc and type string. */
+
+boolean asCompareObjAgainstStandardBed(struct asObject *asYours, int numColumnsToCheck, boolean abortOnDifference);
+/* Compare user's .as object asYours to the standard BED.
+ * abortOnDifference specifies whether to warn or abort if they differ within the first numColumnsToCheck columns.
+ * Returns TRUE if they match. */
+
+void loadAndValidateBed(char *row[], int wordCount, int fieldCount, struct lineFile *lf, struct bed * bed, struct asObject *as, boolean isCt);
+/* Convert a row of strings to a bed and validate the contents.  Abort with message if invalid data. Optionally validate bedPlus via asObject. */
+
+#endif /* BASICBED_H */
diff --git a/inc/bbiFile.h b/inc/bbiFile.h
new file mode 100644
index 0000000..8d0ecbc
--- /dev/null
+++ b/inc/bbiFile.h
@@ -0,0 +1,361 @@
+/* bbiFile - Big Binary Indexed file.  Stuff that's common between bigWig and bigBed. */
+
+#ifndef BBIFILE_H
+#define BBIFILE_H
+
+#include "cirTree.h"
+
+/* bigWig/bigBed file structure:
+ *     fixedWidthHeader
+ *         magic# 		4 bytes
+ *         version              2 bytes
+ *	   zoomLevels		2 bytes
+ *         chromosomeTreeOffset	8 bytes
+ *         fullDataOffset	8 bytes
+ *	   fullIndexOffset	8 bytes
+ *         fieldCount           2 bytes (for bigWig 0)
+ *         definedFieldCount    2 bytes (for bigWig 0)
+ *         autoSqlOffset        8 bytes (for bigWig 0) (0 if no autoSql information)
+ *         totalSummaryOffset   8 bytes (0 in earlier versions of file lacking totalSummary)
+ *         uncompressBufSize    4 bytes (Size of uncompression buffer.  0 if uncompressed.)
+ *         reserved             8 bytes (0 for now)
+ *     zoomHeaders		there are zoomLevels number of these
+ *         reductionLevel	4 bytes
+ *	   reserved		4 bytes
+ *	   dataOffset		8 bytes
+ *         indexOffset          8 bytes
+ *     autoSql string (zero terminated - only present if autoSqlOffset non-zero)
+ *     totalSummary - summary of all data in file - only present if totalSummaryOffset non-zero
+ *         basesCovered        8 bytes
+ *         minVal              8 bytes float (for bigBed minimum depth of coverage)
+ *         maxVal              8 bytes float (for bigBed maximum depth of coverage)
+ *         sumData             8 bytes float (for bigBed sum of coverage)
+ *         sumSquared          8 bytes float (for bigBed sum of coverage squared)
+ *     chromosome b+ tree       bPlusTree index
+ *     full data
+ *         sectionCount		8 bytes (item count for bigBeds)
+ *         section data		section count sections, of three types (bed data for bigBeds)
+ *     full index               cirTree index
+ *     zoom info             one of these for each zoom level
+ *         zoom data
+ *             zoomCount	4 bytes
+ *             zoom data	there are zoomCount of these items
+ *                 chromId	4 bytes
+ *	           chromStart	4 bytes
+ *                 chromEnd     4 bytes
+ *                 validCount	4 bytes
+ *                 minVal       4 bytes float 
+ *                 maxVal       4 bytes float
+ *                 sumData      4 bytes float
+ *                 sumSquares   4 bytes float
+ *         zoom index        	cirTree index
+ *     magic# 		4 bytes - same as magic number at start of header
+ */
+
+#ifndef CIRTREE_H
+#include "cirTree.h"
+#endif
+
+#define bbiCurrentVersion 4
+/* Version history (of file format, not utilities - corresponds to version field in header)
+ *    1 - Initial release
+ *    1 - Unfortunately when attempting a transparent change to encoders, made the sectionCount 
+ *        field inconsistent, sometimes not present, sometimes 32 bits.  Since offset positions
+ *        in index were still accurate this did not break most applications, but it did show
+ *        up in the summary section of the Table Browser.
+ *    2 - Made sectionCount consistently 64 bits. Also fixed missing zoomCount in first level of
+ *        zoom in files made by bedToBigBed and bedGraphToBigWig.  (The older wigToBigWig was fine.)
+ *        Added totalSummary section.
+ *    3 - Adding zlib compression.  Only active if uncompressBufSize is non-zero in header.
+ *    4 - Fixed problem in encoder for the max field in zoom levels higher than the first one.
+ *        Added an extra sig at end of file.
+ */
+
+struct bbiZoomLevel
+/* A zoom level in bigWig file. */
+    {
+    struct bbiZoomLevel *next;		/* Next in list. */
+    bits32 reductionLevel;		/* How many bases per item */
+    bits32 reserved;			/* Zero for now. */
+    bits64 dataOffset;			/* Offset of data for this level in file. */
+    bits64 indexOffset;			/* Offset of index for this level in file. */
+    };
+
+struct bbiZoomLevel *bbiBestZoom(struct bbiZoomLevel *levelList, int desiredReduction);
+/* Return zoom level that is the closest one that is less than or equal to 
+ * desiredReduction. */
+
+struct bbiFile 
+/* An open bbiFile */
+    {
+    struct bbiFile *next;	/* Next in list. */
+    char *fileName;		/* Name of file - for better error reporting. */
+    struct udcFile *udc;	/* Open UDC file handle. */
+    bits32 typeSig;		/* bigBedSig or bigWigSig for now. */
+    boolean isSwapped;		/* If TRUE need to byte swap everything. */
+    struct bptFile *chromBpt;	/* Index of chromosomes. */
+    bits16 version;		/* Version number - initially 1. */
+    bits16 zoomLevels;		/* Number of zoom levels. */
+    bits64 chromTreeOffset;	/* Offset to chromosome index. */
+    bits64 unzoomedDataOffset;	/* Start of unzoomed data. */
+    bits64 unzoomedIndexOffset;	/* Start of unzoomed index. */
+    bits16 fieldCount;		/* Number of columns in bed version. */
+    bits16 definedFieldCount;   /* Number of columns using bed standard definitions. */
+    bits64 asOffset;		/* Offset to embedded null-terminated AutoSQL file. */
+    bits64 totalSummaryOffset;	/* Offset to total summary information if any.  (On older files have to calculate) */
+    bits32 uncompressBufSize;	/* Size of uncompression buffer, 0 if uncompressed */
+    struct cirTreeFile *unzoomedCir;	/* Unzoomed data index in memory - may be NULL. */
+    struct bbiZoomLevel *levelList;	/* List of zoom levels. */
+    };
+
+
+struct bbiFile *bbiFileOpen(char *fileName, bits32 sig, char *typeName);
+/* Open up big wig or big bed file. */
+
+void bbiFileClose(struct bbiFile **pBwf);
+/* Close down a big wig/big bed file. */
+
+struct fileOffsetSize *bbiOverlappingBlocks(struct bbiFile *bbi, struct cirTreeFile *ctf,
+	char *chrom, bits32 start, bits32 end, bits32 *retChromId);
+/* Fetch list of file blocks that contain items overlapping chromosome range. */
+ 
+struct bbiChromIdSize
+/* We store an id/size pair in chromBpt bPlusTree */
+    {
+    bits32 chromId;	/* Chromosome ID */
+    bits32 chromSize;	/* Chromosome Size */
+    };
+
+struct bbiChromInfo
+/* Pair of a name and a 32-bit integer. Used to assign IDs to chromosomes. */
+    {
+    struct bbiChromInfo *next;
+    char *name;		/* Chromosome name */
+    bits32 id;		/* Chromosome ID - a small number usually */
+    bits32 size;	/* Chromosome size in bases */
+    };
+
+struct bbiChromInfo *bbiChromList(struct bbiFile *bbi);
+/* Return all chromosomes in file.  Dispose of this with bbiChromInfoFreeList. */
+
+void bbiChromInfoFreeList(struct bbiChromInfo **pList);
+/* Free a list of bbiChromInfo's */
+
+bits32 bbiChromSize(struct bbiFile *bbi, char *chrom);
+/* Returns size of given chromosome. */
+
+void bbiChromInfoKey(const void *va, char *keyBuf);
+/* Get key field out of bbiChromInfo. */
+
+void *bbiChromInfoVal(const void *va);
+/* Get val field out of bbiChromInfo. */
+
+struct bbiChromUsage
+/* Information on how many items per chromosome etc.  Used by multipass bbiFile writers. */
+    {
+    struct bbiChromUsage *next;
+    char *name;	/* chromosome name. */
+    bits32 itemCount;	/* Number of items for this chromosome. */
+    bits32 id;	/* Unique ID for chromosome. */
+    bits32 size;	/* Size of chromosome. */
+    };
+
+
+enum bbiSummaryType
+/* Way to summarize data. */
+    {
+    bbiSumMean = 0,	/* Average value */
+    bbiSumMax = 1,	/* Maximum value */
+    bbiSumMin = 2,	/* Minimum value */
+    bbiSumCoverage = 3,  /* Bases in region containing actual data. */
+    bbiSumStandardDeviation = 4, /* Standard deviation in window. */
+    };
+
+enum bbiSummaryType bbiSummaryTypeFromString(char *string);
+/* Return summary type given a descriptive string. */
+
+char *bbiSummaryTypeToString(enum bbiSummaryType type);
+/* Convert summary type from enum to string representation. */
+
+struct bbiSummary
+/* A summary type item. */
+    {
+    struct bbiSummary *next;
+    bits32 chromId;		/* ID of associated chromosome. */
+    bits32 start,end;		/* Range of chromosome covered. */
+    bits32 validCount;		/* Count of (bases) with actual data. */
+    float minVal;		/* Minimum value of items */
+    float maxVal;		/* Maximum value of items */
+    float sumData;		/* sum of values for each base. */
+    float sumSquares;		/* sum of squares for each base. */
+    bits64 fileOffset;		/* Offset of summary in file. */
+    };
+
+#define bbiSummaryFreeList slFreeList
+
+
+struct bbiSummaryOnDisk
+/* The part of the summary that ends up on disk - in the same order written to disk. */
+    {
+    bits32 chromId;		/* ID of associated chromosome. */
+    bits32 start,end;		/* Range of chromosome covered. */
+    bits32 validCount;		/* Count of (bases) with actual data. */
+    float minVal;		/* Minimum value of items */
+    float maxVal;		/* Maximum value of items */
+    float sumData;		/* sum of values for each base. */
+    float sumSquares;		/* sum of squares for each base. */
+    };
+
+struct bbiInterval
+/* Data on a single interval. */
+    {
+    struct bbiInterval *next;	/* Next in list. */
+    bits32 start, end;			/* Position in chromosome, half open. */
+    double val;				/* Value at that position. */
+    };
+
+typedef struct bbiInterval *(*BbiFetchIntervals)(struct bbiFile *bbi, char *chrom, 
+					    bits32 start, bits32 end, struct lm *lm);
+/* A callback function that returns a bbiInterval list. */
+
+void bbiAttachUnzoomedCir(struct bbiFile *bbi);
+/* Make sure unzoomed cir is attached. */
+
+struct bbiSummaryElement
+/* An element of a summary from the user side. */
+    {
+    bits64 validCount;		/* Count of (bases) with actual data. */
+    double minVal;		/* Minimum value of items */
+    double maxVal;		/* Maximum value of items */
+    double sumData;		/* sum of values for each base. */
+    double sumSquares;		/* sum of squares for each base. */
+    };
+
+boolean bbiSummaryArrayExtended(struct bbiFile *bbi, char *chrom, bits32 start, bits32 end,
+	BbiFetchIntervals fetchIntervals,
+	int summarySize, struct bbiSummaryElement *summary);
+/* Fill in summary with  data from indicated chromosome range in bigWig/bigBed file. 
+ * Returns FALSE if no data at that position. */
+
+boolean bbiSummaryArray(struct bbiFile *bbi, char *chrom, bits32 start, bits32 end,
+	BbiFetchIntervals fetchIntervals,
+	enum bbiSummaryType summaryType, int summarySize, double *summaryValues);
+/* Fill in summaryValues with  data from indicated chromosome range in bigWig file.
+ * Be sure to initialize summaryValues to a default value, which will not be touched
+ * for regions without data in file.  (Generally you want the default value to either
+ * be 0.0 or nan("") depending on the application.)  Returns FALSE if no data
+ * at that position. */
+
+struct bbiSummaryElement bbiTotalSummary(struct bbiFile *bbi);
+/* Return summary of entire file! */
+
+/****** Write side of things - implemented in bbiWrite.c ********/
+
+struct bbiBoundsArray
+/* Minimum info needed for r-tree indexer - where a section lives on disk and the
+ * range it covers. */
+    {
+    bits64 offset;		/* Offset within file. */
+    struct cirTreeRange range;	/* What is covered. */
+    };
+
+struct cirTreeRange bbiBoundsArrayFetchKey(const void *va, void *context);
+/* Fetch bbiBoundsArray key for r-tree */
+
+bits64 bbiBoundsArrayFetchOffset(const void *va, void *context);
+/* Fetch bbiBoundsArray file offset for r-tree */
+
+struct bbiSumOutStream
+/* Buffer output to file so have a chance to compress. */
+    {
+    struct bbiSummaryOnDisk *array;
+    int elCount;
+    int allocCount;
+    FILE *f;
+    boolean doCompress;
+    };
+
+struct bbiSumOutStream *bbiSumOutStreamOpen(int allocCount, FILE *f, boolean doCompress);
+/* Open new bbiSumOutStream. */
+
+void bbiSumOutStreamClose(struct bbiSumOutStream **pStream);
+/* Free up bbiSumOutStream */
+
+void bbiSumOutStreamWrite(struct bbiSumOutStream *stream, struct bbiSummary *sum);
+/* Write out next one to stream. */
+
+void bbiOutputOneSummaryFurtherReduce(struct bbiSummary *sum, 
+	struct bbiSummary **pTwiceReducedList, 
+	int doubleReductionSize, struct bbiBoundsArray **pBoundsPt, 
+	struct bbiBoundsArray *boundsEnd, bits32 chromSize, struct lm *lm, 
+	struct bbiSumOutStream *stream);
+/* Write out sum to file, keeping track of minimal info on it in *pBoundsPt, and also adding
+ * it to second level summary. */
+
+struct bbiSummary *bbiSummarySimpleReduce(struct bbiSummary *list, int reduction, struct lm *lm);
+/* Do a simple reduction - where among other things the reduction level is an integral
+ * multiple of the previous reduction level, and the list is sorted. Allocate result out of lm. */
+
+#define bbiMaxZoomLevels 10	/* Maximum zoom levels produced by writers. */
+
+void bbiWriteDummyHeader(FILE *f);
+/* Write out all-zero header, just to reserve space for it. */
+
+void bbiWriteDummyZooms(FILE *f);
+/* Write out zeroes to reserve space for ten zoom levels. */
+
+void bbiSummaryElementWrite(FILE *f, struct bbiSummaryElement *sum);
+/* Write out summary element to file. */
+
+void bbiWriteChromInfo(struct bbiChromUsage *usageList, int blockSize, FILE *f);
+/* Write out information on chromosomes to file. */
+
+void bbiWriteFloat(FILE *f, float val);
+/* Write out floating point val to file.  Mostly to convert from double... */
+
+struct hash *bbiChromSizesFromFile(char *fileName);
+/* Read two column file into hash keyed by chrom. */
+
+bits64 bbiTotalSummarySize(struct bbiSummary *list);
+/* Return size on disk of all summaries. */
+
+void bbiChromUsageFree(struct bbiChromUsage **pUsage);
+/* free a single bbiChromUsage structure */
+
+void bbiChromUsageFreeList(struct bbiChromUsage **pList);
+/* free a list of bbiChromUsage structures */
+
+struct bbiChromUsage *bbiChromUsageFromBedFile(struct lineFile *lf, 
+	struct hash *chromSizesHash, int *retMinDiff, double *retAveSize, bits64 *retBedCount);
+/* Go through bed file and collect chromosomes and statistics. Free with bbiChromUsageFreeList */
+
+int bbiCountSectionsNeeded(struct bbiChromUsage *usageList, int itemsPerSlot);
+/* Count up number of sections needed for data. */
+
+void bbiAddToSummary(bits32 chromId, bits32 chromSize, bits32 start, bits32 end, 
+	bits32 validCount, double minVal, double maxVal, double sumData, double sumSquares,  
+	int reduction, struct bbiSummary **pOutList);
+/* Add data range to summary - putting it onto top of list if possible, otherwise
+ * expanding list. */
+
+void bbiAddRangeToSummary(bits32 chromId, bits32 chromSize, bits32 start, bits32 end, 
+	double val, int reduction, struct bbiSummary **pOutList);
+/* Add chromosome range to summary - putting it onto top of list if possible, otherwise
+ * expanding list. */
+
+struct bbiSummary *bbiReduceSummaryList(struct bbiSummary *inList, 
+	struct bbiChromInfo *chromInfoArray, int reduction);
+/* Reduce summary list to another summary list. */
+
+bits64 bbiWriteSummaryAndIndex(struct bbiSummary *summaryList, 
+	int blockSize, int itemsPerSlot, boolean doCompress, FILE *f);
+/* Write out summary and index to summary, returning start position of
+ * summary index. */
+
+boolean bbiFileCheckSigs(char *fileName, bits32 sig, char *typeName);
+/* check file signatures at beginning and end of file */
+
+time_t bbiUpdateTime(struct bbiFile *bbi);
+/* return bbi->udc->updateTime */
+
+#endif /* BBIFILE_H */
diff --git a/inc/bigBed.h b/inc/bigBed.h
new file mode 100644
index 0000000..8aee277
--- /dev/null
+++ b/inc/bigBed.h
@@ -0,0 +1,83 @@
+/* bigBed - interface to binary file with bed-style values (that is a bunch of
+ * possibly overlapping regions.
+ *
+ * This shares a lot with the bigWig module. */
+
+#ifndef BIGBED_H
+#define BIGBED_H
+
+#include "asParse.h"
+
+#ifndef BBIFILE
+#include "bbiFile.h"
+#endif
+
+struct bigBedInterval
+/* A partially parsed out bed record plus some extra fields. */
+    {
+    struct bigBedInterval *next;	/* Next in list. */
+    bits32 start, end;		/* Range inside chromosome - half open zero based. */
+    char *rest;			/* Rest of line. May be NULL*/
+    };
+
+struct ppBed
+/* A partially parsed out bed record plus some extra fields. */
+    {
+    struct ppBed *next;	/* Next in list. */
+    char *chrom;		/* Chromosome name (not allocated here) */
+    bits32 start, end;		/* Range inside chromosome - half open zero based. */
+    char *rest;			/* The rest of the bed. */
+    bits64 fileOffset;		/* File offset. */
+    bits32 chromId;		/* Chromosome ID. */
+    };
+
+struct bbiFile *bigBedFileOpen(char *fileName);
+/* Open up big bed file.   Free this up with bbiFileClose. */
+
+#define bigBedFileClose(a) bbiFileClose(a)
+
+struct bigBedInterval *bigBedIntervalQuery(struct bbiFile *bbi, char *chrom,
+	bits32 start, bits32 end, int maxItems, struct lm *lm);
+/* Get data for interval.  Return list allocated out of lm.  Set maxItems to maximum
+ * number of items to return, or to 0 for all items. */
+
+int bigBedIntervalToRow(struct bigBedInterval *interval, char *chrom, char *startBuf, char *endBuf,
+	char **row, int rowSize);
+/* Convert bigBedInterval into an array of chars equivalent to what you'd get by
+ * parsing the bed file. The startBuf and endBuf are used to hold the ascii representation of
+ * start and end.  Note that the interval->rest string will have zeroes inserted as a side effect.
+ * Returns number of fields in row.  */
+
+boolean bigBedSummaryArray(struct bbiFile *bbi, char *chrom, bits32 start, bits32 end,
+	enum bbiSummaryType summaryType, int summarySize, double *summaryValues);
+/* Fill in summaryValues with  data from indicated chromosome range in bigBed file.
+ * Be sure to initialize summaryValues to a default value, which will not be touched
+ * for regions without data in file.  (Generally you want the default value to either
+ * be 0.0 or nan("") depending on the application.)  Returns FALSE if no data
+ * at that position. */
+
+boolean bigBedSummaryArrayExtended(struct bbiFile *bbi, char *chrom, bits32 start, bits32 end,
+	int summarySize, struct bbiSummaryElement *summary);
+/* Get extended summary information for summarySize evenely spaced elements into
+ * the summary array. */
+
+bits64 bigBedItemCount(struct bbiFile *bbi);
+/* Return total items in file. */
+
+char *bigBedAutoSqlText(struct bbiFile *bbi);
+/* Get autoSql text if any associated with file.  Do a freeMem of this when done. */
+
+struct asObject *bigBedAs(struct bbiFile *bbi);
+/* Get autoSql object definition if any associated with file. */
+
+struct asObject *bigBedAsOrDefault(struct bbiFile *bbi);
+// Get asObject associated with bigBed - if none exists in file make it up from field counts.
+
+struct asObject *bigBedFileAsObjOrDefault(char *fileName);
+// Get asObject associated with bigBed file, or the default.
+
+boolean bigBedFileCheckSigs(char *fileName);
+/* check file signatures at beginning and end of file */
+
+#endif /* BIGBED_H */
+
diff --git a/inc/bigWig.h b/inc/bigWig.h
new file mode 100644
index 0000000..d6fcb60
--- /dev/null
+++ b/inc/bigWig.h
@@ -0,0 +1,112 @@
+/* bigWig - interface to binary file with wiggle-style values (that is a bunch of
+ * small non-overlapping regions each associated with a floating point value. 
+ *
+ * There are several ways to use this module.   To create a new bigWig file use the
+ * bigWigCreate function, which takes as input an ascii file in fixedStep, variableStep
+ * or bedGraph format.
+ *
+ * To get a section of of a bigWig for display on a browser, use the bigWigSummaryArray
+ * function, which will fill in an array of doubles with on value for each pixel that
+ * you want to display.
+ *
+ * To read all the data out of a bigWig get the chromosome info with bbiChromList
+ * and then fetch all of it for each chromosome using bigWigIntervalQuery.
+ *
+ * See also the module bbiFile that has a description of they structure of
+ * a bigWig file, and lower level routines used to implement this interface.
+ */
+
+#ifndef BIGWIG_H
+#define BIGWIG_H
+
+#ifndef BBIFILE
+#include "bbiFile.h"
+#endif
+
+#ifndef BITS_H
+#include "bits.h"
+#endif
+
+void bigWigFileCreate(
+	char *inName, 		/* Input file in ascii wiggle format. */
+	char *chromSizes, 	/* Two column tab-separated file: <chromosome> <size>. */
+	int blockSize,		/* Number of items to bundle in r-tree.  1024 is good. */
+	int itemsPerSlot,	/* Number of items in lowest level of tree.  512 is good. */
+	boolean clipDontDie,	/* If TRUE then clip items off end of chrom rather than dying. */
+	boolean compress,	/* If TRUE then compress data. */
+	char *outName);
+/* Convert ascii format wig file (in fixedStep, variableStep or bedGraph format) 
+ * to binary big wig format. */
+
+struct bbiFile *bigWigFileOpen(char *fileName);
+/* Open up big wig file.   Free this up with bbiFileClose */
+
+#define bigWigFileClose(a) bbiFileClose(a)
+
+struct bbiInterval *bigWigIntervalQuery(struct bbiFile *bwf, char *chrom, bits32 start, bits32 end,
+	struct lm *lm);
+/* Get data for interval.  Return list allocated out of lm. */
+
+int bigWigIntervalDump(struct bbiFile *bwf, char *chrom, bits32 start, bits32 end, int maxCount,
+	FILE *out);
+/* Print out info on bigWig parts that intersect chrom:start-end.   Set maxCount to 0 if you 
+ * don't care how many are printed.  Returns number printed. */
+
+boolean bigWigSummaryArray(struct bbiFile *bwf, char *chrom, bits32 start, bits32 end,
+	enum bbiSummaryType summaryType, int summarySize, double *summaryValues);
+/* Fill in summaryValues with  data from indicated chromosome range in bigWig file.
+ * Be sure to initialize summaryValues to a default value, which will not be touched
+ * for regions without data in file.  (Generally you want the default value to either
+ * be 0.0 or nan(0) depending on the application.)  Returns FALSE if no data
+ * at that position. */
+
+boolean bigWigSummaryArrayExtended(struct bbiFile *bwf, char *chrom, bits32 start, bits32 end,
+	int summarySize, struct bbiSummaryElement *summary);
+/* Get extended summary information for summarySize evenely spaced elements into
+ * the summary array. */
+
+double bigWigSingleSummary(struct bbiFile *bwf, char *chrom, int start, int end,
+    enum bbiSummaryType summaryType, double defaultVal);
+/* Return the summarized single value for a range. */
+
+boolean isBigWig(char *fileName);
+/* Peak at a file to see if it's bigWig */
+
+boolean bigWigFileCheckSigs(char *fileName);
+/* check file signatures at beginning and end of file */
+
+/* bigWigValsOnChrom - a little system for optimizing bigWig use when doing a pass over the
+ * whole chromosome.   How it is used typically is:
+ *      struct bigWigValsOnChrom *chromVals = bigWigValsOnChromNew();
+ *      for (chrom = chromList; chrom != NULL; chrom = chrom->next)
+ *          {
+ *          if (bigWigValsOnChromFetchData(chromVals, chrom->name, bigWig))
+ *              // do stuff using the valBuf, or covBuf fields which have
+ *              // the big wig data unpacked into them. Can use chromSize and chrom too 
+ *          }
+ *       bigWigValsOnChromFree(&chromVals);  */
+
+struct bigWigValsOnChrom
+/* Object for bulk access a chromosome at a time.  This is faster than
+ * doing bigWigInterval queries when you have ~3000 or more queries. */
+     {
+     struct bigWigValsOnChrom *next;
+     char *chrom;	/* Current chromosome. */
+     long chromSize;	/* Size of current chromosome. */
+     long bufSize;	/* Size of allocated buffer */
+     double *valBuf;	/* A value for each base on chrom. Zero where no data. */
+     Bits *covBuf;	/* A bit for each base with data. */
+     };
+
+struct bigWigValsOnChrom *bigWigValsOnChromNew();
+/* Allocate new empty bigWigValsOnChromStructure. */
+
+void bigWigValsOnChromFree(struct bigWigValsOnChrom **pChromVals);
+/* Free up bigWigValsOnChrom */
+
+boolean bigWigValsOnChromFetchData(struct bigWigValsOnChrom *chromVals, char *chrom, 
+	struct bbiFile *bigWig);
+/* Fetch data for chromosome from bigWig. Returns FALSE if not data on that chrom. */
+
+#endif /* BIGWIG_H */
+
diff --git a/inc/binRange.h b/inc/binRange.h
new file mode 100644
index 0000000..4727dc7
--- /dev/null
+++ b/inc/binRange.h
@@ -0,0 +1,120 @@
+#ifndef BINRANGE_H
+#define BINRANGE_H
+
+/* binRange Stuff to handle binning - which helps us restrict 
+ * our attention to the parts of database that contain info
+ * about a particular window on a chromosome. This scheme
+ * will work without modification for chromosome sizes up
+ * to half a gigaBase.  The finest sized bin is 128k (1<<17).
+ * The next coarsest is 8x as big (1<<13).  There's a hierarchy
+ * of bins with the chromosome itself being the final bin.
+ * Features are put in the finest bin they'll fit in. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#define BINRANGE_MAXEND_512M (512*1024*1024)
+#define _binOffsetOldToExtended  4681
+
+int binLevelsExtended();
+/* Return number of levels to bins. */
+
+int binLevels();
+/* Return number of levels to bins. */
+
+int binFirstShift();
+/* Return amount to shift a number to get to finest bin. */
+
+int binNextShift();
+/* Return amount to shift a number to get to next coarser bin. */
+
+int binOffsetExtended(int level);
+/* Return offset for bins of a given level. */
+
+int binOffset(int level);
+/* Return offset for bins of a given level. */
+
+/*****  And now for some higher level stuff - useful for binning
+ *****  things in memory. ******/
+
+int binFromRange(int start, int end);
+/* Given start,end in chromosome coordinates assign it
+ * a bin.   There's a bin for each 128k segment, for each
+ * 1M segment, for each 8M segment, for each 64M segment,
+ * and for each chromosome (which is assumed to be less than
+ * 512M.)  A range goes into the smallest bin it will fit in. */
+
+struct binElement
+/* An element in a bin. */
+    {
+    struct binElement *next;
+    int start, end;		/* 0 based, half open range */
+    void *val;			/* Actual bin item. */
+    };
+
+int binElementCmpStart(const void *va, const void *vb);
+/* Compare to sort based on start. */
+
+struct binKeeper
+/* This keeps things in bins in memory */
+    {
+    struct binKeeper *next;
+    int minPos;		/* Minimum position to bin. */
+    int maxPos;		/* Maximum position to bin. */
+    int binCount;	/* Count of bins. */
+    struct binElement **binLists; /* A list for each bin. */
+    };
+
+struct binKeeperCookie
+/* used by binKeeperFirst/binKeeperNext in tracking location in traversing bins */
+    {
+    struct binKeeper *bk;       /* binKeeper we are associated with */
+    int blIdx;                  /* current bin list index */
+    struct binElement *nextBel; /* next binElement */
+    };
+
+struct binKeeper *binKeeperNew(int minPos, int maxPos);
+/* Create new binKeeper that can cover range. */
+
+void binKeeperFree(struct binKeeper **pBk);
+/* Free up a bin keeper. */
+
+void binKeeperAdd(struct binKeeper *bk, int start, int end, void *val);
+/* Add item to binKeeper. */ 
+
+void binKeeperRemove(struct binKeeper *bk, int start, int end, void *val);
+/* Remove item from binKeeper. */ 
+
+struct binElement *binKeeperFind(struct binKeeper *bk, int start, int end);
+/* Return a list of all items in binKeeper that intersect range.
+ * Free this list with slFreeList. */
+
+struct binElement *binKeeperFindSorted(struct binKeeper *bk, int start, int end);
+/* Like binKeeperFind, but sort list on start coordinates. */
+
+struct binElement *binKeeperFindAll(struct binKeeper *bk);
+/* Get all elements sorted. */
+
+boolean binKeeperAnyOverlap(struct binKeeper *bk, int start, int end);
+/* Return TRUE if start/end overlaps with any items in binKeeper. */
+
+void binKeeperReplaceVal(struct binKeeper *bk, int start, int end,
+	void *oldVal, void *newVal);
+/* Replace occurences of old val in range from start->end with newVal */
+
+struct binElement *binKeeperFindLowest(struct binKeeper *bk, int start, int end);
+/* Find the lowest overlapping range. Quick even if search range large */
+
+void binKeeperRemove(struct binKeeper *bk, int start, int end, void *val);
+/* Remove item from binKeeper. */ 
+
+struct binKeeperCookie binKeeperFirst(struct binKeeper *bk);
+/* Return an object to use by binKeeperNext() to traverse the binElements.
+ * The first call to binKeeperNext() will return the first entry in the
+ * table. */
+
+struct binElement* binKeeperNext(struct binKeeperCookie *cookie);
+/* Return the next entry in the binKeeper table.  */
+
+#endif /* BINRANGE_H */
+
diff --git a/inc/bits.h b/inc/bits.h
new file mode 100644
index 0000000..7450097
--- /dev/null
+++ b/inc/bits.h
@@ -0,0 +1,76 @@
+/* bits - handle operations on arrays of bits. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef BITS_H
+#define BITS_H
+
+typedef unsigned char Bits;
+
+#define bitToByteSize(bitSize) ((bitSize+7)/8)
+/* Convert number of bits to number of bytes needed to store bits. */
+
+Bits *bitAlloc(int bitCount);
+/* Allocate bits. */
+
+Bits *bitRealloc(Bits *b, int bitCount, int newBitCount);
+/* Resize a bit array.  If b is null, allocate a new array */
+
+Bits *bitClone(Bits* orig, int bitCount);
+/* Clone bits. */
+
+void bitFree(Bits **pB);
+/* Free bits. */
+
+void bitSetOne(Bits *b, int bitIx);
+/* Set a single bit. */
+
+void bitClearOne(Bits *b, int bitIx);
+/* Clear a single bit. */
+
+void bitSetRange(Bits *b, int startIx, int bitCount);
+/* Set a range of bits. */
+
+boolean bitReadOne(Bits *b, int bitIx);
+/* Read a single bit. */
+
+int bitCountRange(Bits *b, int startIx, int bitCount);
+/* Count number of bits set in range. */
+
+int bitFindSet(Bits *b, int startIx, int bitCount);
+/* Find the index of the the next set bit. */
+
+int bitFindClear(Bits *b, int startIx, int bitCount);
+/* Find the index of the the next clear bit. */
+
+void bitClear(Bits *b, int bitCount);
+/* Clear many bits (possibly up to 7 beyond bitCount). */
+
+void bitClearRange(Bits *b, int startIx, int bitCount);
+/* Clear a range of bits. */
+
+void bitAnd(Bits *a, Bits *b, int bitCount);
+/* And two bitmaps.  Put result in a. */
+
+void bitOr(Bits *a, Bits *b, int bitCount);
+/* Or two bitmaps.  Put result in a. */
+
+void bitXor(Bits *a, Bits *b, int bitCount);
+/* Xor two bitmaps.  Put result in a. */
+
+void bitNot(Bits *a, int bitCount);
+/* Flip all bits in a. */
+
+void bitPrint(Bits *a, int startIx, int bitCount, FILE* out);
+/* Print part or all of bit map as a string of 0s and 1s.  Mostly useful for
+ * debugging */
+
+extern int bitsInByte[256];
+/* Lookup table for how many bits are set in a byte. */
+
+void bitsInByteInit();
+/* Initialize bitsInByte array. */
+
+#endif /* BITS_H */
+
diff --git a/inc/blastParse.h b/inc/blastParse.h
new file mode 100644
index 0000000..c6d87a8
--- /dev/null
+++ b/inc/blastParse.h
@@ -0,0 +1,116 @@
+/* blastParse - read in blast output into C data structure. */
+
+#ifndef BLASTPARSE_H
+#define BLASTPARSE_H
+
+struct blastFile
+/* All the info in a single file. */
+    {
+    struct blastFile *next;
+    char *fileName;			/* Name of file this is in. */
+    char *program;                      /* Blastp, blastx, blastn, etc. */
+    char *version;                      /* Version of program. */
+    char *buildDate;                    /* Build date of program. */
+    struct lineFile *lf;                /* File blast is in. */
+    struct blastQuery *queries;         /* List of queries. */
+    };
+
+struct blastQuery
+/* Info on one query. */
+    {
+    struct blastQuery *next;
+    char *query;                        /* Name of query sequence. */
+    int queryBaseCount;                 /* Number of bases in query. */
+    char *database;                     /* Name of database. */
+    int dbSeqCount;                     /* Number of sequences in database. */
+    int dbBaseCount;                    /* Number of bases in database. */
+    int psiRounds;                      /* PSI BLAST rounds, or 0 if not PSI blast */
+    struct blastGappedAli *gapped;      /* List of gapped alignments. */
+    };
+
+struct blastGappedAli
+/* Info about a gapped alignment. */
+    {
+    struct blastGappedAli *next;
+    struct blastQuery *query;           /* Query associated with this alignment (not owned here). */
+    int psiRound;                       /* PSI BLAST round, or 0 if not PSI blast */
+    char *targetName;                   /* Name of target sequence. */
+    int targetSize;                     /* Size of target sequence. */
+    struct blastBlock *blocks;          /* List of aligning blocks (no big gaps). */
+    };
+
+struct blastBlock
+/* Info about a single block of gapped alignment. */
+    {
+    struct blastBlock *next;
+    struct blastGappedAli *gappedAli;   /* gapped ali associated with block */
+    double bitScore;                    /* About 2 bits per aligning nucleotide. */
+    double eVal;                        /* Expected number of alignments in database. */
+    int matchCount;                     /* Number of matching nucleotides. */
+    int totalCount;                     /* Total number of nucleotides. */
+    int insertCount;                    /* Number of inserts. */
+    BYTE qStrand;                       /* Query strand (+1 or -1) */
+    BYTE tStrand;                       /* Target strand (+1 or -1) */
+    BYTE qFrame;                        /* Frames for tblastn, +/- 1, 2, 3, or */
+    BYTE tFrame;                        /* 0 if none. */
+    int qStart;                         /* Query start position. [0..n) */
+    int tStart;                         /* Target start position. [0..n) */
+    int qEnd;                           /* Query end position. */
+    int tEnd;                           /* Target end position. */
+    char *qSym;                         /* Query letters (including '-') */
+    char *tSym;                         /* Target letters (including '-') */
+    };
+
+struct blastFile *blastFileReadAll(char *fileName);
+/* Read all blast alignment in file. */
+
+struct blastFile *blastFileOpenVerify(char *fileName);
+/* Open file, read and verify header. */
+
+struct blastQuery *blastFileNextQuery(struct blastFile *bf);
+/* Read all alignments associated with next query.  Return NULL at EOF. */
+
+struct blastGappedAli *blastFileNextGapped(struct blastFile *bf, struct blastQuery *bq);
+/* Read in next gapped alignment.   Does *not* put it on bf->gapped list. 
+ * Return NULL at EOF or end of query. */
+
+struct blastBlock *blastFileNextBlock(struct blastFile *bf, 
+	struct blastQuery *bq, struct blastGappedAli *bga);
+/* Read in next blast block.  Return NULL at EOF or end of
+ * gapped alignment. */
+
+void blastFileFree(struct blastFile **pBf);
+/* Free blast file. */
+
+void blastFileFreeList(struct blastFile **pList);
+/* Free list of blast files. */
+
+void blastQueryFree(struct blastQuery **pBq);
+/* Free single blastQuery. */
+
+void blastQueryFreeList(struct blastQuery **pList);
+/* Free list of blastQuery's. */
+
+void blastGappedAliFree(struct blastGappedAli **pBga);
+/* Free blastGappedAli. */
+
+void blastGappedAliFreeList(struct blastGappedAli **pList);
+/* Free blastGappedAli list. */
+
+void blastBlockFree(struct blastBlock **pBb);
+/* Free a single blastBlock. */
+
+void blastBlockFreeList(struct blastBlock **pList);
+/* Free a list of blastBlocks. */
+
+void blastBlockPrint(struct blastBlock* bb, FILE* out);
+/* print a BLAST block for debugging purposes  */
+
+void blastGappedAliPrint(struct blastGappedAli* ba, FILE* out);
+/* print a BLAST gapped alignment for debugging purposes  */
+
+void blastQueryPrint(struct blastQuery *bq, FILE* out);
+/* print a BLAST query for debugging purposes  */
+
+#endif /* BLASTPARSE_H */
+
diff --git a/inc/boxClump.h b/inc/boxClump.h
new file mode 100644
index 0000000..93d0c7e
--- /dev/null
+++ b/inc/boxClump.h
@@ -0,0 +1,41 @@
+/* boxClump - put together 2 dimensional boxes that
+ * overlap with each other into clumps. */
+
+#ifndef BOXCLUMP_H
+#define BOXCLUMP_H
+
+struct boxIn
+/* Input to box clumper. */
+    {
+    struct boxIn *next;		 /* Next in list. */
+    void *data;			 /* Some user-associated data. */
+    int qStart, qEnd;		 /* Range covered in query. */
+    int tStart, tEnd;		 /* Range covered in target. */
+    };
+
+struct boxClump
+/* Output of box clumper. */
+    {
+    struct boxClump *next;	 /* Next in list. */
+    struct boxIn *boxList;	 /* List of boxes in this clump. */
+    int boxCount;		 /* Count of boxes in this clump. */
+    int qStart, qEnd;		 /* Expanse of clump in query. */
+    int tStart, tEnd;		 /* Expanse of clump in target. */
+    };
+
+void boxClumpFree(struct boxClump **pClump);
+/* Free boxClump. */
+
+void boxClumpFreeList(struct boxClump **pList);
+/* Free list of boxClumps. */
+
+int boxClumpCmpCount(const void *va, const void *vb);
+/* Compare to sort based on count of boxes. */
+
+struct boxClump *boxFindClumps(struct boxIn **pBoxList);
+/* Convert list of boxes to a list of clumps.  Clumps
+ * are collections of boxes that overlap.  Note that
+ * the original boxList is overwritten as the boxes
+ * are moved from it to the clumps. */
+
+#endif /* BOXCLUMP_H */
diff --git a/inc/boxLump.h b/inc/boxLump.h
new file mode 100644
index 0000000..55d5ae9
--- /dev/null
+++ b/inc/boxLump.h
@@ -0,0 +1,25 @@
+/* boxLump - This will lump together boxes that overlap into the smallest
+ * box that encompasses the overlap.  It will put other boxes that 
+ * fit in the encompassing box in there too. 
+ *   It works by projecting the box list along one dimension at a
+ * time looking for gaps between boxes. This is similar in function
+ * to boxFindClumps, but a bit less precise, and quite a bit faster.
+ * in some important cases. */
+
+#ifndef BOXLUMP_H
+#define BOXLUMP_H
+
+#ifndef BOXCLUMP_H
+#include "boxClump.h"
+#endif
+
+struct boxClump *boxLump(struct boxIn **pBoxList);
+/* Convert list of boxes to a list of lumps.  The lumps
+ * are a smaller number of boxes that between them contain
+ * all of the input boxes.  Note that
+ * the original boxList is overwritten as the boxes
+ * are moved from it to the lumps. */
+
+#endif /* BOXLUMP_H */
+
+
diff --git a/inc/bwgInternal.h b/inc/bwgInternal.h
new file mode 100644
index 0000000..fab20ab
--- /dev/null
+++ b/inc/bwgInternal.h
@@ -0,0 +1,113 @@
+/* bwgInternal - stuff to create and use bigWig files.  Generally you'll want to use the
+ * simpler interfaces in the bigWig module instead.  This file is good reading though
+ * if you want to extend the bigWig interface, or work with bigWig files directly
+ * without going through the Kent library. */
+
+#ifndef BIGWIGFILE_H
+#define BIGWIGFILE_H
+
+enum bwgSectionType 
+/* Code to indicate section type. */
+    {
+    bwgTypeBedGraph=1,
+    bwgTypeVariableStep=2,
+    bwgTypeFixedStep=3,
+    };
+
+struct bwgBedGraphItem
+/* An bedGraph-type item in a bwgSection. */
+    {
+    struct bwgBedGraphItem *next;	/* Next in list. */
+    bits32 start,end;		/* Range of chromosome covered. */
+    float val;			/* Value. */
+    };
+
+struct bwgVariableStepItem
+/* An variableStep type item in a bwgSection. */
+    {
+    struct bwgVariableStepItem *next;	/* Next in list. */
+    bits32 start;		/* Start position in chromosome. */
+    float val;			/* Value. */
+    };
+
+struct bwgVariableStepPacked
+/* An variableStep type item in a bwgSection. */
+    {
+    bits32 start;		/* Start position in chromosome. */
+    float val;			/* Value. */
+    };
+
+struct bwgFixedStepItem
+/* An fixedStep type item in a bwgSection. */
+    {
+    struct bwgFixedStepItem *next;	/* Next in list. */
+    float val;			/* Value. */
+    };
+
+struct bwgFixedStepPacked
+/* An fixedStep type item in a bwgSection. */
+    {
+    float val;			/* Value. */
+    };
+
+union bwgItem
+/* Union of item pointers for all possible section types. */
+    {
+    struct bwgBedGraphItem *bedGraphList;		/* A linked list */
+    struct bwgFixedStepPacked *fixedStepPacked;		/* An array */
+    struct bwgVariableStepPacked *variableStepPacked;	/* An array */
+    /* No packed format for bedGraph... */
+    };
+
+struct bwgSection
+/* A section of a bigWig file - all on same chrom.  This is a somewhat fat data
+ * structure used by the bigWig creation code.  See also bwgSection for the
+ * structure returned by the bigWig reading code. */
+    {
+    struct bwgSection *next;		/* Next in list. */
+    char *chrom;			/* Chromosome name. */
+    bits32 start,end;			/* Range of chromosome covered. */
+    enum bwgSectionType type;
+    union bwgItem items;		/* List/array of items in this section. */
+    bits32 itemStep;			/* Step within item if applicable. */
+    bits32 itemSpan;			/* Item span if applicable. */
+    bits16 itemCount;			/* Number of items in section. */
+    bits32 chromId;			/* Unique small integer value for chromosome. */
+    bits64 fileOffset;			/* Offset of section in file. */
+    };
+
+struct bwgSectionHead
+/* A header from a bigWig file section - similar to above bug what is on disk. */
+    {
+    bits32 chromId;	/* Chromosome short identifier. */
+    bits32 start,end;	/* Range covered. */
+    bits32 itemStep;	/* For some section types, the # of bases between items. */
+    bits32 itemSpan;	/* For some section types, the # of bases in each item. */
+    UBYTE type;		/* Type byte. */
+    UBYTE reserved;	/* Always zero for now. */
+    bits16 itemCount;	/* Number of items in block. */
+    };
+
+void bwgSectionHeadFromMem(char **pPt, struct bwgSectionHead *head, boolean isSwapped);
+/* Read section header. */
+
+
+int bwgSectionCmp(const void *va, const void *vb);
+/* Compare to sort based on chrom,start,end.  */
+
+struct bwgSection *bwgParseWig(
+	char *fileName,       /* Name of ascii wig file. */
+	boolean clipDontDie,  /* Skip items outside chromosome rather than aborting. */
+	struct hash *chromSizeHash,  /* If non-NULL items checked to be inside chromosome. */
+	int maxSectionSize,   /* Biggest size of a section.  100 - 100,000 is usual range. */
+	struct lm *lm);	      /* Memory pool to allocate from. */
+/* Parse out ascii wig file - allocating memory in lm. */
+
+int bwgAverageResolution(struct bwgSection *sectionList);
+/* Return the average resolution seen in sectionList. */
+
+struct bbiSummary *bwgReduceSectionList(struct bwgSection *sectionList, 
+	struct bbiChromInfo *chromInfoArray, int reduction);
+/* Return summary of section list reduced by given amount. */
+
+#endif /* BIGWIGFILE_H */
diff --git a/inc/cda.h b/inc/cda.h
new file mode 100644
index 0000000..049c1f0
--- /dev/null
+++ b/inc/cda.h
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* cda.h - cDNA Alignment structure.  This stores all the info except
+ * the bases themselves on an cDNA alignment. */
+
+#ifndef CDA_H
+#define CDA_H
+
+#ifndef MEMGFX_H
+#include "memgfx.h"
+#endif 
+
+#ifndef FUZZYFIND_H
+#include "fuzzyFind.h"
+#endif
+
+struct cdaBlock
+    {
+    int nStart, nEnd;           /* Start and end position in cDNA. */
+    int hStart, hEnd;           /* Start and end position on chromosome. */
+    UBYTE startGood, endGood;   /* Number of bases matching perfectly on end */
+    UBYTE midScore;             /* 0-255  255 is perfect. */
+    };
+
+struct cdaAli
+    {
+    struct cdaAli *next;
+    char *name;
+    int baseCount;
+    short milliScore;               /* Score 0-1000 */
+    bits16 chromIx;                 /* On disk as just a UBYTE */
+    char strand;                    /* Strand of chromosome cDNA aligns with + or - */
+    char direction;                 /* Direction of cDNA relative to transcription + or - */
+    UBYTE isEmbryonic;
+    UBYTE hasIntrons;
+    int orientation;                /* +1 or -1 depending on whether *clone* is + or - WRT chrom . */
+                                    /* New and perhaps not always respected. */
+    int chromStart, chromEnd;
+    short blockCount;               /* Number of blocks. */
+    struct cdaBlock *blocks;        /* Dynamically allocated array. */
+    };
+
+boolean cdaCloneIsReverse(struct cdaAli *cda);
+/* Returns TRUE if clone (.3/.5 pair) aligns on reverse strand. */
+
+char cdaCloneStrand(struct cdaAli *cda);
+/* Return '+' or '-' depending on the strand that clone (.3/.5 pair) aligns on. */
+
+char cdaDirChar(struct cdaAli *cda, char chromStrand);
+/* Return '>' or '<' or ' ' depending whether cDNA is going same, opposite, or
+ * unknown alignment as the chromosome strand. */
+
+char *cdaLoadString(FILE *f);
+/* Load in a string from CDA file. */
+
+void cdaReadBlock(FILE *f, struct cdaBlock *block);
+/* Read one block from cda file. */
+
+FILE *cdaOpenVerify(char *fileName);
+/* Call this to open file and verify signature, then call cdaLoadOne
+ * which returns NULL at EOF. This file type is created by binGood.exe. */
+
+struct cdaAli *cdaLoadOne(FILE *f);
+/* Load one cdaAli from file.  Assumes file pointer is correctly positioned.
+ * either by cdaOpenVerify or a previous cdaLoadOne.  Returns NULL at EOF. */
+
+void cdaFixChromStartEnd(struct cdaAli *cda);
+/* Loop through blocks and figure out and fill in chromStart
+ * and chromEnd. */
+
+void cdaCoalesceBlocks(struct cdaAli *ca);
+/* Coalesce blocks separated by small amounts of noise. */
+
+void cdaCoalesceFast(struct cdaAli *ca);
+/* Coalesce blocks as above, but don't update the score. */
+
+void cdaShowAlignmentTrack(struct memGfx *mg, 
+    int xOff, int yOff, int width, int height,  Color goodColor, Color badColor,
+    int dnaSize, int dnaOffset, struct cdaAli *cda, char repeatChar);
+/* Draw alignment on a horizontal track of picture. */
+
+void cdaRcOne(struct cdaAli *cda, int dnaStart, int baseCount);
+/* Reverse complement one cda. DnaStart is typically display window start. */
+
+void cdaRcList(struct cdaAli *cdaList, int dnaStart, int baseCount);
+/* Reverse complement cda list. */
+
+void cdaFreeAli(struct cdaAli *ca);
+/* Free a single cdaAli. */
+
+void cdaFreeAliList(struct cdaAli **pList);
+/* Free list of cdaAli. */
+
+struct cdaAli *cdaAliFromFfAli(struct ffAli *aliList, 
+    DNA *needle, int needleSize, DNA *hay, int haySize, boolean isRc);
+/* Convert from ffAli to cdaAli format. */
+
+void cdaWrite(char *fileName, struct cdaAli *cdaList);
+/* Write out a cdaList to a cda file. */
+
+#endif /* CDA_H */
diff --git a/inc/cgi_build_rules.mk b/inc/cgi_build_rules.mk
new file mode 100644
index 0000000..143b9ad
--- /dev/null
+++ b/inc/cgi_build_rules.mk
@@ -0,0 +1,36 @@
+#	Common set of build rules for CGI binaries
+
+my:: compile
+	chmod a+rx $A${EXE}
+	mv $A${EXE} ${CGI_BIN}-${USER}/$A
+
+alpha:: strip
+	mv $A${EXE} ${CGI_BIN}/$A
+
+beta:: strip
+	mv $A${EXE} ${CGI_BIN}-beta/$A
+
+# don't actually strip so we can get stack traces
+strip::  compile
+	chmod g+w $A${EXE}
+	chmod a+rx $A${EXE}
+
+install::  strip
+	@if [ ! -d "${DESTDIR}${CGI_BIN}" ]; then \
+		${MKDIR} "${DESTDIR}${CGI_BIN}"; \
+	fi
+	rm -f ${DESTDIR}${CGI_BIN}/$A
+	mv $A${EXE} ${DESTDIR}${CGI_BIN}/$A
+
+debug:: $O
+	${CC} ${COPT} ${CFLAGS} $O ${MYLIBS} ${L}
+	mv ${AOUT} $A${EXE}
+
+lib::
+	cd ../../lib; make
+
+clean::
+	rm -f $O $A${EXE}
+
+tags::
+	ctags *.h *.c ../lib/*.c ../inc/*.h ../../lib/*.c ../../inc/*.h
diff --git a/inc/chain.h b/inc/chain.h
new file mode 100644
index 0000000..6be0f2a
--- /dev/null
+++ b/inc/chain.h
@@ -0,0 +1,163 @@
+/* chain - pairwise alignments that can include gaps in both
+ * sequences at once.  This is similar in many ways to psl,
+ * but more suitable to cross species genomic comparisons. */
+
+#ifndef CHAIN_H
+#define CHAIN_H
+
+#ifndef LINEFILE_H
+#include "linefile.h"
+#endif
+
+
+#ifndef BITS_H
+#include "bits.h"
+#endif
+
+struct cBlock
+/* A gapless part of a chain. */
+    {
+    struct cBlock *next;	/* Next in list. */
+    int tStart,tEnd;		/* Range covered in target. */
+    int qStart,qEnd;		/* Range covered in query. */
+    int score;	 	 	/* Score of block. */
+    void *data;			/* Some associated data pointer. */
+    };
+
+int cBlockCmpQuery(const void *va, const void *vb);
+/* Compare to sort based on query start. */
+
+int cBlockCmpTarget(const void *va, const void *vb);
+/* Compare to sort based on target start. */
+
+int cBlockCmpBoth(const void *va, const void *vb);
+/* Compare to sort based on query, then target. */
+
+int cBlockCmpDiagQuery(const void *va, const void *vb);
+/* Compare to sort based on diagonal, then query. */
+
+void cBlocksAddOffset(struct cBlock *blockList, int qOff, int tOff);
+/* Add offsets to block list. */
+
+struct cBlock *cBlocksFromAliSym(int symCount, char *qSym, char *tSym, 
+        int qPos, int tPos);
+/* Convert alignment from alignment symbol (bases and dashes) format 
+ * to a list of chain blocks.  The qPos and tPos correspond to the start
+ * in the query and target sequences of the first letter in  qSym and tSym. */
+
+struct chain
+/* A chain of blocks.  Used for output of chainBlocks. */
+    {
+    struct chain *next;	  	  /* Next in list. */
+    struct cBlock *blockList;      /* List of blocks. */
+    double score;	  	  /* Total score for chain. */
+    char *tName;		  /* target name, allocated here. */
+    int tSize;			  /* Overall size of target. */
+    /* tStrand always + */
+    int tStart,tEnd;		  /* Range covered in target. */
+    char *qName;		  /* query name, allocated here. */
+    int qSize;			  /* Overall size of query. */
+    char qStrand;		  /* Query strand. */
+    int qStart,qEnd;		  /* Range covered in query. */
+    int id;			  /* ID of chain in file. */
+    };
+
+void chainFree(struct chain **pChain);
+/* Free up a chain. */
+
+void chainFreeList(struct chain **pList);
+/* Free a list of dynamically allocated chain's */
+
+int chainCmpScore(const void *va, const void *vb);
+/* Compare to sort based on score. */
+
+int chainCmpScoreDesc(const void *va, const void *vb);
+/* Compare to sort based on score descending. */
+
+int chainCmpTarget(const void *va, const void *vb);
+/* Compare to sort based on target position. */
+
+int chainCmpQuery(const void *va, const void *vb);
+/* Compare to sort based on query chrom and start osition. */
+
+void chainWrite(struct chain *chain, FILE *f);
+/* Write out chain to file in dense format. */
+
+void chainWriteAll(struct chain *chainList, FILE *f);
+/* Write all chains to file. */
+
+void chainWriteLong(struct chain *chain, FILE *f);
+/* Write out chain to file in more verbose format. */
+
+void chainWriteHead(struct chain *chain, FILE *f);
+/* Write chain before block/insert list. */
+
+struct chain *chainRead(struct lineFile *lf);
+/* Read next chain from file.  Return NULL at EOF. 
+ * Note that chain block scores are not filled in by
+ * this. */
+
+struct chain *chainReadChainLine(struct lineFile *lf);
+/* Read line that starts with chain.  Allocate memory
+ * and fill in values.  However don't read link lines. */
+
+void chainReadBlocks(struct lineFile *lf, struct chain *chain);
+/* Read in chain blocks from file. */
+
+void chainIdReset();
+/* Reset chain id. */
+
+void chainIdNext(struct chain *chain);
+/* Add id to chain. */
+
+void chainSwap(struct chain *chain);
+/* Swap target and query side of chain. */
+
+struct hash *chainReadUsedSwap(char *fileName, boolean swapQ, Bits *bits);
+/* Read chains that are marked as used in the 
+ * bits array (which may be NULL) into a hash keyed by id. */
+
+struct hash *chainReadAllSwap(char *fileName, boolean swapQ);
+/* Read chains into a hash keyed by id. 
+ * Set swapQ to True to read chain by query. */
+    
+struct hash *chainReadAll(char *fileName);
+/* Read chains into a hash keyed by id. */
+    
+struct hash *chainReadAllWithMeta(char *fileName, FILE *f);
+/* Read chains into a hash keyed by id and outputs meta data */
+
+struct chain *chainFind(struct hash *hash, int id);
+/* Find chain in hash, return NULL if not found */
+
+struct chain *chainLookup(struct hash *hash, int id);
+/* Find chain in hash. */
+
+void chainSubsetOnT(struct chain *chain, int subStart, int subEnd, 
+    struct chain **retSubChain,  struct chain **retChainToFree);
+/* Get subchain of chain bounded by subStart-subEnd on 
+ * target side.  Return result in *retSubChain.  In some
+ * cases this may be the original chain, in which case
+ * *retChainToFree is NULL.  When done call chainFree on
+ * *retChainToFree.  The score and id fields are not really
+ * properly filled in. */
+
+void chainFastSubsetOnT(struct chain *chain, struct cBlock *firstBlock,
+	int subStart, int subEnd, struct chain **retSubChain,  struct chain **retChainToFree);
+/* Get subchain as in chainSubsetOnT. Pass in initial block that may
+ * be known from some index to speed things up. */
+
+void chainSubsetOnQ(struct chain *chain, int subStart, int subEnd, 
+    struct chain **retSubChain,  struct chain **retChainToFree);
+/* Get subchain of chain bounded by subStart-subEnd on 
+ * query side.  Return result in *retSubChain.  In some
+ * cases this may be the original chain, in which case
+ * *retChainToFree is NULL.  When done call chainFree on
+ * *retChainToFree.  The score and id fields are not really
+ * properly filled in. */
+
+void chainRangeQPlusStrand(struct chain *chain, int *retQs, int *retQe);
+/* Return range of bases covered by chain on q side on the plus
+ * strand. */
+
+#endif /* CHAIN_H */
diff --git a/inc/chainBlock.h b/inc/chainBlock.h
new file mode 100644
index 0000000..f9158de
--- /dev/null
+++ b/inc/chainBlock.h
@@ -0,0 +1,42 @@
+/* chainBlock - Chain together scored blocks from an alignment
+ * into scored chains.  Internally this uses a kd-tree and a
+ * varient of an algorithm suggested by Webb Miller and further
+ * developed by Jim Kent. */
+
+#ifndef CHAINBLOCK_H
+#define CHAINBLOCK_H
+
+#ifndef CHAIN_H
+#include "chain.h"
+#endif
+
+typedef int (*GapCost)(int dq, int dt, void *gapData);
+/* A function that returns gap cost (gaps can be in both dimensions
+ * at once!) */
+
+typedef int (*ConnectCost)(struct cBlock *a, struct cBlock *b, void *gapData);
+/* A function that returns gap cost as well as any penalty
+ * from a and b overlapping. */
+
+struct chain *chainBlocks(
+	char *qName, int qSize, char qStrand,	/* Info on query sequence */
+	char *tName, int tSize, 		/* Info on target. */
+	struct cBlock **pBlockList, 		/* Unordered ungapped alignments. */
+	ConnectCost connectCost, 		/* Calculate cost to connect nodes. */
+	GapCost gapCost, 			/* Cost for non-overlapping nodes. */
+	void *gapData, 				/* Passed through to connect/gapCosts */
+	FILE *details);				/* NULL except for debugging */
+/* Create list of chains from list of blocks.  The blockList will get
+ * eaten up as the blocks are moved from the list to the chain. 
+ * The list of chains returned is sorted by score. 
+ *
+ * The details FILE may be NULL, and is where additional information
+ * about the chaining is put.
+ *
+ * Note that the connectCost needs to adjust for possibly partially 
+ * overlapping blocks, and that these need to be taken out of the
+ * resulting chains in general.  This can get fairly complex.  Also
+ * the chains will need some cleanup at the end.  Use the chainConnect
+ * module to help with this.  See hg/mouseStuff/axtChain for example usage. */
+
+#endif /* CHAINBLOCK_H */
diff --git a/inc/chainConnect.h b/inc/chainConnect.h
new file mode 100644
index 0000000..0ee85d7
--- /dev/null
+++ b/inc/chainConnect.h
@@ -0,0 +1,60 @@
+/* chainConnect - Modules to figure out cost of connecting two blocks
+ * in a chain, and to help clean up overlapping blocks in a chain after
+ * main chainBlock call is done. */
+
+#ifndef CHAINCONNECT_H
+#define CHAINCONNECT_H
+
+struct chainConnect
+/* Structure to help figure out chain connection costs. */
+    {
+    struct dnaSeq *query;
+    struct dnaSeq *target;
+    struct axtScoreScheme *ss;
+    struct gapCalc *gapCalc;
+    };
+
+
+int chainConnectCost(struct cBlock *a, struct cBlock *b, 
+	struct chainConnect *cc);
+/* Calculate connection cost - including gap score
+ * and overlap adjustments if any. */
+
+int chainConnectGapCost(int dq, int dt, struct chainConnect *cc);
+/* Calculate cost of non-overlapping gap. */
+
+void chainRemovePartialOverlaps(struct chain *chain, 
+	struct dnaSeq *qSeq, struct dnaSeq *tSeq, int matrix[256][256]);
+/* If adjacent blocks overlap then find crossover points between them. */
+
+void chainMergeAbutting(struct chain *chain);
+/* Merge together blocks in a chain that abut each
+ * other exactly. */
+
+double chainScoreBlock(char *q, char *t, int size, int matrix[256][256]);
+/* Score block through matrix. */
+
+double chainCalcScore(struct chain *chain, struct axtScoreScheme *ss, 
+	struct gapCalc *gapCalc, struct dnaSeq *query, struct dnaSeq *target);
+/* Calculate chain score freshly. */
+
+double chainCalcScoreSubChain(struct chain *chain, struct axtScoreScheme *ss, 
+	struct gapCalc *gapCalc, struct dnaSeq *query, struct dnaSeq *target);
+/* Calculate chain score assuming query and target 
+   span the chained region rather than entire chrom. */
+
+void chainCalcBounds(struct chain *chain);
+/* Recalculate chain boundaries - setting qStart/qEnd/tStart/tEnd from
+ * a scan of blockList. */
+
+void cBlockFindCrossover(struct cBlock *left, struct cBlock *right,
+	struct dnaSeq *qSeq, struct dnaSeq *tSeq,  
+	int overlap, int matrix[256][256], int *retPos, int *retScoreAdjustment);
+/* Find ideal crossover point of overlapping blocks.  That is
+ * the point where we should start using the right block rather
+ * than the left block.  This point is an offset from the start
+ * of the overlapping region (which is the same as the start of the
+ * right block). */
+
+#endif /* CHAINCONNECT_H */
+
diff --git a/inc/chainToAxt.h b/inc/chainToAxt.h
new file mode 100644
index 0000000..3ac938b
--- /dev/null
+++ b/inc/chainToAxt.h
@@ -0,0 +1,15 @@
+/* chainToAxt - convert from chain to axt format. */
+
+#ifndef CHAINTOAXT_H
+#define CHAINTOAXT_H
+
+struct axt *chainToAxt(struct chain *chain, 
+	struct dnaSeq *qSeq, int qOffset,
+	struct dnaSeq *tSeq, int tOffset, int maxGap, int maxChain);
+/* Convert a chain to a list of axt's.  This will break
+ * where there is a double-sided gap in chain, or 
+ * where there is a single-sided gap greater than maxGap, or 
+ * where there is a chain longer than maxChain.
+ */
+
+#endif /* CHAINTOAXT_H */
diff --git a/inc/chainToPsl.h b/inc/chainToPsl.h
new file mode 100644
index 0000000..e5ed5b2
--- /dev/null
+++ b/inc/chainToPsl.h
@@ -0,0 +1,28 @@
+/* chainToPsl - convert between chains and psl.  Both of these
+ * are alignment formats that can handle gaps in both strands
+ * and do not include the sequence itself. */
+
+#ifndef CHAINTOPSL_H
+#define CHAINTOPSL_H
+
+#ifndef PSL_H
+#include "psl.h"
+#endif
+
+#ifndef CHAINBLOCK_H
+#include "chainBlock.h"
+#endif
+
+struct psl *chainToPsl(struct chain *chain);
+/* chainToPsl - convert chain to psl.  This does not fill in
+ * the match, repMatch, mismatch, and N fields since it needs
+ * the sequence for that.  It does fill in the rest though. */
+
+struct psl *chainToFullPsl(struct chain *chain, 
+	struct dnaSeq *query,   /* Forward query sequence. */
+	struct dnaSeq *rQuery,	/* Reverse complemented query sequence. */
+	struct dnaSeq *target);
+/* Convert chainList to pslList, filling in matches, N's etc. */
+
+#endif /* CHAINTOPSL_H */
+
diff --git a/inc/cheapcgi.h b/inc/cheapcgi.h
new file mode 100644
index 0000000..413320a
--- /dev/null
+++ b/inc/cheapcgi.h
@@ -0,0 +1,506 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* Cheapcgi.h - turns variables passed from the web form into
+ * something that C understands. */
+
+#ifndef CHEAPCGI_H
+#define CHEAPCGI_H
+
+#ifndef DYSTRING_H
+#include "dystring.h"
+#endif
+
+#ifndef HASH_H
+#include "hash.h"
+#endif
+
+#define COLOR_BG_DEFAULT         "#FFFEE8"
+#define COLOR_BG_ALTDEFAULT      "#FFF9D2"
+#define COLOR_BG_DEFAULT_DARKER  "#FCECC0"
+#define COLOR_BG_DEFAULT_DARKEST "#EED5B7"
+#define COLOR_BG_GHOST           "#EEEEEE"
+#define COLOR_BG_PALE            "#F8F8F8"
+#define COLOR_BG_HEADER_LTBLUE   "#D9E4F8"
+#define COLOR_DARKGREEN          "#008800"
+#define COLOR_LTGREEN            "#CCFFCC"
+#define COLOR_DARKBLUE           "#000088"
+#define COLOR_BLUE_BUTTON        "#91B3E6"
+#define COLOR_DARKGREY           "#666666"
+#define COLOR_LTGREY             "#CCCCCC"
+#define COLOR_YELLOW             "#FFFF00"
+#define COLOR_LTYELLOW           "#FFF380"
+#define COLOR_WHITE              "#FFFFFF"
+#define COLOR_RED                "#AA0000"
+#define COLOR_TRACKLIST_LEVEL1   COLOR_BG_DEFAULT
+#define COLOR_TRACKLIST_LEVEL2   COLOR_BG_ALTDEFAULT
+#define COLOR_TRACKLIST_LEVEL3   COLOR_BG_DEFAULT_DARKER
+#define COLOR_TRACKLIST_LEVEL4   COLOR_BG_DEFAULT_DARKEST
+
+void initSigHandlers(boolean dumpStack);
+/* set handler for various terminal signals for logging purposes.
+ * if dumpStack is TRUE, attempt to dump the stack. */
+
+struct cgiVar
+/* Info on one cgi variable. */
+    {
+    struct cgiVar *next;	/* Next in list. */
+    char *name;			/* Name - allocated in hash. */
+    char *val;  		/* Value - also not allocated here. */
+    boolean saved;		/* True if saved. */
+    };
+
+struct cgiVar* cgiVarList();
+/* return the list of cgiVar's */
+
+char *findCookieData(char *varName);
+/* Get the string associated with varName from the cookie string. */
+
+void dumpCookieList();
+/* Print out the cookie list. */
+
+boolean cgiIsOnWeb();
+/* Return TRUE if looks like we're being run as a CGI. */
+
+char *cgiRequestMethod();
+/* Return CGI REQUEST_METHOD (such as 'GET/POST/PUT/DELETE/HEAD') */
+
+char *cgiRequestUri();
+/* Return CGI REQUEST_URI */
+
+char *cgiRequestContentLength();
+/* Return HTTP REQUEST CONTENT_LENGTH if available*/
+
+char *cgiScriptName();
+/* Return name of script so libs can do context-sensitive stuff. */
+
+char *cgiServerName();
+/* Return name of server, better to use cgiServerNamePort() for
+   actual URL construction */
+
+char *cgiServerPort();
+/* Return port number of server */
+
+char *cgiServerNamePort();
+/* Return name of server with port if different than 80 */
+
+char *cgiRemoteAddr();
+/* Return IP address of client (or "unknown"). */
+
+char *cgiUserAgent();
+/* Return remote user agent (HTTP_USER_AGENT) or NULL if remote user agent is not known */
+
+enum browserType
+/* How to look at a track. */
+    {
+    btUnknown=0, // Not yet known
+    btOpera=1,   // Opera
+    btIE=2,      // MS Internet Explorer
+    btFF=3,      // Firefox
+    btChrome=4,  // Google Chrome
+    btSafari=5,  // Safari
+    btOther=6    // Anything else
+    };
+
+enum osType
+/* How to look at a track. */
+    {
+    osUnknown=0, // Not yet known
+    osWindows=1, // The evil empire
+    osLinux=2,   // Workhorse
+    osMac=3,     // ashion or Religion
+    osOther=4    // Anything else
+    };
+
+enum browserType cgiClientBrowser(char **browserQualifier, enum osType *clientOs, 
+                                  char **clientOsQualifier);
+/* These routines abort the html output if the input isn't
+ * there or is misformatted. */
+#define cgiBrowser() cgiClientBrowser(NULL,NULL,NULL)
+
+char *cgiString(char *varName);
+int cgiInt(char *varName);
+double cgiDouble(char *varName);
+
+boolean cgiBoolean(char *varName);
+/* The cgiBoolean is a little problematic.  If the variable
+ * is TRUE it exists, but if it is false it is simply not
+ * defined.   cgiBoolean() thus returns FALSE if the CGI
+ * variable doesn't exist or if it is set to FALSE.  To
+ * work around this when need be use cgiBooleanDefined(),
+ * which relies on the fact that when we define a boolean
+ * variable we also define a hidden variable. */
+
+boolean cgiBooleanDefined(char *name);
+/* Return TRUE if boolean variable is defined (by
+ * checking for shadow). */
+
+char *cgiBooleanShadowPrefix();
+/* Prefix for shadow variable set with boolean variables. */
+
+void cgiMakeHiddenBoolean(char *name, boolean on);
+/* Make hidden boolean variable. Also make a shadow hidden variable so we
+ * can distinguish between variable not present and
+ * variable set to false. */
+
+char *cgiMultListShadowPrefix();
+/* Prefix for shadow variable set with multi-select inputs. */
+
+int cgiIntExp(char *varName);
+/* Evaluate an integer expression in varName and
+ * return value. */
+
+char *cgiOptionalString(char *varName);
+/* Return value of string if it exists in cgi environment, else NULL */
+
+char *cgiUsualString(char *varName, char *usual);
+/* Return value of string if it exists in cgi environment.
+ * Otherwiser return 'usual' */
+
+struct slName *cgiStringList(char *varName);
+/* Find list of cgi variables with given name.  This
+ * may be empty.  Free result with slFreeList(). */
+
+int cgiOptionalInt(char *varName, int defaultVal);
+/* This returns value of varName if it exists in cgi environment,
+ * otherwise it returns defaultVal. */
+
+double cgiOptionalDouble(char *varName, double defaultVal);
+/* Returns double value. */
+
+#define cgiUsualInt cgiOptionalInt
+#define cgiUsualDouble cgiOptionalDouble
+
+struct cgiChoice
+/* Choice table */
+    {
+    char *name;
+    int value;
+    };
+
+int cgiOneChoice(char *varName, struct cgiChoice *choices, int choiceSize);
+/* Returns value associated with string variable in choice table. */
+
+boolean cgiVarExists(char *varName);
+/* Returns TRUE if the variable was passed in. */
+
+void cgiBadVar(char *varName);
+/* Complain about a variable that's not there. */
+
+void cgiDecode(char *in, char *out, int inLength);
+/* Decode from cgi pluses-for-spaces format to normal.
+ * Out will be a little shorter than in typically. */
+
+char *cgiEncode(char *inString);
+/* Return a cgi-encoded version of inString.
+ * Alphanumerics kept as is, space translated to plus,
+ * and all other characters translated to %hexVal.
+ * You can free return value with freeMem(). */
+
+char *cgiEncodeFull(char *inString);
+/* Return a cgi-encoded version of inString (no + for space!).
+ * Alphanumerics/./_ kept as is and all other characters translated to
+ * %hexVal. */
+
+void cgiMakeButtonWithMsg(char *name, char *value, char *msg);
+/* Make 'submit' type button. Display msg on mouseover, if present*/
+
+void cgiMakeButtonWithOnClick(char *name, char *value, char *msg, char *onClick);
+/* Make 'submit' type button, with onclick javascript */
+
+void cgiMakeButton(char *name, char *value);
+/* Make 'submit' type button. */
+
+void cgiMakeOnClickButton(char *command, char *value);
+/* Make 'push' type button with client side onClick (java)script. */
+
+void cgiMakeOnClickSubmitButton(char *command, char *name, char *value);
+/* Make submit button with both variable name and value with client side
+ * onClick (java)script. */
+
+void cgiMakeOptionalButton(char *name, char *value, boolean disabled);
+/* Make 'submit' type button that can be disabled. */
+
+void cgiMakeRadioButton(char *name, char *value, boolean checked);
+/* Make radio type button.  A group of radio buttons should have the
+ * same name but different values.   The default selection should be
+ * sent with checked on. */
+
+void cgiMakeOnClickRadioButton(char *name, char *value, boolean checked,
+                                        char *command);
+/* Make radio type button with onClick command.
+ *  A group of radio buttons should have the
+ * same name but different values.   The default selection should be
+ * sent with checked on. */
+
+void cgiMakeCheckBoxUtil(char *name, boolean checked, char *msg, char *id);
+/* Make check box - can be called directly, though it was originally meant
+ * as the common code for all lower level checkbox routines.
+ * However, it's util functionality has been taken over by
+ * cgiMakeCheckBoxWithIdAndOptionalHtml() */
+
+void cgiMakeCheckBox(char *name, boolean checked);
+/* Make check box. */
+
+void cgiMakeCheckBoxWithMsg(char *name, boolean checked, char *msg);
+/* Make check box, which includes a msg. */
+
+void cgiMakeCheckBoxWithId(char *name, boolean checked, char *id);
+/* Make check box, which includes an ID. */
+
+void cgiMakeCheckBoxJS(char *name, boolean checked, char *javascript);
+/* Make check box with javascript */
+
+void cgiMakeCheckBoxIdAndJS(char *name, boolean checked, char *id, char *javascript);
+/* Make check box with ID and javascript. */
+
+void cgiMakeCheckBoxFourWay(char *name, boolean checked, boolean enabled, char *id, 
+                            char *classes, char *moreHtml);
+/* Make check box - with fourWay functionality (checked/unchecked by enabled/disabled
+ * Also makes a shadow hidden variable that supports the 2 boolean states. */
+
+void cgiMakeTextArea(char *varName, char *initialVal, int rowCount, int columnCount);
+/* Make a text area with area rowCount X columnCount and with text: intialVal. */
+
+void cgiMakeTextAreaDisableable(char *varName, char *initialVal, int rowCount, int columnCount, boolean disabled);
+/* Make a text area that can be disabled. The rea has rowCount X
+ * columnCount and with text: intialVal */
+
+void cgiMakeTextVar(char *varName, char *initialVal, int charSize);
+/* Make a text control filled with initial value.  If charSize
+ * is zero it's calculated from initialVal size. */
+
+void cgiMakeTextVarWithExtraHtml(char *varName, char *initialVal, int width, char *extra);
+/* Make a text control filled with initial value. */
+
+void cgiMakeOnKeypressTextVar(char *varName, char *initialVal, int charSize,
+			      char *script);
+/* Make a text control filled with initial value, with a (java)script
+ * to execute every time a key is pressed.  If charSize is zero it's
+ * calculated from initialVal size. */
+
+void cgiMakeIntVar(char *varName, int initialVal, int maxDigits);
+/* Make a text control filled with initial integer value.  */
+
+#define NO_VALUE            -96669
+void cgiMakeIntVarInRange(char *varName, int initialVal, char *title, int width, 
+                          char *min, char *max);
+/* Make a integer control filled with initial value.
+   If min and/or max are non-NULL will enforce range
+   Requires utils.js jQuery.js and inputBox class */
+void cgiMakeIntVarWithLimits(char *varName, int initialVal, char *title, int width, 
+                             int min, int max);
+void cgiMakeIntVarWithMin(char *varName, int initialVal, char *title, int width, int min);
+void cgiMakeIntVarWithMax(char *varName, int initialVal, char *title, int width, int max);
+#define cgiMakeIntVarNoLimits(varName,initialVal,title,width) \
+        cgiMakeIntVarInRange(varName,initialVal,title,width,NULL,NULL)
+/* All four of these call cgiMakeIntVarInRange() and therefore require utils.js */
+
+void cgiMakeDoubleVar(char *varName, double initialVal, int maxDigits);
+/* Make a text control filled with initial floating-point value.  */
+
+void cgiMakeDoubleVarInRange(char *varName, double initialVal, char *title, int width, 
+                             char *min, char *max);
+/* Make a floating point control filled with initial value.
+   If min and/or max are non-NULL will enforce range
+   Requires utils.js jQuery.js and inputBox class */
+void cgiMakeDoubleVarWithLimits(char *varName, double initialVal, char *title, int width, 
+                                double min, double max);
+void cgiMakeDoubleVarWithMin(char *varName, double initialVal, char *title, int width, double min);
+void cgiMakeDoubleVarWithMax(char *varName, double initialVal, char *title, int width, double max);
+#define cgiMakeDoubleVarNoLimits(varName,initialVal,title,width) \
+        cgiMakeDoubleVarInRange(varName,initialVal,title,width,NULL,NULL)
+/* All four of these call cgiMakeDoubleVarInRange() and therefore require utils.js */
+
+void cgiMakeDropListClass(char *name, char *menu[], int menuSize, char *checked, char *class);
+/* Make a drop-down list with names and style sheet class. */
+
+void cgiMakeDropList(char *name, char *menu[], int menuSize, char *checked);
+/* Make a drop-down list with names.
+ * uses style "normalText" */
+
+void cgiMakeDropListClassWithStyleAndJavascript(char *name, char *menu[],
+                                                int menuSize, char *checked, char *class,
+                                                char *style,char *javascript);
+/* Make a drop-down list with names, text class, style and javascript. */
+
+void cgiMakeDropListClassWithStyle(char *name, char *menu[],
+	int menuSize, char *checked, char *class, char *style);
+/* Make a drop-down list with names, text class and style. */
+
+void cgiMakeDropListWithVals(char *name, char *menu[], char *values[],
+                         int menuSize, char *checked);
+/* Make a drop-down list with names and values. In this case checked
+ * corresponds to a value, not a menu. */
+
+void cgiMakeDropListFull(char *name, char *menu[], char *values[], int menuSize, char *checked, char *extraAttribs);
+/* Make a drop-down list with names and values. */
+
+void cgiDropDownWithTextValsAndExtra(char *name, char *text[], char *values[],
+                                     int count, char *selected, char *extra);
+/* Make a drop-down list with both text and values. */
+
+char *cgiMakeSelectDropList(boolean multiple, char *name, struct slPair *valsAndLabels,
+                            char *selected, char *anyAll,char *extraClasses, char *extraHtml);
+// Returns allocated string of HTML defining a drop-down select
+// (if multiple, REQUIRES ui-dropdownchecklist.js)
+// valsAndLabels: val (pair->name) must be filled in but label (pair->val) may be NULL.
+// selected: if not NULL is a val found in the valsAndLabels (multiple then comma delimited list).
+//           If null and anyAll not NULL, that will be selected
+// anyAll: if not NULL is the string for an initial option. It can contain val and label,
+//         delimited by a comma
+// extraHtml: if not NULL contains id, javascript calls and style.
+//            It does NOT contain class definitions
+#define cgiMakeMultiSelectDropList(name,valsAndLabels,selected,anyAll,extraClasses,extraHtml) \
+        cgiMakeSelectDropList(TRUE,(name),(valsAndLabels),(selected),(anyAll),\
+                              (extraClasses),(extraHtml))
+#define cgiMakeSingleSelectDropList(name,valsAndLabels,selected,anyAll,extraClasses,extraHtml) \
+        cgiMakeSelectDropList(FALSE,(name),(valsAndLabels),(selected),(anyAll),\
+                              (extraClasses),(extraHtml))
+
+void cgiMakeMultList(char *name, char *menu[], int menuSize, struct slName *checked, int length);
+/* Make a list of names which can have multiple selections.
+ * Same as drop-down list except "multiple" is added to select tag */
+
+void cgiMakeCheckboxGroup(char *name, char *menu[], int menuSize, struct slName *checked,
+			  int tableColumns);
+/* Make a table of checkboxes that have the same variable name but different
+ * values (same behavior as a multi-select input). */
+
+void cgiMakeCheckboxGroupWithVals(char *name, char *menu[], char *values[], int menuSize,
+				  struct slName *checked, int tableColumns);
+/* Make a table of checkboxes that have the same variable name but different
+ * values (same behavior as a multi-select input), with nice labels in menu[]. */
+
+void cgiMakeHiddenVarWithExtra(char *varName, char *string, char *extra);
+/* Store string in hidden input for next time around. */
+
+#define cgiMakeHiddenVar(name,val) cgiMakeHiddenVarWithExtra((name),(val),NULL)
+/* Store string in hidden input for next time around. */
+
+void cgiContinueHiddenVar(char *varName);
+/* Write CGI var back to hidden input for next time around.
+ * (if it exists). */
+
+void cgiContinueAllVars();
+/* Write back all CGI vars as hidden input for next time around. */
+
+void cgiVarExclude(char *varName);
+/* If varName exists, remove it. */
+
+void cgiVarExcludeExcept(char **varNames);
+/* Exclude all variables except for those in NULL
+ * terminated array varNames.  varNames may be NULL
+ * in which case nothing is excluded. */
+
+void cgiVarSet(char *varName, char *val);
+/* Set a cgi variable to a particular value. */
+
+struct dyString *cgiUrlString();
+/* Get URL-formatted that expresses current CGI variable state. */
+
+boolean cgiSpoof(int *pArgc, char *argv[]);
+/* Use the command line to set up things as if we were a CGI program.
+ * User types in command line (assuming your program called cgiScript)
+ * like:
+ *        cgiScript nonCgiArg1 var1=value1 var2=value2 var3=value3 nonCgiArg2
+ * or like
+ *        cgiScript nonCgiArg1 var1=value1&var2=value2&var3=value3 nonCgiArg2
+ * (The non-cgi arguments can occur anywhere.  The cgi arguments (all containing
+ * the character '=') are erased from argc/argv.  Normally you call this
+ *        cgiSpoof(&argc, argv);
+ */
+
+boolean cgiFromCommandLine(int *pArgc, char *argv[], boolean preferWeb);
+/* Use the command line to set up things as if we were a CGI program.
+ * If preferWeb is TRUE will choose real CGI variables over command
+ * line ones. */
+
+void useTempFile();
+/* tell cheapcgi to use temp files */
+
+boolean cgiFromFile(char *fileName);
+/* Set up a cgi environment using parameters stored in a file.
+ * Takes file with arguments in the form:
+ *       argument1=someVal
+ *       # This is a comment
+ *       argument2=someOtherVal
+ *       ...
+ * and puts them into the cgi environment so that the usual
+ * cgiGetVar() commands can be used. Useful when a program
+ * has a lot of possible parameters.
+ */
+
+boolean cgiParseInput(char *input, struct hash **retHash,
+	struct cgiVar **retList);
+/* Parse cgi-style input into a hash table and list.  This will alter
+ * the input data.  The hash table will contain references back
+ * into input, so please don't free input until you're done with
+ * the hash. Prints message and returns FALSE if there's an error.*/
+
+void cgiSimpleTableStart();
+/* start HTML table  -- no customization. Leaves room
+ * for a fancier implementation */
+
+void cgiTableEnd();
+/* end HTML table */
+
+void cgiMakeSubmitButton();
+/* Make 'submit' type button. */
+
+void cgiMakeResetButton();
+/* Make 'reset' type button. */
+
+void cgiMakeClearButton(char *form, char *field);
+/* Make button to clear a text field. */
+
+void cgiMakeFileEntry(char *name);
+/* Make file entry box/browser */
+
+void cgiSimpleTableRowStart();
+/* Start table row */
+
+void cgiTableRowEnd();
+/* End table row */
+
+void cgiSimpleTableFieldStart();
+/* Start table field */
+
+void cgiTableFieldStartAlignRight();
+/* Start table field */
+
+void cgiTableFieldEnd();
+/* End table field */
+
+void cgiTableField(char *text);
+/* Make table field entry */
+
+void cgiTableFieldWithMsg(char *text, char *msg);
+/* Make table field entry with mouseover */
+
+void cgiParagraph(char *text);
+/* Make text paragraph */
+
+void logCgiToStderr();
+/* Log useful CGI info to stderr */
+
+void cgiResetState();
+/* This is for reloading CGI settings multiple times in the same program
+ * execution.  No effect if state has not yet been initialized. */
+
+void cgiDown(float lines);
+// Drop down a certain number of lines (may be fractional)
+
+char *commonCssStyles();
+/* Returns a string of common CSS styles */
+
+char *javaScriptLiteralEncode(char *inString);
+/* Use backslash escaping on newline
+ * and quote chars, backslash and others.
+ * Intended that the encoded string will be
+ * put between quotes at a higher level and
+ * then interpreted by Javascript. */
+
+#endif /* CHEAPCGI_H */
diff --git a/inc/cirTree.h b/inc/cirTree.h
new file mode 100644
index 0000000..088d70e
--- /dev/null
+++ b/inc/cirTree.h
@@ -0,0 +1,82 @@
+/* cirTree chromosome id r tree.  Part of a system to index chromosome ranges - things of
+ * form chrN:start-end.  Generally you'll be using the crTree module - which
+ * makes use of this module and the bPlusTree module - rather than this module directly.
+ * This module works with chromosomes mapped to small integers rather than chromosomes
+ * as strings, saving space and speeding things up in the process, but requiring the
+ * separate bPlusTree to map the names to IDs. 
+ *   This module implements a one dimensional R-tree index treating the chromosome ID
+ * as the most significant part of a two-part key, and the base position as the least 
+ * significant part of the key.  */
+
+#ifndef CIRTREE_H
+#define CIRTREE_H
+
+struct cirTreeFile
+/* R tree index file handle. */
+    {
+    struct cirTreeFile *next;	/* Next in list of index files if any. */
+    char *fileName;		/* Name of file - for error reporting. */
+    struct udcFile *udc;			/* Open file pointer. */
+    boolean isSwapped;		/* If TRUE need to byte swap everything. */
+    bits64 rootOffset;		/* Offset of root block. */
+    bits32 blockSize;		/* Size of block. */
+    bits64 itemCount;		/* Number of items indexed. */
+    bits32 startChromIx;	/* First chromosome in file. */
+    bits32 startBase;		/* Starting base position. */
+    bits32 endChromIx;		/* Ending chromosome in file. */
+    bits32 endBase;		/* Ending base position. */
+    bits64 fileSize;		/* Total size of index file. */
+    bits32 itemsPerSlot;	/* Max number of items to put in each index slot at lowest level. */
+    };
+
+struct cirTreeFile *cirTreeFileOpen(char *fileName);
+/* Open up r-tree index file - reading header and verifying things. */
+
+void cirTreeFileClose(struct cirTreeFile **pCrt);
+/* Close and free up cirTree file opened with cirTreeFileAttach. */
+
+struct cirTreeFile *cirTreeFileAttach(char *fileName, struct udcFile *udc);
+/* Open up r-tree index file on previously open file, with cirTree
+ * header at current file position. */
+
+void cirTreeFileDetach(struct cirTreeFile **pCrt);
+/* Detach and free up cirTree file opened with cirTreeFileAttach. */
+
+struct fileOffsetSize *cirTreeFindOverlappingBlocks(struct cirTreeFile *crf, 
+	bits32 chromIx, bits32 start, bits32 end);
+/* Return list of file blocks that between them contain all items that overlap
+ * start/end on chromIx.  Also there will be likely some non-overlapping items
+ * in these blocks too. When done, use slListFree to dispose of the result. */
+
+struct cirTreeRange
+/* A chromosome id and an interval inside it. */
+    {
+    bits32 chromIx;	/* Chromosome id. */
+    bits32 start;	/* Start position in chromosome. */
+    bits32 end;		/* One past last base in interval in chromosome. */
+    };
+
+void cirTreeFileBulkIndexToOpenFile(
+	void *itemArray, int itemSize, bits64 itemCount, 
+	bits32 blockSize, bits32 itemsPerSlot,
+	void *context,
+	struct cirTreeRange (*fetchKey)(const void *va, void *context),
+	bits64 (*fetchOffset)(const void *va, void *context), 
+	bits64 endFileOffset, FILE *f);
+/* Create a r tree index from a sorted array, writing output starting at current position
+ * of an already open file.  See cirTreeFileCreate for explanation of parameters. */
+
+void cirTreeFileCreate(
+	void *itemArray, 	/* Sorted array of things to index.  Sort on chromIx,start. */
+	int itemSize, 		/* Size of each element in array. */
+	bits64 itemCount, 	/* Number of elements in array. */
+	bits32 blockSize,	/* R tree block size - # of children for each node. */
+	bits32 itemsPerSlot,	/* Number of items to put in each index slot at lowest level. */
+	void *context,		/* Context pointer for use by fetch call-back functions. */
+	struct cirTreeRange (*fetchKey)(const void *va, void *context),/* Given item, return key. */
+	bits64 (*fetchOffset)(const void *va, void *context), /* Given item, return file offset */
+	bits64 endFileOffset,				 /* Last position in file we index. */
+	char *fileName);                                 /* Name of output file. */
+/* Create a r tree index file from a sorted array. */
+
+#endif /* CIRTREE_H */
diff --git a/inc/codebias.h b/inc/codebias.h
new file mode 100644
index 0000000..f9b3e00
--- /dev/null
+++ b/inc/codebias.h
@@ -0,0 +1,33 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* codebias.h - stuff for managing codon bias and finding frame. */
+#ifndef CODEBIAS_H
+#define CODEBIAS_H
+
+#ifndef DNAUTIL_H
+#include "dnautil.h"
+#endif
+
+
+struct codonBias
+/* Tendency of codons to occur in a particular region. 
+ * Tables are in scaled log probability format. */
+    {
+    int mark0[64];
+    int mark1[64][64];
+    };
+
+struct codonBias *codonLoadBias(char *fileName);
+/* Create scaled log codon bias tables based on .cod file.  
+ * You can freeMem it when you're done. */
+
+ int codonFindFrame(DNA *dna, int dnaSize, struct codonBias *forBias);
+/* Assuming a stretch of DNA is an exon, find most likely frame that it's in. 
+ * Beware this routine will replace N's with T's in the input dna.*/
+
+
+#endif /* CODEBIAS_H */
+
diff --git a/inc/common.h b/inc/common.h
new file mode 100644
index 0000000..7fbd2ae
--- /dev/null
+++ b/inc/common.h
@@ -0,0 +1,1435 @@
+/* Common.h - functions that are commonly used.  Includes
+ * routines for managing singly linked lists, some basic
+ * string manipulation stuff, and other stuff of the
+ * short but useful nature.
+ *
+ * This file is copyright 2002-2005 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef COMMON_H	/* Wrapper to avoid including this twice. */
+#define COMMON_H
+
+/* Some stuff to support large files in Linux. */
+#ifndef _LARGEFILE_SOURCE
+#define _LARGEFILE_SOURCE 1
+#endif
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+#endif
+
+/* Some stuff for safer pthreads. */
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <setjmp.h>
+#include <time.h>
+#include <math.h>
+#include <errno.h>
+#include <unistd.h>
+#include <libgen.h>
+
+#if defined(MACHTYPE_ppc)
+#include <sys/wait.h>
+#endif
+
+#if defined(__APPLE__)
+#if defined(__i686__)
+/* The i686 apple math library defines warn. */
+#define warn jkWarn
+#endif
+#endif
+
+#ifdef __CYGWIN32__
+#include <mingw/math.h>
+#endif
+
+#ifndef NAN
+#define NAN (0.0 / 0.0)
+#endif
+
+#ifndef WIFEXITED
+#define WIFEXITED(stat)  (((*((int *) &(stat))) & 0xff) == 0)
+#endif
+
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat) (short)(((*((int *) &(stat))) >> 8) & 0xffff)
+#endif
+
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(stat) (((*((int *) &(stat)))) && ((*((int *) &(stat))) == ((*((int *) &(stat))) &0x00ff)))
+#endif
+
+#ifndef WTERMSIG
+#define WTERMSIG(stat)    ((*((int *) &(stat))) & 0x7f)
+#endif
+
+#ifndef WIFSTOPPED
+#define WIFSTOPPED(stat)  (((*((int *) &(stat))) & 0xff) == 0177)
+#endif
+
+#ifndef WSTOPSIG
+#define WSTOPSIG(stat)    (((*((int *) &(stat))) >> 8) & 0xff)
+#endif
+
+#ifndef HUGE
+#define HUGE MAXFLOAT
+#endif
+
+
+/* Let's pretend C has a boolean type. */
+#define TRUE 1
+#define FALSE 0
+#define boolean int
+#ifndef	__cplusplus
+#ifndef bool
+#define bool char
+#endif
+#endif
+
+/* Some other type synonyms */
+#define UBYTE unsigned char   /* Wants to be unsigned 8 bits. */
+#define BYTE signed char      /* Wants to be signed 8 bits. */
+#define UWORD unsigned short  /* Wants to be unsigned 16 bits. */
+#define WORD short	      /* Wants to be signed 16 bits. */
+#define bits64 unsigned long long  /* Wants to be unsigned 64 bits. */
+#define bits32 unsigned       /* Wants to be unsigned 32 bits. */
+#define bits16 unsigned short /* Wants to be unsigned 16 bits. */
+#define bits8 unsigned char   /* Wants to be unsigned 8 bits. */
+#define signed32 int	      /* Wants to be signed 32 bits. */
+#define bits8 unsigned char   /* Wants to be unsigned 8 bits. */
+
+#define BIGNUM 0x3fffffff	/* A really big number */
+#define BIGDOUBLE 1.7E+308	/* Close to biggest double-precision number */
+
+#define LIMIT_2or8GB (2147483647 * ((sizeof(size_t)/4)*(sizeof(size_t)/4)))
+/*      == 2 Gb for 32 bit machines, 8 Gb for 64 bit machines */
+#define LIMIT_2or6GB (2147483647 + (2147483647 * ((sizeof(size_t)/4)-1)) + \
+	(2147483647 * ((sizeof(size_t)/4)-1)))
+/*      == 2 Gb for 32 bit machines, 6 Gb for 64 bit machines */
+
+/* Default size of directory path, file name and extension string buffers */
+#define PATH_LEN 512
+#define FILENAME_LEN 128
+#define FILEEXT_LEN 64
+
+/* inline functions: To declare a function inline, place the entire function
+ * in a header file and prefix it with the INLINE macro.  If used with a
+ * compiler that doesn't support inline, change the INLINE marco to be simply
+ * `static'.
+ */
+#ifndef INLINE
+#define INLINE static inline
+#endif
+
+/* stdargs compatibility: in a unix universe a long time ago, types of va_list
+ * were passed by value.  It was assume one could do things like:
+ *
+ *     va_start(args);
+ *     vfprintf(fh1, fmt, args);
+ *     vfprintf(fh2, fmt, args);
+ *     va_end(args);
+ *
+ * and life would good.  However this is not true on some modern systems (for
+ * instance gcc/glibc on x86_64), where va_args can be a pointer to some type
+ * of object).  The second call to vfprintf() would then crash, since the
+ * first call modified the object that va_args was pointing to. C99 adds a
+ * va_copy macro that to address this issue.  Many non-C99 system include this
+ * macro, sometimes called __va_copy.  Here we ensure that va_copy is defined.
+ * If if doesn't exist, we try to define it in terms of __va_copy.  If that is
+ * not available, we make the assumption that va_list can be copied by value
+ * and create our own.  Our implementation is the same as used on Solaris.
+ */
+#if defined(__va_copy) && !defined(va_copy)
+#   define va_copy __va_copy
+#endif
+#if !defined(va_copy)
+#   define va_copy(to, from) ((to) = (from))
+#endif
+
+/* Cast a pointer to a long long. Use to printf format points as long-longs
+ * in a 32/64bit portable manner.  Format should use %llx for the result.
+ * Needed because casting a pointer to a different sized number cause a
+ * warning with gcc */
+#define ptrToLL(p) ((long long)((size_t)p))
+
+/* How big is this array? */
+#define ArraySize(a) (sizeof(a)/sizeof((a)[0]))
+
+#define uglyf printf  /* debugging printf */
+#define uglyAbort errAbort /* debugging error abort. */
+#define uglyOut stdout /* debugging fprintf target. */
+
+void *needMem(size_t size);
+/* Need mem calls abort if the memory allocation fails. The memory
+ * is initialized to zero. */
+
+void *needLargeMem(size_t size);
+/* This calls abort if the memory allocation fails. The memory is
+ * not initialized to zero. */
+
+void *needLargeZeroedMem(size_t size);
+/* Request a large block of memory and zero it. */
+
+void *needLargeMemResize(void* vp, size_t size);
+/* Adjust memory size on a block, possibly relocating it.  If vp is NULL,
+ * a new memory block is allocated.  Memory not initted. */
+
+void *needLargeZeroedMemResize(void* vp, size_t oldSize, size_t newSize);
+/* Adjust memory size on a block, possibly relocating it.  If vp is NULL, a
+ * new memory block is allocated.  If block is grown, new memory is zeroed. */
+
+void *needHugeMem(size_t size);
+/* No checking on size.  Memory not initted to 0. */
+
+void *needHugeZeroedMem(size_t size);
+/* Request a large block of memory and zero it. */
+
+void *needHugeMemResize(void* vp, size_t size);
+/* Adjust memory size on a block, possibly relocating it.  If vp is NULL,
+ * a new memory block is allocated.  No checking on size.  Memory not
+ * initted. */
+
+void *needHugeZeroedMemResize(void* vp, size_t oldSize, size_t newSize);
+/* Adjust memory size on a block, possibly relocating it.  If vp is NULL, a
+ * new memory block is allocated.  No checking on size.  If block is grown,
+ * new memory is zeroed. */
+
+void *needMoreMem(void *old, size_t copySize, size_t newSize);
+/* Allocate a new buffer, copy old buffer to it, free old buffer. */
+
+void *cloneMem(void *pt, size_t size);
+/* Allocate a new buffer of given size, and copy pt to it. */
+
+#define CloneVar(pt) cloneMem(pt, sizeof((pt)[0]))
+/* Allocate copy of a structure. */
+
+void *wantMem(size_t size);
+/* Want mem just calls malloc - no zeroing of memory, no
+ * aborting if request fails. */
+
+void freeMem(void *pt);
+/* Free memory will check for null before freeing. */
+
+void freez(void *ppt);
+/* Pass address of pointer.  Will free pointer and set it
+ * to NULL. Typical use:
+ *     s = needMem(1024);
+ *          ...
+ *     freez(&s); */
+
+#define AllocVar(pt) (pt = needMem(sizeof(*pt)))
+/* Shortcut to allocating a single variable on the heap and
+ * assigning pointer to it. */
+
+#define AllocArray(pt, size) (pt = needLargeZeroedMem(sizeof(*pt) * (size)))
+
+#define AllocA(type) needMem(sizeof(type))
+/* Shortcut to allocating a variable on heap of a specific type. */
+
+#define AllocN(type,count) ((type*)needLargeZeroedMem(sizeof(type) * (count)))
+/* Shortcut to allocating an array on the heap of a specific type. */
+
+#define ExpandArray(array, oldCount, newCount) \
+  (array = needMoreMem((array), (oldCount)*sizeof((array)[0]), (newCount)*sizeof((array)[0])))
+/* Expand size of dynamically allocated array. */
+
+#define CopyArray(source, dest,count) memcpy(dest,source,(count)*sizeof(dest[0]))
+/* Copy count elements of array from source to dest. */
+
+#define CloneArray(a, count) cloneMem(a, (count)*sizeof(a[0]))
+/* Make new dynamic array initialized with  count elements of a */
+
+void errAbort(char *format, ...)
+/* Abort function, with optional (printf formatted) error message. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+void errnoAbort(char *format, ...)
+/* Prints error message from UNIX errno first, then does errAbort. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+#define internalErr()  errAbort("Internal error %s %d", __FILE__, __LINE__)
+/* Generic internal error message */
+
+void warn(char *format, ...)
+/* Issue a warning message. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+void warnWithBackTrace(char *format, ...)
+/* Issue a warning message and append backtrace. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+void verbose(int verbosity, char *format, ...)
+/* Write printf formatted message to log (which by
+ * default is stdout) if global verbose variable
+ * is set to verbosity or higher.  Default level is 1. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 2, 3)))
+#endif
+    ;
+
+void verboseTimeInit(void);
+/* Initialize or reinitialize the previous time for use by verboseTime. */
+
+void verboseTime(int verbosity, char *label, ...)
+/* Print label and how long it's been since last call.  Start time can be
+ * initialized with verboseTimeInit, otherwise the elapsed time will be
+ * zero. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 2, 3)))
+#endif
+    ;
+
+void verboseDot();
+/* Write I'm alive dot (at verbosity level 1) */
+
+int verboseLevel();
+/* Get verbosity level. */
+
+void verboseSetLevel(int verbosity);
+/* Set verbosity level in log.  0 for no logging,
+ * higher number for increasing verbosity. */
+
+INLINE void zeroBytes(void *vpt, int count)
+/* fill a specified area of memory with zeroes */
+{
+memset(vpt, '\0', count);
+}
+
+#define ZeroVar(v) zeroBytes(v, sizeof(*v))
+
+void reverseBytes(char *bytes, long length);
+/* Reverse the order of the bytes. */
+
+void reverseInts(int *a, int length);
+/* Reverse the order of the integer array. */
+
+void reverseUnsigned(unsigned *a, int length);
+/* Reverse the order of the unsigned array. */
+
+void reverseDoubles(double *a, int length);
+/* Reverse the order of the double array. */
+
+void reverseStrings(char **a, int length);
+/* Reverse the order of the char* array. */
+
+void swapBytes(char *a, char *b, int length);
+/* Swap buffers a and b. */
+
+/* Some things to manage simple lists - structures that begin
+ * with a pointer to the next element in the list. */
+struct slList
+    {
+    struct slList *next;
+    };
+
+int slCount(const void *list);
+/* Return # of elements in list.  */
+
+void *slElementFromIx(void *list, int ix);
+/* Return the ix'th element in list.  Returns NULL
+ * if no such element. */
+
+int slIxFromElement(void *list, void *el);
+/* Return index of el in list.  Returns -1 if not on list. */
+
+INLINE void slAddHead(void *listPt, void *node)
+/* Add new node to start of list.
+ * Usage:
+ *    slAddHead(&list, node);
+ * where list and nodes are both pointers to structure
+ * that begin with a next pointer.
+ */
+{
+struct slList **ppt = (struct slList **)listPt;
+struct slList *n = (struct slList *)node;
+n->next = *ppt;
+*ppt = n;
+}
+
+INLINE void slSafeAddHead(void *listPt, void *node)
+/* Add new node to start of list.  Now that slAddHead is an inline instead of
+ * a macro, this function is obsolete.
+ */
+{
+slAddHead(listPt, node);
+}
+
+void slAddTail(void *listPt, void *node);
+/* Add new node to tail of list.
+ * Usage:
+ *    slAddTail(&list, node);
+ * where list and nodes are both pointers to structure
+ * that begin with a next pointer. This is sometimes
+ * convenient but relatively slow.  For longer lists
+ * it's better to slAddHead, and slReverse when done.
+ */
+
+void *slPopHead(void *listPt);
+/* Return head of list and remove it from list. (Fast) */
+
+void *slPopTail(void *listPt);
+/* Return tail of list and remove it from list. (Not so fast) */
+
+void *slCat(void *a, void *b);
+/* Return concatenation of lists a and b.
+ * Example Usage:
+ *   struct slName *a = getNames("a");
+ *   struct slName *b = getNames("b");
+ *   struct slName *ab = slCat(a,b)
+ * After this it is no longer safe to use a or b.
+ */
+
+void *slLastEl(void *list);
+/* Returns last element in list or NULL if none. */
+
+void slReverse(void *listPt);
+/* Reverse order of a list.
+ * Usage:
+ *    slReverse(&list);
+ */
+
+typedef int CmpFunction(const void *elem1, const void *elem2);
+
+void slSort(void *pList, CmpFunction *compare);
+/* Sort a singly linked list with Qsort and a temporary array.
+ * The arguments to the compare function in real, non-void, life
+ * are pointers to pointers. */
+
+void slUniqify(void *pList, CmpFunction *compare, void (*free)());
+/* Return sorted list with duplicates removed.
+ * Compare should be same type of function as slSort's compare (taking
+ * pointers to pointers to elements.  Free should take a simple
+ * pointer to dispose of duplicate element, and can be NULL. */
+
+boolean slRemoveEl(void *vpList, void *vToRemove);
+/* Remove element from doubly linked list.  Usage:
+ *    slRemove(&list, el);
+ * Returns TRUE if element in list.  */
+
+void slFreeList(void *listPt);
+/* Free all elements in list and set list pointer to null.
+ * Usage:
+ *    slFreeList(&list);
+ */
+
+struct slInt
+/* List of integers. */
+    {
+    struct slInt *next;	/* Next in list. */
+    int val;		/* Integer value. */
+    };
+
+struct slInt *slIntNew(int x);
+#define newSlInt slIntNew
+/* Return a new double. */
+
+int slIntCmp(const void *va, const void *vb);
+/* Compare two slInts. */
+
+int slIntCmpRev(const void *va, const void *vb);
+/* Compare two slInts in reverse direction. */
+
+struct slInt * slIntFind(struct slInt *list, int target);
+/* Find target in slInt list or return NULL */
+
+void doubleSort(int count, double *array);
+/* Sort an array of doubles. */
+
+double doubleMedian(int count, double *array);
+/* Return median value in array.  This will sort
+ * the array as a side effect. */
+
+void doubleBoxWhiskerCalc(int count, double *array, double *retMin,
+	double *retQ1, double *retMedian, double *retQ3, double *retMax);
+/* Calculate what you need to draw a box and whiskers plot from an array of doubles. */
+
+struct slDouble
+/* List of double-precision numbers. */
+    {
+    struct slDouble *next;	/* Next in list. */
+    double val;			/* Double-precision value. */
+    };
+
+struct slDouble *slDoubleNew(double x);
+#define newSlDouble slDoubleNew
+/* Return a new int. */
+
+int slDoubleCmp(const void *va, const void *vb);
+/* Compare two slDoubles. */
+
+double slDoubleMedian(struct slDouble *list);
+/* Return median value on list. */
+
+void slDoubleBoxWhiskerCalc(struct slDouble *list, double *retMin,
+	double *retQ1, double *retMedian, double *retQ3, double *retMax);
+/* Calculate what you need to draw a box and whiskers plot from a list of slDoubles. */
+
+void intSort(int count, int *array);
+/* Sort an array of ints. */
+
+int intMedian(int count, int *array);
+/* Return median value in array.  This will sort
+ * the array as a side effect. */
+
+struct slName
+/* List of names. The name array is allocated to accommodate full name
+ */
+    {
+    struct slName *next;	/* Next in list. */
+    char name[1];               /* Allocated at run time to length of string. */
+    };
+
+struct slName *newSlName(char *name);
+
+#define slNameNew newSlName
+/* Return a new slName. */
+
+#define slNameFree freez
+/* Free a single slName */
+
+#define slNameFreeList slFreeList
+/* Free a list of slNames */
+
+struct slName *slNameNewN(char *name, int size);
+/* Return new slName of given size. */
+
+int slNameCmpCase(const void *va, const void *vb);
+/* Compare two slNames, ignore case. */
+
+int slNameCmp(const void *va, const void *vb);
+/* Compare two slNames. */
+
+int slNameCmpStringsWithEmbeddedNumbers(const void *va, const void *vb);
+/* Compare strings such as gene names that may have embedded numbers,
+ * so that bmp4a comes before bmp14a */
+
+void slNameSortCase(struct slName **pList);
+/* Sort slName list, ignore case. */
+
+void slNameSort(struct slName **pList);
+/* Sort slName list. */
+
+boolean slNameInList(struct slName *list, char *string);
+/* Return true if string is in name list -- case insensitive. */
+
+boolean slNameInListUseCase(struct slName *list, char *string);
+/* Return true if string is in name list -- case sensitive. */
+
+void *slNameFind(void *list, char *string);
+/* Return first element of slName list (or any other list starting
+ * with next/name fields) that matches string. */
+
+int slNameFindIx(struct slName *list, char *string);
+/* Return index of first element of slName list (or any other
+ * list starting with next/name fields) that matches string.
+ * ... Return -1 if not found. */
+
+char *slNameStore(struct slName **pList, char *string);
+/* Put string into list if it's not there already.
+ * Return the version of string stored in list. */
+
+struct slName *slNameAddHead(struct slName **pList, char *name);
+/* Add name to start of list and return it. */
+
+struct slName *slNameAddTail(struct slName **pList, char *name);
+/* Add name to end of list (not efficient for long lists),
+ * and return it. */
+
+struct slName *slNameCloneList(struct slName *list);
+/* Return clone of list. */
+
+struct slName *slNameListFromString(char *s, char delimiter);
+/* Return list of slNames gotten from parsing delimited string.
+ * The final delimiter is optional. a,b,c  and a,b,c, are equivalent
+ * for comma-delimited lists. */
+
+#define slNameListFromComma(s) slNameListFromString(s, ',')
+/* Parse out comma-separated list. */
+
+struct slName *slNameListOfUniqueWords(char *text,boolean respectQuotes);
+// Return list of unique words found by parsing string delimited by whitespace.
+// If respectQuotes then ["Lucy and Ricky" 'Fred and Ethyl'] will yield 2 slNames no quotes
+
+struct slName *slNameListFromStringArray(char *stringArray[], int arraySize);
+/* Return list of slNames from an array of strings of length arraySize.
+ * If a string in the array is NULL, the array will be treated as
+ * NULL-terminated. */
+
+char *slNameListToString(struct slName *list, char delimiter);
+/* Return string created by joining all names with the delimiter. */
+
+struct slName *slNameLoadReal(char *fileName);
+/* load file lines that are not blank or start with a '#' into a slName
+ * list */
+
+struct slName *slNameIntersection(struct slName *a, struct slName *b);
+/* return intersection of two slName lists.  */
+
+struct slRef
+/* Singly linked list of generic references. */
+    {
+    struct slRef *next;	/* Next in list. */
+    void *val;		/* A reference to something. */
+    };
+
+struct slRef *slRefNew(void *val);
+/* Create new slRef element. */
+
+struct slRef *refOnList(struct slRef *refList, void *val);
+/* Return ref if val is already on list, otherwise NULL. */
+
+void refAdd(struct slRef **pRefList, void *val);
+/* Add reference to list. */
+
+void refAddUnique(struct slRef **pRefList, void *val);
+/* Add reference to list if not already on list. */
+
+struct slRef *refListFromSlList(void *list);
+/* Make a reference list that mirrors a singly-linked list. */
+
+struct slPair
+/* A name/value pair. */
+    {
+    struct slPair *next;	/* Next in list. */
+    char *name;			/* Name of item. */
+    void *val;			/* Pointer to item data. */
+    };
+
+struct slPair *slPairNew(char *name, void *val);
+/* Allocate new name/value pair. */
+
+void slPairAdd(struct slPair **pList, char *name, void *val);
+/* Add new slPair to head of list. */
+
+void slPairFree(struct slPair **pEl);
+/* Free up struct and name.  (Don't free up values.) */
+
+void slPairFreeList(struct slPair **pList);
+/* Free up list.  (Don't free up values.) */
+
+void slPairFreeVals(struct slPair *list);
+/* Free up all values on list. */
+
+void slPairFreeValsAndList(struct slPair **pList);
+/* Free up all values on list and list itself */
+
+struct slPair *slPairFind(struct slPair *list, char *name);
+/* Return list element of given name, or NULL if not found. */
+
+void *slPairFindVal(struct slPair *list, char *name);
+/* Return value associated with name in list, or NULL if not found. */
+
+struct slPair *slPairListFromString(char *str,boolean respectQuotes);
+// Return slPair list parsed from list in string like:  [name1=val1 name2=val2 ...]
+// if respectQuotes then string can have double quotes: [name1="val 1" "name 2"=val2 ...]
+//    resulting pair strips quotes: {name1}={val 1},{name 2}={val2}
+// Returns NULL if parse error.  Free this up with slPairFreeValsAndList.
+#define slPairFromString(s) slPairListFromString(s,FALSE)
+
+char *slPairListToString(struct slPair *list,boolean quoteIfSpaces);
+// Returns an allocated string of pairs in form of [name1=val1 name2=val2 ...]
+// If requested, will wrap name or val in quotes if contain spaces: [name1="val 1" "name 2"=val2]
+
+char *slPairNameToString(struct slPair *list, char delimiter,boolean quoteIfSpaces);
+// Return string created by joining all names (ignoring vals) with the delimiter.
+// If requested, will wrap name in quotes if contain spaces: [name1,"name 2" ...]
+
+int slPairCmpCase(const void *va, const void *vb);
+/* Compare two slPairs, ignore case. */
+
+void slPairSortCase(struct slPair **pList);
+/* Sort slPair list, ignore case. */
+
+int slPairCmp(const void *va, const void *vb);
+/* Compare two slPairs. */
+
+int slPairValCmpCase(const void *va, const void *vb);
+/* Case insensitive compare two slPairs on their values (must be string). */
+
+int slPairValCmp(const void *va, const void *vb);
+/* Compare two slPairs on their values (must be string). */
+
+void slPairValSortCase(struct slPair **pList);
+/* Sort slPair list on values (must be string), ignore case. */
+
+void slPairValSort(struct slPair **pList);
+/* Sort slPair list on values (must be string). */
+
+int slPairIntCmp(const void *va, const void *vb);
+// Compare two slPairs on their integer values.
+
+void slPairIntSort(struct slPair **pList);
+// Sort slPair list on integer values.
+
+int slPairAtoiCmp(const void *va, const void *vb);
+// Compare two slPairs on their strings interpreted as integer values.
+
+void slPairValAtoiSort(struct slPair **pList);
+// Sort slPair list on string values interpreted as integers.
+
+void gentleFree(void *pt);
+/* check pointer for NULL before freeing.
+ * (Actually plain old freeMem does that these days.) */
+
+/*******  Some stuff for processing strings. *******/
+
+char *cloneStringZ(const char *s, int size);
+/* Make a zero terminated copy of string in memory */
+
+char *cloneString(const char *s);
+/* Make copy of string in dynamic memory */
+
+char *cloneLongString(char *s);
+/* Make clone of long string. */
+
+char *catTwoStrings(char *a, char *b);
+/* Allocate new string that is a concatenation of two strings. */
+
+int differentWord(char *s1, char *s2);
+/* strcmp ignoring case - returns zero if strings are
+ * the same (ignoring case) otherwise returns difference
+ * between first non-matching characters. */
+
+#define sameWord(a,b) (!differentWord(a,b))
+/* Return TRUE if two strings are same ignoring case */
+
+#define differentString(a,b) (strcmp(a,b))
+/* Returns FALSE if two strings same. */
+
+int differentStringNullOk(char *a, char *b);
+/* Returns 0 if two strings (either of which may be NULL)
+ * are the same.  Otherwise it returns a positive or negative
+ * number depending on the alphabetical order of the two
+ * strings.
+ * This is basically a strcmp that can handle NULLs in
+ * the input.  If used in a sort the NULLs will end
+ * up before any of the cases with data.   */
+
+#define sameOk(a,b) (differentStringNullOk(a,b) == 0)
+/* returns TRUE if two strings same, NULLs OK */
+
+#define sameString(a,b) (strcmp(a,b)==0)
+/* Returns TRUE if two strings same. */
+
+#define sameStringN(a,b,c) (strncmp(a,b,c)==0)
+/* Returns TRUE if two strings start with the same c characters. */
+
+#define isEmpty(string) ((string) == NULL || (string)[0] == 0)
+#define isNotEmpty(string) (! isEmpty(string))
+
+int cmpStringsWithEmbeddedNumbers(const char *a, const char *b);
+/* Compare strings such as gene names that may have embedded numbers,
+ * so that bmp4a comes before bmp14a */
+
+int cmpWordsWithEmbeddedNumbers(const char *a, const char *b);
+/* Case insensitive version of cmpStringsWithEmbeddedNumbers. */
+
+boolean startsWith(const char *start, const char *string);
+/* Returns TRUE if string begins with start. */
+
+boolean startsWithWord(char *firstWord, char *line);
+/* Return TRUE if first white-space-delimited word in line
+ * is same as firstWord.  Comparison is case sensitive. */
+
+boolean startsWithWordByDelimiter(char *firstWord,char delimit, char *line);
+/* Return TRUE if first word in line is same as firstWord as delimited by delimit.
+   Comparison is case sensitive. Delimit of ' ' uses isspace() */
+
+#define stringIn(needle, haystack) strstr(haystack, needle)
+/* Returns position of needle in haystack or NULL if it's not there. */
+/*        char *stringIn(char *needle, char *haystack);      */
+
+char *rStringIn(char *needle, char *haystack);
+/* Return last position of needle in haystack, or NULL if it's not there. */
+
+char *stringBetween(char *start, char *end, char *haystack);
+/* Return string between start and end strings, or NULL if
+ * none found.  The first such instance is returned.
+ * String must be freed by caller. */
+
+char * findWordByDelimiter(char *word,char delimit, char *line);
+/* Return pointer to first word in line matching 'word' and delimited
+   by 'delimit'. Comparison is case sensitive. Delimit of ' ' uses isspace() */
+
+boolean endsWith(char *string, char *end);
+/* Returns TRUE if string ends with end. */
+
+char lastChar(char *s);
+/* Return last character in string. */
+
+void trimLastChar(char *s);
+/* Erase last character in string. */
+
+char *lastNonwhitespaceChar(char *s);
+// Return pointer to last character in string that is not whitespace.
+
+char *matchingCharBeforeInLimits(char *limit, char *s, char c);
+/* Look for character c sometime before s, but going no further than limit.
+ * Return NULL if not found. */
+
+boolean wildMatch(const char *wildCard, const char *string);
+/* does a case insensitive wild card match with a string.
+ * * matches any string or no character.
+ * ? matches any single character.
+ * anything else etc must match the character exactly. */
+
+boolean sqlMatchLike(char *wildCard, char *string);
+/* Match using % and _ wildcards. */
+
+boolean anyWild(const char *string);
+/* Return TRUE if any wild card characters in string. */
+
+char *memMatch(char *needle, int nLen, char *haystack, int hLen);
+/* Returns first place where needle (of nLen chars) matches
+ * haystack (of hLen chars) */
+
+void toUpperN(char *s, int n);
+/* Convert a section of memory to upper case. */
+
+void toLowerN(char *s, int n);
+/* Convert a section of memory to lower case. */
+
+void toggleCase(char *s, int size);
+/* toggle upper and lower case chars in string. */
+
+char *strUpper(char *s);
+#define touppers(s) (void)strUpper(s)
+/* Convert entire string to upper case. */
+
+char *strLower(char *s);
+#define tolowers(s) (void)strLower(s)
+/* Convert entire string to lower case */
+
+char *replaceChars(char *string, char *oldStr, char *newStr);
+/*
+  Replaces the old with the new.
+ The old and new string need not be of equal size
+ Can take any length string.
+ Return value needs to be freeMem'd.
+*/
+
+int strSwapStrs(char *string, int sz,char *oldStr, char *newStr);
+/* Swaps all occurrences of the oldStr with the newStr in string. Need not be same size
+   Swaps in place but restricted by sz.  Returns count of swaps or -1 for sz failure.*/
+
+char * memSwapChar(char *s, int len, char oldChar, char newChar);
+/* Substitute newChar for oldChar throughout memory of given length.
+   old or new may be null */
+#define strSwapChar(s,old,new)   memSwapChar((s),strlen(s),(old),(new))
+#define subChar(s,old,new) (void)memSwapChar((s),strlen(s),(old),(new))
+/* Substitute newChar for oldChar throughout string s. */
+
+void stripChar(char *s, char c);
+/* Remove all occurences of c from s. */
+
+char *stripEnclosingChar(char *inout,char encloser);
+// Removes enclosing char if found at both beg and end, preserving pointer
+// Note: handles brackets '(','{' and '[' by complement at end
+#define stripEnclosingDoubleQuotes(inout) stripEnclosingChar((inout),'"')
+#define stripEnclosingSingleQuotes(inout) stripEnclosingChar((inout),'\'')
+
+void stripString(char *s, char *strip);
+/* Remove all occurences of strip from s. */
+
+int countCase(char *s,boolean upper);
+// Count letters with case (upper or lower)
+
+int countChars(char *s, char c);
+/* Return number of characters c in string s. */
+
+int countCharsN(char *s, char c, int size);
+/* Return number of characters c in string s of given size. */
+
+int countLeadingChars(char *s, char c);
+/* Count number of characters c at start of string. */
+
+int countLeadingDigits(const char *s);
+/* Return number of leading digits in s */
+
+int countLeadingNondigits(const char *s);
+/* Count number of leading non-digit characters in s. */
+
+int countSame(char *a, char *b);
+/* Count number of characters that from start in a,b that are same. */
+
+int countSeparatedItems(char *string, char separator);
+/* Count number of items in string you would parse out with given
+ * separator,  assuming final separator is optional. */
+
+int chopString(char *in, char *sep, char *outArray[], int outSize);
+/* int chopString(in, sep, outArray, outSize); */
+/* This chops up the input string (cannabilizing it)
+ * into an array of zero terminated strings in
+ * outArray.  It returns the number of strings.
+ * If you pass in NULL for outArray, it will just
+ * return the number of strings that it *would*
+ * chop. */
+
+extern char crLfChopper[];
+extern char whiteSpaceChopper[];
+/* Some handy predefined separators. */
+
+int chopByWhite(char *in, char *outArray[], int outSize);
+/* Like chopString, but specialized for white space separators. */
+
+#define chopLine(line, words) chopByWhite(line, words, ArraySize(words))
+/* Chop line by white space. */
+
+int chopByWhiteRespectDoubleQuotes(char *in, char *outArray[], int outSize);
+/* Like chopString, but specialized for white space separators.
+ * Further, any doubleQuotes (") are respected.
+ * If doubleQuote encloses whole string, then they are removed:
+ *   "Fred and Ethyl" results in word [Fred and Ethyl]
+ * If doubleQuotes exist inside string they are retained:
+ *   Fred "and Ethyl" results in word [Fred "and Ethyl"]
+ * Special note "" is a valid, though empty word. */
+
+int chopByChar(char *in, char chopper, char *outArray[], int outSize);
+/* Chop based on a single character. */
+
+#define chopTabs(string, words) chopByChar(string, '\t', words, ArraySize(words))
+/* Chop string by tabs. */
+
+#define chopCommas(string, words) chopByChar(string, ',', words, ArraySize(words))
+/* Chop string by commas. */
+
+
+char *skipBeyondDelimit(char *s,char delimit);
+/* Returns NULL or pointer to first char beyond one (or more contiguous) delimit char.
+   If delimit is ' ' then skips beyond first patch of whitespace. */
+
+char *skipLeadingSpaces(char *s);
+/* Return first white space or NULL if none.. */
+
+char *skipToSpaces(char *s);
+/* Return first white space. */
+
+void eraseTrailingSpaces(char *s);
+/* Replace trailing white space with zeroes. */
+
+void eraseWhiteSpace(char *s);
+/* Remove white space from a string */
+
+void eraseNonAlphaNum(char *s);
+/* Remove non-alphanumeric chars from string */
+
+char *trimSpaces(char *s);
+/* Remove leading and trailing white space. */
+
+void repeatCharOut(FILE *f, char c, int count);
+/* Write character to file repeatedly. */
+
+void spaceOut(FILE *f, int count);
+/* Put out some spaces to file. */
+
+void starOut(FILE *f, int count);
+/* Put out some asterisks to file. */
+
+boolean hasWhiteSpace(char *s);
+/* Return TRUE if there is white space in string. */
+
+char *firstWordInLine(char *line);
+/* Returns first word in line if any (white space separated).
+ * Puts 0 in place of white space after word. */
+
+char *lastWordInLine(char *line);
+/* Returns last word in line if any (white space separated).
+ * Returns NULL if string is empty.  Removes any terminating white space
+ * from line. */
+
+char *nextWord(char **pLine);
+/* Return next word in *pLine and advance *pLine to next
+ * word. Returns NULL when no more words. */
+
+char *nextWordRespectingQuotes(char **pLine);
+// return next word but respects single or double quotes surrounding sets of words.
+
+char *cloneFirstWord(char *line);
+/* Clone first word in line */
+
+char *nextTabWord(char **pLine);
+/* Return next tab-separated word. */
+
+char *cloneFirstWordByDelimiter(char *line,char delimit);
+/* Returns a cloned first word, not harming the memory passed in
+   Delimiter of ' ' will delimit by isspace() */
+#define cloneFirstWordInLine(line) cloneFirstWordByDelimiter((line),' ')
+#define cloneFirstWordByTab(line)  cloneFirstWordByDelimiter((line),'\t')
+/* Returns a cloned first word, not harming the memory passed in */
+
+char *cloneNextWordByDelimiter(char **line,char delimit);
+/* Returns a cloned first word, advancing the line pointer
+   but not harming memory passed in. Delimit ' ' uses isspace() */
+#define cloneNextWord(line)      cloneNextWordByDelimiter((line),' ')
+#define cloneNextWordByTab(line) cloneNextWordByDelimiter((line),'\t')
+
+char *nextStringInList(char **pStrings);
+/* returns pointer to the first string and advances pointer to next in
+   list of strings dilimited by 1 null and terminated by 2 nulls. */
+
+int cntStringsInList(char *pStrings);
+/* returns count of strings in a
+   list of strings dilimited by 1 null and terminated by 2 nulls. */
+
+int stringArrayIx(char *string, char *array[], int arraySize);
+/* Return index of string in array or -1 if not there. */
+
+int ptArrayIx(void *pt, void *array, int arraySize);
+/* Return index of pt in array or -1 if not there. */
+
+#define stringIx(string, array) stringArrayIx( (string), (array), ArraySize(array))
+
+/* Some stuff that is left out of GNU .h files!? */
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif
+
+#ifndef FILEPATH_H
+void splitPath(char *path, char dir[PATH_LEN], char name[FILENAME_LEN],
+	       char extension[FILEEXT_LEN]);
+/* Split a full path into components.  The dir component will include the
+ * trailing / if any.  The extension component will include the starting
+ * . if any.   Pass in NULL for dir, name, or extension if you don't care about
+ * that part. */
+#endif /* FILEPATH_H */
+
+char *addSuffix(char *head, char *suffix);
+/* Return a needMem'd string containing "headsuffix". Should be free'd
+ when finished. */
+
+void chopSuffix(char *s);
+/* Remove suffix (last . in string and beyond) if any. */
+
+void chopSuffixAt(char *s, char c);
+/* Remove end of string from last occurrence of char c.
+ * chopSuffixAt(s, '.') is equivalent to regular chopSuffix. */
+
+char *chopPrefix(char *s);
+/* This will replace the first '.' in a string with
+ * 0, and return the character after this.  If there
+ * is no '.' in the string this will just return the
+ * unchanged s passed in. */
+
+char *chopPrefixAt(char *s, char c);
+/* Like chopPrefix, but can chop on any character, not just '.' */
+
+FILE *mustOpen(char *fileName, char *mode);
+/* Open a file - or squawk and die. */
+
+void mustWrite(FILE *file, void *buf, size_t size);
+/* Write to file or squawk and die. */
+
+#define writeOne(file, var) mustWrite((file), &(var), sizeof(var))
+/* Write out one variable to file. */
+
+void mustRead(FILE *file, void *buf, size_t size);
+/* Read size bytes from a file or squawk and die. */
+
+#define mustReadOne(file, var) mustRead((file), &(var), sizeof(var))
+/* Read one variable from file or die. */
+
+void mustGetLine(FILE *file, char *buf, int charCount);
+/* Read at most charCount-1 bytes from file, but stop after newline if one is
+ * encountered.  The string in buf is '\0'-terminated.  (See man 3 fgets.)
+ * Die if there is an error. */
+
+int mustOpenFd(char *fileName, int flags);
+/* Open a file descriptor (see man 2 open) or squawk and die. */
+
+void mustReadFd(int fd, void *buf, size_t size);
+/* Read size bytes from a file descriptor or squawk and die. */
+
+void mustWriteFd(int fd, void *buf, size_t size);
+/* Write size bytes to file descriptor fd or die.  (See man 2 write.) */
+
+off_t mustLseek(int fd, off_t offset, int whence);
+/* Seek to given offset, relative to whence (see man lseek) in file descriptor fd or errAbort.
+ * Return final offset (e.g. if this is just an (fd, 0, SEEK_CUR) query for current position). */
+
+void mustCloseFd(int *pFd);
+/* Close file descriptor *pFd if >= 0, abort if there's an error, set *pFd = -1. */
+
+#define writeOneFd(fd, var) mustWriteFd((fd), &(var), sizeof(var))
+/* Write out one variable to file descriptor fd. */
+
+#define readOne(file, var) (fread(&(var), sizeof(var), 1, (file)) == 1)
+/* Read one variable from file. Returns FALSE if can't do it. */
+
+#define readOneFd(fd, var) (read((fd), &(var), sizeof(var)) == sizeof(var))
+/* Read one variable from file. Returns FALSE if can't do it. */
+
+#define mustReadOneFd(fd, var) mustReadFd((fd), &(var), sizeof(var))
+/* Read one variable from file or die. */
+
+#define memReadOne(pPt, var) memRead((pPt), &(var), sizeof(var))
+/* Read one variable from memory. */
+
+void writeString(FILE *f, char *s);
+/* Write a 255 or less character string to a file.
+ * This will write the length of the string in the first
+ * byte then the string itself. */
+
+char *readString(FILE *f);
+/* Read a string (written with writeString) into
+ * memory.  freeMem the result when done. Returns
+ * NULL at EOF. */
+
+char *mustReadString(FILE *f);
+/* Read a string.  Squawk and die at EOF or if any problem. */
+
+boolean fastReadString(FILE *f, char buf[256]);
+/* Read a string into buffer, which must be long enough
+ * to hold it.  String is in 'writeString' format.
+ * Returns FALSE at EOF. */
+
+void msbFirstWriteBits64(FILE *f, bits64 x);
+/* Write out 64 bit number in manner that is portable across architectures */
+
+bits64 msbFirstReadBits64(FILE *f);
+/* Write out 64 bit number in manner that is portable across architectures */
+
+void carefulClose(FILE **pFile);
+/* Close file if open and null out handle to it. */
+
+boolean carefulCloseWarn(FILE **pFile);
+/* Close file if open and null out handle to it.
+ * Return FALSE and print a warning message if there
+ * is a problem.*/
+
+char *firstWordInFile(char *fileName, char *wordBuf, int wordBufSize);
+/* Read the first word in file into wordBuf. */
+
+struct fileOffsetSize
+/* A piece of a file. */
+   {
+   struct fileOffsetSize *next;	/* Next in list. */
+   bits64	offset;		/* Start offset of block. */
+   bits64	size;		/* Size of block. */
+   };
+
+int fileOffsetSizeCmp(const void *va, const void *vb);
+/* Help sort fileOffsetSize by offset. */
+
+struct fileOffsetSize *fileOffsetSizeMerge(struct fileOffsetSize *inList);
+/* Returns a new list which is inList transformed to have adjacent blocks
+ * merged.  Best to use this with a sorted list. */
+
+void fileOffsetSizeFindGap(struct fileOffsetSize *list,
+	struct fileOffsetSize **pBeforeGap, struct fileOffsetSize **pAfterGap);
+/* Starting at list, find all items that don't have a gap between them and the previous item.
+ * Return at gap, or at end of list, returning pointers to the items before and after the gap. */
+
+void mustSystem(char *cmd);
+/* Execute cmd using "sh -c" or die.  (See man 3 system.) fail on errors */
+
+int roundingScale(int a, int p, int q);
+/* returns rounded a*p/q */
+
+int intAbs(int a);
+/* Return integer absolute value */
+
+#define logBase2(x)(log(x)/log(2))
+/* return log base two of number */
+
+#define round(a) ((int)((a)+0.5))
+/* Round floating point val to nearest integer. */
+
+#define roundll(a) ((long long)((a)+0.5))
+/* Round floating point val to nearest long long. */
+
+#ifndef min
+#define min(a,b) ( (a) < (b) ? (a) : (b) )
+/* Return min of a and b. */
+#endif
+
+#ifndef max
+#define max(a,b) ( (a) > (b) ? (a) : (b) )
+/* Return max of a and b. */
+#endif
+
+int  rangeIntersection(int start1, int end1, int start2, int end2);
+/* Return amount of bases two ranges intersect over, 0 or negative if no
+ * intersection. */
+
+int  positiveRangeIntersection(int start1, int end1, int start2, int end2);
+/* Return amount of bases two ranges intersect over, 0 if no
+ * intersection. */
+
+INLINE void memRead(char **pPt, void *buf, int size)
+/* Copy memory from *pPt to buf, and advance *pPt by size. */
+{
+memcpy(buf, *pPt, size);
+*pPt += size;
+}
+
+INLINE void memWrite(char **pPt, void *buf, int size)
+/* Copy memory from buf to *pPt and advance *pPt by size. */
+{
+memcpy(*pPt, buf, size);
+*pPt += size;
+}
+
+#define memWriteOne(pPt, var) memWrite((pPt), &(var), sizeof(var))
+/* Write out one variable to memory stream. */
+
+INLINE void memWriteFloat(char **pPt, float val)
+/* Write out floating point val to file.  Mostly to convert from double... */
+{
+memWriteOne(pPt, val);
+}
+
+bits64 byteSwap64(bits64 a);
+/* Swap from intel to sparc order of a 64 bit quantity. */
+
+bits64 readBits64(FILE *f, boolean isSwapped);
+/* Read and optionally byte-swap 64 bit entity. */
+
+bits64 fdReadBits64(int fd, boolean isSwapped);
+/* Read and optionally byte-swap 64 bit entity. */
+
+bits64 memReadBits64(char **pPt, boolean isSwapped);
+/* Read and optionally byte-swap 64 bit entity from memory buffer pointed to by
+ * *pPt, and advance *pPt past read area. */
+
+bits32 byteSwap32(bits32 a);
+/* Swap from intel to sparc order of a 32 bit quantity. */
+
+bits32 readBits32(FILE *f, boolean isSwapped);
+/* Read and optionally byte-swap 32 bit entity. */
+
+bits32 fdReadBits32(int fd, boolean isSwapped);
+/* Read and optionally byte-swap 32 bit entity. */
+
+bits32 memReadBits32(char **pPt, boolean isSwapped);
+/* Read and optionally byte-swap 32 bit entity from memory buffer pointed to by
+ * *pPt, and advance *pPt past read area. */
+
+bits16 byteSwap16(bits16 a);
+/* Swap from intel to sparc order of a 16 bit quantity. */
+
+bits16 readBits16(FILE *f, boolean isSwapped);
+/* Read and optionally byte-swap 16 bit entity. */
+
+bits16 fdReadBits16(int fd, boolean isSwapped);
+/* Read and optionally byte-swap 16 bit entity. */
+
+bits16 memReadBits16(char **pPt, boolean isSwapped);
+/* Read and optionally byte-swap 32 bit entity from memory buffer pointed to by
+ * *pPt, and advance *pPt past read area. */
+
+double byteSwapDouble(double a);
+/* Return byte-swapped version of a */
+
+double readDouble(FILE *f, boolean isSwapped);
+/* Read and optionally byte-swap double-precision floating point entity. */
+
+double memReadDouble(char **pPt, boolean isSwapped);
+/* Read and optionally byte-swap double-precision floating point entity
+ * from memory buffer pointed to by *pPt, and advance *pPt past read area. */
+
+float byteSwapFloat(float a);
+/* Return byte-swapped version of a */
+
+float readFloat(FILE *f, boolean isSwapped);
+/* Read and optionally byte-swap single-precision floating point entity. */
+
+float memReadFloat(char **pPt, boolean isSwapped);
+/* Read and optionally byte-swap single-precision floating point entity
+ * from memory buffer pointed to by *pPt, and advance *pPt past read area. */
+
+void removeReturns(char* dest, char* src);
+/* Removes the '\r' character from a string.
+ * the source and destination strings can be the same,
+ * if there are no threads */
+
+int intExp(char *text);
+/* Convert text to integer expression and evaluate.
+ * Throws if it finds a non-number. */
+
+double doubleExp(char *text);
+/* Convert text to floating point expression and
+ * evaluate. */
+
+char* readLine(FILE* fh);
+/* Read a line of any size into dynamic memory, return null on EOF */
+
+off_t fileSize(char *fileName);
+/* The size of a file. */
+
+boolean fileExists(char *fileName);
+/* Does a file exist? */
+
+/*
+ Friendly name for strstrNoCase
+*/
+char *containsStringNoCase(char *haystack, char *needle);
+
+char *strstrNoCase(char *haystack, char *needle);
+/* A case-insensitive strstr */
+
+int vasafef(char* buffer, int bufSize, char *format, va_list args);
+/* Format string to buffer, vsprintf style, only with buffer overflow
+ * checking.  The resulting string is always terminated with zero byte. */
+
+int safef(char* buffer, int bufSize, char *format, ...)
+/* Format string to buffer, vsprintf style, only with buffer overflow
+ * checking.  The resulting string is always terminated with zero byte. */
+#ifdef __GNUC__
+__attribute__((format(printf, 3, 4)))
+#endif
+;
+
+void safecpy(char *buf, size_t bufSize, const char *src);
+/* copy a string to a buffer, with bounds checking.*/
+
+void safencpy(char *buf, size_t bufSize, const char *src, size_t n);
+/* copy n characters from a string to a buffer, with bounds checking.
+ * Unlike strncpy, always null terminates the result */
+
+void safecat(char *buf, size_t bufSize, const char *src);
+/* Append  a string to a buffer, with bounds checking.*/
+
+void safencat(char *buf, size_t bufSize, const char *src, size_t n);
+/* append n characters from a string to a buffer, with bounds checking. */
+
+char *naForNull(char *s);
+/* Return 'n/a' if s is NULL, otherwise s. */
+
+char *naForEmpty(char *s);
+/* Return n/a if s is "" or NULL, otherwise s. */
+
+char *emptyForNull(char *s);
+/* Return "" if s is NULL, otherwise s. */
+
+char *nullIfAllSpace(char *s);
+/* Return NULL if s is all spaces, otherwise s. */
+
+char *trueFalseString(boolean b);
+/* Return "true" or "false" */
+
+void uglyTime(char *label, ...);
+/* Print label and how long it's been since last call.  Call with
+ * a NULL label to initialize. */
+
+/*	In case the development environment does not supply INFINITY	*/
+#if !defined(INFINITY)
+#define INFINITY (1.0/0.0)
+#endif
+
+void makeDirs(char* path);
+/* make a directory, including parent directories */
+
+char *skipNumeric(char *s);
+/* Return first char of s that's not a digit */
+
+char *skipToNumeric(char *s);
+/* skip up to where numeric digits appear */
+
+char *splitOffNonNumeric(char *s);
+/* Split off non-numeric part, e.g. mm of mm8. Result should be freed when done */
+
+char *splitOffNumber(char *db);
+/* Split off number part, e.g. 8 of mm8. Result should be freed when done */
+
+void vaDumpStack(char *format, va_list args);
+/* debugging function to run the pstack program on the current process. In
+ * prints a message, following by a new line, and then the stack track.  Just
+ * prints errors to stderr rather than aborts. For debugging purposes
+ * only.  */
+
+void dumpStack(char *format, ...)
+/* debugging function to run the pstack program on the current process. In
+ * prints a message, following by a new line, and then the stack track.  Just
+ * prints errors to stderr rather than aborts. For debugging purposes
+ * only.  */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+// SETTING_ON set of macros are frequently used comparisons of string values for boolean questions.
+// Notice the subtle difference between NOT_ON and IS_OFF.
+//        NOT_ON could be NULL but IS_OFF must be explicitly set
+#define SETTING_IS_ON(setting) (  setting && (sameWord(setting,"on") || sameWord(setting,"true") \
+                               || sameWord(setting,"yes") || sameWord(setting,"enabled") \
+                               || atoi(setting) != 0) )
+#define SETTING_NOT_ON(setting)   (!SETTING_IS_ON(setting))
+#define SETTING_IS_OFF(setting) (  setting && (sameWord(setting,"off") \
+                                || sameWord(setting,"false") || sameWord(setting,"no") \
+                                || sameWord(setting,"disabled") || sameWord(setting,"0")) )
+
+// Standard bit mask macros
+#define BITS_ADD(    flags,bits) ((flags) = ((flags) |  (bits)))
+#define BITS_REMOVE( flags,bits) ((flags) = ((flags) & ~(bits)))
+#define BITS_ARE_ON( flags,bits) (((flags) & (bits)) == (bits))
+#define BITS_ARE_OFF(flags,bits) (((flags) & (bits)) == 0)
+
+// It is sometimes useful to distinguish between 3 "boolean" states: TRUE, FALSE and UNKNOWN
+enum enumBool
+    {
+    beUnknown=0,              // Not yet set
+    ebYes=1,                  // already set to TRUE
+    ebNo=-1                   // already set to FALSE
+    };
+#define SET_TO_YES(ebool) { (ebool) = ebYes; }
+#define SET_TO_NO(ebool)  { (ebool) = ebNo; }
+#define IS_YES(ebool)     ((ebool) == ebYes)
+#define IS_NO(ebool)      ((ebool) == ebNo)
+#define IS_KNOWN(ebool)   (IS_YES(ebool) || IS_NO(ebool))
+#define IS_TRUE           IS_YES
+#define IS_FALSE          IS_NO
+
+time_t mktimeFromUtc (struct tm *t);
+/* Return time_t for tm in UTC (GMT)
+ * Useful for stuff like converting to time_t the
+ * last-modified HTTP response header
+ * which is always GMT. Returns -1 on failure of mktime */
+
+
+time_t dateToSeconds(const char *date,const char*format);
+// Convert a string date to time_t
+
+boolean dateIsOld(const char *date,const char*format);
+// Is this string date older than now?
+
+char *dateAddTo(char *date,char *format,int addYears,int addMonths,int addDays);
+/* Add years,months,days to a formatted date and returns the new date as a cloned string
+*  format is a strptime/strftime format: %F = yyyy-mm-dd */
+
+#endif /* COMMON_H */
diff --git a/inc/common.mk b/inc/common.mk
new file mode 100644
index 0000000..ffb11ff
--- /dev/null
+++ b/inc/common.mk
@@ -0,0 +1,33 @@
+CC=gcc
+COPT=-O -g
+HG_DEFS=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE -DMACHTYPE_${MACHTYPE}
+HG_INC=-I../inc -I../../inc -I../../../inc -I../../../../inc -I../../../../../inc
+
+#global external libraries 
+L=
+
+# pthreads is required
+L+=-pthread
+
+ifeq (${BINDIR},)
+    BINDIR = ${HOME}/bin/${MACHTYPE}
+endif
+
+MKDIR=mkdir -p
+ifeq (${STRIP},)
+   STRIP=strip
+endif
+
+# portable naming of compiled executables: add ".exe" if compiled on 
+# Windows (with cygwin).
+ifeq (${OS}, Windows_NT)
+  AOUT=a
+  EXE=.exe
+else
+  AOUT=a.out
+  EXE=
+endif
+
+%.o: %.c
+	${CC} ${COPT} ${CFLAGS} ${HG_DEFS} ${LOWELAB_DEFS} ${HG_WARN} ${HG_INC} ${XINC} -o $@ -c $<
+
diff --git a/inc/correlate.h b/inc/correlate.h
new file mode 100644
index 0000000..7bb4858
--- /dev/null
+++ b/inc/correlate.h
@@ -0,0 +1,39 @@
+/* correlate - calculate r, also known as Pearson's correlation
+ * coefficient.  r*r has the nice property that it explains
+ * how much of one variable's variation can be explained as
+ * a linear function of the other variable's variation. */
+#ifndef CORRELATE_H
+#define CORRELATE_H
+
+struct correlate
+/* This helps manage correlations. */
+    {
+    struct correlate *next;	/* Next in list */
+    double sumX;		/* Sum of all X's so far. */
+    double sumY;		/* Sum of all Y's so far. */
+    double sumXY;		/* Sum of all X*Y */
+    double sumXX;		/* Sum of all X*X */
+    double sumYY;		/* Sum of all Y*Y */
+    long long n;		/* Number of samples. */
+    };
+
+struct correlate *correlateNew();
+/* Return new correlation handler. */
+
+void correlateFree(struct correlate **pC);
+/* Free up correlator. */
+
+void correlateNext(struct correlate *c, double x, double y);
+/* Add next sample to correlation. */
+
+void correlateNextMulti(struct correlate *c, double x, double y, int count);
+/* Do same thing as calling correlateNext with x and y count times. */
+
+double correlateResult(struct correlate *c);
+/* Returns correlation (aka R) */
+
+double correlateArrays(double *x, double *y, int size);
+/* Return correlation of two arrays of doubles. */
+
+#endif /* CORRELATE_H */
+
diff --git a/inc/crTree.h b/inc/crTree.h
new file mode 100644
index 0000000..1e8643b
--- /dev/null
+++ b/inc/crTree.h
@@ -0,0 +1,90 @@
+/* crTree chromosome r tree. This module creates and uses a disk-based index that can find items
+ * that overlap with a chromosome range - something of the form chrN:start-end - with a
+ * minimum of disk access.  It is implemented with a combination of bPlusTrees and r-trees. 
+ * The items being indexed can overlap with each other.  
+ * 
+ * There's two main sides to using this module - creating an index, and using it.
+ *
+ * The first step of index creation is actually to insure that the file being indexed
+ * is ordered by chromosome,start,end.  For a .bed file you can insure this
+ * with the command:
+ *     sort -k1,1 -k2,2n -k3,3n unsorted.bed > sorted.bed
+ * Note that the the chromosome field is sorted alphabetically and the start and end
+ * fields are sorted numerically.
+ *
+ * Once this is done then the index creation program scans the input file, and
+ * makes a list of crTreeItems, one for each item in the file. A crTreeItem just 
+ * contains the chromosome range and file offset for an item. In the process of scanning, 
+ * build up a hash containing the chromosome names (using hashStoreName) rather than allocating
+ * a separate string for each chromosome name in each item.  Pass the list and the
+ * hash to crTreeFileCreate.
+ *
+ * Using an index is done in two steps.  First you open the index with crTreeFileOpen,
+ * and then you use crTreeFindOverlappingBlocks to find parts of the file the overlap
+ * with your query range.  The result of a crTreeFindOverlappingBlocks call is a list
+ * of regions in the file.  These regions typically include some non-overlapping items
+ * as well.  It is up to the caller to parse through the resulting region list to
+ * convert it from just bytes on disk into the memory data structure.  During this
+ * parsing you should ignore items that don't overlap your range of interest.
+ *
+ * The programs crTreeIndexBed and crTreeSearchBed create and search a crTree index
+ * for a bed file, and are useful examples to view for other programs that want to
+ * use the crTree system. */
+
+#ifndef CRTREE_H
+#define CRTREE_H
+
+struct crTreeFile
+/* Chromosome R tree index file handle. */
+    {
+    struct crTreeFile *next;	/* Next in list of index files if any. */
+    char *fileName;		/* Name of file - for better error reporting. */
+    struct udcFile *udc;			/* Open file handle. */
+    struct bptFile *chromBpt;	/* Index of chromosomes. */
+    struct cirTreeFile *cir;	/* Index of ranges. */
+    boolean isSwapped;		/* If TRUE need to byte swap everything. */
+    bits64 chromOffset;		/* Offset of chromosome index. */
+    bits64 cirOffset;		/* Offset of range index. */
+    };
+
+struct crTreeFile *crTreeFileOpen(char *fileName);
+/* Open up r-tree index file - reading headers and verifying things. */
+
+void crTreeFileClose(struct crTreeFile **pCrt);
+/* Close and free up crTree file opened with crTreeFileAttach. */
+
+struct fileOffsetSize *crTreeFindOverlappingBlocks(struct crTreeFile *crt, 
+	char *chrom, bits32 start, bits32 end);
+/* Return list of file blocks that between them contain all items that overlap
+ * start/end on chromIx.  Also there will be likely some non-overlapping items
+ * in these blocks too. When done, use slListFree to dispose of the result. */
+
+struct crTreeItem
+/* A chromosome and an interval inside it. */
+    {
+    struct crTreeItem *next;  /* Next in singly linked list. */
+    char *chrom;	/* Name of chromosome not allocated here. */
+    bits32 start;	/* Start position in chromosome. */
+    bits32 end;	/* One past last base in interval in chromosome. */
+    bits64 fileOffset;	/* Offset of item in file we are indexing. */
+    };
+
+void crTreeFileCreateInputCheck(struct crTreeItem *itemList, struct hash *chromHash, 
+	bits32 blockSize, bits32 itemsPerSlot, bits64 endPosition, char *fileName);
+/* Do sanity checking on itemList and chromHash and endPosition.  Make sure that itemList is
+ * sorted properly mostly. */
+
+void crTreeFileCreate(
+	struct crTreeItem *itemList,  /* List of all items - sorted here and in underlying file. */
+	struct hash *chromHash,	      /* Hash of all chromosome names. */
+	bits32 blockSize,	/* R tree block size - # of children for each node. 1024 is good. */
+	bits32 itemsPerSlot,	/* Number of items to put in each index slot at lowest level.
+				 * Typically either blockSize/2 or 1. */
+	bits64 endPosition,	/* File offset after have read all items in file. */
+	char *fileName);        /* Name of output file. */
+/* Create a cr tree index of file. The itemList contains the position of each item in the
+ * chromosome and in the file being indexed.  Both the file and the itemList must be sorted
+ * by chromosome (alphabetic), start (numerical), end (numerical). */
+
+#endif /* CRTREE_H */
+
diff --git a/inc/crudeali.h b/inc/crudeali.h
new file mode 100644
index 0000000..41f0cb7
--- /dev/null
+++ b/inc/crudeali.h
@@ -0,0 +1,26 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* crudeAli.h - Interface to the fast, crude blast-like aligner. */
+
+#ifndef CRUDEALI_H
+#define CRUDEALI_H
+
+struct crudeAli
+/* Stored info on a crude alignment. */
+    {
+    struct crudeAli *next;
+    int chromIx;
+    int start, end;
+    int score;
+    char strand;
+    int qStart, qEnd;
+    };
+
+struct crudeAli *crudeAliFind(DNA *probe, int probeSize, struct nt4Seq **chrome, int chromeCount, int tileSize, int minScore);
+/* Returns a list of crude alignments.  (You can free this with slFreeList() */
+
+#endif /* CRUDEALI_H */
+
diff --git a/inc/diGraph.h b/inc/diGraph.h
new file mode 100644
index 0000000..58f43f4
--- /dev/null
+++ b/inc/diGraph.h
@@ -0,0 +1,202 @@
+/* diGraph - Directed graph routines. */
+#ifndef DIGRAPH_H
+#define DIGRAPH_H
+
+#ifndef DLIST_H
+#include "dlist.h"
+#endif
+
+struct diGraph
+/* A directed graph. */
+    {
+    struct dgNode *nodeList;
+    struct hash *nodeHash;
+    struct dlList *edgeList;
+    };
+
+struct dgNode
+/* A node on a directed graph */
+    {
+    struct dgNode *next;   /* Next in master node list. */
+    char *name;            /* Name of node (allocated in hash). */
+    void *val;             /* Value of node. */
+    struct dgConnection *nextList;  /* Ways out of node. */
+    struct dgConnection *prevList;  /* Ways into node. */
+    int topoOrder;      /* Topographical order after call to dgTopoSort. */
+    int component;      /* Connected component number after call to dgConnectedComponents. */
+    int priority;       /* Node priority. */
+    struct dgNode *tempEntry;  /* Way in for breadth first search */
+    bool visited;       /* Visit order in depth first traversal. */
+    bool conn;	        /* Flag for connection algorithms. */
+    bool flagA;         /* Flag used in rangeGraph algorithms. */
+    bool flagB;         /* Currently unused flag. */
+    };
+
+struct dgEdge
+/* An edge on graph */
+    {
+    void *val;		/* Value of edge. */
+    struct dgNode *a;   /* Node on incoming side. */
+    struct dgNode *b;   /* Node on outgoing side. */
+    };
+
+struct dgConnection
+/* Connects one node to another. Linked to edge. */
+    {
+    struct dgConnection *next;  /* Next in list. */
+    struct dgNode *node;        /* Node this connects to. */
+    struct dlNode *edgeOnList;  /* Associated edge. */
+    };
+
+struct dgNodeRef
+/* A reference to a node. */
+    {
+    struct dgNodeRef *next;	/* Next in list. */
+    struct dgNode *node;        /* Pointer to node. */
+    };
+
+struct dgEdgeRef
+/* A reference to an edge. */
+    {
+    struct dgEdgeRef *next;	/* Next in list. */
+    struct dgEdge *edge;        /* Reference to edge. */
+    };
+
+struct diGraph *dgNew();
+/* Return a new directed graph object. */
+
+void dgFree(struct diGraph **pGraph);
+/* Free a directed graph. */
+
+struct dgNode *dgAddNode(struct diGraph *dg, char *name, void *val);
+/* Create new node in graph. */
+
+struct dgNode *dgAddNumberedNode(struct diGraph *dg, int id, void *val);
+/* Create new node with a number instead of a name. */
+ 
+struct dgNode *dgFindNode(struct diGraph *dg, char *name);
+/* Find existing node in graph. */
+
+struct dgNode *dgFindNumberedNode(struct diGraph *dg, int id);
+/* Find node given number. */
+
+void *dgNodeVal(struct dgNode *node);
+/* Return value associated with node. */
+
+void *dgNodeName(struct dgNode *node);
+/* Return name associated with node. */
+
+int dgNodeNumber(struct dgNode *node);
+/* Return number of node.  (Will likely return 0 if node
+ * was added with a name rather than a number). */
+
+struct dgEdge *dgConnect(struct diGraph *dg, struct dgNode *a, struct dgNode *b);
+/* Connect node a to node b.  Returns connecting edge. */
+
+struct dgEdge *dgConnectWithVal(struct diGraph *dg, struct dgNode *a, struct dgNode *b, void *val);
+/* Connect node a to node b and put val on edge. */
+
+void dgDisconnect(struct diGraph *dg, struct dgNode *a, struct dgNode *b);
+/* Disconnect nodes a and b. */
+
+struct dgEdge *dgDirectlyFollows(struct diGraph *dg, struct dgNode *a, struct dgNode *b);
+/* Return TRUE if b directly follows a. */
+
+boolean dgPathExists(struct diGraph *dg, struct dgNode *a, struct dgNode *b);
+/* Return TRUE if there's a path from a to b. */
+
+struct dgNodeRef *dgFindPath(struct diGraph *dg, struct dgNode *a, struct dgNode *b);
+/* Find shortest path from a to b.  Return NULL if can't be found. */
+
+struct dgNodeRef *dgFindConnectedToNode(struct diGraph *dg, struct dgNode *a);
+/* Return reference list of all nodes connected to a, including a.
+ * slFreeList this list when done. */
+
+struct dgNodeRef *dgFindNewConnected(struct diGraph *dg, struct dgNode *a);
+/* Find a connected component guaranteed not to be covered before 
+ * that includes a. */
+
+struct dgNodeRef *dgFindNewConnectedWithVals(struct diGraph *dg, struct dgNode *a);
+/* Find a connected component guaranteed not to be covered before 
+ * that includes a.  Connected components must have values*/
+
+struct dgNodeRef *dgFindNextConnected(struct diGraph *dg);
+/* Return list of nodes that make up next connected component,
+ * or NULL if no more components.  slFreeList this when
+ * done.  Call "dgClearConnFlags" before first call to this.
+ * Do not call dgFindConnectedToNode between dgFindFirstConnected 
+ * and this as they use the same flag variables to keep track of
+ * what vertices are used. */
+
+struct dgNodeRef *dgFindNextConnectedWithVals(struct diGraph *dg);
+/* Like dgFindConnected, but only considers graph nodes that
+ * have a val attached. */
+
+int dgConnectedComponents(struct diGraph *dg);
+/* Count number of connected components and set component field
+ * of each node to reflect which component it is in. */
+
+int dgConnectedComponentsWithVals(struct diGraph *dg);
+/* Count number of connected components and set component field
+ * of each node to reflect which component it is in. Only
+ * consider components with values. */
+
+void dgTopoSort(struct diGraph *dg);
+/* Fill in topological order of nodes. */
+
+boolean dgHasCycles(struct diGraph *dg);
+/* Return TRUE if directed graph has cycles. */
+
+boolean dgParentsAllVisited(struct dgNode *node);
+/* Return TRUE if all parents of node have  been visited. */
+
+struct dgNodeRef *dgConstrainedPriorityOrder(struct diGraph *dg);
+/* Return traversal of graph in priority order subject to
+ * constraint that all parents must be output before
+ * their children regardless of node priority. 
+ * Graph must be cycle free. */
+
+boolean dgRangesConsistent(struct diGraph *rangeGraph,
+   boolean (*findEdgeRange)(struct dgEdge *edge, int *retMin, int *retMax) );
+/* Return TRUE if graph with a range of allowable distances associated
+ * with each edge is internally consistent. */
+
+boolean dgAddedRangeConsistent(struct diGraph *rangeGraph,
+   struct dgNode *a, struct dgNode *b, int abMin, int abMax,
+   boolean (*findEdgeRange)(struct dgEdge *edge, int *retMin, int *retMax) );
+/* Return TRUE if graph with a range of allowable distances associated
+ * with each edge would be internally consistent if add edge from a to b
+ * with given min/max values. */
+
+struct dgEdgeRef *dgFindSubEdges(struct diGraph *dg, struct dgNodeRef *subGraph);
+/* Return list of edges in graph that connected together nodes in subGraph. */
+
+void dgSwapEdges(struct diGraph *dg, struct dgEdgeRef *erList);
+/* Swap polarity of all edges in erList.  (Assumes you don't have
+ * edges going both directions in graph.) */
+
+void dgClearConnFlags(struct diGraph *dg);
+/* Clear out conn flags. */
+
+void dgClearVisitFlags(struct diGraph *dg);
+/* Clear out visit order flags. */
+
+struct dgNodeRef *dgFindNodeInRefList(struct dgNodeRef *refList, struct dgNode *node);
+/* Return reference to node if in list, or NULL if not. */
+
+struct dgConnection *dgFindNodeInConList(struct dgConnection *conList, struct dgNode *node);
+/* Return connection to node if in list, or NULL if not. */
+
+struct dgConnection *dgNextList(struct dgNode *node);
+/* Return list of connections out of this node. Don't free (or rearrange)
+ * this list please. */
+
+struct dgConnection *dgPrevList(struct dgNode *node);
+/* Return list of connections into this node. Don't free (or rearrange)
+ * this list please. */
+
+void dgDumpGraph(struct diGraph *dg, FILE *out, boolean hideIsolated);
+/* Dump info on graph to output. */
+
+#endif /* DIGRAPH_H */
+
diff --git a/inc/diGraph.h.97 b/inc/diGraph.h.97
new file mode 100644
index 0000000..f8fc310
--- /dev/null
+++ b/inc/diGraph.h.97
@@ -0,0 +1,210 @@
+/* diGraph - Directed graph routines. */
+#ifndef DIGRAPH_H
+#define DIGRAPH_H
+
+#ifndef DLIST_H
+#include "dlist.h"
+#endif
+
+struct diGraph
+/* A directed graph. */
+    {
+    struct dgNode *nodeList;
+    struct hash *nodeHash;
+    struct dlList *edgeList;
+    };
+
+struct dgNode
+/* A node on a directed graph */
+    {
+    struct dgNode *next;   /* Next in master node list. */
+    char *name;            /* Name of node (allocated in hash). */
+    void *val;             /* Value of node. */
+    struct dgConnection *nextList;  /* Ways out of node. */
+    struct dgConnection *prevList;  /* Ways into node. */
+    int topoOrder;      /* Topographical order after call to dgTopoSort. */
+    int component;      /* Connected component number after call to dgConnectedComponents. */
+    int priority;       /* Node priority. */
+    struct dgNode *tempEntry;  /* Way in for breadth first search */
+    bool visited;       /* Visit order in depth first traversal. */
+    bool conn;	        /* Flag for connection algorithms. */
+    bool flagA;         /* Flag used in rangeGraph algorithms. */
+    bool flagB;         /* Currently unused flag. */
+    };
+
+struct dgEdge
+/* An edge on graph */
+    {
+    void *val;		/* Value of edge. */
+    struct dgNode *a;   /* Node on incoming side. */
+    struct dgNode *b;   /* Node on outgoing side. */
+    bool unflippable;	/* True if can't flip this edge (specialized ooGreedy thing really) */
+    };
+
+struct dgConnection
+/* Connects one node to another. Linked to edge. */
+    {
+    struct dgConnection *next;  /* Next in list. */
+    struct dgNode *node;        /* Node this connects to. */
+    struct dlNode *edgeOnList;  /* Associated edge. */
+    };
+
+struct dgNodeRef
+/* A reference to a node. */
+    {
+    struct dgNodeRef *next;	/* Next in list. */
+    struct dgNode *node;        /* Pointer to node. */
+    };
+
+struct dgEdgeRef
+/* A reference to an edge. */
+    {
+    struct dgEdgeRef *next;	/* Next in list. */
+    struct dgEdge *edge;        /* Reference to edge. */
+    };
+
+struct diGraph *dgNew();
+/* Return a new directed graph object. */
+
+void dgFree(struct diGraph **pGraph);
+/* Free a directed graph. */
+
+struct dgNode *dgAddNode(struct diGraph *dg, char *name, void *val);
+/* Create new node in graph. */
+
+struct dgNode *dgAddNumberedNode(struct diGraph *dg, int id, void *val);
+/* Create new node with a number instead of a name. */
+ 
+struct dgNode *dgFindNode(struct diGraph *dg, char *name);
+/* Find existing node in graph. */
+
+struct dgNode *dgFindNumberedNode(struct diGraph *dg, int id);
+/* Find node given number. */
+
+void *dgNodeVal(struct dgNode *node);
+/* Return value associated with node. */
+
+void *dgNodeName(struct dgNode *node);
+/* Return name associated with node. */
+
+int dgNodeNumber(struct dgNode *node);
+/* Return number of node.  (Will likely return 0 if node
+ * was added with a name rather than a number). */
+
+struct dgEdge *dgConnect(struct diGraph *dg, struct dgNode *a, struct dgNode *b);
+/* Connect node a to node b.  Returns connecting edge. */
+
+struct dgEdge *dgConnectWithVal(struct diGraph *dg, struct dgNode *a, struct dgNode *b, void *val);
+/* Connect node a to node b and put val on edge. */
+
+struct dgEdge *dgConnectUnflippable(struct diGraph *dg, struct dgNode *a, struct dgNode *b,
+    void *val);
+/* Connect a to b with an edge than can't be flipped. */
+
+void dgDisconnect(struct diGraph *dg, struct dgNode *a, struct dgNode *b);
+/* Disconnect nodes a and b. */
+
+struct dgEdge *dgDirectlyFollows(struct diGraph *dg, struct dgNode *a, struct dgNode *b);
+/* Return TRUE if b directly follows a. */
+
+boolean dgPathExists(struct diGraph *dg, struct dgNode *a, struct dgNode *b);
+/* Return TRUE if there's a path from a to b. */
+
+struct dgNodeRef *dgFindPath(struct diGraph *dg, struct dgNode *a, struct dgNode *b);
+/* Find shortest path from a to b.  Return NULL if can't be found. */
+
+struct dgNodeRef *dgFindConnectedToNode(struct diGraph *dg, struct dgNode *a);
+/* Return reference list of all nodes connected to a, including a.
+ * slFreeList this list when done. */
+
+struct dgNodeRef *dgFindNewConnected(struct diGraph *dg, struct dgNode *a);
+/* Find a connected component guaranteed not to be covered before 
+ * that includes a. */
+
+struct dgNodeRef *dgFindNewFlippableConnected(struct diGraph *dg, struct dgNode *a);
+/* Find a connected component guaranteed not to be covered before 
+ * that includes a.  Connected components must be connected by flippable
+ * edges. */
+
+struct dgNodeRef *dgFindNextConnected(struct diGraph *dg);
+/* Return list of nodes that make up next connected component,
+ * or NULL if no more components.  slFreeList this when
+ * done.  Call "dgClearConnFlags" before first call to this.
+ * Do not call dgFindConnectedToNode between dgFindFirstConnected 
+ * and this as they use the same flag variables to keep track of
+ * what vertices are used. */
+
+struct dgNodeRef *dgFindNextFlippableConnected(struct diGraph *dg);
+/* Like dgFindConnected, but only considers graph nodes that
+ * are conencted by a flippable edge. */
+
+int dgConnectedComponents(struct diGraph *dg);
+/* Count number of connected components and set component field
+ * of each node to reflect which component it is in. */
+
+int dgConnectedFlippableComponents(struct diGraph *dg);
+/* Count number of connected components and set component field
+ * of each node to reflect which component it is in. Only
+ * consider components connected by flippable edges. */
+
+void dgTopoSort(struct diGraph *dg);
+/* Fill in topological order of nodes. */
+
+boolean dgHasCycles(struct diGraph *dg);
+/* Return TRUE if directed graph has cycles. */
+
+boolean dgParentsAllVisited(struct dgNode *node);
+/* Return TRUE if all parents of node have  been visited. */
+
+struct dgNodeRef *dgConstrainedPriorityOrder(struct diGraph *dg);
+/* Return traversal of graph in priority order subject to
+ * constraint that all parents must be output before
+ * their children regardless of node priority. 
+ * Graph must be cycle free. */
+
+boolean dgRangesConsistent(struct diGraph *rangeGraph,
+   boolean (*findEdgeRange)(struct dgEdge *edge, int *retMin, int *retMax) );
+/* Return TRUE if graph with a range of allowable distances associated
+ * with each edge is internally consistent. */
+
+boolean dgAddedRangeConsistent(struct diGraph *rangeGraph,
+   struct dgNode *a, struct dgNode *b, int abMin, int abMax,
+   boolean (*findEdgeRange)(struct dgEdge *edge, int *retMin, int *retMax) );
+/* Return TRUE if graph with a range of allowable distances associated
+ * with each edge would be internally consistent if add edge from a to b
+ * with given min/max values. */
+
+struct dgEdgeRef *dgFindSubEdges(struct diGraph *dg, struct dgNodeRef *subGraph,
+	boolean onlyFlippable);
+/* Return list of edges in graph that connected together nodes in subGraph. 
+ * Optionally return only flippable edges. */
+
+void dgSwapEdges(struct diGraph *dg, struct dgEdgeRef *erList);
+/* Swap polarity of all edges in erList.  (Assumes you don't have
+ * edges going both directions in graph.) */
+
+void dgClearConnFlags(struct diGraph *dg);
+/* Clear out conn flags. */
+
+void dgClearVisitFlags(struct diGraph *dg);
+/* Clear out visit order flags. */
+
+struct dgNodeRef *dgFindNodeInRefList(struct dgNodeRef *refList, struct dgNode *node);
+/* Return reference to node if in list, or NULL if not. */
+
+struct dgConnection *dgFindNodeInConList(struct dgConnection *conList, struct dgNode *node);
+/* Return connection to node if in list, or NULL if not. */
+
+struct dgConnection *dgNextList(struct dgNode *node);
+/* Return list of connections out of this node. Don't free (or rearrange)
+ * this list please. */
+
+struct dgConnection *dgPrevList(struct dgNode *node);
+/* Return list of connections into this node. Don't free (or rearrange)
+ * this list please. */
+
+void dgDumpGraph(struct diGraph *dg, FILE *out, boolean hideIsolated);
+/* Dump info on graph to output. */
+
+#endif /* DIGRAPH_H */
+
diff --git a/inc/dlist.h b/inc/dlist.h
new file mode 100644
index 0000000..27cd226
--- /dev/null
+++ b/inc/dlist.h
@@ -0,0 +1,138 @@
+/* dlist.h - Headers for generic doubly-linked list routines. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef DLIST_H
+#define DLIST_H
+
+#ifndef COMMON_H
+#include "common.h"
+#endif
+
+struct dlNode
+/* An element on a doubly linked list. */
+    {
+    struct dlNode *next;
+    struct dlNode *prev;
+    void *val;
+    };
+
+struct dlList
+/* A doubly linked list. */
+    {
+    struct dlNode *head;
+    struct dlNode *nullMiddle;
+    struct dlNode *tail;
+    };
+
+#define dlEnd(node) (node->next == NULL)
+/* True if node past end. */
+
+#define dlStart(node) (node->prev == NULL)
+/* True if node before start. */
+
+/* Iterate on a doubly linked list as so:
+    for (el = list->head; !dlEnd(el); el = el->next)
+        val = el->val;
+   or
+    for (el = list->tail; !dlStart(el); el = el->prev)
+        val = el->val;
+ */
+
+struct dlList *newDlList();
+/* Return a new doubly linked list. */
+
+#define dlListNew newDlList
+/* Add object-first synonym. */
+
+void dlListInit(struct dlList *dl);
+/* Initialize list to be empty */
+
+void dlListReset(struct dlList *dl);
+/* Reset a list to the empty state (does not free values)  */
+
+void freeDlList(struct dlList **pList);
+/* Free up a doubly linked list and it's nodes (but not the node values). */
+#define dlListFree freeDlList
+
+void freeDlListAndVals(struct dlList **pList);
+/* Free all values in doubly linked list and the list itself.  (Just calls
+ * freeMem on all values. */
+#define dlListFreeAndVals freeDlListAndVals
+
+void dlAddBefore(struct dlNode *anchor, struct dlNode *newNode);
+/* Add a node to list before anchor member. */
+
+void dlAddAfter(struct dlNode *anchor, struct dlNode *newNode);
+/* Add a node to list after anchor member. */
+
+void dlAddHead(struct dlList *list, struct dlNode *newNode);
+/* Add a node to head of list. */
+
+void dlAddTail(struct dlList *list, struct dlNode *newNode);
+/* Add a node to tail of list. */
+
+struct dlNode *dlAddValBefore(struct dlNode *anchor, void *val);
+/* Create a node containing val and add to list before anchor member. */
+
+struct dlNode *dlAddValAfter(struct dlNode *anchor, void *val);
+/* Create a node containing val and add to list after anchor member. */
+
+struct dlNode *dlAddValHead(struct dlList *list, void *val);
+/* Create a node containing val and add to head of list. */
+
+struct dlNode *dlAddValTail(struct dlList *list, void *val);
+/* Create a node containing val and add to tail of list. */
+
+void dlRemove(struct dlNode *node);
+/* Removes a node from list. Node is not freed. */
+
+void dlRemoveHead(struct dlList *list);
+/* Removes head from list. Node is not freed. */
+
+void dlRemoveTail(struct dlList *list);
+/* Remove tail from list. Node is not freed.  */
+
+struct dlNode *dlPopHead(struct dlList *list);
+/* Remove first node from list and return it. */
+
+struct dlNode *dlPopTail(struct dlList *list);
+/* Remove last node from list and return it. */
+
+void dlDelete(struct dlNode **nodePtr);
+/* Removes a node from list and frees it. */
+
+int dlCount(struct dlList *list);
+/* Return length of list. */
+
+boolean dlEmpty(struct dlList *list);
+/* Return TRUE if list is empty. */
+
+#define dlIsEmpty(list) ((list)->head->next == NULL)
+/* Return TRUE if list is empty.  Macro version of above. */
+
+struct dlNode *dlGetBeforeHead(struct dlList *list);
+/* Get the node before the head of the list */
+
+struct dlNode *dlGetAfterTail(struct dlList *list);
+/* Get the node after the tail of the list */
+
+void dlSort(struct dlList *list, int (*compare )(const void *elem1,  const void *elem2));
+/* Sort a doubly linked list with Qsort and a temporary array. 
+ * The arguments to the compare function in real, non-void, life
+ * are pointers to pointers of the type that is in the val field of 
+ * the nodes of the list. */
+
+void *dlListToSlList(struct dlList *dList);
+/* Return slList from dlList. */
+
+void dlCat(struct dlList *a, struct dlList *b);
+/* Move items from b to end of a. */
+
+struct dlNode *dlValInList(struct dlList *list, void *val);
+/* Return node on list if any that has associated val. */
+
+#endif /* DLIST_H */
+
+
diff --git a/inc/dnaLoad.h b/inc/dnaLoad.h
new file mode 100644
index 0000000..dcd798b
--- /dev/null
+++ b/inc/dnaLoad.h
@@ -0,0 +1,40 @@
+/* dnaLoad - Load dna from a variaty of file formats. */
+
+#ifndef DNALOAD_H
+#define DNALOAD_H
+
+struct dnaLoad;		/* Structure we keep private. */
+
+struct dnaLoad *dnaLoadOpen(char *fileName);
+/* Return new DNA loader.  Call dnaLoadNext() on this until
+ * you get a NULL return, then dnaLoadClose(). */
+
+struct dnaSeq *dnaLoadNext(struct dnaLoad *dl);
+/* Return next dna sequence. */
+
+int dnaLoadCurStart(struct dnaLoad *dl);
+/* Returns the start offset of current sequence within a larger
+ * sequence.  Useful for programs that want to auto-lift
+ * nib and 2bit fragments.  Please call only after a
+ * sucessful dnaLoadNext. */
+
+int dnaLoadCurEnd(struct dnaLoad *dl);
+/* Returns the end offset of current sequence within a larger
+ * sequence.  Useful for programs that want to auto-lift
+ * nib and 2bit fragments.  Please call only after a
+ * sucessful dnaLoadNext. */
+
+int dnaLoadCurSize(struct dnaLoad *dl);
+/* Returns the size of the parent sequence.  Useful for
+ * auto-lift programs.  Please call only after dnaLoadNext. */
+
+void dnaLoadClose(struct dnaLoad **pDl);
+/* Free up resources associated with dnaLoad. */
+
+struct dnaSeq *dnaLoadAll(char *fileName);
+/* Return list of all DNA referenced in file.  File
+ * can be either a single fasta file, a single .2bit
+ * file, a .nib file, or a text file containing
+ * a list of the above files. DNA is mixed case. */
+
+#endif /* DNALOAD_H */
diff --git a/inc/dnaMarkov.h b/inc/dnaMarkov.h
new file mode 100644
index 0000000..552422f
--- /dev/null
+++ b/inc/dnaMarkov.h
@@ -0,0 +1,43 @@
+/* dnaMarkov - stuff to build 1st, 2nd, 3rd, and coding
+ * 3rd degree Markov models for DNA. */
+
+#ifndef DNAMARKOV_H
+#define DNAMARKOV_H
+
+void dnaMark0(struct dnaSeq *seqList, double mark0[5], int slogMark0[5]);
+/* Figure out frequency of bases in input.  Results go into
+ * mark0 and optionally in scaled log form into slogMark0.
+ * Order is N, T, C, A, G.  (TCAG is our normal order) */
+
+void dnaMark1(struct dnaSeq *seqList, double mark0[5], int slogMark0[5], 
+	double mark1[5][5], int slogMark1[5][5]);
+/* Make up 1st order Markov model - probability that one nucleotide
+ * will follow another. Input is sequence and 0th order Markov models.
+ * Output is first order Markov model. slogMark1 can be NULL. */
+
+void dnaMark2(struct dnaSeq *seqList, double mark0[5], int slogMark0[5],
+	double mark1[5][5], int slogMark1[5][5],
+	double mark2[5][5][5], int slogMark2[5][5][5]);
+/* Make up 1st order Markov model - probability that one nucleotide
+ * will follow the previous two. */
+
+void dnaMarkTriple(struct dnaSeq *seqList, 
+    double mark0[5], int slogMark0[5],
+    double mark1[5][5], int slogMark1[5][5],
+    double mark2[5][5][5], int slogMark2[5][5][5],
+    int offset, int advance, int earlyEnd);
+/* Make up a table of how the probability of a nucleotide depends on the previous two.
+ * Depending on offset and advance parameters this could either be a straight 2nd order
+ * Markov model, or a model for a particular coding frame. */
+
+char *dnaMark2Serialize(double mark2[5][5][5]);
+// serialize a 2nd order markov model
+
+void dnaMark2Deserialize(char *buf, double mark2[5][5][5]);
+// deserialize a 2nd order markov model from buf which was serialized with dnaMark2Serialize
+
+void dnaMarkMakeLog2(double mark2[5][5][5]);
+// convert a 2nd-order markov array to log2
+
+#endif /* DNAMARKOV_H */
+
diff --git a/inc/dnaMotif.h b/inc/dnaMotif.h
new file mode 100644
index 0000000..6d4f7b1
--- /dev/null
+++ b/inc/dnaMotif.h
@@ -0,0 +1,126 @@
+/* dnaMotif.h was originally generated by the autoSql program, which also 
+ * generated dnaMotif.c and dnaMotif.sql.  This header links the database and
+ * the RAM representation of objects. */
+
+#ifndef DNAMOTIF_H
+#define DNAMOTIF_H
+
+#ifndef DNAUTIL_H
+#include "dnautil.h"
+#endif
+
+struct dnaMotif
+/* A gapless DNA motif */
+{
+    struct dnaMotif *next;  /* Next in singly linked list. */
+    char *name; /* Motif name. */
+    int columnCount;    /* Count of columns in motif. */ 
+    float *aProb;       /* Probability of A's in each column. */ 
+    float *cProb;       /* Probability of C's in each column. */
+    float *gProb;       /* Probability of G's in each column. */
+    float *tProb;       /* Probability of T's in each column. */
+};
+
+struct dnaMotif *dnaMotifCommaIn(char **pS, struct dnaMotif *ret);
+/* Create a dnaMotif out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new dnaMotif */
+
+void dnaMotifFree(struct dnaMotif **pEl);
+/* Free a single dynamically allocated dnaMotif such as created
+ * with dnaMotifLoad(). */
+
+void dnaMotifFreeList(struct dnaMotif **pList);
+/* Free a list of dynamically allocated dnaMotif's */
+
+void dnaMotifOutput(struct dnaMotif *el, FILE *f, char sep, char lastSep);
+/* Print out dnaMotif.  Separate fields with sep. Follow last field with lastSep. */
+
+#define dnaMotifTabOut(el,f) dnaMotifOutput(el,f,'\t','\n');
+/* Print out dnaMotif as a line in a tab-separated file. */
+
+#define dnaMotifCommaOut(el,f) dnaMotifOutput(el,f,',',',');
+/* Print out dnaMotif as a comma separated list including final comma. */
+
+float dnaMotifSequenceProb(struct dnaMotif *motif, DNA *dna);
+/* Return probability of dna according to motif.  Make sure
+ * motif is probabalistic (with call to dnaMotifMakeProbabalistic
+ * if you're not sure) before calling this. */
+
+char dnaMotifBestStrand(struct dnaMotif *motif, DNA *dna);
+/* Figure out which strand of DNA is better for probabalistic motif. */
+
+double dnaMotifBitScore(struct dnaMotif *motif, DNA *dna);
+/* Return logBase2-odds score of dna given a probabalistic motif. */
+
+double dnaMotifBitScoreWithMark0Bg(struct dnaMotif *motif, DNA *dna, double mark0[5]);
+/* Return logBase2-odds score of dna given a probabalistic motif and using a 0-order markov model for the background. */
+
+double dnaMotifBitScoreWithMarkovBg(struct dnaMotif *motif, DNA *dna, double mark2[5][5][5]);
+/* Return logBase2-odds score of dna given a probabalistic motif using a 2nd-order markov model for the background.
+   motif and markd2 must be in log2 format.
+   Seq must contain an extra two bases at the front (i.e. we start scoring from dna + 2). */
+
+void dnaMotifMakeLog2(struct dnaMotif *motif);
+
+void dnaMotifNormalize(struct dnaMotif *motif);
+/* Make all columns of motif sum to one. */
+
+boolean dnaMotifIsScoreBased(struct dnaMotif *motif);
+/* Return TRUE if dnaMotif is score-based (which we decide by
+ * the presense of negative values. */
+
+void dnaMotifScoreToProb(struct dnaMotif *motif);
+/* Convert motif that is log-odds score based to motif
+ * that is probability based.  This assumes that the
+ * background distribution is simple: 25% for each base */
+
+void dnaMotifMakeProbabalistic(struct dnaMotif *motif);
+/* Change motif, which may be score or count based, to 
+ * probabalistic one, where each column adds to 1.0 */
+
+double dnaMotifBitsOfInfo(struct dnaMotif *motif, int pos);
+/* Return bits of information at position. */
+
+void dnaMotifPrintProb(struct dnaMotif *motif, FILE *f);
+/* Print DNA motif probabilities. */
+
+void dnaMotifToLogoPs2(struct dnaMotif *motif, double widthPerBase, double height, 
+                       double minHeight, char *fileName);
+/* Write logo corresponding to motif to postScript file, with extended options. minHeight
+ * is the minimum height that is excluded from information content scaling.  This allows
+ * something to show up in columns with very little information content.  Setting this
+ * to be the same as height creates an frequency-based logo.
+ */
+
+void dnaMotifToLogoPs(struct dnaMotif *motif, double widthPerBase, double height, 
+	char *fileName);
+/* Write logo corresponding to motif to postScript file. */
+
+void dnaMotifToLogoPsW(struct dnaMotif *motif, double widthPerBase, double width,
+	double height, char *fileName);
+/* Write logo corresponding to motif to postScript file. 
+ * use the whole window width, rather than just incrementing
+ * by widthPerBase */
+
+void dnaMotifToLogoPng(
+	struct dnaMotif *motif,	/* Motif to draw. */
+	double widthPerBase, 	/* Width of each base. */
+	double height, 		/* Max height. */
+	char *gsExe, 		/* ghostscript executable, NULL for default */
+	char *tempDir,          /* temp dir , NULL for default */
+	char *fileName);	/* output png file name. */
+/* Write logo corresponding to motif to png file. */
+
+void dnaMotifToLogoPGM(
+	struct dnaMotif *motif,	/* Motif to draw. */
+	double widthPerBase, 	/* Width of each base. */
+	double width, 		/* Max width. */
+	double height, 		/* Max height. */
+	char *gsExe, 		/* ghostscript executable, NULL for default */
+	char *tempDir,          /* temp dir , NULL for default */
+	char *fileName);	/* output png file name. */
+/* Write logo corresponding to motif to PGM file. */
+
+#endif /* DNAMOTIF_H */
+
diff --git a/inc/dnaseq.h b/inc/dnaseq.h
new file mode 100644
index 0000000..164b1e9
--- /dev/null
+++ b/inc/dnaseq.h
@@ -0,0 +1,73 @@
+/* dnaSeq - stuff to manage DNA sequences. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef DNASEQ_H
+#define DNASEQ_H
+
+#ifndef DNAUTIL_H
+#include "dnautil.h"
+#endif
+
+#ifndef BITS_H
+#include "bits.h"
+#endif
+
+struct dnaSeq
+/* A dna sequence in one-character per base format. */
+    {
+    struct dnaSeq *next;  /* Next in list. */
+    char *name;           /* Name of sequence. */
+    DNA *dna;             /* Sequence base by base. */
+    int size;             /* Size of sequence. */
+    Bits* mask;           /* Repeat mask (optional) */
+    };
+
+typedef struct dnaSeq bioSeq;	/* Preferred use if either DNA or protein. */
+typedef struct dnaSeq aaSeq;	/* Preferred use if protein. */
+
+struct dnaSeq *newDnaSeq(DNA *dna, int size, char *name);
+/* Create a new DNA seq. */
+
+struct dnaSeq *cloneDnaSeq(struct dnaSeq *seq);
+/* Duplicate dna sequence in RAM. */
+
+void freeDnaSeq(struct dnaSeq **pSeq);
+/* Free up DNA seq.  */
+#define dnaSeqFree freeDnaSeq
+
+void freeDnaSeqList(struct dnaSeq **pSeqList);
+/* Free up list of DNA sequences. */
+#define dnaSeqFreeList freeDnaSeqList
+
+aaSeq *translateSeqN(struct dnaSeq *inSeq, unsigned offset, unsigned size, boolean stop);
+/* Return a translated sequence.  Offset is position of first base to
+ * translate. If size is 0 then use length of inSeq. */
+
+aaSeq *translateSeq(struct dnaSeq *inSeq, unsigned offset, boolean stop);
+/* Return a translated sequence.  Offset is position of first base to
+ * translate. If stop is TRUE then stop at first stop codon.  (Otherwise 
+ * represent stop codons as 'Z'). */
+
+boolean seqIsDna(bioSeq *seq);
+/* Make educated guess whether sequence is DNA or protein. */
+
+boolean seqIsLower(bioSeq *seq);
+/* Return TRUE if sequence is all lower case. */
+
+bioSeq *whichSeqIn(bioSeq **seqs, int seqCount, char *letters);
+/* Figure out which if any sequence letters is in. */
+
+Bits *maskFromUpperCaseSeq(bioSeq *seq);
+/* Allocate a mask for sequence and fill it in based on
+ * sequence case. */
+
+struct hash *dnaSeqHash(struct dnaSeq *seqList);
+/* Return hash of sequences keyed by name. */
+
+int dnaSeqCmpName(const void *va, const void *vb);
+/* Compare to sort based on sequence name. */
+
+#endif /* DNASEQ_H */
+
diff --git a/inc/dnautil.h b/inc/dnautil.h
new file mode 100644
index 0000000..7ce450b
--- /dev/null
+++ b/inc/dnautil.h
@@ -0,0 +1,260 @@
+/* Some stuff that you'll likely need in any program that works with
+ * DNA.  Includes stuff for amino acids as well. 
+ *
+ * Assumes that DNA is stored as a character.
+ * The DNA it generates will include the bases 
+ * as lowercase tcag.  It will generally accept
+ * uppercase as well, and also 'n' or 'N' or '-'
+ * for unknown bases. 
+ *
+ * Amino acids are stored as single character upper case. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+
+#ifndef DNAUTIL_H
+#define DNAUTIL_H
+
+void dnaUtilOpen(); /* Good idea to call this before using any arrays
+		     * here.  */
+
+/* Numerical values for bases. */
+#define T_BASE_VAL 0
+#define U_BASE_VAL 0
+#define C_BASE_VAL 1
+#define A_BASE_VAL 2
+#define G_BASE_VAL 3
+#define N_BASE_VAL 4   /* Used in 1/2 byte representation. */
+
+typedef char DNA;
+typedef char AA;
+typedef char BIOPOL;	/* Biological polymer. */
+
+/* A little array to help us decide if a character is a 
+ * nucleotide, and if so convert it to lower case. 
+ * Contains zeroes for characters that aren't used
+ * in DNA sequence. */
+extern DNA ntChars[256];
+extern AA aaChars[256];
+
+/* An array that converts alphabetical DNA representation
+ * to numerical one: X_BASE_VAL as above.  For charaters
+ * other than [atgcATGC], has -1. */
+extern int ntVal[256];
+extern int aaVal[256];
+extern int ntValLower[256];	/* NT values only for lower case. */
+extern int ntValUpper[256];	/* NT values only for upper case. */
+
+/* Like ntVal, but with T_BASE_VAL in place of -1 for nonexistent nucleotides. */
+extern int ntValNoN[256];     
+
+/* Like ntVal but with N_BASE_VAL in place of -1 for 'n', 'x', '-', etc. */
+extern int ntVal5[256];
+
+/* Inverse array - takes X_BASE_VAL int to a DNA char
+ * value. */
+extern DNA valToNt[];
+
+/* Similar array that doesn't convert to lower case. */
+extern DNA ntMixedCaseChars[256];
+
+/* Another array to help us do complement of DNA  */
+extern DNA ntCompTable[256];
+
+/* Arrays to convert between lower case indicating repeat masking, and
+ * a 1/2 byte representation where the 4th bit indicates if the characeter
+ * is masked. Uses N_BASE_VAL for `n', `x', etc.
+*/
+#define MASKED_BASE_BIT 8
+extern int ntValMasked[256];
+extern DNA valToNtMasked[256];
+
+/*Complement DNA (not reverse)*/
+void complement(DNA *dna, long length);
+
+/* Reverse complement DNA. */
+void reverseComplement(DNA *dna, long length);
+
+
+/* Reverse offset - return what will be offset (0 based) to
+ * same member of array after array is reversed. */
+long reverseOffset(long offset, long arraySize);
+
+/* Switch start/end (zero based half open) coordinates
+ * to opposite strand. */
+void reverseIntRange(int *pStart, int *pEnd, int size);
+
+/* Switch start/end (zero based half open) coordinates
+ * to opposite strand. */
+void reverseUnsignedRange(unsigned *pStart, unsigned *pEnd, int size); 
+
+enum dnaCase {dnaUpper,dnaLower,dnaMixed,};
+/* DNA upper, lower, or mixed case? */
+
+/* Convert T's to U's */
+void toRna(DNA *dna);
+
+int cmpDnaStrings(DNA *a, DNA *b);
+/* Compare using screwy non-alphabetical DNA order TCGA */
+
+typedef char Codon; /* Our codon type. */
+
+/* Return single letter code (upper case) for protein.
+ * Returns X for bad input, 0 for stop codon.
+ * The "Standard" Code */
+AA lookupCodon(DNA *dna); 
+
+boolean isStopCodon(DNA *dna);
+/* Return TRUE if it's a stop codon. */
+
+boolean isKozak(char *dna, int dnaSize, int pos);
+/* Return TRUE if it's a Kozak compatible start, using a relatively
+ * weak definition (either A/G 3 bases before or G after) . */
+
+boolean isReallyStopCodon(char *dna, boolean selenocysteine);
+/* Return TRUE if it's really a stop codon, even considering
+ * possibilility of selenocysteine. */
+
+/* Returns one letter code for protein, 
+ * 0 for stop codon or X for bad input,
+ * Vertebrate Mitochondrial Code */
+AA lookupMitoCodon(DNA *dna);
+
+Codon codonVal(DNA *start);
+/* Return value from 0-63 of codon starting at start. 
+ * Returns -1 if not a codon. */
+
+DNA *valToCodon(int val);
+/* Return  codon corresponding to val (0-63) */
+
+extern char *aaAbbr(int i);
+/* return pointer to AA abbrevation */
+
+extern char aaLetter(int i);
+/* return AA letter */
+
+void dnaTranslateSome(DNA *dna, char *out, int outSize);
+/* Translate DNA upto a stop codon or until outSize-1 amino acids, 
+ * whichever comes first. Output will be zero terminated. */
+
+char *skipIgnoringDash(char *a, int size, bool skipTrailingDash);
+/* Count size number of characters, and any 
+ * dash characters. */
+
+int countNonDash(char *a, int size);
+/* Count number of non-dash characters. */
+
+int nextPowerOfFour(long x);
+/* Return next power of four that would be greater or equal to x.
+ * For instance if x < 4, return 1, if x < 16 return 2.... 
+ * (From biological point of view how many bases are needed to
+ * code this number.) */
+
+long dnaFilteredSize(char *rawDna);
+/* Return how long DNA will be after non-DNA is filtered out. */
+
+long aaFilteredSize(char *rawDna);
+/* Return how long peptide will be after non-peptide is filtered out. */
+
+void dnaFilter(char *in, DNA *out);
+/* Filter out non-DNA characters. */
+
+void aaFilter(char *in, DNA *out);
+/* Filter out non-peptide characters. */
+
+void dnaFilterToN(char *in, DNA *out);
+/* Change all non-DNA characters to N. */
+
+void upperToN(char *s, int size);
+/* Turn upper case letters to N's. */
+
+void lowerToN(char *s, int size);
+/* Turn lower case letters to N's. */
+
+void dnaBaseHistogram(DNA *dna, int dnaSize, int histogram[4]);
+/* Count up frequency of occurance of each base and store 
+ * results in histogram. Use X_BASE_VAL to index histogram. */
+
+void dnaMixedCaseFilter(char *in, DNA *out);
+/* Filter out non-DNA characters but leave case intact. */
+
+bits64 basesToBits64(char *dna, int size);
+/* Convert dna of given size (up to 32) to binary representation */
+
+bits32 packDna16(DNA *in);
+/* pack 16 bases into a word */
+
+bits16 packDna8(DNA *in);
+/* Pack 8 bases into a short word */
+
+UBYTE packDna4(DNA *in);
+/* Pack 4 bases into a UBYTE */
+
+void unpackDna(bits32 *tiles, int tileCount, DNA *out);
+/* Unpack DNA. Expands to 16x tileCount in output. */
+
+void unpackDna4(UBYTE *tiles, int byteCount, DNA *out);
+/* Unpack DNA. Expands to 4x byteCount in output. */
+
+void unalignedUnpackDna(bits32 *tiles, int start, int size, DNA *unpacked);
+/* Unpack into out, even though not starting/stopping on tile 
+ * boundaries. */
+
+int intronOrientationMinSize(DNA *iStart, DNA *iEnd, int minIntronSize);
+/* Given a gap in genome from iStart to iEnd, return 
+ * Return 1 for GT/AG intron between left and right, -1 for CT/AC, 0 for no
+ * intron. */
+
+int intronOrientation(DNA *iStart, DNA *iEnd);
+/* Given a gap in genome from iStart to iEnd, return 
+ * Return 1 for GT/AG intron between left and right, -1 for CT/AC, 0 for no
+ * intron.  Assumes minIntronSize of 32. */
+
+int dnaScore2(DNA a, DNA b);
+/* Score match between two bases (relatively crudely). */
+
+int dnaScoreMatch(DNA *a, DNA *b, int size);
+/* Compare two pieces of DNA base by base. Total mismatches are
+ * subtracted from total matches and returned as score. 'N's 
+ * neither hurt nor help score. */
+
+int aaScore2(AA a, AA b);
+/* Score match between two bases (relatively crudely). */
+
+int aaScoreMatch(AA *a, AA *b, int size);
+/* Compare two peptides aa by aa. */
+
+int  dnaOrAaScoreMatch(char *a, char *b, int size, int matchScore, int mismatchScore, 
+	char ignore);
+/* Compare two sequences (without inserts or deletions) and score. */
+
+void writeSeqWithBreaks(FILE *f, char *letters, int letterCount, int maxPerLine);
+/* Write out letters with newlines every maxLine. */
+
+int tailPolyASizeLoose(DNA *dna, int size);
+/* Return size of PolyA at end (if present).  This allows a few non-A's as 
+ * noise to be trimmed too, but skips first two aa for taa stop codon. 
+ * It is less conservative in extending the polyA region than maskTailPolyA. */
+
+int headPolyTSizeLoose(DNA *dna, int size);
+/* Return size of PolyT at start (if present).  This allows a few non-T's as 
+ * noise to be trimmed too, but skips last two tt for revcomp'd taa stop 
+ * codon.  
+ * It is less conservative in extending the polyA region than maskHeadPolyT. */
+
+int maskTailPolyA(DNA *dna, int size);
+/* Convert PolyA at end to n.  This allows a few non-A's as noise to be 
+ * trimmed too.  Returns number of bases trimmed.  */
+
+int maskHeadPolyT(DNA *dna, int size);
+/* Convert PolyT at start.  This allows a few non-T's as noise to be 
+ * trimmed too.  Returns number of bases trimmed.  */
+
+boolean isDna(char *poly, int size);
+/* Return TRUE if letters in poly are at least 90% ACGTU */
+
+boolean isAllDna(char *poly, int size);
+/* Return TRUE if letters in poly are 100% ACGTU */
+
+#endif /* DNAUTIL_H */
diff --git a/inc/dsPrint.h b/inc/dsPrint.h
new file mode 100644
index 0000000..08f458d
--- /dev/null
+++ b/inc/dsPrint.h
@@ -0,0 +1,108 @@
+// dsPrint - Dynamic string Stack based Printing.
+//
+// This module relies upon a dyString based stack of buffers which accumulate output
+// for later printing.  As a stack, only the top buffer can be filled and flushed out
+// (dsPrintFlush).  When flushing, the top buffer's content is appended to the next
+// lower buffer, unless explicitly requested otherwise (dsPrintDirectly).
+// If the stack is empty, dsPrintf will be equivalent to printf.
+//
+// Output goes to STDOUT unless a single alternative out file is registered.
+
+#ifndef DSPRINT_H      /* Wrapper to avoid including this twice. */
+#define DSPRINT_H
+
+#include "common.h"
+#include "dystring.h"
+
+int dsPrintOpen(int initialBufSize);
+// Allocate dynamic string and puts at top of stack
+// returns token to be used for later stack accounting asserts
+
+int dsPrintf(char *format, ...);
+// Prints into end of the top ds buffer, and return resulting string length
+// If there is no current buffer, this acts like a simple printf and returns -1
+#define dsPuts(str) dsPrintf("%s\n",str)
+#define dsPutc(chr) dsPrintf("%c",chr)
+#define SWAP_PRINTF
+#ifdef SWAP_PRINTF
+#define printf dsPrintf
+#define puts dsPuts
+#undef putc
+#define putc dsPutc
+#endif//def SWAP_PRINTF
+
+int dsPrintDirectly(int token,FILE *file);
+// Prints the contents of the top buffer directly to a file.
+// Will leave the filled buffer at top of stack
+// Returns the length printed.
+
+int dsPrintFlush(int token);
+// Flushes the top buffer to the next lower one and empties top buffer.
+// If there is no lower buffer then the content is printed to STDOUT (or registered out).
+// Returns the length flushed.
+
+int dsPrintClose(int token);
+// Abandons the top buffer and its content, freeing memory.
+// Returns the length abandoned.
+#define dsPrintAbandon(token) dsPrintClose(token)
+
+int dsPrintFlushAndClose(int token);
+// Flushes the top buffer to the next lower one and frees the top buffer.
+// If there is no lower buffer then the content is printed to STDOUT (or registered out).
+// Returns the length flushed.
+
+char * dsPrintContent(int token);
+// returns the content of the current buffer as a string, but does not flush or free it
+// NOTE: returned pointer is not cloned memory and will be changed by successive dsPrint calls
+
+int dsPrintEmpty(int token);
+// Empties the top buffer in stack (abandoning content), but leave buffer in place
+// Returns the length abandoned.
+#define dsPrintAbandonContent(token) dsPrintEmpty(token)
+
+int dsPrintSize(int token);
+// Returns the curent length of the buffer starting at the level corresponding to token.
+// Unlike other cases, the token does not have to correspond to the top of the stack!
+#define dsPrintIsEmpty(token) (dsPrintSize(token) == 0)
+
+int dsPrintStackDepth();
+// Returns the current dsPrint buffer stack depth
+#define dsPrintIsOpen() (dsPrintStackDepth() > 0)
+
+void dsPrintRegisterOut(FILE *out);
+// Registers an alternative to STDOUT.  After registering, all dsPrint out goes to this file.
+// NOTE: There is no stack. Register/Unregister serially.
+
+void dsPrintUnregisterOut(FILE *out);
+// Unregisters the alternative to STDOUT.  After unregistering all dsPrint out goes to STDOUT.
+// NOTE: There is no stack. Register/Unregister serially.
+
+int dsPrintSizeAll();
+// returns combined current size of all buffers
+#define dsPrintIsAllEmpty(token) (dsPrintSizeAll() == 0)
+
+int dsPrintFlushAndCloseAll();
+// flushes, frees and closes all stacked buffers
+// returns length flushed
+
+char *dsPrintCannibalizeAndClose(int token);
+// Closes the top stack buffer returning content.  Returned string should be freed.
+
+char *dsPrintCannibalizeAndCloseAll();
+// Closes all stack buffers and returns a single string that is the full content.  
+// Returned string should be freed.
+
+//void dsPrintTest();
+// Tests of dsPrint functions
+
+/* Next steps:
+ * 1) DONE WITH MACROS: in cheapCgi.c replace all printfs with dsPrintf
+ * 2) DONE WITH MACROS: in hui.c replace all printfs with dsPrintf
+ * 3) DONE WITH MACROS: in hgTrackUi replace all printfs with dsPrintf
+ * 4) DONE: After 1-3, add opens and closes to hgTrackUi
+ * 5) DONE: Handle boxing cfg with dsPrintf (note existing cfgs that support boxing still do it)
+ * 6) Handle isConfigurable tests with dsPrintf and throw away results
+ *    This one will require making hgTrackUi Cfgs all lib code.
+ */
+
+#endif /* DSPRINT_H */
diff --git a/inc/dtdParse.h b/inc/dtdParse.h
new file mode 100644
index 0000000..2acb1a3
--- /dev/null
+++ b/inc/dtdParse.h
@@ -0,0 +1,57 @@
+/* dtdParse - parse an XML DTD file.  Actually this only
+ * parses a relatively simple subset of DTD's.  It's still
+ * useful for autoXml and xmlToSql. */
+
+#ifndef DTDPARSE_H
+#define DTDPARSE_H
+
+struct dtdElement
+/* An element in an XML file. */
+    {
+    struct dtdElement *next;	/* Next in list. */
+    char *name;			/* Element Name. */
+    char *mixedCaseName;	/* Name converted from EL_NAME or el-name to elName. */
+    struct dtdElChild *children;     /* Child elements. */
+    struct dtdAttribute *attributes; /* Attributes. */
+    int lineIx;			/* Line where element occurs in dtd file. */
+    char *textType;		/* Text between tags if any. */
+    };
+
+struct dtdElChild
+/* A reference to a child element. */
+   {
+   struct dtdElChild *next;	/* Next in list. */
+   char *name;			/* Name of element. */
+   char copyCode;		/* '1', '+', '?', or '*' */
+   boolean isOr;                /* Is this part of a ( n | m ) "or" list? */
+   struct dtdElement *el;	/* Element definition. */
+   };
+
+struct dtdAttribute
+/* An attribute of some sort. */
+    {
+    struct dtdAttribute *next;	/* Next in list. */
+    char *name;			/* Name of attribute. */
+    char *mixedCaseName;	/* Name converted from EL_NAME or el-name to elName. */
+    char *type;			/* Element type - CDATA, INT, FLOAT, etc. */
+    boolean required;		/* True if required. */
+    char *usual;		/* Default value (or NULL if none) */
+    };
+
+void dtdParse(char *fileName, char *prefix, char *textField,
+	struct dtdElement **retList, struct hash **retHash);
+/* Parse out a dtd file into elements that are returned in retList,
+ * and for your convenience also in retHash (which is keyed by the
+ * name of the element.  Note that XML element names can include the '-'
+ * character.  For this and other reasons in addition to the element
+ * name as it appears in the XML tag, the element has a mixedCaseName
+ * that strips '-' and '_' chars, and tries to convert the name to
+ * a mixed-case convention style name.  The prefix if any will be
+ * prepended to mixed-case names.  The textField is what to name
+ * the field that contains the letters between tags.  By default
+ * (if NULL) it is "text." */
+
+void dtdElementDump(struct dtdElement *el, FILE *f);
+/* Dump info on element. */
+
+#endif /* DTDPARSE_H */
diff --git a/inc/dystring.h b/inc/dystring.h
new file mode 100644
index 0000000..892fb7a
--- /dev/null
+++ b/inc/dystring.h
@@ -0,0 +1,98 @@
+/* dystring - dynamically resizing string.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef DYSTRING_H	/* Wrapper to avoid including this twice. */
+#define DYSTRING_H
+
+#include "common.h"
+
+struct dyString
+/* Dynamically resizable string that you can do formatted
+ * output to. */
+    {
+    struct dyString *next;	/* Next in list. */
+    char *string;		/* Current buffer. */
+    int bufSize;		/* Size of buffer. */
+    int stringSize;		/* Size of string. */
+    };
+
+struct dyString *newDyString(int initialBufSize);
+/* Allocate dynamic string with initial buffer size.  (Pass zero for default) */
+
+#define dyStringNew newDyString
+
+void freeDyString(struct dyString **pDs);
+/* Free up dynamic string. */
+
+#define dyStringFree(a) freeDyString(a);
+
+void freeDyStringList(struct dyString **pDs);
+/* Free up a list of dynamic strings */
+
+#define dyStringFreeList(a) freeDyStringList(a);
+
+void dyStringAppend(struct dyString *ds, char *string);
+/* Append zero terminated string to end of dyString. */
+
+void dyStringAppendN(struct dyString *ds, char *string, int stringSize);
+/* Append string of given size to end of string. */
+
+char dyStringAppendC(struct dyString *ds, char c);
+/* Append char to end of string. */
+
+void dyStringAppendMultiC(struct dyString *ds, char c, int n);
+/* Append N copies of char to end of string. */
+
+void dyStringAppendEscapeQuotes(struct dyString *dy, char *string,
+	char quot, char esc);
+/* Append escaped-for-quotation version of string to dy. */
+
+#define dyStringWriteOne(dy, var) dyStringAppendN(dy, (char *)(&var), sizeof(var))
+/* Write one variable (binary!) to dyString - for cases when want to treat string like
+ * a file stream. */
+
+void dyStringVaPrintf(struct dyString *ds, char *format, va_list args);
+/* VarArgs Printf to end of dyString. */
+
+void dyStringPrintf(struct dyString *ds, char *format, ...)
+/*  Printf to end of dyString. */
+#ifdef __GNUC__
+__attribute__((format(printf, 2, 3)))
+#endif
+    ;
+
+struct dyString *dyStringCreate(char *format, ...);
+/*  Create a dyString with a printf style initial content */
+
+#define dyStringClear(ds) (ds->string[0] = ds->stringSize = 0)
+/* Clear string. */
+
+struct dyString * dyStringSub(char *orig, char *in, char *out);
+/* Make up a duplicate of orig with all occurences of in substituted
+ * with out. */
+
+void dyStringBumpBufSize(struct dyString *ds, int size);
+/* Force dyString buffer to be at least given size. */
+
+char *dyStringCannibalize(struct dyString **pDy);
+/* Kill dyString, but return the string it is wrapping
+ * (formerly dy->string).  This should be free'd at your
+ * convenience. */
+
+#define dyStringContents(ds) (ds)->string
+/* return raw string. */
+
+#define dyStringLen(ds) ds->stringSize
+/* return raw string length. */
+
+void dyStringResize(struct dyString *ds, int newSize);
+/* resize a string, if the string expands, blanks are appended */
+
+void dyStringQuoteString(struct dyString *dy, char quotChar, char *text);
+/* Append quotChar-quoted text (with any internal occurrences of quotChar
+ * \-escaped) onto end of dy. */
+
+#endif /* DYSTRING_H */
+
diff --git a/inc/emblParse.h b/inc/emblParse.h
new file mode 100644
index 0000000..ff87f15
--- /dev/null
+++ b/inc/emblParse.h
@@ -0,0 +1,75 @@
+/* Parse EMBL formatted files. EMBL files are basically line
+ * oriented.  Each line begins with a short (usually two letter)
+ * type word.  Adjacent lines with the same type are generally
+ * considered logical extensions of each other.  In many cases
+ * lines can be considered fields in an EMBL database.  Records
+ * are separated by lines starting with '//'  Generally lines
+ * starting with XX are empty and used to make the records more
+ * human readable.   Here is an example record:
+ 
+ C  M00001
+ XX
+ ID  V$MYOD_01
+ XX
+ NA  MyoD
+ XX
+ DT  EWI (created); 19.10.92.
+ DT  ewi (updated); 22.06.95.
+ XX
+ PO     A     C     G     T
+ 01     0     0     0     0
+ 02     0     0     0     0
+ 03     1     2     2     0
+ 04     2     1     2     0
+ 05     3     0     1     1
+ 06     0     5     0     0
+ 07     5     0     0     0
+ 08     0     0     4     1
+ 09     0     1     4     0
+ 10     0     0     0     5
+ 11     0     0     5     0
+ 12     0     1     2     2
+ 13     0     2     0     3
+ 14     1     0     3     1
+ 15     0     0     0     0
+ 16     0     0     0     0
+ 17     0     0     0     0
+ XX
+ BF  T00526; MyoD                         ; mouse
+ XX
+ BA  5 functional elements in 3 genes
+ XX
+ XX
+ //
+ */
+
+#ifndef EMBLPARSE_H
+#define EMBLPARSE_H
+
+#ifndef HASH_H
+#include "hash.h"
+#endif
+
+#ifndef DYSTRING_H
+#include "dystring.h"
+#endif
+
+#ifndef LINEFILE_H
+#include "linefile.h"
+#endif
+
+boolean emblLineGroup(struct lineFile *lf, char type[16], struct dyString *val);
+/* Read next line of embl file.  Read line after that too if it
+ * starts with the same type field. Return FALSE at EOF. */
+
+struct hash *emblRecord(struct lineFile *lf);
+/* Read next record and return it in hash.   (Free this
+ * hash with freeHashAndVals.)   Hash is keyed by type
+ * and has string values. */
+
+struct lineFile *emblOpen(char *fileName, char type[256]);
+/* Open up embl file, verify format and optionally  return 
+ * type (VV line).  Close this with lineFileClose(). */
+
+#endif /* EMBLPARSE_H */
+
diff --git a/inc/ens.h b/inc/ens.h
new file mode 100644
index 0000000..b48dfa4
--- /dev/null
+++ b/inc/ens.h
@@ -0,0 +1,168 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* ens.h - Interface to ensEMBL database. */
+#ifndef ENS_H
+#define ENS_H
+
+#ifndef DNAUTIL_H
+#include "dnautil.h"
+#endif 
+
+#ifndef DLIST_H
+#include "dlist.h"
+#endif 
+
+#ifndef UNFIN_H
+#include "unfin.h"
+#endif
+
+struct ensAnalysis
+/* A category of a feature. */
+    {
+    struct ensAnalysis *next;	/* Next in list */
+    int id;			/* Unique id for this feature type. */
+    char *db;			/* Database used. */
+    char *dbVersion;		/* Version of database. */
+    char *program;		/* Program used. */
+    char *programVersion;	/* Version of program. */
+    char *gffSource;		/* Source field from GFF. */
+    char *gffFeature;		/* Feature field from GFF. */
+    char *shortName;		/* 15 letter summary. */
+    };
+
+struct ensFeature
+/* An ensemble feature. */
+    {
+    struct ensFeature *next;	   /* Next in list. */
+    struct contigTree *tContig;    /* Name of target (genomic) sequence */
+    int tStart, tEnd;              /* Position in genomic sequence. */
+    int score;                     /* Score (I don't know units) */
+    int orientation;               /* +1 or -1.  Strand relative to contig. */
+    int type;                      /* Index into analysis table describing type of feature. */
+    char *typeName;                /* Subtype of type really. May be NULL. Not alloced here. */ 
+    int qStart, qEnd;              /* Query (cDNA, protein, etc.) sequence position. */
+    char *qName;                   /* Query sequence name. */
+    };
+
+struct ensExon
+/* An ensemble exon.  Since multiple transcripts can
+ * use the same exon, this is stored as a reference on
+ * a dlList in the transcript and as an instance in the
+ * slList in the gene. */
+    {
+    struct ensExon *next;		/* Next in list (in ensGene) */
+    char *id;				/* Ensemble ID (not allocated here). */
+    struct contigTree *contig;	        /* Contig within clone this is in. (Not allocated here).*/
+    char phase;				/* AKA Frame - codon position of 1st base. */
+    char endPhase;                      /* Codon position of last base. */
+    int orientation;                    /* +1 or -1. Strand relative to contig. */
+    int seqStart;			/* Start position. */
+    int seqEnd;				/* End position. */
+    };
+
+struct ensTranscript
+/* A transcript (isoform) of a gene. */
+    {
+    struct ensTranscript *next;		/* Next in list. */
+    char *id;				/* Ensemble ID. */
+    struct dlList *exonList;		/* Ordered list of exon references. */
+    struct ensExon *startExon;          /* Reference to first coding exon. */
+    struct ensExon *endExon;            /* Reference to last coding exon. */
+    int startSeq, endSeq;               /* Start, end of coding region. */
+    };
+
+struct ensGene
+/* A gene.  A collection of exons and how they
+ * are put together. */
+    {
+    struct ensGene *next;		  /* Next in list. */
+    char *id;				  /* Ensemble ID with many zeroes. */
+    struct ensTranscript *transcriptList; /* List of ways to transcribe and splice. */
+    struct hash *exonIdHash;		  /* Fast lookup of exons from exon ids. */
+    struct ensExon *exonList;		  /* Total exons in all transcripts. */
+    };
+
+void ensGetAnalysisTable(struct ensAnalysis ***retTable, int *retCount);
+/* Returns analysis table (array of different things a feature can be). 
+ * No need to free this, it's managed by system. */
+
+struct dnaSeq *ensDnaInBacRange(char *clone, int start, int end, enum dnaCase dnaCase);
+/* Get DNA for range of clone in browser coordinates, including NNNs between contigs. */
+
+struct dnaSeq *ensDnaInBac(char *clone, enum dnaCase dnaCase);
+/* Get DNA for clone in browser coordinates, including NNNs between contigs. */
+
+
+struct ensFeature *ensGetFeature(char *featureId);
+/* Get a single feature of the given ID.  Returns NULL if no such feature.  */
+
+struct ensFeature *ensFeaturesInBac(char *clone);
+/* Get list of features associated with BAC clone. */
+
+struct ensFeature *ensFeaturesInBacRange(char *clone, int start, int end);
+/* Get list of features associated a section of BAC clone. */
+
+void ensFreeFeature(struct ensFeature **pFeature);
+/* Free up a single feature. */
+
+void ensFreeFeatureList(struct ensFeature **pFeatureList);
+/* Free up a list of features. */
+
+
+
+struct slName *ensGeneNamesInBac(char *bacName);
+/* Get list of all gene names in bac. */
+
+struct ensGene *ensGetGene(char *geneName);
+/* Get named gene. This can also be viewed as a list of one genes. */
+
+struct ensGene *ensGenesInBac(char *bacName);
+/* Get list of all genes in bac. */
+
+struct ensGene *ensGenesInBacRange(char *bacName, int start, int end);
+/* Get list of genes in a section of a BAC clone.  The start/end are
+ * in browser coordinates. */
+
+void ensFreeGene(struct ensGene **pGene);
+/* Free up a single gene. */
+
+void ensFreeGeneList(struct ensGene **pGeneList);
+/* Free up a list of genes. */
+
+
+
+void ensParseContig(char *combined, char retBac[32], int *retContig);
+/* Parse combined bac.contig into two separate values. */
+
+int ensBrowserCoordinates(struct contigTree *contig, int x);
+/* Return x in browser coordinates. */
+
+int ensSubmitCoordinates(struct contigTree *contig, int x);
+/* Return x in GenBank/EMBL submission coordinates. */
+
+int ensBacBrowserLength(char *clone);
+/* Return size of clone in browser coordinate space. */
+
+int ensBacSubmitLength(char *clone);
+/* Return size of clone in GenBank/EMBL submission  coordinate space. */
+
+struct contigTree *ensBacContigs(char *bacId);
+/* Return contigTree rooted at Bac.  Do not free this or modify it, 
+ * the system takes care of it. */
+
+struct contigTree *ensGetContig(char *contigId);
+/* Return contig associated with contigId. Do not free this, system
+ * takes care of it. */
+
+void ensTranscriptBounds(struct ensTranscript *trans, int *retStart, int *retEnd);
+/* Find beginning and end of transcript in browser coordinates. */
+
+void ensGeneBounds(struct ensGene *gene, int *retStart, int *retEnd);
+/* Find beginning and end of gene in browser coordinates. */
+
+#endif /* ENS_H */
+
+
diff --git a/inc/errCatch.h b/inc/errCatch.h
new file mode 100644
index 0000000..a9bfc1e
--- /dev/null
+++ b/inc/errCatch.h
@@ -0,0 +1,56 @@
+/* errCatch - help catch errors so that errAborts aren't
+ * fatal, and warn's don't necessarily get printed immediately. 
+ * Note that error conditions caught this way will tend to
+ * leak resources unless there are additional wrappers. 
+ *
+ * Typical usage is
+ * errCatch = errCatchNew();
+ * if (errCatchStart(errCatch))
+ *     doFlakyStuff();
+ * errCatchEnd(errCatch);
+ * if (errCatch->gotError)
+ *     warn("Flaky stuff failed: %s", errCatch->message->string);
+ * errCatchFree(&errCatch); 
+ * cleanupFlakyStuff();
+ */
+#ifndef ERRCATCH_H
+#define ERRCATCH_H
+
+#ifndef DYSTRING_H
+    #include "dystring.h"
+#endif
+
+struct errCatch
+/* Something to help catch errors.   */
+    {
+    struct errCatch *next;	 /* Next in stack. */
+    jmp_buf jmpBuf;		 /* Where to jump back to for recovery. */
+    struct dyString *message; /* Error message if any */
+    boolean gotError;		 /* Some sort of error was caught. */
+    };
+
+struct errCatch *errCatchNew();
+/* Return new error catching structure. */
+
+void errCatchFree(struct errCatch **pErrCatch);
+/* Free up resources associated with errCatch */
+
+#define errCatchStart(e) (errCatchPushHandlers(e) && setjmp(e->jmpBuf) == 0)
+/* Little wrapper around setjmp.  This returns TRUE
+ * on the main execution thread, FALSE after abort. */
+
+
+boolean errCatchPushHandlers(struct errCatch *errCatch);
+/* Push error handlers.  Not usually called directly. 
+ * but rather through errCatchStart() macro.  Always
+ * returns TRUE. */
+
+void errCatchEnd(struct errCatch *errCatch);
+/* Restore error handlers and pop self off of catching stack. */
+
+boolean errCatchFinish(struct errCatch **pErrCatch);
+/* Finish up error catching.  Report error if there is a
+ * problem and return FALSE.  If no problem return TRUE.
+ * This handles errCatchEnd and errCatchFree. */
+#endif /* ERRCATCH_H */
+
diff --git a/inc/errabort.h b/inc/errabort.h
new file mode 100644
index 0000000..4fd645b
--- /dev/null
+++ b/inc/errabort.h
@@ -0,0 +1,93 @@
+/* ErrAbort.h - our error handler. 
+ *
+ * This maintains two stacks - a warning message printer
+ * stack, and a "abort handler" stack.
+ *
+ * By default the warnings will go to stderr, and
+ * aborts will exit the program.  You can push a
+ * function on to the appropriate stack to change
+ * this behavior.  The top function on the stack
+ * gets called.
+ *
+ * Most functions in this library will call errAbort()
+ * if they run out of memory.  
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef ERRABORT_H
+#define ERRABORT_H
+
+boolean isErrAbortInProgress();  
+/* Flag to indicate that an error abort is in progress.
+ * Needed so that a warn handler can tell if it's really
+ * being called because of a warning or an error. */
+
+void errAbort(char *format, ...)
+/* Abort function, with optional (printf formatted) error message. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+void vaErrAbort(char *format, va_list args);
+/* Abort function, with optional (vprintf formatted) error message. */
+
+void errnoAbort(char *format, ...)
+/* Prints error message from UNIX errno first, then does errAbort. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+typedef void (*AbortHandler)();
+/* Function that can abort. */
+
+void pushAbortHandler(AbortHandler handler);
+/* Set abort handler */
+
+void popAbortHandler();
+/* Revert to old abort handler. */
+
+void noWarnAbort();
+/* Abort without message. */
+
+void pushDebugAbort();
+/* Push abort handler that will invoke debugger. */
+
+void vaWarn(char *format, va_list args);
+/* Call top of warning stack to issue warning. */
+
+void warn(char *format, ...)
+/* Issue a warning message. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+void errnoWarn(char *format, ...)
+/* Prints error message from UNIX errno first, then does rest of warning. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+typedef void (*WarnHandler)(char *format, va_list args);
+/* Function that can warn. */
+
+void pushWarnHandler(WarnHandler handler);
+/* Set warning handler */
+
+void popWarnHandler();
+/* Revert to old warn handler. */
+
+void pushWarnAbort();
+/* Push handler that will abort on warnings. */
+
+void pushSilentWarnHandler();
+/* Set warning handler to be quiet.  Do a popWarnHandler to restore. */
+
+void errAbortDebugnPushPopErr();
+/*  generate stack dump if there is a error in the push/pop functions */
+
+#endif /* ERRABORT_H */
diff --git a/inc/fa.h b/inc/fa.h
new file mode 100644
index 0000000..02971b6
--- /dev/null
+++ b/inc/fa.h
@@ -0,0 +1,129 @@
+/* Routines for reading and writing fasta format sequence files.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef FA_H
+#define FA_H
+
+#ifndef DNASEQ_H
+#include "dnaseq.h"
+#endif
+
+#ifndef LINEFILE_H
+#include "linefile.h"
+#endif
+
+struct dnaSeq *faReadDna(char *fileName);
+/* Open fa file and read a single dna sequence from it. */
+
+aaSeq *faReadAa(char *fileName);
+/* Open fa file and read a single dna sequence from it. */
+
+bioSeq *faReadSeq(char *fileName, boolean isDna);
+/* Read a dna or protein sequence. */
+
+struct dnaSeq *faReadAllDna(char *fileName);
+/* Return list of all DNA sequences in FA file. */
+
+struct dnaSeq *faReadAllPep(char *fileName);
+/* Return list of all Peptide sequences in FA file. */
+
+struct dnaSeq *faReadAllSeq(char *fileName, boolean isDna);
+/* Return list of all sequences in FA file. */
+
+struct dnaSeq *faReadAllMixed(char *fileName);
+/* Read in mixed case fasta file, preserving case. */
+
+struct hash *faReadAllIntoHash(char *fileName, enum dnaCase dnaCase);
+/* Return hash of all sequences in FA file.  */
+
+struct dnaSeq *faReadAllMixedInLf(struct lineFile *lf);
+/* Read in mixed case sequence from open fasta file. */
+
+struct dnaSeq *faReadOneDnaSeq(FILE *f, char *name, boolean mustStartWithSign);
+/* Read one sequence from FA file. Assumes positioned at or before
+ * the '>' at start of sequence. */  
+
+boolean faReadNext(FILE *f, char *defaultName, boolean mustStartWithComment, 
+    char **retCommentLine, struct dnaSeq **retSeq);
+/* Read next sequence from .fa file. Return sequence in retSeq.  If retCommentLine is non-null
+ * return the '>' line in retCommentLine.   The whole thing returns FALSE at end of file. 
+ * Assumes positioned at or before the '>' at start of sequence.  File must have been
+ * opened in binary mode! Note: sequence is mapped to lower case */
+
+boolean faReadMixedNext(FILE *f, boolean preserveCase, char *defaultName, 
+    boolean mustStartWithComment, char **retCommentLine, struct dnaSeq **retSeq);
+/* Read next sequence from .fa file. Return sequence in retSeq.  If retCommentLine is non-null
+ * return the '>' line in retCommentLine.   The whole thing returns FALSE at end of file. Provides flag for preserving case in sequence */
+
+struct dnaSeq *faFromMemText(char *text);
+/* Return a sequence from a .fa file that's been read into
+ * a string in memory. This cannabalizes text, which should
+ * be allocated with needMem.  This buffer becomes part of
+ * the returned dnaSeq, which may be freed normally with
+ * freeDnaSeq. */
+
+bioSeq *faSeqFromMemText(char *text, boolean isDna);
+/* Convert fa in memory to bioSeq. This cannabalizes text
+ * as does faFromMemText above. */
+
+bioSeq *faNextSeqFromMemText(char **pText, boolean isDna);
+/* Convert fa in memory to bioSeq.  Update *pText to point to next
+ * record.  Returns NULL when no more sequences left. */
+
+bioSeq *faNextSeqFromMemTextRaw(char **pText);
+/* Same as faNextSeqFromMemText, but will leave in 
+ * letters even if they aren't in DNA or protein alphabed. */
+
+bioSeq *faSeqListFromMemText(char *text, boolean isDna);
+/* Convert fa's in memory into list of dnaSeqs. */
+
+bioSeq *faSeqListFromMemTextRaw(char *text);
+/* Convert fa's in memory into list of dnaSeqs without
+ * converting chars to N's. */
+
+boolean faFastReadNext(FILE *f, DNA **retDna, int *retSize, char **retName);
+/* Read in next FA entry as fast as we can. Return FALSE at EOF. 
+ * The returned DNA and name will be overwritten by the next call
+ * to this function. */
+
+boolean faSpeedReadNext(struct lineFile *lf, DNA **retDna, int *retSize, char **retName);
+/* Read in next FA entry as fast as we can. Faster than that old,
+ * pokey faFastReadNext. Return FALSE at EOF. 
+ * The returned DNA and name will be overwritten by the next call
+ * to this function. */
+
+boolean faPepSpeedReadNext(struct lineFile *lf, DNA **retDna, int *retSize, char **retName);
+/* Read in next peptide FA entry as fast as we can.  */
+
+boolean faSomeSpeedReadNext(struct lineFile *lf, DNA **retDna, int *retSize, char **retName, boolean isDna);
+/* Read in DNA or Peptide FA record. */
+
+boolean faMixedSpeedReadNext(struct lineFile *lf, DNA **retDna, int *retSize, char **retName);
+/* Read in DNA or Peptide FA record in mixed case.   Allow any upper or lower case
+ * letter, or the dash character in. */
+
+void faToProtein(char *poly, int size);
+/* Convert possibly mixed-case protein to upper case.  Also
+ * convert any strange characters to 'X'.  Does not change size.
+ * of sequence. */
+
+void faToDna(char *poly, int size);
+/* Convert possibly mixed-case DNA to lower case.  Also turn
+ * any strange characters to 'n'.  Does not change size.
+ * of sequence. */
+
+void faFreeFastBuf();
+/* Free up buffers used in fa fast and speedreading. */
+
+void faWrite(char *fileName, char *startLine, DNA *dna, int dnaSize);
+/* Write out FA file or die trying. */
+
+void faWriteNext(FILE *f, char *startLine, DNA *dna, int dnaSize);
+/* Write next sequence to fa file. */
+
+void faWriteAll(char *fileName, bioSeq *seqList);
+/* Write out all sequences in list to file. */
+
+#endif /* FA_H */
diff --git a/inc/filePath.h b/inc/filePath.h
new file mode 100644
index 0000000..ca4ddb5
--- /dev/null
+++ b/inc/filePath.h
@@ -0,0 +1,31 @@
+/* filePath - stuff to handle file name parsing. */
+#ifndef FILEPATH_H
+#define FILEPATH_H
+
+#include "common.h"
+
+void splitPath(char *path, char dir[PATH_LEN], char name[FILENAME_LEN],
+	       char extension[FILEEXT_LEN]);
+/* Split a full path into components.  The dir component will include the
+ * trailing / if any.  The extension component will include the starting
+ * . if any.   Pass in NULL for dir, name, or extension if you don't care about
+ * that part. */
+
+char *expandRelativePath(char *baseDir, char *relPath);
+/* Expand relative path to more absolute one. */
+
+char *pathRelativeToFile(char *baseFile, char *relPath);
+/* Given a base file name and a path relative to that, return
+ * relative path interpreted as if it were seen from the
+ * same directory holding the baseFile.  
+ *   An example of using this would be in processing include
+ * files.  In this case the baseFile would be the current
+ * source file, and the relPath would be from the include
+ * statement.  The returned result could then be used to
+ * open the include file. */
+
+void undosPath(char *path);
+/* Convert '\' to '/' in path. (DOS/Windows is typically ok with
+ * this actually.) */
+
+#endif /* FILEPATH_H */
diff --git a/inc/flydna.h b/inc/flydna.h
new file mode 100644
index 0000000..bdbd2a0
--- /dev/null
+++ b/inc/flydna.h
@@ -0,0 +1,32 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* flydna.h - routines for accessing fly genome and cDNA sequences. */
+
+#ifndef FLYDNA_H
+#define FLYDNA_H
+
+void flyLoadNt4Genome(struct nt4Seq ***retNt4Seq, int *retNt4Count);
+/* Load up entire packed fly genome into memory. */
+
+void flyFreeNt4Genome(struct nt4Seq ***pNt4Seq);
+/* Free up packed fly genome. */
+
+void flyChromNames(char ***retNames, int *retNameCount);
+/* Get list of fly chromosome names. */
+
+boolean flyCdnaSeq(char *name, struct dnaSeq **retDna, struct wormCdnaInfo *retInfo);
+/* Get a single fly cDNA sequence. Optionally (if retInfo is non-null) get additional
+ * info about the sequence. */
+
+char *flyFeaturesDir();
+/* Return the features directory. (Includes trailing slash.) */
+
+FILE *flyOpenGoodAli();
+/* Opens good alignment file and reads signature. 
+ * (You can then cdaLoadOne() it.) */
+
+#endif /* FLYDNA_H */
+
diff --git a/inc/fof.h b/inc/fof.h
new file mode 100644
index 0000000..af2d27a
--- /dev/null
+++ b/inc/fof.h
@@ -0,0 +1,82 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* fof.h - Manages a fof-type index file.  This index refers
+ * to records in multiple external files. */
+
+struct fofPos
+/* This holds the result of a FOF search. */
+    {
+    FILE *f;              /* File. */
+    bits32 offset;        /* Offset within file. */
+    bits32 size;          /* Size within file. */
+    int indexIx;          /* Position within index. */
+    char *fileName;       /* File name. */
+    };
+
+
+struct fof *fofOpen(char *fofName, char *fofDir);
+/* Open up the named fof. fofDir may be NULL.  It should include 
+ * trailing '/' if non-null. */
+
+void fofClose(struct fof **pFof);
+/* Close down the named fof. */
+
+int fofElementCount(struct fof *fof);
+/* How many names are in fof file? */
+
+void fofMake(char *inFiles[], int inCount, char *outName, 
+    boolean (*readHeader)(FILE *inFile, void *data),
+    boolean (*nextRecord)(FILE *inFile, void *data, char **rName, int *rNameLen), 
+    void *data, boolean dupeOk);
+/* Make an index file
+ * Inputs:
+ *     inFiles - List of files that you're indexing with header read and verified.
+ *     inCount - Size of file list.
+ *     outName - name of index file to create
+ *     readHeader - function that sets up file to read first record.  May be NULL.
+ *     nextRecord - function that reads next record in file you're indexing
+ *                  and returns the name of that record.  Returns FALSE at
+ *                  end of file.  Can set *rNameLen to zero you want indexer
+ *                  to ignore the record. 
+ *     data - void pointer passed through to nextRecord.
+ *     dupeOk - set to TRUE if you want dupes to not cause squawking
+ */
+
+boolean fofFindFirst(struct fof *fof, char *prefix, 
+    int prefixSize, struct fofPos *retPos);
+/* Find first element with key starting with prefix. */
+
+boolean fofFind(struct fof *fof, char *name, struct fofPos *retPos);
+/* Find element corresponding with name.  Returns FALSE if no such name
+ * in the index file. */
+
+void *fofFetch(struct fof *fof, char *name, int *retSize);
+/* Lookup element in index, allocate memory for it, and read
+ * it.  Returns buffer with element in it, which should be
+ * freeMem'd when done. Aborts if element isn't there. */
+
+char *fofFetchString(struct fof *fof, char *name, int *retSize);
+/* Lookup element in index, allocate memory for it, read it.
+ * Returns zero terminated string with element in it, which 
+ * should be freeMem'd when done. Aborts if element isn't there. */
+
+struct fofBatch
+/* A structure for doing batch FOF searches.  Client fills
+ * in key and data members.  fofBatchSearch then fills in
+ * file, offset, and size members.  The list on return is
+ * sorted by file position for fast i/o. */
+    {
+    struct fofBatch *next;  /* Next in list. */
+    char *key;              /* Lookup key - filled in by client. Not allocate here. */
+    void *data;             /* Data associated with key - filled in by client. */
+    FILE *f;                /* File - filled in by server. */
+    bits32 offset;          /* Offset in file - filled in by server. */
+    bits32 size;            /* Size in file - filled in by server. */
+    };
+ 
+struct fofBatch *fofBatchFind(struct fof *fof, struct fofBatch *list);
+/* Look up all of members on list. */
+
diff --git a/inc/foo b/inc/foo
new file mode 100644
index 0000000..19b5031
--- /dev/null
+++ b/inc/foo
@@ -0,0 +1,361 @@
+80ad2e61 (kent          2009-02-02 06:05:52 +0000   1) /* bbiFile - Big Binary Indexed file.  Stuff that's common between bigWig and bigBed. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000   2) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000   3) #ifndef BBIFILE_H
+80ad2e61 (kent          2009-02-02 06:05:52 +0000   4) #define BBIFILE_H
+80ad2e61 (kent          2009-02-02 06:05:52 +0000   5) 
+e875bb30 (angie         2009-07-27 19:55:17 +0000   6) #include "cirTree.h"
+e875bb30 (angie         2009-07-27 19:55:17 +0000   7) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000   8) /* bigWig/bigBed file structure:
+18e51ee9 (kent          2009-02-03 00:39:44 +0000   9)  *     fixedWidthHeader
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  10)  *         magic# 		4 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  11)  *         version              2 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  12)  *	   zoomLevels		2 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  13)  *         chromosomeTreeOffset	8 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  14)  *         fullDataOffset	8 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  15)  *	   fullIndexOffset	8 bytes
+0eb44740 (kent          2009-11-05 19:35:01 +0000  16)  *         fieldCount           2 bytes (for bigWig 0)
+0eb44740 (kent          2009-11-05 19:35:01 +0000  17)  *         definedFieldCount    2 bytes (for bigWig 0)
+0eb44740 (kent          2009-11-05 19:35:01 +0000  18)  *         autoSqlOffset        8 bytes (for bigWig 0) (0 if no autoSql information)
+0eb44740 (kent          2009-11-05 19:35:01 +0000  19)  *         totalSummaryOffset   8 bytes (0 in earlier versions of file lacking totalSummary)
+fe6b431f (kent          2009-11-12 23:15:52 +0000  20)  *         uncompressBufSize    4 bytes (Size of uncompression buffer.  0 if uncompressed.)
+fe6b431f (kent          2009-11-12 23:15:52 +0000  21)  *         reserved             8 bytes (0 for now)
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  22)  *     zoomHeaders		there are zoomLevels number of these
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  23)  *         reductionLevel	4 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  24)  *	   reserved		4 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  25)  *	   dataOffset		8 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  26)  *         indexOffset          8 bytes
+0442310c (kent          2009-11-05 19:46:58 +0000  27)  *     autoSql string (zero terminated - only present if autoSqlOffset non-zero)
+0442310c (kent          2009-11-05 19:46:58 +0000  28)  *     totalSummary - summary of all data in file - only present if totalSummaryOffset non-zero
+0eb44740 (kent          2009-11-05 19:35:01 +0000  29)  *         basesCovered        8 bytes
+0eb44740 (kent          2009-11-05 19:35:01 +0000  30)  *         minVal              8 bytes float (for bigBed minimum depth of coverage)
+0eb44740 (kent          2009-11-05 19:35:01 +0000  31)  *         maxVal              8 bytes float (for bigBed maximum depth of coverage)
+0eb44740 (kent          2009-11-05 19:35:01 +0000  32)  *         sumData             8 bytes float (for bigBed sum of coverage)
+0eb44740 (kent          2009-11-05 19:35:01 +0000  33)  *         sumSquared          8 bytes float (for bigBed sum of coverage squared)
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  34)  *     chromosome b+ tree       bPlusTree index
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  35)  *     full data
+0eb44740 (kent          2009-11-05 19:35:01 +0000  36)  *         sectionCount		8 bytes (item count for bigBeds)
+820a9b65 (kent          2009-03-17 20:46:33 +0000  37)  *         section data		section count sections, of three types (bed data for bigBeds)
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  38)  *     full index               cirTree index
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  39)  *     zoom info             one of these for each zoom level
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  40)  *         zoom data
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  41)  *             zoomCount	4 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  42)  *             zoom data	there are zoomCount of these items
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  43)  *                 chromId	4 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  44)  *	           chromStart	4 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  45)  *                 chromEnd     4 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  46)  *                 validCount	4 bytes
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  47)  *                 minVal       4 bytes float 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  48)  *                 maxVal       4 bytes float
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  49)  *                 sumData      4 bytes float
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  50)  *                 sumSquares   4 bytes float
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  51)  *         zoom index        	cirTree index
+dc806d5e (kent          2010-04-06 23:42:59 +0000  52)  *     magic# 		4 bytes - same as magic number at start of header
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  53)  */
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  54) 
+9dcefc8f (kent          2009-07-28 03:06:18 +0000  55) #ifndef CIRTREE_H
+9dcefc8f (kent          2009-07-28 03:06:18 +0000  56) #include "cirTree.h"
+9dcefc8f (kent          2009-07-28 03:06:18 +0000  57) #endif
+9dcefc8f (kent          2009-07-28 03:06:18 +0000  58) 
+be2e056e (kent          2010-04-06 23:06:42 +0000  59) #define bbiCurrentVersion 4
+0eb44740 (kent          2009-11-05 19:35:01 +0000  60) /* Version history (of file format, not utilities - corresponds to version field in header)
+0eb44740 (kent          2009-11-05 19:35:01 +0000  61)  *    1 - Initial release
+0eb44740 (kent          2009-11-05 19:35:01 +0000  62)  *    1 - Unfortunately when attempting a transparent change to encoders, made the sectionCount 
+0eb44740 (kent          2009-11-05 19:35:01 +0000  63)  *        field inconsistent, sometimes not present, sometimes 32 bits.  Since offset positions
+0eb44740 (kent          2009-11-05 19:35:01 +0000  64)  *        in index were still accurate this did not break most applications, but it did show
+0eb44740 (kent          2009-11-05 19:35:01 +0000  65)  *        up in the summary section of the Table Browser.
+0eb44740 (kent          2009-11-05 19:35:01 +0000  66)  *    2 - Made sectionCount consistently 64 bits. Also fixed missing zoomCount in first level of
+0eb44740 (kent          2009-11-05 19:35:01 +0000  67)  *        zoom in files made by bedToBigBed and bedGraphToBigWig.  (The older wigToBigWig was fine.)
+fe6b431f (kent          2009-11-12 23:15:52 +0000  68)  *        Added totalSummary section.
+fe6b431f (kent          2009-11-12 23:15:52 +0000  69)  *    3 - Adding zlib compression.  Only active if uncompressBufSize is non-zero in header.
+be2e056e (kent          2010-04-06 23:06:42 +0000  70)  *    4 - Fixed problem in encoder for the max field in zoom levels higher than the first one.
+dc806d5e (kent          2010-04-06 23:42:59 +0000  71)  *        Added an extra sig at end of file.
+0eb44740 (kent          2009-11-05 19:35:01 +0000  72)  */
+0eb44740 (kent          2009-11-05 19:35:01 +0000  73) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  74) struct bbiZoomLevel
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  75) /* A zoom level in bigWig file. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  76)     {
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  77)     struct bbiZoomLevel *next;		/* Next in list. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  78)     bits32 reductionLevel;		/* How many bases per item */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  79)     bits32 reserved;			/* Zero for now. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  80)     bits64 dataOffset;			/* Offset of data for this level in file. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  81)     bits64 indexOffset;			/* Offset of index for this level in file. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  82)     };
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  83) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  84) struct bbiZoomLevel *bbiBestZoom(struct bbiZoomLevel *levelList, int desiredReduction);
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  85) /* Return zoom level that is the closest one that is less than or equal to 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  86)  * desiredReduction. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  87) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  88) struct bbiFile 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  89) /* An open bbiFile */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  90)     {
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  91)     struct bbiFile *next;	/* Next in list. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  92)     char *fileName;		/* Name of file - for better error reporting. */
+7ccdade4 (kent          2009-02-09 02:43:23 +0000  93)     struct udcFile *udc;	/* Open UDC file handle. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  94)     bits32 typeSig;		/* bigBedSig or bigWigSig for now. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  95)     boolean isSwapped;		/* If TRUE need to byte swap everything. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  96)     struct bptFile *chromBpt;	/* Index of chromosomes. */
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  97)     bits16 version;		/* Version number - initially 1. */
+18e51ee9 (kent          2009-02-03 00:39:44 +0000  98)     bits16 zoomLevels;		/* Number of zoom levels. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000  99)     bits64 chromTreeOffset;	/* Offset to chromosome index. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 100)     bits64 unzoomedDataOffset;	/* Start of unzoomed data. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 101)     bits64 unzoomedIndexOffset;	/* Start of unzoomed index. */
+223c4619 (kent          2009-02-10 22:11:00 +0000 102)     bits16 fieldCount;		/* Number of columns in bed version. */
+223c4619 (kent          2009-02-10 22:11:00 +0000 103)     bits16 definedFieldCount;   /* Number of columns using bed standard definitions. */
+ad1a80b0 (kent          2009-03-15 00:17:52 +0000 104)     bits64 asOffset;		/* Offset to embedded null-terminated AutoSQL file. */
+0eb44740 (kent          2009-11-05 19:35:01 +0000 105)     bits64 totalSummaryOffset;	/* Offset to total summary information if any.  (On older files have to calculate) */
+fe6b431f (kent          2009-11-12 23:15:52 +0000 106)     bits32 uncompressBufSize;	/* Size of uncompression buffer, 0 if uncompressed */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 107)     struct cirTreeFile *unzoomedCir;	/* Unzoomed data index in memory - may be NULL. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 108)     struct bbiZoomLevel *levelList;	/* List of zoom levels. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 109)     };
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 110) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 111) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 112) struct bbiFile *bbiFileOpen(char *fileName, bits32 sig, char *typeName);
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 113) /* Open up big wig or big bed file. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 114) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 115) void bbiFileClose(struct bbiFile **pBwf);
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 116) /* Close down a big wig/big bed file. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 117) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 118) struct fileOffsetSize *bbiOverlappingBlocks(struct bbiFile *bbi, struct cirTreeFile *ctf,
+adcb838d (kent          2009-02-03 08:18:53 +0000 119) 	char *chrom, bits32 start, bits32 end, bits32 *retChromId);
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 120) /* Fetch list of file blocks that contain items overlapping chromosome range. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 121)  
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 122) struct bbiChromIdSize
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 123) /* We store an id/size pair in chromBpt bPlusTree */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 124)     {
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 125)     bits32 chromId;	/* Chromosome ID */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 126)     bits32 chromSize;	/* Chromosome Size */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 127)     };
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 128) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 129) struct bbiChromInfo
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 130) /* Pair of a name and a 32-bit integer. Used to assign IDs to chromosomes. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 131)     {
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 132)     struct bbiChromInfo *next;
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 133)     char *name;		/* Chromosome name */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 134)     bits32 id;		/* Chromosome ID - a small number usually */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 135)     bits32 size;	/* Chromosome size in bases */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 136)     };
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 137) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 138) struct bbiChromInfo *bbiChromList(struct bbiFile *bbi);
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 139) /* Return all chromosomes in file.  Dispose of this with bbiChromInfoFreeList. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 140) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 141) void bbiChromInfoFreeList(struct bbiChromInfo **pList);
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 142) /* Free a list of bbiChromInfo's */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 143) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 144) bits32 bbiChromSize(struct bbiFile *bbi, char *chrom);
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 145) /* Returns size of given chromosome. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 146) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 147) void bbiChromInfoKey(const void *va, char *keyBuf);
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 148) /* Get key field out of bbiChromInfo. */
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 149) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 150) void *bbiChromInfoVal(const void *va);
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 151) /* Get val field out of bbiChromInfo. */
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 152) 
+bf087c11 (kent          2009-07-27 18:02:11 +0000 153) struct bbiChromUsage
+bf087c11 (kent          2009-07-27 18:02:11 +0000 154) /* Information on how many items per chromosome etc.  Used by multipass bbiFile writers. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 155)     {
+bf087c11 (kent          2009-07-27 18:02:11 +0000 156)     struct bbiChromUsage *next;
+bf087c11 (kent          2009-07-27 18:02:11 +0000 157)     char *name;	/* chromosome name. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 158)     bits32 itemCount;	/* Number of items for this chromosome. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 159)     bits32 id;	/* Unique ID for chromosome. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 160)     bits32 size;	/* Size of chromosome. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 161)     };
+bf087c11 (kent          2009-07-27 18:02:11 +0000 162) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 163) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 164) enum bbiSummaryType
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 165) /* Way to summarize data. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 166)     {
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 167)     bbiSumMean = 0,	/* Average value */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 168)     bbiSumMax = 1,	/* Maximum value */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 169)     bbiSumMin = 2,	/* Minimum value */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 170)     bbiSumCoverage = 3,  /* Bases in region containing actual data. */
+7497c149 (kent          2009-11-20 17:12:17 +0000 171)     bbiSumStandardDeviation = 4, /* Standard deviation in window. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 172)     };
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 173) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 174) enum bbiSummaryType bbiSummaryTypeFromString(char *string);
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 175) /* Return summary type given a descriptive string. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 176) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 177) char *bbiSummaryTypeToString(enum bbiSummaryType type);
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 178) /* Convert summary type from enum to string representation. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 179) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 180) struct bbiSummary
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 181) /* A summary type item. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 182)     {
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 183)     struct bbiSummary *next;
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 184)     bits32 chromId;		/* ID of associated chromosome. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 185)     bits32 start,end;		/* Range of chromosome covered. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 186)     bits32 validCount;		/* Count of (bases) with actual data. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 187)     float minVal;		/* Minimum value of items */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 188)     float maxVal;		/* Maximum value of items */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 189)     float sumData;		/* sum of values for each base. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 190)     float sumSquares;		/* sum of squares for each base. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 191)     bits64 fileOffset;		/* Offset of summary in file. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 192)     };
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 193) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 194) #define bbiSummaryFreeList slFreeList
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 195) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 196) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 197) struct bbiSummaryOnDisk
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 198) /* The part of the summary that ends up on disk - in the same order written to disk. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 199)     {
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 200)     bits32 chromId;		/* ID of associated chromosome. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 201)     bits32 start,end;		/* Range of chromosome covered. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 202)     bits32 validCount;		/* Count of (bases) with actual data. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 203)     float minVal;		/* Minimum value of items */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 204)     float maxVal;		/* Maximum value of items */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 205)     float sumData;		/* sum of values for each base. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 206)     float sumSquares;		/* sum of squares for each base. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 207)     };
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 208) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 209) struct bbiInterval
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 210) /* Data on a single interval. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 211)     {
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 212)     struct bbiInterval *next;	/* Next in list. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 213)     bits32 start, end;			/* Position in chromosome, half open. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 214)     double val;				/* Value at that position. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 215)     };
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 216) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 217) typedef struct bbiInterval *(*BbiFetchIntervals)(struct bbiFile *bbi, char *chrom, 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 218) 					    bits32 start, bits32 end, struct lm *lm);
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 219) /* A callback function that returns a bbiInterval list. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 220) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 221) void bbiAttachUnzoomedCir(struct bbiFile *bbi);
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 222) /* Make sure unzoomed cir is attached. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 223) 
+82c38150 (kent          2009-02-03 02:50:39 +0000 224) struct bbiSummaryElement
+82c38150 (kent          2009-02-03 02:50:39 +0000 225) /* An element of a summary from the user side. */
+82c38150 (kent          2009-02-03 02:50:39 +0000 226)     {
+82c38150 (kent          2009-02-03 02:50:39 +0000 227)     bits64 validCount;		/* Count of (bases) with actual data. */
+82c38150 (kent          2009-02-03 02:50:39 +0000 228)     double minVal;		/* Minimum value of items */
+82c38150 (kent          2009-02-03 02:50:39 +0000 229)     double maxVal;		/* Maximum value of items */
+82c38150 (kent          2009-02-03 02:50:39 +0000 230)     double sumData;		/* sum of values for each base. */
+82c38150 (kent          2009-02-03 02:50:39 +0000 231)     double sumSquares;		/* sum of squares for each base. */
+82c38150 (kent          2009-02-03 02:50:39 +0000 232)     };
+82c38150 (kent          2009-02-03 02:50:39 +0000 233) 
+82c38150 (kent          2009-02-03 02:50:39 +0000 234) boolean bbiSummaryArrayExtended(struct bbiFile *bbi, char *chrom, bits32 start, bits32 end,
+82c38150 (kent          2009-02-03 02:50:39 +0000 235) 	BbiFetchIntervals fetchIntervals,
+82c38150 (kent          2009-02-03 02:50:39 +0000 236) 	int summarySize, struct bbiSummaryElement *summary);
+5726fd60 (kent          2009-06-17 15:19:03 +0000 237) /* Fill in summary with  data from indicated chromosome range in bigWig/bigBed file. 
+82c38150 (kent          2009-02-03 02:50:39 +0000 238)  * Returns FALSE if no data at that position. */
+82c38150 (kent          2009-02-03 02:50:39 +0000 239) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 240) boolean bbiSummaryArray(struct bbiFile *bbi, char *chrom, bits32 start, bits32 end,
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 241) 	BbiFetchIntervals fetchIntervals,
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 242) 	enum bbiSummaryType summaryType, int summarySize, double *summaryValues);
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 243) /* Fill in summaryValues with  data from indicated chromosome range in bigWig file.
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 244)  * Be sure to initialize summaryValues to a default value, which will not be touched
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 245)  * for regions without data in file.  (Generally you want the default value to either
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 246)  * be 0.0 or nan("") depending on the application.)  Returns FALSE if no data
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 247)  * at that position. */
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 248) 
+0442310c (kent          2009-11-05 19:46:58 +0000 249) struct bbiSummaryElement bbiTotalSummary(struct bbiFile *bbi);
+0442310c (kent          2009-11-05 19:46:58 +0000 250) /* Return summary of entire file! */
+0442310c (kent          2009-11-05 19:46:58 +0000 251) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 252) /****** Write side of things - implemented in bbiWrite.c ********/
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 253) 
+bf087c11 (kent          2009-07-27 18:02:11 +0000 254) struct bbiBoundsArray
+bf087c11 (kent          2009-07-27 18:02:11 +0000 255) /* Minimum info needed for r-tree indexer - where a section lives on disk and the
+bf087c11 (kent          2009-07-27 18:02:11 +0000 256)  * range it covers. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 257)     {
+bf087c11 (kent          2009-07-27 18:02:11 +0000 258)     bits64 offset;		/* Offset within file. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 259)     struct cirTreeRange range;	/* What is covered. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 260)     };
+bf087c11 (kent          2009-07-27 18:02:11 +0000 261) 
+bf087c11 (kent          2009-07-27 18:02:11 +0000 262) struct cirTreeRange bbiBoundsArrayFetchKey(const void *va, void *context);
+bf087c11 (kent          2009-07-27 18:02:11 +0000 263) /* Fetch bbiBoundsArray key for r-tree */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 264) 
+bf087c11 (kent          2009-07-27 18:02:11 +0000 265) bits64 bbiBoundsArrayFetchOffset(const void *va, void *context);
+bf087c11 (kent          2009-07-27 18:02:11 +0000 266) /* Fetch bbiBoundsArray file offset for r-tree */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 267) 
+ced62f42 (kent          2009-11-13 19:02:39 +0000 268) struct bbiSumOutStream
+ced62f42 (kent          2009-11-13 19:02:39 +0000 269) /* Buffer output to file so have a chance to compress. */
+ced62f42 (kent          2009-11-13 19:02:39 +0000 270)     {
+ced62f42 (kent          2009-11-13 19:02:39 +0000 271)     struct bbiSummaryOnDisk *array;
+ced62f42 (kent          2009-11-13 19:02:39 +0000 272)     int elCount;
+ced62f42 (kent          2009-11-13 19:02:39 +0000 273)     int allocCount;
+ced62f42 (kent          2009-11-13 19:02:39 +0000 274)     FILE *f;
+ced62f42 (kent          2009-11-13 19:02:39 +0000 275)     boolean doCompress;
+ced62f42 (kent          2009-11-13 19:02:39 +0000 276)     };
+ced62f42 (kent          2009-11-13 19:02:39 +0000 277) 
+ced62f42 (kent          2009-11-13 19:02:39 +0000 278) struct bbiSumOutStream *bbiSumOutStreamOpen(int allocCount, FILE *f, boolean doCompress);
+ced62f42 (kent          2009-11-13 19:02:39 +0000 279) /* Open new bbiSumOutStream. */
+ced62f42 (kent          2009-11-13 19:02:39 +0000 280) 
+ced62f42 (kent          2009-11-13 19:02:39 +0000 281) void bbiSumOutStreamClose(struct bbiSumOutStream **pStream);
+ced62f42 (kent          2009-11-13 19:02:39 +0000 282) /* Free up bbiSumOutStream */
+ced62f42 (kent          2009-11-13 19:02:39 +0000 283) 
+ced62f42 (kent          2009-11-13 19:02:39 +0000 284) void bbiSumOutStreamWrite(struct bbiSumOutStream *stream, struct bbiSummary *sum);
+ced62f42 (kent          2009-11-13 19:02:39 +0000 285) /* Write out next one to stream. */
+ced62f42 (kent          2009-11-13 19:02:39 +0000 286) 
+bf087c11 (kent          2009-07-27 18:02:11 +0000 287) void bbiOutputOneSummaryFurtherReduce(struct bbiSummary *sum, 
+bf087c11 (kent          2009-07-27 18:02:11 +0000 288) 	struct bbiSummary **pTwiceReducedList, 
+bf087c11 (kent          2009-07-27 18:02:11 +0000 289) 	int doubleReductionSize, struct bbiBoundsArray **pBoundsPt, 
+ced62f42 (kent          2009-11-13 19:02:39 +0000 290) 	struct bbiBoundsArray *boundsEnd, bits32 chromSize, struct lm *lm, 
+ced62f42 (kent          2009-11-13 19:02:39 +0000 291) 	struct bbiSumOutStream *stream);
+bf087c11 (kent          2009-07-27 18:02:11 +0000 292) /* Write out sum to file, keeping track of minimal info on it in *pBoundsPt, and also adding
+bf087c11 (kent          2009-07-27 18:02:11 +0000 293)  * it to second level summary. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 294) 
+bf087c11 (kent          2009-07-27 18:02:11 +0000 295) struct bbiSummary *bbiSummarySimpleReduce(struct bbiSummary *list, int reduction, struct lm *lm);
+bf087c11 (kent          2009-07-27 18:02:11 +0000 296) /* Do a simple reduction - where among other things the reduction level is an integral
+bf087c11 (kent          2009-07-27 18:02:11 +0000 297)  * multiple of the previous reduction level, and the list is sorted. Allocate result out of lm. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 298) 
+bf087c11 (kent          2009-07-27 18:02:11 +0000 299) #define bbiMaxZoomLevels 10	/* Maximum zoom levels produced by writers. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 300) 
+bf087c11 (kent          2009-07-27 18:02:11 +0000 301) void bbiWriteDummyHeader(FILE *f);
+bf087c11 (kent          2009-07-27 18:02:11 +0000 302) /* Write out all-zero header, just to reserve space for it. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 303) 
+bf087c11 (kent          2009-07-27 18:02:11 +0000 304) void bbiWriteDummyZooms(FILE *f);
+bf087c11 (kent          2009-07-27 18:02:11 +0000 305) /* Write out zeroes to reserve space for ten zoom levels. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 306) 
+681b584b (kent          2009-11-07 17:38:19 +0000 307) void bbiSummaryElementWrite(FILE *f, struct bbiSummaryElement *sum);
+681b584b (kent          2009-11-07 17:38:19 +0000 308) /* Write out summary element to file. */
+681b584b (kent          2009-11-07 17:38:19 +0000 309) 
+bf087c11 (kent          2009-07-27 18:02:11 +0000 310) void bbiWriteChromInfo(struct bbiChromUsage *usageList, int blockSize, FILE *f);
+bf087c11 (kent          2009-07-27 18:02:11 +0000 311) /* Write out information on chromosomes to file. */
+bf087c11 (kent          2009-07-27 18:02:11 +0000 312) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 313) void bbiWriteFloat(FILE *f, float val);
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 314) /* Write out floating point val to file.  Mostly to convert from double... */
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 315) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 316) struct hash *bbiChromSizesFromFile(char *fileName);
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 317) /* Read two column file into hash keyed by chrom. */
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 318) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 319) bits64 bbiTotalSummarySize(struct bbiSummary *list);
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 320) /* Return size on disk of all summaries. */
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 321) 
+feca5961 (braney        2009-08-13 21:48:17 +0000 322) void bbiChromUsageFree(struct bbiChromUsage **pUsage);
+feca5961 (braney        2009-08-13 21:48:17 +0000 323) /* free a single bbiChromUsage structure */
+feca5961 (braney        2009-08-13 21:48:17 +0000 324) 
+feca5961 (braney        2009-08-13 21:48:17 +0000 325) void bbiChromUsageFreeList(struct bbiChromUsage **pList);
+feca5961 (braney        2009-08-13 21:48:17 +0000 326) /* free a list of bbiChromUsage structures */
+feca5961 (braney        2009-08-13 21:48:17 +0000 327) 
+5b1b1663 (kent          2009-08-12 21:36:26 +0000 328) struct bbiChromUsage *bbiChromUsageFromBedFile(struct lineFile *lf, 
+0eb44740 (kent          2009-11-05 19:35:01 +0000 329) 	struct hash *chromSizesHash, int *retMinDiff, double *retAveSize, bits64 *retBedCount);
+feca5961 (braney        2009-08-13 21:48:17 +0000 330) /* Go through bed file and collect chromosomes and statistics. Free with bbiChromUsageFreeList */
+5b1b1663 (kent          2009-08-12 21:36:26 +0000 331) 
+5b1b1663 (kent          2009-08-12 21:36:26 +0000 332) int bbiCountSectionsNeeded(struct bbiChromUsage *usageList, int itemsPerSlot);
+5b1b1663 (kent          2009-08-12 21:36:26 +0000 333) /* Count up number of sections needed for data. */
+5b1b1663 (kent          2009-08-12 21:36:26 +0000 334) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 335) void bbiAddToSummary(bits32 chromId, bits32 chromSize, bits32 start, bits32 end, 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 336) 	bits32 validCount, double minVal, double maxVal, double sumData, double sumSquares,  
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 337) 	int reduction, struct bbiSummary **pOutList);
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 338) /* Add data range to summary - putting it onto top of list if possible, otherwise
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 339)  * expanding list. */
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 340) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 341) void bbiAddRangeToSummary(bits32 chromId, bits32 chromSize, bits32 start, bits32 end, 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 342) 	double val, int reduction, struct bbiSummary **pOutList);
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 343) /* Add chromosome range to summary - putting it onto top of list if possible, otherwise
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 344)  * expanding list. */
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 345) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 346) struct bbiSummary *bbiReduceSummaryList(struct bbiSummary *inList, 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 347) 	struct bbiChromInfo *chromInfoArray, int reduction);
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 348) /* Reduce summary list to another summary list. */
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 349) 
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 350) bits64 bbiWriteSummaryAndIndex(struct bbiSummary *summaryList, 
+fe6b431f (kent          2009-11-12 23:15:52 +0000 351) 	int blockSize, int itemsPerSlot, boolean doCompress, FILE *f);
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 352) /* Write out summary and index to summary, returning start position of
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 353)  * summary index. */
+18e51ee9 (kent          2009-02-03 00:39:44 +0000 354) 
+3d890482 (Brian Raney   2010-12-15 13:13:52 -0800 355) boolean bbiFileCheckSigs(char *fileName, bits32 sig, char *typeName);
+3d890482 (Brian Raney   2010-12-15 13:13:52 -0800 356) /* check file signatures at beginning and end of file */
+3d890482 (Brian Raney   2010-12-15 13:13:52 -0800 357) 
+044b178a (Hiram Clawson 2011-02-08 11:54:30 -0800 358) time_t bbiUpdateTime(struct bbiFile *bbi);
+044b178a (Hiram Clawson 2011-02-08 11:54:30 -0800 359) /* return bbi->udc->updateTime */
+044b178a (Hiram Clawson 2011-02-08 11:54:30 -0800 360) 
+80ad2e61 (kent          2009-02-02 06:05:52 +0000 361) #endif /* BBIFILE_H */
diff --git a/inc/fuzzyFind.h b/inc/fuzzyFind.h
new file mode 100644
index 0000000..c54ee8a
--- /dev/null
+++ b/inc/fuzzyFind.h
@@ -0,0 +1,260 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* fuzzyFind.h - This is the interface to the fuzzyFind
+ * DNA sequence aligner.  This just returns a single
+ * alignment - the one the algorithm thinks is best.
+ * The algorithm is heuristic, but pretty good.  (See
+ * comments in the fuzzyFind.c file for more details.) It
+ * is not good for finding distant homologies, but it
+ * will fairly reliably align a somewhat noisy cDNA
+ * sequence with genomic sequence.
+ *
+ * The main data structure is the ffAli - which is
+ * a node in a doubly linked list.  The finder algorithm
+ * returns a pointer to the leftmost node in the list.
+ * When you're done with the alignment you can dispose
+ * of it via ffFreeAli.
+ *
+ * The finder supports three levels of stringency.
+ * Generally you're best off using "ffTight".  "ffLoose"
+ * will allow for more distant matches, but at the 
+ * expense of very often taking several seconds to
+ * return a garbage alignment.  "ffExact" requires
+ * an exact match - which is quick, but in the
+ * real world not so often useful.
+ *
+ * If you want to compare alignments use ffScore.
+ */
+
+#ifndef FUZZYFIND_H
+#define FUZZYFIND_H
+
+#ifndef MEMGFX_H
+#include "memgfx.h"
+#endif 
+
+#ifndef DNAUTIL_H
+#include "dnautil.h"
+#endif
+
+#ifndef LOCALMEM_H
+#include "localmem.h"
+#endif
+
+#ifndef ALITYPE_H
+#include "aliType.h"
+#endif
+
+struct ffAli
+/* Node of a doubly linked list that will contain one
+ * alignment. Contains information on a matching
+ * set of DNA between needle and haystack. */
+    {
+    struct ffAli *left;   /* Neighboring intervals. */
+    struct ffAli *right;
+    char *nStart, *nEnd;          /* Needle start and end. (1/2 open interval) */
+    char *hStart, *hEnd;          /* Haystack start and end. */
+    int startGood, endGood; /* Number that match perfectly on ends. */
+    };
+
+/* maximum intron size for fuzzy find functions */
+
+#define ffIntronMaxDefault 750000	/* Default maximum intron size */
+
+extern int ffIntronMax;
+
+void setFfIntronMax(int value);         /* change max intron size */
+void setFfExtendThroughN(boolean val);	/* Set whether or not can extend through N's. */
+
+/************* lib/ffAli.c routines - using alignments ************/
+
+void ffFreeAli(struct ffAli **pAli);
+/* Dispose of memory gotten from fuzzyFind(). */
+
+int ffOneIntronOrientation(struct ffAli *left, struct ffAli *right);
+/* Return 1 for GT/AG intron between left and right, -1 for CT/AC, 0 for no
+ * intron. */
+
+int ffIntronOrientation(struct ffAli *ali);
+/* Return + for positive orientation overall, - for negative,
+ * 0 if can't tell. */
+
+int ffScoreIntron(DNA a, DNA b, DNA y, DNA z, int orientation);
+/* Return a better score the closer an intron is to
+ * consensus. Max score is 4. */
+
+struct ffAli *ffRightmost(struct ffAli *ff);
+/* Return rightmost block of alignment. */
+
+struct ffAli *ffMakeRightLinks(struct ffAli *rightMost);
+/* Given a pointer to the rightmost block in an alignment
+ * which has all of the left pointers filled in, fill in
+ * the right pointers and return the leftmost block. */
+ 
+void ffCountGoodEnds(struct ffAli *aliList);
+/* Fill in the goodEnd and badEnd scores. */
+
+int ffAliCount(struct ffAli *d);
+/* How many blocks in alignment? */
+
+struct ffAli *ffAliFromSym(int symCount, char *nSym, char *hSym,
+	struct lm *lm, char *nStart, char *hStart);
+/* Convert symbol representation of alignments (letters plus '-')
+ * to ffAli representation.  If lm is nonNULL, ffAli result 
+ * will be lmAlloced, else it will be needMemed. This routine
+ * depends on nSym/hSym being zero terminated. */
+
+/************* lib/ffScore.c routines - scoring alignments ************/
+
+int ffScoreMatch(DNA *a, DNA *b, int size);
+/* Compare two pieces of DNA base by base. Total mismatches are
+ * subtracted from total matches and returned as score. 'N's 
+ * neither hurt nor help score. */
+
+int ffScoreCdna(struct ffAli *ali);
+/* Return score of alignment.  A perfect alignment score will
+ * be the number of bases in needle. */
+
+int ffScore(struct ffAli *ali, enum ffStringency stringency);
+/* Score DNA based alignment. */
+
+int ffScoreProtein(struct ffAli *ali, enum ffStringency stringency);
+/* Figure out overall score of protein alignment. */
+
+int ffScoreSomething(struct ffAli *ali, enum ffStringency stringency,
+   boolean isProt);
+/* Score any alignment. */
+
+int ffScoreSomeAlis(struct ffAli *ali, int count, enum ffStringency stringency);
+/* Figure out score of count consecutive alis. */
+
+int ffCalcGapPenalty(int hGap, int nGap, enum ffStringency stringency);
+/* Return gap penalty for given h and n gaps. */
+
+int ffCalcCdnaGapPenalty(int hGap, int nGap);
+/* Return gap penalty for given h and n gaps in cDNA. */
+
+int ffGapPenalty(struct ffAli *ali, struct ffAli *right, enum ffStringency stringency);
+/* Calculate gap penaltly for alignment. */
+
+int ffCdnaGapPenalty(struct ffAli *ali, struct ffAli *right);
+/* Calculate gap penaltly for cdna alignment. */
+
+/************* jkOwnLib/ffAliHelp -helpers for alignment producers. ****************/
+
+boolean ffSlideIntrons(struct ffAli *ali);
+/* Slide introns (or spaces between aligned blocks)
+ * to match consensus.  Return TRUE if any slid. */
+
+boolean ffSlideOrientedIntrons(struct ffAli *ali, int orient);
+/* Slide introns (or spaces between aligned blocks)
+ * to match consensus on given strand (usually from ffIntronOrientation). */
+
+struct ffAli *ffRemoveEmptyAlis(struct ffAli *ali, boolean doFree);
+/* Remove empty blocks from list. Optionally free empties too. */
+
+struct ffAli *ffMergeHayOverlaps(struct ffAli *ali);
+/* Remove overlaps in haystack that perfectly abut in needle.
+ * These are transformed into perfectly abutting haystacks
+ * that have a gap in the needle. */
+
+struct ffAli *ffMergeNeedleAlis(struct ffAli *ali, boolean doFree);
+/* Remove overlapping areas needle in alignment. Assumes ali is sorted on
+ * ascending nStart field. Also merge perfectly abutting neighbors.*/
+
+void ffExpandExactRight(struct ffAli *ali, DNA *needleEnd, DNA *hayEnd);
+/* Expand aligned segment to right as far as can exactly. */
+
+void ffExpandExactLeft(struct ffAli *ali, DNA *needleStart, DNA *hayStart);
+/* Expand aligned segment to left as far as can exactly. */
+
+struct ffAli *ffMergeClose(struct ffAli *aliList, 
+	DNA *needleStart, DNA *hayStart);
+/* Remove overlapping areas needle in alignment. Assumes ali is sorted on
+ * ascending nStart field. Also merge perfectly abutting neighbors or
+ * ones that could be merged at the expense of just a few mismatches.*/
+
+void ffAliSort(struct ffAli **pList, 
+	int (*compare )(const void *elem1,  const void *elem2));
+/* Sort a doubly linked list of ffAlis. */
+
+void ffCat(struct ffAli **pA, struct ffAli **pB);
+/* Concatenate B to the end of A. Eat up second list
+ * in process. */
+
+int ffCmpHitsHayFirst(const void *va, const void *vb);
+/* Compare function to sort hit array by ascending
+ * target offset followed by ascending query offset. */
+
+int ffCmpHitsNeedleFirst(const void *va, const void *vb);
+/* Compare function to sort hit array by ascending
+ * query offset followed by ascending target offset. */
+
+/************* jkOwnLib/fuzzyFind - old local cDNA alignment. ****************/
+
+struct ffAli *ffFind(DNA *needleStart, DNA *needleEnd, DNA *hayStart, DNA *hayEnd,
+    enum ffStringency stringency);
+/* Return an alignment of needle in haystack. (Returns left end of doubly
+ * linked alignment list.) The input DNA is all expected to be lower case
+ * characters - a, c, g, t, or n. */
+
+boolean ffFindEitherStrand(DNA *needle, DNA *haystack, enum ffStringency stringency,
+    struct ffAli **pAli, boolean *pRcNeedle);
+/* Return TRUE if find an alignment using needle, or reverse complement of 
+ * needle to search haystack. DNA must be lower case. Needle and haystack
+ * are zero terminated. */
+
+boolean ffFindEitherStrandN(DNA *needle, int needleSize, DNA *haystack, int haySize,
+    enum ffStringency stringency, struct ffAli **pAli, boolean *pRcNeedle);
+/* Return TRUE if find an alignment using needle, or reverse complement of 
+ * needle to search haystack. DNA must be lower case. */
+
+boolean ffFindAndScore(DNA *needle, int needleSize, DNA *haystack, int haySize,
+    enum ffStringency stringency, struct ffAli **pAli, boolean *pRcNeedle, int *pScore);
+/* Return TRUE if find an alignment using needle, or reverse complement of 
+ * needle to search haystack. DNA must be lower case. If pScore is non-NULL returns
+ * score of alignment. */
+
+/************* lib/fuzzyShow - display alignments. ****************/
+
+void ffShowSideBySide(FILE *f, struct ffAli *leftAli, DNA *needle, int needleNumOffset,
+		      DNA *haystack, int hayNumOffset, int haySize, int hayOffStart, int hayOffEnd,
+		      int blockMaxGap, boolean rcHaystack, boolean initialNewline);
+/* Print HTML side-by-side alignment of needle and haystack (no title or labels) to f.
+ * {hay,needle}NumOffset are the coords at which the DNA sequence begins.
+ * hayOff{Start,End} are the range of coords *relative to hayNumOffset* to which the 
+ * alignment display will be clipped -- pass in {0,haySize} for no clipping. */
+
+int ffShAliPart(FILE *f, struct ffAli *aliList, 
+    char *needleName, DNA *needle, int needleSize, int needleNumOffset,
+    char *haystackName, DNA *haystack, int haySize, int hayNumOffset,
+    int blockMaxGap, boolean rcNeedle, boolean rcHaystack,
+    boolean showJumpTable, 
+    boolean showNeedle, boolean showHaystack,
+    boolean showSideBySide, boolean upcMatch,
+    int cdsS, int cdsE, int hayPartS, int hayPartE);
+/* Display parts of alignment on html page.  If hayPartS..hayPartE is a 
+ * smaller subrange of the alignment, highlight that part of the alignment 
+ * in both needle and haystack with underline & bold, and show only that 
+ * part of the haystack (plus padding).  Returns number of blocks (after
+ * merging blocks separated by blockMaxGap or less). */
+
+int ffShAli(FILE *f, struct ffAli *aliList, 
+    char *needleName, DNA *needle, int needleSize, int needleNumOffset,
+    char *haystackName, DNA *haystack, int haySize, int hayNumOffset,
+    int blockMaxGap,
+    boolean rcNeedle);
+/* Display alignment on html page.  Returns number of blocks (after
+ * merging blocks separated by blockMaxGap or less). */
+
+void ffShowAli(struct ffAli *aliList, 
+    char *needleName, DNA *needle, int needleNumOffset,
+    char *haystackName, DNA *haystack, int hayNumOffset,
+    boolean rcNeedle);
+/* Display alignment on html page to stdout. */
+
+#endif /* FUZZYFIND_H */
+
diff --git a/inc/gapCalc.h b/inc/gapCalc.h
new file mode 100644
index 0000000..8da6208
--- /dev/null
+++ b/inc/gapCalc.h
@@ -0,0 +1,44 @@
+/* gapCalc - Stuff to calculate complex (but linear) gap costs quickly,
+ * and read specifications from a file. */
+
+#ifndef GAPCALC_H
+#define GAPCALC_H
+
+    
+struct gapCalc;	  /* Predeclare structure.  It's complex and private though, so
+                   * real declaration is in gapCalc.c. */
+
+struct gapCalc *gapCalcDefault();
+/* Return default gapCalc. */
+
+struct gapCalc *gapCalcRnaDna();
+/* Return gaps suitable for RNA queries vs. DNA targets */
+
+struct gapCalc *gapCalcCheap();
+/* Return cheap gap costs. */
+
+struct gapCalc *gapCalcOriginal();
+/* Return gap costs from original paper. */
+
+struct gapCalc *gapCalcFromFile(char *fileName);
+/* Return gapCalc from file. */
+
+struct gapCalc *gapCalcFromString(char *s);
+/* Return gapCalc from description string. */
+
+struct gapCalc *gapCalcRead(struct lineFile *lf);
+/* Create gapCalc from open file. */
+
+void gapCalcFree(struct gapCalc **pGapCalc);
+/* Free up resources associated with gapCalc. */
+
+int gapCalcCost(struct gapCalc *gapCalc, int dq, int dt);
+/* Figure out gap costs. */
+
+char *gapCalcSampleFileContents();
+/* Return contents of a sample linear gap file. */
+
+void gapCalcTest(struct gapCalc *gapCalc);
+/* Print out gap cost info. */
+
+#endif /* GAPCALC_H */
diff --git a/inc/gdf.h b/inc/gdf.h
new file mode 100644
index 0000000..07380df
--- /dev/null
+++ b/inc/gdf.h
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* gdf - Intronerator Gene Description File. */
+
+#ifndef GDF_H
+#define GDF_H
+
+#ifndef DNAUTIL_H
+#include "dnautil.h"
+#endif
+
+struct gdfDataPoint
+/* This stores data at each exon/intron boundary. */
+    {
+    int start;
+    };
+
+struct gdfGene
+/* One structure of these for each gene (each isoform of each gene
+ * actually. */
+    {
+    struct gdfGene *next;
+    char *name;
+    int dataCount;
+    struct gdfDataPoint *dataPoints;
+    char strand;
+    UBYTE chromIx;
+    };
+
+struct gdfGene *newGdfGene(char *name, int nameSize, int exonCount, char strand, UBYTE chromIx);
+/* Return a new gene. */
+
+void gdfFreeGene(struct gdfGene *gene);
+/* Free a gene. */
+
+void gdfFreeGeneList(struct gdfGene **pList);
+/* Free a whole list of genes. */
+
+struct gdfGene *gdfReadOneGene(FILE *f);
+/* Read one entry from a Gdf file.  Assumes that the file pointer
+ * is in the right place. */
+
+void gdfGeneExtents(struct gdfGene *gene, long *pMin, long *pMax);
+/* Figure out first and last base in gene. */
+
+void gdfOffsetGene(struct gdfGene *gene, int offset);
+/* Add offset to each point in gene */
+
+void gdfRcGene(struct gdfGene *gene, int size);
+/* Flip gene to other strand. Assumes dataPoints are already
+ * moved into range from 0-size */
+
+void gdfUpcExons(struct gdfGene *gene, int geneOffset, DNA *dna, int dnaSize, int dnaOffset);
+/* Uppercase exons in DNA. */
+
+
+#endif /* GDF_H */
+
diff --git a/inc/genoFind.h b/inc/genoFind.h
new file mode 100644
index 0000000..669091c
--- /dev/null
+++ b/inc/genoFind.h
@@ -0,0 +1,385 @@
+/* genoFind.h - Interface to modules for fast finding of sequence
+ * matches. */
+/* Copyright 2001-2002 Jim Kent.  All rights reserved. */
+
+#ifndef GENOFIND_H
+#define GENOFIND_H
+
+#ifndef DNASEQ_H
+#include "dnaseq.h"
+#endif
+
+#ifndef FUZZYFIND_H
+#include "fuzzyFind.h"
+#endif
+
+#ifndef HASH_H
+#include "hash.h"
+#endif
+
+#ifndef ALITYPE_H
+#include "aliType.h"
+#endif
+
+#ifndef LOCALMEM_H
+#include "localmem.h"
+#endif 
+
+#ifndef BITS_H
+#include "bits.h"
+#endif
+
+#ifndef AXT_H
+#include "axt.h"
+#endif
+
+enum gfConstants {
+    gfMinMatch = 2,
+    gfMaxGap = 2,
+    gfTileSize = 11,
+    gfMaxTileUse = 1024,
+    gfPepMaxTileUse = 30000,
+};
+
+struct gfSeqSource
+/* Where a block of sequence comes from. */
+    {
+    struct gfSeqSource *next;
+    char *fileName;	/* Name of file. */
+    bioSeq *seq;	/* Sequences.  Usually either this or fileName is NULL. */
+    bits32 start,end;	/* Position within merged sequence. */
+    Bits *maskedBits;	/* If non-null contains repeat-masking info. */
+    };
+
+struct gfHit
+/* A genoFind hit. */
+   {
+   struct gfHit *next;
+   bits32 qStart;		/* Where it hits in query. */
+   bits32 tStart;		/* Where it hits in target. */
+   bits32 diagonal;		/* tStart + qSize - qStart. */
+   };
+
+/* gfHits are free'd with simple freeMem or slFreeList. */
+
+struct gfClump
+/* A clump of hits. */
+/* Note: for clumps from regular (blat) queries, tStart and tEnd include 
+ * target->start, but for clumps from gfPcrClumps(), tStart and tEnd have 
+ * already had target->start subtracted.  So tStart and tEnd in PCR clumps 
+ * are relative to that target sequence (not the collection of all target 
+ * sequences). */
+    {
+    struct gfClump *next;	/* Next clump. */
+    bits32 qStart, qEnd;	/* Position in query. */
+    struct gfSeqSource *target;	/* Target source sequence. */
+    bits32 tStart, tEnd;	/* Position in target. */
+    int hitCount;		/* Number of hits. */
+    struct gfHit *hitList;	/* List of hits. Not allocated here. */
+    int queryCoverage;		/* Number of bases covered in query (thx AG!) */
+    };
+
+void gfClumpFree(struct gfClump **pClump);
+/* Free a single clump. */
+
+void gfClumpFreeList(struct gfClump **pList);
+/* Free a list of dynamically allocated gfClump's */
+
+struct genoFind
+/* An index of all K-mers in the genome. */
+    {
+    int maxPat;                          /* Max # of times pattern can occur
+                                          * before it is ignored. */
+    int minMatch;                        /* Minimum number of tile hits needed
+                                          * to trigger a clump hit. */
+    int maxGap;                          /* Max gap between tiles in a clump. */
+    int tileSize;			 /* Size of each N-mer. */
+    int stepSize;			 /* Spacing between N-mers. */
+    int tileSpaceSize;                   /* Number of N-mer values. */
+    int tileMask;			 /* 1-s for each N-mer. */
+    int sourceCount;			 /* Count of source files. */
+    struct gfSeqSource *sources;         /* List of sequence sources. */
+    bool isPep;			 	 /* Is a peptide. */
+    bool allowOneMismatch;		 /* Allow a single mismatch? */
+    int segSize;			 /* Index is segmented if non-zero. */
+    bits32 totalSeqSize;		 /* Total size of all sequences. */
+    bits32 *listSizes;                   /* Size of list for each N-mer */
+    void *allocated;                     /* Storage space for all lists. */
+    bits32 **lists;                      /* A list for each N-mer. Used if
+                                          * isSegmented is false. */
+    bits16 **endLists;                   /* A more complex list for each N-mer.
+                                          * Used if isSegmented is true.
+					  * Values come in groups of threes.
+					  * The first is the packed last few
+					  * letters of the tile.  The next two
+					  * are the offset in the genome.  This
+					  * would be a struct but that would take
+					  * 8 bytes instead of 6, or nearly an
+					  * extra gigabyte of RAM. */
+    };
+
+void genoFindFree(struct genoFind **pGenoFind);
+/* Free up a genoFind index. */
+
+struct gfSeqSource *gfFindNamedSource(struct genoFind *gf, char *name);
+/* Find target of given name.  Return NULL if none. */
+
+/* ---  Stuff for saving results ---- */
+
+
+struct gfOutput
+/* A polymorphic object to help us write many file types. */
+    {
+    struct gfOutput *next;
+    void *data;		/* Type-specific data pointer.  Must be freeMem'able */
+    void (*out)(char *chromName, int chromSize, int chromOffset,
+	    struct ffAli *ali, bioSeq *tSeq, struct hash *t3Hash, bioSeq *qSeq, 
+	    boolean qIsRc, boolean tIsRc,
+	    enum ffStringency stringency, int minMatch, struct gfOutput *out);
+    /* This is the type of a client provided function to save an alignment. 
+     * The parameters are:
+     *     chromName - name of target (aka genomic or database) sequence.
+     *     chromSize - size of target sequence.
+     *     chromOffset - offset of genoSequence in target.
+     *     ffAli - alignment with pointers into tSeq/qSeq or in
+     *             translated target case, into t3Hash.
+     *     tSeq - part of target sequence in normal case.   In translated
+     *             target case look at t3Hash instead.
+     *     t3Hash - used only in translated target case.  A hash keyed by
+     *             target sequence name with values *lists* of trans3 structures.
+     *             This hash can be searched to find both the translated and
+     *             untranslated versions of the bits of the target that are in 
+     *             memory.  (You can assume at this point all parts needed for
+     *             output are indeed in memory.)
+     *     qSeq - query sequence (this isn't segmented at all). 
+     *     isRc - True if query is reverse complemented.
+     *     stringency - ffCdna, etc.  I'm hoping to move this elsewhere.
+     *     minMatch - minimum score to output.  Also should be moved elsewhere.
+     *     outputData - custom data for specific output function.
+     * The interface is a bit complex - partly from the demands of translated
+     * output, and partly from trying not to have the entire target sequence in
+     * memory.
+     */
+    void (*queryOut)(struct gfOutput *out, FILE *f); 
+    /* Called for each query */
+
+    void (*fileHead)(struct gfOutput *out, FILE *f);
+    /* Write file header if any */
+
+    boolean reportTargetStrand; /* Report target as well as query strand? */
+    struct hash *maskHash;	/* associates target sequence name and mask. */
+    int minGood;		/* Minimum sequence identity in thousandths. */
+    boolean qIsProt;		/* Query is peptide. */
+    boolean tIsProt;		/* Target is peptide. */
+    int queryIx;		/* Index of query */
+    boolean includeTargetFile;	/* Prefix file: to target sequence name. */
+    };
+
+struct gfOutput *gfOutputAny(char *format, 
+	int goodPpt, boolean qIsProt, boolean tIsProt, 
+	boolean noHead, char *databaseName,
+	int databaseSeqCount, double databaseLetters,
+	double minIdentity, FILE *f);
+/* Initialize output in a variety of formats in file or memory. 
+ * Parameters:
+ *    format - either 'psl', 'pslx', 'blast', 'wublast', 'axt'
+ *    goodPpt - minimum identity of alignments to output in parts per thousand
+ *    qIsProt - true if query side is a protein.
+ *    tIsProt - true if target (database) side is a protein.
+ *    noHead - if true suppress header in psl/pslx output.
+ *    databaseName - name of database.  Only used for blast output
+ *    databaseSeq - number of sequences in database - only for blast
+ *    databaseLetters - number of bases/aas in database - only blast
+ *    FILE *f - file.  
+ */
+
+struct gfOutput *gfOutputPsl(int goodPpt, 
+	boolean qIsProt, boolean tIsProt, FILE *f, 
+	boolean saveSeq, boolean noHead);
+/* Set up psl/pslx output */
+
+struct gfOutput *gfOutputAxt(int goodPpt, boolean qIsProt, 
+	boolean tIsProt, FILE *f);
+/* Setup output for axt format. */
+
+struct gfOutput *gfOutputAxtMem(int goodPpt, boolean qIsProt, 
+	boolean tIsProt);
+/* Setup output for in memory axt output. */
+
+struct gfOutput *gfOutputBlast(int goodPpt, 
+	boolean qIsProt, boolean tIsProt, 
+	char *databaseName, int databaseSeqCount, double databaseLetters,
+	char *blastType, /* blast, blast8, blast9, wublast, or xml */
+	double minIdentity, FILE *f);
+/* Setup output for blast/wublast format. */
+
+void gfOutputQuery(struct gfOutput *out, FILE *f);
+/* Finish writing out results for a query to file. */
+
+void gfOutputHead(struct gfOutput *out, FILE *f);
+/* Write out header if any. */
+
+void gfOutputFree(struct gfOutput **pOut);
+/* Free up output. */
+
+/* -------- Routines to build up index ------------ */
+
+void gfCheckTileSize(int tileSize, boolean isPep);
+/* Check that tile size is legal.  Abort if not. */
+
+struct genoFind *gfIndexSeq(bioSeq *seqList,
+	int minMatch, int maxGap, int tileSize, int maxPat, char *oocFile,
+	boolean isPep, boolean allowOneMismatch, boolean maskUpper,
+	int stepSize);
+/* Make index for all seqs in list. 
+ *      minMatch - minimum number of matching tiles to trigger alignments
+ *      maxGap   - maximum deviation from diagonal of tiles
+ *      tileSize - size of tile in nucleotides
+ *      maxPat   - maximum use of tile to not be considered a repeat
+ *      oocFile  - .ooc format file that lists repeat tiles.  May be NULL. 
+ *      isPep    - TRUE if indexing proteins, FALSE for DNA. 
+ *      maskUpper - Mask out upper case sequence (currently only for nucleotides).
+ *      stepSize - space between tiles.  Zero means default (which is tileSize). 
+ * For DNA sequences upper case bits will be unindexed. */
+
+struct genoFind *gfIndexNibsAndTwoBits(int fileCount, char *fileNames[],
+	int minMatch, int maxGap, int tileSize, int maxPat, char *oocFile, 
+	boolean allowOneMismatch, int stepSize);
+/* Make index for all .nib and .2bits in list. 
+ *      minMatch - minimum number of matching tiles to trigger alignments
+ *      maxGap   - maximum deviation from diagonal of tiles
+ *      tileSize - size of tile in nucleotides
+ *      maxPat   - maximum use of tile to not be considered a repeat
+ *      oocFile  - .ooc format file that lists repeat tiles.  May be NULL. 
+ *      allowOneMismatch - allow one mismatch in a tile.  
+ *      stepSize - space between tiles.  Zero means default (which is tileSize). */
+
+void gfIndexTransNibsAndTwoBits(struct genoFind *transGf[2][3], 
+    int fileCount, char *fileNames[], 
+    int minMatch, int maxGap, int tileSize, int maxPat, char *oocFile,
+    boolean allowOneMismatch, boolean mask, int stepSize);
+/* Make translated (6 frame) index for all .nib and .2bit files. */
+
+/* -------- Routines to scan index for homolgous areas ------------ */
+
+struct gfClump *gfFindClumps(struct genoFind *gf, struct dnaSeq *seq, 
+	struct lm *lm, int *retHitCount);
+/* Find clumps associated with one sequence. */
+
+struct gfClump *gfFindClumpsWithQmask(struct genoFind *gf, bioSeq *seq, 
+        Bits *qMaskBits, int qMaskOffset,
+	struct lm *lm, int *retHitCount);
+/* Find clumps associated with one sequence soft-masking seq according to qMaskBits */
+
+struct gfHit *gfFindHitsInRegion(struct genoFind *gf, bioSeq *seq, 
+	Bits *qMaskBits, int qMaskOffset, struct lm *lm, 
+	struct gfSeqSource *target, int tMin, int tMax);
+/* Find hits restricted to one particular region. 
+ * The hits returned by this will be in target sequence
+ * coordinates rather than concatenated whole genome
+ * coordinates as hits inside of clumps usually are.  */
+
+void gfTransFindClumps(struct genoFind *gfs[3], aaSeq *seq, struct gfClump *clumps[3], struct lm *lm, int *retHitCount);
+/* Find clumps associated with one sequence in three translated reading frames. */
+
+void gfTransTransFindClumps(struct genoFind *gfs[3], aaSeq *seqs[3], 
+	struct gfClump *clumps[3][3], struct lm *lm, int *retHitCount);
+/* Find clumps associated with three sequences in three translated 
+ * reading frames. Used for translated/translated protein comparisons. */
+
+void gfClumpDump(struct genoFind *gf, struct gfClump *clump, FILE *f);
+/* Print out info on clump.  This routine subtracts clump->target->start 
+ * from clump->tStart and from clump->tEnd for printing, so that printed 
+ * coords are relative to that target sequence. */
+
+
+void gfAlignAaClumps(struct genoFind *gf,  struct gfClump *clumpList, aaSeq *seq,
+    boolean isRc,  int minMatch,  struct gfOutput *out);
+/* Convert gfClumps to an actual alignment that gets saved via 
+ * outFunction/outData. */
+
+void gfFindAlignAaTrans(struct genoFind *gfs[3], aaSeq *qSeq, struct hash *t3Hash, 
+	boolean tIsRc, int minMatch, struct gfOutput *out);
+/* Look for qSeq alignment in three translated reading frames. Save alignment
+ * via outFunction/outData. */
+
+
+/* ---  Some routines for dealing with gfServer at a low level ---- */
+
+char *gfSignature();
+/* Return signature that starts each command to gfServer. Helps defend 
+ * server from confused clients. */
+
+void gfCatchPipes();
+/* Set up to catch broken pipe signals. */
+
+int gfReadMulti(int sd, void *vBuf, size_t size);
+/* Read in until all is read or there is an error. */
+
+/* ---  Some routines for dealing with gfServer at a high level ---- */
+
+struct hash *gfFileCacheNew();
+/* Create hash for storing info on .nib and .2bit files. */
+
+void gfFileCacheFree(struct hash **pCache);
+/* Free up resources in cache. */
+
+void gfAlignStrand(int *pConn, char *nibDir, struct dnaSeq *seq,
+    boolean isRc,  int minMatch, 
+    struct hash *tFileCache, struct gfOutput *out);
+/* Search genome on server with one strand of other sequence to find homology. 
+ * Then load homologous bits of genome locally and do detailed alignment.
+ * Call 'outFunction' with each alignment that is found.  gfSavePsl is a handy
+ * outFunction to use. */
+
+void gfAlignTrans(int *pConn, char *nibDir, aaSeq *seq,
+    int minMatch, struct hash *tFileHash, struct gfOutput *out);
+/* Search indexed translated genome on server with an amino acid sequence. 
+ * Then load homologous bits of genome locally and do detailed alignment.
+ * Call 'outFunction' with each alignment that is found. */
+
+void gfAlignTransTrans(int *pConn, char *nibDir, struct dnaSeq *seq, 
+	boolean qIsRc, int minMatch, struct hash *tFileCache, 
+	struct gfOutput *out, boolean isRna);
+/* Search indexed translated genome on server with an dna sequence.  Translate
+ * this sequence in three frames. Load homologous bits of genome locally
+ * and do detailed alignment.  Call 'outFunction' with each alignment
+ * that is found. */
+
+int gfConnect(char *hostName, char *portName);
+/* Set up our network connection to server. */
+
+int gfDefaultRepMatch(int tileSize, int stepSize, boolean protTiles);
+/* Figure out appropriate step repMatch value. */
+
+void gfMakeOoc(char *outName, char *files[], int fileCount, 
+	int tileSize, bits32 maxPat, enum gfType tType);
+/* Count occurences of tiles in seqList and make a .ooc file. */
+
+void gfLongDnaInMem(struct dnaSeq *query, struct genoFind *gf, 
+   boolean isRc, int minScore, Bits *qMaskBits, struct gfOutput *out,
+   boolean fastMap, boolean band);
+/* Chop up query into pieces, align each, and stitch back
+ * together again. */
+
+void gfLongTransTransInMem(struct dnaSeq *query, struct genoFind *gfs[3], 
+   struct hash *t3Hash, boolean qIsRc, boolean tIsRc, boolean qIsRna,
+   int minScore, struct gfOutput *out);
+/* Chop up query into pieces, align each in translated space, and stitch back
+ * together again as nucleotides. */
+
+struct gfClump *gfPcrClumps(struct genoFind *gf, 
+        char *fPrimer, int fPrimerSize, char *rPrimer, int rPrimerSize,
+	int minDistance, int maxDistance);
+/* Find possible PCR hits.  The fPrimer and rPrimer are on opposite strands.
+ * Note: unlike clumps from other query functions, PCR clumps from this 
+ * function have already had clump->target->start subtracted from 
+ * clump->tStart and clump->tEnd so that the coords are relative to that 
+ * target sequence (not the collection of all target sequences). */
+
+#define MAXSINGLEPIECESIZE 5000 /* maximum size of a single piece */
+
+#define gfVersion "35"	/* Current BLAT version number */
+
+#endif /* GENOFIND_H */
+
diff --git a/inc/genomeRangeTree.h b/inc/genomeRangeTree.h
new file mode 100644
index 0000000..4feec60
--- /dev/null
+++ b/inc/genomeRangeTree.h
@@ -0,0 +1,111 @@
+/* genomeRangeTree - This module is a way of keeping track of
+ * non-overlapping ranges (half-open intervals) across a whole
+ * genome (multiple chromosomes or scaffolds). 
+ * It is a hash table container mapping chrom to rangeTree.
+ * Most of the work is performed by rangeTree, this container
+ * enables local memory and stack to be shared by many rangeTrees
+ * so it should be able to handle genomes with a very large 
+ * number of scaffolds. See rangeTree for more information. */
+
+#ifndef GENOMERANGETREE_H
+#define GENOMERANGETREE_H
+
+#ifndef HASH_H
+#include "hash.h"
+#endif
+
+#ifndef DYSTRING_H
+#include "dystring.h"
+#endif
+
+#ifndef RANGETREE_H
+#include "rangeTree.h"
+#endif
+
+struct genomeRangeTree
+/* A structure that allows efficient random access of ranges of bases covered
+ * by a particular feature genome-wide.  Implemented as a range tree for each
+ * scaffold or chromosome in a genome. */
+    {
+    struct genomeRangeTree *next;  /* Next genomeRangeTree in list if any. */
+    struct hash *hash;             /* Hash of rangeTrees keyed by chromosome/scaffold name. */
+    struct rbTreeNode *stack[128]; /* Stack for binary search. */
+    struct lm *lm;                 /* Local memory pool for tree nodes and ranges. */
+    };
+
+struct genomeRangeTree *genomeRangeTreeNew();
+/* Create a new, empty, genomeRangeTree. Uses the default hash size.
+ * Free with genomeRangeTreeFree. */
+
+struct genomeRangeTree *genomeRangeTreeNewSize(int hashPowerOfTwoSize);
+/* Create a new, empty, genomeRangeTree. 
+ * Free with genomeRangeTreeFree. */
+
+void genomeRangeTreeFree(struct genomeRangeTree **pTree);
+/* Free up genomeRangeTree. */
+
+struct rbTree *genomeRangeTreeFindRangeTree(struct genomeRangeTree *tree, char *chrom);
+/* Find the rangeTree for this chromosome, if any. Returns NULL if chrom not found.
+ * Free with genomeRangeTreeFree. */
+
+struct rbTree *genomeRangeTreeFindOrAddRangeTree(struct genomeRangeTree *tree, char *chrom);
+/* Find the rangeTree for this chromosome, or add new chrom and empty rangeTree if not found.
+ * Free with genomeRangeTreeFree. */
+
+struct range *genomeRangeTreeAdd(struct genomeRangeTree *tree, char *chrom, int start, int end);
+/* Add range to tree, merging with existing ranges if need be. 
+ * Adds new rangeTree if chrom not found. */
+
+struct range *genomeRangeTreeAddVal(struct genomeRangeTree *tree, char *chrom, int start, int end, void *val, void *(*mergeVals)(void *existing, void*new));
+/* Add range to tree, merging with existing ranges if need be. 
+ * Adds new rangeTree if chrom not found. 
+ * If this is a new range, set the value to this val.
+ * If there are existing items for this range, and if mergeVals function is not null, 
+ * apply mergeVals to the existing values and this new val, storing the result as the val
+ * for this range (see rangeTreeAddValCount() and rangeTreeAddValList() below for examples). */
+
+struct range *genomeRangeTreeAddValCount(struct genomeRangeTree *tree, char *chrom, int start, int end);
+/* Add range to tree, merging with existing ranges if need be. 
+ * Adds new rangeTree if chrom not found. 
+ * Set range val to count of elements in the range. Counts are pointers to 
+ * ints allocated in tree localmem */
+
+struct range *genomeRangeTreeAddValList(struct genomeRangeTree *tree, char *chrom, int start, int end, void *val);
+/* Add range to tree, merging with existing ranges if need be. 
+ * Adds new rangeTree if chrom not found. 
+ * Add val to the list of values (if any) in each range.
+ * val must be valid argument to slCat (ie, be a struct with a 'next' pointer as its first member) */
+
+boolean genomeRangeTreeOverlaps(struct genomeRangeTree *tree, char *chrom, int start, int end);
+/* Return TRUE if start-end overlaps anything in tree. */
+
+int genomeRangeTreeOverlapSize(struct genomeRangeTree *tree, char *chrom, int start, int end);
+/* Return the total size of intersection between interval
+ * from start to end, and items in range tree. Sadly not
+ * thread-safe. */
+
+struct range *genomeRangeTreeFindEnclosing(struct genomeRangeTree *tree, char *chrom, int start, int end);
+/* Find item in range tree that encloses range between start and end 
+ * if there is any such item. */
+
+struct range *genomeRangeTreeAllOverlapping(struct genomeRangeTree *tree, char *chrom, int start, int end);
+/* Return list of all items in range tree that overlap interval start-end.
+ * Do not free this list, it is owned by tree.  However it is only good until
+ * next call to rangeTreeFindInRange or rangeTreeList. Not thread safe. */
+
+struct range *genomeRangeTreeMaxOverlapping(struct genomeRangeTree *tree, char *chrom, int start, int end);
+/* Return item that overlaps most with start-end. Not thread safe.  Trashes list used
+ * by rangeTreeAllOverlapping. */
+
+struct range *genomeRangeTreeList(struct genomeRangeTree *tree, char *chrom);
+/* Return list of all ranges in single rangeTree in order.  Not thread safe. 
+ * No need to free this when done, memory is local to tree. */
+
+struct dyString *genomeRangeTreeToString(struct genomeRangeTree *tree);
+/* Return a string representation of the genomeRangeTree.
+ * Useful for testing.
+ * Not thread-safe; uses globals */
+
+
+#endif /* GENOMERANGETREE_H */
+
diff --git a/inc/gfClientLib.h b/inc/gfClientLib.h
new file mode 100644
index 0000000..7f67a97
--- /dev/null
+++ b/inc/gfClientLib.h
@@ -0,0 +1,26 @@
+/* gfClientLib - stuff that both blat and pcr clients of
+ * genoFind use. */
+
+#ifndef GFCLIENTLIB_H
+#define GFCLIENTLIB_H
+
+void gfClientFileArray(char *fileName, char ***retFiles, int *retFileCount);
+/* Check if file if .2bit or .nib or .fa.  If so return just that
+ * file in a list of one.  Otherwise read all file and treat file
+ * as a list of filenames.  */
+
+bioSeq *gfClientSeqList(int fileCount, char *files[], 
+	boolean isProt, boolean isTransDna, char *maskType, 
+	float minRepDivergence, boolean showStatus);
+/* From an array of .fa and .nib file names, create a
+ * list of dnaSeqs, which are set up so that upper case is masked and lower case
+ * is unmasked sequence. (This is the opposite of the input, but set so that
+ * we can use lower case as our primary DNA sequence, which historically predates
+ * our use of lower case masking.)  Protein sequence on the other hand is
+ * all upper case. */
+
+void gfClientUnmask(struct dnaSeq *seqList);
+/* Unmask all sequences. */
+
+#endif /* GFCLIENTLIB_H */
+
diff --git a/inc/gfPcrLib.h b/inc/gfPcrLib.h
new file mode 100644
index 0000000..e35137c
--- /dev/null
+++ b/inc/gfPcrLib.h
@@ -0,0 +1,100 @@
+/* gfPcrLib - Routines to help do in silico PCR.
+ * Copyright 2004 Jim Kent.  All rights reserved. */
+
+#ifndef GFPCRLIB_H
+#define GFPCRLIB_H
+
+struct gfPcrInput
+/* Info for input to one PCR experiment. */
+    {
+    struct gfPcrInput *next;  /* Next in singly linked list. */
+    char *name;	/* Name of experiment */
+    char *fPrimer;	/* Forward primer - 15-30 bases */
+    char *rPrimer;	/* Reverse primer - after fPrimer and on opposite strand */
+    };
+
+void gfPcrInputStaticLoad(char **row, struct gfPcrInput *ret);
+/* Load a row from gfPcrInput table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+
+struct gfPcrInput *gfPcrInputLoad(char **row);
+/* Load a gfPcrInput from row fetched with select * from gfPcrInput
+ * from database.  Dispose of this with gfPcrInputFree(). */
+
+struct gfPcrInput *gfPcrInputLoadAll(char *fileName);
+/* Load all gfPcrInput from a whitespace-separated file.
+ * Dispose of this with gfPcrInputFreeList(). */
+
+void gfPcrInputFree(struct gfPcrInput **pEl);
+/* Free a single dynamically allocated gfPcrInput such as created
+ * with gfPcrInputLoad(). */
+
+void gfPcrInputFreeList(struct gfPcrInput **pList);
+/* Free a list of dynamically allocated gfPcrInput's */
+
+struct gfPcrOutput
+/* Output of PCR experiment. */
+    {
+    struct gfPcrOutput *next;	/* Next in list */
+    char *name;			/* Name of experiment. */
+    char *fPrimer;	/* Forward primer - 15-30 bases */
+    char *rPrimer;	/* Reverse primer - after fPrimer and on opposite strand */
+    char *seqName;	/* Name of sequence (chromosome maybe) that gets amplified. */
+    int seqSize;	/* Size of sequence (chromosome maybe) */
+    int fPos;		/* Position of forward primer in seq. */
+    int rPos;		/* Position of reverse primer in seq. */
+    char strand;	/* Strand of amplified sequence. */
+    char *dna;		/* Fragment of sequence that gets amplified.
+                         * Note in some senses you'll want to replace
+			 * start and ends of this with fPrimer/rPrimer to
+			 * be strictly accurate.  */
+    };
+
+void gfPcrOutputFree(struct gfPcrOutput **pOut);
+/* Free up a gfPcrOutput structure. */
+
+void gfPcrOutputFreeList(struct gfPcrOutput **pList);
+/* Free up a list of gfPcrOutputs. */
+
+
+
+
+void gfPcrLocal(char *pcrName, 
+	struct dnaSeq *seq, int seqOffset, char *seqName, int seqSize,
+	int maxSize, char *fPrimer, int fPrimerSize, char *rPrimer, int rPrimerSize,
+	int minPerfect, int minGood, char strand, struct gfPcrOutput **pOutList);
+/* Do detailed PCR scan on DNA already loaded into memory and put results
+ * (in reverse order) on *pOutList. */
+
+struct gfRange *gfPcrGetRanges(char *host, char *port, char *fPrimer, char *rPrimer,
+	int maxSize);
+/* Query gfServer with primers and convert response to a list of gfRanges. */
+
+struct gfPcrOutput *gfPcrViaNet(char *host, char *port, char *seqDir, 
+	struct gfPcrInput *inList,
+	int maxSize, int minPerfect, int minGood);
+/* Do PCRs using gfServer index, returning list of results. */
+
+void gfPcrOutputWriteOne(struct gfPcrOutput *out, char *outType, 
+	char *url, FILE *f);
+/* Write a single output in specified format (either "fa" or "bed") 
+ * to file.  If url is non-null it should be a printf formatted
+ * string that takes %s, %d, %d for chromosome, start, end. */
+
+void gfPcrOutputWriteList(struct gfPcrOutput *outList, char *outType, 
+	char *url, FILE *f);
+/* Write list of outputs in specified format (either "fa" or "bed") 
+ * to file.  If url is non-null it should be a printf formatted
+ * string that takes %s, %d, %d for chromosome, start, end. */
+
+void gfPcrOutputWriteAll(struct gfPcrOutput *outList, 
+	char *outType, char *url, char *fileName);
+/* Create file of outputs in specified format (either "fa" or "bed") 
+ * to file.  If url is non-null it should be a printf formatted
+ * string that takes %s, %d, %d for chromosome, start, end. */
+
+char *gfPcrMakePrimer(char *s);
+/* Make primer (lowercased DNA) out of text.  Complain if
+ * it is too short or too long. */
+
+#endif /* GFPCRLIB_H */
diff --git a/inc/gfWebLib.h b/inc/gfWebLib.h
new file mode 100644
index 0000000..0ba8990
--- /dev/null
+++ b/inc/gfWebLib.h
@@ -0,0 +1,28 @@
+/* gfWebLib - stuff shared by gfWebBlat and gfWebPcr - little web programs
+ * that query gfServer in different ways. */
+
+struct gfServerAt
+/* A gfServer with an in-memory index. */
+    {
+    struct gfServerAt *next;
+    char *host;		/* IP Address of machine running server. */
+    char *port;		/* IP Port on host. */
+    char *seqDir;	/* Where associated sequence lives. */
+    char *name;		/* Name user sees. */
+    };
+
+struct gfServerAt *gfWebFindServer(struct gfServerAt *serverList, char *varName);
+/* Find active server (that matches contents of CGI variable varName). */
+
+struct gfWebConfig
+/* A parsed out configuration file. */
+    {
+    char *company;	/* Company name if any. */
+    char *background;	/* Web page background if any. */
+    struct gfServerAt *serverList;  /* List of servers. */
+    struct gfServerAt *transServerList;  /* List of translated servers. */
+    char *tempDir;	/* Where to put temporary files. */
+    };
+
+struct gfWebConfig *gfWebConfigRead(char *fileName);
+/* Read configuration file into globals. */
diff --git a/inc/gff.h b/inc/gff.h
new file mode 100644
index 0000000..f33a52a
--- /dev/null
+++ b/inc/gff.h
@@ -0,0 +1,141 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* gff.h Parse a GFF or GTF file. */
+
+#ifndef GFF_H
+#define GFF_H
+
+struct gffLine
+/* A parsed line in a GFF file. */
+    {
+    struct gffLine *next;  /* Next line in file */
+    char *seq;      /* Name of sequence. */
+    char *source;   /* Program that made this line.  Not allocated here. */
+    char *feature;  /* Type field. (Intron, CDS, etc). Not allocated here. */
+    int start;      /* Start of feature in sequence. Starts with 0, not 1 */
+    int end;        /* End of feature in sequence. End is not included. */
+    double score;   /* Score. */
+    char strand;    /* Strand of sequence feature is on. + or - or .*/
+    char frame;     /* Frame feature is in. 1, 2, 3, or . */
+    char *group;    /* Group line is in. Not allocated here.  Corresponds to transcript_id in GTF */
+    char *geneId;    /* gene_id in GTF, NULL in GFF.  Not allocated here. */
+    char *exonId;       /* exon_id in GTF, NULL in GFF. Not allocated here. */
+    int exonNumber; /* O in GFF or if missing in GTF.  Otherwise exon number. */
+    char *intronId;       /* intron_id in GTF, NULL in GFF. Not allocated here. */
+    char *intronStatus;   /* intron status. Not allocated here. */
+    char *proteinId;      /* protein_id in GTF, NULL in GFF. Not allocated here. */
+    char *geneName;       /* gene_name or NULL in GTF, NULL in GFF. Not allocated here. */
+    char *transcriptName; /* transcript_name or NULL in GTF, NULL in GFF. Not allocated here. */
+    };
+
+struct gffGroup
+/* A group of lines in a GFF file (all that share the same group field). */
+    {
+    struct gffGroup *next;   /* Next group in file. */
+    char *name;     /* Name of group. Not allocated here. */
+    char *seq;      /* Name of sequence. Not allocated here. */
+    char *source;      /* Name of source program. Not allocated here. */
+    /* The next three fields are only valid after call to gffGroupLines() */
+    int start;      /* Start of feature in sequence. Starts with 0, not 1 */
+    int end;        /* End of feature in sequence. End is not included. */
+    char strand;    /* Strand of sequence. */
+    struct gffLine *lineList;  /* List of lines in group. */
+    };
+
+struct gffSource
+/* A list of sources. */
+    {
+    struct gffSource *next; /* Next in list. */
+    char *name;	  /* Name, not allocated here. */
+    unsigned int id;   /* Database ID (or just 0) */
+    };
+
+struct gffFeature
+/* A list of types in GFF file. */
+    {
+    struct gffFeature *next; /* Next in list. */
+    char *name;	  /* Name, not allocated here. */
+    };
+
+struct gffSeqName
+/* A list of sequence. */
+    {
+    struct gffSeqName *next;  /* Next in list. */
+    char *name;   /* Name, not allocated here. */
+    };
+
+struct gffGeneId
+/* A list of genes. */
+    {
+    struct gffGeneId *next;  /* Next in list. */
+    char *name;   /* Name, not allocated here. */
+    };
+
+struct gffFile
+/* This keeps information on a fully parsed GFF file. */
+    {
+    struct gffFile *next;
+    char *fileName;             /* Name of file (allocated here) */
+    struct hash *seqHash;	/* A name only hash of the sequence. */
+    struct hash *sourceHash;	/* A name only hash of gff sources. */
+    struct hash *featureHash;   /* A name only hash of gff types. */
+    struct hash *groupHash;	/* Associates group names and gffGroups. */
+    struct hash *geneIdHash;    /* Hash of all geneIds. */
+    struct hash *strPool;       /* hash used to allocate strings */
+    struct gffLine *lineList;   /* List of lines - lines may be in groupList instead. */
+    struct gffSeqName *seqList; /* List of sequences in file. */
+    struct gffSource *sourceList; /* List of all sources in file. */
+    struct gffFeature *featureList; /* List of all types in file. */
+    struct gffGroup *groupList; /* A list of groups. */
+    struct gffGeneId *geneIdList;  /* List of all gene ID's. */
+    bool isGtf;			/* Is this a GTF file? */
+    bool typeKnown;		/* Is 'isGtf' known? */
+    };
+
+void gffGroupFree(struct gffGroup **pGroup);
+/* Free up a gffGroup including lineList. */
+
+void gffGroupFreeList(struct gffGroup **pList);
+/* Free up a list of gffGroups. */
+
+void gffGroupLines(struct gffFile *gff);
+/* Group lines of gff file together, in process mofing
+ * gff->lineList to gffGroup->lineList. */
+
+struct gffFile *gffRead(char *fileName);
+/* Create a gffFile structure from a GFF file. */
+
+struct gffFile *gffFileNew(char *fileName);
+/* Create a new gffFile structure. */
+
+void gffFileAdd(struct gffFile *gff, char *fileName, int baseOffset);
+/* Add file to gffFile. */
+
+void gffFileAddRow(struct gffFile *gff, int baseOffset, char *words[], int wordCount, 
+		char *fileName, int lineIx);
+/* Process one row of GFF file (a non-comment line parsed by tabs normally). */
+
+void gffFileFree(struct gffFile **pGff);
+/* Free up a gff file. */
+
+int gffLineCmp(const void *va, const void *vb);
+/* Compare two gffLines (for use in slSort, etc.) . */
+
+void gffOutput(struct gffLine *el, FILE *f, char sep, char lastSep);
+/* Print out GTF.  Separate fields with sep. Follow last field with lastSep. */
+
+boolean gffHasGtfGroup(char *line);
+/* Return TRUE if line has a GTF group field */
+
+#define gffTabOut(el,f) gffOutput(el,f,'\t','\n');
+/* Print out GTF as a line in a tab-separated file. */
+
+#define gffCommaOut(el,f) gffOutput(el,f,',',',');
+/* Print out GTF as a comma separated list including final comma. */
+
+
+#endif /* GFF_H */
+
diff --git a/inc/gff3.h b/inc/gff3.h
new file mode 100644
index 0000000..2184209
--- /dev/null
+++ b/inc/gff3.h
@@ -0,0 +1,265 @@
+/*
+ * Object for accessing GFF3 files
+ * See GFF3 specification for details of file format:
+ *   http://www.sequenceontology.org/gff3.shtml
+ */
+#ifndef gff3_h
+#define gff3_h
+
+struct gff3Ann
+/* Annotation record from a GFF3 file.  Attributes define in the spec (those
+ * starting with upper case letters) are parsed into fields of this
+ * object. User defined attributes (starting with lower-case characters) are
+ * stored as in a list, along with a copy of the string versions of the spec
+ * attributes. All strings stored in the object have been un-escaped.
+ * All storage for the object is allocated by the gff3File object.
+ * For discontinuous features, there are multiple gff3Ann objects.
+ * These objects are stored in a double-linked list, and all references
+ * point to the first one in ascending start order.*/
+{
+    struct gff3Ann *prevPart; /* Discontinuous features have linked annotation */
+    struct gff3Ann *nextPart; /* field name next not used to avoid confusion */
+    char *seqid;   /* The ID of the landmark used to establish the coordinate
+                    * system for the current feature. IDs may contain any
+                    * characters. */
+    char *source;  /* The source is a free text qualifier intended to describe
+                    * the algorithm or operating procedure that generated this
+                    * feature.  Typically this is the name of a piece of
+                    * software, such as "Genescan" or a database name, such as
+                    * "Genbank."  In effect, the source is used to extend the
+                    * feature ontology by adding a qualifier to the type
+                    * creating a new composite type that is a subclass of the
+                    * type in the type column. */
+
+    char *type; /* The type of the feature (previously called the "method").
+                 * This is constrained to be either: (a) a term from the
+                 * "lite" sequence ontology, SOFA; or (b) a SOFA accession
+                 * number.  The latter alternative is distinguished using the
+                 * syntax SO:000000. */
+
+    int start; /* The start and end of the feature, in 0-based, half open
+                * integer coordinates, relative to the landmark given in
+                * seqid.  Start is always less than or equal to end.  For
+                * zero-length features, such as insertion sites, start equals
+                * end and the implied site is to the right of the indicated
+                * base in the direction of the landmark.*/
+    int end;
+    float score; /* The score of the feature, a floating point number.  As in
+                    earlier versions of the format, the semantics of the score
+                    are ill-defined.  It is strongly recommended that E-values
+                    be used for sequence similarity features, and that
+                    P-values be used for ab initio gene prediction features. */
+    boolean haveScore;  /* was score specified? */
+
+    char *strand; /* The strand of the feature.  '+' for positive strand
+                   * (relative to the landmark), '-' for minus strand, and
+                   * NULL for features that are not stranded.  In addition,
+                   * '?' can be used for features whose strandedness is
+                   * relevant, but unknown. */
+
+    int phase; /* For features of type "CDS", the phase indicates where the
+                * feature begins with reference to the reading frame.  The
+                * phase is one of the integers 0, 1, or 2, indicating the
+                * number of bases that should be removed from the beginning of
+                * this feature to reach the first base of the next codon. In
+                * other words, a phase of 0 indicates that the next codon
+                * begins at the first base of the region described by the
+                * current line, a phase of 1 indicates that the next codon
+                * begins at the second base of this region, and a phase of 2
+                * indicates that the codon begins at the third base of this
+                * region. This is NOT to be confused with the frame, which is
+                * simply start modulo 3.  For forward strand features, phase
+                * is counted from the start field. For reverse strand
+                * features, phase is counted from the end field. The phase is
+                * REQUIRED for all CDS features. and -1 for other features. */
+
+    /* The remaining fields are the attributes.  Attributes defined by the
+     * GFF3 spec (starting with an upper-case letter) are stored in the fields
+     * below.  Application-specific attributes (starting with a lower-case
+     * letter) are stored in the attrs list.  */
+
+    char *id;  /* Indicates the name of the feature.  IDs must be unique
+                * within the scope of the GFF file.*/
+    char *name;  /* Display name for the feature.  This is the name to be
+                  * displayed to the user.  Unlike IDs, there is no requirement
+                  * that the Name be unique within the file. */
+
+    struct slName *aliases; /* A secondary names for the feature.  It is
+                             * suggested that this tag be used whenever a
+                             * secondary identifier for the feature is needed,
+                             * such as locus names and accession numbers.
+                             * Unlike ID, there is no requirement that Alias
+                             * be unique within the file. */
+    
+    struct slName *parentIds; /* Indicates the parent of the feature.  A parent
+                               * ID can be used to group exons into transcripts,
+                               * transcripts into genes, an so forth.  A feature
+                               * may have multiple parents.  Parent can *only* be
+                               * used to indicate a partof relationship. */
+    struct gff3AnnRef *parents; /* Parent objects for parentIds */
+                                      
+
+    char *targetId; /* Indicates the target of a nucleotide-to-nucleotide or
+                       protein-to-nucleotide alignment.  NULL if not specified. */
+    int targetStart; /* target start/end, in 0-based, half open coordinates */
+    int targetEnd;
+    char *targetStrand; /* optional target strand, or NULL if none. */
+
+    char *gap; /* The alignment of the feature to the target if the two are
+                * not collinear (e.g. contain gaps).  The alignment format is
+                * taken from the CIGAR format.  See "THE GAP ATTRIBUTE"
+                * section of GFF3 specification for a description of this
+                * format.*/
+
+    char *derivesFromId; /* Used to disambiguate the relationship between one
+                          * feature and another when the relationship is a
+                          * temporal one rather than a purely structural "part
+                          * of" one.  This is needed for polycistronic
+                          * genes. */
+    struct gff3Ann *derivesFrom; /* Object for derivesFromId */
+
+    struct slName *notes;  /* free text notes. */
+
+    struct slName *dbxrefs; /* database cross references. */
+
+    struct slName *ontologyTerms; /* cross reference to ontology terms. */
+
+    struct gff3Attr *attrs;  /* attributes, both user-define and spec-defined,
+                                  * parsed into one or more values */
+
+    struct gff3AnnRef *children;  /* child nodes */
+
+    struct gff3SeqRegion *seqRegion;  /* start/end of sequence region, taken
+                                       * from ##sequence-region records, or
+                                       * NULL if not specified.*/
+
+    struct gff3File *file;  /* file this record is associated with */
+    int lineNum;            /* line number of record in file, or -1
+                             * if not known */
+};
+
+struct gff3AnnRef
+/* A reference to a gff3Ann object */
+{
+    struct gff3AnnRef *next;   /* next link in the chain */
+    struct gff3Ann *ann;       /* reference to object */
+};
+
+struct gff3Attr
+/* an attribute and string values */
+{
+    struct gff3Attr *next;     /* next attribute in the list */
+    char *tag;                 /* name of attribute */
+   struct slName *vals;       /* values for the attribute */
+};
+
+struct gff3SeqRegion
+/* start/end of a sequence region, taken from ##sequence-region record.*/
+{
+    struct gff3SeqRegion *next;     /* next region */
+    char *seqid;    /* sequence if of region */
+    int start;      /* bounds of region */
+    int end;
+};
+
+struct gff3File
+/* Object representing a GFF file. Manages all memory for related objects. */
+{
+    char *fileName;       /* path of file that was parsed */
+    struct hash *byId;    /* index of gff3Ann object by id.  Links to first object of link discontinuous features */
+    struct gff3AnnRef *anns;   /* all records in the file. Includes all parts of discontinuous features */
+    struct gff3AnnRef *roots;  /* all records without parents. */
+    struct hash *pool;         /* used to allocate string values that tend to
+                                * be repeated in the files.  localMem is also 
+                                * to allocated memory for all other objects. */
+    struct gff3SeqRegion *seqRegions;  /* list of gff3SeqRegion objects. */
+    struct hash *seqRegionMap;  /* map of seqId to gff3SeqRegion objects. NULL
+                                 * if none are specified */
+
+    struct slName *featureOntologies;    /* feature ontology URIs */
+    struct slName *attributeOntologies;  /* attribute ontology URIs */
+    struct slName *sourceOntologies;     /* source ontology URIs */
+    struct slName *species;              /* Species, usually NCBI Taxonomy
+                                          * URI */
+    char *genomeBuildSource;             /* source of genome build */
+    char *genomeBuildName;               /* name or version of genome build */
+    struct dnaSeq *seqs;                 /* list of sequences */
+    struct hash *seqMap;                 /* map of sequence ids to sequence
+                                          * string from ##FASTA section or
+                                          * NULL if none specified */
+    struct lineFile *lf;                 /* only set while parsing */
+    FILE *errFh;            /* write errors to this file */
+    int maxErr;             /* maximum number of errors before aborting */
+    int errCnt;             /* error count */
+};
+
+
+/* standard attribute tags */
+extern char *gff3AttrID;
+extern char *gff3AttrName;
+extern char *gff3AttrAlias;
+extern char *gff3AttrParent;
+extern char *gff3AttrTarget;
+extern char *gff3AttrGap;
+extern char *gff3AttrDerivesFrom;
+extern char *gff3AttrNote;
+extern char *gff3AttrDbxref;
+extern char *gff3AttrOntologyTerm;
+
+/* commonly used features names */
+extern char *gff3FeatGene;
+extern char *gff3FeatMRna;
+extern char *gff3FeatExon;
+extern char *gff3FeatCDS;
+extern char *gff3FeatThreePrimeUTR;
+extern char *gff3FeatFivePrimeUTR;
+extern char *gff3FeatStartCodon;
+extern char *gff3FeatStopCodon;
+
+struct gff3File *gff3FileOpen(char *fileName, int maxErr, FILE *errFh);
+/* Parse a GFF3 file into a gff3File object.  If maxErr not zero, then
+ * continue to parse until this number of error have been reached.  A maxErr
+ * less than zero does not stop reports all errors. Write errors to errFh,
+ * if NULL, use stderr. */
+
+void gff3FileFree(struct gff3File **g3fPtr);
+/* Free a gff3File object */
+
+struct gff3Ann *gff3FileFindAnn(struct gff3File *g3f, char *id);
+/* find an annotation record by id, or NULL if not found. */
+
+struct gff3Attr *gff3AnnFindAttr(struct gff3Ann *g3a, char *tag);
+/* find a user attribute, or NULL */
+
+void gff3FileWrite(struct gff3File *g3f, char *fileName);
+/* write contents of an GFF3File object to a file */
+
+INLINE struct gff3AnnRef *gff3AnnRefNew(struct gff3Ann *g3a)
+/* Allocate a gff3AnnRef object from the heap.  Not used by the parsing code, as 
+ * all data is contained in localMem objects */
+{
+struct gff3AnnRef *ref;
+AllocVar(ref);
+ref->ann = g3a;
+return ref;
+}
+
+int gff3AnnRefLocCmp(const void *va, const void *vb);
+/* sort compare function for location of two gff3AnnRef objects */
+
+INLINE int gff3PhaseToFrame(int phase)
+/* convert a phase to a frame */
+{
+switch (phase)
+    {
+    case 0:
+        return 0;
+    case 1:
+        return 2;
+    case 2:
+        return 1;
+    }
+return -1;
+}
+
+#endif
diff --git a/inc/gfxPoly.h b/inc/gfxPoly.h
new file mode 100644
index 0000000..7e363c7
--- /dev/null
+++ b/inc/gfxPoly.h
@@ -0,0 +1,31 @@
+/* gfxPoly - two dimensional polygon. */
+
+#ifndef GFXPOLY_H
+#define GFXPOLY_H
+
+struct gfxPoint
+/* A two-dimensional point, typically in pixel coordinates. */
+    {
+    struct gfxPoint *next;
+    int x, y;		/* Position */
+    };
+
+struct gfxPoly
+/* A two-dimensional polygon */
+    {
+    struct gfxPoly *next;
+    int ptCount;		/* Number of points. */
+    struct gfxPoint *ptList;	/* First point in list, which is circular. */
+    struct gfxPoint *lastPoint;	/* Last point in list. */
+    };
+
+struct gfxPoly *gfxPolyNew();
+/* Create new (empty) polygon */
+
+void gfxPolyFree(struct gfxPoly **pPoly);
+/* Free up resources associated with polygon */
+
+void gfxPolyAddPoint(struct gfxPoly *poly, int x, int y);
+/* Add point to polygon. */
+
+#endif /* GFXPOLY_H */
diff --git a/inc/gifLabel.h b/inc/gifLabel.h
new file mode 100644
index 0000000..462f8f2
--- /dev/null
+++ b/inc/gifLabel.h
@@ -0,0 +1,10 @@
+/* gifLabel - create labels as GIF files. */
+
+int gifLabelMaxWidth(char **labels, int labelCount);
+/* Return maximum pixel width of labels.  It's ok to have
+ * NULLs in labels array. */
+
+void gifLabelVerticalText(char *fileName, char **labels, int labelCount, 
+	int height);
+/* Make a gif file with given labels.  This will check to see if fileName
+ * exists already, and if so do nothing. */
diff --git a/inc/hacTree.h b/inc/hacTree.h
new file mode 100644
index 0000000..97006fc
--- /dev/null
+++ b/inc/hacTree.h
@@ -0,0 +1,82 @@
+/* hacTree - Hierarchical Agglomerative Clustering a list of inputs into a binary tree */
+/*
+ * This clustering algorithm can be used for problems with high
+ * dimensionality, such as clustering sequences by similarity.  It can
+ * be used for problems with low dimensionality too, such as
+ * clustering a sequence of numbers (1-dimensional: points along the
+ * number line), but there are more efficient algorithms for problems
+ * with low dimensionality.
+ *
+ * In order to use this, you need to provide functions that operate on a
+ * pair of input items (and extra data pointer):
+ * 1. a distance function that takes two input items and returns a number,
+ *    small for short distances/high similarity and large for long
+ *    distances/low similarity
+ * 2. a merging function that takes two input items and returns a new item
+ *    that represents both of them.  Therefore the data structure that
+ *    represents an input item must also be capable of representing a
+ *    cluster of input items.  Usually this is done by combining values
+ *    from input items into a new value that will compare properly with
+ *    other items or clusters in the distance function.
+ *
+ * Then pass in an slList of items, pointers to those two functions, and
+ * a pointer to data used in your distance and merging functions (or NULL).
+ * You get back a pointer to the root node of a binary tree structure
+ * where each leaf node contains one of your items and each node above
+ * that contains a cluster.  The root node contains the cluster of all items.
+ *
+ * If a significant proportion of input items are identical to each other,
+ * you can also pass in a comparison function that will be used to sort the
+ * items before clustering.  After sorting, adjacent identical items will
+ * be pre-clustered in order to reduce the number of inputs to the main
+ * clustering step.
+ *
+ * kent/src/lib/tests/hacTreeTest.c contains a couple simple examples.
+ *
+ * To get the top k clusters, perform a breadth-first,
+ * lowest-distance-child-first search of the tree to find the top k
+ * nodes/clusters with the smallest distances from the root node/cluster.
+ * [It would be nice for this module to provide that function, if/when a need for it arises.]
+ */
+#ifndef HACTREE_H
+#define HACTREE_H
+
+#include "localmem.h"
+
+/* Caller-provided function to measure distance between two items or clusters */
+/* Note: this must be able to handle identical inputs or NULL inputs */
+/* Note: this should be monotonic and nonnegative, *not* a + or -
+ * difference (as would be used for comparing/ordering/sorting) */
+typedef double hacDistanceFunction(const struct slList *item1, const struct slList *item2,
+				   void *extraData);
+
+/* Caller-provided function to merge two items or clusters into a new cluster */
+/* Note: this must be able to handle NULL inputs */
+typedef struct slList *(hacMergeFunction)(const struct slList *item1, const struct slList *item2,
+					  void *extraData);
+
+/* Optional caller-provided function to compare two items or clusters for pre-sorting
+ * and pre-clustering of identical items. */
+typedef int hacCmpFunction(const struct slList *item1, const struct slList *item2,
+			   void *extraData);
+
+/* Structure of nodes of the binary tree that contains a hierarchical clustering of inputs */
+struct hacTree
+    {
+    struct hacTree *next;       // Can have an unordered list of these
+    struct hacTree *parent;     // Cluster that contains this cluster, NULL for root node
+    struct hacTree *left;       // Left child, NULL for leaf node
+    struct hacTree *right;      // Right child, NULL for leaf node
+    double childDistance;       // Result of distance function on left and right kids
+    struct slList *itemOrCluster;  // If leaf node, one of the items passed in;
+                                // otherwise, result of merging left and right kids' itemOrClusters
+    };
+
+struct hacTree *hacTreeFromItems(const struct slList *itemList, struct lm *localMem,
+				 hacDistanceFunction *distF, hacMergeFunction *mergeF,
+				 hacCmpFunction *cmpF, void *extraData);
+/* Using distF, mergeF, optionally cmpF and binary tree operations,
+ * perform a hierarchical agglomerative (bottom-up) clustering of
+ * items.  To free the resulting tree, lmCleanup(&localMem). */
+
+#endif//def HACTREE_H
diff --git a/inc/hash.h b/inc/hash.h
new file mode 100644
index 0000000..a7fc017
--- /dev/null
+++ b/inc/hash.h
@@ -0,0 +1,279 @@
+/* Hash - a simple hash table that provides name/value pairs. 
+ * The most common usage is to create a hash as so:
+ *    struct hash *hash = hashNew(0);
+ * to add elements to a hash as so:
+ *    hashAdd(hash, name, value);
+ * and to retrieve a named element as so:
+ *    value = hashFindVal(hash, name);
+ * The hashFindVal function will return NULL if the name does not
+ * appear in the hash.  Alternatively you can use:
+ *    value = hashMustFindVal(hash, name);
+ * which will abort if name is not in the hash.  When done with a hash do:
+ *     hashFree(&hash);
+ *
+ * The hash does support multiple values for the same key.  To use
+ * this functionality, try the loop:
+ *     struct hashEl *hel;
+ *     for (hel = hashLookup(hash, name); hel != NULL; hel = hashLookupNext(hel))
+ *         {
+ *         value = hel->val;
+ *         // Further processing here.
+ * The order of elements retrieved this way will be most-recently-added first.
+ * The hashLookup function is _slightly_ faster than the hashFindVal function,
+ * so sometimes it is used just to test for the presence of an element in the
+ * hash when not interested in the value associated with it.
+ *
+ * One can iterate through all the elements in a hash in three ways.  One can
+ * get a list of all things in the hash as so:
+ *     struct hashEl *hel, *helList = hashElListHash(hash);
+ *     for (hel = helList; hel != NULL; hel = hel->next)
+ *        {
+ *        value = hel->val;
+ *        // Further processing of value here. 
+ *        }
+ *     hashElFreeList(&helList);
+ * One can avoid the overhead of creating a list by using an iterator object
+ * and function:
+ *    struct hashEl *hel;
+ *    struct hashCookie cookie = hashFirst(hash);
+ *    while ((hel = hashNext(&cookie)) != NULL)
+ *        {
+ *        value = hel->val;
+ * Finally one can use hashTraverseEls or hashTraverseVals with a callback 
+ * function that takes a hashEl, or the void *value as parameter respectively.
+ *
+ * There are various other functions involving hashes in this module as well
+ * that provide various short cuts.  For information on these and additional
+ * details of the functions described, please read the full hash.h file, and
+ * if so inclined the hash.c file as well.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef HASH_H
+#define HASH_H
+
+struct hashEl
+/* An element in a hash list. */
+    {
+    struct hashEl *next;
+    char *name;
+    void *val;
+    bits32 hashVal;
+    };
+
+struct hash
+    {
+    struct hash *next;	/* Next in list. */
+    bits32 mask;	/* Mask hashCrc with this to get it to fit table. */
+    struct hashEl **table;	/* Hash buckets. */
+    int powerOfTwoSize;		/* Size of table as a power of two. */
+    int size;			/* Size of table. */
+    struct lm *lm;	/* Local memory pool. */
+    int elCount;		/* Count of elements. */
+    boolean autoExpand;         /* Automatically expand hash */
+    float expansionFactor;      /* Expand when elCount > size*expansionFactor */
+    int numResizes;             /* number of times resize was called */
+    };
+
+#define defaultExpansionFactor 1.0
+
+#define hashMaxSize 28 
+
+struct hashCookie
+/* used by hashFirst/hashNext in tracking location in traversing hash */
+    {
+    struct hash *hash;      /* hash we are associated with */
+    int idx;                /* current index in hash */
+    struct hashEl *nextEl;  /* current element in hash */
+    };
+
+bits32 hashString(char *string);
+/* Compute a hash value of a string. */
+
+bits32 hashCrc(char *string);
+/* Returns a CRC value on string. */
+
+struct hashEl *hashLookup(struct hash *hash, char *name);
+/* Looks for name in hash table. Returns associated element,
+ * if found, or NULL if not.  If there are multiple entries
+ * for name, the last one added is returned (LIFO behavior).
+ */
+
+struct hashEl *hashLookupUpperCase(struct hash *hash, char *name);
+/* Lookup upper cased name in hash. (Assumes all elements of hash
+ * are themselves already in upper case.) */
+
+struct hashEl *hashLookupNext(struct hashEl *hashEl);
+/* Find the next occurance of name that may occur in the table multiple times,
+ * or NULL if not found.  Use hashLookup to find the first occurrence.  Elements
+ * are returned in LIFO order.
+ */
+
+struct hashEl *hashAdd(struct hash *hash, char *name, void *val);
+/* Add new element to hash table.  If an item with name, already exists, a new
+ * item is added in a LIFO manner.  The last item added for a given name is
+ * the one returned by the hashLookup functions.  hashLookupNext must be used
+ * to find the preceding entries for a name.
+ */
+
+struct hashEl *hashAddN(struct hash *hash, char *name, int nameSize, void *val);
+/* Add name of given size to hash (no need to be zero terminated) */
+
+void *hashRemove(struct hash *hash, char *name);
+/* Remove item of the given name from hash table. 
+ * Returns value of removed item, or NULL if not in the table.
+ * If their are multiple entries for name, the last one added
+ * is removed (LIFO behavior).
+ */
+
+struct hashEl *hashAddUnique(struct hash *hash, char *name, void *val);
+/* Add new element to hash table. Squawk and die if is already in table. */
+
+struct hashEl *hashAddSaveName(struct hash *hash, char *name, void *val, char **saveName);
+/* Add new element to hash table.  Save the name of the element, which is now
+ * allocated in the hash table, to *saveName.  A typical usage would be:
+ *    AllocVar(el);
+ *    hashAddSaveName(hash, name, el, &el->name);
+ */
+
+struct hashEl *hashStore(struct hash *hash, char *name);
+/* If element in hash already return it, otherwise add it
+ * and return it. */
+
+char  *hashStoreName(struct hash *hash, char *name);
+/* Put name into hash table. */
+
+char *hashMustFindName(struct hash *hash, char *name);
+/* Return name as stored in hash table (in hel->name). 
+ * Abort if not found. */
+
+void *hashMustFindVal(struct hash *hash, char *name);
+/* Lookup name in hash and return val.  Abort if not found. */
+
+void *hashFindVal(struct hash *hash, char *name);
+/* Look up name in hash and return val or NULL if not found. */
+
+void *hashOptionalVal(struct hash *hash, char *name, void *usual);
+/* Look up name in hash and return val, or usual if not found. */
+
+void *hashFindValUpperCase(struct hash *hash, char *name);
+/* Lookup upper cased name in hash and return val or return NULL if not found.
+ * (Assumes all elements of hash are themselves already in upper case.) */
+
+struct hashEl *hashAddInt(struct hash *hash, char *name, int val);
+/* Store integer value in hash */
+
+void hashIncInt(struct hash *hash, char *name);
+/* Increment integer value in hash */
+
+int hashIntVal(struct hash *hash, char *name);
+/* Return integer value associated with name in a simple 
+ * hash of ints. */
+
+int hashIntValDefault(struct hash *hash, char *name, int defaultInt);
+/* Return integer value associated with name in a simple 
+ * hash of ints or defaultInt if not found. */
+
+long long hashIntSum(struct hash *hash);
+/* Return sum of all the ints in a hash of ints. */
+
+void hashTraverseEls(struct hash *hash, void (*func)(struct hashEl *hel));
+/* Apply func to every element of hash with hashEl as parameter. */
+
+void hashTraverseVals(struct hash *hash, void (*func)(void *val));
+/* Apply func to every element of hash with hashEl->val as parameter. */
+
+struct hashEl *hashElListHash(struct hash *hash);
+/* Return a list of all elements of hash.   Free return with hashElFreeList. */
+
+int hashElCmp(const void *va, const void *vb);
+/* Compare two hashEl by name. */
+
+int hashElCmpWithEmbeddedNumbers(const void *va, const void *vb);
+/* Compare two hashEl by name sorting including numbers within name,
+ * suitable for chromosomes, genes, etc. */
+
+void *hashElFindVal(struct hashEl *list, char *name);
+/* Look up name in hashEl list and return val or NULL if not found. */
+
+void hashElFree(struct hashEl **pEl);
+/* Free hash el list returned from hashListAll.  */
+
+void hashElFreeList(struct hashEl **pList);
+/* Free hash el list returned from hashListAll.  (Don't use
+ * this internally. */
+
+struct hashCookie hashFirst(struct hash *hash);
+/* Return an object to use by hashNext() to traverse the hash table.
+ * The first call to hashNext will return the first entry in the table. */
+
+struct hashEl* hashNext(struct hashCookie *cookie);
+/* Return the next entry in the hash table, or NULL if no more. Do not modify
+ * hash table while this is being used. (see note in code if you want to fix
+ * this) */
+
+void *hashNextVal(struct hashCookie *cookie);
+/* Return the next value in the hash table, or NULL if no more. Do not modify
+ * hash table while this is being used. */
+
+char *hashNextName(struct hashCookie *cookie);
+/* Return the next name in the hash table, or NULL if no more. Do not modify
+ * hash table while this is being used. */
+
+struct hash *newHashExt(int powerOfTwoSize, boolean useLocalMem);
+/* Returns new hash table. Uses local memory optionally. */
+#define hashNewExt(a) newHashExt(a)	/* Synonym */
+
+#define newHash(a) newHashExt(a, TRUE)
+/* Returns new hash table using local memory. */
+#define hashNew(a) newHash(a)	/* Synonym */
+
+void hashResize(struct hash *hash, int powerOfTwoSize);
+/* Resize the hash to a new size */
+
+struct hash *hashFromSlNameList(void *list);
+/* Create a hash out of a list of slNames or any kind of list where the */
+/* first field is the next pointer and the second is the name. */
+
+void freeHash(struct hash **pHash);
+/* Free up hash table. */
+#define hashFree(a) freeHash(a)	/* Synonym */
+
+void freeHashAndVals(struct hash **pHash);
+/* Free up hash table and all values associated with it.
+ * (Just calls freeMem on each hel->val) */
+
+void hashFreeWithVals(struct hash **pHash, void (freeFunc)());
+/* Free up hash table and all values associated with it. freeFunc is a
+ * function to free an entry, should take a pointer to a pointer to an
+ * entry. */
+
+void hashFreeList(struct hash **pList);
+/* Free up a list of hashes. */
+
+void hashHisto(struct hash *hash, char *fname);
+/* Output bucket usage counts to a file for producing a histogram  */
+
+void hashPrintStats(struct hash *hash, char *label, FILE *fh);
+/* print statistic about a hash table */
+
+struct hashEl *hashReplace(struct hash *hash, char *name, void *val);
+/* Replace an existing element in hash table, or add it if not present. */
+
+boolean hashMayRemove(struct hash *hash, char *name);
+/* Remove item of the given name from hash table, if present.
+ * Return true if it was present */
+
+void hashMustRemove(struct hash *hash, char *name);
+/* Remove item of the given name from hash table, or error
+ * if not present */
+
+char *hashToRaString(struct hash *hash);
+/* Convert hash to string in ra format. */
+
+int hashNumEntries(struct hash *hash);
+/* count the number of entries in a hash */
+
+#endif /* HASH_H */
+
diff --git a/inc/hgGene.h b/inc/hgGene.h
new file mode 100644
index 0000000..ba9752b
--- /dev/null
+++ b/inc/hgGene.h
@@ -0,0 +1,129 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* hgGene.h was originally generated by the autoSql program, which also 
+ * generated hgGene.c and hgGene.sql.  This header links the database and the RAM 
+ * representation of objects. */
+
+struct geneFinder
+/* A gene finding program. */
+    {
+    struct geneFinder *next;  /* Next in singly linked list. */
+    unsigned id;	/* Unique ID */
+    char *name;	/* Name of gene finder */
+    };
+
+void geneFinderStaticLoad(char **row, struct geneFinder *ret);
+/* Load a row from geneFinder table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+
+struct geneFinder *geneFinderLoad(char **row);
+/* Load a geneFinder from row fetched with select * from geneFinder
+ * from database.  Dispose of this with geneFinderFree(). */
+
+struct geneFinder *geneFinderCommaIn(char **pS);
+/* Create a geneFinder out of a comma separated string. */
+
+void geneFinderFree(struct geneFinder **pEl);
+/* Free a single dynamically allocated geneFinder such as created
+ * with geneFinderLoad(). */
+
+void geneFinderFreeList(struct geneFinder **pList);
+/* Free a list of dynamically allocated geneFinder's */
+
+void geneFinderOutput(struct geneFinder *el, FILE *f, char sep, char lastSep);
+/* Print out geneFinder.  Separate fields with sep. Follow last field with lastSep. */
+
+#define geneFinderTabOut(el,f) geneFinderOutput(el,f,'\t','\n');
+/* Print out geneFinder as a line in a tab-separated file. */
+
+#define geneFinderCommaOut(el,f) geneFinderOutput(el,f,',',',');
+/* Print out geneFinder as a comma separated list including final comma. */
+
+struct hgGene
+/* A gene prediction */
+    {
+    struct hgGene *next;  /* Next in singly linked list. */
+    unsigned id;	/* Unique ID */
+    char *name;	/* Name of gene */
+    unsigned geneFinder;	/* Program that made prediction */
+    unsigned startBac;	/* Bac this starts in */
+    unsigned startPos;	/* Position within bac where starts */
+    unsigned endBac;	/* Bac this ends in */
+    unsigned endPos;	/* Position withing bac where ends */
+    signed char orientation;	/* Orientation relative to start bac */
+    unsigned transcriptCount;	/* Number of transcripts */
+    unsigned *transcripts;	/* Array of transcripts */
+    };
+
+struct hgGene *hgGeneLoad(char **row);
+/* Load a hgGene from row fetched with select * from hgGene
+ * from database.  Dispose of this with hgGeneFree(). */
+
+struct hgGene *hgGeneCommaIn(char **pS);
+/* Create a hgGene out of a comma separated string. */
+
+void hgGeneFree(struct hgGene **pEl);
+/* Free a single dynamically allocated hgGene such as created
+ * with hgGeneLoad(). */
+
+void hgGeneFreeList(struct hgGene **pList);
+/* Free a list of dynamically allocated hgGene's */
+
+void hgGeneOutput(struct hgGene *el, FILE *f, char sep, char lastSep);
+/* Print out hgGene.  Separate fields with sep. Follow last field with lastSep. */
+
+#define hgGeneTabOut(el,f) hgGeneOutput(el,f,'\t','\n');
+/* Print out hgGene as a line in a tab-separated file. */
+
+#define hgGeneCommaOut(el,f) hgGeneOutput(el,f,',',',');
+/* Print out hgGene as a comma separated list including final comma. */
+
+struct hgTranscript
+/* A transcript prediction */
+    {
+    struct hgTranscript *next;  /* Next in singly linked list. */
+    unsigned id;	/* Unique ID */
+    char *name;	/* Name of transcript */
+    unsigned hgGene;	/* Gene this is in */
+    unsigned startBac;	/* Bac this starts in */
+    unsigned startPos;	/* Position within bac where starts */
+    unsigned endBac;	/* Bac this ends in */
+    unsigned endPos;	/* Position withing bac where ends */
+    unsigned cdsStartBac;	/* Start of coding region. */
+    unsigned cdsStartPos;	/* Start of coding region. */
+    unsigned cdsEndBac;	/* End of coding region. */
+    unsigned cdsEndPos;	/* End of coding region. */
+    signed char orientation;	/* Orientation relative to start bac */
+    unsigned exonCount;	/* Number of exons */
+    unsigned *exonStartBacs;	/* Exon start positions */
+    unsigned *exonStartPos;	/* Exon start positions */
+    unsigned *exonEndBacs;	/* Exon start positions */
+    unsigned *exonEndPos;	/* Exon start positions */
+    };
+
+struct hgTranscript *hgTranscriptLoad(char **row);
+/* Load a hgTranscript from row fetched with select * from hgTranscript
+ * from database.  Dispose of this with hgTranscriptFree(). */
+
+struct hgTranscript *hgTranscriptCommaIn(char **pS);
+/* Create a hgTranscript out of a comma separated string. */
+
+void hgTranscriptFree(struct hgTranscript **pEl);
+/* Free a single dynamically allocated hgTranscript such as created
+ * with hgTranscriptLoad(). */
+
+void hgTranscriptFreeList(struct hgTranscript **pList);
+/* Free a list of dynamically allocated hgTranscript's */
+
+void hgTranscriptOutput(struct hgTranscript *el, FILE *f, char sep, char lastSep);
+/* Print out hgTranscript.  Separate fields with sep. Follow last field with lastSep. */
+
+#define hgTranscriptTabOut(el,f) hgTranscriptOutput(el,f,'\t','\n');
+/* Print out hgTranscript as a line in a tab-separated file. */
+
+#define hgTranscriptCommaOut(el,f) hgTranscriptOutput(el,f,',',',');
+/* Print out hgTranscript as a comma separated list including final comma. */
+
diff --git a/inc/hgap.h b/inc/hgap.h
new file mode 100644
index 0000000..4af14b7
--- /dev/null
+++ b/inc/hgap.h
@@ -0,0 +1,233 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* HGAP - Human Genome Annotation Project database. */
+#ifndef HGAP_H
+#define HGAP_H
+
+#ifndef DNASEQ_H
+#include "dnaseq.h"
+#endif 
+
+#ifndef UNFIN_H
+#include "unfin.h"
+#endif
+
+#ifndef JKSQL_H
+#include "jksql.h"
+#endif
+
+typedef unsigned int HGID;	/* A database ID. */
+
+void hgSetDb(char *dbName);
+/* Set the database name. */
+
+char *hgGetDb();
+/* Return the current database name. */
+
+struct sqlConnection *hgAllocConn();
+/* Get free connection if possible. If not allocate a new one. */
+
+struct sqlConnection *hgFreeConn(struct sqlConnection **pConn);
+/* Put back connection for reuse. */
+
+
+HGID hgIdQuery(struct sqlConnection *conn, char *query);
+/* Return first field of first table as HGID. 0 return ok. */
+
+HGID hgRealIdQuery(struct sqlConnection *conn, char *query);
+/* Return first field of first table as HGID- abort if 0. */
+
+
+struct sqlConnection *hgStartUpdate();
+/* Get a connection for an update.  (Starts allocating id's) */
+
+void hgEndUpdate(struct sqlConnection **pConn, char *comment, ...);
+/* Finish up connection with a printf format comment. */
+
+HGID hgNextId();
+/* Get next unique id.  (Should only be called after hgStartUpdate). */
+
+FILE *hgCreateTabFile(char *tableName);
+/* Open a tab file with name corresponding to tableName.  This
+ * may just be fclosed when done. (Currently just makes
+ * tableName.tab in the current directory.) */
+
+void hgLoadTabFile(struct sqlConnection *conn, char *tableName);
+/* Load tab delimited file corresponding to tableName. 
+ * Should only be used after hgCreatTabFile, and only after
+ * file closed. */
+
+
+enum 
+/* Various constants used. */
+    {
+    hgContigPad = 800,	  /* Number of N's between contigs. */
+    };
+
+struct hgBac
+/* This represents a sequenced clone (BAC/PAC/cosmid) */
+    {
+    struct hgBac *next;	      /* Next in list. */
+    struct hgNest *nest;      /* Coordinate space. */
+    HGID id;		      /* HGAP ID. */
+    char name[16];            /* GenBank accession. */
+    int contigCount;          /* Number of contigs. */
+    struct hgContig *contigs; /* Contig list. */
+    };
+
+struct hgContig
+/* This represents a contig within a BAC. */
+    {
+    struct hgContig *next;    /* Next in list. */
+    struct hgNest *nest;      /* Coordinate space. */
+    HGID id;		      /* HGAP ID. */
+    char name[20];            /* Name like AC000007.24 */
+    struct hgBac *bac;        /* Bac this is in. */
+    int ix;                   /* Contig index. */
+    int submitOffset;         /* Position in genBank submission. */
+    int size;                 /* Size in bases. */
+    };
+
+struct hgNest
+/* This structure describes the contig tree
+ * chromosomes->chromosome contigs->bacs->
+ * bac contigs.  */
+    {
+    struct hgNest *next;	/* Pointer to next sibling. */
+    struct hgNest *children;	/* Children. */
+    struct hgNest *parent;      /* Parent if any. */
+    HGID id;		        /* HGAP ID. */
+    int orientation;            /* +1 or -1 relative to parent. */
+    int offset;			/* Offset relative to parent. */
+    int size;                   /* Size in bases. */
+    struct hgContig *contig;    /* Associated contig if any. */
+    };
+
+struct hgBac *hgGetBac(char *acc);
+/* Load BAC with given accession into memory. Don't free this, it's
+ * managed by system. */
+
+struct hgContig *hgGetContig(char *acc, int contigIx);
+/* Get contig.  contigIx is position in submission, not position in
+ * ordering. */
+
+struct dnaSeq *hgContigSeq(struct hgContig *contig);
+/* Return DNA associated with contig. */
+
+struct dnaSeq *hgRnaSeq(char *acc);
+/* Return sequence for RNA. */
+
+void hgRnaSeqAndId(char *acc, struct dnaSeq **retSeq, HGID *retId);
+/* Return sequence for RNA and it's database ID. */
+
+struct dnaSeq *hgBacOrderedSeq(struct hgBac *bac);
+/* Return DNA associated with BAC including NNN's between
+ * contigs in ordered coordinates. */
+
+struct dnaSeq *hgBacSubmittedSeq(char *acc);
+/* Returns DNA associated with BAC in submitted ordering
+ * and coordinates. */
+
+struct dnaSeq *hgBacContigSeq(char *acc);
+/* Returns list of sequences, one for each contig in BAC. */
+
+int hgOffset(struct hgNest *source, int offset, struct hgNest *dest);
+/* Translate offset from source to destination coordinate space.
+ * Destination has to be an ancestor (or the same) as source. */
+
+/* The following is a series of nested structures for
+ * describing a range of DNA. The later structures include
+ * the first fields of the earlier ones.  Routines that
+ * work on the earlier structures will also work on
+ * the later.  This is a crude but effective form of single 
+ * inheritance. */
+
+struct hgRange
+/* Just start/end locations somewhere... */
+    {
+    struct hgRange *next; /* Next in list. */
+    int tStart, tEnd;	  /* Position in target or only sequence tStart <= x < tEnd */
+    };
+
+int hgCmpTStart(const void *va, const void *vb);
+/* Compare function to sort by tStart, then by tEnd. */
+
+struct hgHit
+/* A simple hit - an interesting range of a sequence. */
+    {
+    struct hgHit *next;   /* Next in list. */
+    int tStart, tEnd;	  /* Position in target or only sequence tStart <= x < tEnd */
+    int tOrientation;	  /* +1 or -1 orientation. */
+    char *target;	  /* Name of target seq. (Not allocated here.) */
+    };
+
+int hgCmpTarget(const void *va, const void *vb);
+/* Compare function to sort by target, orientaation, tStart, then tEnd. */
+
+struct hgScoredHit
+/* A hit with a log odds score. */
+    {
+    struct hgScoredHit *next;
+    int tStart, tEnd;	  /* Position in target or only sequence tStart <= x < tEnd */
+    int tOrientation;	  /* +1 or -1 orientation. */
+    char *target;	  /* Name of target seq. (Not allocated here.) */
+    int logOdds;          /* Log odds style score - scaled x 1000. */
+    };
+
+int hgCmpScore(const void *va, const void *vb);
+/* Compare function to sort logOdds score. */
+
+struct hgAliHit
+/* A hit representing an alignment between two sequences without inserts. */
+    {
+    struct hgAliHit *next;
+    int tStart, tEnd;	  /* Position in target or only sequence tStart <= x < tEnd */
+    int tOrientation;	  /* +1 or -1 orientation. */
+    char *target;	  /* Name of target seq. (Not allocated here.) */
+    int logOdds;          /* Log odds style score - scaled x 1000. */
+    int qStart, qEnd;     /* Position in query sequence. */
+    int qOrientation;	  /* +1 or -1 query orientation. */
+    char *query;	  /* Name of query seq. (Not allocated here.) */
+    };
+
+int hgCmpQStart(const void *va, const void *vb);
+/* Compare function to sort by qStart, then by qEnd. */
+
+int hgCmpQuery(const void *va, const void *vb);
+/* Compare function to sort by query, orientation, qStart, then qEnd. */
+
+struct hgBoundedHit
+/* An alignment hit that can have soft or hard edges. */
+    {
+    struct hgBoundedHit *next;
+    int tStart, tEnd;	  /* Position in target or only sequence tStart <= x < tEnd */
+    int tOrientation;	  /* +1 or -1 orientation. */
+    char *target;	  /* Name of target seq. (Not allocated here.) */
+    int logOdds;          /* Log odds style score - scaled x 1000. */
+    int qStart, qEnd;     /* Position in query sequence. */
+    int qOrientation;	  /* +1 or -1 query orientation. */
+    char *query;	  /* Name of query seq. (Not allocated here.) */
+    bool hardStart;       /* Start position known */
+    bool hardEnd;         /* End position known */
+    };
+
+struct hgAlignment
+/* An alignment with gaps. */
+    {
+    struct hgAlignment *next;
+    int tStart, tEnd;	  /* Position in target or only sequence tStart <= x < tEnd */
+    int tOrientation;	  /* +1 or -1 orientation. */
+    char *target;	  /* Name of target seq. (Not allocated here.) */
+    int logOdds;          /* Log odds style score - scaled x 1000. */
+    int qStart, qEnd;     /* Position in query sequence. */
+    int qOrientation;     /* +1 or -1 orientation. */
+    bool hardStart;       /* Start position known */
+    bool hardEnd;         /* End position known */
+    struct hgBoundedHit *hitList;  /*  Subalignments. */
+    };
+
+#endif /* HGAP_H */
+
diff --git a/inc/hgdb.h b/inc/hgdb.h
new file mode 100644
index 0000000..8df0d28
--- /dev/null
+++ b/inc/hgdb.h
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* hgdb - Stuff to access human genome database. */
+#ifndef HGDB_H
+#define HGDB_H
+
+char *hgdbRootDir();
+/* Return root directory of human genome database. */
+
+struct dnaSeq *hgdbRnaSeq(char *accession);
+/* Return mRNA or EST sequence from an accession number. */
+
+struct fof *hgdbRnaFof();
+/* Return index for RNA sequences. */
+
+struct dnaSeq *hgdbShortSeq(char *accession);
+/* Return mRNA, EST, BACend or STS sequence based on
+ * accession number. */
+
+struct fof *hgdbShortFof();
+/* Return index for short sequences. */
+
+struct dnaSeq *hgdbFinishedSeq(char *accession);
+/* Return finished BAC sequence. */
+
+struct dnaSeq *hgdbUnfinishedSeq(char *accession);
+/* Return unfinished BAC sequence. May be in 
+ * several contigs (dnaSeq returned may be a list.) */
+
+struct dnaSeq *hgdbGetSeq(char *accession);
+/* Return sequence from any source. */
+
+char *hgdbKeyText(char *accession);
+/* Get key-value lines about accession number. */
+
+struct fof *hgdbKeyFof();
+/* Return index for key-values indexed by accession. */
+
+boolean hgdbSmallKey(char *accession, char *key, char *valBuf, int valBufSize);
+/* Get value of small key.  Returns FALSE if key doesn't exist. */
+
+#endif /* HGDB_H */
+
diff --git a/inc/histogram.h b/inc/histogram.h
new file mode 100644
index 0000000..2aff1bc
--- /dev/null
+++ b/inc/histogram.h
@@ -0,0 +1,26 @@
+/* histogram function for data array in memory	*/
+
+#if !defined(HISTOGRAM_H)
+#define HISTOGRAM_H
+
+#define	DEFAULT_BIN_COUNT	26
+/*	ARBITRARY default choice of # of bins	*/
+
+struct histoResult {
+    struct histoResult *next;	/*	might be a list of them	*/
+    float binSize;		/*	size of a bin	*/
+    unsigned binCount;		/*	number of bins	*/
+    unsigned count;		/*	number of values	*/
+    float binZero;		/*	bin 0 starts at this value	*/
+    unsigned *binCounts;	/*	array binCounts[binCount]	*/
+    float *pValues;		/*	array pValues[binCount]		*/
+};
+
+void freeHistoGram(struct histoResult **histoResults);
+/*      free the histoResults list	*/
+
+struct histoResult *histoGram(float *values, size_t N, float binSize,
+	unsigned binCount, float minValue, float min, float max,
+	struct histoResult *accumHisto);
+/*	construct histogram of data in values[N] array.	*/
+#endif
diff --git a/inc/hmmPfamParse.h b/inc/hmmPfamParse.h
new file mode 100644
index 0000000..f9c6c9d
--- /dev/null
+++ b/inc/hmmPfamParse.h
@@ -0,0 +1,55 @@
+/* hmmpfamParse - Parse hmmpfam files.. */
+
+#ifndef HMMPFAMPARSE_H
+#define HMMPFAMPARSE_H
+
+struct hpfDomain
+/* Describes amino acids covered by one use of model. */
+    {
+    struct hpfDomain *next;
+    int qStart, qEnd;	/* Where this is in query sequence. */
+    int hmmStart, hmmEnd; /* Where this is in profile HMM. */
+    double score;	/* Some sort of bit score. */
+    double eVal;	/* Expectation value. */
+    };
+
+struct hpfModel 
+/* Results for a single model for a single query */
+    {
+    struct hpfModel *next;
+    char *name;	/* Model name */
+    char *description; /* Longer description */
+    double score;	/* Some sort of bit score. */
+    double eVal;	/* Expectation value. */
+    struct hpfDomain *domainList;	/* All places model occurs in query */
+    };
+
+void hpfModelFree(struct hpfModel **pMod);
+/* Free memory associated with hpfModel */
+
+void hpfModelFreeList (struct hpfModel **pList);
+/* Free memory associated with list of hpfModels.  */
+
+struct hpfResult
+/* Result for a single query sequence. */
+    {
+    struct hpfResult *next;
+    char *name;	/* Query sequence name. */
+    struct hpfModel *modelList;  /* All models that hit query */
+    };
+
+void hpfResultFree(struct hpfResult **pHr);
+/* Free memory associated with hpfResult */
+
+void hpfResultFreeList(struct hpfResult **pList);
+/* Free memory associated with list of hpfResults. */
+
+
+struct hpfModel *hpfFindResultInModel(struct hpfResult *hr, char *modName);
+/* Look for named result in model. */
+
+struct hpfResult *hpfNext(struct lineFile *lf);
+/* Parse out next record in hmmpfam result file. */
+
+
+#endif /* HMMPFAMPARSE_H */
diff --git a/inc/hmmstats.h b/inc/hmmstats.h
new file mode 100644
index 0000000..7db9bde
--- /dev/null
+++ b/inc/hmmstats.h
@@ -0,0 +1,30 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* hmmstats.h - Stuff for doing statistical analysis in general and 
+ * hidden Markov models in particular. */
+#ifndef HMMSTATS_H
+#define HMMSTATS_H
+
+int scaledLog(double val);
+/* Return scaled log of val. */
+
+#define logScaleFactor 1000
+/* Amount we scale logs by. */
+
+double simpleGaussean(double x);
+/* Gaussean distribution with standard deviation 1 and mean 0. */
+
+double gaussean(double x, double mean, double sd);
+/* Gaussean distribution with mean and standard deviation at point x  */
+
+double calcVarianceFromSums(double sum, double sumSquares, bits64 n);
+/* Calculate variance. */
+
+double calcStdFromSums(double sum, double sumSquares, bits64 n);
+/* Calculate standard deviation. */
+
+#endif /* HMMSTATS_H */
+
diff --git a/inc/htmlPage.h b/inc/htmlPage.h
new file mode 100644
index 0000000..a5f74b8
--- /dev/null
+++ b/inc/htmlPage.h
@@ -0,0 +1,239 @@
+/* htmlPage - stuff to read, parse, and submit  htmlPages and forms. 
+ *
+ * typical usage is:
+ *   struct htmlPage *page = htmlPageGet(url);
+ *   htmlPageValidateOrAbort(page);
+ *   var = htmlPageGetVar(page, page->forms, "org");
+ *   if (var != NULL)
+ *      printf("Organism = %s\n", var->curVal);
+ *   htmlPageSetVar(page, page->forms, "org", "Human");
+ *   newPage = htmlPageFromForm(page, page->forms, "submit", "Go");
+ */
+
+#ifndef HTMLPAGE_H
+#define HTMLPAGE_H
+
+#ifndef DYSTRING_H
+#include "dystring.h"
+#endif
+
+struct htmlStatus
+/* HTTP version and status code. */
+    {
+    struct htmlStatus *next;	/* Next in list. */
+    char *version;		/* Usually something like HTTP/1.1 */
+    int status;			/* HTTP status code.  200 is good. */
+    };
+
+struct htmlCookie
+/* A cookie - stored by browser usually.  We need to echo it
+ * back when we post forms. */
+    {
+    struct htmlCookie *next;	/* Next in list. */
+    char *name;			/* Cookie name. */
+    char *value;		/* Cookie value. */
+    char *domain;		/* The set of web domains this applies to. */
+    char *path;			/* Cookie applies below this path I guess. */
+    char *expires;		/* Expiration date. */
+    boolean secure;		/* Is it a secure cookie? */
+    };
+
+struct htmlAttribute
+/* An html attribute - part of a set of name/values pairs in a tag. */
+    {
+    struct htmlAttribute *next;
+    char *name;		/* Attribute name. */
+    char *val;		/* Attribute value. */
+    };
+
+struct htmlTag
+/* A html tag - includes attribute list and parent, but no text. */
+    {
+    struct htmlTag *next;
+    char *name;	/* Tag name. */
+    struct htmlAttribute *attributes;  /* Attribute list. */
+    char *start;  /* Start of this tag.  Not allocated here.*/
+    char *end;	  /* End of tag (one past closing '>')  Not allocated here.*/
+    };
+
+struct htmlFormVar
+/* A variable within an html form - from input, button, etc. */
+    {
+    struct htmlFormVar *next;	/* Next in list. */
+    char *name;			/* Variable name.  Not allocated here.*/
+    char *tagName;		/* Name of tag.  Not allocated here. */
+    char *type;			/* Variable type. Not allocated here. */
+    char *curVal;		/* Current value if any.  Allocated here. */
+    struct slName *values;	/* List of available values.  Null if textBox. */
+    struct slRef *tags;	        /* List of references associated tags. */
+    };
+
+struct htmlForm
+/* A form within an html page. */
+    {
+    struct htmlForm *next;	/* Next form in list. */
+    char *name;			/* Name (n/a if not defined).  Not allocated here. */
+    char *action;		/* Action attribute value.  Not allocated here. */
+    char *method;		/* Defaults to "GET". Not allocated here.  */
+    struct htmlTag *startTag;	/* Tag that holds <FORM>. Not allocated here.  */
+    struct htmlTag *endTag;	/* Tag one past </FORM> . Not allocated here. */
+    struct htmlFormVar *vars; /* List of form variables. */
+    };
+
+struct htmlPage
+/* A complete html page parsed out. */
+    {
+    struct htmlPage *next;
+    char *url;				/* Url that produced this page. */
+    struct htmlStatus *status;		/* Version and status. */
+    struct hash *header;		/* Hash of header lines (cookies, etc.) */
+    struct htmlCookie *cookies;		/* Associated cookies if any. */
+    char *fullText;			/* Full unparsed text including headers. */
+    char *htmlText;			/* Text unparsed after header.  Same mem as fullText. */
+    struct htmlTag *tags;		/* List of tags in this page. */
+    struct htmlForm *forms;		/* List of all forms. */
+    };
+
+void htmlStatusFree(struct htmlStatus **pStatus);
+/* Free up resources associated with status */
+
+void htmlStatusFreeList(struct htmlStatus **pList);
+/* Free a list of dynamically allocated htmlStatus's */
+
+struct htmlStatus *htmlStatusParse(char **pText);
+/* Read in status from first line.  Update pText to point to next line. 
+ * Note unlike many routines here, this does not insert zeros into text. */
+
+void htmlCookieFree(struct htmlCookie **pCookie);
+/* Free memory associated with cookie. */
+
+void htmlCookieFreeList(struct htmlCookie **pList);
+/* Free a list of dynamically allocated htmlCookie's */
+
+struct htmlCookie *htmlCookieFileRead(char *fileName);
+/* Read cookies from a line oriented file.  First word in line
+ * is the cookie name, the rest of the line the cookie value. */
+
+void htmlAttributeFree(struct htmlAttribute **pAttribute);
+/* Free up resources associated with attribute. */
+
+void htmlAttributeFreeList(struct htmlAttribute **pList);
+/* Free a list of dynamically allocated htmlAttribute's */
+
+char *htmlTagAttributeVal(struct htmlPage *page, struct htmlTag *tag, 
+	char *name, char *defaultVal);
+/* Return value of named attribute, or defaultVal if attribute doesn't exist. */
+
+char *htmlTagAttributeNeeded(struct htmlPage *page, struct htmlTag *tag, char *name);
+/* Return named tag attribute.  Complain and return "n/a" if it
+ * doesn't exist. */
+
+void htmlTagFree(struct htmlTag **pTag);
+/* Free up resources associated with tag. */
+
+void htmlTagFreeList(struct htmlTag **pList);
+/* Free a list of dynamically allocated htmlTag's */
+
+void htmlFormVarFree(struct htmlFormVar **pVar);
+/* Free up resources associated with form variable. */
+
+void htmlFormVarFreeList(struct htmlFormVar **pList);
+/* Free a list of dynamically allocated htmlFormVar's */
+
+void htmlFormVarPrint(struct htmlFormVar *var, FILE *f, char *prefix);
+/* Print out variable to file, prepending prefix. */
+
+void htmlFormFree(struct htmlForm **pForm);
+/* Free up resources associated with form variable. */
+
+void htmlFormFreeList(struct htmlForm **pList);
+/* Free a list of dynamically allocated htmlForm's */
+
+void htmlFormPrint(struct htmlForm *form, FILE *f);
+/* Print out form structure. */
+
+char *htmlFormCgiVars(struct htmlPage *page, struct htmlForm *form, 
+	char *buttonName, char *buttonVal, struct dyString *dyHeader);
+/* Return cgi vars in name=val format from use having pressed
+ * submit button of given name and value. */
+
+struct htmlForm *htmlFormGet(struct htmlPage *page, char *name);
+/* Get named form. */
+
+struct htmlFormVar *htmlFormVarGet(struct htmlForm *form, char *name);
+/* Get named variable. */
+
+void htmlFormVarSet(struct htmlForm *form, char *name, char *val);
+/* Set variable to given value.  */
+
+struct htmlFormVar *htmlPageGetVar(struct htmlPage *page, struct htmlForm *form, char *name);
+/* Get named variable.  If form is NULL, first form in page is used. */
+
+void htmlPageSetVar(struct htmlPage *page, struct htmlForm *form, char *name, char *val);
+/* Set variable to given value.  If form is NULL, first form in page is used. */
+
+void htmlPageFree(struct htmlPage **pPage);
+/* Free up resources associated with htmlPage. */
+
+void htmlPageFreeList(struct htmlPage **pList);
+/* Free a list of dynamically allocated htmlPage's */
+
+char *htmlExpandUrl(char *base, char *url);
+/* Expand URL that is relative to base to stand on it's own. 
+ * Return NULL if it's not http or https. */
+
+char *htmlNextCrLfLine(char **pS);
+/* Return zero-terminated line and advance *pS to start of
+ * next line.  Return NULL at end of file.  Warn if there is
+ * no <CR>. */
+
+struct slName *htmlPageScanAttribute(struct htmlPage *page, 
+	char *tagName, char *attribute);
+/* Scan page for values of particular attribute in particular tag.
+ * if tag is NULL then scans in all tags. */
+
+struct slName *htmlPageLinks(struct htmlPage *page);
+/* Scan through tags list and pull out HREF attributes. */
+
+void htmlPageFormOrAbort(struct htmlPage *page);
+/* Aborts if no FORM found */
+
+void htmlPageValidateOrAbort(struct htmlPage *page);
+/* Do some basic validations.  Aborts if there is a problem. */
+
+char *htmlSlurpWithCookies(char *url, struct htmlCookie *cookies);
+/* Send get message to url with cookies, and return full response as
+ * a dyString.  This is not parsed or validated, and includes http
+ * header lines.  Typically you'd pass this to htmlPageParse() to
+ * get an actual page. */
+
+struct htmlPage *htmlPageParse(char *url, char *fullText);
+/* Parse out page and return.  Warn and return NULL if problem. */
+
+struct htmlPage *htmlPageParseOk(char *url, char *fullText);
+/* Parse out page and return only if status ok. */
+
+struct htmlPage *htmlPageParseNoHead(char *url, char *htmlText);
+/* Parse out page in memory (past http header if any) and return. */
+
+struct htmlPage *htmlPageFromForm(struct htmlPage *origPage, struct htmlForm *form, 
+	char *buttonName, char *buttonVal);
+/* Return a new htmlPage based on response to pressing indicated button
+ * on indicated form in origPage. */
+
+struct htmlPage *htmlPageGetWithCookies(char *url, struct htmlCookie *cookies);
+/* Get page from URL giving server the given cookies.   Note only the
+ * name and value parts of the cookies need to be filled in. */
+
+struct htmlPage *htmlPageGet(char *url);
+/* Get page from URL (may be a file). */
+
+struct htmlPage *htmlPageForwarded(char *url, struct htmlCookie *cookies);
+/* Get html page.  If it's just a forwarding link then get do the
+ * forwarding.  Cookies is a possibly empty list of cookies with
+ * name and value parts filled in. */
+
+struct htmlPage *htmlPageForwardedNoAbort(char *url, struct htmlCookie *cookies);
+/* Try and get an HTML page.  Print warning and return NULL if there's a problem. */
+#endif /* HTMLPAGE_H */
+
diff --git a/inc/htmshell.h b/inc/htmshell.h
new file mode 100644
index 0000000..96e4422
--- /dev/null
+++ b/inc/htmshell.h
@@ -0,0 +1,180 @@
+/* Htmshell.h - stuff to make it easier to generate HTML files on
+ * the fly.  Typically included with cheapcgi.h in almost any
+ * CGI program.
+ *
+ * To use this generally you should call the function htmShell()
+ * very early inside of main().  You pass htmShell() a routine
+ * which does most of the work of your web server-side applet.
+ *
+ * These routines will throw errors, which are caught by
+ * htmShell, which then returns.  For the most part you just
+ * want an error to cause an error message to be printed and
+ * then terminate your CGI program, so this works fine.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+void htmlSetCookie(char* name, char* value, char* expires, char* path, char* domain, boolean isSecure);
+/* create a cookie with the given stats */
+
+void htmlParagraph(char *line, ...);
+/* Print a line in it's own paragraph. */
+
+void htmlVaParagraph(char *line, va_list args);
+/* Print a line in it's own paragraph. */
+
+void htmlCenterParagraph(char *line, ...);
+/* Center a line in it's own paragraph. */
+
+void htmlHorizontalLine();
+/* Print a horizontal line. */
+
+void htmlNbSpaces(int count);
+/* Print a number of non-breaking spaces. */
+
+void htmHorizontalLine(FILE *f);
+/* Print a horizontal line. */
+
+void htmTextOut(FILE *f, char *s);
+/* Print out string to file, if necessary replacing > with > and the like */
+
+void htmlTextOut(char *s);
+/* Print out string, if necessary replacing > with > and the like */
+
+char *htmlTextStripTags(char *s);
+/* Returns a cloned string with all html tags stripped out */
+
+char *htmlTextReplaceTagsWithChar(char *s, char ch);
+/* Returns a cloned string with all html tags replaced with given char (useful for tokenizing) */
+
+char *htmlEncodeText(char *s, boolean tagsOkay);
+/* Returns a cloned string with quotes replaced by html codes.
+   Changes ',",\n and if not tagsOkay >,<,& to code equivalents.
+   This differs from cgiEncode as it handles text that will
+   be displayed in an html page or tooltip style title.  */
+#define htmlEncode(s) htmlEncodeText(s,FALSE)
+
+char *attributeEncode(char *str);
+// encode double and single quotes in a string to be used as an element attribute
+
+void htmlMemDeath();
+/* Complain about lack of memory and abort.  */
+
+void htmlStart(char *title);
+/* Write the start of a cgi-generated html file */
+
+void htmStart(FILE *f, char *title);
+/* Write the start of a stand alone .html file. */
+
+void printBodyTag(FILE *f);
+// print starting BODY tag, including any appropriate attributes (class, background and bgcolor). 
+
+void htmStartWithHead(FILE *f, char *head, char *title);
+/* Write the start of a stand alone .html file, plus head info */
+
+void htmStartDirDepth(FILE *f, char *title, int dirDepth);
+/* Write the start of a stand alone .html file.  dirDepth is the number of levels
+ * beneath apache root that caller's HTML will appear to the web client.
+ * E.g. if writing HTML from cgi-bin, dirDepth is 1; if trash/body/, 2. */
+
+void htmlEnd();
+/* Write the end of a cgi-generated html file */
+
+void htmEnd(FILE *f);
+/* Write the end of a stand-alone html file */
+
+extern char *htmlStyleUndecoratedLink;
+/* Style that gets rid of underline of links. */
+
+void htmlSetStyle(char *style);
+/* Set document wide style. A favorite style to
+ * use for many purposes is htmlStyleUndecoratedLink
+ * which will remove underlines from links.
+ * Needs to be called before htmlStart or htmShell. */
+
+void htmlSetStyleSheet(char *styleSheet);
+/* Set document wide style sheet by adding css name to HEAD part.
+ * Needs to be called before htmlStart or htmShell. */
+
+void htmlSetFormClass(char *formClass);
+/* Set class in the BODY part. */
+
+
+void htmlSetStyleTheme(char *style);
+/* Set theme style, these styles can overwrite document wide styles.
+ * Needs to be called before htmlStart or htmShell. */
+
+void htmlSetBackground(char *imageFile);
+/* Set background image - needs to be called before htmlStart
+ * or htmShell. */
+
+void htmlSetBgColor(int color);
+/* Set background color - needs to be called before htmlStart
+ * or htmShell. */
+
+void htmlBadVar(char *varName);
+/* Complain about input variables. */
+
+void htmlImage(char *fileName, int width, int height);
+/* Display centered image file. */
+
+jmp_buf htmlRecover;  /* Error recovery jump. Exposed for cart's use. */
+
+void htmlVaWarn(char *format, va_list args);
+/* Write an error message.  (Generally you just call warn() or errAbort().
+ * This is exposed mostly for the benefit of the cart.) */
+
+char *htmlWarnStartPattern();
+/* Return starting pattern for warning message. */
+
+char *htmlWarnEndPattern();
+/* Return ending pattern for warning message. */
+
+void htmlWarnBoxSetup(FILE *f);
+/* Creates an invisible, empty warning box than can be filled with errors
+ * and then made visible. */
+
+void htmlAbort();
+/* Terminate HTML file.  Exposed for cart's use. */
+
+void htmlPushEarlyHandlers();
+/* Push stuff to close out web page to make sensible error
+ * message during initialization. */
+
+/* Wrap error recovery around call to doMiddle. */
+void htmErrOnlyShell(void (*doMiddle)());
+
+/* Wrap error recovery and and input processing around call to doMiddle. */
+void htmEmptyShell(void (*doMiddle)(), char *method);
+
+/* Wrap an html file around the passed in function.
+ * The passed in function is already in the body. It
+ * should just make paragraphs and return.
+ * Method should be "query" or "get" or "post" (or NULL
+ * if you don't care)..
+ */
+void htmShell( char *title, void (*doMiddle)(), char *method);
+
+/* Wrap an html file around the passed in function.
+ * The passed in function is already in the body. It
+ * should just make paragraphs and return.
+ * Method should be "query" or "get" or "post".
+param title - The HTML page title
+param head - The head text: can be a refresh directive or javascript
+param method - The function pointer to execute in the middle
+param method - The browser request method to use
+ */
+void htmShellWithHead( char *title, char *head, void (*doMiddle)(), char *method);
+
+/* tell htmlOut to not escape special HTML chars '<', '>' */
+void htmlNoEscape();
+
+/* tell htmlOut to escape special HTML chars '<', '>' */
+void htmlDoEscape();
+
+/* Include an HTML file in a CGI.
+ *   The file path is relative to the web server document root */
+void htmlIncludeWebFile(char *file);
+
+/* Include an HTML file in a CGI */
+void htmlIncludeFile(char *path);
diff --git a/inc/https.h b/inc/https.h
new file mode 100644
index 0000000..7197d0e
--- /dev/null
+++ b/inc/https.h
@@ -0,0 +1,9 @@
+/* Connect via https. */
+
+#ifndef NET_HTTPS_H
+#define NET_HTTPS_H
+
+int netConnectHttps(char *hostName, int port);
+/* Return socket for https connection with server or -1 if error. */
+
+#endif//ndef NET_HTTPS_H
diff --git a/inc/intValTree.h b/inc/intValTree.h
new file mode 100644
index 0000000..07203bb
--- /dev/null
+++ b/inc/intValTree.h
@@ -0,0 +1,50 @@
+/* intValTree - a binary tree with integer keys and void values.  This is based on the 
+ * red/black self-balancing binary tree algorithm in the rbTree module. */
+
+#ifndef INTVALTREE_H
+#define INTVALTREE_H
+
+#ifndef RBTREE_H
+#include "rbTree.h"
+#endif
+
+struct rbTree *intValTreeNew();
+/* Create a new, empty, tree with integer keys and void values. */
+
+#define intValTreeFree(a) rbTreeFree(a)
+/* Free up intVal tree.  */
+
+struct intVal
+/* An integer coupled with a void value. */
+    {
+    int key;
+    void *val;
+    };
+
+int intValCmp(void *va, void *vb);
+/* Return -1 if a before b,  0 if a and b overlap,
+ * and 1 if a after b. */
+
+struct intVal *intValTreeAdd(struct rbTree *tree, int key, void *val);
+/* Add to binary tree.  Will abort if key is already in tree. */
+
+struct intVal *intValTreeUpdate(struct rbTree *tree, int key, void *val);
+/* Add to binary tree. If key is already in tree just updates it with val. */
+
+struct intVal *intValTreeRemove(struct rbTree *tree, int key);
+/* Removes given tree from key. */
+
+struct intVal *intValTreeLookup(struct rbTree *tree, int key);
+/* Returns intVal associated with given key, or NULL if none exists. */
+
+void *intValTreeFind(struct rbTree *tree, int key);
+/* Returns value associated with given key, or NULL if none exists. */
+
+void *intValTreeMustFind(struct rbTree *tree, int key);
+/* Return value associated with given key. Aborts if none exists. */
+
+int *intValTreeKeys(struct rbTree *tree);
+/* Returns array of keys (size is tree->n).  You freeMem this when done. */
+
+#endif /* INTVALTREE_H */
+
diff --git a/inc/internet.h b/inc/internet.h
new file mode 100644
index 0000000..1633799
--- /dev/null
+++ b/inc/internet.h
@@ -0,0 +1,43 @@
+/* internet - some stuff for routines that use the internet
+ * and aren't afraid to include some internet specific structures
+ * and the like.   See also net for stuff that is higher level. */
+
+#ifndef INTERNET_H
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+bits32 internetHostIp(char *hostName);
+/* Get IP v4 address (in host byte order) for hostName.
+ * Warn and return 0 if there's a problem. */
+
+boolean internetFillInAddress(char *hostName, int port, 
+	struct sockaddr_in *address);
+/* Fill in address. Warn and return FALSE if can't.  */
+
+boolean internetIpToDottedQuad(bits32 ip, char dottedQuad[17]);
+/* Convert IP4 address in host byte order to dotted quad 
+ * notation.  Warn and return FALSE if there's a 
+ * problem. */
+
+boolean internetDottedQuadToIp(char *dottedQuad, bits32 *retIp);
+/* Convert dotted quad format address to IP4 address in
+ * host byte order.  Warn and return FALSE if there's a 
+ * problem. */
+
+boolean internetIsDottedQuad(char *s);
+/* Returns TRUE if it looks like s is a dotted quad. */
+
+void internetParseDottedQuad(char *dottedQuad, unsigned char quad[4]);
+/* Parse dotted quads into quad */
+
+void internetUnpackIp(bits32 packed, unsigned char unpacked[4]);
+/* Convert from 32 bit to 4-byte format with most significant
+ * byte first. */
+
+boolean internetIpInSubnet(unsigned char unpackedIp[4], 
+	unsigned char subnet[4]);
+/* Return true if unpacked IP address is in subnet. */
+
+#endif /* INTERNET_H */
diff --git a/inc/itsa.h b/inc/itsa.h
new file mode 100644
index 0000000..b460430
--- /dev/null
+++ b/inc/itsa.h
@@ -0,0 +1,90 @@
+/* itsa - indexed traversable suffix array.  Used for doing quick genomic searches.
+ * Use itsaMake utility to create one of these files , and the routines here to access it.  
+ * See comment by itsaFileHeader for file format. See src/shortReads/itsaMake/itsa.doc as well 
+ * for an explanation of the data structures, particularly the traverse array. */
+/* This file is copyright 2008 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef ITSA_H
+#define ITSA_H
+
+struct itsaFileHeader
+/* Short read index file binary file header.  A itsa file starts with this fixed 128 byte
+ * structure.  It is followed by the following sections:
+ *    chromosome name strings - zero terminated.  Padded with zero to 4 byte boundary 
+ *    chromosome sizes (32 bits each)
+ *    chromosome DNA - one byte per base lower case.  A zero between each chrom, and a zero before
+ *                     and after (to make some end conditions easier).  Padded if need be with
+ *                     additional zeroes to 4 base boundary.
+ *    suffix array -   32 bits for each indexed base. Alphabetical offsets into DNA
+ *    traverse array - Also 32 bits per indexed base. Helper info to traverse array like a tree. 
+ *    index13 - index of all 13-base prefixes in the suffix array.  4**13 32 bit values.  
+ *              Will have zeros in positions where there is no data for this slot.
+ *              Index+1 of suffix array where there is data (to free up zero for no data). 
+ *    cursors13 - cursor position at each of the index13 positions*/
+    {
+    bits32 magic;	 /* Always ITSA_MAGIC */
+    bits16 majorVersion; /* This version changes when backward compatibility breaks. */
+    bits16 minorVersion; /* This version changes whenever a feature is added. */
+    bits64 size;	 /* Total size to memmap, including header. */
+    bits32 chromCount;	 /* Total count of chromosomes/contigs in file. */
+    bits32 chromNamesSize;	/* Size of names of all contigs (including zeroes at end),
+    				   padded to 4 byte boundary as needed). */
+    bits64 arraySize;	 /* Total number of bases actually indexed (non-N, unmasked). */
+    bits64 dnaDiskSize;	 /* Size of DNA on disk with zero separators. Padded to 4 byte boundary  */
+    bits64 reserved[11];/* All zeroes for now. */
+    };
+
+struct itsa 
+/* Suffix array in memory */
+    {
+    struct itsa *next;
+    boolean isMapped;	/* True if memory mapped. */
+    struct itsaFileHeader *header;	/* File header. */
+    char **chromNames;	/* Name of each chromosome. */
+    bits32 *chromSizes;    /* Size of each chromosome.  No deallocation required (in memmap) */
+    bits32 *chromOffsets;  /* Offset of each chromosome's DNA */
+    char *allDna;	/* All DNA from each contig/chromosome with zero separators. */
+    bits32 *array;	/* Alphabetized offsets into allDna.  The suffix array. */
+    bits32 *traverse;	/* Offsets to position in array where current prefix changes. */
+    bits32 *index13;	/* Look up the first 13 bases of the query sequence here to find the corresponding
+                         * offset into the suffix array.  0 indicates empty slot.  Subtract 1 to get
+			 * offset (to free up zero for this meaning). */
+    UBYTE *cursors13;	/* Cursor positions in suffix array at index positions. */
+    };
+
+struct itsa *itsaRead(char *fileName, boolean memoryMap);
+/* Read in a itsa from a file.  Does this via memory mapping if you like,
+ * which will be faster typically for about 100 reads, and slower for more
+ * than that (_much_ slower for thousands of reads and more). */
+
+void itsaFree(struct itsa **pSufx);
+/* Free up resources associated with index. */
+
+int itsaOffsetToChromIx(struct itsa *itsa, bits32 tOffset);
+/* Figure out index of chromosome containing tOffset */
+
+/** Stuff to define ITSA files **/
+#define ITSA_MAGIC 0x600BA3A1	/* Magic number at start of ITSA file */
+#define ITSA_MAJOR_VERSION 0	
+#define ITSA_MINOR_VERSION 0
+
+/* Number of slots in itsa index. */
+#define itsaSlotCount (1<<(13*2))
+
+/* Base values in _alphabetical_ order. Unfortunately the ones in dnautil.h are not.... */
+#define ITSA_A 0
+#define ITSA_C 1
+#define ITSA_G 2
+#define ITSA_T 3
+
+/* Table to convert letters to one of the above values. Call itsaBaseToValInit() before using. */
+extern int itsaBaseToVal[256];
+
+void itsaBaseToValInit();
+/* Initialize itsaBaseToVal array */
+
+int itsaDnaToBinary(char *dna, int size);
+/* Convert dna to binary representation. Call itsaBaseToValInit() first. */
+
+#endif /* ITSA_H */
diff --git a/inc/iupac.h b/inc/iupac.h
new file mode 100644
index 0000000..2ff3318
--- /dev/null
+++ b/inc/iupac.h
@@ -0,0 +1,42 @@
+/* iupac - routines to help cope with IUPAC ambiguity codes in DNA sequence. */
+
+#ifndef IUPAC_H
+#define IUPAC_H
+
+boolean iupacMatch(char iupac, char dna);
+/* See if iupac ambiguity code matches dna character */
+
+boolean iupacMatchLower(char iupac, char dna);
+/* See if iupac ambiguity code matches dna character where
+ * both are lower case */
+
+boolean isIupac(char c);
+/* See if iupac c is a legal iupac char */
+
+boolean isIupacLower(char c);
+/* See if iupac c is a legal (lower case) iupac char */
+
+void iupacFilter(char *in, char *out);
+/* Filter out non-DNA non-UIPAC ambiguity code characters and change to lower case. */
+
+boolean anyIupac(char *s);
+/* Return TRUE if there are any IUPAC ambiguity codes in s */
+
+char iupacComplementBaseLower(char iupac);
+/* Return IUPAC complement for a single base */
+
+void iupacComplementLower(char *iupac, int iuSize);
+/* Return IUPAC complement many bases. Assumes iupac is lower case. */
+
+void iupacReverseComplement(char *iu, int iuSize);
+/* Reverse complement a string containing DNA and IUPAC codes. Result will be always
+ * lower case. */
+
+boolean iupacMatchStart(char *iupacPrefix, char *dnaString);
+/* Return TRUE if start of DNA is compatible with iupac */
+
+char *iupacIn(char *needle, char *haystack);
+/* Return first place in haystack (DNA) that matches needle that may contain IUPAC codes. */
+
+#endif /* IUPAC_H */
+
diff --git a/inc/jointalign.h b/inc/jointalign.h
new file mode 100644
index 0000000..c9d9fe0
--- /dev/null
+++ b/inc/jointalign.h
@@ -0,0 +1,30 @@
+/*****************************************************************************
+ * Copyright (C) 2002 Ryan Weber.  This source code may be freely used       *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Ryan Weber (weber at cse.ucsc.edu) *
+ *****************************************************************************/
+/* jointalign.h - routines for printing a joint alignment in html. */
+
+#ifndef JOINTALIGN_H
+#define JOINTALIGN_H
+
+void htmlPrintJointAlignment( char *seq1, char *seq2, int columnNum, 
+        int start, int end, char *strand );
+/* Print sequences 1 and 2 (assumed to be a joint alignment),
+ * formatted for html output. Coordinates are printed based on
+ * the start and end positions and oriented according to the
+ * strand the sequences are on (+ or -).*/
+
+boolean ucaseMatch( char a, char b );
+/* Case insensitive character matching */
+
+void validateSeqs( char *seq1, char *seq2 );
+/*Make sure sequences are the same length*/
+
+void htmlPrintJointAlignmentLine( char *seq1, char *seq2, int start, int end);
+/* Prints one line of the joint alignment between seq1 and seq2,
+ * from seq[start] to seq[end-1].*/
+
+
+#endif /* JOINTALIGN */
+
diff --git a/inc/jpegSize.h b/inc/jpegSize.h
new file mode 100644
index 0000000..c74f242
--- /dev/null
+++ b/inc/jpegSize.h
@@ -0,0 +1,11 @@
+/* jpegSize - read a jpeg header and figure out dimensions of image.
+ * Adapted by Galt Barber from Matthias Wandel's jhead program */
+
+#ifndef JPEGSIZE_H
+
+void jpegSize(char *fileName, int *width, int *height);
+/* Read image width and height.
+ * Parse marker stream until SOS or EOI; */
+
+#endif /* JPEGSIZE_H */
+
diff --git a/inc/keys.h b/inc/keys.h
new file mode 100644
index 0000000..d12f45d
--- /dev/null
+++ b/inc/keys.h
@@ -0,0 +1,66 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* keys.h - Stuff to manage a little key/value table and
+ * evaluate expressions on it. */
+#ifndef KEYS_H
+#define KEYS_H
+
+struct keyVal
+/* A key/value pair of strings. */
+    {
+    char *key;
+    char *val;
+    };
+
+struct kvt *newKvt(int size);
+/* Get a new key value table. */
+
+void freeKvt(struct kvt **pKvt);
+/* Free up key value table. */
+
+void kvtClear(struct kvt *kvt);
+/* Clear the keys table. */
+
+struct keyVal *kvtAdd(struct kvt *kvt, char *key, char *val);
+/* Add in new key. */
+
+struct keyVal* kvtGet(struct kvt *kvt, char *key);
+/* get the keyVal for the specified key, of NULL if not found. */
+
+char *kvtLookup(struct kvt *kvt, char *key);
+/* Search table for key.  Return key value, or NULL if
+ * key not found. */
+
+void kvtWriteAll(struct kvt *kvt, FILE *f, struct slName *hideList);
+/* Write all keys to file except the ones in hideList */
+
+void kvtParseAdd(struct kvt *kvt, char *text);
+/* Add in keys from text.  Text is in format:
+ *     key val
+ * for each line of text. Text gets many of it's
+ * space characters and newlines replaced by 0's
+ * and should persist until call to keysClear(). */
+
+struct keyExp
+/* A handle on a parsed expression which can be
+ * quickly evaluated.  */
+    {
+    void *rootExp;       /* Internally struct exp. */
+    void *tokenList;     /* Internally struct tok. */
+    };
+
+boolean keyExpEval(struct keyExp *exp, struct kvt *kvt);
+/* Recursively evaluate expression. */
+
+struct keyExp *keyExpParse(char *text);
+/* Parse text into key expression.  Squawk and die if it
+ * fails. */
+
+boolean keyTextScan(char *text, char *key, char *valBuf, int valBufSize);
+/* Get value of key in text. Return FALSE if key doesn't exist. */
+
+#endif /* KEYS_H */
+
diff --git a/inc/knetUdc.h b/inc/knetUdc.h
new file mode 100644
index 0000000..f2af578
--- /dev/null
+++ b/inc/knetUdc.h
@@ -0,0 +1,10 @@
+/* knetUdc -- install udc i/o functions in knetfile interface in Heng Li's samtools lib. */
+/* As of 2/23/10, the KNETFILE_HOOKS extension is a UCSC-local modification of samtools. */
+
+#ifndef KNETUDC_H
+#define KNETUDC_H
+
+void knetUdcInstall();
+/* install udc i/o functions in knetfile interface in Heng Li's samtools lib. */
+
+#endif//ndef KNETUDC_H
diff --git a/inc/kxTok.h b/inc/kxTok.h
new file mode 100644
index 0000000..717b5bb
--- /dev/null
+++ b/inc/kxTok.h
@@ -0,0 +1,65 @@
+/* kxTok - quick little tokenizer for stuff first
+ * loaded into memory.  Originally developed for
+ * "Key eXpression" evaluator. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef KXTOK_H
+#define KXTOK_H
+
+enum kxTokType
+    {
+    kxtEnd,
+    kxtString,
+    kxtWildString,
+    kxtEquals,
+    kxtGT,      /* Greater Than */
+    kxtGE,      /* Greater Than or Equal */
+    kxtLT,      /* Less Than */
+    kxtLE,      /* Less Than or Equal */
+    kxtAnd,
+    kxtOr,
+    kxtXor,
+    kxtNot,
+    kxtOpenParen,
+    kxtCloseParen,
+    kxtAdd,
+    kxtSub,
+    kxtDiv,
+    kxtMul,
+    kxtDot,
+    kxtMod,
+    kxtPunct,
+    };
+
+struct kxTok
+/* A key expression token.   Input text is tokenized
+ * into a list of these. */
+    {
+    struct kxTok *next;
+    enum kxTokType type;
+    bool spaceBefore;	/* True if there is a space before */
+    char string[1];  /* Allocated at run time */
+    };
+
+struct kxTok *kxTokenize(char *text, boolean wildAst);
+/* Convert text to stream of tokens. If 'wildAst' is
+ * TRUE then '*' character will be treated as wildcard
+ * rather than multiplication sign. */
+
+struct kxTok *kxTokenizeFancy(char *text, boolean wildAst,
+			      boolean wildPercent, boolean includeHyphen);
+/* Convert text to stream of tokens. If 'wildAst' is
+ * TRUE then '*' character will be treated as wildcard
+ * rather than multiplication sign.  
+ * If wildPercent is TRUE then the '%' character will be treated as a 
+ * wildcard (as in SQL) rather than a modulo (kxtMod) or percent sign.
+ * If includeHyphen is TRUE then a '-' character in the middle of a String 
+ * token will be treated as a hyphen (part of the String token) instead of 
+ * a new kxtSub token. */
+
+void kxTokIncludeQuotes(boolean val);
+/* Pass in TRUE if kxTok should include quote characters in string tokens. */
+
+#endif /* KXTOK_K */
diff --git a/inc/linefile.h b/inc/linefile.h
new file mode 100644
index 0000000..1f28171
--- /dev/null
+++ b/inc/linefile.h
@@ -0,0 +1,289 @@
+/* lineFile - stuff to rapidly read text files and parse them into
+ * lines.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef LINEFILE_H
+#define LINEFILE_H
+
+#include "dystring.h"
+
+#ifdef USE_TABIX
+#include "tabix.h"
+#endif
+
+enum nlType {
+ nlt_undet, /* undetermined */
+ nlt_unix,  /* lf   */
+ nlt_dos,   /* crlf */
+ nlt_mac    /* cr   */
+};
+
+struct metaOutput
+/* struct to store list of file handles to output meta data to
+ * meta data is text after # */
+    {
+    struct metaOutput *next;    /* next file handle */
+    FILE *metaFile;             /* file to write metadata to */
+    };
+
+struct lineFile
+/* Structure to handle fast, line oriented
+ * fileIo. */
+    {
+    struct lineFile *next;	/* Might need to be on a list. */
+    char *fileName;		/* Name of file. */
+    int fd;			/* File handle.  -1 for 'memory' files. */
+    int bufSize;		/* Size of buffer. */
+    off_t bufOffsetInFile;	/* Offset in file of first buffer byte. */
+    int bytesInBuf;		/* Bytes read into buffer. */
+    int reserved;		/* Reserved (zero for now). */
+    int lineIx;			/* Current line. */
+    int lineStart;		/* Offset of line in buffer. */
+    int lineEnd;		/* End of line in buffer. */
+    bool zTerm;			/* Replace '\n' with zero? */
+    enum nlType nlType;         /* type of line endings: dos, unix, mac or undet */
+    bool reuse;			/* Set if reusing input. */
+    char *buf;			/* Buffer. */
+    struct pipeline *pl;        /* pipeline if reading compressed */
+    struct metaOutput *metaOutput;   /* list of FILE handles to write metaData to */
+    bool isMetaUnique;          /* if set, do not repeat comments in output */
+    struct hash *metaLines;     /* save lines to suppress repetition */
+#ifdef USE_TABIX
+    tabix_t *tabix;		/* A tabix-compressed file and its binary index file (.tbi) */
+    ti_iter_t tabixIter;	/* An iterator to get decompressed indexed lines of text */
+#endif
+    struct dyString *fullLine;  // Filled with full line when a lineFileNextFull is called
+    struct dyString *rawLines;  // Filled with raw lines used to create the full line
+    boolean fullLineReuse;      // If TRUE, next call to lineFileNextFull will get
+                                // already built fullLine
+    void *dataForCallBack;                                 // ptr to data needed for callbacks
+    void(*checkSupport)(struct lineFile *lf, char *where); // check if operation supported 
+    boolean(*nextCallBack)(struct lineFile *lf, char **retStart, int *retSize); // next line callback
+    void(*closeCallBack)(struct lineFile *lf);             // close callback
+    };
+
+char *getFileNameFromHdrSig(char *m);
+/* Check if header has signature of supported compression stream,
+   and return a phoney filename for it, or NULL if no sig found. */
+
+struct lineFile *lineFileDecompressFd(char *name, bool zTerm, int fd);
+/* open a linefile with decompression from a file or socket descriptor */
+
+struct lineFile *lineFileDecompressMem(bool zTerm, char *mem, long size);
+/* open a linefile with decompression from a memory stream */
+
+struct lineFile *lineFileMayOpen(char *fileName, bool zTerm);
+/* Try and open up a lineFile. If fileName ends in .gz, .Z, or .bz2,
+ * it will be read from a decompress pipeline. */
+
+struct lineFile *lineFileOpen(char *fileName, bool zTerm);
+/* Open up a lineFile or die trying If fileName ends in .gz, .Z, or .bz2,
+ * it will be read from a decompress pipeline.. */
+
+struct lineFile *lineFileAttach(char *fileName, bool zTerm, int fd);
+/* Wrap a line file around an open'd file. */
+
+struct lineFile *lineFileStdin(bool zTerm);
+/* Wrap a line file around stdin. */
+
+struct lineFile *lineFileOnString(char *name, bool zTerm, char *s);
+/* Wrap a line file object around string in memory. This buffer
+ * have zeroes written into it if zTerm is non-zero.  It will
+ * be freed when the line file is closed. */
+
+struct lineFile *lineFileOnBigBed(char *bigBedFileName);
+/* Wrap a line file object around a BigBed. */
+
+void lineFileClose(struct lineFile **pLf);
+/* Close up a line file. */
+
+void lineFileCloseList(struct lineFile **pList);
+/* Close up a list of line files. */
+
+boolean lineFileNext(struct lineFile *lf, char **retStart, int *retSize);
+/* Fetch next line from file. */
+
+boolean lineFileNextFull(struct lineFile *lf, char **retFull, int *retFullSize,
+                        char **retRaw, int *retRawSize);
+// Fetch next line from file joining up any that are continued by ending '\'
+// If requested, and was joined, the unjoined raw lines are also returned
+// NOTE: comment lines can't be continued!  ("# comment \ \n more comment" is 2 lines.)
+
+boolean lineFileNextReal(struct lineFile *lf, char **retStart);
+/* Fetch next line from file that is not blank and
+ * does not start with a '#'. */
+
+boolean lineFileNextFullReal(struct lineFile *lf, char **retStart);
+// Fetch next line from file that is not blank and does not start with a '#'.
+// Continuation lines (ending in '\') are joined into a single line.
+
+void lineFileNeedNext(struct lineFile *lf, char **retStart, int *retSize);
+/* Fetch next line from file.  Squawk and die if it's not there. */
+
+void lineFileReuse(struct lineFile *lf);
+/* Reuse current line. */
+
+void lineFileReuseFull(struct lineFile *lf);
+// Reuse last full line read.  Unlike lineFileReuse,
+// lineFileReuseFull only works with previous lineFileNextFull call
+
+#define lineFileString(lf) ((lf)->buf + (lf)->lineStart)
+/* Current string in line file. */
+
+#define lineFileTell(lf) ((lf)->bufOffsetInFile + (lf)->lineStart)
+/* Current offset (of string start) in file. */
+
+void lineFileSeek(struct lineFile *lf, off_t offset, int whence);
+/* Seek to read next line from given position. */
+
+void lineFileRewind(struct lineFile *lf);
+/* Return lineFile to start. */
+
+void lineFileAbort(struct lineFile *lf, char *format, ...)
+/* Print file name, line number, and error message, and abort. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 2, 3)))
+#endif
+;
+
+void lineFileVaAbort(struct lineFile *lf, char *format, va_list args);
+/* Print file name, line number, and error message, and abort. */
+
+void lineFileUnexpectedEnd(struct lineFile *lf);
+/* Complain about unexpected end of file. */
+
+void lineFileExpectWords(struct lineFile *lf, int expecting, int got);
+/* Check line has right number of words. */
+
+void lineFileExpectAtLeast(struct lineFile *lf, int expecting, int got);
+/* Check line has right number of words. */
+
+void lineFileShort(struct lineFile *lf);
+/* Complain that line is too short. */
+
+boolean lineFileNextRow(struct lineFile *lf, char *words[], int wordCount);
+/* Return next non-blank line that doesn't start with '#' chopped into words.
+ * Returns FALSE at EOF.  Aborts on error. */
+
+#define lineFileRow(lf, words) lineFileNextRow(lf, words, ArraySize(words))
+/* Read in line chopped into fixed size word array. */
+
+boolean lineFileNextCharRow(struct lineFile *lf, char sep, char *words[], int wordCount);
+/* Return next non-blank line that doesn't start with '#' chopped into words
+ * delimited by sep. Returns FALSE at EOF.  Aborts on error. */
+
+boolean lineFileNextRowTab(struct lineFile *lf, char *words[], int wordCount);
+/* Return next non-blank line that doesn't start with '#' chopped into words
+ * at tabs. Returns FALSE at EOF.  Aborts on error. */
+
+#define lineFileRowTab(lf, words) \
+	lineFileNextRowTab(lf, words, ArraySize(words))
+/* Read in line chopped by tab into fixed size word array. */
+
+int lineFileChopNext(struct lineFile *lf, char *words[], int maxWords);
+/* Return next non-blank line that doesn't start with '#' chopped into words. */
+
+#define lineFileChop(lf, words) lineFileChopNext(lf, words, ArraySize(words))
+/* Ease-of-usef macro for lineFileChopNext above. */
+
+int lineFileChopCharNext(struct lineFile *lf, char sep, char *words[], int maxWords);
+/* Return next non-blank line that doesn't start with '#' chopped into
+   words delimited by sep. */
+
+int lineFileChopNextTab(struct lineFile *lf, char *words[], int maxWords);
+/* Return next non-blank line that doesn't start with '#' chopped into words
+ * on tabs */
+
+#define lineFileChopTab(lf, words) lineFileChopNextTab(lf, words, ArraySize(words))
+/* Ease-of-usef macro for lineFileChopNext above. */
+
+int lineFileCheckAllIntsNoAbort(char *s, void *val, 
+    boolean isSigned, int byteCount, char *typeString, boolean noNeg, 
+    char *errMsg, int errMsgSize);
+/* Convert string to (signed) integer of the size specified.  
+ * Unlike atol assumes all of string is number, no trailing trash allowed.
+ * Returns 0 if conversion possible, and value is returned in 'val'
+ * Otherwise 1 for empty string or trailing chars, and 2 for numeric overflow,
+ * and 3 for (-) sign in unsigned number.
+ * Error messages if any are written into the provided buffer.
+ * Pass NULL val if you only want validation.
+ * Use noNeg if negative values are not allowed despite the type being signed,
+ * returns 4. */
+
+void lineFileAllInts(struct lineFile *lf, char *words[], int wordIx, void *val,
+  boolean isSigned,  int byteCount, char *typeString, boolean noNeg);
+/* Returns long long integer from converting the input string. Aborts on error. */
+
+int lineFileAllIntsArray(struct lineFile *lf, char *words[], int wordIx, void *array, int arraySize,
+  boolean isSigned,  int byteCount, char *typeString, boolean noNeg);
+/* Convert comma separated list of numbers to an array.  Pass in
+ * array and max size of array. Aborts on error. Returns number of elements in parsed array. */
+
+int lineFileNeedNum(struct lineFile *lf, char *words[], int wordIx);
+/* Make sure that words[wordIx] is an ascii integer, and return
+ * binary representation of it. */
+
+int lineFileNeedFullNum(struct lineFile *lf, char *words[], int wordIx);
+/* Make sure that words[wordIx] is an ascii integer, and return
+ * binary representation of it. Require all chars in word to be digits.*/
+
+double lineFileNeedDouble(struct lineFile *lf, char *words[], int wordIx);
+/* Make sure that words[wordIx] is an ascii double value, and return
+ * binary representation of it. */
+
+void lineFileSkip(struct lineFile *lf, int lineCount);
+/* Skip a number of lines. */
+
+char *lineFileSkipToLineStartingWith(struct lineFile *lf, char *start, int maxCount);
+/* Skip to next line that starts with given string.  Return NULL
+ * if no such line found, otherwise return the line. */
+
+char *lineFileReadAll(struct lineFile *lf);
+/* Read remainder of lineFile and return it as a string. */
+
+boolean lineFileParseHttpHeader(struct lineFile *lf, char **hdr,
+				boolean *chunked, int *contentLength);
+/* Extract HTTP response header from lf into hdr, tell if it's
+ * "Transfer-Encoding: chunked" or if it has a contentLength. */
+
+struct dyString *lineFileSlurpHttpBody(struct lineFile *lf,
+				       boolean chunked, int contentLength);
+/* Return a dyString that contains the http response body in lf.  Handle
+ * chunk-encoding and content-length. */
+
+void lineFileSetMetaDataOutput(struct lineFile *lf, FILE *f);
+/* set file to write meta data to,
+ * should be called before reading from input file */
+
+void lineFileSetUniqueMetaData(struct lineFile *lf);
+/* suppress duplicate lines in metadata */
+
+void lineFileExpandBuf(struct lineFile *lf, int newSize);
+/* Expand line file buffer. */
+
+void lineFileRemoveInitialCustomTrackLines(struct lineFile *lf);
+/* remove initial browser and track lines */
+
+/*----- Optionally-compiled wrapper on tabix (compression + indexing): -----*/
+
+#define COMPILE_WITH_TABIX "%s: Sorry, this functionality is available only when\n" \
+    "you have installed the tabix library from\n" \
+     "http://samtools.sourceforge.net/ and rebuilt kent/src with USE_TABIX=1\n" \
+     "(see http://genomewiki.ucsc.edu/index.php/Build_Environment_Variables)."
+
+struct lineFile *lineFileTabixMayOpen(char *fileOrUrl, bool zTerm);
+/* Wrap a line file around a data file that has been compressed and indexed
+ * by the tabix command line program.  The index file <fileName>.tbi must be
+ * readable in addition to fileName. If there's a problem, warn & return NULL.
+ * This works only if kent/src has been compiled with USE_TABIX=1 and linked
+ * with the tabix C library. */
+
+boolean lineFileSetTabixRegion(struct lineFile *lf, char *seqName, int start, int end);
+/* Assuming lf was created by lineFileTabixMayOpen, tell tabix to seek to the specified region
+ * and return TRUE (or if there are no items in region, return FALSE). */
+
+#endif /* LINEFILE_H */
+
+
diff --git a/inc/localmem.h b/inc/localmem.h
new file mode 100644
index 0000000..e5da176
--- /dev/null
+++ b/inc/localmem.h
@@ -0,0 +1,47 @@
+/* LocalMem.h - local memory routines. 
+ * 
+ * These routines are meant for the sort of scenario where
+ * a lot of little to medium size pieces of memory are
+ * allocated, and then disposed of all at once.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+struct lm *lmInit(int blockSize);
+/* Create a local memory pool. Parameters are:
+ *      blockSize - how much system memory to allocate at a time.  Can
+ *                  pass in zero and a reasonable default will be used.
+ */
+
+void lmCleanup(struct lm **pLm);
+/* Clean up a local memory pool. */
+
+void *lmAlloc(struct lm *lm, size_t size);
+/* Allocate memory from local pool. */
+
+char *lmCloneString(struct lm *lm, char *string);
+/* Return local mem copy of string. */
+
+char*lmCloneStringZ(struct lm *lm, char *string, int size);
+/* Return local mem copy of string of given size, adding null terminator. */
+
+char *lmCloneFirstWord(struct lm *lm, char *line);
+/* Clone first word in line */
+
+char *lmCloneSomeWord(struct lm *lm, char *line, int wordIx);
+/* Return a clone of the given space-delimited word within line.  Returns NULL if
+ * not that many words in line. */
+
+struct slName *lmSlName(struct lm *lm, char *name);
+/* Return slName in memory. */
+
+void *lmCloneMem(struct lm *lm, void *pt, size_t size);
+/* Return a local mem copy of memory block. */
+
+#define lmAllocVar(lm, pt) (pt = lmAlloc(lm, sizeof(*pt)));
+/* Shortcut to allocating a single variable in local mem and
+ * assigning pointer to it. */
+
+#define lmAllocArray(lm, pt, size) (pt = lmAlloc(lm, sizeof(*pt) * (size)))
+/* Shortcut to allocating an array in local mem and
+ * assigning pointer to it. */
diff --git a/inc/log.h b/inc/log.h
new file mode 100644
index 0000000..4c2474c
--- /dev/null
+++ b/inc/log.h
@@ -0,0 +1,74 @@
+/* log.h - logging for servers, can log to a file and/or syslog.  Compile with
+ * -DNO_SYSLOG for systems without syslog. */
+
+#ifndef LOG_H
+#define LOG_H
+
+void logOpenSyslog(char* program, char *facility);
+/* Initialize syslog using the specified facility.  Facility is the syslog
+ * facility as specified in syslog.conf.  If facility is NULL, local0 is used.
+ * This adds a warn and errAbort handlers that do logging.  If custom handlers
+ * are added, they should call logErrorVa().
+ */
+
+void logOpenFile(char* program, char *logFile);
+/* Initialize logging to the specified file.  Append to the file if it exists.
+ * This adds a warn and errAbort handlers that do logging.  If custom handlers
+ * are added, they should call logErrorVa(). 
+ */
+
+void logSetMinPriority(char *minPriority);
+/* set minimum priority to log, which is one of the syslog priority names,
+ * even when logging to a file */
+
+FILE *logGetFile();
+/* Returns the log FILE object if file logging is enabled, or NULL if it
+ * isn't. This is useful for logging debugging data that doesn't fit the log
+ * message paradigm, For example, logging fasta records. */
+
+void logErrorVa(char *format, va_list args);
+/* Variable args logError. */
+
+void logError(char *format, ...)
+/* Log an error message. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+void logWarnVa(char *format, va_list args);
+/* Variable args logWarn. */
+
+void logWarn(char *format, ...)
+/* Log a warn message. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+void logInfoVa(char *format, va_list args);
+/* Variable args logInfo. */
+
+void logInfo(char *format, ...)
+/* Log an info message. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+void logDebugVa(char *format, va_list args);
+/* Variable args logDebug. */
+
+void logDebug(char *format, ...)
+/* Log a debug message. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+
+void logDaemonize(char *progName);
+/* daemonize server process: closing open file descriptors and
+ * starting logging based on the -logFacility and -log command line options .
+ * if -debug is supplied , don't fork. */
+
+#endif
diff --git a/inc/maDbRep.h b/inc/maDbRep.h
new file mode 100644
index 0000000..77fce3d
--- /dev/null
+++ b/inc/maDbRep.h
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+#ifndef MADBREP_H
+#define MADBREP_H
+
+/* maDbRep.h was originally generated by the autoSql program, which also 
+ * generated maDbRep.c and maDbRep.sql.  This header links the database and the RAM 
+ * representation of objects. */
+
+struct mrnaAli
+/* An mRNA/genomic alignment */
+    {
+    struct mrnaAli *next;  /* Next in singly linked list. */
+    unsigned id;	/* Unique ID */
+    signed char readDir;	/* Read direction of mRNA +1 or -1 */
+    signed char orientation;	/* Orientation relative to first BAC */
+    unsigned char hasIntrons;	/* True if alignment has introns */
+    unsigned char isEst;	/* True if an EST. */
+    int score;	/* Score in something like log-odds form */
+    char qAcc[13];	/* GenBank Accession for mRNA sequence */
+    unsigned qId;	/* Database ID of mRNA sequence */
+    unsigned qTotalSize;	/* Total bases (not just aligned) in mRNA */
+    unsigned qStart;	/* Start in mRNA sequence */
+    unsigned qEnd;	/* End in mRNA sequence */
+    unsigned tStartBac;	/* ID of first genomic BAC in alignment */
+    unsigned tStartPos;	/* Start position within first BAC */
+    unsigned tEndBac;	/* ID of last genomic BAC in alignment */
+    unsigned tEndPos;	/* End position within last BAC */
+    unsigned blockCount;	/* Number of aligned blocks */
+    unsigned *blockSizes;	/* Size of each block */
+    unsigned *qBlockStarts;	/* Start of each block in mRNA */
+    unsigned *tBlockBacs;	/* BAC each block starts in */
+    unsigned *tBlockStarts;	/* Position within BAC of each block start */
+    unsigned short *startGoods;	/* Number of perfect bases at start of block */
+    unsigned short *endGoods;	/* Number of perfect bases at end of block */
+    };
+
+struct mrnaAli *mrnaAliLoad(char **row);
+/* Load a mrnaAli from row fetched with select * from mrnaAli
+ * from database.  Dispose of this with mrnaAliFree(). */
+
+void mrnaAliFree(struct mrnaAli **pEl);
+/* Free a single dynamically allocated mrnaAli such as created
+ * with mrnaAliLoad(). */
+
+void mrnaAliFreeList(struct mrnaAli **pList);
+/* Free a list of dynamically allocated mrnaAli's */
+
+void mrnaAliOutput(struct mrnaAli *el, FILE *f, char sep, char lastSep);
+/* Print out mrnaAli.  Separate fields with sep. Follow last field with lastSep. */
+
+#define mrnaAliTabOut(el,f) mrnaAliOutput(el,f,'\t','\n');
+/* Print out mrnaAli as a line in a tab-separated file. */
+
+#define mrnaAliCommaOut(el,f) mrnaAliOutput(el,f,',',',');
+/* Print out mrnaAli as a comma separated list including final comma. */
+
+#endif /* MADBREP_H */
+
diff --git a/inc/maToFf.h b/inc/maToFf.h
new file mode 100644
index 0000000..18b8aa7
--- /dev/null
+++ b/inc/maToFf.h
@@ -0,0 +1,21 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+#ifndef MATOFF_H
+#define MATOFF_H
+
+/* Convert between mrnaAli and ffAli representations of an alignment. */
+
+struct mrnaAli *ffToMa(struct ffAli *ffLeft, 
+	struct dnaSeq *mrnaSeq, char *mrnaAcc,
+	struct dnaSeq *genoSeq, char *genoAcc, 
+	boolean isRc, boolean isEst);
+/* Convert ffAli structure to mrnaAli. */
+
+struct ffAli *maToFf(struct mrnaAli *ma, DNA *needle, DNA *haystack);
+/* Convert from database to internal representation of alignment. */
+
+#endif /* MATOFF_H */
+
diff --git a/inc/maf.h b/inc/maf.h
new file mode 100644
index 0000000..d337958
--- /dev/null
+++ b/inc/maf.h
@@ -0,0 +1,258 @@
+/* maf.h - Multiple alignment format.  */
+#ifndef MAF_H
+#define MAF_H
+
+#ifndef COMMON_H
+#include "common.h"
+#endif
+
+#ifndef AXT_H
+#include "axt.h"
+#endif
+
+struct mafFile
+/* A file full of multiple alignments. */
+    {
+    struct mafFile *next;
+    int version;	 /* Required */
+    char *scoring;	 /* Optional (may be NULL). Name of  scoring scheme. */
+    struct mafAli *alignments;	/* Possibly empty list of alignments. */
+    struct lineFile *lf; /* Open line file if any. NULL except while parsing. */
+    };
+
+void mafFileFree(struct mafFile **pObj);
+/* Free up a maf file including closing file handle if necessary. */
+
+void mafFileFreeList(struct mafFile **pList);
+/* Free up a list of maf files. */
+
+struct mafAli
+/* A multiple alignment. */
+    {
+    struct mafAli *next;
+    double score;        /* Score.  Meaning depends on mafFile.scoring.  0.0 if no scoring. */
+    struct mafComp *components;	/* List of components of alignment */
+    int textSize;         /* Size of text in each component. */
+    struct mafRegDef *regDef; /* source of region definitions (r line) */
+    };
+
+void mafAliFree(struct mafAli **pObj);
+/* Free up a maf alignment. */
+
+void mafAliFreeList(struct mafAli **pList);
+/* Free up a list of maf alignmentx. */
+
+/* the set of syntenic relationships that the previous and
+ * following alignments have with the current one */
+#define	MAF_INVERSE_STATUS		'V'
+#define	MAF_INSERT_STATUS		'I'
+#define	MAF_CONTIG_STATUS		'C'
+#define	MAF_CONTIG_NESTED_STATUS	'c'
+#define	MAF_NEW_STATUS			'N'
+#define	MAF_NEW_NESTED_STATUS		'n'
+#define	MAF_MAYBE_NEW_STATUS		'S'
+#define	MAF_MAYBE_NEW_NESTED_STATUS	's'
+#define	MAF_MISSING_STATUS		'M'
+#define	MAF_TANDEM_STATUS		'T'
+
+struct mafComp
+/* A component of a multiple alignment. */
+    {
+    struct mafComp *next;
+    char *src;	 /* Name of sequence source.  */
+    int srcSize; /* Size of sequence source.  */
+    char strand; /* Strand of sequence.  Either + or -*/
+    int start;	 /* Start within sequence. Zero based. If strand is - is relative to src end. */
+    int size;	 /* Size in sequence (does not include dashes).  */
+    char *text;  /* The sequence including dashes. */
+    char *quality;  /* The quality data (same length as text, or NULL). */
+    char leftStatus; /* the syntenic status of the alignment before us vis a vis ourselves */
+    int leftLen;     /* length related information for the previous alignment for the species */
+    char rightStatus; /* the syntenic status of the alignment after us vis a vis ourselves */
+    int rightLen;     /* length related information for the following alignment for the species */
+    };
+
+void mafCompFree(struct mafComp **pObj);
+/* Free up a maf component. */
+
+void mafCompFreeList(struct mafComp **pList);
+/* Free up a list of maf components. */
+
+char *mafCompGetSrcDb(struct mafComp *mc, char *buf, int bufSize);
+/* parse the srcDb name from the mafComp src name, return NULL if no srcDb */
+
+char *mafCompGetSrcName(struct mafComp *mc);
+/* parse the src sequence name from the mafComp src name */
+
+struct mafRegDef
+/* MAF region definition (r line) */
+{
+    char *type;   // type of definition, one of constants below (not malloced)
+    int size;     // region size
+    char *id;     // identifiers
+};
+extern char *mafRegDefTxUpstream;  // transcription start size upstream region
+
+struct mafRegDef *mafRegDefNew(char *type, int size, char *id);
+/* construct a new mafRegDef object */
+
+void mafRegDefFree(struct mafRegDef **mrdPtr);
+/* Free a mafRegDef object */
+
+int mafPlusStart(struct mafComp *comp);
+/* Return start relative to plus strand of src. */
+
+struct mafFile *mafOpen(char *fileName);
+/* Open up a .maf file for reading.  Read header and
+ * verify. Prepare for subsequent calls to mafNext().
+ * Prints error message and aborts if there's a problem. */
+
+struct mafFile *mafMayOpen(char *fileName);
+/* Like mafOpen above, but returns NULL rather than aborting 
+ * if file does not exist. */
+
+void mafRewind(struct mafFile *mf);
+/* Seek to beginning of open maf file */
+
+struct mafAli *mafNext(struct mafFile *mafFile);
+/* Return next alignment in file or NULL if at end. 
+ * This will close the open file handle at end as well. */
+
+struct mafAli *mafNextWithPos(struct mafFile *mf, off_t *retOffset);
+/* Return next alignment in FILE or NULL if at end.  If retOffset is
+ * non-NULL, return start offset of record in file. */
+
+struct mafFile *mafReadAll(char *fileName);
+/* Read in full maf file */
+
+void mafWriteStart(FILE *f, char *scoring);
+/* Write maf header and scoring scheme name (may be null) */
+
+void mafWrite(FILE *f, struct mafAli *maf);
+/* Write next alignment to file. */
+
+void mafWriteEnd(FILE *f);
+/* Write end tag of maf file. */
+
+void mafWriteAll(struct mafFile *mf, char *fileName);
+/* Write out full mafFile. */
+
+struct mafComp *mafMayFindComponent(struct mafAli *maf, char *src);
+/* Find component of given source. Return NULL if not found. */
+
+struct mafComp *mafMayFindComponentDb(struct mafAli *maf, char *db);
+/* Find component of given database or source. Return NULL if not found. */
+
+struct mafComp *mafFindComponent(struct mafAli *maf, char *src);
+/* Find component of given source or die trying. */
+
+struct mafComp *mafMayFindCompSpecies(struct mafAli *maf, char *species, char sepChar);
+/* Find component of given source that starts with species followed by sepChar or '\0'
+   Return NULL if not found. */
+
+struct mafComp *mafFindCompSpecies(struct mafAli *maf, char *species, char sepChar);
+/* Find component of given source that starts with species followed by sepChar or '\0'
+   or die trying. */
+
+struct mafComp *mafMayFindCompPrefix(struct mafAli *maf, char *pre, char *sep);
+/* Find component of given source that starts with pre followed by sep.
+   Return NULL if not found. */
+
+struct mafComp *mafFindCompPrefix(struct mafAli *maf, char *pre, char *sep);
+/* Find component of given source that starts with pre followed by sep
+   or die trying. */
+
+boolean mafMayFindAllComponents(struct mafAli *maf, struct hash *cHash);
+/* Check to see if all components in hash are in maf block.  Return FALSE if not found. */
+
+struct mafComp *mafMayFindComponentInHash(struct mafAli *maf, struct hash *cHash);
+/* Find arbitrary component of given source that matches any string in the cHash.
+   Return NULL if not found. */
+
+struct mafComp *mafMayFindSpeciesInHash(struct mafAli *maf, struct hash *cHash, char sepChar);
+/* Find arbitrary component of given who's source prefix (ended by sep)
+   matches matches any string in the cHash.  Return NULL if not found. */
+
+void mafMoveComponentToTop(struct mafAli *maf, char *componentSource);
+/* Move given component to head of component list. */
+
+struct mafAli *mafFromAxt(struct axt *pAxt, int tSize, 
+	char *tPrefix, int qSize, char *qPrefix);
+/* Make up a maf file from axt.  Slower than mafFromAxtTemp,
+ * but the axt and maf are independent afterwards. */
+
+void mafFromAxtTemp(struct axt *axt, int tSize, int qSize,
+	struct mafAli *temp);
+/* Make a maf out of axt,  parasiting on the memory in axt.
+ * Do *not* mafFree this temp.  The memory it has in pointers
+ * is still owned by the axt.  Furthermore the next call to
+ * this function will invalidate the previous temp value.
+ * It's sort of a kludge, but quick to run and easy to implement. */
+
+struct mafAli *mafSubset(struct mafAli *maf, char *componentSource,
+	int newStart, int newEnd);
+/* see mafSubsetE below  (called with getInitialDases = FALSE */
+
+struct mafAli *mafSubsetE(struct mafAli *maf, char *componentSource,
+	int newStart, int newEnd, bool getInitialDashes);
+/* Extract subset of maf that intersects a given range
+ * in a component sequence.  The newStart and newEnd
+ * are given in the forward strand coordinates of the
+ * component sequence.  The componentSource is typically
+ * something like 'mm3.chr1'.  This will return NULL
+ * if maf does not intersect range.  The score field
+ * in the returned maf will not be filled in (since
+ * we don't know which scoring scheme to use). 
+ * If getInitialDashes is TRUE then the initial -'s
+ * in the reference sequence are *not* removed*/
+
+boolean mafNeedSubset(struct mafAli *maf, char *componentSource,
+	int newStart, int newEnd);
+/* Return TRUE if maf only partially fits between newStart/newEnd
+ * in given component. */
+
+double mafScoreMultiz(struct mafAli *maf);
+/* Return score of a maf (calculated rather than what is
+ * stored in the structure. */
+
+double mafScoreRangeMultiz(struct mafAli *maf, int start, int size);
+/* Return score of a subset of an alignment.  Parameters are:
+ *    maf - the alignment
+ *    start - the (zero based) offset to start calculating score
+ *    size - the size of the subset
+ * The following relationship should hold:
+ *   scoreRange(maf,start,size) =
+ *	scoreRange(maf,0,start+size) - scoreRange(maf,0,start)
+ */
+
+double mafScoreMultizMaxCol(int species);
+/* Return maximum possible score for a column. */
+
+void mafColMinMaxScore(struct mafAli *maf, 
+	double *retMin, double *retMax);
+/* Get min/max maf scores for a column. */
+
+void mafFlipStrand(struct mafAli *maf);
+/* Reverse complement maf. */
+
+void mafSrcDb(char *name, char *retDb, int retDbSize);
+/* Parse out just database part of name (up to but not including
+ * first dot). If dot found, return entire name */
+
+boolean mafColumnEmpty(struct mafAli *maf, int col);
+/* Return TRUE if the column is all '-' or '.' */
+
+void mafStripEmptyColumns(struct mafAli *maf);
+/* Remove columns that are all '-' or '.' from  maf. */
+
+boolean isContigOrTandem(char status);
+/* is status MAF_CONTIG_STATUS or MAF_TANDEM_STATUS */
+
+struct mafComp *mafCompClone(struct mafComp *srcComp);
+/* clone a mafComp */
+
+struct mafAli *mafAliClone(struct mafAli *srcAli);
+/* clone a mafAli */
+
+#endif /* MAF_H */
+
diff --git a/inc/md5.h b/inc/md5.h
new file mode 100644
index 0000000..a97e435
--- /dev/null
+++ b/inc/md5.h
@@ -0,0 +1,21 @@
+#ifndef MD5_H
+#define MD5_H
+
+#define uint8  unsigned char
+#define uint32 unsigned long int
+#define uint64 unsigned long long int
+
+struct md5_context
+{
+    uint64 total;
+    uint32 state[4];
+    uint8 buffer[64];
+};
+
+void md5_starts( struct md5_context *ctx );
+void md5_update( struct md5_context *ctx, uint8 *input, uint32 length );
+void md5_finish( struct md5_context *ctx, uint8 digest[16] );
+
+#endif /* MD5_H */
+
+
diff --git a/inc/memalloc.h b/inc/memalloc.h
new file mode 100644
index 0000000..eebc92d
--- /dev/null
+++ b/inc/memalloc.h
@@ -0,0 +1,55 @@
+/* Let the user redirect where memory allocation/deallocation
+ * happens.  'careful' routines help debug scrambled heaps. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef MEMALLOC_H
+#define MEMALLOC_H
+
+struct memHandler
+    {
+    struct memHandler *next;
+    void * (*alloc)(size_t size);
+    void (*free)(void *vpt);
+    void * (*realloc)(void* vpt, size_t size);
+    };
+
+struct memHandler *pushMemHandler(struct memHandler *newHandler);
+/* Use newHandler for memory requests until matching popMemHandler.
+ * Returns previous top of memory handler stack. */
+
+struct memHandler *popMemHandler();
+/* Removes top element from memHandler stack and returns it. */
+
+void setDefaultMemHandler();
+/* Sets memHandler to the default. */
+
+void pushCarefulMemHandler(size_t maxAlloc);
+/* Push the careful (paranoid, conservative, checks everything)
+ * memory handler  top of the memHandler stack and use it. */
+
+void carefulCheckHeap();
+/* Walk through allocated memory and make sure that all cookies are
+ * in place. Only walks through what's been done since 
+ * pushCarefulMemHandler(). */
+
+int carefulCountBlocksAllocated();
+/* How many memory items are allocated? (Since called
+ * pushCarefulMemHandler(). */
+
+long carefulTotalAllocated();
+/* Return total bases allocated */
+
+void setMaxAlloc(size_t s);
+/* Set large allocation limit. */
+
+void memTrackerStart();
+/* Push memory handler that will track blocks allocated so that
+ * they can be automatically released with memTrackerEnd().  */
+
+void memTrackerEnd();
+/* Free any remaining blocks and pop tracker memory handler. */
+
+#endif /* MEMALLOC_H */
+
diff --git a/inc/memgfx.h b/inc/memgfx.h
new file mode 100644
index 0000000..c3c3952
--- /dev/null
+++ b/inc/memgfx.h
@@ -0,0 +1,389 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* Memgfx - stuff to do graphics in memory buffers.
+ * Typically will just write these out as .gif or .png files.
+ * This stuff is byte-a-pixel for simplicity.
+ * It can do 256 colors.
+ */
+#ifndef MEMGFX_H
+#define MEMGFX_H
+
+#ifndef GFXPOLY_H
+#include "gfxPoly.h"
+#endif
+
+#ifdef COLOR32
+typedef unsigned int Color;
+
+// BIGENDIAN machines:
+
+#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc) || defined(__ppc__) || defined(__s390__) || defined(__s390x__)
+
+#define MEMGFX_BIGENDIAN	1
+#define MG_WHITE   0xffffffff
+#define MG_BLACK   0x000000ff
+#define MG_RED     0xff0000ff
+#define MG_GREEN   0x00ff00ff
+#define MG_BLUE    0x0000ffff
+#define MG_CYAN    0x00ffffff
+#define MG_MAGENTA 0xff00ffff
+#define MG_YELLOW  0xffff00ff
+#define MG_GRAY    0x808080ff
+
+#define MAKECOLOR_32(r,g,b) (((unsigned int)0xff) | ((unsigned int)b<<8) | ((unsigned int)g << 16) | ((unsigned int)r << 24))
+
+#else
+
+#define MG_WHITE   0xffffffff
+#define MG_BLACK   0xff000000
+#define MG_RED     0xff0000ff
+#define MG_GREEN   0xff00ff00
+#define MG_BLUE    0xffff0000
+#define MG_CYAN    0xffffff00
+#define MG_MAGENTA 0xffff00ff
+#define MG_YELLOW  0xff00ffff
+#define MG_GRAY    0xff808080
+
+#define MAKECOLOR_32(r,g,b) (((unsigned int)0xff<<24) | ((unsigned int)b<<16) | ((unsigned int)g << 8) | (unsigned int)r)
+#endif
+
+#else /* 8-bit color */
+typedef unsigned char Color;
+
+#define MG_WHITE 0
+#define MG_BLACK 1
+#define MG_RED 2
+#define MG_GREEN 3
+#define MG_BLUE 4
+#define MG_CYAN 5
+#define MG_MAGENTA 6
+#define MG_YELLOW 7
+#define MG_GRAY 8
+#define MG_FREE_COLORS_START 9
+
+#endif /* COLOR32 */
+
+#define MG_WRITE_MODE_NORMAL    0
+#define MG_WRITE_MODE_MULTIPLY  (1 << 0)
+
+struct rgbColor
+    {
+    unsigned char r, g, b;
+    };
+
+/* HSV and HSL structs can be used for changing lightness, darkness, or
+ * color of RGB colors. Convert RGB->HS[LV], modify hue, saturation, or
+ * value/lightness, then convert back to RGB.
+ * The datatypes were chosen to be fast but also give accurate conversion
+ * back to RGB.
+ * Hue is a float [0,360) degrees 0=red, 120=green, 240=blue
+ * S/V/L are integers [0,1000]
+ */
+
+struct hsvColor
+    {
+    double h;
+    unsigned short s, v;
+    };
+
+struct hslColor
+    {
+    double h;
+    unsigned short s, l;
+    };
+
+extern struct rgbColor mgFixedColors[9];  /* Contains MG_WHITE - MG_GRAY */
+
+struct memGfx
+    {
+    Color *pixels;
+    int width, height;
+    struct rgbColor colorMap[256];
+    int colorsUsed;
+    int clipMinX, clipMaxX;
+    int clipMinY, clipMaxY;
+    struct colHash *colorHash;	/* Hash for fast look up of color. */
+    unsigned int writeMode;
+    };
+
+struct memGfx *mgNew(int width, int height);
+/* Get a new thing to draw on in memory. */
+
+void mgFree(struct memGfx **pmg);
+/* Free up memory raster. */
+
+void mgClearPixelsTrans(struct memGfx *mg);
+/* Set all pixels to transparent. */
+
+void mgClearPixels(struct memGfx *mg);
+/* Set all pixels to background. */
+
+void mgSetClip(struct memGfx *mg, int x, int y, int width, int height);
+/* Set clipping rectangle. */
+
+void mgUnclip(struct memGfx *mg);
+/* Set clipping rect cover full thing. */
+
+Color mgFindColor(struct memGfx *mg, unsigned char r, unsigned char g, unsigned char b);
+/* Returns closest color in color map to rgb values.  If it doesn't
+ * already exist in color map and there's room, it will create
+ * exact color in map. */
+
+Color mgClosestColor(struct memGfx *mg, unsigned char r, unsigned char g, unsigned char b);
+/* Returns closest color in color map to r,g,b */
+
+Color mgAddColor(struct memGfx *mg, unsigned char r, unsigned char g, unsigned char b);
+/* Adds color to end of color map if there's room. */
+
+int mgColorsFree(struct memGfx *mg);
+/* Returns # of unused colors in color map. */
+
+
+#define _mgBpr(mg) ((mg)->width)
+/* Get what to add to get to next line */
+
+#define _mgPixAdr(mg,x,y) ((mg)->pixels+_mgBpr(mg) * (y) + (x))
+/* Get pixel address */
+
+#define _mgPutDot(mg, x, y, color) (*_mgPixAdr(mg,x,y) = (color))
+/* Unclipped plot a dot */
+
+#define _mgGetDot(mg, x, y) (*_mgPixAdr(mg,x,y))
+/* Unclipped get a dot, you do not want to use this, this is special for
+ * verticalText only */
+
+void _mgPutDotMultiply(struct memGfx *mg, int x, int y,Color color);
+
+INLINE void mgPutDot(struct memGfx *mg, int x, int y,Color color)
+{
+if ((x)>=(mg)->clipMinX && (x) < (mg)->clipMaxX && (y)>=(mg)->clipMinY  && (y) < (mg)->clipMaxY) 
+    {
+        switch(mg->writeMode)
+        {
+        case MG_WRITE_MODE_NORMAL:
+            {
+            _mgPutDot(mg,x,y,color);
+            }
+            break;
+        case MG_WRITE_MODE_MULTIPLY:
+            {
+            _mgPutDotMultiply(mg,x,y,color);
+            }
+            break;
+        }
+    }
+}
+/* Clipped put dot */
+
+#define mgGetDot(mg,x,y) ((x)>=(mg)->clipMinX && (x) < (mg)->clipMaxX && (y)>=(mg)->clipMinY  && (y) < (mg)->clipMaxY) ? _mgGetDot(mg,x,y) : 0
+/* Clipped get dot, you do not want to use this, this is special for
+ * verticalText only */
+
+void mgPutSeg(struct memGfx *mg, int x, int y, int width, Color *dots);
+/* Put a series of dots starting at x, y and going to right width pixels. */
+
+void mgPutSegZeroClear(struct memGfx *mg, int x, int y, int width, Color *dots);
+/* Put a series of dots starting at x, y and going to right width pixels.
+ * Don't put zero dots though. */
+
+void mgDrawBox(struct memGfx *mg, int x, int y, int width, int height, Color color);
+/* Draw a (horizontal) box */
+
+void mgDrawLine(struct memGfx *mg, int x1, int y1, int x2, int y2, Color color);
+/* Draw a line from one point to another. */
+
+void mgDrawHorizontalLine(struct memGfx *mg, int y1, Color color);
+/*special case of mgDrawLine*/
+
+void mgLineH(struct memGfx *mg, int y, int x1, int x2, Color color);
+/* Draw horizizontal line width pixels long starting at x/y in color */
+
+void mgSavePng(struct memGfx *mg, char *filename, boolean useTransparency);
+/* Save memory bitmap to filename as a PNG.
+ * If useTransparency, then the first color in memgfx's colormap/palette is
+ * assumed to be the image background color, and pixels of that color
+ * are made transparent. */
+
+boolean mgSaveToPng(FILE *png_file, struct memGfx *mg, boolean useTransparency);
+/* Save PNG to an already open file.
+ * If useTransparency, then the first color in memgfx's colormap/palette is
+ * assumed to be the image background color, and pixels of that color
+ * are made transparent. */
+
+typedef void (*TextBlit)(int bitWidth, int bitHeight, int bitX, int bitY,
+	unsigned char *bitData, int bitDataRowBytes, 
+	struct memGfx *dest, int destX, int destY, 
+	Color color, Color backgroundColor);
+/* This defines the type of a function that takes a rectangular
+ * area of a bitplane and expands it into a rectangular area
+ * of a full color screen. */
+
+void mgTextBlit(int bitWidth, int bitHeight, int bitX, int bitY,
+	unsigned char *bitData, int bitDataRowBytes, 
+	struct memGfx *dest, int destX, int destY, 
+	Color color, Color backgroundColor);
+/* This function leaves the background as it was. */
+
+void mgTextBlitSolid(int bitWidth, int bitHeight, int bitX, int bitY,
+	unsigned char *bitData, int bitDataRowBytes, 
+	struct memGfx *dest, int destX, int destY, 
+	Color color, Color backgroundColor);
+/* This function sets the background to the background color. */
+
+typedef struct font_hdr MgFont;
+/* Type of our font.  */
+
+/* Collection of fonts from here and there.  The mgTinyFont() and mgSmallFont() are uniq
+ * here.  The rest are synonyms at this point for the adobe fonts below. */
+MgFont *mgTinyFont();
+MgFont *mgSmallFont();
+MgFont *mgMediumFont();
+MgFont *mgLargeFont();
+MgFont *mgHugeFont();
+MgFont *mgTinyBoldFont();
+MgFont *mgSmallBoldFont();
+MgFont *mgMediumBoldFont();
+MgFont *mgLargeBoldFont();
+MgFont *mgHugeBoldFont();
+MgFont *mgTinyFixedFont();
+MgFont *mgSmallFixedFont();
+MgFont *mgMediumFixedFont();
+MgFont *mgLargeFixedFont();
+MgFont *mgHugeFixedFont();
+
+/* Adobe fonts from xfree project. */
+MgFont *mgCourier8Font();
+MgFont *mgCourier10Font();
+MgFont *mgCourier12Font();
+MgFont *mgCourier14Font();
+MgFont *mgCourier18Font();
+MgFont *mgCourier24Font();
+MgFont *mgCourier34Font();
+MgFont *mgHelvetica8Font();
+MgFont *mgHelvetica10Font();
+MgFont *mgHelvetica12Font();
+MgFont *mgHelvetica14Font();
+MgFont *mgHelvetica18Font();
+MgFont *mgHelvetica24Font();
+MgFont *mgHelvetica34Font();
+MgFont *mgHelveticaBold8Font();
+MgFont *mgHelveticaBold10Font();
+MgFont *mgHelveticaBold12Font();
+MgFont *mgHelveticaBold14Font();
+MgFont *mgHelveticaBold18Font();
+MgFont *mgHelveticaBold24Font();
+MgFont *mgHelveticaBold34Font();
+MgFont *mgTimes8Font();
+MgFont *mgTimes10Font();
+MgFont *mgTimes12Font();
+MgFont *mgTimes14Font();
+MgFont *mgTimes18Font();
+MgFont *mgTimes24Font();
+MgFont *mgTimes34Font();
+
+/* free Meslo font */
+MgFont *mgMenloMediumFont();
+
+void mgText(struct memGfx *mg, int x, int y, Color color, 
+	MgFont *font, char *text);
+/* Draw a line of text with upper left corner x,y. */
+
+void mgTextCentered(struct memGfx *mg, int x, int y, int width, int height, 
+	Color color, MgFont *font, char *text);
+/* Draw a line of text centered in box defined by x/y/width/height */
+
+void mgTextRight(struct memGfx *mg, int x, int y, int width, int height, 
+	Color color, MgFont *font, char *text);
+/* Draw a line of text right justified in box defined by x/y/width/height */
+
+int mgFontPixelHeight(MgFont *font);
+/* How high in pixels is font? */
+
+int mgFontLineHeight(MgFont *font);
+/* How many pixels to next line ideally? */
+
+int mgFontWidth(MgFont *font, char *chars, int charCount);
+/* How wide are a couple of letters? */
+
+int mgFontStringWidth(MgFont *font, char *string);
+/* How wide is a string? */
+
+int mgFontCharWidth(MgFont *font, char c);
+/* How wide is a character? */
+
+char *mgFontSizeBackwardsCompatible(char *size);
+/* Given "size" argument that may be in old tiny/small/medium/big/huge format,
+ * return it in new numerical string format. Do NOT free the return string*/
+
+MgFont *mgFontForSizeAndStyle(char *textSize, char *fontType);
+/* Get a font of given size and style.  Abort with error message if not found.
+ * The textSize should be 6,8,10,12,14,18,24 or 34.  For backwards compatibility
+ * textSizes of "tiny" "small", "medium", "large" and "huge" are also ok.
+ * The fontType should be "medium", "bold", or "fixed" */
+
+MgFont *mgFontForSize(char *textSize);
+/* Get a font of given size and style.  Abort with error message if not found.
+ * The textSize should be 6,8,10,12,14,18,24 or 34.  For backwards compatibility
+ * textSizes of "tiny" "small", "medium", "large" and "huge" are also ok. */
+
+void mgFillUnder(struct memGfx *mg, int x1, int y1, int x2, int y2, 
+	int bottom, Color color);
+/* Draw a 4 sided filled figure that has line x1/y1 to x2/y2 at
+ * it's top, a horizontal line at bottom at it's bottom,  and
+ * vertical lines from the bottom to y1 on the left and bottom to
+ * y2 on the right. */
+
+struct memGfx *mgRotate90(struct memGfx *in);
+/* Create a copy of input that is rotated 90 degrees clockwise. */
+
+void mgCircle(struct memGfx *mg, int xCen, int yCen, int rad, 
+	Color color, boolean filled);
+/* Draw a circle using a stepping algorithm.  Doesn't correct
+ * for non-square pixels. */
+
+void mgDrawPoly(struct memGfx *mg, struct gfxPoly *poly, Color color,
+	boolean filled);
+/* Draw polygon, possibly filled in color. */
+
+struct hslColor mgRgbToHsl(struct rgbColor rgb);
+/* Convert RGB to HSL colorspace (see http://en.wikipedia.org/wiki/HSL_and_HSV) 
+ * In HSL, Hue is the color in the range [0,360) with 0=red 120=green 240=blue,
+ * Saturation goes from a shade of grey (0) to fully saturated color (1000), and
+ * Lightness goes from black (0) through the hue (500) to white (1000). */
+
+struct hsvColor mgRgbToHsv(struct rgbColor rgb);
+/* Convert RGB to HSV colorspace (see http://en.wikipedia.org/wiki/HSL_and_HSV)
+ * In HSV, Hue is the color in the range [0,360) with 0=red 120=green 240=blue,
+ * Saturation goes from white (0) to fully saturated color (1000), and
+ * Value goes from black (0) through to the hue (1000). */
+#define hsvValMax 1000
+#define hsvSatMax 1000
+
+struct rgbColor mgHslToRgb(struct hslColor hsl);
+/* Convert HSL to RGB colorspace (see http://en.wikipedia.org/wiki/HSL_and_HSV) */
+
+struct rgbColor mgHsvToRgb(struct hsvColor hsv);
+/* Convert HSV to RGB colorspace (see http://en.wikipedia.org/wiki/HSL_and_HSV) */
+
+struct rgbColor mgRgbTransformHsl(struct rgbColor in, double h, double s, double l);
+/* Transform rgb 'in' value using
+ *   hue shift 'h' (0..360 degrees), 
+ *   saturation scale 's', and 
+ *   lightness scale 'l'
+ * Returns the transformed rgb value 
+ * Use H=0, S=L=1 for identity transformation
+ */
+
+struct rgbColor mgRgbTransformHsv(struct rgbColor in, double h, double s, double v);
+/* Transform rgb 'in' value using
+ *   hue shift 'h' (0..360 degrees), 
+ *   saturation scale 's', and 
+ *   value scale 'v'
+ * Returns the transformed rgb value 
+ * Use H=0, S=V=1 for identity transformation
+ */
+
+#endif /* MEMGFX_H */
diff --git a/inc/metaWig.h b/inc/metaWig.h
new file mode 100644
index 0000000..7856e39
--- /dev/null
+++ b/inc/metaWig.h
@@ -0,0 +1,44 @@
+/* Interface class so that wigs and bigWigs look similar */
+
+#ifndef METAWIG_H
+#define METAWIG_H
+
+#ifndef BBIFILE_H
+#include "bbiFile.h"
+#endif
+
+enum metaWigType 
+    {
+    mwtSections,
+    mwtBigWig,
+    };
+
+struct metaWig
+/* Interface class so that wigs and bigWigs look similar */
+    {
+    struct metaWig *next;
+    enum metaWigType type;
+
+    /* For type mwtSections */
+    struct bwgSection *sectionList;	/* List of all sections. */
+    struct hash *chromHash; 		/* Hash value is first section in that chrom */
+    struct lm *lm;			/* Where sectionList is allocated. */
+
+    /* For type mwtBigWig */
+    struct bbiFile *bwf;
+    };
+
+struct metaWig *metaWigOpen(char *fileName);
+/* Wrap self around file.  Read all of it if it's wig, just header if bigWig. */
+
+void metaWigClose(struct metaWig **pMw);
+/* Close up metaWig file */
+
+struct slName *metaWigChromList(struct metaWig *mw);
+/* Return list of chromosomes covered in wig. */
+
+struct bbiInterval *metaIntervalsForChrom(struct metaWig *mw, char *chrom, struct lm *lm);
+/* Get sorted list of all intervals with data on chromosome. */
+
+#endif /* METAWIG_H */
+
diff --git a/inc/mime.h b/inc/mime.h
new file mode 100644
index 0000000..6ff937c
--- /dev/null
+++ b/inc/mime.h
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ * This file is copyright 2005 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. 
+ *****************************************************************************/
+/* mime.h - parses MIME messages, especially from a cgi from a multipart web form */
+
+#ifndef HASH_H
+#include "hash.h"
+#endif 
+
+#define MIMEBUFSIZE 32*1024  /* size of buffer for mime input */
+
+struct mimePart
+/* structure for an element of a MIME (multipart) message */
+    {
+    struct mimePart *next; /* next (sibling) if is part of multipart */
+    struct hash *hdr;      /* hash of part headers */
+    off_t size;     /* determines if local mem or saved to tempfile */
+      /* only one of the next 3 pointers will be non-null, and that is the type */
+    char* data;     /* if size< MAXPARTSIZE and does not contain null */
+    char* fileName; /* if size>=MAXPARTSIZE or data contains null */
+    boolean binary; /* if contains 0 chars, cannot store as a c-string */
+    struct mimePart *multi;/* points to head of child list if itself contains multiparts */
+    };
+
+struct mimeBuf
+/* structure for buffering a MIME message during parsing */
+    {
+    int d;                  /* descriptor (file,socket,etc) */
+    char buf[MIMEBUFSIZE];  /* actual buffer */
+    char *i;                /* index into buffer, current location */
+    char *eop;              /* end of part or -1 */
+    char *boundary;         /* boundary pattern for marking end of mime part */
+    int  blen;              /* boundary pattern length (strlen) */
+    char *eod;              /* end of data = eoi-(blen-1) */
+    char *eoi;              /* end of input or -1 */
+    char *eom;              /* end of memory just buf+MIMEBUFSIZE */
+    };
+
+char *getMimeHeaderMainVal(char *header);
+/* Parse a typical mime header line returning the first
+ * main value up to whitespace, punctuation, or end. 
+ * freeMem the returned string when done */
+
+char *getMimeHeaderFieldVal(char *header, char *field);
+/* Parse a typical mime header line looking for field=
+ * and return the value which may be quoted.
+ * freeMem the returned string when done */
+
+struct mimeBuf * initMimeBuf(int d);
+/* d is a descriptor for a file or socket or some other descriptor 
+   that the MIME input can be read from. 
+   Initializes the mimeBuf structure. */
+
+struct mimePart *parseMultiParts(struct mimeBuf *b, char *altHeader);
+/* This is a recursive function.  It parses multipart MIME messages.
+   Data that are binary or too large will be saved in mimePart->filename
+   otherwise saved as a c-string in mimePart->data.  If multipart,
+   then first child is mimePart->child, subsequent sibs are in child->next.
+   altHeader is a string of headers that can be fed in if the headers have
+   already been read off the stream by an earlier process, i.e. apache.
+ */
diff --git a/inc/net.h b/inc/net.h
new file mode 100644
index 0000000..91c6882
--- /dev/null
+++ b/inc/net.h
@@ -0,0 +1,248 @@
+/* Net.h some stuff to wrap around net communications. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+
+#ifndef NET_H
+#define NET_H
+
+#include "linefile.h"
+#include "dystring.h"
+
+int netConnect(char *hostName, int port);
+/* Start connection with a server having resolved port. Return < 0 if error. */
+
+int netMustConnect(char *hostName, int port);
+/* Start connection with server or die. */
+
+int netMustConnectTo(char *hostName, char *portName);
+/* Start connection with a server and a port that needs to be converted to integer */
+
+int netAcceptingSocket(int port, int queueSize);
+/* Create a socket for to accept connections. */
+
+int netAcceptingSocketFrom(int port, int queueSize, char *host);
+/* Create a socket that can accept connections from a 
+ * IP address on the current machine if the current machine
+ * has multiple IP addresses. */
+
+int netAccept(int sd);
+/* Accept incoming connection from socket descriptor. */
+
+int netAcceptFrom(int sd, unsigned char subnet[4]);
+/* Wait for incoming connection from socket descriptor
+ * from IP address in subnet.  Subnet is something
+ * returned from netParseDottedQuad.  */
+
+FILE *netFileFromSocket(int socket);
+/* Wrap a FILE around socket.  This should be fclose'd
+ * and separately the socket close'd. */
+
+void netBlockBrokenPipes();
+/* Make it so a broken pipe doesn't kill us. */
+
+size_t netReadAll(int sd, void *vBuf, size_t size);
+/* Read given number of bytes into buffer.
+ * Don't give up on first read! */
+
+int netMustReadAll(int sd, void *vBuf, size_t size);
+/* Read given number of bytes into buffer or die.
+ * Don't give up if first read is short! */
+
+boolean netSendString(int sd, char *s);
+/* Send a string down a socket - length byte first. */
+
+boolean netSendLongString(int sd, char *s);
+/* Send a string down a socket - up to 64k characters. */
+
+boolean netSendHugeString(int sd, char *s);
+/* Send a string down a socket - up to 4G characters. */
+
+char *netRecieveString(int sd, char buf[256]);
+/* Read string into buf and return it.  If buf is NULL
+ * an internal buffer will be used. Abort if any problem. */
+
+char *netRecieveLongString(int sd);
+/* Read string up to 64k and return it.  freeMem
+ * the result when done. Abort if any problem*/
+
+char *netRecieveHugeString(int sd);
+/* Read string up to 4G and return it.  freeMem
+ * the result when done. Abort if any problem*/
+
+char *netGetString(int sd, char buf[256]);
+/* Read string into buf and return it.  If buf is NULL
+ * an internal buffer will be used. Print warning message
+ * and return NULL if any problem. */
+
+char *netGetLongString(int sd);
+/* Read string up to 64k and return it.  freeMem
+ * the result when done.  Print warning message and
+ * return NULL if any problem. */
+
+char *netGetHugeString(int sd);
+/* Read string up to 4 gig and return it.  freeMem
+ * the result when done.  Print warning message and
+ * return NULL if any problem. */
+
+void netCatchPipes();
+/* Set up to catch broken pipe signals. */
+
+boolean netPipeIsBroken();
+/* Return TRUE if pipe is broken */
+
+void  netClearPipeFlag();
+/* Clear broken pipe flag. */
+
+void netParseSubnet(char *in, unsigned char out[4]);
+/* Parse subnet, which is a prefix of a normal dotted quad form.
+ * Out will contain 255's for the don't care bits. */
+
+struct netParsedUrl
+/* A parsed URL. */
+   {
+   char protocol[16];	/* Protocol - http or ftp, etc. */
+   char user[128];	/* User name (optional)  */
+   char password[128];	/* Password  (optional)  */
+   char host[128];	/* Name of host computer - www.yahoo.com, etc. */
+   char port[16];       /* Port, usually 80 or 8080. */
+   char file[1024];	/* Remote file name/query string, starts with '/' */
+   ssize_t byteRangeStart; /* Start of byte range, use -1 for none */
+   ssize_t byteRangeEnd;   /* End of byte range use -1 for none */
+   };
+
+void netParseUrl(char *url, struct netParsedUrl *parsed);
+/* Parse a URL into components.   A full URL is made up as so:
+ *   http://user:password@hostName:port/file;byterange=0-499
+ * User and password may be cgi-encoded.
+ * This is set up so that the http:// and the port are optional. 
+ */
+
+char *urlFromNetParsedUrl(struct netParsedUrl *npu);
+/* Build URL from netParsedUrl structure */
+
+int netUrlOpen(char *url);
+/* Return socket descriptor (low-level file handle) for read()ing url data,
+ * or -1 if error.  Just close(result) when done. */
+
+int netUrlOpenSockets(char *url, int *retCtrlSocket);
+/* Return socket descriptor (low-level file handle) for read()ing url data,
+ * or -1 if error. 
+ * If retCtrlSocket is non-NULL and url is FTP, set *retCtrlSocket
+ * to the FTP control socket which is left open for a persistent connection.
+ * close(result) (and close(*retCtrlSocket) if applicable) when done. */
+
+struct hash;
+
+int netUrlHeadExt(char *url, char *method, struct hash *hash);
+/* Go get head and return status.  Return negative number if
+ * can't get head. If hash is non-null, fill it with header
+ * lines with upper cased keywords for case-insensitive lookup,
+ * including hopefully CONTENT-TYPE: . */
+
+int netUrlHead(char *url, struct hash *hash);
+/* Go get head and return status.  Return negative number if
+ * can't get head. If hash is non-null, fill it with header
+ * lines with upper cased keywords for case-insensitive lookup, 
+ * including hopefully CONTENT-TYPE: . */
+
+long long netUrlSizeByRangeResponse(char *url);
+/* Use byteRange as a work-around alternate method to get file size (content-length).  
+ * Return negative number if can't get. */
+
+struct lineFile *netLineFileOpen(char *url);
+/* Return a lineFile attached to url.  This one
+ * will skip any headers.   Free this with
+ * lineFileClose(). */
+
+struct lineFile *netLineFileMayOpen(char *url);
+/* Same as netLineFileOpen, but warns and returns
+ * null rather than aborting on problems. */
+
+struct lineFile *netLineFileSilentOpen(char *url);
+/* Open a lineFile on a URL.  Just return NULL without any user
+ * visible warning message if there's a problem. */
+
+struct dyString *netSlurpFile(int sd);
+/* Slurp file into dynamic string and return.  Result will include http headers and
+ * the like. */
+
+struct dyString *netSlurpUrl(char *url);
+/* Go grab all of URL and return it as dynamic string.  Result will include http headers
+ * and the like. This will errAbort if there's a problem. */
+
+char *netReadTextFileIfExists(char *url);
+/* Read entire URL and return it as a string.  URL should be text (embedded zeros will be
+ * interpreted as end of string).  If the url doesn't exist or has other problems,
+ * returns NULL. Does *not* include http headers. */
+
+struct lineFile *netHttpLineFileMayOpen(char *url, struct netParsedUrl **npu);
+/* Parse URL and open an HTTP socket for it but don't send a request yet. */
+
+void netHttpGet(struct lineFile *lf, struct netParsedUrl *npu,
+		boolean keepAlive);
+/* Send a GET request, possibly with Keep-Alive. */
+
+int netOpenHttpExt(char *url, char *method, char *optionalHeader);
+/* Return a file handle that will read the url.  optionalHeader
+ * may by NULL or may contain cookies and other info. */
+
+int netHttpConnect(char *url, char *method, char *protocol, char *agent, char *optionalHeader);
+/* Parse URL, connect to associated server on port, and send most of
+ * the request to the server.  If specified in the url send user name
+ * and password too.  Typically the "method" will be "GET" or "POST"
+ * and the agent will be the name of your program or
+ * library. optionalHeader may be NULL or contain additional header
+ * lines such as cookie info. 
+ * Proxy support via hg.conf httpProxy or env var http_proxy
+ * Return data socket, or -1 if error.*/
+
+int netHttpGetMultiple(char *url, struct slName *queries, void *userData,
+		       void (*responseCB)(void *userData, char *req,
+					  char *hdr, struct dyString *body));
+/* Given an URL which is the base of all requests to be made, and a 
+ * linked list of queries to be appended to that base and sent in as 
+ * requests, send the requests as a batch and read the HTTP response 
+ * headers and bodies.  If not all the requests get responses (i.e. if 
+ * the server is ignoring Keep-Alive or is imposing a limit), try again 
+ * until we can't connect or until all requests have been served. 
+ * For each HTTP response, do a callback. */
+
+
+boolean netSkipHttpHeaderLinesWithRedirect(int sd, char *url, char **redirectedUrl);
+/* Skip http header lines. Return FALSE if there's a problem.
+ * The input is a standard sd or fd descriptor.
+ * This is meant to be able work even with a re-passable stream handle,
+ * e.g. can pass it to the pipes routines, which means we can't
+ * attach a linefile since filling its buffer reads in more than just the http header.
+ * Handles 300, 301, 302, 303, 307 http redirects by setting *redirectedUrl to
+ * the new location. */
+
+boolean netSkipHttpHeaderLinesHandlingRedirect(int sd, char *url, int *redirectedSd, char **redirectedUrl);
+/* Skip http headers lines, returning FALSE if there is a problem.  Generally called as
+ *    netSkipHttpHeaderLine(sd, url, &sd, &url);
+ * where sd is a socket (file) opened with netUrlOpen(url), and url is in dynamic memory.
+ * If the http header indicates that the file has moved, then it will update the *redirectedSd and
+ * *redirectedUrl with the new socket and URL, first closing sd.
+ * If for some reason you want to detect whether the forwarding has occurred you could
+ * call this as:
+ *    char *newUrl = NULL;
+ *    int newSd = 0;
+ *    netSkipHttpHeaderLine(sd, url, &newSd, &newUrl);
+ *    if (newUrl != NULL)
+ *          // Update sd with newSd, free url if appropriate and replace it with newUrl, etc.
+ *          //  free newUrl when finished.
+ * This routine handles up to 5 steps of redirection.
+ * The logic to this routine is also complicated a little to make it work in a pipe, which means we
+ * can't attach a lineFile since filling the lineFile buffer reads in more than just the http header. */
+
+boolean netGetFtpInfo(char *url, long long *retSize, time_t *retTime);
+/* Return date in UTC and size of ftp url file */
+
+
+boolean parallelFetch(char *url, char *outPath, int numConnections, int numRetries, boolean newer, boolean progress);
+/* Open multiple parallel connections to URL to speed downloading */
+
+#endif /* NET_H */
+
diff --git a/inc/nib.h b/inc/nib.h
new file mode 100644
index 0000000..622a213
--- /dev/null
+++ b/inc/nib.h
@@ -0,0 +1,113 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* nib.h - interface to nucleotides stored 4 bits per base (so have
+ * room for N. */
+#ifndef NIB_H
+#define NIB_H
+
+#ifndef DNAUTIL_H
+#include "dnautil.h"
+#endif 
+
+#ifndef HASH_H
+#include "hash.h"
+#endif
+
+/** Options for controlling masking  */
+#define NIB_MASK_MIXED    0x01 /* Read uses case to indicate masking.
+                                * Write sets mask bit for lower-case */
+#define NIB_MASK_MAP      0x02 /* Read builds dnaSeq->mask bit map. Write
+                                * uses mask to set mask bases.  Note: the
+                                * bit map indicates which bases are not repeats
+                                */
+#define NIB_BASE_NAME     0x04 /* Return a sequence name that is the base name
+                                * the file. */
+
+void nibOpenVerify(char *fileName, FILE **retFile, int *retSize);
+/* Open file and verify it's in good nibble format. */
+
+struct dnaSeq *nibLoadPart(char *fileName, int start, int size);
+/* Load part of an .nib file. */
+
+struct dnaSeq *nibLoadPartMasked(int options, char *fileName, int start, int size);
+/* Load part of an .nib file, with control over handling of masked positions */
+
+struct dnaSeq *nibLdPart(char *fileName, FILE *f, int seqSize, int start, int size);
+/* Load part of an open .nib file. */
+
+struct dnaSeq *nibLdPartMasked(int options, char *fileName, FILE *f, int seqSize, int start, int size);
+/* Load part of an open .nib file, with control over handling of masked
+ * positions. */
+
+struct dnaSeq *nibLoadAll(char *fileName);
+/* Load all of a nib file. */
+
+struct dnaSeq *nibLoadAllMasked(int options, char *fileName);
+/* Load part of a .nib file, with control over handling of masked
+ * positions. Subranges of nib files may specified in the file name
+ * using the syntax:
+ *    /path/file.nib:seqid:start-end
+ * or\n"
+ *    /path/file.nib:start-end
+ * With the first form, seqid becomes the id of the subrange, with the second
+ * form, a sequence id of file:start-end will be used.
+ */
+
+void nibWrite(struct dnaSeq *seq, char *fileName);
+/* Write out file in format of four bits per nucleotide. */
+
+void nibWriteMasked(int options, struct dnaSeq *seq, char *fileName);
+/* Write out file in format of four bits per nucleotide, with control over
+ * handling of masked positions. */
+
+boolean nibIsFile(char *fileName);
+/* Return TRUE if file is a nib file. */
+
+boolean nibIsRange(char *fileName);
+/* Return TRUE if file specifies a subrange of a nib file. */
+
+void nibParseName(unsigned options, char *fileSpec, char *filePath,
+                         char *name, unsigned *start, unsigned *end);
+/* Parse the nib name, getting the file name, seq name to use, and
+ * optionally the start and end positions. Zero is return for start
+ * and end if they are not specified. Return the path to the file
+ * and the name to use for the sequence. */
+
+struct nibStream *nibStreamOpen(char *fileName);
+/* Create a new nib stream.  Open file and stuff. */
+
+void nibStreamClose(struct nibStream **pNs);
+/* Close a nib stream.  Flush last nibble if need be.  Fix up header. */
+
+void nibStreamOne(struct nibStream *ns, DNA base);
+/* Write out one base to nibStream. */
+
+void nibStreamMany(struct nibStream *ns, DNA *dna, int size);
+/* Write many bases to nibStream. */
+
+struct nibInfo
+/* Info on a nib file. */
+    {
+    struct nibInfo *next;
+    char *fileName;	/* Name of nib file. */
+    int size;		/* Number of bases in nib. */
+    FILE *f;		/* Open file. */
+    };
+
+struct nibInfo *nibInfoNew(char *path);
+/* Make a new nibInfo with open nib file. */
+
+void nibInfoFree(struct nibInfo **pNib);
+/* Free up nib info and close file if open. */
+
+struct nibInfo *nibInfoFromCache(struct hash *hash, char *nibDir, char *nibName);
+/* Get nibInfo on nibDir/nibName.nib from cache, filling cache if need be. */
+
+int nibGetSize(char* nibFile);
+/* Get the number of nucleotides in a nib */
+
+#endif /* NIB_H */
+
diff --git a/inc/nibTwo.h b/inc/nibTwo.h
new file mode 100644
index 0000000..c9466ce
--- /dev/null
+++ b/inc/nibTwo.h
@@ -0,0 +1,55 @@
+/* nibTwo - Something to let you transparently access either
+ * .2bit or .nib files. */
+
+#ifndef NIBTWO_H
+#define NIBTWO_H
+
+#ifndef NIB_H
+#include "nib.h"
+#endif
+
+#ifndef TWOBIT_H
+#include "twoBit.h"
+#endif
+
+struct nibTwoCache
+/* This is a cache for either a directory full of nib files or a .2bit file. */
+    {
+    struct nibTwoCache *next;	/* Next in list */
+    char *pathName;		/* Nib dir name or .2bit file name. */
+    boolean isTwoBit;		/* True if this is a .2bit file. */
+    struct twoBitFile *tbf;	/* Two bit file handle if any. */
+    struct hash *nibHash;	/* Hash of nibInfo's if any. */
+    };
+
+struct nibTwoCache *nibTwoCacheNew(char *pathName);
+/* Get something that will more or less transparently get sequence from 
+ * nib files or .2bit. */ 
+
+void nibTwoCacheFree(struct nibTwoCache **pNtc);
+/* Free up resources associated with nibTwoCache. */
+
+struct dnaSeq *nibTwoCacheSeq(struct nibTwoCache *ntc, char *seqName);
+/* Return all of sequence. This will have repeats in lower case. */
+
+struct dnaSeq *nibTwoCacheSeqPartExt(struct nibTwoCache *ntc, char *seqName, int start, int size,
+                                     boolean doMask, int *retFullSeqSize);
+/* Return part of sequence. If *retFullSeqSize is non-null then return full
+ * size of sequence (not just loaded part) there.   Sequence will be lower
+ * case if doMask is false, mixed case (repeats in lower)
+ * if doMask is true. */
+
+struct dnaSeq *nibTwoCacheSeqPart(struct nibTwoCache *ntc, char *seqName, 
+	int start, int size, int *retFullSeqSize);
+/* Return part of sequence. If *retFullSeqSize is non-null then return full size of
+ * sequence (not just loaded part) there. This will have repeats in lower case. */
+
+struct dnaSeq *nibTwoLoadOne(char *pathName, char *seqName);
+/* Return sequence from a directory full of nibs or a .2bit file. 
+ * The sequence will have repeats in lower case. */
+
+int nibTwoGetSize(struct nibTwoCache *ntc, char *seqName);
+/* Return size of sequence. */
+
+#endif /* NIBTWO_H */
+
diff --git a/inc/nt4.h b/inc/nt4.h
new file mode 100644
index 0000000..a04e382
--- /dev/null
+++ b/inc/nt4.h
@@ -0,0 +1,45 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+#ifndef NT4_H
+#define NT4_H
+
+#ifndef DNAUTIL_H
+#include "dnautil.h"
+#endif
+
+struct nt4Seq
+/* A packed (2 bits per nucleotide) sequence.  'N's are
+ * converted to 'T's. */
+    {
+    struct nt4Seq *next;	/* Next in list. */
+    bits32 *bases;              /* Packed bases. */
+    int baseCount;              /* Number of bases. */
+    char *name;                 /* Name of sequence. */
+    };
+
+struct nt4Seq *newNt4(DNA *dna, int size, char *name);
+/* Create a new DNA seq with 2 bits per base pair. */
+
+void freeNt4(struct nt4Seq **pSeq);
+/* Free up DNA seq with 2 bits per base pair */
+
+struct nt4Seq *loadNt4(char *fileName, char *seqName);
+/* Load up an nt4 sequence from a file. */
+
+void  saveNt4(char *fileName, DNA *dna, bits32 dnaSize);
+/* Save dna in an NT4 file. */
+
+int nt4BaseCount(char *fileName);
+/* Return number of bases in NT4 file. */
+
+DNA *nt4Unpack(struct nt4Seq *n, int start, int size);
+/* Create an unpacked section of nt4 sequence.  */
+
+DNA *nt4LoadPart(char *nt4FileName, int start, int size);
+/* Load part of an nt4 file. */
+
+#endif /* _4NT_H */
+
diff --git a/inc/obscure.h b/inc/obscure.h
new file mode 100644
index 0000000..42a4ab6
--- /dev/null
+++ b/inc/obscure.h
@@ -0,0 +1,174 @@
+/* Obscure.h  - stuff that's relatively rarely used
+ * but still handy. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef OBSCURE_H
+#define OBSCURE_H
+
+long incCounterFile(char *fileName);
+/* Increment a 32 bit value on disk. */
+
+int digitsBaseTwo(unsigned long x);
+/* Return base two # of digits. */
+
+int digitsBaseTen(int x);
+/* Return number of digits base 10. */
+
+void sprintLongWithCommas(char *s, long long l);
+/* Print out a long number with commas a thousands, millions, etc. */
+
+void printLongWithCommas(FILE *f, long long l);
+/* Print out a long number with commas a thousands, millions, etc. */
+
+void sprintWithGreekByte(char *s, int slength, long long size);
+/* Numbers formatted with PB, TB, GB, MB, KB, B */
+
+void writeGulp(char *file, char *buf, int size);
+/* Write out a bunch of memory. */
+
+void readInGulp(char *fileName, char **retBuf, size_t *retSize);
+/* Read whole file in one big gulp. */
+
+void readAllWords(char *fileName, char ***retWords, int *retWordCount, char **retBuf);
+/* Read in whole file and break it into words. You need to freeMem both
+ * *retWordCount and *retBuf when done. */
+
+int countWordsInFile(char *fileName);
+/* Count number of words in file. */
+
+struct slName *readAllLines(char *fileName);
+/* Read all lines of file into a list.  (Removes trailing carriage return.) */
+
+void copyFile(char *source, char *dest);
+/* Copy file from source to dest. */
+
+void copyOpenFile(FILE *inFh, FILE *outFh);
+/* copy an open stdio file */
+
+void cpFile(int s, int d);
+/* Copy from source file to dest until reach end of file. */
+
+void *intToPt(int i);
+/* Convert integer to pointer. Use when really want to store an
+ * int in a pointer field. */
+
+int ptToInt(void *pt);
+/* Convert pointer to integer.  Use when really want to store a
+ * pointer in an int. */
+
+void *sizetToPt(size_t i);
+/* Convert size_t to pointer. Use when really want to store a
+ * size_t in a pointer. */
+
+size_t ptToSizet(void *pt);
+/* Convert pointer to size_t.  Use when really want to store a
+ * pointer in a size_t. */
+
+boolean parseQuotedStringNoEscapes( char *in, char *out, char **retNext);
+/* Read quoted string from in (which should begin with first quote).
+ * Write unquoted string to out, which may be the same as in.
+ * Return pointer to character past end of string in *retNext. 
+ * Return FALSE if can't find end.
+ * Unlike parseQuotedString() do not treat backslash as an escape
+ *	character, merely pass it on through.
+ */
+
+boolean parseQuotedString( char *in, char *out, char **retNext);
+/* Read quoted string from in (which should begin with first quote).
+ * Write unquoted string to out, which may be the same as in.
+ * Return pointer to character past end of string in *retNext. 
+ * Return FALSE if can't find end. */
+
+char *nextQuotedWord(char **pLine);
+/* Generalization of nextWord.  Returns next quoted
+ * string or if no quotes next word.  Updates *pLine
+ * to point past word that is returned. Does not return
+ * quotes. */
+
+char *makeQuotedString(char *in, char quoteChar);
+/* Create a string surrounded by quoteChar, with internal
+ * quoteChars escaped.  freeMem result when done. */
+
+char *makeEscapedString(char *in, char toEscape);
+/* Return string that is a copy of in, but with all
+ * toEscape characters preceded by '\' 
+ * When done freeMem result. */
+
+void escCopy(char *in, char *out, char toEscape, char escape);
+/* Copy in to out, escaping as needed.  Out better be big enough. 
+ * (Worst case is strlen(in)*2 + 1.) */
+
+struct slName *stringToSlNames(char *string);
+/* Convert string to a list of slNames separated by
+ * white space, but allowing multiple words in quotes.
+ * Quotes if any are stripped.  */
+
+struct slName *commaSepToSlNames(char *commaSep);
+/* Convert comma-separated list of items to slName list. */
+
+struct slName *charSepToSlNames(char *string, char c);
+/* Convert character-separated list of items to slName list. 
+ * Note that the last occurence of c is optional.  (That
+ * is for a comma-separated list a,b,c and a,b,c, are
+ * equivalent. */
+
+struct hash *hashVarLine(char *line, int lineIx);
+/* Return a symbol table from a line of form:
+ *   var1=val1 var2='quoted val2' var3="another val" */
+
+struct hash *hashThisEqThatLine(char *line, int lineIx, boolean firstStartsWithLetter);
+/* Return a symbol table from a line of form:
+ *   1-this1=val1 2-this='quoted val2' var3="another val" 
+ * If firstStartsWithLetter is true, then the left side of the equals must start with
+ * and equals. */
+
+struct hash *hashWordsInFile(char *fileName, int hashSize);
+/* Create a hash of space delimited words in file. 
+ * hashSize is as in hashNew() - pass 0 for default. */
+
+struct hash *hashNameIntFile(char *fileName);
+/* Given a two column file (name, integer value) return a
+ * hash keyed by name with integer values */
+
+struct hash *hashTwoColumnFile(char *fileName);
+/* Given a two column file (key, value) return a hash. */
+
+void shuffleArrayOfPointers(void *pointerArray, int arraySize, 
+	int shuffleCount);
+/* Shuffle array of pointers of given size given number of times. */
+
+void shuffleList(void *pList, int shuffleCount);
+/* Randomize order of slList.  Usage:
+ *     shuffleList(&list)
+ * where list is a pointer to a structure that
+ * begins with a next field. */
+
+char *stripCommas(char *position);
+/* make a new string with commas stripped out */
+
+void dotForUserInit(int dotMod);
+/* Set how often dotForUser() outputs a dot. */
+
+void dotForUser();
+/* Write out a dot every _dotForUserMod times this is called. */
+
+void spaceToUnderbar(char *s);
+/* Convert white space to underbar. */
+
+void rangeRoundUp(double start, double end, double *retStart, double *retEnd);
+/* Round start and end so that they cover a slightly bigger range, but with more round
+ * numbers.  For instance 0.23:9.89 becomes 0:10 */
+
+void rangeFromMinMaxMeanStd(double minVal, double maxVal, double mean, double std,
+	double *retStart, double *retEnd);
+/* Given some basic statistical properties, set a range that will be good on a wide
+ * range of biological data. */
+
+void printVmPeak();
+/* print to stderr peak Vm memory usage (if /proc/ business exists) */
+
+boolean nameInCommaList(char *name, char *commaList);
+/* Return TRUE if name is in comma separated list. */
+#endif /* OBSCURE_H */
diff --git a/inc/oldGff.h b/inc/oldGff.h
new file mode 100644
index 0000000..550e9cc
--- /dev/null
+++ b/inc/oldGff.h
@@ -0,0 +1,103 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* oldGff.h - This reads a *special* type of .GFF file.  
+ * Some of the routines herein expect the gff file to include
+ * both DNA and gene/intron/exon info.  They expect the
+ * genes to be named by the group field. */
+#ifndef OLDGFF_H
+#define OLDGFF_H
+
+struct gff
+/* This is the structure that holds info on a gff file.
+ */
+    {
+    char fileName[256];
+    FILE *file;
+    long fileSize;
+    char buf[256];
+    int bufSize;
+    int bytesInBuf;
+    int readIx;
+    int lineNumber;
+    struct lm *memPool;
+    char *dna;
+    long dnaSize;
+    char dnaName[128];
+    struct gffGene *genes;
+    };
+
+/* An intron or exon - just an offset into a DNA array. */
+struct gffSegment
+    {
+    struct gffSegment *next;	/* This must be first field! */
+    long start, end;
+    int frame;
+    };
+typedef struct gffSegment GffIntron;
+typedef struct gffSegment GffExon;
+
+struct gffGene
+/* At the end of a GFF file are a number of genes, each of which 
+ * is a list of exons/introns. */
+    {
+    struct gffGene *next;	/* This must be first field! */
+    long start, end;
+    int frame;
+    char strand;	/* + or - */
+    char name[64];
+    GffExon *exons;
+    GffIntron *introns;
+    DNA *dna;
+    long dnaSize;
+    };
+
+
+boolean gffOpen(struct gff *gff, char *fileName);
+/* Initialize gff structure and open file for it. */
+
+boolean gffOpenAndRead(struct gff *gff, char *fileName);
+/* Open up gff file and read everything in it. */
+
+void gffClose(struct gff *gff);
+/* Close down gff structure. */
+
+boolean gffReadDna(struct gff *gff);
+/* Read all the DNA in a file. */
+
+struct gffGene *gffFindGene(struct gff *gff, char *geneName);
+/* Find gene with given name.  Case sensitive. */
+
+struct gffGene *gffFindGeneIgnoreCase(struct gff *gff, char *geneName);
+/* Find gene with given name.  Not case sensitive. */
+
+void gffPrintInfo(struct gff *gff, FILE *out);
+/* Print summary info about file. */
+
+boolean gffReadGenes(struct gff *gff);
+/* Read all the gene (as opposed to base) info in file. */
+
+struct gffGene *gffDupeGene(struct gff *gff, struct gffGene *oldGene);
+/* Make a duplicate of gene (with it's own DNA). gffFreeGene it when done. */
+
+struct gffGene *gffDupeGeneAndSurrounds(struct gff *gff, struct gffGene *oldGene,
+    int leftExtra, int rightExtra);
+/* Make a duplicate of gene with extra DNA around coding region. 
+ * gffFreeGene it when done. */
+
+struct gffGene *gffGeneWithOwnDna(struct gff *gff, char *geneName);
+/* Find gene with given name.  Case sensitive. */
+
+void gffFreeGene(struct gffGene **pGene);
+/* Free a gene returned with dupeGene or geneWithOwnDna. 
+ * (You don't want to free the ones returned by findGene,
+ * they are still owned by the gff.)
+ */
+
+struct dnaSeq *gffReadDnaSeq(char *fileName);
+/* Open gff file and read DNA sequence from it. */
+
+#endif /* GFF_H */
+
diff --git a/inc/oligoTm.h b/inc/oligoTm.h
new file mode 100644
index 0000000..d2490bd
--- /dev/null
+++ b/inc/oligoTm.h
@@ -0,0 +1,98 @@
+/* oligoTm - calculate melting temperature of relatively short DNA sequences.
+ * This is based on the nearest-neighbor thermodynamics of bases from Breslauer,
+ * Frank, Bloecker, and Markey, Proc. Natl. Acad. Sci. USA, vol 83, page 3748,
+ * and uses work from see Rychlik, Spencer, Roads, Nucleic Acids Research, vol 18, 
+ * no 21.  This code was imported from the oligotm module of Whitehead Institute's
+ * primer3 program, and adapted into UCSC conventions by Jim Kent.  Any redistribution
+ * of this code should contain the following copyright notice from Whitehead:
+ *
+ * Copyright (c) 1996,1997,1998,1999,2000,2001,2004
+ *         Whitehead Institute for Biomedical Research. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * 1.      Redistributions must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the  documentation
+ * and/or other materials provided with the distribution.  Redistributions of
+ * source code must also reproduce this information in the source code itself.
+ * 
+ * 2.      If the program is modified, redistributions must include a notice
+ * (in the same places as above) indicating that the redistributed program is
+ * not identical to the version distributed by Whitehead Institute.
+ * 
+ * 3.      All advertising materials mentioning features or use of this
+ * software  must display the following acknowledgment:
+ *         This product includes software developed by the
+ *         Whitehead Institute for Biomedical Research.
+ * 
+ * 4.      The name of the Whitehead Institute may not be used to endorse or
+ * promote products derived from this software without specific prior written
+ * permission.
+ * 
+ * We also request that use of this software be cited in publications as 
+ * 
+ *   Rozen, S., Skaletsky, H.  \"Primer3 on the WWW for general users
+ *   and for biologist programmers.\"  In S. Krawetz and S. Misener, eds.
+ *   Bioinformatics Methods and Protocols in the series Methods in 
+ *   Molecular Biology.  Humana Press, Totowa, NJ, 2000, pages 365-386.
+ *   Code available at
+ *   http://fokker.wi.mit.edu/primer3/.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE WHITEHEAD INSTITUTE ``AS IS'' AND  ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE WHITEHEAD INSTITUTE BE LIABLE  FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+
+#ifndef OLIGOTM_H
+#define OLIGOTM_H
+
+double oligoTm(char *dna, double DNA_nM, double K_mM);
+/* Calculate melting point of short DNA sequence given DNA concentration in 
+ * nanomoles, and salt concentration in millimoles.  This is calculated using eqn
+ * (ii) in Rychlik, Spencer, Roads, Nucleic Acids Research, vol 18, no 21, page
+ * 6410, with tables of nearest-neighbor thermodynamics for DNA bases as
+ * provided in Breslauer, Frank, Bloecker, and Markey,
+ * Proc. Natl. Acad. Sci. USA, vol 83, page 3748. */
+
+double oligoDg(char *dna);
+/* Calculate dg (change in Gibb's free energy) from melting oligo
+ * the nearest neighbor model. Seq should be relatively short, given 
+ * the characteristics of the nearest neighbor model (36 bases or less
+ * is best). */
+
+double longSeqTm(char *s, int start, int len, double salt_conc);
+/* Calculate the melting temperature of substr(seq, start, length) using the
+ * formula from Bolton and McCarthy, PNAS 84:1390 (1962) as presented in
+ * Sambrook, Fritsch and Maniatis, Molecular Cloning, p 11.46 (1989, CSHL
+ * Press).
+ *
+ * Tm = 81.5 + 16.6(log10([Na+])) + .41*(%GC) - 600/length
+ *
+ * Where [Na+] is the molar sodium concentration, (%GC) is the percent of Gs
+ * and Cs in the sequence, and length is the length of the sequence.
+ *
+ * A similar formula is used by the prime primer selection program in GCG
+ * (http://www.gcg.com), which instead uses 675.0 / length in the last term
+ * (after F. Baldino, Jr, M.-F. Chesselet, and M.E.  Lewis, Methods in
+ * Enzymology 168:766 (1989) eqn (1) on page 766 without the mismatch and
+ * formamide terms).  The formulas here and in Baldino et al. assume Na+ rather
+ * than K+.  According to J.G. Wetmur, Critical Reviews in BioChem. and
+ * Mol. Bio. 26:227 (1991) 50 mM K+ should be equivalent in these formulae to .2
+ * M Na+.
+ *
+ * This function takes salt_conc to be the millimolar (mM) concentration,
+ * since mM is the usual units in PCR applications.  */
+
+double seqTm(char *seq, double dna_conc, double salt_conc);
+/* Figure out melting temperature of sequence of any length given
+ * dna and salt concentration. */
+#endif /* OLIGOTM_H */
+
diff --git a/inc/ooc.h b/inc/ooc.h
new file mode 100644
index 0000000..5b0bd9b
--- /dev/null
+++ b/inc/ooc.h
@@ -0,0 +1,16 @@
+/* ooc.h - Stuff to handle overused N-mers (tiles) in genome
+ * indexing schemes. */
+/* Copyright 2001-2002 Jim Kent.  All rights reserved. */
+
+#ifndef OOC_H
+#define OOC_H
+
+void oocMaskCounts(char *oocFile, bits32 *tileCounts, int tileSize, bits32 maxPat);
+/* Set items of tileCounts to maxPat if they are in oocFile. 
+ * Effectively masks this out of index.*/
+
+void oocMaskSimpleRepeats(bits32 *tileCounts, int seedSize, bits32 maxPat);
+/* Mask out simple repeats in index . */
+
+#endif /* OOC_H */
+
diff --git a/inc/options.h b/inc/options.h
new file mode 100644
index 0000000..58601e0
--- /dev/null
+++ b/inc/options.h
@@ -0,0 +1,97 @@
+/* Stuff to process options out of command line. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef OPTIONS_H
+#define OPTIONS_H
+
+#include "common.h"
+
+/* Types for options */
+#define OPTION_BOOLEAN    0x01
+#define OPTION_STRING     0x02
+#define OPTION_INT        0x04
+#define OPTION_FLOAT      0x10
+#define OPTION_LONG_LONG  0x20
+#define OPTION_MULTI      0x40
+#define OPTION_DOUBLE	  0x80
+
+/* Mask for option types (excluding OPTION_MULTI) */
+#define OPTION_TYPE_MASK (OPTION_BOOLEAN|OPTION_STRING|OPTION_INT|OPTION_FLOAT|OPTION_LONG_LONG|OPTION_DOUBLE)
+
+struct optionSpec
+/* Specification of a single option.  An array of these are passed
+ * to optionInit() to validate options. */
+{
+    char *name;      /* option name */
+    unsigned flags;  /* Flags for option, specifies types */
+};
+
+char *optionVal(char *name, char *defaultVal);
+/* Return named option if in options hash, otherwise default. */
+
+int optionInt(char *name, int defaultVal);
+/* Return integer value of named option, or default value
+ * if not set. */
+
+long long optionLongLong(char *name, long long defaultVal);
+/* Return long long value of named option, or default value
+ * if not set. */
+
+float optionFloat(char *name, float defaultVal);
+/* Return floating point value or default value if not set. */
+
+struct slName *optionMultiVal(char *name, struct slName *defaultVal);
+/* Returns a list of the values assocated with a named option if in options hash, otherwise default. */
+
+double optionDouble(char *name, double defaultVal);
+/* Return double value or default value if not set */
+
+boolean optionExists(char *name);
+/* Return TRUE if option has been set. */
+
+void optionMustExist(char *name);
+/* Abort if option has not been set. */
+
+void optionInit(int *pArgc, char *argv[], struct optionSpec *optionSpecs);
+/* Read options in command line into options hash.
+ * Options come in three forms:
+ *      -option         words starting with dash
+ *      option=val      words with = in the middle
+ *      -option=val     combining the two.
+ * The resulting hash will be keyed by the option name with the val
+ * string for value.  For '-option' types the value is 'on'.
+ * The words in argv are parsed in assending order.  If a word of
+ * "--" is encountered, argument parsing stops.
+ * If optionSpecs is not NULL, it is an array of optionSpec that are
+ * used to validate the options.  An option must exist in the array
+ * and the value must be convertable to the type specified in flags.
+ * Boolean options have must no value, all other options must have one.
+ * Array is terminated by a optionSpec with a NULL name.
+ * If array NULL, no validation is done.
+ */
+
+void optionHash(int *pArgc, char *argv[]);
+/* Read options in command line into options hash.   
+ * Options come in three forms:
+ *      -option         words starting with dash
+ *      option=val      words with = in the middle
+ *      -option=val     combining the two.
+ * The resulting hash will be keyed by the option name with the val
+ * string for value.  For '-option' types the value is 'on'.
+ * The words in argv are parsed in assending order.  If a word of
+ * "--" is encountered, argument parsing stops. */
+
+void optionHashSome(int *pArgc, char *argv[], boolean justFirst);
+/* Set up option hash from command line, optionally only adding
+ * up to first non-optional word. */
+
+struct hash *optionParseIntoHash(int *pArgc, char *argv[], boolean justFirst);
+/* Read options in argc/argv into a hash of your own choosing. */
+
+void optionFree();
+/* free the option hash */
+
+#endif /* OPTIONS_H */
+
diff --git a/inc/pairHmm.h b/inc/pairHmm.h
new file mode 100644
index 0000000..a054006
--- /dev/null
+++ b/inc/pairHmm.h
@@ -0,0 +1,94 @@
+/* pairHmm - stuff to help implement pairwise hidden markov models,
+ * which are useful ways of aligning two sequences. 
+ *
+ * This file is copyright 2000-2004 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef PAIRHMM_H
+#define PAIRHMM_H
+
+/* Mommy coding scheme - this is how one cell in the dynamic programming table
+ * points to it's parent (mommy) cell.  Since these tables are really big,
+ * rather than use a simple pointer costing four bytes, we use a encoding
+ * scheme that requires only one byte. 
+ *
+ * Bits 0-4  the "hidden" state of the mommy.  Lets us have 32 hidden states.
+ *           currently only using 7.
+ * Bit  5    whether or not mommy is in previous cell in query
+ * Bit  6    whether or not mommy is in previous cell in target
+ * Bit  7    set during trace back for cells along optimal path
+ *
+ * Since the query and target advancing bits (5 and 6) are never both zero,
+ * it is safe to use the value of all-bits-zero as an indicator of
+ * no mommy. */
+
+/* Compress state, query, and target offset into one byte. */
+#define phmmPackMommy(stateIx, qOff, tOff) ((UBYTE)((stateIx) + ((-(qOff))<<5) + ((-(tOff))<<6)))
+
+/* Traceback sets this, really just for debugging. */
+#define phmmMommyTraceBit (1<<7)
+
+struct phmmMommy
+/* This contains the parent info for a single state of the matrix. */
+    {
+    UBYTE mommy; /* Unlike a parent, you can only have one mommy! */
+    };
+
+extern UBYTE phmmNullMommy; /* mommy value for orphans.... */
+
+struct phmmState
+/* This corresponds to a hidden Markov state.  Each one of
+ * these has a two dimensional array[targetSize+1][querySize+1]
+ * of cells. */
+    {
+    struct phmmMommy *cells;	/* The 2-D array containing traceback info. */
+    int *scores;		/* Scores for the current row. */
+    int *lastScores;		/* Scores for the previous row. */
+    int stateIx;		/* Numerical handle on state. */
+    char *name;			/* Name of state. */
+    char emitLetter;		/* Single letter representing state. */
+    };
+
+struct phmmMatrix
+/* The alignment matrix - has an array of states. */
+    {
+    char *query;	/* One sequence to align- all lower case. */
+    char *target;    	/* Other sequence to align. */
+    int querySize;	/* Size of query. */
+    int targetSize;	/* Size of target. */
+    int qDim;		/* One plus size of query - dimension of matrix. */
+    int tDim;		/* One plus size of target - dimension of matrix. */
+    int stateCount;	/* Number of hidden states in HMM. */
+    int stateSize;	/* Number of cells in each state's matrix. */
+    int stateByteSize;	/* Number of bytes used by each state's matrix. */
+    struct phmmState *states;  /* Array of states. */
+    struct phmmMommy *allCells; /* Memory for all matrices. */
+    int *allScores;	      /* Memory for two rows of scores. */
+    };
+
+struct phmmMatrix *phmmMatrixNew(int stateCount,
+    char *query, int querySize, char *target, int targetSize);
+/* Allocate all memory required for an phmmMatrix. Set up dimensions. */
+
+void phmmMatrixFree(struct phmmMatrix **pAm);
+/* Free up memory required for an phmmMatrix and make sure
+ * nobody reuses it. */
+
+struct phmmState *phmmNameState(struct phmmMatrix *am, int stateIx, 
+	char *name, char emitLetter);
+/* Give a name to a state and return a pointer to it. */
+
+struct phmmAliPair *phmmTraceBack(struct phmmMatrix *am, struct phmmMommy *end);
+/* Create list of alignment pair by tracing back through matrix from end
+ * state back to a start.*/
+
+void phmmPrintTrace(struct phmmMatrix *am, struct phmmAliPair *pairList, 
+	boolean showStates, FILE *f, boolean extraAtEnds);
+/* Print out trace to file. */
+
+struct axt *phhmTraceToAxt(struct phmmMatrix *am, struct phmmAliPair *pairList, 
+	int score, char *qName, char *tName);
+/* Convert alignment from traceback format to axt. */
+
+#endif /* PAIRHMM_H */
+
diff --git a/inc/patSpace.h b/inc/patSpace.h
new file mode 100644
index 0000000..03a0ccd
--- /dev/null
+++ b/inc/patSpace.h
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* patSpace - a homology finding algorithm that occurs mostly in 
+ * pattern space (as opposed to offset space). */
+
+#ifndef PATSPACE_H
+#define PATSPACE_H
+
+#ifndef DNASEQ_H
+#include "dnaseq.h"
+#endif
+
+struct patSpace *makePatSpace(
+    struct dnaSeq **seqArray,       /* Array of sequence lists. */
+    int seqArrayCount,              /* Size of above array. */
+    int seedSize,	            /* Alignment seed size - 10 or 11. Must match oocFileName */
+    char *oocFileName,              /* File with tiles to filter out, may be NULL. */
+    int minMatch,                   /* Minimum # of matching tiles.  4 is good. */
+    int maxGap                      /* Maximum gap size - 32k is good for 
+                                       cDNA (introns), 500 is good for DNA assembly. */
+    );
+/* Allocate a pattern space and fill from sequences.  (Each element of
+   seqArray is a list of sequences. */
+
+void freePatSpace(struct patSpace **pPatSpace);
+/* Free up a pattern space. */
+
+struct patClump
+/* This holds pattern space output - a list of homologous clumps. */
+    {
+    struct patClump *next;     /* Link to next in list. */
+    int bacIx;                 /* Index of .fa file where hit occurs. */
+    int seqIx;                 /* Index of contig where hit occurs. */
+    struct dnaSeq *seq;        /* Sequence in which hit occurs. */
+    int start;                 /* Start offset within sequence. */
+    int size;                  /* Size of block within sequence. */
+    };
+
+struct patClump *patSpaceFindOne(struct patSpace *ps, DNA *dna, int dnaSize);
+/* Find occurrences of DNA in patSpace. The resulting list can be
+ * freed with slFreeList. */
+
+
+#endif /* PATSPACE_H */
+
diff --git a/inc/peakCluster.h b/inc/peakCluster.h
new file mode 100644
index 0000000..e65823a
--- /dev/null
+++ b/inc/peakCluster.h
@@ -0,0 +1,98 @@
+/* peakCluster - cluster peak calls from different sources. */
+
+#ifndef PEAKCLUSTER_H
+#define PEAKCLUSTER_H
+
+struct peakDim
+/* A peak dimension */
+    {
+    int colIx;		/* Column index in table. */
+    char *label;	/* Label */
+    };
+
+struct peakSource 
+/* A source of peak information */
+    {
+    struct peakSource *next;
+    char *dataSource;		/* File (or table) */
+    int chromColIx;		/* Chromosome column index. */
+    int startColIx;		/* Start coordinate column index. */
+    int endColIx;		/* End ccoordinate column ix. */
+    int scoreColIx;		/* Index for score column. */
+    double normFactor;		/* Multiply this to get browser score. */
+    char **labels;		/* Label for each dimension */
+    int minColCount;		/* Minimum number of columns. */
+    };
+
+struct peakItem
+/* An item in a peak track */
+    {
+    struct peakItem *next;
+    char *chrom;		/* Chromosome. Not allocated here. */
+    int chromStart,chromEnd;	/* Half open coordinates. */
+    double score;		/* Ideally something like -log(p). */
+    struct peakSource *source;   /* Source track/file for item. */
+    char *asciiLine;		/* Ascii representation of line. */
+    };
+
+struct peakCluster
+/* A cluster of items. */
+    {
+    struct peakCluster *next;
+    char *chrom;		/* Chromosome.  Not allocated here. */
+    int chromStart, chromEnd;	/* Half open coordinates. */
+    double score;		/* Sum of component scores. */
+    double maxSubScore;		/* Max of component scores. */
+    struct slRef *itemRefList;	/* List of references to component items. */
+    };
+
+struct peakClusterMaker
+/* Help make a cluster of peaks on multiple-chromosome data sets. */
+    {
+    struct peakClusterMaker *next;
+    struct hash *chromHash;	   /* Key is chromosome, value is a rbTree of items. */
+    struct rbTreeNode *stack[128]; /* Stack for rbTree evaluations. */
+    };
+
+struct peakClusterMaker *peakClusterMakerNew();
+/* Return a new peakClusterMaker. */
+
+void peakClusterMakerFree(struct peakClusterMaker **pMaker);
+/* Free up a peakClusterMaker. */
+
+struct hashEl *peakClusterMakerChromList(struct peakClusterMaker *maker);
+/* Return list of chromosomes.  In hashEl format where the hashEl val is
+ * a rangeTree filled with items. Do a slFreeList when done. */
+
+struct peakSource *peakSourceLoadAll(char *fileName, int dimCount);
+/* Read file, parse it line by line and return list of peakSources. */
+
+void peakClusterMakerAddFromSource(struct peakClusterMaker *maker, struct peakSource *source);
+/* Read through data source and add items to it to rangeTrees in maker */
+
+struct peakCluster *peakClusterItems(struct lm *lm, struct peakItem *itemList, 
+	double forceJoinScore, double weakLevel);
+/* Convert a list of items to a list of clusters of items.  This may break up clusters that
+ * have weakly linked parts. 
+      [                ]
+      AAAAAAAAAAAAAAAAAA 
+       BBBBBB   DDDDDD
+        CCCC     EEEE
+   gets tranformed into
+       [    ]   [    ]
+      AAAAAAAAAAAAAAAAAA 
+       BBBBBB   DDDDDD
+        CCCC     EEEE
+   The strategy is to build a rangeTree of coverage, which might look something like so:
+      123333211123333211 
+   then define cluster ends that exceed the minimum limit, which is either 10% of the highest
+   or forceJoinScore if 10% of the highest is more than forceJoinScore.  This will go to
+   something like so:
+        [---]   [----]   
+   Finally the items that are overlapping a cluster are assigned to it.  Note that this
+   may mean that an item may be in multiple clusters.
+        [ABC]   [ ADE]
+ */
+
+#endif /* PEAKCLUSTER_H */
+
diff --git a/inc/phyloTree.h b/inc/phyloTree.h
new file mode 100644
index 0000000..70ad89a
--- /dev/null
+++ b/inc/phyloTree.h
@@ -0,0 +1,77 @@
+/* phlyogenetic trees */
+
+
+#ifndef PHYLOTREE_H
+#define PHYLOTREE_H
+
+#include "linefile.h"
+
+struct phyloName
+{
+    char *name;		/* name of this node */
+    double length;	/* length of the branch to this node */
+};
+
+struct phyloTree
+{
+    struct phyloTree *next;		/* next in single linked list */
+    struct phyloTree *parent;		/* the parent of this node */
+    struct phyloTree **edges;
+    struct phyloName *ident;		/* the name and branch length */
+    struct phyloTree *mark;		/* probably the favorite child */
+    bool isDup;				/* is this a duplication node */
+    int numEdges;
+    int allocedEdges;
+
+    void *priv;
+};
+
+extern struct phyloTree *phyloOpenTree(char *fileName);
+/* opens an NH tree file */
+
+extern struct phyloTree *phyloReadTree(struct lineFile *lf);
+/* reads a phyloTree from lineFile (first line only) */
+
+extern struct phyloTree *phyloParseString(char *string);
+/* build a phyloTree from a string */
+
+extern void phyloPrintTree( struct phyloTree *,FILE *f);
+/* print a phyloTree to f in Newick format */
+
+extern void phyloDebugTree( struct phyloTree *,FILE *f);
+/* print a phyloTree to f */
+
+extern char *phyloFindPath(struct phyloTree *tree, char *ref, char *cross);
+/* find the shortest path from ref to cross (returns a list
+ * of the node names separated by spaces */
+
+extern char *phyloNodeNames(struct phyloTree *tree);
+/* return list of all the node names separated by spaces */
+
+extern struct phyloTree *phyloFindName( struct phyloTree *tree,char *name );
+/* find the node with this name */
+
+extern struct phyloTree *phyloReRoot(struct phyloTree *inTree);
+/* return a tree whose root is inTree and what were parents are now "right" children */
+
+extern void phyloDeleteEdge(struct phyloTree *tree, struct phyloTree *edge);
+/* delete an edge from a node.  Aborts on error */
+
+extern struct phyloTree *phyloAddEdge(struct phyloTree *parent, struct phyloTree *child);
+/* add an edge to a phyloTree node */
+
+extern void phyloClearTreeMarks(struct phyloTree *tree);
+/* clear the favorite child marks */
+
+extern struct phyloTree *phyloFindMarkUpTree(struct phyloTree *tree);
+/* find a marked node somewhere above this node */
+
+extern void phyloMarkUpTree(struct phyloTree *tree);
+/* mark all the nodes from this one up to the top of the tree */
+
+extern void phyloPrintTreeNoDups( struct phyloTree *tree,FILE *f);
+/* print out phylogenetic tree in Newick format (only speciation nodes) */
+
+extern int phyloCountLeaves( struct phyloTree *tree);
+
+#endif
diff --git a/inc/pipeline.h b/inc/pipeline.h
new file mode 100644
index 0000000..7fa1870
--- /dev/null
+++ b/inc/pipeline.h
@@ -0,0 +1,154 @@
+/* pipeline.h - create a process pipeline that can be used for reading or
+ * writing.  These pipeline objects don't go through the shell, so they
+ * avoid many of the obscure problems associated with system() and popen().
+ *
+ * Read pipelines are pipelines where a program reads output written by the
+ * pipeline, and write pipelines are where the program writes data to the
+ * pipeline.  The type of pipeline is specified in the set of option flags
+ * passed to pipelineOpen().  The file at the other end of the pipeline is
+ * specified in the otherEndFile argument of pipelineOpen(), as shown here:
+ *
+ * pipelineRead:
+ *
+ *   otherEndFile --> cmd[0] --> ... --> cmd[n] --> pipelineLf() etc.
+ *
+ * pipelineWrite:
+ *
+ *   pipeLineFile() --> cmd[0] --> ... --> cmd[n] --> otherEndFile
+ *
+ * Specify otherEndFile as "/dev/null" for no input or no output (or to
+ * discard output).  If otherEndFile is NULL, then either stdin or stdout are
+ * inherited from the current process.
+ * 
+ * I/O to the pipeline is done by using the result of pipelineFd(),
+ * pipelineFile(), or pipelineLineFile().
+ *
+ * An example that reads a compressed file, sorting it numerically by the 
+ * first column:
+ *    
+ *    static char *cmd1[] = {"gzip", "-dc", NULL};
+ *    static char *cmd2[] = {"sort", "-k", "1,1n", NULL};
+ *    static char **cmds[] = {cmd1, cmd2, NULL};
+ *    
+ *    struct pipeline *pl = pipelineOpen(cmds, pipelineRead, inFilePath, stderrFd);
+ *    struct lineFile *lf = pipelineLineFile(pl);
+ *    char *line;
+ *    
+ *    while (lineFileNext(lf, &line, NULL))
+ *        {
+ *        ...
+ *        }
+ *    pipelineWait(pl);
+ *    pipelineFree(&pl);
+ *
+ * A similar example that generates data and writes a compressed file, sorting
+ * it numerically by the first column:
+ *    
+ *    
+ *    static char *cmd1[] = {"sort", "-k", "1,1n", NULL};
+ *    static char *cmd2[] = {"gzip", "-c3", NULL};
+ *    static char **cmds[] = {cmd1, cmd2, NULL};
+ *    
+ *    struct pipeline *pl = pipelineOpen(cmds, pipelineWrite, outFilePath, stderrFd);
+ *    char *line;
+ *    
+ *    while ((line = makeNextRow()) != NULL)
+ *        fprintf(fh, "%s\n", line);
+ *    
+ *    pipelineWait(pl);
+ *    pipelineFree(&pl);
+ *
+ * To append to an output file, use pipelineWrite|pipelineAppend:
+ *    
+ *    struct pipeline *pl = pipelineOpen(cmds, pipelineWrite|pipelineAppend, outFilePath, stderrFd);
+ */
+#ifndef PIPELINE_H
+#define PIPELINE_H
+#include <stdio.h>
+struct linefile;
+struct pipeline;
+
+enum pipelineOpts
+/* pipeline options bitset */
+    {
+    pipelineRead       = 0x01, /* read from pipeline */
+    pipelineWrite      = 0x02, /* write to pipeline */
+    pipelineNoAbort    = 0x04, /* don't abort if a process exits non-zero,
+                                * wait will return exit code instead.
+                                * Still aborts if process signals. */
+    pipelineAppend     = 0x10, /* Append to output file (used only with pipelineWrite) */
+    /* these are internal options */
+    pipelineMemInput   = 0x08  /* pipeline takes input from memory */
+    };
+
+struct pipeline *pipelineOpenFd(char ***cmds, unsigned opts,
+                                int otherEndFd, int stderrFd);
+/* Create a pipeline from an array of commands.  Each command is an array of
+ * arguments.  Shell expansion is not done on the arguments.  If pipelineRead
+ * is specified, the output of the pipeline is readable from the pipeline
+ * object.  If pipelineWrite is specified, the input of the pipeline is
+ * writable from the pipeline object. */
+
+struct pipeline *pipelineOpen(char ***cmds, unsigned opts,
+                              char *otherEndFile, char *stderrFile);
+/* Create a pipeline from an array of commands.  Each command is an array of
+ * arguments.  Shell expansion is not done on the arguments.  If pipelineRead
+ * is specified, the output of the pipeline is readable from the pipeline
+ * object.  If pipelineWrite is specified, the input of the pipeline is
+ * writable from the pipeline object.  If stderrFile is NULL, stderr is inherited,
+ * otherwise it is redirected to this file.
+ */
+
+void pipelineDumpCmds(char ***cmds);
+/* Dump out pipeline-formatted commands to stdout for debugging. */
+
+struct pipeline *pipelineOpenMem(char ***cmds, unsigned opts,
+                                 void *otherEndBuf, size_t otherEndBufSize,
+                                 int stderrFd);
+/* Create a pipeline from an array of commands, with the pipeline input/output
+ * in a memory buffer.  See pipeline.h for full documentation.  Currently only
+ * input to a read pipeline is supported  */
+
+struct pipeline *pipelineOpenFd1(char **cmd, unsigned opts,
+                                 int otherEndFd, int stderrFd);
+/* like pipelineOpenFd(), only takes a single command */
+
+struct pipeline *pipelineOpen1(char **cmd, unsigned opts,
+                               char *otherEndFile, char *stderrFile);
+/* like pipelineOpen(), only takes a single command */
+
+struct pipeline *pipelineOpenMem1(char **cmd, unsigned opts,
+                                  void *otherEndBuf, size_t otherEndBufSize,
+                                  int stderrFd);
+/* like pipelineOpenMem(), only takes a single command */
+
+char *pipelineDesc(struct pipeline *pl);
+/* Get the desciption of a pipeline for use in error messages */
+
+int pipelineFd(struct pipeline *pl);
+/* Get the file descriptor for a pipeline */
+
+FILE *pipelineFile(struct pipeline *pl);
+/* Get a FILE object wrapped around the pipeline.  Do not close the FILE, is
+ * owned by the pipeline object.  A FILE is created on first call to this
+ * function.  Subsequent calls return the same FILE.*/
+
+struct lineFile *pipelineLineFile(struct pipeline *pl);
+/* Get a lineFile object wrapped around the pipeline.  Do not close the
+ * lineFile, is owned by the pipeline object.  A lineFile is created on first
+ * call to this function.  Subsequent calls return the same object.*/
+
+int pipelineWait(struct pipeline *pl);
+/* Wait for processes in a pipeline to complete; normally aborts if any
+ * process exists non-zero.  If pipelineNoAbort was specified, return the exit
+ * code of the first process exit non-zero, or zero if none failed. */
+
+void pipelineFree(struct pipeline **plPtr);
+/* free a pipeline object */
+
+#endif
+/*
+ * Local Variables:
+ * c-file-style: "jkent-c"
+ * End:
+ */
diff --git a/inc/portable.h b/inc/portable.h
new file mode 100644
index 0000000..bdbfc4c
--- /dev/null
+++ b/inc/portable.h
@@ -0,0 +1,152 @@
+/* portable.h - wrappers around things that vary from server
+ * to server and operating system to operating system. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef PORTABLE_H
+#define PORTABLE_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+struct slName *listDir(char *dir, char *pattern);
+/* Return an alphabetized list of all files that match 
+ * the wildcard pattern in directory. */
+
+struct slName *listDirRegEx(char *dir, char *regEx, int flags);
+/* Return an alphabetized list of all files that match 
+ * the regular expression pattern in directory.
+ * See REGCOMP(3) for flags (e.g. REG_ICASE)  */
+
+
+struct fileInfo 
+/* Info about a file. */
+    {
+    struct fileInfo  *next;	/* Next in list. */
+    off_t size;		/* Size in bytes. */
+    bool isDir;		/* True if file is a directory. */
+    int statErrno;	/* Result of stat (e.g. bad symlink). */
+    time_t lastAccess;  /* Last access time. */
+    char name[1];	/* Allocated at run time. */
+    };
+
+struct fileInfo *newFileInfo(char *name, off_t size, bool isDir, int statErrno, 
+	time_t lastAccess);
+/* Return a new fileInfo. */
+
+struct fileInfo *listDirXExt(char *dir, char *pattern, boolean fullPath, boolean ignoreStatFailures);
+/* Return list of files matching wildcard pattern with
+ * extra info. If full path is true then the path will be
+ * included in the name of each file.  You can free the
+ * resulting list with slFreeList. */
+
+struct fileInfo *listDirX(char *dir, char *pattern, boolean fullPath);
+/* Return list of files matching wildcard pattern with
+ * extra info. If full path is true then the path will be
+ * included in the name of each file.  You can free the
+ * resulting list with slFreeList. */
+
+char *getCurrentDir();
+/* Return current directory.  Abort if it fails. */
+
+void setCurrentDir(char *newDir);
+/* Set current directory.  Abort if it fails. */
+
+boolean maybeSetCurrentDir(char *newDir);
+/* Change directory, return FALSE (and set errno) if fail. */
+
+boolean makeDir(char *dirName);
+/* Make dir.  Returns TRUE on success.  Returns FALSE
+ * if failed because directory exists.  Prints error
+ * message and aborts on other error. */
+
+void makeDirsOnPath(char *pathName);
+/* Create directory specified by pathName.  If pathName contains
+ * slashes, create directory at each level of path if it doesn't
+ * already exist.  Abort with error message if there's a problem.
+ * (It's not considered a problem for the directory to already
+ * exist. ) */
+
+char *simplifyPathToDir(char *path);
+/* Return path with ~ (for home) and .. taken out.   freeMem result when done. */
+
+long clock1000();
+/* 1000 hz clock */
+
+void sleep1000(int milli);
+/* Sleep for given number of milliseconds. */
+
+long clock1();
+/* A 1 hz clock. */
+
+char *rTempName(char *dir, char *base, char *suffix);
+/* Make a temp name that's almost certainly unique. */
+
+/* This structure helps us generate temp names and use
+ * them.  Since different servers locate where the cgi
+ * runs from differently, and where the generated html
+ * file runs from - this is necessary for portable code. */
+struct tempName
+	{
+	char forCgi[128];
+	char forHtml[128];
+	};
+
+void makeTempName(struct tempName *tn, char *base, char *suffix);
+/* Make a good name for a temp file. */
+
+char *semiUniqName(char *base);
+/* Figure out a name likely to be unique.
+ * Name will have no periods.  Returns a static
+ * buffer, so best to clone result unless using
+ * immediately. */
+
+char *cgiDir();
+/* Return directory to look for cgi in. */
+
+char *trashDir();
+/* Return directory for relative path to trash from cgi binaries */
+
+void mkdirTrashDirectory(char *prefix);
+/*	create the specified trash directory if it doesn't exist */
+
+double machineSpeed();
+/* Return relative speed of machine.  UCSC CSE dept. 1999 web server is 1.0 */
+
+char *mysqlHost();
+/* Return host computer on network for mySQL database. */
+
+char *getHost();
+/* Get name of this machine. */
+
+void uglyfBreak();
+/* Invoke the debugger. */
+
+char *getUser();
+/* Get user name */
+
+void envUpdate(char *name, char *value);
+/* Update an environment string */
+
+int mustFork();
+/* Fork or abort. */
+
+int rawKeyIn();
+/* Read in an unbuffered, unechoed character from keyboard. */
+
+time_t fileModTime(char *pathName);
+/* Return file last modification time.  The units of
+ * these may vary from OS to OS, but you can depend on
+ * later files having a larger time. */
+
+
+boolean isPipe(int fd);
+/* determine in an open file is a pipe  */
+
+boolean maybeTouchFile(char *fileName);
+/* If file exists, set its access and mod times to now.  If it doesn't exist, create it.
+ * Return FALSE if we have a problem doing so. */
+
+#endif /* PORTABLE_H */
+
diff --git a/inc/psGfx.h b/inc/psGfx.h
new file mode 100644
index 0000000..9d04cb2
--- /dev/null
+++ b/inc/psGfx.h
@@ -0,0 +1,118 @@
+/* PostScript graphics - 
+ * This provides a bit of a shell around writing graphics to
+ * a postScript file.  Perhaps the most important thing it
+ * does is convert 0,0 from being at the bottom left to
+ * being at the top left. */
+
+#ifndef PSGFX_H
+#define PSGFX_H
+
+#include "psPoly.h"
+
+struct psGfx 
+/* A postScript output file. */
+    {
+    FILE *f;                      /* File to write to. */
+    double userWidth, userHeight; /* Size of image in virtual pixels. */
+    double ptWidth, ptHeight;     /* Size of image in points (1/72 of an inch) */
+    double xScale, yScale;        /* Conversion from pixels to points. */
+    double xOff, yOff;            /* Offset from pixels to points. */
+    double fontHeight;		  /* Height of current font. */
+    };
+
+struct psGfx *psOpen(char *fileName, 
+	double userWidth, double userHeight, /* Dimension of image in user's units. */
+	double ptWidth, double ptHeight,     /* Dimension of image in points. */
+	double ptMargin);                    /* Image margin in points. */
+/* Open up a new postscript file.  If ptHeight is 0, it will be
+ * calculated to keep pixels square. */
+
+void psClose(struct psGfx **pPs);
+/* Close out postScript file. */
+
+void psTranslate(struct psGfx *ps, double xTrans, double yTrans);
+/* add a constant to translate all coordinates */
+
+void psSetLineWidth(struct psGfx *ps, double factor);
+/* Set line width to factor * a single pixel width. */
+
+void psClipRect(struct psGfx *ps, double x, double y, 
+	double width, double height);
+/* Set clipping rectangle. */
+
+void psDrawBox(struct psGfx *ps, double x, double y, 
+	double width, double height);
+/* Draw a filled box in current color. */
+
+void psDrawLine(struct psGfx *ps, double x1, double y1, 
+	double x2, double y2);
+/* Draw a line from x1/y1 to x2/y2 */
+
+void psFillUnder(struct psGfx *ps, double x1, double y1, 
+	double x2, double y2, double bottom);
+/* Draw a 4 sided filled figure that has line x1/y1 to x2/y2 at
+ * it's top, a horizontal line at bottom at it's bottom,  and
+ * vertical lines from the bottom to y1 on the left and bottom to
+ * y2 on the right. */
+
+void psXyOut(struct psGfx *ps, double x, double y);
+/* Output x,y position transformed into PostScript space. 
+ * Useful if you're mixing direct PostScript with psGfx
+ * functions. */
+
+void psWhOut(struct psGfx *ps, double width, double height);
+/* Output width/height transformed into PostScript space. */
+
+void psMoveTo(struct psGfx *ps, double x, double y);
+/* Move PostScript position to given point. */
+
+void psTextAt(struct psGfx *ps, double x, double y, char *text);
+/* Output text in current font at given position. */
+
+void psTextBox(struct psGfx *ps, double x, double y, char *text);
+/* Fill a box the size of the text at the given position*/
+
+void psTextDown(struct psGfx *ps, double x, double y, char *text);
+/* Output text going downwards rather than across at position. */
+
+void psTextRight(struct psGfx *mg, double x, double y, 
+	double width, double height, char *text);
+/* Draw a line of text right justified in box defined by x/y/width/height */
+
+void psTextCentered(struct psGfx *mg, double x, double y, 
+	double width, double height, char *text);
+/* Draw a line of text centered in box defined by x/y/width/height */
+
+void psTimesFont(struct psGfx *ps, double size);
+/* Set font to times of a certain size. */
+
+void psSetColor(struct psGfx *ps, int r, int g, int b);
+/* Set current color. r/g/b values are between 0 and 255. */
+
+void psSetGray(struct psGfx *ps, double grayVal);
+/* Set gray value (between 0.0 and 1.0. */
+
+void psPushG(struct psGfx *ps);
+/* Save graphics state on stack. */
+
+void psPopG(struct psGfx *ps);
+/* Pop off saved graphics state. */
+
+void psDrawPoly(struct psGfx *ps, struct psPoly *poly, boolean filled);
+/* Draw a possibly filled polygon */
+
+void psFillEllipse(struct psGfx *ps, double x, double y, double xrad, double yrad);
+/* Draw a filled ellipse */
+
+void psDrawEllipse(struct psGfx *ps, double x, double y, double xrad, double yrad,
+    double startAngle, double endAngle);
+/* Draw an ellipse outline */
+
+char * convertEpsToPdf(char *epsFile);
+/* Convert EPS to PDF and return filename, or NULL if failure. */
+
+void psLineTo(struct psGfx *ps, double x, double y);
+/* Draw line from current point to given point,
+ * and make given point new current point. */
+#endif /* PSGFX_H */
+
diff --git a/inc/psPoly.h b/inc/psPoly.h
new file mode 100644
index 0000000..a39cb93
--- /dev/null
+++ b/inc/psPoly.h
@@ -0,0 +1,31 @@
+/* psPoly - two dimensional polygon. */
+
+#ifndef PSPOLY_H
+#define PSPOLY_H
+
+struct psPoint
+/* A two-dimensional point, typically in pixel coordinates. */
+    {
+    struct psPoint *next;
+    double x, y;		/* Position */
+    };
+
+struct psPoly
+/* A two-dimensional polygon */
+    {
+    struct psPoly *next;
+    int ptCount;		/* Number of points. */
+    struct psPoint *ptList;	/* First point in list, which is circular. */
+    struct psPoint *lastPoint;	/* Last point in list. */
+    };
+
+struct psPoly *psPolyNew();
+/* Create new (empty) polygon */
+
+void psPolyFree(struct psPoly **pPoly);
+/* Free up resources associated with polygon */
+
+void psPolyAddPoint(struct psPoly *poly, double x, double y);
+/* Add point to polygon. */
+
+#endif /* PSPOLY_H */
diff --git a/inc/pscmGfx.h b/inc/pscmGfx.h
new file mode 100644
index 0000000..b5d13c3
--- /dev/null
+++ b/inc/pscmGfx.h
@@ -0,0 +1,71 @@
+/* pscmGfx - routines for making postScript output seem a
+ * lot like 256 color bitmap output. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef PSCMGFX_H
+#define PSCMGFX_H
+
+#include "memgfx.h"
+
+struct pscmGfx 
+/* Structure to simululate 256 color image
+ * in postScript - so to make it easier to
+ * swap between memGfx/gif output and PostScript
+ * output */
+    {
+    struct pscmGfx *next;
+    struct psGfx *ps;	  /* Underlying postScript object. */
+    int colAlloc;	  /* Colors allocated. */
+    int colUsed;	  /* Colors used. */
+    void *curFont;	  /* Current font. */
+    int curColor;	  /* Current color. */
+    struct colHash *colorHash;	/* Hash for fast look up of color. */
+    struct rgbColor colorMap[256]; /* The color map. */
+    int colorsUsed;		/* Number of colors actually used. */
+    int clipMinX, clipMaxX;     /* Clipping region upper left corner. */
+    int clipMinY, clipMaxY;     /* lower right, not inclusive */
+    struct hash *hints;   /* Hints to guide behavior */
+    int writeMode;        /* current write mode */
+    };
+
+struct pscmGfx *pscmOpen(int width, int height, char *file);
+/* Return new pscmGfx. */
+
+void pscmClose(struct pscmGfx **ppscm);
+/* Finish writing out and free structure. */
+
+void pscmSetClip(struct pscmGfx *pscm, int x, int y, int width, int height);
+/* Set clipping rectangle. */
+
+void pscmUnclip(struct pscmGfx *pscm);
+/* Set clipping rect cover full thing. */
+
+int pscmFindColorIx(struct pscmGfx *pscm, int r, int g, int b);
+/* Find color index for rgb. */
+
+void pscmSetColor(struct pscmGfx *pscm, Color color);
+/* Set current color to Color. */
+
+void pscmBox(struct pscmGfx *pscm, int x, int y, 
+	int width, int height, int colorIx);
+/* Draw a box. */
+
+void pscmLine(struct pscmGfx *pscm, 
+	int x1, int y1, int x2, int y2, int colorIx);
+/* Draw a line from one point to another. */
+
+void pscmText(struct pscmGfx *pscm, int x, int y, int colorIx, 
+	MgFont *font, char *text);
+/* Draw a line of text with upper left corner x,y. */
+
+void pscmTextRight(struct pscmGfx *pscm, int x, int y, int width, int height,
+	int color, MgFont *font, char *text);
+/* Draw a line of text right justified in box defined by x/y/width/height */
+
+void pscmTextCentered(struct pscmGfx *pscm, int x, int y, 
+	int width, int height, int color, MgFont *font, char *text);
+/* Draw a line of text centered in box defined by x/y/width/height */
+
+#endif /* PSCMGFX_H */
diff --git a/inc/psl.h b/inc/psl.h
new file mode 100644
index 0000000..5e01ab2
--- /dev/null
+++ b/inc/psl.h
@@ -0,0 +1,326 @@
+/* psl.h was originally generated by the autoSql program, which also 
+ * generated psl.c and psl.sql.  This header links the database and 
+ * the RAM representation of objects.   Additional functions were
+ * added later. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef PSL_H
+#define PSL_H
+
+#ifndef LOCALMEM_H
+#include "localmem.h"
+#endif 
+
+#ifndef LINEFILE_H
+#include "linefile.h"
+#endif
+
+#ifndef FUZZYFIND_H
+#include "fuzzyFind.h"
+#endif
+
+#ifndef DNASEQ_H
+#include "dnaseq.h"
+#endif
+
+/* Some forward declarations of structures used but not defined here. */
+struct rbTree;
+
+#define PSL_NUM_COLS  21  /* number of columns in a PSL */
+#define PSLX_NUM_COLS 23  /* number of columns in a PSLX */
+
+/* Options to pslGetCreateSql */
+#define PSL_TNAMEIX   0x01  /* create target name index */
+#define PSL_WITH_BIN  0x02  /* add bin column */
+#define PSL_XA_FORMAT 0x04  /* add XA format columns */
+
+/* options for pslFromAlign */
+#define PSL_IS_SOFTMASK 0x01 /* lower case are mask */
+
+struct psl
+/* Summary info about a patSpace alignment */
+    {
+    struct psl *next;  /* Next in singly linked list. */
+    unsigned match;	/* Number of bases that match that aren't repeats */
+    unsigned misMatch;	/* Number of bases that don't match */
+    unsigned repMatch;	/* Number of bases that match but are part of repeats */
+    unsigned nCount;	/* Number of 'N' bases */
+    unsigned qNumInsert;	/* Number of inserts in query */
+    int qBaseInsert;	/* Number of bases inserted in query */
+    unsigned tNumInsert;	/* Number of inserts in target */
+    int tBaseInsert;	/* Number of bases inserted in target */
+    char strand[3];	/* + or - for strand */
+    char *qName;	/* Query sequence name */
+    unsigned qSize;	/* Query sequence size */
+    int qStart;	/* Alignment start position in query */
+    int qEnd;	/* Alignment end position in query */
+    char *tName;	/* Target sequence name */
+    unsigned tSize;	/* Target sequence size */
+    int tStart;	/* Alignment start position in target */
+    int tEnd;	/* Alignment end position in target */
+    unsigned blockCount;	/* Number of blocks in alignment */
+    unsigned *blockSizes;	/* Size of each block */
+    unsigned *qStarts;	/* Start of each block in query. */
+    unsigned *tStarts;	/* Start of each block in target. */
+
+    char **qSequence;  /* query sequence for each block */
+    char **tSequence;  /* target sequence for each block */
+    };
+
+struct psl *pslxLoad(char **row);
+/* Load a pslx from row fetched with select * from psl
+ * from database.  Dispose of this with pslFree(). */
+
+struct psl *pslLoad(char **row);
+/* Load a psl from row fetched with select * from psl
+ * from database.  Dispose of this with pslFree(). */
+
+struct psl *pslCommaIn(char **pS, struct psl *ret);
+/* Create a psl out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new psl */
+
+void pslFree(struct psl **pEl);
+/* Free a single dynamically allocated psl such as created
+ * with pslLoad(). */
+
+void pslFreeList(struct psl **pList);
+/* Free a list of dynamically allocated psl's */
+
+void pslOutput(struct psl *el, FILE *f, char sep, char lastSep);
+/* Print out psl.  Separate fields with sep. Follow last field with lastSep. */
+
+#define pslTabOut(el,f) pslOutput(el,f,'\t','\n')
+/* Print out psl as a line in a tab-separated file. */
+
+#define pslCommaOut(el,f) pslOutput(el,f,',',',')
+/* Print out psl as a comma separated list including final comma. */
+
+/* ----- end autoSql generated part --------------- */
+
+void pslOutFormat(struct psl *el, FILE *f, char sep, char lastSep);
+/* Print out selected psl values.  Separate fields with sep. Follow last field with lastSep. */
+/* Prints out a better format with bold field headings followed by value */
+/* Requires further upstream work to ensure that only the field headers */
+/* declared here are printed if replacing an existing psl print function*/
+
+struct psl *pslLoadAll(char *fileName);
+/* Load all psl's in file. */
+
+struct psl *pslNext(struct lineFile *lf);
+/* Read next line from file and convert it to psl.  Return
+ * NULL at eof. */
+
+struct psl *pslxLoadLm(char **row, struct lm *lm);
+/* Load row into local memory pslx. */
+
+struct psl *pslLoadLm(char **row, struct lm *lm);
+/* Load row into local memory psl. */
+
+void pslWriteHead(FILE *f);
+/* Write head of psl. */
+
+void pslxWriteHead(FILE *f, enum gfType qType, enum gfType tType);
+/* Write head of pslx (extended psl). */
+
+void pslWriteAll(struct psl *pslList, char *fileName, boolean writeHeader);
+/* Write a psl file from list. */
+
+struct lineFile *pslFileOpen(char *fileName);
+/* Read header part of psl and make sure it's right. 
+ * Return line file handle to it. */
+
+struct lineFile *pslFileOpenWithMeta(char *fileName, FILE *f);
+/* Read header part of psl and make sure it's right. 
+ * Return line file handle to it and send meta data to output file f */
+
+struct lineFile *pslFileOpenWithUniqueMeta(char *fileName, FILE *f);
+/* Read header part of psl and make sure it's right. 
+* Set flag to suppress duplicate header comments.
+* Return line file handle to it. */
+
+void pslxFileOpen(char *fileName, enum gfType *retQueryType, 
+	enum gfType *retTargetType, struct lineFile **retLf);
+/* Read header part of psl and make sure it's right.  Return
+ * sequence types and file handle. */
+
+void pslxFileOpenWithMeta(char *fileName, enum gfType *retQueryType, enum gfType *retTargetType, struct lineFile **retLf, FILE *f);
+/* Read header part of psl and make sure it's right.  Return
+ * sequence types and file handle and send meta data to output file f */
+
+void pslxFileOpenWithUniqueMeta(char *fileName, enum gfType *retQueryType, enum gfType *retTargetType, struct lineFile **retLf, FILE *f);
+/* Read header part of psl and make sure it's right.  Return
+* sequence types and file handle and send only unique meta data to output f */
+
+int pslCmpQuery(const void *va, const void *vb);
+/* Compare to sort based on query. */
+
+int pslCmpTarget(const void *va, const void *vb);
+/* Compare to sort based on target. */
+
+int pslCmpTargetAndStrand(const void *va, const void *vb);
+/* Compare to sort based on target, strand,  tStart. */
+
+int pslCmpScore(const void *va, const void *vb);
+/* Compare to sort based on score (descending). */
+
+int pslCmpQueryScore(const void *va, const void *vb);
+/* Compare to sort based on query then score (descending). */
+
+int pslCalcMilliBad(struct psl *psl, boolean isMrna);
+/* Calculate badness in parts per thousand. */
+
+int pslCmpScoreDesc(const void *va, const void *vb);
+/* Compare to sort based on score descending. */
+
+int pslCmpMatch(const void *va, const void *vb);
+/* Compare to sort based on match. */
+
+int pslScore(const struct psl *psl);
+/* Return score for psl. */
+
+struct ffAli *pslToFfAli(struct psl *psl, struct dnaSeq *query, struct dnaSeq *target,
+	int targetOffset);
+/* Convert from psl to ffAli format. */
+
+struct ffAli *pslToFakeFfAli(struct psl *psl, DNA *needle, DNA *haystack);
+/* Convert from psl to ffAli format.  In some cases you can pass NULL
+ * for needle and haystack - depending what the post-processing is going
+ * to be. */
+
+struct psl *pslFromFakeFfAli(struct ffAli *ff, 
+	DNA *needle, DNA *haystack, char strand,
+	char *qName, int qSize, char *tName, int tSize);
+/* This will create a basic psl structure from a sorted series of ffAli
+ * blocks.  The fields that would need actual sequence to be filled in
+ * are left zero however - fields including match, repMatch, mismatch. */
+
+int pslOrientation(struct psl *psl);
+/* Translate psl strand + or - to orientation +1 or -1 */
+
+/* marcos to get query and target strand.  Target returns implied + when
+ * it's not specific  */
+#define pslQStrand(p) ((p)->strand[0])
+#define pslTStrand(p) (((p)->strand[1] != '-') ? '+' : '-')
+
+int pslWeightedIntronOrientation(struct psl *psl, struct dnaSeq *genoSeq, int offset);
+/* Return >0 if introns make it look like alignment is on + strand,
+ *        <0 if introns make it look like alignment is on - strand,
+ *        0 if can't tell.  The absolute value of the return indicates
+ * how many splice sites we've seen supporting the orientation.
+ * Sequence should NOT be reverse complemented.  */
+
+int pslIntronOrientation(struct psl *psl, struct dnaSeq *genoSeq, int offset);
+/* Return 1 if introns make it look like alignment is on + strand,
+ *       -1 if introns make it look like alignment is on - strand,
+ *        0 if can't tell.
+ * Sequence should NOT be reverse complemented.  */
+
+boolean pslHasIntron(struct psl *psl, struct dnaSeq *seq, int seqOffset);
+/* Return TRUE if there's a probable intron. Sequence should NOT be
+ * reverse complemented. */
+
+void pslTailSizes(struct psl *psl, int *retStartTail, int *retEndTail);
+/* Find the length of "tails" (rather than extensions) implied by psl. */
+
+void pslRc(struct psl *psl);
+/* Reverse-complement a PSL alignment.  This makes the target strand explicit. */
+
+void pslSwap(struct psl *psl, boolean noRc);
+/* swap query and target in psl.  If noRc is TRUE, don't reverse-complement
+ * PSL if needed, instead make target strand explict. */
+
+void pslTargetOffset(struct psl *psl, int offset);
+/* Add offset to target positions in psl. */
+
+void pslDump(struct psl *psl, FILE *f);
+/* Dump most of PSL to file - for debugging. */
+
+struct psl *pslTrimToTargetRange(struct psl *oldPsl, int tMin, int tMax);
+/* Return psl trimmed to fit inside tMin/tMax.  Note this does not
+ * update the match/misMatch and related fields. */
+
+struct psl *pslTrimToQueryRange(struct psl *oldPsl, int qMin, int qMax);
+/* Return psl trimmed to fit inside qMin/qMax.  Note this does not
+ * update the match/misMatch and related fields. */
+
+char* pslGetCreateSql(char* table, unsigned options, int tNameIdxLen);
+/* Get SQL required to create PSL table.  Options is a bit set consisting
+ * of PSL_TNAMEIX, PSL_WITH_BIN, and PSL_XA_FORMAT.  tNameIdxLen is
+ * the number of characters in target name to index.  If greater than
+ * zero, must specify PSL_TNAMEIX.  If zero and PSL_TNAMEIX is specified,
+ * to will default to 8. */
+
+int pslCheck(char *pslDesc, FILE* out, struct psl* psl);
+/* Validate a PSL for consistency.  pslDesc is printed the error messages
+ * to file out (open /dev/null to discard). Return count of errors. */
+
+int pslCountBlocks(struct psl *target, struct psl *query, int maxBlockGap);
+/* count the number of blocks in the query that overlap the target */
+/* merge blocks that are closer than maxBlockGap */
+
+struct hash *readPslToBinKeeper(char *sizeFileName, char *pslFileName);
+/* read a list of psls and return results in hash of binKeeper structure for fast query*/
+
+boolean pslIsProtein(const struct psl *psl);
+/* is psl a protein psl (are it's blockSizes and scores in protein space) */
+
+struct psl* pslFromAlign(char *qName, int qSize, int qStart, int qEnd, char *qString,
+                         char *tName, int tSize, int tStart, int tEnd, char *tString,
+                         char* strand, unsigned options);
+/* Create a PSL from an alignment.  Options PSL_IS_SOFTMASK if lower case
+ * bases indicate repeat masking.  Returns NULL if alignment is empty after
+ * triming leading and trailing indels.*/
+
+int pslShowAlignment(struct psl *psl, boolean isProt,
+	char *qName, bioSeq *qSeq, int qStart, int qEnd,
+	char *tName, bioSeq *tSeq, int tStart, int tEnd, FILE *f);
+/* Show protein/DNA alignment or translated DNA alignment in HTML format. */
+
+int pslGenoShowAlignment(struct psl *psl, boolean isProt,
+		      char *qName, bioSeq *qSeq, int qStart, int qEnd,
+		      char *tName, bioSeq *tSeq, int tStart, int tEnd, int exnStarts[], int exnEnds[], int exnCnt, FILE *f);
+/* Show protein/DNA alignment or translated DNA alignment in HTML format. */
+
+struct psl* pslNew(char *qName, unsigned qSize, int qStart, int qEnd,
+                   char *tName, unsigned tSize, int tStart, int tEnd,
+                   char *strand, unsigned blockSpace, unsigned opts);
+/* create a new psl with space for the specified number of blocks allocated.
+ * pslGrow maybe used to expand this space if needed.  Valid options are
+ * PSL_XA_FORMAT. */
+
+void pslGrow(struct psl *psl, int *blockSpacePtr);
+/* Increase memory allocated to a psl to hold more blocks.  blockSpacePtr
+ * should point the the current maximum number of blocks and will be
+ * updated to with the new amount of space. */
+
+struct psl* pslFromGff3Cigar(char *qName, int qSize, int qStart, int qEnd,
+                             char *tName, int tSize, int tStart, int tEnd,
+                             char* strand, char *cigar);
+/* create a PSL from a GFF3-style cigar formatted alignment */
+
+int pslRangeTreeOverlap(struct psl *psl, struct rbTree *rangeTree);
+/* Return amount that psl overlaps (on target side) with rangeTree. */
+
+float pslIdent(struct psl *psl);
+/* computer fraction identity */
+
+float pslQueryAligned(struct psl *psl);
+/* compute fraction of query that was aligned */
+
+INLINE unsigned pslQEnd(struct psl *psl, int blkIdx)
+/* return query end for the given block */
+{
+return psl->qStarts[blkIdx] + psl->blockSizes[blkIdx];
+}
+
+INLINE unsigned pslTEnd(struct psl *psl, int blkIdx)
+/* return target end for the given block */
+{
+return psl->tStarts[blkIdx] + psl->blockSizes[blkIdx];
+}
+
+#endif /* PSL_H */
+
diff --git a/inc/pslTbl.h b/inc/pslTbl.h
new file mode 100644
index 0000000..b1d1b7f
--- /dev/null
+++ b/inc/pslTbl.h
@@ -0,0 +1,42 @@
+/* table of psl alignments, grouped by query */
+#ifndef PSLTBL_H
+#define PSLTBL_H
+
+struct psl;
+struct hash;
+
+struct pslQuery
+/* object containing PSLs for a single query */
+{
+    struct pslQuery *next;
+    char *qName;          /* qName, memory not owned here */
+    struct psl *psls;     /* alignments */
+};
+
+struct pslTbl
+/* table of psl alignments */
+{
+    struct pslTbl *next;               /* next psl table in a list */
+    char *setName;                     /* name identifying the set of psl.
+                                        * maybe file name, or  other name */
+    struct hash *queryHash;            /* hash of pslQuery objects */
+};
+
+struct pslTbl *pslTblNew(char *pslFile, char *setName);
+/* construct a new object, loading the psl file.  If setName is NULL, the file
+* name is saved as the set name. */
+
+void pslTblFree(struct pslTbl **pslTblPtr);
+/* free object */
+
+void pslTblFreeList(struct pslTbl **pslTblList);
+/* free list of pslTbls */
+
+#endif
+
+/*
+ * Local Variables:
+ * c-file-style: "jkent-c"
+ * End:
+ */
+
diff --git a/inc/pslTransMap.h b/inc/pslTransMap.h
new file mode 100644
index 0000000..0f53035
--- /dev/null
+++ b/inc/pslTransMap.h
@@ -0,0 +1,17 @@
+/* pslTransMap - transitive mapping of an alignment another sequence, via a
+ * common alignment */
+#ifndef PSLTRANSMAP_H
+#define PSLTRANSMAP_H
+
+enum pslTransMapOpts
+/* option set for pslTransMap */
+{
+    pslTransMapNoOpts     = 0x00,  /* no options */
+    pslTransMapKeepTrans  = 0x01   /* keep translated alignment strand */
+};
+
+struct psl* pslTransMap(unsigned opts, struct psl *inPsl, struct psl *mapPsl);
+/* map a psl via a mapping psl, a single psl is returned, or NULL if it
+ * couldn't be mapped. */
+
+#endif
diff --git a/inc/pthreadWrap.h b/inc/pthreadWrap.h
new file mode 100644
index 0000000..5021bb4
--- /dev/null
+++ b/inc/pthreadWrap.h
@@ -0,0 +1,45 @@
+/* pthreadWrap - error checking wrappers around Posix
+ * thread functions.  Most of the errors here are invariably
+ * fatal, but shouldn't happen unless the kernal or
+ * the program is hosed. */
+
+#ifndef PTHREADWRAP_H
+#define PTHREADWRAP_H
+
+#include <pthread.h>
+
+void pthreadCreate(pthread_t *thread, const pthread_attr_t *attr,
+	void *(*start_routine)(void *), void *arg);
+/* Create a thread or squawk and die. */
+
+boolean pthreadMayCreate(pthread_t *thread, const pthread_attr_t *attr,
+	void *(*start_routine)(void *), void *arg);
+/* Create a thread.  Warn and return FALSE if there is a problem. */
+
+void pthreadMutexInit(pthread_mutex_t *mutex);
+/* Initialize mutex or die trying */
+
+void pthreadMutexDestroy(pthread_mutex_t *mutex);
+/* Free up mutex. */
+
+void pthreadMutexLock(pthread_mutex_t *mutex);
+/* Lock a mutex to gain exclusive access or die trying. */
+
+void pthreadMutexUnlock(pthread_mutex_t *mutex);
+/* Unlock a mutex or die trying. */
+
+void pthreadCondInit(pthread_cond_t *cond);
+/* Initialize pthread conditional. */
+
+void pthreadCondDestroy(pthread_cond_t *cond);
+/* Free up conditional. */
+
+void pthreadCondSignal(pthread_cond_t *cond);
+/* Set conditional signal to wake up a sleeping thread, or
+ * die trying. */
+
+void pthreadCondWait(pthread_cond_t *cond, pthread_mutex_t *mutex);
+/* Wait for conditional signal. */
+
+#endif /* PTHREADWRAP_H */
+
diff --git a/inc/qa.h b/inc/qa.h
new file mode 100644
index 0000000..016db68
--- /dev/null
+++ b/inc/qa.h
@@ -0,0 +1,65 @@
+/* qa - Module to help do testing, especially on html based apps. */
+
+#ifndef QA_H
+#define QA_H
+
+#ifndef HTMLPAGE_H
+#include "htmlPage.h"
+#endif
+
+char *qaStringBetween(char *text, char *startPattern, char *endPattern);
+/* Return text that occurs between startPattern and endPattern,
+ * or NULL if no startPattern.  (Will return up to 100 characters
+ * after startPattern if there is no endPattern) */
+
+char *qaScanForErrorMessage(char *text);
+/* Scan text for error message.  If one exists then
+ * return copy of it.  Else return NULL. */
+
+int qaCountBetween(char *s, char *startPattern, char *endPattern, 
+	char *midPattern);
+
+struct slName *qaRandomSample(char *db, char *table, char *field, int count);
+/* Get random sample from database. */
+
+
+struct qaStatus
+/* Timing and other info about fetching a web page. */
+    {
+    struct qaStatus *next;
+    int milliTime;	/* Time page fetch took. */
+    char *errMessage;	/* Error message if any. */
+    boolean hardError;	/* Crash of some sort. */
+    };
+
+struct qaStatus *qaPageGet(char *url, struct htmlPage **retPage);
+/* Get info on given url, (and return page if retPage non-null). */
+
+struct qaStatus *qaPageFromForm(struct htmlPage *origPage, struct htmlForm *form, 
+	char *buttonName, char *buttonVal, struct htmlPage **retPage);
+/* Get update to form based on pressing a button. */
+
+void qaStatusSoftError(struct qaStatus *qs, char *format, ...);
+/* Add error message for something less than a crash. */
+
+void qaStatusReportOne(FILE *f, struct qaStatus *qs, char *format, ...);
+/* Report status */
+
+struct qaStatistics
+/* Stats on one set of tests. */
+    {
+    struct qaStatistics *next;
+    int testCount;	/* Number of tests. */
+    int softCount;	/* Soft error count. */
+    int hardCount;	/* Hard error count. */
+    long milliTotal;	/* Time tests took. */
+    };
+
+void qaStatisticsAdd(struct qaStatistics *stats, struct qaStatus *qs);
+/* Add test results to totals */
+
+void qaStatisticsReport(struct qaStatistics *stats, char *label, FILE *f);
+/* Write a line of stats to file. */
+
+#endif /* QA_H */
+
diff --git a/inc/quickHeap.h b/inc/quickHeap.h
new file mode 100644
index 0000000..8dfdb9b
--- /dev/null
+++ b/inc/quickHeap.h
@@ -0,0 +1,53 @@
+/* quickHeap - Heap implemented as an array for speed.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial.
+ *
+ *    The array can be resized as it grows.
+ *  By preserving the relationship that the children of n are at 2n+1 and 2n+2,
+ *  and therefore the parent of n is at (n-1)/2, we can save alot of pointer
+ *  manipulation and get some speed.  
+ *    This routine could for instance be used at the heart of a multi-way mergesort
+ *  or other situation such as a priority queue.
+ *
+ */
+
+struct quickHeap 
+/* A quick array heap. */
+    {
+    void **heap;
+    int heapCount;
+    int heapMax;
+    int (*compareFunc)(const void *elem1, const void *elem2);
+    };
+
+struct quickHeap *newQuickHeap(int initSize, 
+   int (*compare )(const void *elem1,  const void *elem2));
+/* Create a new array quick heap of initial size specified,
+ * The compare function must return > 0 if elem1 > elem2, etc.*/
+
+void freeQuickHeap(struct quickHeap **pH);
+/* Heap needs more space, double the size of the array preserving elements */
+
+void addToQuickHeap(struct quickHeap *h, void *elem);
+/* add to heap at end (expands array if needed), rebalance */
+
+void quickHeapTopChanged(struct quickHeap *h);
+/* only the value of the top element has changed, now rebalance */
+
+boolean quickHeapEmpty(struct quickHeap *h);
+/* return TRUE if quick heap is empty, otherwise FALSE */
+
+boolean removeFromQuickHeapByElem(struct quickHeap *h, void *elem);
+/* Do a linear search in heap array for elem,
+ * then remove it by position n. Return TRUE
+ * if found and removed, otherwise return FALSE. */
+
+void *peekQuickHeapTop(struct quickHeap *h);
+/* return the top element or NULL if empty */
+
+void *removeQuickHeapTop(struct quickHeap *h);
+/* Return elem (pointer) in heap array[0]
+ * which will be NULL if heap is empty.
+ * Then that top element if found is removed. */
+
diff --git a/inc/quotedP.h b/inc/quotedP.h
new file mode 100644
index 0000000..f483a33
--- /dev/null
+++ b/inc/quotedP.h
@@ -0,0 +1,21 @@
+/* Quoted Printable encoding and decoding.
+ * by Galt Barber */
+
+#ifndef QUOTEDP_H
+#define QUOTEDP_H
+
+char *quotedPrintableEncode(char *input);
+/* Use Quoted-Printable standard to encode a string.
+ */
+
+boolean quotedPCollapse(char *line);
+/* Use Quoted-Printable standard to decode a string.
+ * Return true if the line does not end in '='
+ * which indicate continuation. */
+
+char *quotedPrintableDecode(char *input);
+/* Use Quoted-Printable standard to decode a string.  Return decoded
+ * string which will be freeMem'd. */
+
+#endif /* QUOTEDP_H */
+
diff --git a/inc/ra.h b/inc/ra.h
new file mode 100644
index 0000000..96d38bc
--- /dev/null
+++ b/inc/ra.h
@@ -0,0 +1,81 @@
+/* Stuff to parse .ra files. Ra files are simple text databases.
+ * The database is broken into records by blank lines.
+ * Each field takes a line.  The name of the field is the first
+ * word in the line.  The value of the field is the rest of the line.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef RA_H
+
+struct hash *raNextStanza(struct lineFile *lf);
+// Return a hash containing next record.
+// Will ignore '#' comments and joins continued lines (ending in '\').
+// Returns NULL at end of file.  freeHash this when done.
+// Note this will free the hash keys and values as well,
+// so you'll have to cloneMem them if you want them for later.
+#define raNextRecord(lf)  raNextStanza(lf)
+
+struct slPair *raNextStanzAsPairs(struct lineFile *lf);
+// Return ra stanza as an slPair list instead of a hash.  Handy to preserve the
+// order.  Will ignore '#' comments and joins continued lines (ending in '\').
+#define raNextRecordAsSlPairList(lf)  raNextStanzAsPairs(lf)
+
+struct slPair *raNextStanzaLinesAndUntouched(struct lineFile *lf);
+// Return list of lines starting from current position, up through last line of next stanza.
+// May return a few blank/comment lines at end with no real stanza.
+// Will join continuation lines, allocating memory as needed.
+// returns pairs with name=joined line and if joined,
+// val will contain raw lines '\'s and linefeeds, else val will be NULL.
+
+boolean raSkipLeadingEmptyLines(struct lineFile *lf, struct dyString *dy);
+/* Skip leading empty lines and comments.  Returns FALSE at end of file.
+ * Together with raNextTagVal you can construct your own raNextRecord....
+ * If dy parameter is non-null, then the text parsed gets placed into dy. */
+
+boolean raNextTagVal(struct lineFile *lf, char **retTag, char **retVal, struct dyString  *dy);
+// Read next line.  Return FALSE at end of file or blank line.  Otherwise fill in
+// *retTag and *retVal and return TRUE.  If dy parameter is non-null, then the text parsed
+// gets appended to dy. Continuation lines in RA file will be joined to produce tag and val,
+// but dy will be filled with the unedited multiple lines containing the continuation chars.
+
+struct hash *raFromString(char *string);
+/* Return hash of key/value pairs from string.
+ * As above freeHash this when done. */
+
+boolean raFoldInOne(struct lineFile *lf, struct hash *hashOfHash);
+/* Fold in one record from ra file into hashOfHash.
+ * This will add ra's and ra fields to whatever already
+ * exists in the hashOfHash,  overriding fields of the
+ * same name if they exist already. */
+
+void raFoldIn(char *fileName, struct hash *hashOfHash);
+/* Read ra's in file name and fold them into hashOfHash.
+ * This will add ra's and ra fields to whatever already
+ * exists in the hashOfHash,  overriding fields of the
+ * same name if they exist already. */
+
+struct hash *raReadSingle(char *fileName);
+/* Read in first ra record in file and return as hash. */
+
+struct hash *raReadAll(char *fileName, char *keyField);
+/* Return hash that contains all ra records in file keyed
+ * by given field, which must exist.  The values of the
+ * hash are themselves hashes. */
+
+struct hash *raReadWithFilter(char *fileName, char *keyField,char *filterKey,char *filterValue);
+/* Return hash that contains all filtered ra records in file keyed by given field, which must exist.
+ * The values of the hash are themselves hashes.  The filter is a key/value pair that must exist.
+ * Example raReadWithFilter(file,"term","type","antibody"): returns hash of hashes of every term with type=antibody */
+
+struct hash *raReadThreeLevels(char *fileName, char *lowKeyField, char *middleKeyField);
+/* Return 3 level hash that contains all ra records in file keyed by lowKeyField, which must exist.
+ * and broken into sub hashes based upon middleKeyField that must exist.
+ * Example raReadThreeLevels("cv.ra","term","type"):
+ *         returns hash of 'type' hashes of 'term' hashes of every stanza in cv.ra */
+
+struct hash *raTagVals(char *fileName, char *tag);
+/* Return a hash of all values of given tag seen in any stanza of ra file. */
+
+#endif /* RA_H */
+
diff --git a/inc/rainbow.h b/inc/rainbow.h
new file mode 100644
index 0000000..580786a
--- /dev/null
+++ b/inc/rainbow.h
@@ -0,0 +1,18 @@
+/* rainbow - stuff to generate rainbow colors. */
+
+#ifndef RAINBOW_H
+#define RAINBOW_H
+
+#ifndef MEMGFX_H
+#include "memgfx.h"
+#endif
+
+struct rgbColor saturatedRainbowAtPos(double pos);
+/* Given pos, a number between 0 and 1, return a saturated rainbow rgbColor
+ * where 0 maps to red,  0.1 is orange, and 0.9 is violet and 1.0 is back to red */
+
+struct rgbColor lightRainbowAtPos(double pos);
+/* Given pos, a number between 0 and 1, return a lightish rainbow rgbColor
+ * where 0 maps to red,  0.1 is orange, and 0.9 is violet and 1.0 is back to red */
+
+#endif /* RAINBOW_H */
diff --git a/inc/rangeTree.h b/inc/rangeTree.h
new file mode 100644
index 0000000..e2ceeca
--- /dev/null
+++ b/inc/rangeTree.h
@@ -0,0 +1,98 @@
+/* rangeTree - This module is a way of keeping track of
+ * non-overlapping ranges (half-open intervals). It is
+ * based on the self-balancing rbTree code.  Use it in
+ * place of a bitmap when the total number of ranges
+ * is significantly smaller than the number of bits would
+ * be. */
+
+#ifndef RANGETREE_H
+#define RANGETREE_H
+
+#ifndef RBTREE_H
+#include "rbTree.h"
+#endif
+
+struct range
+/* An interval in a list of intervals. */
+    {
+    struct range *next;
+    int start,end;	/* Zero based half open interval. */
+    void *val;		/* Some value associated with range. */
+    };
+
+struct rbTree *rangeTreeNew();
+/* Create a new, empty, rangeTree.  Free with rbFreeTree. */
+
+#define rangeTreeFree(a) rbTreeFree(a)
+/* Free up range tree.  */
+
+int rangeCmp(void *va, void *vb);
+/* Return -1 if a before b,  0 if a and b overlap,
+ * and 1 if a after b. */
+
+
+struct range *rangeTreeAddVal(struct rbTree *tree, int start, int end, void *val, void *(*mergeVals)(void *existingVal, void *newVal) );
+/* Add range to tree, merging with existing ranges if need be. 
+ * If this is a new range, set the value to this val.
+ * If there are existing items for this range, and if mergeVals function is not null, 
+ * apply mergeVals to the existing values and this new val, storing the result as the val
+ * for this range (see rangeTreeAddValCount() and rangeTreeAddValList() below for examples). */
+
+struct range *rangeTreeAdd(struct rbTree *tree, int start, int end);
+/* Add range to tree, merging with existing ranges if need be. */
+
+struct range *rangeTreeAddValCount(struct rbTree *tree, int start, int end);
+/* Add range to tree, merging with existing ranges if need be. 
+ * Set range val to count of elements in the range. Counts are pointers to 
+ * ints allocated in tree localmem */
+
+struct range *rangeTreeAddValList(struct rbTree *tree, int start, int end, void *val);
+/* Add range to tree, merging with existing ranges if need be. 
+ * Add val to the list of values (if any) in each range.
+ * val must be valid argument to slCat (ie, be a struct with a 'next' pointer as its first member) */
+
+void rangeTreeAddToCoverageDepth(struct rbTree *tree, int start, int end);
+/* Add area from start to end to a tree that is being built up to store the
+ * depth of coverage.  Recover coverage back out by looking at ptToInt(range->val)
+ * on tree elements. */
+
+boolean rangeTreeOverlaps(struct rbTree *tree, int start, int end);
+/* Return TRUE if start-end overlaps anything in tree */
+
+int rangeTreeOverlapSize(struct rbTree *tree, int start, int end);
+/* Return the total size of intersection between interval
+ * from start to end, and items in range tree. Sadly not
+ * thread-safe.
+ * On 32 bit machines be careful not to overflow
+ * range of start, end or total size return value. */
+
+int rangeTreeOverlapTotalSize(struct rbTree *tree);
+/* Return the total size of all ranges in range tree.
+ * Sadly not thread-safe. 
+ * On 32 bit machines be careful not to overflow
+ * range of start, end or total size return value. */
+
+struct range *rangeTreeFindEnclosing(struct rbTree *tree, int start, int end);
+/* Find item in range tree that encloses range between start and end 
+ * if there is any such item. */
+
+struct range *rangeTreeAllOverlapping(struct rbTree *tree, int start, int end);
+/* Return list of all items in range tree that overlap interval start-end.
+ * Do not free this list, it is owned by tree.  However it is only good until
+ * next call to rangeTreeFindInRange or rangTreeList. Not thread safe. */
+
+struct range *rangeTreeMaxOverlapping(struct rbTree *tree, int start, int end);
+/* Return item that overlaps most with start-end. Not thread safe.  Trashes list used
+ * by rangeTreeAllOverlapping. */
+
+struct range *rangeTreeList(struct rbTree *tree);
+/* Return list of all ranges in tree in order.  Not thread safe. 
+ * No need to free this when done, memory is local to tree. */
+
+struct rbTree *rangeTreeNewDetailed(struct lm *lm, struct rbTreeNode *stack[128]);
+/* Allocate rangeTree on an existing local memory & stack.  This is for cases
+ * where you want a lot of trees, and don't want the overhead for each one. 
+ * Note, to clean these up, just do freez(&rbTree) rather than rbFreeTree(&rbTree). */
+
+#endif /* RANGETREE_H */
+
diff --git a/inc/rbTree.h b/inc/rbTree.h
new file mode 100644
index 0000000..c42c328
--- /dev/null
+++ b/inc/rbTree.h
@@ -0,0 +1,102 @@
+/* rbTree - rbTreeRed-rbTreeBlack Tree - a type of binary tree which 
+ * automatically keeps relatively balanced during
+ * inserts and deletions.
+ *   original author: Shane Saunders
+ *   adapted into local conventions: Jim Kent
+ */
+#ifndef RBTREE_H
+#define RBTREE_H
+
+typedef enum {rbTreeRed,rbTreeBlack} rbTreeColor;
+
+
+/* Structure type for nodes in the red-black tree. */
+struct rbTreeNode 
+    {
+    struct rbTreeNode *left, *right;		/* Children. */
+    rbTreeColor color;				/* Heart of algorithm. */
+    void *item;					/* Item stored in tree */
+    };
+
+/* Structure type for the red-black tree. */
+struct rbTree 
+    {
+    struct rbTree *next;			/* Next tree in list. */
+    struct rbTreeNode *root;			/* Root of tree */
+    int n;					/* Number of items in tree. */
+    int (* compare)(void *, void *);/* Comparison function */
+    struct rbTreeNode **stack;                  /* Ancestor stack. */
+    struct lm *lm;	                        /* Local memory pool. */
+    struct rbTreeNode *freeList;		/* List of nodes to reuse. */
+    };
+
+struct rbTree *rbTreeNew(int (*compare)(void *, void *));
+/* Allocates space for a red-black tree and returns a pointer
+ * to it.  The function compare compares they keys of two items, and returns a
+ * negative, zero, or positive integer depending on whether the first item is
+ * less than, equal to, or greater than the second. */
+
+void rbTreeFree(struct rbTree **pTree);
+/* Frees space used by the red-black tree pointed to by t. */
+
+void rbTreeFreeList(struct rbTree **pList);
+/* Free up a list of rbTrees. */
+
+struct rbTree *rbTreeNewDetailed(int (*compare)(void *, void *), struct lm *lm, 
+	struct rbTreeNode *stack[128]);
+/* Allocate rbTree on an existing local memory & stack.  This is for cases
+ * where you want a lot of trees, and don't want the overhead for each one. 
+ * Note, to clean these up, just do freez(&rbTree) rather than rbFreeTree(&rbTree). */
+
+void *rbTreeAdd(struct rbTree *t, void *item);
+/* Inserts an item into the red-black tree pointed to by t,
+ * according the the value its key.  The key of an item in the red-black
+ * tree must be unique among items in the tree.  If an item with the same key
+ * already exists in the tree, a pointer to that item is returned.  Otherwise,
+ * NULL is returned, indicating insertion was successful.
+ */
+
+void *rbTreeFind(struct rbTree *t, void *item);
+/* Find an item in the red-black tree with the same key as the
+ * item pointed to by `item'.  Returns a pointer to the item found, or NULL
+ * if no item was found.
+ */
+
+void *rbTreeRemove(struct rbTree *t, void *item);
+/* rbTreeRemove() - Delete an item in the red-black tree with the same key as
+ * the item pointed to by `item'.  Returns a pointer to the  deleted item,
+ * and NULL if no item was found.
+ */
+
+void rbTreeTraverseRange(struct rbTree *tree, void *minItem, void *maxItem,
+	void (*doItem)(void *item));
+/* Apply doItem function to all items in tree such that
+ * minItem <= item <= maxItem */
+
+struct slRef *rbTreeItemsInRange(struct rbTree *tree, void *minItem, void *maxItem);
+/* Return a sorted list of references to items in tree between range.
+ * slFreeList this list when done. */
+
+void rbTreeTraverse(struct rbTree *tree, void (*doItem)(void *item));
+/* Apply doItem function to all items in tree */
+
+void rbTreeTraverseWithContext(struct rbTree *tree, 
+	void (*doItem)(void *item, void *context), void *context);
+/* Traverse tree calling doItem on every item with context pointer passed through to doItem.
+ * This often avoids having to declare global or static variables for the doItem callback to use. */
+
+struct slRef *rbTreeItems(struct rbTree *tree);
+/* Return sorted list of items.  slFreeList this when done.*/
+
+void rbTreeDump(struct rbTree *tree, FILE *f, 
+	void (*dumpItem)(void *item, FILE *f));
+/* Dump out rb tree to file, mostly for debugging. */
+
+int rbTreeCmpString(void *a, void *b);	
+/* Set up rbTree so as to work on strings. */
+
+int rbTreeCmpWord(void *a, void *b);	
+/* Set up rbTree so as to work on case-insensitive strings. */
+
+#endif /* RBTREE_H */
+
diff --git a/inc/regexHelper.h b/inc/regexHelper.h
new file mode 100644
index 0000000..37c5e70
--- /dev/null
+++ b/inc/regexHelper.h
@@ -0,0 +1,29 @@
+/* regexHelper: easy wrappers on POSIX Extended Regular Expressions (man 7 regex, man 3 regex) */
+
+#ifndef REGEXHELPER_H
+#define REGEXHELPER_H
+
+#include "common.h"
+#include <regex.h>
+
+const regex_t *regexCompile(const char *exp, const char *description, int compileFlags);
+/* Compile exp (or die with an informative-as-possible error message).
+ * Cache pre-compiled regex's internally (so don't free result after use). */
+
+boolean regexMatch(const char *string, const char *exp);
+/* Return TRUE if string matches regular expression exp (case sensitive). */
+
+boolean regexMatchNoCase(const char *string, const char *exp);
+/* Return TRUE if string matches regular expression exp (case insensitive). */
+
+boolean regexMatchSubstr(const char *string, const char *exp,
+			 regmatch_t substrArr[], size_t substrArrSize);
+/* Return TRUE if string matches regular expression exp (case sensitive);
+ * regexec fills in substrArr with substring offsets. */
+
+boolean regexMatchSubstrNoCase(const char *string, const char *exp,
+			       regmatch_t substrArr[], size_t substrArrSize);
+/* Return TRUE if string matches regular expression exp (case insensitive);
+ * regexec fills in substrArr with substring offsets. */
+
+#endif // REGEXHELPER_H
diff --git a/inc/repMask.h b/inc/repMask.h
new file mode 100644
index 0000000..6e25563
--- /dev/null
+++ b/inc/repMask.h
@@ -0,0 +1,56 @@
+/* repMask.h was originally generated by the autoSql program, which also 
+ * generated repMask.c and repMask.sql.  This header links the database and the RAM 
+ * representation of objects. */
+
+#ifndef REPMASK_H
+#define REPMASK_H
+
+struct repeatMaskOut
+/* Repeat Masker out format */
+    {
+    struct repeatMaskOut *next;  /* Next in singly linked list. */
+    unsigned score;	/* Smith-Waterman score. */
+    float percDiv;	/* Percentage base divergence. */
+    float percDel;	/* Percentage deletions. */
+    float percInc;	/* Percentage inserts. */
+    char *qName;	/* Name of query. */
+    int qStart;	/* Start query position. */
+    int qEnd;	/* End query position. */
+    char *qLeft;	/* Bases left in query. */
+    char strand[2];	/* Query strand (+ or C) */
+    char *rName;	/* Repeat name */
+    char *rFamily;	/* Repeat name */
+    char *rStart;	/* Start position in repeat. */
+    unsigned rEnd;	/* End position in repeat. */
+    char *rLeft;	/* Bases left in repeat. */
+    };
+
+void repeatMaskOutStaticLoad(char **row, struct repeatMaskOut *ret);
+/* Load a row from repeatMaskOut table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+
+struct repeatMaskOut *repeatMaskOutLoad(char **row);
+/* Load a repeatMaskOut from row fetched with select * from repeatMaskOut
+ * from database.  Dispose of this with repeatMaskOutFree(). */
+
+struct repeatMaskOut *repeatMaskOutCommaIn(char **pS);
+/* Create a repeatMaskOut out of a comma separated string. */
+
+void repeatMaskOutFree(struct repeatMaskOut **pEl);
+/* Free a single dynamically allocated repeatMaskOut such as created
+ * with repeatMaskOutLoad(). */
+
+void repeatMaskOutFreeList(struct repeatMaskOut **pList);
+/* Free a list of dynamically allocated repeatMaskOut's */
+
+void repeatMaskOutOutput(struct repeatMaskOut *el, FILE *f, char sep, char lastSep);
+/* Print out repeatMaskOut.  Separate fields with sep. Follow last field with lastSep. */
+
+#define repeatMaskOutTabOut(el,f) repeatMaskOutOutput(el,f,'\t','\n');
+/* Print out repeatMaskOut as a line in a tab-separated file. */
+
+#define repeatMaskOutCommaOut(el,f) repeatMaskOutOutput(el,f,',',',');
+/* Print out repeatMaskOut as a comma separated list including final comma. */
+
+#endif /* REPMASK_H */
+
diff --git a/inc/rle.h b/inc/rle.h
new file mode 100644
index 0000000..7a08188
--- /dev/null
+++ b/inc/rle.h
@@ -0,0 +1,16 @@
+/* rle - byte oriented run length encoding. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef RLE_H
+#define RLE_H
+
+int rleCompress(void *in, int inSize, signed char *out);
+/* Compress in to out.  Out should be at least inSize * 1.5. 
+ * Returns compressed size. */
+
+void rleUncompress(signed char *in, int inSize, void *out, int outSize);
+/* Uncompress in to out. */
+
+#endif /* RLE_H */
diff --git a/inc/rnautil.h b/inc/rnautil.h
new file mode 100644
index 0000000..4905edb
--- /dev/null
+++ b/inc/rnautil.h
@@ -0,0 +1,55 @@
+/* rnautil.h - functions for dealing with RNA and RNA secondary structure.  */
+#ifndef RNAUTIL_H
+#define RNAUTIL_H
+
+#ifndef COMMON_H
+#include "common.h"
+#endif
+
+extern const char *RNA_PAIRS[];
+/* Null terminated array of rna pairs */
+
+void dna2rna(char *s);
+/* Replace 't' with 'u' and 'T' with 'U'. */
+
+bool rnaPair(char a, char b);
+/* Returns TRUE if a and b can pair, and false otherwise */
+
+void reverseFold(char *s);
+/* Reverse the order of the parenthesis defining an RNA secondary structure annotation. */
+
+void fold2pairingList(char *fold, int len, int **p2pairList);
+/* take a parenthesis string, allocate and return an array of pairing
+   positions: pairList[i] = j <=> i pair with j and pairList[i] = -1
+   <=> i does not pair.*/
+
+void mkPairPartnerSymbols(int * pairList, char * pairSymbols, int size);
+/* Make a symbol string indicating pairing partner */
+
+char * projectString(char * s, char * ref, char refChar, char insertChar);
+/* Insert 'insertChar' in 's' at every positin 'ref' has 'refChar'. */
+
+char * gapAdjustFold(char * s, char * ref);
+/* Insert space in s when there is a gap ('-') in ref. */
+
+int * projectIntArray(int * in, char * ref, char refChar, int insertInt);
+/* Insert 'insertChar' in 's' at every positin 'ref' has 'refChar'. */
+
+int * gapIntArrayAdjust(int * in, char * ref);
+/* Insert space in s when there is a gap ('-') in ref. */
+
+void markCompensatoryMutations(char *s, char *ref, int * pairList, int *markList);
+/* Compares s to ref and pairList and sets values in markList
+ * according to pairing properties. The value of markList[i] specifies
+ * the pairing property of the i'th position. The following values are
+ * used: -1: default; 0: ref[i] = s[i] and both compatible with
+ * pairList, 1: ref[i] != s[i] and both compatible with pairList; 2:
+ * s[i] not compatible with pairList;
+ */
+
+int assignBin(double val, double minVal, double maxVal, int binCount);
+/* Divide range given by minVal and maxVal into maxBin+1 intervals
+   (bins), and return index of the bin val falls into. */
+
+#endif /* RNAUTIL_H */
+
diff --git a/inc/rql.h b/inc/rql.h
new file mode 100644
index 0000000..8dd934f
--- /dev/null
+++ b/inc/rql.h
@@ -0,0 +1,130 @@
+/* rql.h - interface to RQL (Ra Query Language - similar in syntax to SQL) parser and
+ * interpreter. */
+
+#ifndef RQL_H
+#define RQL_H
+
+#ifndef TOKENIZER_H
+#include "tokenizer.h"
+#endif
+
+enum rqlOp
+/* An operation in the parse tree. */
+    {
+    rqlOpUnknown,	/* Should not occur */
+    rqlOpLiteral,        /* Literal string or number. */
+    rqlOpSymbol,	/* A symbol name. */
+
+    /* Type casts. */
+    rqlOpStringToBoolean,	
+    rqlOpIntToBoolean,
+    rqlOpDoubleToBoolean,
+    rqlOpStringToInt,
+    rqlOpDoubleToInt,
+    rqlOpBooleanToInt,
+    rqlOpStringToDouble,
+    rqlOpBooleanToDouble,
+    rqlOpIntToDouble,
+
+    /* Comparisons. */
+    rqlOpEq,	/* An equals comparison */
+    rqlOpNe,	/* A not equals comparison */
+    rqlOpGt,  /* Greater than comparison. */
+    rqlOpLt,  /* Less than comparison. */
+    rqlOpGe,  /* Greater than or equals comparison. */
+    rqlOpLe,  /* Less than or equals comparison. */
+    rqlOpLike, /* SQL wildcard compare. */
+
+    /* Logic ops. */
+    rqlOpAnd,     /* An and */
+    rqlOpOr,      /* An or */
+    rqlOpNot,	  /* A unary not. */
+
+    /* Leading minus. */
+    rqlOpUnaryMinusInt,
+    rqlOpUnaryMinusDouble,
+
+    /* Fancy ops to fetch sub-parts. */
+    rqlOpArrayIx,	/* An array with an index. */
+    };
+
+char *rqlOpToString(enum rqlOp op);
+/* Return string representation of parse op. */
+
+enum rqlType
+/* A type */
+    {
+    rqlTypeBoolean = 1,
+    rqlTypeString = 2,
+    rqlTypeInt = 3,
+    rqlTypeDouble = 4,
+    };
+
+union rqlVal
+/* Some value of arbirary type that can be of any type corresponding to rqlType */
+    {
+    boolean b;
+    char *s;
+    int i;
+    double x;
+    };
+
+struct rqlEval
+/* Result of evaluation of parse tree. */
+    {
+    enum rqlType type;
+    union rqlVal val;
+    };
+
+struct rqlParse
+/* A rql parse-tree. */
+    {
+    struct rqlParse *next;	/* Points to younger sibling if any. */
+    struct rqlParse *children;	/* Points to oldest child if any. */
+    enum rqlOp op;		/* Operation at this node. */
+    enum rqlType type;		/* Return type of this operation. */
+    union rqlVal val;		/* Return value of this operation. */
+    };
+
+struct rqlStatement
+/* A parsed out RQL statement */
+    {
+    char *next;		/* Next in list */
+    char *command;	/* Generally the first word in the statement. */
+    struct slName *fieldList;	/* List of fields if any. */
+    struct slName *tableList;	/* List of tables if any. */
+    struct rqlParse *whereClause;	/* Where clause if any - in parse tree. */
+    struct slName *whereVarList;	/* List of variables used in where clause. */
+    int limit;		/* If >= 0 then limits # of records returned. */
+    };
+
+void rqlValDump(union rqlVal val, enum rqlType type, FILE *f);
+/* Dump out value to file. */
+
+void rqlParseDump(struct rqlParse *p, int depth, FILE *f);
+/* Dump out rqlParse tree and children. */
+
+struct rqlParse *rqlParseExpression(struct tokenizer *tkz);
+/* Parse out a clause, usually a where clause. */
+
+struct rqlStatement *rqlStatementParse(struct lineFile *lf);
+/* Parse an RQL statement out of text */
+
+void rqlStatementFree(struct rqlStatement **pRql);
+/* Free up an rql statement. */
+
+void rqlStatementDump(struct rqlStatement *rql, FILE *f);
+/* Print out statement to file. */
+
+typedef char* (*RqlEvalLookup)(void *record, char *key);
+/* Callback for rqlEvalOnRecord to lookup a variable value. */
+
+struct rqlEval rqlEvalOnRecord(struct rqlParse *p, void *record, RqlEvalLookup lookup,
+	struct lm *lm);
+/* Evaluate parse tree on record, using lm for memory for string operations. */
+
+struct rqlEval rqlEvalCoerceToBoolean(struct rqlEval r);
+/* Return TRUE if it's a nonempty string or a non-zero number. */
+
+#endif /* RQL_H */
+
diff --git a/inc/rudp.h b/inc/rudp.h
new file mode 100644
index 0000000..6bec32e
--- /dev/null
+++ b/inc/rudp.h
@@ -0,0 +1,175 @@
+/* rudp - (semi) reliable UDP communication.  This adds an
+ * acknowledgement and resend layer on top of UDP. 
+ *
+ * UDP is a packet based rather than stream based internet communication 
+ * protocol. Messages sent by UDP are checked for integrety by the UDP layer, 
+ * and discarded if transmission errors are detected.  However packets are
+ * not necessarily received in the same order that they are sent,
+ * and packets may be duplicated or lost.  
+ 
+ * Using rudp packets are only very rarely lost, and the sender is 
+ * notified if they are.  After rudp there are still duplicate
+ * packets that may arrive out of order.  Aside from the duplicates
+ * the packets are in order though.
+ *
+ * For many, perhaps most applications, TCP/IP is a saner choice
+ * than UDP or rudp.  If the communication channel is between just 
+ * two computers you can pretty much just treat TCP/IP as a fairly
+ * reliable pipe.   However if the communication involves many
+ * computers sometimes UDP can be a better choice.  It is possible to
+ * do broadcast and multicast with UDP but not with TCP/IP.  Also
+ * for systems like parasol, where a server may be making and breaking
+ * connections rapidly to thousands of computers, TCP paradoxically
+ * can end up less reliable than UDP.  Though TCP is relatively 
+ * robust when a connection is made,  it can relatively easily fail
+ * to make a connection in the first place, and spend quite a long
+ * time figuring out that the connection can't be made.  Moreover at
+ * the end of each connection TCP goes into a 'TIMED_WAIT' state,  which
+ * prevents another connection from coming onto the same port for a
+ * time that can be as long as 255 seconds.  Since there are only
+ * about 15000 available ports,  this limits TCP/IP to 60 connections
+ * per second in some cases.  Generally the system does not handle
+ * running out of ports gracefully, and this did occur with the 
+ * TCP/IP based version of Parasol.
+ *
+ * This module puts a thin layer around UDP to make it a little bit more
+ * reliable.  Currently the interface is geared towards Parasol rather
+ * than broadcast type applications.  This module will try to send
+ * a message a limited number of times before giving up.  It puts
+ * a small header containing a message ID and timestamp on each message.   
+ * This header is echoed back in acknowledgment by the reciever. This
+ * echo lets the sender know if it needs to resend the message, and
+ * lets it know how long a message takes to get to the destination and
+ * back.  It uses this round trip time information to figure out how
+ * long to wait between resends. 
+ *
+ * Much of this code is based on the 'Adding Reliability to a UDP Application
+ * section in volume I, chapter 20, section 5, of _UNIX Network Programming_
+ * by W. Richard Stevens. */
+
+#ifndef RUDP_H
+#define RUDP_H
+
+#ifndef INTERNET_H
+#include "internet.h"
+#endif
+
+#include "hash.h"
+#include "dlist.h"
+
+struct rudp
+/* A UDP socket and a little bit of stuff to help keep track
+ * of how often we should resend unacknowledged messages. */
+    {
+    int socket;		/* The associated UDP socket. */
+    int rttLast;	/* Last round trip time (RTT) for a message/ack in microseconds. */
+    int rttAve;		/* Approximate average of recent RTTs. */
+    int rttVary;	/* Approximate variation of recent RTTs. */
+    int timeOut;	/* Ideal timeout for next receive. */
+    int receiveCount;	/* Number of packets attempted to receive. */
+    int sendCount;	/* Number of packets attempted to send. */
+    int resendCount;	/* Number of resends. */
+    int failCount;	/* Number of failures. */
+    bits32 lastId;	/* Id number of last message sent. */
+    int maxRetries;	/* Maximum number of retries per message. */
+    bits32 lastIdReceived; /* Id number of last message received. */
+    boolean resend;     /* TRUE if the packet is a re-send */
+    int pid;                 /* sender process id - helps filter out duplicate received packets */
+    int connId;              /* sender conn id - helps filter out duplicate received packets */
+    struct hash *recvHash;   /* hash of data received - helps filter out duplicate received packets */
+    struct dlList *recvList; /* list of data received - helps filter out duplicate received packets */
+    int recvCount;           /* number in list clean */
+    };
+
+enum rudpType
+    {
+    rudpAck = 199,	/* Acknowledge message. */
+    rudpData = 200,	/* Message with some data. */
+    };
+
+struct rudpHeader
+/* The header to a rudp message.  */
+    {
+    bits32 id;		/* Message id.  Returned with ack. */
+    bits32 sendSec;	/* Time sent in seconds.  Returned with ack. */
+    bits32 sendMicro;	/* Time sent microseconds. Returned with ack. */
+    bits8 type;		/* One of rudpType above. */
+    bits8 reserved1;	/* Reserved, always zero for now. */
+    bits8 reserved2;	/* Reserved, always zero for now. */
+    bits8 reserved3;	/* Reserved, always zero for now. */
+    int pid;            /* sender process id - helps filter out duplicate received packets */
+    int connId;         /* sender conn id - helps filter out duplicate received packets */
+    };
+
+struct packetSeen
+/* A packet was last seen when? */
+    {
+    char *recvHashKey;          /* hash key */
+    time_t lastChecked;		/* Last time we checked machine in seconds past 1972 */
+    struct dlNode *node;        /* List node of packetSeen. */
+    };
+
+typedef bits32 rudpHost;  /* The IP address (in host order) of another computer. */
+
+#define udpEthMaxSize 1444
+    /* Max data size that will fit into a single ethernet packet after UDP and IP
+     * headers.  Things are faster & more reliable if you stay below this */
+
+#define rudpMaxSize (udpEthMaxSize - sizeof(struct rudpHeader)  )
+
+struct rudp *rudpNew(int socket);
+/* Wrap a rudp around a socket. Call rudpFree when done, or
+ * rudpClose if you also want to close(socket). */
+
+void rudpFree(struct rudp **pRu);
+/* Free up rudp.  Note this does *not* close the associated socket. */
+
+struct rudp *rudpOpen();
+/* Open up an unbound rudp.   This is suitable for
+ * writing to and for reading responses.  However 
+ * you'll want to rudpOpenBound if you want to listen for
+ * incoming messages.   Call rudpClose() when done 
+ * with this one.  Warns and returns NULL if there is
+ * a problem. */
+
+struct rudp *rudpMustOpen();
+/* Open up unbound rudp.  Warn and die if there is a problem. */
+
+struct rudp *rudpOpenBound(struct sockaddr_in *sai);
+/* Open up a rudp socket bound to a particular port and address.
+ * Use this rather than rudpOpen if you want to wait for
+ * messages at a specific address in a server or the like. */
+
+struct rudp *rudpMustOpenBound(struct sockaddr_in *sai);
+/* Open up a rudp socket bound to a particular port and address
+ * or die trying. */
+
+void rudpClose(struct rudp **pRu);
+/* Close socket and free memory. */
+
+int rudpSend(struct rudp *ru, struct sockaddr_in *sai, void *message, int size);
+/* Send message of given size to port at host via rudp.  Prints a warning and
+ * sets errno and returns -1 if there's a problem. */
+
+int rudpReceive(struct rudp *ru, void *messageBuf, int bufSize);
+/* Read message into buffer of given size.  Returns actual size read on
+ * success. On failure prints a warning, sets errno, and returns -1. */
+
+int rudpReceiveFrom(struct rudp *ru, void *messageBuf, int bufSize, 
+	struct sockaddr_in *retFrom);
+/* Read message into buffer of given size.  Returns actual size read on
+ * success. On failure prints a warning, sets errno, and returns -1. 
+ * Also returns ip address of message source. */
+
+int rudpReceiveTimeOut(struct rudp *ru, void *messageBuf, int bufSize, 
+	struct sockaddr_in *retFrom, int timeOut);
+/* Like rudpReceive from above, but with a timeOut (in microseconds)
+ * parameter.  If timeOut is zero then it will wait forever. */
+
+void rudpPrintStatus(struct rudp *ru);
+/* Print out status info. */
+
+void rudpTest();
+/* Test out rudp stuff. */
+
+#endif /* RUDP_H */
diff --git a/inc/scoreWindow.h b/inc/scoreWindow.h
new file mode 100644
index 0000000..43fec29
--- /dev/null
+++ b/inc/scoreWindow.h
@@ -0,0 +1,7 @@
+/* scoreWindow - find window with most matches to a given char */
+
+/* simple program to find max scoring window representing string of char c in a string s of size size */
+/* index of max score is returned , match and misMatch are the scores to assign, suggested defaults are match=1 and misMatch=1*/
+/* when used for scoring polyA tails, set c='A' for positive strand  or c='T' for neg strand */
+/* start, end are returned pointing to the start and end of the highest scoring window in s */
+int scoreWindow(char c, char *s, int size, int *score, int *start, int *end, int match, int misMatch);
diff --git a/inc/seg.h b/inc/seg.h
new file mode 100644
index 0000000..940639c
--- /dev/null
+++ b/inc/seg.h
@@ -0,0 +1,109 @@
+/* seg.h - Segment file format. */
+#ifndef SEG_H
+#define SEG_H
+
+#include "common.h"
+
+struct segComp
+/* A genomic segment. */
+	{
+	struct segComp *next;
+	char *src;		/* Name of segment source. */
+	int start;		/* Start of segment. Zero based. If strand is - it is */
+					/*   relative to source end.*/
+	int size;		/* Size of segment. */
+	char strand;	/* Strand of segment. Either + or -. */
+	int srcSize;	/* Size of segment source. */
+	};
+
+struct segBlock
+/* A list of genomic segments. */
+	{
+	struct segBlock *next;
+	struct segBlock *prev;
+	char *name;					/* Name of this segment list. */
+	int val;					/* Integer value for this segment list. */
+	struct segComp *components;	/* List of segments in this segment list. */
+	};
+
+struct segFile
+/* A file full of genomic segments. */
+	{
+	struct segFile *next;
+	int version;				/* segFile version. */
+	struct segBlock *blocks;	/* Possibly empty list of segment blocks. */
+	struct lineFile *lf;		/* Open lineFile if any. */
+	};
+
+void segCompFree(struct segComp **pObj);
+/* Free up a segment component. */
+
+void segCompFreeList(struct segComp **pList);
+/* Free up a list of segment components. */
+
+void segBlockFree(struct segBlock **pObj);
+/* Free up a segment block. */
+
+void segBlockFreeList(struct segBlock **pList);
+/* Free up a list of segment blocks. */
+
+void segFileFree(struct segFile **pObj);
+/* Free up a segment file including closing file handle if necessary. */
+
+void segFileFreeList(struct segFile **pList);
+/* Free up a list of segment files. */
+
+struct segFile *segMayOpen(char *fileName);
+/* Open up a segment file for reading. Read header and verify. Prepare
+ * for subsequent calls to segNext(). Return NULL if file does not exist. */
+
+struct segFile *segOpen(char *fileName);
+/* Like segMayOpen() above, but prints an error message and aborts if
+ * there is a problem. */
+
+void segRewind(struct segFile *sf);
+/* Seek to beginning of open segment file */
+
+struct segBlock *segNextWithPos(struct segFile *sf, off_t *retOffset);
+/* Return next segment in segment file or NULL if at end. If retOffset
+ * is not NULL, return start offset of record in file. */
+
+struct segBlock *segNext(struct segFile *sf);
+/* Return next segment in segment file or NULL if at end.  This will
+ * close the open file handle at the end as well. */
+
+struct segFile *segReadAll(char *fileName);
+/* Read in full segment file */
+
+void segWriteStart(FILE *f);
+/* Write segment file header to the file. */
+
+void segWrite(FILE *f, struct segBlock *block);
+/* Write next segment block to the file. */
+
+void segWriteEnd(FILE *f);
+/* Write segment file end tag to the file. */
+
+struct segComp *segMayFindCompSpecies(struct segBlock *sb, char *src,
+	char sepChar);
+/* Find component with a source that matches src up to and possibly
+   including sepChar. Return NULL if not found. */
+
+struct segComp *segFindCompSpecies(struct segBlock *sb, char *src,
+	char sepChar);
+/* Find component with a source that matches src up to and possibly
+   including sepChar or die trying. */
+
+struct segComp *cloneSegComp(struct segComp *sc);
+/* Return a copy of the argument segment component. */
+
+char *segFirstCompSpecies(struct segBlock *sb, char sepChar);
+/* Return the species possibly followed by sepChar of the first component
+   of the argument block. Return NULL if the block has no components. */
+
+struct slName *segSecSpeciesList(struct segBlock *sb, struct segComp *refComp,
+	char sepChar);
+/* Return a name list containing the species possibly followed by sepChar
+of all components other than refComp on the block. */
+
+#endif /* SEG_H */
diff --git a/inc/seqOut.h b/inc/seqOut.h
new file mode 100644
index 0000000..f3daf29
--- /dev/null
+++ b/inc/seqOut.h
@@ -0,0 +1,91 @@
+/* seqOut - stuff to output sequences and alignments in web 
+ * or ascii viewable form. */
+
+
+struct cfm
+/* Colored web character output formatter. */
+    {
+    int wordLen;	/* Number of characters between spaces (often 10) */
+    int lineLen;        /* Number of characters between lines (often 50) */
+    int inWord, inLine; /* Position in word and line. */
+    bool lineNumbers;   /* True if write position at end of line. */
+    bool countDown;     /* True if want numbers counting down. */
+    long charCount;     /* Number of characters written total. */
+    FILE *out;          /* File to write to. */
+    int numOff;         /* Number to start with. */
+    int color;          /* Cache last color here. */
+    bool underline;	/* Underline? */
+    bool bold;		/* Font in bold. */
+    bool italic;	/* Italic? */
+    };
+
+struct cfm *cfmNew(int wordLen, int lineLen, 
+	boolean lineNumbers, boolean countDown, FILE *out, int numOff);
+/* Set up colored sequence formatting for html. */
+
+void cfmOut(struct cfm *cfm, char c, int color);
+/* Write out a byte, and depending on color formatting extras  */
+
+void cfmOutExt(struct cfm *cfm, char c, int color, boolean underline, boolean bold, boolean italic);
+/* Write out a byte, and formatting extras  */
+
+void cfmFree(struct cfm **pCfm);
+/* Finish and free up cfm formatting job. */
+
+enum seqOutColor
+/* Symbolic color for sequence output. */
+    {
+    socBlack = 0,		/* Not aligning. */
+    socBlue = 1,		/* Aligning. */
+    socBrightBlue = 2,		/* End of an aligning block. */
+    socRed = 3, 		/* Aligning UTR. */
+    socOrange = 4,		/* End of an aligning UTR block. */
+    };
+extern int seqOutColorLookup[];		/* Converts these to html format colors. */
+
+struct baf
+/* Block allignment formatter. */
+    {
+    char nChars[256];
+    char hChars[256];
+    int cix;
+    int nLineStart;
+    int hLineStart;
+    int nCurPos;
+    int hCurPos;
+    DNA *needle, *haystack;
+    int nNumOff, hNumOff;
+    FILE *out;
+    int lineSize;
+    bool hCountDown;     /* True if want numbers counting down. */
+    bool isTrans;	 /* True if haystack is translated. */
+    bool nCountDown;	 /* True if want needle numbers counting down. */
+    };
+
+void bafInit(struct baf *baf, DNA *needle, int nNumOff, boolean nCountDown,
+	DNA *haystack, int hNumOff, boolean hCountDown, 
+	FILE *out, int lineSize, boolean isTrans);
+/* Initialize block alignment formatter. */
+
+void bafSetAli(struct baf *baf, struct ffAli *ali);
+/* Set up block formatter around an ffAli block. */
+
+void bafSetPos(struct baf *baf, int nStart, int hStart);
+/* Set up block formatter starting at nStart/hStart. */
+
+void bafStartLine(struct baf *baf);
+/* Set up block formatter to start new line at current position. */
+
+void bafWriteLine(struct baf *baf);
+/* Write out a line of an alignment (which takes up
+ * three lines on the screen. */
+
+void bafOut(struct baf *baf, char n, char h);
+/* Write a pair of character to block alignment. */
+
+void bafFlushLineNoHr(struct baf *baf);
+/* Write out alignment line if it has any characters in it (no <HR>). */
+
+void bafFlushLine(struct baf *baf);
+/* Write out alignment line if it has any characters in it, and an <HR>. */
+
diff --git a/inc/seqStats.h b/inc/seqStats.h
new file mode 100644
index 0000000..427804a
--- /dev/null
+++ b/inc/seqStats.h
@@ -0,0 +1,11 @@
+/* seqStats - some sequence statistics functions that need
+ * math libraries. */
+
+#ifndef SEQSTATS_H
+#define SEQSTATS_H
+
+double dnaMatchEntropy(DNA *query, DNA *target, int baseCount);
+/* Return entropy of matching bases - a number between 0 and 1, with
+ * higher numbers the more diverse the matching bases. */
+
+#endif /* SEQSTATS_H */
diff --git a/inc/shaRes.h b/inc/shaRes.h
new file mode 100644
index 0000000..07a1a10
--- /dev/null
+++ b/inc/shaRes.h
@@ -0,0 +1,45 @@
+/* Shared Resource file 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef SHARES_H
+#define SHARES_H
+
+struct shaResNode
+/* A shared resource node. */
+    {
+    struct shaResNode *next;
+    struct shaResNode *prev;
+    int links;
+    char *name;
+    struct shaResList *list;
+    void *data;
+    };
+
+struct shaResList
+/* A shared resource list. */
+    {
+    struct shaResNode *head;
+    void (*freeData)(void *pData);
+    };
+
+
+void shaUnlink(struct shaResNode *node);
+/* Decrement link count and free if down to zero. */
+
+void shaLink(struct shaResNode *node);
+/* Increment link count. */
+
+struct shaResNode *shaNewNode(struct shaResList *list, char *name, void *data);
+/* Create a new node with link count of one. */
+
+void shaCleanup(struct shaResList *list);
+/* Free every node on list. */
+
+void shaInit(struct shaResList *list, void (*freeData)(void *pData));
+/* Start up resource list. */
+#endif /* SHARES_H */
+
+
+
diff --git a/inc/sig.h b/inc/sig.h
new file mode 100644
index 0000000..881cdde
--- /dev/null
+++ b/inc/sig.h
@@ -0,0 +1,101 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* Sig.h - signatures that start various binary files. */
+#ifndef SIG_H
+#define SIG_H
+
+#define aliSig 0xCDAB8245
+/* Binary alignment file. */
+
+#define alxSig 0xA1B1C1D3
+/* Index into binary alignment file, sorted by start base offset. */
+
+#define pgoSig 0x690
+/* Index into GDF file, sorted by start base offset. Signature is 32 bit. */
+
+#define cdoSig 0xCD01
+/* Index into c2g text file, sorted by start base offset. 32 bit signature. */
+
+#define xaoSig 0xA0B0C0D0
+/* Index into xeno alignment, sorted by start base offset.  32 bit signature. */
+
+#define glSig 0xF1E2D3C4
+/* Binary gene file, sorted by chromosome and then starting offset. */
+
+/* IX sig is int ixSig[4] = {0x693F8ED1, 0x7EDA1C32, 0x4BA58983, 0x277CB89C,};
+ * These are made by snofMake, and are indexes sorted by name. */
+
+/* XI - same as IX but on big-endian (or is it little-endian) archetectures. */
+
+#define nt4Signature 0x12345678
+/* Signature at the beginning of an nt4 file - 2 bit a nucleotide binary file. */
+
+#define lm2Signature 0x12131416
+/* Signature at the beginning of a lm2 file - a 2nd order markov model for nucleotides. */
+
+#define oocSig 0x584155f2
+/* Signature of file that contains over-represented oligomers for patSpace
+ * algorithm. */
+
+#define oocSigSwapped 0xf2554158
+/* Signature of file that contains over-represented oligomers for patSpace
+ * algorithm. */
+
+#define fofSig 0x13410da8
+/* Signature into fof type index file (that can index multiple external files). */
+
+#define nibSig 0x6BE93D3A
+/* Signature into nib file (4 bits per nucleotide DNA file) */
+
+#define qacSig 0x32b67998
+/* Signature of qac file (compressed quality file) */
+
+#define caqSig 0x9879b632
+/* Signature of byte-swapped qac file. */
+
+#define twoBitSig 0x1A412743
+/* Signature into 2bit file (2 bits per nucleotide DNA file) plus
+ * information on N and masked bases. */
+
+#define twoBitSwapSig 0x4327411A
+/* Signature of byte-swapped two-bit file. */
+
+#define chromGraphSig 0x4528421C
+/* Signature of chromGraph binary data file */
+
+#define chromGraphSwapSig 0x1C422845
+/* Signature of byte-swapped chromGraph binary data file */
+
+#define genomeRangeTreeSig     0xf7fb8104
+/* Signature of genomeRangeTree binary data file */
+
+#define genomeRangeTreeSwapSig 0x0481fbf7
+/* Signature of genomeRangeTree binary data file */
+
+#define bptSig 0x78CA8C91
+/* Signature of generic b+ tree index file. */
+
+#define bptSwapped 0x918CCA78
+/* Signature of generic b+ tree index file. */
+
+#define cirTreeSig 0x2468ACE0
+/* Signature of a chromosome id r-tree index file. */
+
+#define crTreeSig 0x2369ADE1
+/* Signature of a chromosome r-tree index file. */
+
+#define bigWigSig 0x888FFC26
+/* Signature for a big wig file. */
+
+#define bigBedSig 0x8789F2EB
+/* Signature for a big bed file. */
+
+#define udcBitmapSig 0x4187E2F6
+/* Signature for a url data cache bitmap file. */
+
+#endif /* SIG_H */
+
+
diff --git a/inc/slog.h b/inc/slog.h
new file mode 100644
index 0000000..5563606
--- /dev/null
+++ b/inc/slog.h
@@ -0,0 +1,18 @@
+/* slog - fixed point scaled logarithm stuff. */
+#ifndef SLOG_H
+#define SLOG_H
+
+extern double fSlogScale;	/* Convert to fixed point by multiplying by this. */
+extern double invSlogScale;	/* To convert back to floating point use this. */
+
+int slog(double val);
+/* Return scaled log. */
+
+int carefulSlog(double val);
+/* Returns scaled log that makes sure there's no int overflow. */
+
+double invSlog(int scaledLog);
+/* Inverse of slog. */
+
+#endif /* SLOG_H */
+
diff --git a/inc/snof.h b/inc/snof.h
new file mode 100644
index 0000000..dfeec55
--- /dev/null
+++ b/inc/snof.h
@@ -0,0 +1,60 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* snof.h - Sorted Name Offset File - stuff to handle a simple
+ * indexed file.
+ *
+ * This accesses a file of name/offset pairs that are sorted by
+ * name.  Does a binary search of file to find the offset given name.
+ * Most typically this is used to do a quick lookup given an index file. 
+ */ 
+
+struct snof
+/* Sorted Name Offset File structure.  Get one from snofOpen.  Use
+ * with snofFindOffset.  Finish up with snofClose. */
+    {
+    FILE *file;
+    int maxNameSize;
+    int itemSize;
+    int headSize;
+    int endIx;
+    char *first;
+    char *last;
+    char *less;
+    char *mid;
+    char *more;
+    };
+
+struct snof *snofOpen(char *indexName);
+/* Open up the index file.  Returns NULL if there's any problem. */
+
+struct snof *snofMustOpen(char *indexName);
+/* Open up index file or die. */
+
+void snofClose(struct snof **pSnof);
+/* Close down the index file. */
+
+int snofElementCount(struct snof *snof);
+/* How many names are in snof file? */
+
+long snofOffsetAtIx(struct snof *snof, int ix);
+/* The offset of a particular index in file. */
+
+char *snofNameAtIx(struct snof *snof, int ix);
+/* The name at a particular index in file.  (This will be overwritten by
+ * later calls to snof system. Strdup if you want to keep it.)
+ */
+
+void snofNameOffsetAtIx(struct snof *snof, int ix, char **pName, long *pOffset);
+/* Get both name and offset for an index. */
+
+boolean snofFindFirstStartingWith(struct snof *snof, char *prefix, int prefixSize,
+    int *pSnofIx);
+/* Find first index in snof file whose name begins with prefix. */
+
+boolean snofFindOffset(struct snof *snof, char *name, long *pOffset);
+/* Find offset corresponding with name.  Returns FALSE if no such name
+ * in the index file. */
+
diff --git a/inc/snofmake.h b/inc/snofmake.h
new file mode 100644
index 0000000..406d04f
--- /dev/null
+++ b/inc/snofmake.h
@@ -0,0 +1,35 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+
+boolean snofMakeIndex(FILE *inFile, char *outName, 
+    boolean (*nextRecord)(FILE *inFile, void *data, char **rName, int *rNameLen), 
+    void *data);
+/* Make an index file - name/offset pairs that are sorted by name.
+ * Inputs:
+ *     inFile - open file that you're indexing with header read and verified.
+ *     outName - name of index file to create
+ *     nextRecord - function that reads next record in file you're indexing
+ *                  and returns the name of that record.  Returns FALSE at
+ *                  end of file.  Can set *rNameLen to zero you want indexer
+ *                  to ignore the record. 
+ *     data - void pointer passed through to nextRecord.
+ *
+ * Writes diagnostic output to stderr and returns FALSE if there's a problem.
+ */
+
+boolean snofDupeOkIndex(FILE *inFile, char *outName, 
+    boolean (*nextRecord)(FILE *inFile, void *data, char **rName, int *rNameLen), 
+    void *data, boolean dupeOk);
+/* Make an index file, as in snofMakeIndex, but optionally allow duplicates
+ * without complaining. */
+
+void snofSignature(char **rSig, int *rSigSize);
+/* The get signature that should be at start of a snof indexed 
+ * file. */
+
+boolean isSnofSig(void *sig);
+/* Return true if sig is right. */
+
diff --git a/inc/spaceSaver.h b/inc/spaceSaver.h
new file mode 100644
index 0000000..ea23473
--- /dev/null
+++ b/inc/spaceSaver.h
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* spaceSaver - routines that help layout 1-D objects into a
+ * minimum number of tracks so that no two objects overlap
+ * within a single track. */
+#ifndef SPACESAVER_H
+#define SPACESAVER_H
+
+struct spaceSaver
+/* Help layout 1-D objects onto multiple tracks so that
+ * no two objects overlap on a single track. */
+    {
+    struct spaceSaver *next;	/* Next in list. */
+    struct spaceNode *nodeList; /* List of things put in space saver. */
+    struct spaceRowTracker *rowList; /* List of rows. */
+    int rowCount;             /* Number of rows. */
+    int winStart,winEnd;      /* Start and end of area we're modeling. */
+    int cellsInRow;           /* Number of cells per row. */
+    double scale;             /* What to scale by to get to cell coordinates. */
+    int maxRows;	      /* Maximum number of rows.  */
+    boolean isFull;	      /* Set to true if can't fit data into maxRows. */
+    };
+
+struct spaceNode
+/* Which row is this one on? */
+    {
+    struct spaceNode *next;	/* Next in list. */
+    int row;			/* Which row, starting at zero. */
+    void *val;
+    };
+
+struct spaceRowTracker 
+/* Keeps track of how much of row is used. */
+    {
+    struct spaceRowTracker *next;	/* Next in list. */
+    bool *used;                 /* A flag for each spot used. */
+    };
+
+struct spaceSaver *spaceSaverMaxCellsNew(int winStart, int winEnd, int maxRows, int maxCells);
+/* Create a new space saver around the given window.   */
+
+struct spaceSaver *spaceSaverNew(int winStart, int winEnd, int maxRows);
+/* Create a new space saver around the given window.   */
+
+void spaceSaverFree(struct spaceSaver **pSs);
+/* Free up a space saver. */
+
+struct spaceNode *spaceSaverAdd(struct spaceSaver *ss, int start, int end, void *val);
+/* Add a new node to space saver. */
+
+
+struct spaceNode *spaceSaverAddOverflow(struct spaceSaver *ss, int start, int end, 
+					void *val, boolean allowOverflow);
+/* Add a new node to space saver. Returns NULL if can't fit item in
+ * and allowOverflow == FALSE. If allowOverflow == TRUE then put items
+ * that won't fit in first row (ends up being last row after
+ * spaceSaverFinish()). */
+
+void spaceSaverFinish(struct spaceSaver *ss);
+/* Tell spaceSaver done adding nodes. */
+#endif /* SPACESAVER_H */
+
diff --git a/inc/spacedColumn.h b/inc/spacedColumn.h
new file mode 100644
index 0000000..f294c0a
--- /dev/null
+++ b/inc/spacedColumn.h
@@ -0,0 +1,46 @@
+/* spacedColumn - stuff to handle parsing text files where fields are
+ * fixed width rather than tab delimited. */
+
+#ifndef SPACEDCOLUMN_H
+#define SPACEDCOLUMN_H
+
+struct spacedColumn
+/* Specs on a column. */
+    {
+    struct spacedColumn *next;
+    int start;	/* Starting index. */
+    int size;	/* Size of column. */
+    };
+
+#define spacedColumnFreeList slFreeList
+
+struct spacedColumn *spacedColumnFromWidthArray(int array[], int size);
+/* Return a list of spaced columns corresponding to widths in array.
+ * The final char in each column should be whitespace. */
+
+struct spacedColumn *spacedColumnFromSample(char *sample);
+/* Return spaced column list from a sample line , which is assumed to
+ * have no spaces except between columns */
+
+struct spacedColumn *spacedColumnFromSizeCommaList(char *commaList);
+/* Given an comma-separated list of widths in ascii, return
+ * a list of spacedColumns. */
+
+struct spacedColumn *spacedColumnFromLineFile(struct lineFile *lf);
+/* Scan through lineFile and figure out column spacing. Assumes
+ * file contains nothing but columns. */
+
+struct spacedColumn *spacedColumnFromFile(char *fileName);
+/* Read file and figure out where columns are. */
+
+int spacedColumnBiggestSize(struct spacedColumn *colList);
+/* Return size of biggest column. */
+
+boolean spacedColumnParseLine(struct spacedColumn *colList, 
+	char *line, char *row[]);
+/* Parse line into row according to colList.  This will
+ * trim leading and trailing spaces. It will write 0's
+ * into line.  Returns FALSE if there's a problem (like
+ * line too short.) */
+
+#endif /* SPACEDCOLUMN_H */
diff --git a/inc/spacedSeed.h b/inc/spacedSeed.h
new file mode 100644
index 0000000..8548790
--- /dev/null
+++ b/inc/spacedSeed.h
@@ -0,0 +1,19 @@
+/* spacedSeed - stuff to help with spaced seeds for alignments. */
+
+#ifndef SPACEDSEED_H
+#define SPACEDSEED_H
+
+extern char *spacedSeeds[];
+/* Array of spaced seeds in format with '1' for cares, '0' for don't care. */
+
+int spacedSeedMaxWeight();
+/* Return max weight of spaced seed. */
+
+int *spacedSeedOffsets(int weight);
+/* Return array with offsets for seed of given weight. */
+
+int spacedSeedSpan(int weight);
+/* Return span of seed of given weight */
+
+#endif /*SPACEDSEED_H */
+
diff --git a/inc/splatAli.h b/inc/splatAli.h
new file mode 100644
index 0000000..002c70b
--- /dev/null
+++ b/inc/splatAli.h
@@ -0,0 +1,80 @@
+/* splatAli.h was originally generated by the autoSql program, which also 
+ * generated splatAli.c and splatAli.sql.  This header links the database and
+ * the RAM representation of objects. */
+/* This file is copyright 2008 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef SPLATALI_H
+#define SPLATALI_H
+
+#define SPLATALI_NUM_COLS 7
+
+struct splatAli
+/* A parsed out splat format alignment. */
+    {
+    struct splatAli *next;  /* Next in singly linked list. */
+    char *chrom;	/* Chromosome mapped to */
+    int chromStart;	/* Start position in chromosome (zero based) */
+    int chromEnd;	/* End position in genome (one based) */
+    char *alignedBases;	/* Tag bases - in upper case for match, -/^ for insert/delete */
+    int score;	/* Mapping score. 1000/placesMapped */
+    char strand[2];	/* + or - for strand */
+    char *readName;	/* Name of read */
+    };
+
+void splatAliStaticLoad(char **row, struct splatAli *ret);
+/* Load a row from splatAli table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+
+struct splatAli *splatAliLoad(char **row);
+/* Load a splatAli from row fetched with select * from splatAli
+ * from database.  Dispose of this with splatAliFree(). */
+
+struct splatAli *splatAliLoadAll(char *fileName);
+/* Load all splatAli from whitespace-separated file.
+ * Dispose of this with splatAliFreeList(). */
+
+struct splatAli *splatAliLoadAllByChar(char *fileName, char chopper);
+/* Load all splatAli from chopper separated file.
+ * Dispose of this with splatAliFreeList(). */
+
+#define splatAliLoadAllByTab(a) splatAliLoadAllByChar(a, '\t');
+/* Load all splatAli from tab separated file.
+ * Dispose of this with splatAliFreeList(). */
+
+struct splatAli *splatAliCommaIn(char **pS, struct splatAli *ret);
+/* Create a splatAli out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new splatAli */
+
+void splatAliFree(struct splatAli **pEl);
+/* Free a single dynamically allocated splatAli such as created
+ * with splatAliLoad(). */
+
+void splatAliFreeList(struct splatAli **pList);
+/* Free a list of dynamically allocated splatAli's */
+
+void splatAliOutput(struct splatAli *el, FILE *f, char sep, char lastSep);
+/* Print out splatAli.  Separate fields with sep. Follow last field with lastSep. */
+
+#define splatAliTabOut(el,f) splatAliOutput(el,f,'\t','\n');
+/* Print out splatAli as a line in a tab-separated file. */
+
+#define splatAliCommaOut(el,f) splatAliOutput(el,f,',',',');
+/* Print out splatAli as a comma separated list including final comma. */
+
+/* -------------------------------- End autoSql Generated Code -------------------------------- */
+
+int splatAliCmpReadName(const void *va, const void *vb);
+/* Compare two based on readName. Also separate secondarily on chrom position. */
+
+int splatAliScore(char *ali);
+/* Score splat-encoded alignment. */
+
+void splatAliLookForBest(struct splatAli *start, struct splatAli *end, 
+	int *retBestScore, int *retBestCount);
+/* Scan through list from start up to but not including end (which may be NULL)
+ * and figure out best score and number of elements in list with that score. */
+
+#endif /* SPLATALI_H */
+
diff --git a/inc/splix.h b/inc/splix.h
new file mode 100644
index 0000000..fabd4f0
--- /dev/null
+++ b/inc/splix.h
@@ -0,0 +1,80 @@
+/* splix - splat (speedy local alignment tool)  index.  Index that helps map short reads
+ * quickly to the genome. */
+/* This file is copyright 2008 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef SPLIX_H
+#define SPLIX_H
+
+struct splixFileHeader
+/* Short read index file binary file header.  A splix file starts with this fixed 128 byte
+ * structure.  It is followed by the following sections:
+ *    chromosome name strings - zero terminated
+ *    chromosome sizes (32 bits each)
+ *    chromosome DNA - one byte per base lower case.  A zero between each chrom.
+ *    indexSlotSizes (4^^12 32 bit words containing size of each index slot
+ *    indexSlots - explained more below
+ * Each of these sections is padded with zeroes to end on an 8 byte (64 bit) boundary.
+ * The index section consists of 4^^12 (16 million roughly) index slots.  Each slot 
+ * corresponds to a DNA 12-mer.  The format of a slot is:
+ *    hexesBefore1 - size # of 16 bit words, each containing 6 bases of DNA 2 bits/base 
+ *                   and 4 bits of zero (most significant bits are zero).  These represent
+ *                   the sixmers found before the 12-mer.  They are sorted numerically.
+ *    hexesBefore2 - as hexesBefore, but contains sixmer six before the 12-mer.
+ *    hexesAfter1 - sixmers after the 12-mer.
+ *    hexesAfter2 - sixmers six after the 12-mer.
+ *    offsetsBefore1 - 32 bit offsets into indexed DNA corresponding with hexBefore1
+ *    offsetsBefore2 - 32 bit offsets into indexed DNA corresponding with hexBefore2
+ *    offsetsAfter1 - 32 bit offsets corresponding ith hexesAfter1
+ *    offsetsAfter2 - 32 bit offsets corresponding ith hexesAfter2
+ * The splix files are structured so that they can be memory mapped relatively easily,
+ * and so that on program load, and for a particular read, most of the action happens
+ * in a few isolated piece of memory rather than scattered all over. */
+    {
+    bits32 magic;	/* Always SPLIX_MAGIC */
+    bits16 majorVersion; /* This version changes when backward compatibility breaks. */
+    bits16 minorVersion; /* This version changes whenever a feature is added. */
+    bits64 size;	/* Total size to memmap, including header. */
+    bits32 chromCount;	/* Total count of chromosomes/contigs in file. */
+    bits32 chromNamesSize;	/* Size of names of all contigs (including zeroes at end),
+    				   padded to 8 byte boundary as needed). */
+    bits64 basesIndexed;/* Total number of bases actually indexed (non-N, unmasked). */
+    bits64 dnaDiskSize;	/* Size of DNA on disk including zero separators and 8 byte padding */
+    bits64 reserved[11];/* All zeroes for now. */
+    };
+
+struct splix 
+/* Short read index in memory */
+    {
+    struct splix *next;
+    boolean isMapped;	/* True if memory mapped. */
+    struct splixFileHeader *header;	/* File header. */
+    char **chromNames;	/* Name of each chromosome. */
+    bits32 *chromSizes;    /* Size of each chromosome.  No deallocation required (in memmap) */
+    bits32 *chromOffsets;	/* Offset of each chromosome's DNA */
+    char *allDna;	/* All DNA from each contig/chromosome with zero separators. */
+    bits32 *slotSizes;	/* 4^^12 array of slot sizes.  No deallocation required (in memmap) */
+    char **slots;  	/* 16 M slots corresponding to 12 bases. Actual format of slot is
+                         * explained in indexSlots section of splixFileHeader */
+    };
+
+#define splixSlotCount (1<<(12*2))
+#define splixMinQuerySize 24
+
+struct splix *splixRead(char *fileName, boolean memoryMap);
+/* Read in a splix from a file.  Does this via memory mapping if you like,
+ * which will be faster typically for about 100 reads, and slower for more
+ * than that (_much_ slower for thousands of reads and more). */
+
+void splixFree(struct splix **pSplix);
+/* Free up resources associated with index. */
+
+int splixOffsetToChromIx(struct splix *splix, bits32 tOffset);
+/* Figure out index of chromosome containing tOffset */
+
+/** Stuff to define SPLIX files **/
+#define SPLIX_MAGIC 0x5616A283	/* Magic number at start of SPLIX file */
+#define SPLIX_MAJOR_VERSION 0	
+#define SPLIX_MINOR_VERSION 0
+
+#endif /* SPLIX_H */
diff --git a/inc/sqlList.h b/inc/sqlList.h
new file mode 100644
index 0000000..1de0832
--- /dev/null
+++ b/inc/sqlList.h
@@ -0,0 +1,142 @@
+/* Stuff for processing comma separated lists .
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef SQLLIST_H
+#define SQLLIST_H
+struct hash;
+
+int sqlDoubleArray(char *s, double *array, int maxArraySize);
+int sqlFloatArray(char *s, float *array, int maxArraySize);
+int sqlUnsignedArray(char *s, unsigned *array, int maxArraySize);
+int sqlSignedArray(char *s, int *array, int maxArraySize);
+int sqlShortArray(char *s, short *array, int arraySize);
+int sqlUshortArray(char *s, unsigned short *array, int arraySize);
+int sqlByteArray(char *s, signed char *array, int arraySize);
+int sqlUbyteArray(char *s, unsigned char *array, int arraySize);
+int sqlCharArray(char *s, char *array, int arraySize);
+int sqlLongLongArray(char *s, long long *array, int arraySize);
+/* Convert comma separated list of numbers to an array.  Pass in 
+ * array and max size of array.  Returns actual array size.*/
+
+void sqlDoubleStaticArray(char *s, double **retArray, int *retSize);
+void sqlFloatStaticArray(char *s, float **retArray, int *retSize);
+void sqlUnsignedStaticArray(char *s, unsigned **retArray, int *retSize);
+void sqlSignedStaticArray(char *s, int **retArray, int *retSize);
+void sqlShortStaticArray(char *s, short **retArray, int *retSize);
+void sqlUshortStaticArray(char *s, unsigned short **retArray, int *retSize);
+void sqlByteStaticArray(char *s, signed char **retArray, int *retSize);
+void sqlUbyteStaticArray(char *s, unsigned char **retArray, int *retSize);
+void sqlCharStaticArray(char *s, char **retArray, int *retSize);
+void sqlLongLongStaticArray(char *s, long long **array, int *retSize);
+/* Convert comma separated list of numbers to an array which will be
+ * overwritten next call to this function or to sqlXxxxxxDynamicArray,
+ * but need not be freed. */
+
+void sqlDoubleDynamicArray(char *s, double **retArray, int *retSize);
+void sqlFloatDynamicArray(char *s, float **retArray, int *retSize);
+void sqlUnsignedDynamicArray(char *s, unsigned **retArray, int *retSize);
+void sqlSignedDynamicArray(char *s, int **retArray, int *retSize);
+void sqlShortDynamicArray(char *s, short **retArray, int *retSize);
+void sqlUshortDynamicArray(char *s, unsigned short **retArray, int *retSize);
+void sqlByteDynamicArray(char *s, signed char **retArray, int *retSize);
+void sqlUbyteDynamicArray(char *s, unsigned char **retArray, int *retSize);
+void sqlCharDynamicArray(char *s, char **retArray, int *retSize);
+void sqlLongLongDynamicArray(char *s, long long **retArray, int *retSize);
+/* Convert comma separated list of numbers to an dynamically allocated
+ * array, which should be freeMem()'d when done. */
+
+
+int sqlStringArray(char *s, char **array, int maxArraySize);
+/* Convert comma separated list of strings to an array.  Pass in 
+ * array and max size of array.  Returns actual size.  This will
+ * only persist as long as s persists.... Use sqlStringDynamicArray
+ * if calling repeatedly. */
+
+void sqlStringStaticArray(char *s, char  ***retArray, int *retSize);
+/* Convert comma separated list of strings to an array which will be
+ * overwritten next call to this function or to sqlUnsignedDynamicArray,
+ * but need not be freed. */
+
+void sqlStringDynamicArray(char *s, char ***retArray, int *retSize);
+/* Convert comma separated list of strings to an dynamically allocated
+ * array, which should be freeMem()'d when done. */
+
+void sqlStringFreeDynamicArray(char ***pArray);
+/* Free up a dynamic array (ends up freeing array and first string on it.) */
+
+char *sqlDoubleArrayToString( double *array, int arraySize);
+char *sqlFloatArrayToString( float *array, int arraySize);
+char *sqlUnsignedArrayToString( unsigned *array, int arraySize);
+char *sqlSignedArrayToString( int *array, int arraySize);
+char *sqlShortArrayToString( short *array, int arraySize);
+char *sqlUshortArrayToString( unsigned short *array, int arraySize);
+char *sqlByteArrayToString( signed char *array, int arraySize);
+char *sqlUbyteArrayToString( unsigned char *array, int arraySize);
+char *sqlCharArrayToString( char *array, int arraySize);
+char *sqlLongLongArrayToString( long long *array, int arraySize);
+char *sqlStringArrayToString( char **array, int arraySize);
+/* Convert arrays into comma separated strings. The char *'s returned
+ * should be freeMem()'d when done */
+
+char *sqlEscapeString(const char *orig);
+/* Prepares string for inclusion in a SQL statement . Remember to free
+ * returned string.  returned string contains strlen(length)*2+1 as many bytes
+ * as orig because in worst case every character has to be escaped.
+ * Example 1: The Gene's Name -> The Gene''s Name
+ * Example 2: he said "order and orient" -> he said ""order and orient"" */
+
+char *sqlEscapeString2(char *to, const char* from);
+/* Prepares a string for inclusion in a sql statement.  Output string
+ * must be 2*strlen(from)+1 */
+
+int sqlUnsignedComma(char **pS);
+/* Return signed number at *pS.  Advance *pS past comma at end.
+ * This function is used by the system that automatically loads
+ * structured object from longblobs. */
+
+int sqlSignedComma(char **pS);
+/* Return signed number at *pS.  Advance *pS past comma at end */
+
+char sqlCharComma(char **pS);
+/* Return char at *pS.  Advance *pS past comma after char */
+
+long long sqlLongLongComma(char **pS);
+/* Return long long number at *pS.  Advance *pS past comma at end */
+
+double sqlDoubleComma(char **pS);
+/* Return double floating number at *pS.  Advance *pS past comma at end */
+
+float sqlFloatComma(char **pS);
+/* Return floating point number at *pS.  Advance *pS past comma at end */
+
+char *sqlStringComma(char **pS);
+/* Return string at *pS.  (Either quoted or not.)  Advance *pS. */
+
+void sqlFixedStringComma(char **pS, char *buf, int bufSize);
+/* Copy string at *pS to buf.  Advance *pS. */
+
+char *sqlEatChar(char *s, char c);
+/* Make sure next character is 'c'.  Return past next char */
+
+unsigned sqlEnumParse(char *valStr, char **values, struct hash **valHashPtr);
+/* parse an enumerated column value */
+
+unsigned sqlEnumComma(char **pS, char **values, struct hash **valHashPtr);
+/* Return enum at *pS.  (Either quoted or not.)  Advance *pS. */
+
+void sqlEnumPrint(FILE *f, unsigned value, char **values);
+/* print an enumerated column value */
+
+unsigned sqlSetParse(char *valStr, char **values, struct hash **valHashPtr);
+/* parse a set column value */
+
+unsigned sqlSetComma(char **pS, char **values, struct hash **valHashPtr);
+/* Return set at *pS.  (Either quoted or not.)  Advance *pS. */
+
+void sqlSetPrint(FILE *f, unsigned value, char **values);
+/* print a set column value */
+
+#endif /* SQLLIST_H */
+
diff --git a/inc/sqlNum.h b/inc/sqlNum.h
new file mode 100644
index 0000000..ff3f056
--- /dev/null
+++ b/inc/sqlNum.h
@@ -0,0 +1,83 @@
+/* sqlNum.h - routines to convert from ascii to
+ * unsigned/integer a bit more quickly than atoi. 
+ * Called sqlNum because it was first developed for use with
+ * SQL databases, which tend to require a lot of conversion from
+ * string to binary representation of numbers. In particular the
+ * code generator AutoSQL puts in lots of calls to these routines
+ * into it's parsers.  Other parser in the source tree have come
+ * to use these too though since they are fast and have good error
+ * checking.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef SQLNUM_H
+#define SQLNUM_H
+
+/* get off_t */
+#include <sys/types.h>
+
+unsigned sqlUnsigned(char *s);
+/* Convert series of digits to unsigned integer about
+ * twice as fast as atoi (by not having to skip white 
+ * space or stop except at the null byte.) */
+
+unsigned sqlUnsignedInList(char **pS);
+/* Convert series of digits to unsigned integer about
+ * twice as fast as atoi (by not having to skip white 
+ * space or stop except at the null byte.) 
+ * All of string is number. Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+
+unsigned long sqlUnsignedLong(char *s);
+/* Convert series of digits to unsigned long about
+ * twice as fast as atol (by not having to skip white 
+ * space or stop except at the null byte.) */
+
+unsigned long sqlUnsignedLongInList(char **pS);
+/* Convert series of digits to unsigned long about
+ * twice as fast as atol (by not having to skip white 
+ * space or stop except at the null byte.) 
+ * All of string is number. Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+
+int sqlSigned(char *s);
+/* Convert string to signed integer.  Unlike atol assumes 
+ * all of string is number. */
+
+int sqlSignedInList(char **pS);
+/* Convert string to signed integer.  Unlike atol assumes 
+ * all of string is number. Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+
+long long sqlLongLong(char *s);
+/* Convert string to a long long.  Unlike atol assumes all of string is
+ * number. */
+
+long long sqlLongLongInList(char **pS);
+/* Convert string to a long long.  Unlike atol, assumes 
+ * all of string is number. Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+
+float sqlFloat(char *s);
+/* Convert string to a float.  Assumes all of string is number
+ * and aborts on an error. */
+
+float sqlFloatInList(char **pS);
+/* Convert string to a float.  Assumes all of string is number
+ * and aborts on an error. 
+ * Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+
+double sqlDouble(char *s);
+/* Convert string to a double.  Assumes all of string is number
+ * and aborts on an error. */
+
+double sqlDoubleInList(char **pS);
+/* Convert string to a double.  Assumes all of string is number
+ * and aborts on an error.
+ * Number may be delimited by a comma.
+ * Returns the position of the delimiter or the terminating 0. */
+
+#endif /* SQLNUM_H */
+ 
diff --git a/inc/subText.h b/inc/subText.h
new file mode 100644
index 0000000..555d8eb
--- /dev/null
+++ b/inc/subText.h
@@ -0,0 +1,41 @@
+/* subText.h - perform text substitutions. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef SUBTEXT_H
+#define SUBTEXT_H
+
+struct subText
+/* Structure that holds data for a single substitution to be made.
+ * The subText routines work mostly on lists of these. */
+    {
+    struct subText *next;	/* pointer to next substitution */
+    char *in;			/* source side of substitution */
+    char *out;			/* dest side of substitution */
+    int inSize;			/* length of in string */
+    int outSize;		/* length of out string */
+    };
+
+struct subText *subTextNew(char *in, char *out);
+/* Make new substitution structure. */
+
+void subTextFree(struct subText **pSub);
+/* Free a subText. */
+
+void subTextFreeList(struct subText **pList);
+/* Free a list of dynamically allocated subText's */
+
+int subTextSizeAfter(struct subText *subList, char *in);
+/* Return size string will be after substitutions. */
+
+void subTextStatic(struct subText *subList, char *in, char *out, int outMaxSize);
+/* Do substition to output buffer of given size.  Complain
+ * and die if not big enough. */
+
+char *subTextString(struct subText *subList, char *in);
+/* Return string with substitutions in list performed.  freeMem
+ * this string when done. */
+
+#endif /* SUBTEXT_H */
+
diff --git a/inc/sufa.h b/inc/sufa.h
new file mode 100644
index 0000000..5538968
--- /dev/null
+++ b/inc/sufa.h
@@ -0,0 +1,60 @@
+/* sufa - suffix array for genome.  Use sufaMake utility to create one of these, and
+ * the routines here to access it.  See comment by sufaFileHeader for file format. */
+/* This file is copyright 2008 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef SUFA_H
+#define SUFA_H
+
+struct sufaFileHeader
+/* Short read index file binary file header.  A sufa file starts with this fixed 128 byte
+ * structure.  It is followed by the following sections:
+ *    chromosome name strings - zero terminated.  Padded with zero to 4 byte boundary 
+ *    chromosome sizes (32 bits each)
+ *    chromosome DNA - one byte per base lower case.  A zero between each chrom, and a zero before
+ *                     and after (to make some end conditions easier).  Padded if need be with
+ *                     additional zeroes to 4 base boundary.
+ *    suffixArray - 32 bits for each indexed base */
+    {
+    bits32 magic;	/* Always SUFA_MAGIC */
+    bits16 majorVersion; /* This version changes when backward compatibility breaks. */
+    bits16 minorVersion; /* This version changes whenever a feature is added. */
+    bits64 size;	/* Total size to memmap, including header. */
+    bits32 chromCount;	/* Total count of chromosomes/contigs in file. */
+    bits32 chromNamesSize;	/* Size of names of all contigs (including zeroes at end),
+    				   padded to 4 byte boundary as needed). */
+    bits64 arraySize;   /* Total number of bases actually indexed (non-N, unmasked). */
+    bits64 dnaDiskSize;	/* Size of DNA on disk with zero separators. Padded to 4 byte boundary  */
+    bits64 reserved[11];/* All zeroes for now. */
+    };
+
+struct sufa 
+/* Suffix array in memory */
+    {
+    struct sufa *next;
+    boolean isMapped;	/* True if memory mapped. */
+    struct sufaFileHeader *header;	/* File header. */
+    char **chromNames;	/* Name of each chromosome. */
+    bits32 *chromSizes;    /* Size of each chromosome.  No deallocation required (in memmap) */
+    bits32 *chromOffsets;  /* Offset of each chromosome's DNA */
+    char *allDna;	/* All DNA from each contig/chromosome with zero separators. */
+    bits32 *array;	/* Alphabetized offsets into allDna. */
+    };
+
+struct sufa *sufaRead(char *fileName, boolean memoryMap);
+/* Read in a sufa from a file.  Does this via memory mapping if you like,
+ * which will be faster typically for about 100 reads, and slower for more
+ * than that (_much_ slower for thousands of reads and more). */
+
+void sufaFree(struct sufa **pSufa);
+/* Free up resources associated with index. */
+
+int sufaOffsetToChromIx(struct sufa *sufa, bits32 tOffset);
+/* Figure out index of chromosome containing tOffset */
+
+/** Stuff to define SUFA files **/
+#define SUFA_MAGIC 0x6727B283	/* Magic number at start of SUFA file */
+#define SUFA_MAJOR_VERSION 0	
+#define SUFA_MINOR_VERSION 0
+
+#endif /* SUFA_H */
diff --git a/inc/sufx.h b/inc/sufx.h
new file mode 100644
index 0000000..6c588fc
--- /dev/null
+++ b/inc/sufx.h
@@ -0,0 +1,64 @@
+/* sufx - suffix array with traversal extension for genome.  Use sufxMake utility to 
+ * create one of these files , and the routines here to access it.  See comment by 
+ * sufxFileHeader for file format. See src/shortReads/sufxMake/sufx.doc as well for
+ * an explanation of the data structures, particularly the traverse array. */
+/* This file is copyright 2008 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef SUFX_H
+#define SUFX_H
+
+struct sufxFileHeader
+/* Short read index file binary file header.  A sufx file starts with this fixed 128 byte
+ * structure.  It is followed by the following sections:
+ *    chromosome name strings - zero terminated.  Padded with zero to 4 byte boundary 
+ *    chromosome sizes (32 bits each)
+ *    chromosome DNA - one byte per base lower case.  A zero between each chrom, and a zero before
+ *                     and after (to make some end conditions easier).  Padded if need be with
+ *                     additional zeroes to 4 base boundary.
+ *    suffix array -   32 bits for each indexed base. Alphabetical offsets into DNA
+ *    traverse array - Also 32 bits per indexed base. Helper info to traverse array like a tree. */
+    {
+    bits32 magic;	 /* Always SUFX_MAGIC */
+    bits16 majorVersion; /* This version changes when backward compatibility breaks. */
+    bits16 minorVersion; /* This version changes whenever a feature is added. */
+    bits64 size;	 /* Total size to memmap, including header. */
+    bits32 chromCount;	 /* Total count of chromosomes/contigs in file. */
+    bits32 chromNamesSize;	/* Size of names of all contigs (including zeroes at end),
+    				   padded to 4 byte boundary as needed). */
+    bits64 arraySize;	 /* Total number of bases actually indexed (non-N, unmasked). */
+    bits64 dnaDiskSize;	 /* Size of DNA on disk with zero separators. Padded to 4 byte boundary  */
+    bits64 reserved[11];/* All zeroes for now. */
+    };
+
+struct sufx 
+/* Suffix array in memory */
+    {
+    struct sufx *next;
+    boolean isMapped;	/* True if memory mapped. */
+    struct sufxFileHeader *header;	/* File header. */
+    char **chromNames;	/* Name of each chromosome. */
+    bits32 *chromSizes;    /* Size of each chromosome.  No deallocation required (in memmap) */
+    bits32 *chromOffsets;  /* Offset of each chromosome's DNA */
+    char *allDna;	/* All DNA from each contig/chromosome with zero separators. */
+    bits32 *array;	/* Alphabetized offsets into allDna. */
+    bits32 *traverse;	/* Offsets to position in array where current prefix changes. */
+    };
+
+struct sufx *sufxRead(char *fileName, boolean memoryMap);
+/* Read in a sufx from a file.  Does this via memory mapping if you like,
+ * which will be faster typically for about 100 reads, and slower for more
+ * than that (_much_ slower for thousands of reads and more). */
+
+void sufxFree(struct sufx **pSufx);
+/* Free up resources associated with index. */
+
+int sufxOffsetToChromIx(struct sufx *sufx, bits32 tOffset);
+/* Figure out index of chromosome containing tOffset */
+
+/** Stuff to define SUFX files **/
+#define SUFX_MAGIC 0x600BA3A1	/* Magic number at start of SUFX file */
+#define SUFX_MAJOR_VERSION 0	
+#define SUFX_MINOR_VERSION 0
+
+#endif /* SUFX_H */
diff --git a/inc/supStitch.h b/inc/supStitch.h
new file mode 100644
index 0000000..3ef0d63
--- /dev/null
+++ b/inc/supStitch.h
@@ -0,0 +1,73 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* supStitch stitches together a bundle of ffAli alignments that share
+ * a common query and target sequence into larger alignments if possible.
+ * This is commonly used when the query sequence was broken up into
+ * overlapping blocks in the initial alignment, and also to look for
+ * introns larger than fuzzyFinder can handle. */
+
+#ifndef SUPSTITCH_H
+#define SUPSTITCH_H
+
+#ifndef DNASEQ_H
+#include "dnaseq.h"
+#endif
+
+#ifndef FUZZYFIND_H
+#include "fuzzyFind.h"
+#endif
+
+#ifndef PATSPACE_H
+#include "patSpace.h"
+#endif
+
+struct ssFfItem
+/* A list of fuzzy finder alignments. */
+    {
+    struct ssFfItem *next;      /* Next in list. */
+    struct ffAli *ff;		/* Alignment (owned by ssFfItem) */
+    };
+
+void ssFfItemFree(struct ssFfItem **pEl);
+/* Free a single ssFfItem. */
+
+void ssFfItemFreeList(struct ssFfItem **pList);
+/* Free a list of ssFfItems. */
+
+struct ssBundle
+/* A bunch of alignments all with the same query sequence.  This
+ * is the input to the stitcher.*/
+    {
+    struct ssBundle *next;	/* Next in list. */
+    struct ssFfItem *ffList;    /* Item list - memory owned by bundle. */
+    bioSeq *qSeq;        /* Query sequence (not owned by bundle.) */
+    bioSeq *genoSeq;     /* Genomic sequence (not owned by bundle.) */
+    int genoIx;                 /* Index of bac in associated PatSpace. */
+    int genoContigIx;           /* Index of contig inside of seq. */
+    void *data;			/* User defined data pointer. */
+    boolean isProt;		/* True if it's a protein based bundle. */
+    struct trans3 *t3List;	/* Sometimes set to three translated frames. */
+    boolean avoidFuzzyFindKludge;	/* Temporary flag to avoid call to fuzzyFind. */
+    };
+
+void ssBundleFree(struct ssBundle **pEl);
+/* Free up one ssBundle */
+
+void ssBundleFreeList(struct ssBundle **pList);
+/* Free up list of ssBundles */
+
+
+void ssStitch(struct ssBundle *bundle, enum ffStringency stringency, 
+	int minScore, int maxToReturn);
+/* Glue together mrnas in bundle as much as possible. 
+ * Updates bundle->ffList with stitched together version. */
+
+struct ssBundle *ssFindBundles(struct patSpace *ps, struct dnaSeq *cSeq, 
+	char *cName, enum ffStringency stringency, boolean avoidSelfSelf);
+/* Find patSpace alignments on cSeq and bundle them together. */
+
+#endif /* SUPSTITCH_H */
+
diff --git a/inc/synQueue.h b/inc/synQueue.h
new file mode 100644
index 0000000..9107fb0
--- /dev/null
+++ b/inc/synQueue.h
@@ -0,0 +1,34 @@
+/* synQueue - a sychronized message queue for messages between
+ * threads. */
+
+#ifndef SYNQUEUE_H
+#define SYNQUEUE_H
+
+struct synQueue *synQueueNew();
+/* Make a new, empty, synQueue. */
+
+void synQueueFree(struct synQueue **pSq);
+/* Free up synQueue.  Be sure no other threads are using
+ * it first though! This will not free any dynamic memory
+ * in the messages.  Use synQueueFreeAndVals for that. */
+
+void synQueueFreeAndVals(struct synQueue **pSq);
+/* Free up synQueue.  Be sure no other threads are using
+ * it first though! This will freeMem all the messages */
+
+void synQueuePut(struct synQueue *sq, void *message);
+/* Add message to end of queue. */
+
+void *synQueueGet(struct synQueue *sq);
+/* Get message off start of queue.  Wait until there is
+ * a message if queue is empty. */
+
+void *synQueueGrab(struct synQueue *sq);
+/* Get message off start of queue.  Return NULL immediately 
+ * if queue is empty. */
+
+int synQueueSize(struct synQueue *sq);
+/* Return number of messages currently on queue. */
+
+#endif /* SYNQUEUE_H */
+
diff --git a/inc/tabRow.h b/inc/tabRow.h
new file mode 100644
index 0000000..cc5b583
--- /dev/null
+++ b/inc/tabRow.h
@@ -0,0 +1,45 @@
+/* tabRow - a row from a database or a tab-separated file held in
+ * memory.   Just a light wrapper around an array of strings. 
+ * Also some routines to convert slLines to tabRows. */
+
+#ifndef TABROW_H
+#define TABROW_H
+
+struct tabRow
+/* A parsed out tableRow. */
+    {
+    struct tabRow *next;
+    int colCount;
+    char *columns[1];
+    };
+
+struct tabRow *tabRowNew(int colCount);
+/* Return new row. */
+
+int tabRowMaxColCount(struct tabRow *rowList);
+/* Return largest column count */
+
+struct tabRow *tabRowByWhite(struct slName *lineList, char *fileName,
+	boolean varCol);
+/* Convert lines to rows based on spaces.  If varCol is TRUE then not
+ * all rows need to have same number of columns. */
+
+struct tabRow *tabRowByChar(struct slName *lineList, char c, char *fileName,
+	boolean varCol);
+/* Convert lines to rows based on character separation.  If varCol is TRUE then not
+ * all rows need to have same number of columns. */
+
+struct tabRow *tabRowByFixedOffsets(struct slName *lineList, struct slInt *offList,
+	char *fileName);
+/* Return rows parsed into fixed width fields whose starts are defined by
+ * offList. */
+
+struct tabRow *tabRowByFixedGuess(struct slName *lineList, char *fileName);
+/* Return rows parsed into fixed-width fields. */
+
+struct slInt *tabRowGuessFixedOffsets(struct slName *lineList, char *fileName);
+/* Return our best guess list of starting positions for space-padded fixed
+ * width fields. */
+
+#endif /* TABROW_H */
+
diff --git a/inc/textOut.h b/inc/textOut.h
new file mode 100644
index 0000000..0bb0650
--- /dev/null
+++ b/inc/textOut.h
@@ -0,0 +1,46 @@
+/* textOut - set up stdout to be HTTP text, file or compressed file. */
+
+#ifndef TEXTOUT_H
+#define TEXTOUT_H
+
+#include "pipeline.h"
+
+/* Supported compression types: */
+#define textOutCompressNone "none"
+#define textOutCompressBzip2 "bzip2"
+#define textOutCompressCompress "compress"
+#define textOutCompressGzip "gzip"
+#define textOutCompressZip "zip"
+
+/* Menu and values for passing to cgiMakeDropListFull: */
+/* (not declaring the static char *[]'s here because those can lead to 
+ * "variable defined but not used" warnings -- declare locally.) */
+#define textOutCompressMenuContents { "plain text",\
+				       "gzip compressed (.gz)",\
+				       "bzip2 compressed (.bz2)",\
+				       "LZW compressed (.Z)",\
+				       "zip compressed (.zip)",\
+				       NULL\
+				     }
+
+#define textOutCompressValuesContents { textOutCompressNone,\
+					 textOutCompressGzip,\
+					 textOutCompressBzip2,\
+					 textOutCompressCompress,\
+					 textOutCompressZip,\
+					 NULL\
+				       }
+
+
+struct pipeline *textOutInit(char *fileName, char *compressType);
+/* Set up stdout to be HTTP text, file (if fileName is specified), or 
+ * compressed file (if both fileName and a supported compressType are 
+ * specified). 
+ * Return NULL if no compression, otherwise a pipeline handle on which 
+ * textOutClose should be called when we're done writing stdout. */
+
+void textOutClose(struct pipeline **pCompressPipeline);
+/* Flush and close stdout, wait for the pipeline to finish, and then free 
+ * the pipeline object. */
+
+#endif /* TEXTOUT_H */
diff --git a/inc/tokenizer.h b/inc/tokenizer.h
new file mode 100644
index 0000000..d1ce9d9
--- /dev/null
+++ b/inc/tokenizer.h
@@ -0,0 +1,66 @@
+/* tokenizer - A tokenizer structure that will chop up file into
+ * tokens.  It is aware of quoted strings and otherwise tends to return
+ * white-space or punctuated-separated words, with punctuation in
+ * a separate token.  This is used by autoSql. */
+
+#ifndef TOKENIZER_H
+#define TOKENIZER_H
+
+struct tokenizer
+/* This handles reading in tokens. */
+    {
+    bool reuse;	         /* True if want to reuse this token. */
+    bool eof;            /* True at end of file. */
+    int leadingSpaces;	 /* Number of leading spaces before token. */
+    struct lineFile *lf; /* Underlying file. */
+    char *curLine;       /* Current line of text. */
+    char *linePt;        /* Start position within current line. */
+    char *string;        /* String value of token */
+    int sSize;           /* Size of string. */
+    int sAlloc;          /* Allocated string size. */
+      /* Some variables set after tokenizerNew to control details of
+       * parsing. */
+    bool leaveQuotes;	 /* Leave quotes in string. */
+    bool uncommentC;	 /* Take out C (and C++) style comments. */
+    bool uncommentShell; /* Take out # style comments. */
+    };
+
+struct tokenizer *tokenizerNew(char *fileName);
+/* Return a new tokenizer. */
+
+struct tokenizer *tokenizerOnLineFile(struct lineFile *lf);
+/* Create a new tokenizer on open lineFile. */
+
+void tokenizerFree(struct tokenizer **pTkz);
+/* Tear down a tokenizer. */
+
+void tokenizerReuse(struct tokenizer *tkz);
+/* Reuse token. */
+
+int tokenizerLineCount(struct tokenizer *tkz);
+/* Return line of current token. */
+
+char *tokenizerFileName(struct tokenizer *tkz);
+/* Return name of file. */
+
+char *tokenizerNext(struct tokenizer *tkz);
+/* Return token's next string (also available as tkz->string) or
+ * NULL at EOF. This string will be overwritten with the next call
+ * to tokenizerNext, so cloneString if you need to save it. */
+
+void tokenizerErrAbort(struct tokenizer *tkz, char *format, ...);
+/* Print error message followed by file and line number and
+ * abort. */
+
+void tokenizerNotEnd(struct tokenizer *tkz);
+/* Squawk if at end. */
+
+char *tokenizerMustHaveNext(struct tokenizer *tkz);
+/* Get next token, which must be there. */
+
+void tokenizerMustMatch(struct tokenizer *tkz, char *string);
+/* Require next token to match string.  Return next token
+ * if it does, otherwise abort. */
+
+#endif /* TOKENIZER_H */
+
diff --git a/inc/trans3.h b/inc/trans3.h
new file mode 100644
index 0000000..61f0f0c
--- /dev/null
+++ b/inc/trans3.h
@@ -0,0 +1,59 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* trans3 - a sequence and three translated reading frames. 
+ * In the gfServer/gfClient system these are found in a
+ * t3Hash that has as values lists of trans3.  These reflect
+ * the fragments of the genome actually loaded in memory
+ * to perform the alignment. */
+
+#ifndef TRANS3_H
+#define TRANS3_H
+
+#ifndef DNASEQ_H
+#include "dnaseq.h"
+#endif
+
+#ifndef HASH_H
+#include "hash.h"
+#endif
+
+struct trans3
+/* A sequence and three translations of it. */
+     {
+     struct trans3 *next;		/* Next in list. */
+     char *name;			/* Name (not allocated here) */
+     struct dnaSeq *seq;		/* Untranslated sequence.  Not allocated here. */
+     aaSeq *trans[3];			/* Translated sequences.  Allocated here*/
+     int start,end;			/* Start/end of sequence in a larger context. */
+     int nibSize;			/* Size of nib file this is embedded in. */
+     boolean isRc;			/* Has been reverse complemented? */
+     };
+
+struct trans3 *trans3New(struct dnaSeq *seq);
+/* Create a new set of translated sequences. */
+
+void trans3Free(struct trans3 **pT3);
+/* Free a trans3 structure. */
+
+void trans3FreeList(struct trans3 **pList);
+/* Free a list of dynamically allocated trans3's */
+
+struct trans3 *trans3Find(struct hash *t3Hash, char *name, int start, int end);
+/* Find trans3 in hash which corresponds to sequence of given name and includes
+ * bases between start and end. */
+
+void trans3Offset(struct trans3 *t3List, AA *aa, int *retOffset, int *retFrame);
+/* Figure out offset of peptide in context of larger sequences. */
+
+int trans3GenoPos(char *pt, bioSeq *seq, struct trans3 *t3List, boolean isEnd);
+/* Convert from position in one of three translated frames in
+ * t3List to genomic offset. If t3List is NULL then just use seq
+ * instead. */
+
+int trans3Frame(char *pt, struct trans3 *t3List);
+/* Figure out which frame pt is in or 0 if no frame. */
+
+#endif /* TRANS3_H */
diff --git a/inc/trix.h b/inc/trix.h
new file mode 100644
index 0000000..7bb3a56
--- /dev/null
+++ b/inc/trix.h
@@ -0,0 +1,45 @@
+/* trix - text retrieval index.  Stuff for fast two level index
+ * of text for fast word searches. */
+
+struct trix
+/* A two level index */
+    {
+    struct lineFile *lf;	/* Open file on first level index. */
+    struct trixIxx *ixx;	/* Second level index in memory. */
+    int ixxSize;		/* Size of second level index. */
+    int ixxAlloc;	        /* Space allocated for index. */
+    struct hash *wordHitHash;	/* Hash of word hitsLists, so search on "the the the" works fast. */
+    };
+
+struct trixSearchResult
+/* Result of a trix search. */
+    {
+    struct trixSearchResult *next;
+    char *itemId;               /* ID of matching item */
+    int unorderedSpan;          /* Minimum span in single doc with words in any order. */
+    int orderedSpan;            /* Minimum span in single doc with words in search order. */
+    int wordPos;		/* Position of word in doc more or less. */
+    int leftoverLetters;	/* Number of leftover letters in words. */
+    };
+
+#define trixPrefixSize 5	/* Size of prefix in second level index. */
+
+struct trix *trixOpen(char *ixFile);
+/* Open up index.  Load second level index in memory. */
+
+void trixClose(struct trix **pTrix);
+/* Close up index and free up associated resources. */
+
+struct trixSearchResult *trixSearch(struct trix *trix, int wordCount, char **words,
+	boolean expand);
+/* Return a list of items that match all words.  This will be sorted so that
+ * multiple-word matches where the words are closer to each other and in the
+ * right order will be first.  Do a trixSearchResultFreeList when done. 
+ * If expand is TRUE then this will match not only the input words, but also
+ * additional words that start with the input words. */
+
+void trixSearchResultFree(struct trixSearchResult **pTsr);
+/* Free up data associated with trixSearchResult. */
+
+void trixSearchResultFreeList(struct trixSearchResult **pList);
+/* Free up a list of trixSearchResults. */
diff --git a/inc/twoBit.h b/inc/twoBit.h
new file mode 100644
index 0000000..abe8957
--- /dev/null
+++ b/inc/twoBit.h
@@ -0,0 +1,194 @@
+/* twoBit - DNA sequence represented as two bits per pixel
+ * with associated list of regions containing N's, and
+ * masked regions. */
+
+#ifndef TWOBIT_H
+#define TWOBIT_H
+
+struct twoBit
+/* Two bit representation of DNA. */
+    {
+    struct twoBit *next;	/* Next sequence in list */
+    char *name;			/* Name of sequence. */
+    UBYTE *data;		/* DNA at two bits per base. */
+    bits32 size;		/* Size of this sequence. */
+    bits32 nBlockCount;		/* Count of blocks of Ns. */
+    bits32 *nStarts;		/* Starts of blocks of Ns. */
+    bits32 *nSizes;		/* Sizes of blocks of Ns. */
+    bits32 maskBlockCount;	/* Count of masked blocks. */
+    bits32 *maskStarts;		/* Starts of masked regions. */
+    bits32 *maskSizes;		/* Sizes of masked regions. */
+    bits32 reserved;		/* Reserved for future expansion. */
+    };
+
+struct twoBitIndex
+/* An entry in twoBit index. */
+    {
+    struct twoBitIndex *next;	/* Next in list. */
+    char *name;			/* Name - allocated in hash */
+    bits32 offset;		/* Offset in file. */
+    };
+
+struct twoBitFile
+/* Holds header and index info from .2bit file. */
+    {
+    struct twoBitFile *next;
+    char *fileName;	/* Name of this file, for error reporting. */
+    FILE *f;		/* Open file. */
+    boolean isSwapped;	/* Is byte-swapping needed. */
+    bits32 version;	/* Version of .2bit file */
+    bits32 seqCount;	/* Number of sequences. */
+    bits32 reserved;	/* Reserved, always zero for now. */
+    struct twoBitIndex *indexList;	/* List of sequence. */
+    struct hash *hash;	/* Hash of sequences. */
+    struct bptFile *bpt;	/* Alternative index. */
+    };
+
+struct twoBitSpec
+/* parsed .2bit file and sequence specs */
+{
+    char *fileName;                 /* path to file */
+    struct twoBitSeqSpec *seqs;     /* list of sequences and subsequences */
+};
+
+struct twoBitSeqSpec
+/* specification for a seq or subsequence in a .2bit file */
+{
+    struct twoBitSeqSpec *next;
+    char *name;                 /* name of sequence */
+    bits32 start;              /* start of subsequence 0 */
+    bits32 end;                /* end of subsequence;
+                                 * 0 if not a subsequence */
+};
+
+struct twoBitFile *twoBitOpen(char *fileName);
+/* Open file, read in header and index.  
+ * Squawk and die if there is a problem. */
+
+struct twoBitFile *twoBitOpenExternalBptIndex(char *twoBitName, char *bptName);
+/* Open file, read in header, but not regular index.  Instead use
+ * bpt index.   Beware if you use this the indexList field will be NULL
+ * as will the hash. */
+
+void twoBitClose(struct twoBitFile **pTbf);
+/* Free up resources associated with twoBitFile. */
+
+int twoBitSeqSize(struct twoBitFile *tbf, char *name);
+/* Return size of sequence in two bit file in bases. */
+
+long long twoBitTotalSize(struct twoBitFile *tbf);
+/* Return total size of all sequences in two bit file. */
+
+struct dnaSeq *twoBitReadSeqFragExt(struct twoBitFile *tbf, char *name,
+                                    int fragStart, int fragEnd, boolean doMask, int *retFullSize);
+/* Read part of sequence from .2bit file.  To read full
+ * sequence call with start=end=0.  Sequence will be lower
+ * case if doMask is false, mixed case (repeats in lower)
+ * if doMask is true. */
+
+struct dnaSeq *twoBitReadSeqFrag(struct twoBitFile *tbf, char *name,
+	int fragStart, int fragEnd);
+/* Read part of sequence from .2bit file.  To read full
+ * sequence call with start=end=0.  Note that sequence will
+ * be mixed case, with repeats in lower case and rest in
+ * upper case. */
+
+struct dnaSeq *twoBitReadSeqFragLower(struct twoBitFile *tbf, char *name,
+	int fragStart, int fragEnd);
+/* Same as twoBitReadSeqFrag, but sequence is returned in lower case. */
+
+struct dnaSeq *twoBitLoadAll(char *spec);
+/* Return list of all sequences matching spec, which is in
+ * the form:
+ *
+ *    file/path/input.2bit[:seqSpec1][,seqSpec2,...]
+ *
+ * where seqSpec is either
+ *     seqName
+ *  or
+ *     seqName:start-end */
+
+struct slName *twoBitSeqNames(char *fileName);
+/* Get list of all sequences in twoBit file. */
+
+struct twoBit *twoBitFromDnaSeq(struct dnaSeq *seq, boolean doMask);
+/* Convert dnaSeq representation in memory to twoBit representation.
+ * If doMask is true interpret lower-case letters as masked. */
+
+struct twoBit *twoBitFromFile(char *fileName);
+/* Get twoBit list of all sequences in twoBit file. */
+
+struct twoBit *twoBitOneFromFile(struct twoBitFile *tbf, char *name);
+/* Get single sequence as two bit. */
+
+void twoBitFree(struct twoBit **pTwoBit);
+/* Free up a two bit structure. */
+
+void twoBitFreeList(struct twoBit **pList);
+/* Free a list of dynamically allocated twoBit's */
+
+
+void twoBitWriteOne(struct twoBit *twoBit, FILE *f);
+/* Write out one twoBit sequence to binary file. 
+ * Note this does not include the name, which is
+ * stored only in index. */
+
+void twoBitWriteHeader(struct twoBit *twoBitList, FILE *f);
+/* Write out header portion of twoBit file, including initial
+ * index */
+
+boolean twoBitIsFile(char *fileName);
+/* Return TRUE if file is in .2bit format. */
+
+boolean twoBitParseRange(char *rangeSpec, char **retFile, 
+	char **retSeq, int *retStart, int *retEnd);
+/* Parse out something in format
+ *    file/path/name:seqName:start-end
+ * or
+ *    file/path/name:seqName
+ * This will destroy the input 'rangeSpec' in the process.
+ * Returns FALSE if it doesn't fit this format. 
+ * If it is the shorter form then start and end will both
+ * be returned as zero, which is ok by twoBitReadSeqFrag. */
+
+boolean twoBitIsRange(char *rangeSpec);
+/* Return TRUE if it looks like a two bit range specifier. */
+
+boolean twoBitIsFileOrRange(char *spec);
+/* Return TRUE if it is a two bit file or subrange. */
+
+boolean twoBitIsSpec(char *spec);
+/* Return TRUE spec is a valid 2bit spec (see twoBitSpecNew) */
+
+struct twoBitSpec *twoBitSpecNew(char *specStr);
+/* Parse a .2bit file and sequence spec into an object.
+ * The spec is a string in the form:
+ *
+ *    file/path/input.2bit[:seqSpec1][,seqSpec2,...]
+ *
+ * where seqSpec is either
+ *     seqName
+ *  or
+ *     seqName:start-end
+ *
+ * free result with twoBitSpecFree().
+ */
+
+struct twoBitSpec *twoBitSpecNewFile(char *twoBitFile, char *specFile);
+/* parse a file containing a list of specifications for sequences in the
+ * specified twoBit file. Specifications are one per line in forms:
+ *     seqName
+ *  or
+ *     seqName:start-end
+ */
+
+void twoBitSpecFree(struct twoBitSpec **specPtr);
+/* free a twoBitSpec object */
+
+void twoBitOutNBeds(struct twoBitFile *tbf, char *seqName, FILE *outF);
+/* output a series of bed3's that enumerate the number of N's in a sequence*/
+
+int twoBitSeqSizeNoNs(struct twoBitFile *tbf, char *seqName);
+/* return the length of the sequence, not counting N's */
+
+#endif /* TWOBIT_H */
diff --git a/inc/udc.h b/inc/udc.h
new file mode 100644
index 0000000..a36eeb6
--- /dev/null
+++ b/inc/udc.h
@@ -0,0 +1,143 @@
+/* udc - url data cache - a caching system that keeps blocks of data fetched from URLs in
+ * sparse local files for quick use the next time the data is needed. 
+ *
+ * This cache is enormously simplified by there being no local _write_ to the cache,
+ * just reads.  
+ *
+ * The overall strategy of the implementation is to have a root cache directory
+ * with a subdir for each file being cached.  The directory for a single cached file
+ * contains two files - "bitmap" and "sparseData" that contains information on which
+ * parts of the URL are cached and the actual cached data respectively. The subdirectory name
+ * associated with the file is constructed from the URL in a straightforward manner.
+ *     http://genome.ucsc.edu/cgi-bin/hgGateway
+ * gets mapped to:
+ *     rootCacheDir/http/genome.ucsc.edu/cgi-bin/hgGateway/
+ * The URL protocol is the first directory under the root, and the remainder of the
+ * URL, with some necessary escaping, is used to define the rest of the cache directory
+ * structure, with each '/' after the protocol line translating into another directory
+ * level.
+ *    
+ * The bitmap file contains time stamp and size data as well as an array with one bit
+ * for each block of the file that has been fetched.  Currently the block size is 8K. */
+
+#ifndef UDC_H
+#define UDC_H
+
+struct udcFile;
+/* Handle to a cached file.  Inside of structure mysterious unless you are udc.c. */
+
+struct udcFile *udcFileMayOpen(char *url, char *cacheDir);
+/* Open up a cached file. cacheDir may be null in which case udcDefaultDir() will be
+ * used.  Return NULL if file doesn't exist. */
+
+struct udcFile *udcFileOpen(char *url, char *cacheDir);
+/* Open up a cached file.  cacheDir may be null in which case udcDefaultDir() will be
+ * used.  Abort if if file doesn't exist. */
+
+void udcFileClose(struct udcFile **pFile);
+/* Close down cached file. */
+
+bits64 udcRead(struct udcFile *file, void *buf, bits64 size);
+/* Read a block from file.  Return amount actually read. */
+
+void udcMustRead(struct udcFile *file, void *buf, bits64 size);
+/* Read a block from file.  Abort if any problem, including EOF before size is read. */
+
+#define udcMustReadOne(file, var) udcMustRead(file, &(var), sizeof(var))
+/* Read one variable from file or die. */
+
+bits64 udcReadBits64(struct udcFile *file, boolean isSwapped);
+/* Read and optionally byte-swap 64 bit entity. */
+
+bits32 udcReadBits32(struct udcFile *file, boolean isSwapped);
+/* Read and optionally byte-swap 32 bit entity. */
+
+bits16 udcReadBits16(struct udcFile *file, boolean isSwapped);
+/* Read and optionally byte-swap 16 bit entity. */
+
+float udcReadFloat(struct udcFile *file, boolean isSwapped);
+/* Read and optionally byte-swap floating point number. */
+
+double udcReadDouble(struct udcFile *file, boolean isSwapped);
+/* Read and optionally byte-swap double-precision floating point number. */
+
+int udcGetChar(struct udcFile *file);
+/* Get next character from file or die trying. */
+
+char *udcReadStringAndZero(struct udcFile *file);
+/* Read in zero terminated string from file.  Do a freeMem of result when done. */
+
+char *udcFileReadAll(char *url, char *cacheDir, size_t maxSize, size_t *retSize);
+/* Read a complete file via UDC. The cacheDir may be null in which case udcDefaultDir()
+ * will be used.  If maxSize is non-zero, check size against maxSize
+ * and abort if it's bigger.  Returns file data (with an extra terminal for the
+ * common case where it's treated as a C string).  If retSize is non-NULL then
+ * returns size of file in *retSize. Do a freeMem or freez of the returned buffer
+ * when done. */
+
+struct lineFile *udcWrapShortLineFile(char *url, char *cacheDir, size_t maxSize);
+/* Read in entire short (up to maxSize) url into memory and wrap a line file around it.
+ * The cacheDir may be null in which case udcDefaultDir() will be used.  If maxSize
+ * is zero then a default value (currently 64 meg) will be used. */
+
+void udcSeek(struct udcFile *file, bits64 offset);
+/* Seek to a particular (absolute) position in file. */
+
+bits64 udcTell(struct udcFile *file);
+/* Return current file position. */
+
+bits64 udcCleanup(char *cacheDir, double maxDays, boolean testOnly);
+/* Remove cached files older than maxDays old. If testOnly is set
+ * no clean up is done, but the size of the files that would be
+ * cleaned up is still. */
+
+void udcParseUrlFull(char *url, char **retProtocol, char **retAfterProtocol, char **retColon,
+		     char **retAuth);
+/* Parse the URL into components that udc treats separately.
+ * *retAfterProtocol is Q-encoded to keep special chars out of filenames.  
+ * Free all *ret's except *retColon when done. */
+
+char *udcDefaultDir();
+/* Get default directory for cache.  Use this for the udcFileOpen call if you
+ * don't have anything better.... */
+
+void udcSetDefaultDir(char *path);
+/* Set default directory for cache */
+
+#define udcDevicePrefix "udc:"
+/* Prefix used by convention to indicate a file should be accessed via udc.  This is
+ * followed by the local path name or a url, so in common practice you see things like:
+ *     udc:http://genome.ucsc.edu/goldenPath/hg18/tracks/someTrack.bb */
+
+struct slName *udcFileCacheFiles(char *url, char *cacheDir);
+/* Return low-level list of files used in cache. */
+
+char *udcPathToUrl(const char *path, char *buf, size_t size, char *cacheDir);
+/* Translate path into an URL, store in buf, return pointer to buf if successful
+ * and NULL if not. */
+
+long long int udcSizeFromCache(char *url, char *cacheDir);
+/* Look up the file size from the local cache bitmap file, or -1 if there
+ * is no cache for url. */
+
+unsigned long udcCacheAge(char *url, char *cacheDir);
+/* Return the age in seconds of the oldest cache file.  If a cache file is
+ * missing, return the current time (seconds since the epoch). */
+
+int udcCacheTimeout();
+/* Get cache timeout (if local cache files are newer than this many seconds,
+ * we won't ping the remote server to check the file size and update time). */
+
+void udcSetCacheTimeout(int timeout);
+/* Set cache timeout (if local cache files are newer than this many seconds,
+ * we won't ping the remote server to check the file size and update time). */
+
+time_t udcUpdateTime(struct udcFile *udc);
+/* return udc->updateTime */
+
+#ifdef PROGRESS_METER
+off_t remoteFileSize(char *url);
+/* fetch remote file size from given URL */
+#endif
+
+#endif /* UDC_H */
diff --git a/inc/unfin.h b/inc/unfin.h
new file mode 100644
index 0000000..dd2d11e
--- /dev/null
+++ b/inc/unfin.h
@@ -0,0 +1,31 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* unfin - things to help handle unfinished (fragmented) DNA sequences). */
+#ifndef UNFIN_H
+#define UNFIN_H
+
+enum {contigPad = 800,};
+/* How may N's between contigs. */
+
+struct contigTree
+/* A hierarchical structure of contigs.  A forest of these is
+ * maintained by the system.  (No need to free these.) */
+    {
+    struct contigTree  *next;    /* Sibling. */
+    struct contigTree *children; /* Sub-contigs. */
+    struct contigTree *parent;   /* Parent of contig. */
+    char *id;	       /* Ensemble ID. (Not allocated here.) */
+    int submitLength;  /* Number of bases in submission. */
+    int submitOffset;  /* Offset relative to parent in genBank submission. */
+    int orientation;   /* +1 or -1. Strand relative to parent.*/
+    int corder;        /* Order of contig in genBank submission. */
+    int browserOffset; /* Offset relative to parent for browser, ordered by ensemble, with
+                        * ensContigPad N's between each contig. */ 
+    int browserLength; /* Size including padding. */
+    };
+
+#endif /* UNFIN_H */
+
diff --git a/inc/vGfx.h b/inc/vGfx.h
new file mode 100644
index 0000000..63dd864
--- /dev/null
+++ b/inc/vGfx.h
@@ -0,0 +1,193 @@
+/* vGfx - interface to polymorphic graphic object
+ * that currently can either be a memory buffer or
+ * a postScript file. */
+
+#ifndef VGFX_H
+#define VGFX_H
+
+#ifndef MEMGFX_H
+#include "memgfx.h"
+#endif
+
+struct vGfx
+/* Virtual graphic object - mostly a bunch of function
+ * pointers. */
+    {
+    struct vGfx *next;	/* Next in list. */
+    void *data;		/* Type specific data. */
+    boolean pixelBased; /* Real pixels, not PostScript or something. */
+    int width, height;  /* Virtual pixel dimensions. */
+
+    void (*close)(void **pV);
+    /* Finish writing out and free structure. */
+
+    void (*dot)(void *v, int x, int y, int colorIx);
+    /* Draw a single pixel.  Try to work at a higher level
+     * when possible! */
+
+    int (*getDot)(void *v, int x, int y);
+    /* Fetch a single pixel.  Please do not use this, this is special
+     * for verticalText only. */
+
+    void (*box)(void *v, int x, int y, 
+	    int width, int height, int colorIx);
+    /* Draw a box. */
+
+    void (*line)(void *v, 
+	    int x1, int y1, int x2, int y2, int colorIx);
+    /* Draw a line from one point to another. */
+
+    void (*text)(void *v, int x, int y, int colorIx, void *font, char *text);
+    /* Draw a line of text with upper left corner x,y. */
+
+    void (*textRight)(void *v, int x, int y, int width, int height,
+    	int colorIx, void *font, char *text);
+   /* Draw a line of text right justified in box defined by x/y/width/height */
+
+    void (*textCentered)(void *v, int x, int y, int width, int height,
+    	int colorIx, void *font, char *text);
+    /* Draw a line of text in middle of box. */
+
+    int (*findColorIx)(void *v, int r, int g, int b);
+    /* Find color in map if possible, otherwise create new color or
+     * in a pinch a close color. */
+
+    struct rgbColor (*colorIxToRgb)(void *v, int colorIx);
+    /* Return rgb values for given color index. */
+
+    void (*setWriteMode)(void *v, unsigned int writeMode);
+    /* Set write mode. */
+
+    void (*setClip)(void *v, int x, int y, int width, int height);
+    /* Set clipping rectangle. */
+
+    void (*unclip)(void *v);
+    /* Set clipping rect cover full thing. */
+
+    void (*verticalSmear)(void *v,
+	    int xOff, int yOff, int width, int height, 
+	    Color *dots, boolean zeroClear);
+    /* Put a series of one 'pixel' width vertical lines. */
+
+    void (*fillUnder)(void *v, int x1, int y1, int x2, int y2, 
+	    int bottom, Color color);
+    /* Draw a 4 sided filled figure that has line x1/y1 to x2/y2 at
+     * it's top, a horizontal line at bottom at it's bottom,  and
+     * vertical lines from the bottom to y1 on the left and bottom to
+     * y2 on the right. */
+
+    void (*drawPoly)(void *v, struct gfxPoly *poly, Color color, 
+    	boolean filled);
+    /* Draw polygon, possibly filled in color. */
+
+    void (*setHint)(void *v, char *hint, char *value);
+    /* Set hint */
+
+    char * (*getHint)(void *v, char *hint);
+    /* Get hint */
+
+    int (*getFontPixelHeight)(void *v, void *font);
+    /* How high in pixels is font? */
+
+    int (*getFontStringWidth)(void *v, void *font, char *string);
+    /* How wide is a string? */
+    };
+
+struct vGfx *vgOpenPng(int width, int height, char *fileName, boolean useTransparency);
+/* Open up something that will write out a PNG file upon vgClose.  
+ * If useTransparency, then the first color in memgfx's colormap/palette is
+ * assumed to be the image background color, and pixels of that color
+ * are made transparent. */
+
+struct vGfx *vgOpenPostScript(int width, int height, char *fileName);
+/* Open up something that will someday be a PostScript file. */
+
+void vgClose(struct vGfx **pVg);
+/* Close down virtual graphics object, and finish writing it to file. */
+
+#define vgDot(v,x,y, color) v->dot(v->data,x,y,color)
+/* Draw a single pixel.  Try to work at a higher level
+ * when possible! */
+
+#define vgGetDot(v,x,y) v->getDot(v->data,x,y)
+/* Fetch a single pixel.  Please do not use this, this is special for
+ * verticalText only */
+
+#define vgBox(v,x,y,width,height,color) v->box(v->data,x,y,width,height,color)
+/* Draw a box. */
+
+#define vgLine(v,x1,y1,x2,y2,color) v->line(v->data,x1,y1,x2,y2,color)
+/* Draw a line from one point to another. */
+
+#define vgText(v,x,y,color,font,string) v->text(v->data,x,y,color,font,string)
+/* Draw a line of text with upper left corner x,y. */
+
+#define vgTextRight(v,x,y,width,height,color,font,string) \
+	v->textRight(v->data,x,y,width,height,color,font,string)
+/* Draw a line of text right justified in box defined by x/y/width/height */
+
+#define vgTextCentered(v,x,y,width,height,color,font,string) \
+	v->textCentered(v->data,x,y,width,height,color,font,string)
+/* Draw a line of text in middle of box. */
+
+#define vgFindColorIx(v,r,g,b) v->findColorIx(v->data, r, g, b)
+/* Find index of RGB color.  */
+
+#define vgColorIxToRgb(v,colorIx) v->colorIxToRgb(v->data, colorIx)
+/* Return rgb values for given color index. */
+
+#define vgSetWriteMode(v, writeMode)    \
+	v->setWriteMode(v->data, writeMode)
+/* Set write mode. */
+
+#define vgSetClip(v,x,y,width,height) \
+	v->setClip(v->data, x, y, width, height)
+/* Set clipping rectangle. */
+
+#define vgUnclip(v) v->unclip(v->data);
+/* Get rid of clipping rectangle.  Note this is not completely
+ * the same in PostScript and the memory images.  PostScript
+ * demands that vgSetClip/vgUnclip come in pairs, and that
+ * vgSetClip just further restrict a previous vgSetClip call.
+ * The only portable way to do this is to strictly pair up
+ * the setClip/unclip calls and not to nest them. */
+
+#define vgVerticalSmear(v,x,y,w,h,dots,zeroClear) \
+	v->verticalSmear(v->data,x,y,w,h,dots,zeroClear)
+/* Take array of dots and smear them vertically. */
+
+#define vgFillUnder(v,x1,y1,x2,y2,bottom,color) \
+	v->fillUnder(v->data,x1,y1,x2,y2,bottom,color)
+    /* Draw a 4 sided filled figure that has line x1/y1 to x2/y2 at
+     * it's top, a horizontal line at bottom at it's bottom,  and
+     * vertical lines from the bottom to y1 on the left and bottom to
+     * y2 on the right. */
+
+#define vgDrawPoly(v,poly,color,filled) \
+	v->drawPoly(v->data,poly,color,filled)
+    /* Draw a polygon in color, optionally filled. */
+
+#define vgSetHint(v,hint,value) \
+	v->setHint(v->data,hint,value)
+    /* Set hint */
+
+#define vgGetHint(v,hint) \
+	v->getHint(v->data,hint)
+    /* Get hint */
+
+#define vgGetFontPixelHeight(v,font) \
+	v->getFontPixelHeight(v->data,font)
+    /* How high in pixels is font? */
+
+#define vgGetFontStringWidth(v,font,string) \
+	v->getFontStringWidth(v->data,font,string)
+    /* How wide is a string? */
+
+int vgFindRgb(struct vGfx *vg, struct rgbColor *rgb);
+/* Find color index corresponding to rgb color. */
+
+Color vgContrastingColor(struct vGfx *vg, int backgroundIx);
+/* Return black or white whichever would be more visible over
+ * background. */
+
+#endif /* VGFX_H */
diff --git a/inc/vcf.h b/inc/vcf.h
new file mode 100644
index 0000000..6ff5399
--- /dev/null
+++ b/inc/vcf.h
@@ -0,0 +1,232 @@
+/* VCF: Variant Call Format, version 4.0 / 4.1
+ * http://www.1000genomes.org/wiki/Analysis/Variant%20Call%20Format/vcf-variant-call-format-version-40
+ * http://www.1000genomes.org/wiki/Analysis/Variant%20Call%20Format/vcf-variant-call-format-version-41
+ * The vcfFile object borrows many memory handling and error reporting tricks from MarkD's
+ * gff3File; any local deficiencies are not to reflect poorly on Mark's fine work! :) */
+
+#ifndef vcf_h
+#define vcf_h
+
+#include "hash.h"
+#include "linefile.h"
+#include "asParse.h"
+
+enum vcfInfoType
+/* VCF header defines INFO column components; each component has one of these types: */
+    {
+    vcfInfoNoType,	// uninitialized value (0) or unrecognized type name
+    vcfInfoInteger,
+    vcfInfoFloat,
+    vcfInfoFlag,
+    vcfInfoCharacter,
+    vcfInfoString,
+    };
+
+union vcfDatum
+/* Container for a value whose type is specified by an enum vcfInfoType. */
+    {
+    int datInt;
+    double datFloat;
+    boolean datFlag;
+    char datChar;
+    char *datString;
+    };
+
+struct vcfInfoDef
+/* Definition of INFO column component from VCF header: */
+    {
+    struct vcfInfoDef *next;
+    char *key;			// A short identifier, e.g. MQ for mapping quality
+    int fieldCount;		// The number of values to follow the id, or -1 if it varies
+    enum vcfInfoType type;	// The type of values that follow the id
+    char *description;		// Brief description of info
+    };
+
+struct vcfInfoElement
+/* A single INFO column component; each row's INFO column may contain multiple components. */
+    {
+    char *key;			// An identifier described by a struct vcfInfoDef
+    int count;			// Number of data values following id
+    union vcfDatum *values;	// Array of data values following id
+    bool *missingData;		// Array of flags for missing data values ("." instead of number)
+    };
+
+struct vcfGenotype
+/* A single component of the optional GENOTYPE column. */
+    {
+    char *id;			// Name of individual/sample (pointer to vcfFile genotypeIds) or .
+    char hapIxA;		// Index of one haplotype's allele: 0=reference, 1=alt, 2=other alt
+				// *or* if negative, missing data
+    char hapIxB;		// Index of other haplotype's allele, or if negative, missing data
+    bool isPhased;		// True if haplotypes are phased
+    bool isHaploid;		// True if there is only one haplotype (e.g. chrY)
+    int infoCount;		// Number of components named in FORMAT column
+    struct vcfInfoElement *infoElements;	// Array of info components for this genotype call
+    };
+
+struct vcfRecord
+/* A VCF data row (or list of rows). */
+{
+    struct vcfRecord *next;
+    char *chrom;		// Reference assembly sequence name
+    unsigned int chromStart;	// Start offset in chrom
+    unsigned int chromEnd;	// End offset in chrom
+    char *name;			// Variant name from ID column
+    int alleleCount;		// Number of alleles (reference + alternates)
+    char **alleles;		// Alleles: reference first then alternate alleles
+    char *qual;			// . or Phred-scaled score, i.e. -10log_10 P(call in ALT is wrong)
+    int filterCount;		// Number of ;-separated filter codes in FILTER column
+    char **filters;		// Code(s) described in header for failed filters (or PASS or .)
+    int infoCount;		// Number of components of INFO column
+    struct vcfInfoElement *infoElements;	// Array of INFO column components
+    char *format;		// Optional column containing ordered list of genotype components
+    char **genotypeUnparsedStrings;	// Temporary array of unparsed optional genotype columns
+    struct vcfGenotype *genotypes;	// If built, array of parsed genotype components;
+					// call vcfParseGenotypes(record) to build.
+    struct vcfFile *file;	// Pointer back to parent vcfFile
+};
+
+struct vcfFile
+/* Info extracted from a VCF file.  Manages all memory for contents.
+ * Clearly borrowing structure from MarkD's gff3File. :) */
+{
+    char *fileOrUrl;		// VCF local file path or URL
+    char *headerString;		// Complete original header including newlines.
+    int majorVersion;		// 4 etc.
+    int minorVersion;		// 0, 1 etc.
+    struct vcfInfoDef *infoDefs;	// Header's definitions of INFO column components
+    struct vcfInfoDef *filterDefs;	// Header's definitions of FILTER column failure codes
+    struct vcfInfoDef *altDefs;	// Header's defs of symbolic alternate alleles (e.g. DEL, INS)
+    struct vcfInfoDef *gtFormatDefs;	// Header's defs of GENOTYPE compnts. listed in FORMAT col.
+    int genotypeCount;		// Number of optional genotype columns described in header
+    char **genotypeIds;		// Array of optional genotype column names described in header
+    struct vcfRecord *records;	// VCF data rows, sorted by position
+    struct hash *byName;		// Hash records by name -- not populated until needed.
+    struct hash *pool;		// Used to allocate string values that tend to
+				// be repeated in the files.  hash's localMem is also
+				// use to allocated memory for all other objects.
+    struct lineFile *lf;	// Used only during parsing
+    int maxErr;			// Maximum number of errors before aborting
+    int errCnt;			// Error count
+};
+
+/* Reserved but optional INFO keys: */
+extern const char *vcfInfoAncestralAllele;
+extern const char *vcfInfoPerAlleleGtCount;	// allele count in genotypes, for each ALT allele,
+						// in the same order as listed
+extern const char *vcfInfoAlleleFrequency;  	// allele frequency for each ALT allele in the same
+						// order as listed: use this when estimated from
+						// primary data, not called genotypes
+extern const char *vcfInfoNumAlleles;		// total number of alleles in called genotypes
+extern const char *vcfInfoBaseQuality;		// RMS base quality at this position
+extern const char *vcfInfoCigar;		// cigar string describing how to align an
+						// alternate allele to the reference allele
+extern const char *vcfInfoIsDbSnp;		// dbSNP membership
+extern const char *vcfInfoDepth;		// combined depth across samples, e.g. DP=154
+extern const char *vcfInfoEnd;			// end position of the variant described in this
+						// record (esp. for CNVs)
+extern const char *vcfInfoIsHapMap2;		// membership in hapmap2
+extern const char *vcfInfoIsHapMap3;		// membership in hapmap3
+extern const char *vcfInfoIs1000Genomes;	// membership in 1000 Genomes
+extern const char *vcfInfoMappingQuality;	// RMS mapping quality, e.g. MQ=52
+extern const char *vcfInfoMapQual0Count;	// number of MAPQ == 0 reads covering this record
+extern const char *vcfInfoNumSamples;		// Number of samples with data
+extern const char *vcfInfoStrandBias;		// strand bias at this position
+extern const char *vcfInfoIsSomatic;		// indicates that the record is a somatic mutation,
+						// for cancer genomics
+extern const char *vcfInfoIsValidated;		// validated by follow-up experiment
+
+/* Reserved but optional per-genotype keys: */
+extern const char *vcfGtGenotype;	// numeric allele values separated by "/" (unphased)
+					// or "|" (phased). Allele values are 0 for
+					// reference allele, 1 for the first allele in ALT,
+					// 2 for the second allele in ALT and so on.
+extern const char *vcfGtDepth;		// read depth at this position for this sample
+extern const char *vcfGtFilter;		// analogous to variant's FILTER field
+extern const char *vcfGtLikelihoods;	// three floating point log10-scaled likelihoods for
+					// AA,AB,BB genotypes where A=ref and B=alt;
+					// not applicable if site is not biallelic.
+extern const char *vcfGtPhred;		// Phred-scaled genotype likelihoods rounded to closest int
+extern const char *vcfGtConditionalQual;	// Conditional genotype quality
+					// i.e. phred quality -10log_10 P(genotype call is wrong,
+					// conditioned on the site's being variant)
+extern const char *vcfGtHaplotypeQualities;	// Two phred qualities comma separated
+extern const char *vcfGtPhaseSet;	// Set of phased genotypes to which this genotype belongs
+extern const char *vcfGtPhasingQuality;	// Phred-scaled P(alleles ordered wrongly in heterozygote)
+extern const char *vcfGtExpectedAltAlleleCount;	// Typically used in association analyses
+
+INLINE void vcfPrintDatum(FILE *f, const union vcfDatum datum, const enum vcfInfoType type)
+/* Print datum to f in the format determined by type. */
+{
+switch (type)
+    {
+    case vcfInfoInteger:
+	fprintf(f, "%d", datum.datInt);
+	break;
+    case vcfInfoFloat:
+	fprintf(f, "%f", datum.datFloat);
+	break;
+    case vcfInfoFlag:
+	fprintf(f, "%s", datum.datString); // Flags could have values in older VCF
+	break;
+    case vcfInfoCharacter:
+	fprintf(f, "%c", datum.datChar);
+	break;
+    case vcfInfoString:
+	fprintf(f, "%s", datum.datString);
+	break;
+    default:
+	errAbort("vcfPrintDatum: Unrecognized type %d", type);
+	break;
+    }
+}
+
+struct vcfFile *vcfFileMayOpen(char *fileOrUrl, int maxErr, int maxRecords, boolean parseAll);
+/* Open fileOrUrl and parse VCF header; return NULL if unable.
+ * If parseAll, then read in all lines, parse and store in
+ * vcff->records; if maxErr >= zero, then continue to parse until
+ * there are maxErr+1 errors.  A maxErr less than zero does not stop
+ * and reports all errors. */
+
+struct vcfFile *vcfTabixFileMayOpen(char *fileOrUrl, char *chrom, int start, int end,
+				    int maxErr, int maxRecords);
+/* Open a VCF file that has been compressed and indexed by tabix and
+ * parse VCF header, or return NULL if unable.  If chrom is non-NULL,
+ * seek to the position range and parse all lines in range into
+ * vcff->records.  If maxErr >= zero, then continue to parse until
+ * there are maxErr+1 errors.  A maxErr less than zero does not stop
+ * and reports all errors. */
+
+struct vcfRecord *vcfRecordFromRow(struct vcfFile *vcff, char **words);
+/* Parse words from a VCF data line into a VCF record structure. */
+
+void vcfFileFree(struct vcfFile **vcffPtr);
+/* Free a vcfFile object. */
+
+const struct vcfRecord *vcfFileFindVariant(struct vcfFile *vcff, char *variantId);
+/* Return all records with name=variantId, or NULL if not found. */
+
+const struct vcfInfoElement *vcfRecordFindInfo(const struct vcfRecord *record, char *key);
+/* Find an INFO element, or NULL. */
+
+struct vcfInfoDef *vcfInfoDefForKey(struct vcfFile *vcff, const char *key);
+/* Return infoDef for key, or NULL if it wasn't specified in the header or VCF spec. */
+
+void vcfParseGenotypes(struct vcfRecord *record);
+/* Translate record->genotypesUnparsedStrings[] into proper struct vcfGenotype[].
+ * This destroys genotypesUnparsedStrings. */
+
+const struct vcfGenotype *vcfRecordFindGenotype(struct vcfRecord *record, char *sampleId);
+/* Find the genotype and associated info for the individual, or return NULL.
+ * This calls vcfParseGenotypes if it has not already been called. */
+
+struct vcfInfoDef *vcfInfoDefForGtKey(struct vcfFile *vcff, const char *key);
+/* Look up the type of genotype FORMAT component key, in the definitions from the header,
+ * and failing that, from the keys reserved in the spec. */
+
+#define VCF_NUM_COLS 10
+
+struct asObject *vcfAsObj();
+// Return asObject describing fields of VCF
+
+#endif // vcf_h
diff --git a/inc/verbose.h b/inc/verbose.h
new file mode 100644
index 0000000..4dd68b7
--- /dev/null
+++ b/inc/verbose.h
@@ -0,0 +1,53 @@
+/* verbose.h - write out status messages according to the
+ * current verbosity level.  These messages go to stderr. */
+
+#ifndef VERBOSE_H
+#define VERBOSE_H
+
+void verbose(int verbosity, char *format, ...)
+/* Write printf formatted message to log (which by
+ * default is stderr) if global verbose variable
+ * is set to verbosity or higher. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 2, 3)))
+#endif
+    ;
+
+void verboseVa(int verbosity, char *format, va_list args);
+/* Log with at given verbosity vprintf formatted args. */
+
+void verboseTimeInit(void);
+/* Initialize or reinitialize the previous time for use by verboseTime. */
+
+void verboseTime(int verbosity, char *label, ...)
+/* Print label and how long it's been since last call.  Start time can be
+ * initialized with verboseTimeInit, otherwise the elapsed time will be
+ * zero. */
+#if defined(__GNUC__)
+__attribute__((format(printf, 2, 3)))
+#endif
+    ;
+
+void verboseDot();
+/* Write I'm alive dot (at verbosity level 1) */
+
+boolean verboseDotsEnabled();
+/* check if outputting of happy dots are enabled.  They will be enabled if the
+ * verbosity is > 0, stderr is a tty and we don't appear to be running an
+ * emacs shell. */
+
+int verboseLevel(void);
+/* Get verbosity level. */
+
+void verboseSetLevel(int verbosity);
+/* Set verbosity level in log.  0 for no logging,
+ * higher number for increasing verbosity. */
+
+void verboseSetLogFile(char *name);
+/* Set logFile for verbose messages overrides stderr. */
+
+FILE *verboseLogFile();
+/* Get the verbose log file. */
+
+#endif /* VERBOSE_H */
+
diff --git a/inc/wormdna.h b/inc/wormdna.h
new file mode 100644
index 0000000..6610600
--- /dev/null
+++ b/inc/wormdna.h
@@ -0,0 +1,245 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* WormDNA - stuff that finds C. elegans sequence data. */
+#ifndef WORMDNA_H
+#define WORMDNA_H
+
+#ifndef DNAUTIL_H
+#include "dnautil.h"
+#endif
+
+#ifndef DNASEQ_H
+#include "dnaseq.h"
+#endif 
+
+#ifndef NT4_H
+#include "nt4.h"
+#endif 
+
+#ifndef GDF_H
+#include "gdf.h"
+#endif
+
+
+struct wormCdnaInfo 
+/* Extra info stored in cDNA database other than string. */
+    {
+    char *motherString;         /* Holds memory for other strings. */
+    char *name;                 /* Name of cDNA. */
+    char *gene;                 /* Something like unc-1 */
+    char orientation;           /* + or - (relative to gene transcription direction) */
+    char *product;              /* Something like "cyclin-dependent kinase" */
+    int cdsStart, cdsEnd;       /* Start and stop of coding region within cDNA. */
+    boolean knowStart, knowEnd; /* Start known?  End known? */
+    boolean isEmbryonic;        /* True if derived from embryo culture. */
+    boolean isAdult;            /* True if derived from adult culture. */
+    boolean isMale;             /* True if males only. */
+    boolean isHermaphrodite;    /* True if hermaphrodites only. */
+    char *description;          /* One line description. */
+    };
+
+boolean wormCdnaInfo(char *name, struct wormCdnaInfo *retInfo);
+/* Get info about cDNA sequence. */
+
+void wormFaCommentIntoInfo(char *faComment, struct wormCdnaInfo *retInfo);
+/* Process line from .fa file containing information about cDNA into binary
+ * structure. */
+
+void wormFreeCdnaInfo(struct wormCdnaInfo *ci);
+/* Free the mother string in the cdnaInfo.  (The info structure itself normally isn't
+ * dynamically allocated. */
+
+boolean wormInfoForGene(char *orfName, struct wormCdnaInfo *retInfo);
+/* Return info if any on gene/ORF, or NULL if none exists. wormFreeCdnaInfo retInfo when done.
+ */
+
+
+boolean wormCdnaSeq(char *name, struct dnaSeq **retDna, struct wormCdnaInfo *retInfo);
+/* Get a single worm cDNA sequence. Optionally (if retInfo is non-null) get additional
+ * info about the sequence. */
+
+void wormCdnaUncache();
+/* Get rid of any resources used caching or quickly accessing
+ * worm cDNA */
+
+
+/* Stuff for searching entire database of worm cDNA */
+
+struct wormCdnaIterator
+    {
+    FILE *faFile;
+    };
+
+boolean wormSearchAllCdna(struct wormCdnaIterator **retSi);
+/* Set up to search entire database or worm cDNA */
+
+void freeWormCdnaIterator(struct wormCdnaIterator **pIt);
+/* Free up iterator returned by wormSearchAllCdna() */
+
+struct dnaSeq *nextWormCdna(struct wormCdnaIterator *it);
+/* Return next sequence in database */
+
+boolean nextWormCdnaAndInfo(struct wormCdnaIterator *it, struct dnaSeq **retSeq, struct wormCdnaInfo *retInfo);
+/* Return next sequence and associated info from database. */
+
+char *wormFeaturesDir();
+/* Return the features directory. (Includes trailing slash.) */
+
+char *wormChromDir();
+/* Return the directory with the chromosomes. */
+
+char *wormCdnaDir();
+/* Return directory with cDNA data. */
+
+char *wormSangerDir();
+/* Return directory with Sanger specific gene predictions. */
+
+char *wormGenieDir();
+/* Return directory with Genie specific gene predictions. */
+
+char *wormXenoDir();
+/* Return directory with cross-species alignments. */
+
+boolean wormIsGeneName(char *name);
+/* See if it looks like a worm gene name - that is
+ *   abc-12
+ * letters followed by a dash followed by a number. */
+
+boolean wormIsOrfName(char *in);
+/* Check to see if the input is formatted correctly to be
+ * an ORF. */
+
+struct slName *wormGeneToOrfNames(char *name);
+/* Returns list of cosmid.N type ORF names that are known by abc-12 type name. */
+
+char *wormGeneFirstOrfName(char *geneName);
+/* Return first ORF synonym to gene. */
+
+boolean wormGeneForOrf(char *orfName, char *geneNameBuf, int bufSize);
+/* Look for gene type (unc-12 or something) synonym for cosmid.N name. */
+
+boolean getWormGeneExonDna(char *name, DNA **retDna);
+/* get the exon sequence for a gene */
+
+boolean getWormGeneDna(char *name, DNA **retDna, boolean upcExons);
+/* Get the DNA associated with a gene.  Optionally upper case exons. */
+
+void wormLoadNt4Genome(struct nt4Seq ***retNt4Seq, int *retNt4Count);
+/* Load up entire packed worm genome into memory. */
+
+void wormFreeNt4Genome(struct nt4Seq ***pNt4Seq);
+/* Free up packed worm genome. */
+
+int wormChromSize(char *chrom);
+/* Return size of worm chromosome. */
+
+DNA *wormChromPart(char *chromId, int start, int size);
+/* Return part of a worm chromosome. */
+
+DNA *wormChromPartExonsUpper(char *chromId, int start, int size);
+/* Return part of a worm chromosome with exons in upper case. */
+
+void wormChromNames(char ***retNames, int *retNameCount);
+/* Get list of worm chromosome names. */
+
+int wormChromIx(char *name);
+/* Return index of worm chromosome. */
+
+char *wormChromForIx(int ix);
+/* Given ix, return worm chromosome official name. */
+
+char *wormOfficialChromName(char *name);
+/* This returns a pointer to our official string for the chromosome name.
+ * (This allows some routines to do directo pointer comparisons rather
+ * than string comparisons.) */
+
+boolean wormGeneRange(char *name, char **retChromId, char *retStrand, int *retStart, int *retEnd);
+/* Return chromosome position of a gene, ORF,  nameless cluster, or cosmid. Returns
+ * FALSE if no such gene/cluster. */
+
+boolean wormParseChromRange(char *in, char **retChromId, int *retStart, int *retEnd);
+/* Chop up a string representation of a range within a chromosome and put the
+ * pieces into the return variables. Return FALSE if it isn't formatted right. */
+
+boolean wormIsChromRange(char *in);
+/* Check to see if the input is formatted correctly to be
+ * a range of a chromosome. */
+
+void wormClipRangeToChrom(char *chrom, int *pStart, int *pEnd);
+/* Make sure that we stay inside chromosome. */
+
+boolean wormIsNamelessCluster(char *name);
+/* Returns true if name is of correct format to be a nameless cluster. */
+
+DNA *wormGetNamelessClusterDna(char *name);
+/* Get DNA associated with nameless cluster */
+
+struct wormFeature
+/* This holds info on where something is in the genome. */
+    {
+    struct wormFeature *next;
+    char *chrom;    /* One of names returned by */
+    int start, end;
+    char typeByte;
+    char name[1];   /* Allocated to fit. */
+    };
+
+struct wormFeature *newWormFeature(char *name, char *chrom, int start, int end, char typeByte);
+/* Allocate a new feature. */
+
+struct wormFeature *wormCdnasInRange(char *chromId, int start, int end);
+/* Get info on all cDNAs that overlap the range. */
+
+struct wormFeature *wormGenesInRange(char *chromId, int start, int end);
+/* Get info on all genes that overlap the range. */
+
+struct wormFeature *wormSomeGenesInRange(char *chromId, int start, int end, char *gdfDir);
+/* Get info on genes that overlap range in a particular set of gene predictions. */
+
+struct wormFeature *wormCosmidsInRange(char *chromId, int start, int end);
+/* Get info on all cosmids that overlap the range. */
+
+struct cdaAli *wormCdaAlisInRange(char *chromId, int start, int end);
+/* Return list of cdna alignments that overlap range. */
+
+FILE *wormOpenGoodAli();
+/* Opens good alignment file and reads signature. 
+ * (You can then cdaLoadOne() it.) */
+
+struct wormGdfCache
+/* Helps managed fast indexed access to gene predictions. */
+    {
+    char **pDir;
+    struct snof *snof;
+    FILE *file;
+    };
+extern struct wormGdfCache wormSangerGdfCache;
+extern struct wormGdfCache wormGenieGdfCache;
+
+struct gdfGene *wormGetGdfGene(char *name);
+/* Get the named gdfGene. */
+
+struct gdfGene *wormGetSomeGdfGene(char *name, struct wormGdfCache *cache);
+/* Get a single gdfGene of given name. */
+
+struct gdfGene *wormGetGdfGeneList(char *baseName, int baseNameSize);
+/* Get all gdfGenes that start with a given name. */
+
+struct gdfGene *wormGetSomeGdfGeneList(char *baseName, int baseNameSize, struct wormGdfCache *cache);
+/* Get all gdfGenes that start with a given name. */
+
+struct gdfGene *wormGdfGenesInRange(char *chrom, int start, int end, 
+    struct wormGdfCache *geneFinder);
+/* Get list of genes in range according to given gene finder. */
+
+void wormUncacheGdf();
+/* Free up resources associated with fast GDF access. */
+
+void wormUncacheSomeGdf(struct wormGdfCache *cache);
+/* Uncache some gene prediction set. */
+
+#endif /* WORMDNA_H */
+
diff --git a/inc/xAli.h b/inc/xAli.h
new file mode 100644
index 0000000..205823e
--- /dev/null
+++ b/inc/xAli.h
@@ -0,0 +1,73 @@
+/* xAli.h was originally generated by the autoSql program, which also 
+ * generated xAli.c and xAli.sql.  This header links the database and
+ * the RAM representation of objects. */
+
+#ifndef XALI_H
+#define XALI_H
+
+struct xAli
+/* An alignment - like psl but includes the sequence itself */
+    {
+    struct xAli *next;  /* Next in singly linked list. */
+    unsigned match;	/* Number of bases that match that aren't repeats */
+    unsigned misMatch;	/* Number of bases that don't match */
+    unsigned repMatch;	/* Number of bases that match but are part of repeats */
+    unsigned nCount;	/* Number of 'N' bases */
+    unsigned qNumInsert;	/* Number of inserts in query */
+    int qBaseInsert;	/* Number of bases inserted in query */
+    unsigned tNumInsert;	/* Number of inserts in target */
+    int tBaseInsert;	/* Number of bases inserted in target */
+    char strand[3];	/* + or - for strand. First character query, second target (optional) */
+    char *qName;	/* Query sequence name */
+    unsigned qSize;	/* Query sequence size */
+    unsigned qStart;	/* Alignment start position in query */
+    unsigned qEnd;	/* Alignment end position in query */
+    char *tName;	/* Target sequence name */
+    unsigned tSize;	/* Target sequence size */
+    unsigned tStart;	/* Alignment start position in target */
+    unsigned tEnd;	/* Alignment end position in target */
+    unsigned blockCount;	/* Number of blocks in alignment */
+    unsigned *blockSizes;	/* Size of each block */
+    unsigned *qStarts;	/* Start of each block in query. */
+    unsigned *tStarts;	/* Start of each block in target. */
+    char **qSeq;	/* Query sequence for each block. */
+    char **tSeq;	/* Target sequence for each block. */
+    };
+
+struct xAli *xAliLoad(char **row);
+/* Load a xAli from row fetched with select * from xAli
+ * from database.  Dispose of this with xAliFree(). */
+
+struct xAli *xAliLoadAll(char *fileName);
+/* Load all xAli from a tab-separated file.
+ * Dispose of this with xAliFreeList(). */
+
+struct xAli *xAliCommaIn(char **pS, struct xAli *ret);
+/* Create a xAli out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new xAli */
+
+void xAliFree(struct xAli **pEl);
+/* Free a single dynamically allocated xAli such as created
+ * with xAliLoad(). */
+
+void xAliFreeList(struct xAli **pList);
+/* Free a list of dynamically allocated xAli's */
+
+void xAliOutput(struct xAli *el, FILE *f, char sep, char lastSep);
+/* Print out xAli.  Separate fields with sep. Follow last field with lastSep. */
+
+#define xAliTabOut(el,f) xAliOutput(el,f,'\t','\n');
+/* Print out xAli as a line in a tab-separated file. */
+
+#define xAliCommaOut(el,f) xAliOutput(el,f,',',',');
+/* Print out xAli as a comma separated list including final comma. */
+
+/* ----------------  Start human generated code. ------------------ */
+
+struct xAli *xAliNext(struct lineFile *lf);
+/* Read next line from file and convert it to xAli.  Return
+ * NULL at eof. */
+
+#endif /* XALI_H */
+
diff --git a/inc/xa.h b/inc/xa.h
new file mode 100644
index 0000000..0a8fe34
--- /dev/null
+++ b/inc/xa.h
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* xa.h - manage cross species alignments stored in database. */
+#ifndef XA_H
+#define XA_H
+
+struct xaAli
+/* This contains information about one xeno alignment. */
+    {
+    struct xaAli *next;
+    char *name;
+    char *query;
+    int qStart, qEnd;
+    char qStrand;
+    char *target;
+    int tStart, tEnd;
+    char tStrand;
+    int milliScore;
+    int symCount;
+    char *qSym, *tSym, *hSym;
+    };
+
+void xaAliFree(struct xaAli *xa);
+/* Free up a single xaAli. */
+
+void xaAliFreeList(struct xaAli **pXa);
+/* Free up a list of xaAlis. */
+
+int xaAliCmpTarget(const void *va, const void *vb);
+/* Compare two xaAli's to sort by ascending target positions. */
+
+FILE *xaOpenVerify(char *fileName);
+/* Open file, verify it's the right type, and
+ * position file pointer for first xaReadNext(). */
+
+FILE *xaIxOpenVerify(char *fileName);
+/* Open file, verify that it's a good xa index. */
+
+struct xaAli *xaReadNext(FILE *f, boolean condensed);
+/* Read next xaAli from file. If condensed
+ * don't fill int query, target, qSym, tSym, or hSym. */
+
+struct xaAli *xaReadRange(char *rangeIndexFileName, char *dataFileName, 
+    int start, int end, boolean condensed);
+/* Return list of all xaAlis that range from start to end.  If condensed
+ * don't fill int query, qSym, tSym, or hSym. */
+
+struct xaAli *xaRdRange(FILE *ix, FILE *data, 
+    int start, int end, boolean condensed);
+/* Like xaReadRange but pass in open files rather than file names. */
+
+char *xaAlignSuffix();
+/* Return suffix of file with actual alignments. */
+
+char *xaChromIxSuffix();
+/* Return suffix of files that index xa's by chromosome position. */
+
+
+#endif /* XA_H */
+
diff --git a/inc/xap.h b/inc/xap.h
new file mode 100644
index 0000000..7183240
--- /dev/null
+++ b/inc/xap.h
@@ -0,0 +1,78 @@
+/* xap - XML Automatic Parser - together with autoXml this helps automatically
+ * read in automatically generated data structures. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef XAP_H
+#define XAP_H
+
+#ifndef DYSTRING_H
+#include "dystring.h"
+#endif
+
+struct xapStack
+/* An element of parse stack. */
+   {
+   void *object;	/* Object being parsed. */
+   char *elName;	/* Name of tag. */
+   struct dyString *text;	/* The text section. */
+   };
+
+struct xap
+/* A parser with a stack built in and other conveniences. */
+   {
+   struct xapStack *stack;			/* Top of stack of open tags. */
+   struct xapStack stackBuf[128];		/* Stack buffer. */
+   struct xapStack *endStack;			/* End of stack. */
+   int stackDepth;				/* Number of elements in stack. */
+   int skipDepth;				/* Depth beneath which we skip. */
+   void *(*startHandler)(struct xap *xap, char *name, char **atts);	/* Handler for start tags. */
+   void (*endHandler)(struct xap *xap, char *name);	/* Handler for end tags. */
+   struct xp *xp;				        /* Pointer to lower level parser. */
+   char *fileName;				/* Name of file being parsed - valid after xapParse. */
+   char *topType;				/* Top level type name - valid after xapParse. */
+   void *topObject;				/* Top level object - valid after xapParse. */
+   FILE *f;					/* File. */
+   };
+
+struct xap *xapNew(void *(*startHandler)(struct xap *xap, char *name, char **atts),
+	void (*endHandler)(struct xap *xap, char *name) ,
+	char *fileName);
+/* Create a new parse stack.  FileName may be NULL. */
+
+void xapFree(struct xap **pXp);
+/* Free up a parse stack. */
+
+void xapParseFile(struct xap *xap, char *fileName);
+/* Open up file and parse it all. */
+
+void xapError(struct xap *xap, char *format, ...);
+/* Issue an error message and abort*/
+
+void xapIndent(int count, FILE *f);
+/* Write out some spaces. */
+
+void xapSkip(struct xap *xap);
+/* Skip current tag and any children.  Called from startHandler. */
+
+void xapParseAny(char *fileName, char *type, 
+	void *(*startHandler)(struct xap *xap, char *name, char **atts),
+	void (*endHandler)(struct xap *xap, char *name),
+	char **retType, void *retObj);
+/* Parse any object out of an XML file. 
+ * If type parameter is non-NULL, force type.
+ * example:
+ *     xapParseAny("file.xml", "das", dasStartHandler, dasEndHandler, &type, &obj); */
+
+struct xap *xapOpen(char *fileName, 
+	void *(*startHandler)(struct xap *xap, char *name, char **atts),
+	void (*endHandler)(struct xap *xap, char *name));
+/* Open up an xml file, but don't start parsing it yet.
+ * Instead call xapNext to get the elements you want out of
+ * the file.  When all done call xapFree. */
+
+void *xapNext(struct xap *xap, char *tag);
+/* Return next item matching tag (and all of it's children). */
+#endif /* XAP_H */
+
diff --git a/inc/xenalign.h b/inc/xenalign.h
new file mode 100644
index 0000000..21455b7
--- /dev/null
+++ b/inc/xenalign.h
@@ -0,0 +1,41 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* xenalign.h - Do cross-species DNA alignments from scratch. */
+#ifndef XENALIGN_H
+#define XENALIGN_H
+
+#ifndef NT4_H
+#include "nt4.h"
+#endif
+
+int xenAlignSmall(DNA *query, int querySize, DNA *target, int targetSize, 
+    FILE *f, boolean printExtraAtEnds);
+/* Use dynamic programming to do small scale 
+ * (querySize * targetSize < 10,000,000)
+ * alignment of DNA. Write results into f.*/
+
+void xenStitch(char *inName, FILE *out, int stitchMinScore, 
+    boolean compactOutput);
+/* Do the big old stitching run putting together contents of inName
+ * into contigs in out.  Create output in newer format. */
+
+void xenStitcher(char *inName, FILE *out, int stitchMinScore, boolean 
+    compactOutput);
+/* Do the big old stitching run putting together contents of inName
+ * into contigs in out. Create output in older format. */
+
+void xenAlignBig(DNA *query, int qSize, DNA *target, int tSize, FILE *f, boolean forHtml);
+/* Do a big alignment - one that has to be stitched together. 
+ * Write results into f. */
+
+void xenShowAli(char *qSym, char *tSym, char *hSym, int symCount, FILE *f,
+   int qOffset, int tOffset, char qStrand, char tStrand, int maxLineSize);
+/* Print alignment and HMM symbols maxLineSize bases at a time to file. */
+
+void xenAlignWorm(DNA *query, int qSize, FILE *f, boolean forHtml);
+/* Do alignment against worm genome. */
+
+#endif /* XENALIGN_H */
diff --git a/inc/xmlEscape.h b/inc/xmlEscape.h
new file mode 100644
index 0000000..f02a860
--- /dev/null
+++ b/inc/xmlEscape.h
@@ -0,0 +1,17 @@
+/* Handle escaping for XML files.  Deal with things like
+ * & and &quot. */
+
+#ifndef XMLESCAPE_H
+#define XMLESCAPE_H
+
+struct hash *xmlEscapeSymHash();
+/* Return hash of predefined xml character symbols to lookup. */
+
+void xmlEscapeBytesToFile(unsigned char *buffer, int len, FILE *f);
+/* Write buffer of given length to file, escaping as need be. */
+
+void xmlEscapeStringToFile(char *s, FILE *f);
+/* Write escaped zero-terminated string to file. */
+
+#endif /* XMLESCAPE_H */
+
diff --git a/inc/xp.h b/inc/xp.h
new file mode 100644
index 0000000..1439657
--- /dev/null
+++ b/inc/xp.h
@@ -0,0 +1,78 @@
+/* xp - A minimal non-verifying xml parser.  It's
+ * stream oriented much like expat.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#ifndef XP_H
+#define XP_H
+
+#ifndef DYSTRING_H
+#include "dystring.h"
+#endif
+
+struct xpStack
+/* A context stack for parser. */
+    {
+    struct dyString *tag;   /* Name of tag. */
+    struct dyString *text;  /* Contains text if any. */
+    };
+
+struct xp
+/* A minimal non-verifying xml parser. */
+    {
+    struct xp *next;	/* Next in list. */
+    struct xpStack *stack;		/* Current top of stack. */
+    struct xpStack stackBuf[64];	/* Stack buffer and start of stack. */
+    struct xpStack *stackBufEnd;	/* End of stack buffer. */
+    struct dyString *attDyBuf[128];	/* Attribute buffer as dynamic string. */
+    char *attBuf[128];    	        /* Attribute buffer as regular string. */
+    struct dyString *endTag;		/* Buffer for an end tag. */
+    void *userData;			/* Pointer to user's data structure. */
+    void (*atStartTag)(void *userData, char *name, char **atts);  /* Got start and attributes. */
+    void (*atEndTag)(void *userData, char *name, char *text);   /* Got end. */
+    int (*read)(void *userData, char *buf, int bufSize);   /* Read some more. */
+    char *fileName;			/* File name. */
+    int lineIx;				/* Number of current line. */
+    char inBuf[16*1024];		/* Text input buffer. */
+    char *inBufEnd;			/* Pointer to end of input buffer. */
+    char *in;				/* Next character to parse. */
+    struct hash *symHash;		/* Hash of > < etc. */
+    };
+
+struct xp *xpNew(void *userData, 
+   void (*atStartTag)(void *userData, char *name, char **atts),
+   void (*atEndTag)(void *userData, char *name, char *text),
+   int (*read)(void *userData, char *buf, int bufSize),
+   char *fileName);
+/* Form a new xp parser.  File name may be NULL - just used for
+ * error reporting. */
+
+void xpFree(struct xp **pXp);
+/* Free up an xp parser. */
+
+int xpLineIx(struct xp *xp);
+/* Return current line number. */
+
+char *xpFileName(struct xp *xp);
+/* Return current file name. */
+
+int xpReadFromFile(void *userData, char *buf, int bufSize);
+/* This is a function you can pass to xpNew as a read handler.
+ * It assumes you've passed an open FILE in as userData. */
+
+void xpError(struct xp *xp, char *format, ...);
+/* Output an error message with filename and line number included. */
+
+boolean xpParseNext(struct xp *xp, char *tag);
+/* Skip through file until get given tag.  Then parse out the
+ * tag and all of it's children (calling atStartTag/atEndTag).
+ * You can call this repeatedly to process all of a given tag
+ * in file. */
+
+void xpParse(struct xp *xp);
+/* Parse from start tag to end tag.  Throw error if a problem.
+ * Returns FALSE if nothing left to parse. */
+
+#endif /* XP_H */
+
diff --git a/inc/zlibFace.h b/inc/zlibFace.h
new file mode 100644
index 0000000..1b9d027
--- /dev/null
+++ b/inc/zlibFace.h
@@ -0,0 +1,26 @@
+/* Wrappers around zlib to make interfacing to it a bit easier. */
+
+#ifndef ZLIBFACE_H
+#define ZLIBFACE_H
+
+size_t zCompress(
+	void *uncompressed, 	/* Start of area to compress. */
+	size_t uncompressedSize,  /* Size of area to compress. */
+	void *compBuf,       /* Where to put compressed bits */
+	size_t compBufSize); /* Size of compressed bits - calculate using zCompBufSize */
+/* Compress data from memory to memory.  Returns size after compression. */
+
+size_t zCompBufSize(size_t uncompressedSize);
+/* Return size of buffer needed to compress something of given size uncompressed. */
+
+size_t zUncompress(
+        void *compressed,	/* Compressed area */
+	size_t compressedSize,	/* Size after compression */
+	void *uncompBuf,	/* Where to put uncompressed bits */
+	size_t uncompBufSize);	/* Max size of uncompressed bits. */
+/* Uncompress data from memory to memory.  Returns size after decompression. */
+
+void zSelfTest(int count);
+/* Run an internal diagnostic. */
+
+#endif /* ZLIBFACE_H */
diff --git a/jkOwnLib/README b/jkOwnLib/README
new file mode 100644
index 0000000..8b3819a
--- /dev/null
+++ b/jkOwnLib/README
@@ -0,0 +1,5 @@
+The modules in this library generally are supporting
+the BLAT or WABA programs.  These modules are all
+copyrighted Jim Kent. License hereby is granted for
+personal, academic and non-profit purposes.  Commercial
+use is permitted only by explicit agreement with Jim Kent.
diff --git a/jkOwnLib/bandExt.c b/jkOwnLib/bandExt.c
new file mode 100644
index 0000000..b9fd893
--- /dev/null
+++ b/jkOwnLib/bandExt.c
@@ -0,0 +1,489 @@
+/* bandExt - banded Smith-Waterman extension of alignments. 
+ * An aligner might first find perfectly matching hits of
+ * a small size, then extend these hits as far as possible
+ * while the sequences perfectly match, then call on routines
+ * in this module to do further extensions allowing small
+ * gaps and mismatches. 
+ *
+ * This version of the algorithm uses affine gap scorea and
+ * has the neat feature that the band can wander around.  
+ * When a score exceeds any previous score, the band will be 
+ * recentered around the highest scoring position. */
+/* Copyright 2003-5 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "dnaseq.h"
+#include "axt.h"
+#include "fuzzyFind.h"
+#include "localmem.h"
+#include "bandExt.h"
+
+
+/* Definitions for traceback byte.  This is encoded as so:
+ *     xxxxLUMM
+ * where the x's are not used.  The L bit is set if parent of the left insert
+ * is also a left insert (otherwise it is a match). Likewise the U bit is set
+ * if the parent of an up insert is also an up insert.  The MM bits contain the
+ * parent of the match state. */
+
+#define mpMatch 1
+#define mpUp 2
+#define mpLeft 3
+#define mpMask 3
+#define upExt (1<<2)
+#define lpExt (1<<3)
+
+struct score
+/* Info on score in our three states. */
+   {
+   int match;
+   int up;
+   int left;
+   };
+
+boolean bandExt(boolean global, struct axtScoreScheme *ss, int maxInsert,
+	char *aStart, int aSize, char *bStart, int bSize, int dir,
+	int symAlloc, int *retSymCount, char *retSymA, char *retSymB, 
+	int *retStartA, int *retStartB)
+/* Try to extend an alignment from aStart/bStart onwards.
+ * Set maxInsert to the maximum gap size allowed.  3 is often
+ * a good choice.  aStart/aSize bStart/bSize describe the
+ * sequence to extend through (not including any of the existing
+ * alignment. Set dir = 1 for forward extension, dir = -1 for backwards. 
+ * retSymA and retSymB should point to arrays of characters of
+ * symAlloc size.  symAlloc needs to be aSize*2 or so.  The
+ * alignment is returned in the various ret values.  The function
+ * overall returns TRUE if an extension occurred, FALSE if not. */
+{
+int i;			/* A humble index or two. */
+int *bOffsets = NULL;	/* Offset of top of band. */
+UBYTE **parents = NULL;	/* Array of parent positions. */
+struct score *curScores = NULL;	/* Scores for current column. */
+struct score *prevScores = NULL;	/* Scores for previous column. */
+struct score *swapScores;	/* Helps to swap cur & prev column. */
+int bandSize = 2*maxInsert + 1;	 /* Size of band including middle */
+int maxIns1 = maxInsert + 1;   	 /* Max insert plus one. */
+int bandPlus = bandSize + 2*maxIns1;  /* Band plus sentinels on either end. */
+int bestScore = 0;	 	 /* Best score so far. */
+int aPos, aBestPos = -1;	 /* Current and best position in a. */
+int bPos, bBestPos = -1;	 /* Current and best position in b. */
+int bandCenter = 0;	/* b Coordinate of current band center. */
+int colShift = 1;	/* Vertical shift between this column and previous. */
+int prevScoreOffset;	/* Offset into previous score column. */
+int curScoreOffset;	/* Offset into current score column. */
+int symCount = 0;	/* Size of alignment and size allocated for it. */
+int gapOpen = ss->gapOpen;	 /* First base in gap costs this. */
+int gapExtend = ss->gapExtend;	 /* Extra bases in gap cost this. */
+int badScore = -gapOpen*100;	 /* A score bad enough no one will want to link with us. */
+int maxDrop = gapOpen + gapExtend*maxInsert; /* Max score drop allowed before giving up. */
+int midScoreOff;		 /* Offset to middle of scoring array. */
+struct lm *lm;			 /* Local memory pool. */
+boolean didExt = FALSE;
+int initGapScore = -gapOpen;
+
+/* For reverse direction just reverse bytes here and there.  It's
+ * a lot easier than the alternative and doesn't cost much time in
+ * the global scheme of things. */
+if (dir < 0)
+    {
+    reverseBytes(aStart, aSize);
+    reverseBytes(bStart, bSize);
+    }
+#ifdef DEBUG
+uglyf("bandExt: dir %d, aStart %d, aSize %d, symAlloc %d\n", dir,
+	aSize, bSize, symAlloc);
+mustWrite(uglyOut, aStart, aSize);
+uglyf("\n");
+mustWrite(uglyOut, bStart, bSize);
+uglyf("\n");
+#endif /* DEBUG */
+
+/* Make up a local mem structure big enough for everything. 
+ * This is just a minor, perhaps misguided speed tweak to
+ * avoid multiple mallocs. */
+lm = lmInit(
+    sizeof(bOffsets[0])*aSize +
+    sizeof(parents[0])*bandSize +
+    bandSize*(sizeof(parents[0][0])*aSize) +
+    sizeof(curScores[0]) * bandPlus +
+    sizeof(prevScores[0]) * bandPlus );
+
+/* Allocate data structures out of local memory pool. */
+lmAllocArray(lm, bOffsets, aSize);
+lmAllocArray(lm, parents, bandSize);
+for (i=0; i<bandSize; ++i)
+    lmAllocArray(lm, parents[i], aSize);
+lmAllocArray(lm, curScores, bandPlus);
+lmAllocArray(lm, prevScores, bandPlus);
+
+/* Set up scoring arrays so that stuff outside of the band boundary 
+ * looks bad.  There will be maxIns+1 of these sentinel values at
+ * the start and at the beginning. */
+for (i=0; i<bandPlus; ++i)
+    {
+    struct score *cs = &curScores[i];
+    cs->match = cs->up = cs->left = badScore;
+    cs = &prevScores[i];
+    cs->match = cs->up = cs->left = badScore;
+    }
+
+/* Set up scoring array so that extending without an initial insert
+ * looks relatively good. */
+midScoreOff = 1 + 2 * maxInsert;
+prevScores[midScoreOff].match = 0;
+
+/* Set up scoring array so that initial inserts of up to maxInsert
+ * are allowed but penalized appropriately. */
+    {
+    int score = -gapOpen;
+    for (i=0; i<maxInsert; ++i)
+	{
+	prevScores[midScoreOff+i].up = score;
+	score -= gapExtend;
+	}
+    }
+
+for (aPos=0; aPos < aSize; ++aPos)
+    {
+    char aBase = aStart[aPos];
+    int *matRow = ss->matrix[(int)aBase];
+    int bestColScore = badScore;
+    int bestColPos = -1;
+    int colTop = bandCenter - maxInsert;
+    int colBottom = bandCenter + maxIns1;
+
+    if (colTop < 0) colTop = 0;
+    if (colBottom > bSize) colBottom = bSize;
+    curScoreOffset =  maxIns1 + colTop - (bandCenter - maxInsert);
+    prevScoreOffset = curScoreOffset + colShift;
+#ifdef DEBUG
+    uglyf("curScoreOffset %d, maxIns %d, prevScoreOffset %d\n", curScoreOffset, maxInsert, prevScoreOffset);
+#endif /* DEBUG */
+
+    /* At top we deal with possibility of initial insert that
+     * comes in at this point, unless the band has wandered off. */
+    if (aPos < maxInsert)
+	{
+	curScores[curScoreOffset-1].up = initGapScore;
+	initGapScore -= gapExtend;
+	}
+    else
+	curScores[curScoreOffset-1].up = badScore;
+
+    for (bPos = colTop; bPos < colBottom; ++bPos)
+	{
+	UBYTE parent;
+	struct score *curScore = &curScores[curScoreOffset];
+
+#ifdef DEBUG
+	uglyf("aPos %d, bPos %d, %c vs %c\n", aPos, bPos, aBase, bStart[bPos]);
+	uglyf("  diag[%d %d %d], left[%d %d %d], up[%d %d %d]\n", 
+		prevScores[prevScoreOffset-1].match, 
+		prevScores[prevScoreOffset-1].left, 
+		prevScores[prevScoreOffset-1].up, 
+		prevScores[prevScoreOffset].match, 
+		prevScores[prevScoreOffset].left, 
+		prevScores[prevScoreOffset].up, 
+		curScores[curScoreOffset-1].match, 
+		curScores[curScoreOffset-1].left, 
+		curScores[curScoreOffset-1].up);
+#endif /* DEBUG */
+
+	/* Handle ways into the matching state and record if it's
+	 * best score so far. */
+	    {
+	    int match = matRow[(int)bStart[bPos]];
+	    struct score *a = &prevScores[prevScoreOffset-1];
+	    int diagScore = a->match;
+	    int leftScore = a->left;
+	    int upScore = a->up;
+	    int score;
+	    if (diagScore >= leftScore && diagScore >= upScore)
+	        {
+		score = diagScore + match;
+		parent = mpMatch;
+		}
+	    else if (leftScore > upScore)
+	        {
+		score = leftScore + match;
+	        parent = mpLeft;
+		}
+	    else
+	        {
+	        score = upScore + match;
+	        parent = mpUp;
+	        }
+	    curScore->match = score;
+	    if (score > bestColScore)
+	        {
+		bestColScore = score;
+		bestColPos = bPos;
+		}
+	    }
+
+	/* Handle ways into left gap state. */
+	    {
+	    struct score *a = &prevScores[prevScoreOffset];
+	    int extScore = a->left - gapExtend;
+	    int openScore = a->match - gapOpen;
+	    if (extScore >= openScore)
+	        {
+		parent |= lpExt;
+		curScore->left = extScore;
+		}
+	    else
+	        {
+		curScore->left = openScore;
+		}
+	    }
+
+	/* Handle ways into up gap state. */
+	    {
+	    struct score *a = &curScore[-1];
+	    int extScore = a->up - gapExtend;
+	    int openScore = a->match - gapOpen;
+	    if (extScore >= openScore)
+	        {
+		parent |= upExt;
+		curScore->up = extScore;
+		}
+	    else
+	        {
+		curScore->up = openScore;
+		}
+	    }
+
+	parents[curScoreOffset - maxIns1][aPos] = parent;
+
+#ifdef DEBUG
+	uglyf(" cur [%d %d %d]\n", 
+		curScore->match, 
+		curScore->left, 
+		curScore->up);
+#endif /* DEBUG */
+	/* Advance to next row in column. */
+	curScoreOffset += 1;
+	prevScoreOffset += 1;
+	}
+
+
+    /* If this column's score is best so far make note of
+     * it and shift things so that the matching bases at the
+     * best score are centered in the band.  This allows the
+     * band to wander where appropriate.  Having the band shift
+     * to the best column position if it is not the best score
+     * so far doesn't work so well though.  */
+    if (bestScore < bestColScore)
+	{
+	bestScore = bestColScore;
+	aBestPos = aPos;
+	bBestPos = bestColPos;
+	colShift = (bestColPos + 1) - bandCenter;
+	}
+    else if (bestColScore < bestScore - maxDrop)
+	{
+	if (!global)
+	    break;
+	}
+    else
+	{
+	colShift = 1;
+	}
+
+    /* Keep track of vertical offset of this column, and
+     * set up offset of next column. */
+    bOffsets[aPos] = bandCenter;
+    bandCenter += colShift;
+
+    /* Swap scoring arrays so current becomes next iteration's previous. */
+    swapScores = curScores;
+    curScores = prevScores;
+    prevScores = swapScores;
+    }
+
+
+/* Trace back. */
+#ifdef DEBUG
+uglyf("traceback: bestScore %d, aBestPos %d, bBestPos %d\n", bestScore, aBestPos, bBestPos);
+#endif /* DEBUG */
+if (global || bestScore > 0)
+    {
+    boolean upState = FALSE;
+    boolean leftState = FALSE;
+    didExt = TRUE;
+    if (global)
+        {
+	aPos = aSize-1;
+	bPos = bSize-1;
+	}
+    else
+	{
+	aPos = aBestPos;
+	bPos = bBestPos;
+	}
+    for (;;)
+	{
+	int pOffset;
+	UBYTE parent;
+	pOffset = bPos - bOffsets[aPos] + maxInsert;
+	if (pOffset < 0) pOffset = 0;
+	// FIXME: there may be some cases near beginning where
+	// pOffset is not right.  Clamping it at 0 prevents a crash
+	// and produces correct behavior in many cases.  However
+	// I'm thinking a better fix would be to have bOffsets follow
+	// colTop rather than bandCenter somehow. Exactly how is
+	// beyond me at the moment.
+	if (pOffset >= bandSize)
+	    {
+#ifdef DEBUG
+	    uglyf("bPos %d, aPos %d, bOffsets[aPos] %d, maxInsert %d\n", bPos, aPos, bOffsets[aPos], maxInsert);
+	    uglyf("pOffset = %d, bandSize = %d\n", pOffset, bandSize);
+	    uglyf("aSize %d, bSize %d\n", aSize, bSize);
+	    faWriteNext(uglyOut, "uglyA", aStart, aSize);
+	    faWriteNext(uglyOut, "uglyB", bStart, bSize);
+#endif /* DEBUG */
+	    assert(global);
+	    return FALSE;
+	    }
+	parent = parents[pOffset][aPos];
+#ifdef DEBUG
+	uglyf("aPos %d, bPos %d, parent %d, pMask %d upState %d, leftState %d\n", aPos, bPos, parent, parent & mpMask, upState, leftState);
+#endif /* DEBUG */
+	if (upState)
+	    {
+	    retSymA[symCount] = '-';
+	    retSymB[symCount] = bStart[bPos];
+	    bPos -= 1;
+	    upState = (parent&upExt);
+	    }
+	else if (leftState)
+	    {
+	    retSymA[symCount] = aStart[aPos];
+	    retSymB[symCount] = '-';
+	    aPos -= 1;
+	    leftState = (parent&lpExt);
+	    }
+	else
+	    {
+	    retSymA[symCount] = aStart[aPos];
+	    retSymB[symCount] = bStart[bPos];
+	    aPos -= 1;
+	    bPos -= 1;
+	    parent &= mpMask;
+	    if (parent == mpUp)
+	        upState = TRUE;
+	    else if (parent == mpLeft)
+	        leftState = TRUE;
+	    }
+	if (++symCount >= symAlloc)
+	    errAbort("unsufficient symAlloc in bandExt");
+	if (aPos < 0 || bPos < 0)
+	    {
+	    while (aPos >= 0)
+		{
+		retSymA[symCount] = aStart[aPos];
+		retSymB[symCount] = '-';
+		if (++symCount >= symAlloc)
+		    errAbort("unsufficient symAlloc in bandExt");
+		--aPos;
+		}
+	    while (bPos >= 0)
+		{
+		retSymA[symCount] = '-';
+		retSymB[symCount] = bStart[bPos];
+		if (++symCount >= symAlloc)
+		    errAbort("unsufficient symAlloc in bandExt");
+		--bPos;
+		}
+	    break;
+	    }
+	}
+    if (dir > 0)
+	{
+	reverseBytes(retSymA, symCount);
+	reverseBytes(retSymB, symCount);
+	}
+    retSymA[symCount] = 0;
+    retSymB[symCount] = 0;
+    }
+else
+    {
+    retSymA[0] = retSymB[0] = 0;
+    }
+
+if (dir < 0)
+    {
+    reverseBytes(aStart, aSize);
+    reverseBytes(bStart, bSize);
+    }
+
+/* Clean up, set return values and go home */
+lmCleanup(&lm);
+if (retStartA != NULL) *retStartA = aBestPos;
+if (retStartB != NULL) *retStartB = bBestPos;
+*retSymCount = symCount;
+return didExt;
+}
+
+struct ffAli *bandExtFf(
+	struct lm *lm,	/* Local memory pool, NULL to use global allocation for ff */
+	struct axtScoreScheme *ss, 	/* Scoring scheme to use. */
+	int maxInsert,			/* Maximum number of inserts to allow. */
+	struct ffAli *origFf,		/* Alignment block to extend. */
+	char *nStart, char *nEnd,	/* Bounds of region to extend through */
+	char *hStart, char *hEnd,	/* Bounds of region to extend through */
+	int dir,			/* +1 to extend end, -1 to extend start */
+	int maxExt)			/* Maximum length of extension. */
+/* Extend a gapless alignment in one direction.  Returns extending
+ * ffAlis, not linked into origFf, or NULL if no extension possible. */
+{
+int symAlloc = 2*maxExt;
+char *symBuf = needMem(4*maxExt);
+char *nBuf = symBuf;
+char *hBuf = symBuf + symAlloc;
+char *ns, *hs;
+int symCount, nExt, hExt;
+int nSize, hSize;
+struct ffAli *ffList = NULL;
+boolean gotExt;
+
+if (dir > 0)
+    {
+    nSize = nEnd - origFf->nEnd;
+    hSize = hEnd - origFf->hEnd;
+    if (nSize > maxExt) nSize = maxExt;
+    if (hSize > maxExt) hSize = maxExt;
+    ns = origFf->nEnd;
+    hs = origFf->hEnd;
+    }
+else
+    {
+    nSize = origFf->nStart - nStart;
+    hSize = origFf->hStart - hStart;
+    if (nSize > maxExt) nSize = maxExt;
+    if (hSize > maxExt) hSize = maxExt;
+    ns = origFf->nStart - nSize;
+    hs = origFf->hStart - hSize;
+    }
+
+gotExt = bandExt(FALSE, ss, maxInsert, ns, nSize, hs, hSize, dir,
+	symAlloc, &symCount, nBuf, hBuf, &nExt, &hExt);
+if (gotExt)
+    {
+    char *nExtStart, *hExtStart;
+    if (dir > 0)
+	{
+	nExtStart = ns;
+	hExtStart = hs;
+	}
+    else
+	{
+	nExtStart = origFf->nStart - nExt - 1;
+	hExtStart = origFf->hStart - hExt - 1;
+	}
+    ffList = ffAliFromSym(symCount, nBuf, hBuf, lm,  nExtStart, hExtStart);
+    }
+freeMem(symBuf);
+return ffList;
+}
+
diff --git a/jkOwnLib/crudeali.c b/jkOwnLib/crudeali.c
new file mode 100644
index 0000000..67d06f2
--- /dev/null
+++ b/jkOwnLib/crudeali.c
@@ -0,0 +1,877 @@
+/* crudeali.c - Files for doing fast blast-style crude alignment. 
+ * This has two modes - a 16-base at a time and a 6 base at a time
+ * which basically is for cDNA alignments and genomic/genomic 
+ * alignments. The six base at a time doesn't use six contigious
+ * bases, but rather 8 bases in a row with the two in "wobble
+ * positions" masked out.  It ends up making things more
+ * sensitive, and, fortunately, the whole thing still fits in
+ * a single 16 bit word. */
+/* Copyright 2000-2003 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "dnautil.h"
+#include "nt4.h"
+#include "dnaseq.h"
+#include "crudeali.h"
+
+
+#define maxTileSize 16
+
+#define wobbleMask 0xF3CF
+
+static int caTileSize = 16;
+static boolean caIsCdna = TRUE;
+
+struct crudeHit
+/* A tileSize exact match between probe and target. */
+    {
+    int probeOffset;
+    int targetOffset;
+    boolean isLumped;
+    };
+
+
+struct crudeExon
+/* A bunch of hits that hang together on a diagonal. */
+    {
+    int probeStart;
+    int probeEnd;
+    int targetStart;
+    int targetEnd;
+    int hitCount;
+    boolean isLumped;
+    };
+
+struct crudeGene
+/* A collection of diagonals that seem to hang together
+ * like exons. */
+    {
+    struct nt4Seq *target;
+    boolean isRc;
+    int probeStart;
+    int probeEnd;
+    int targetStart;
+    int targetEnd;
+    int score;
+    };
+
+static int lumpHitsIntoExons(struct crudeHit *hits, int hitCount, struct crudeExon *exons)
+/* Lump together hits that are within 48 bp of each other and within 2 of
+ * the same diagonal into "exons".  The exons array must be hitCount elements
+ * in order to accomodate the worst case where no lumping occurs.  */
+{
+int i;
+struct crudeExon *exon = exons;
+int exonCount = 0;
+int firstNonLumped = 0;
+
+for (i=0; i<hitCount; ++i)
+    hits[i].isLumped = FALSE;
+
+for (;;)
+    {
+    boolean startedExon = FALSE;
+    int diagDiff = 0;
+    int tOff, pOff;
+    int thisDiff;
+    for (; firstNonLumped < hitCount; ++firstNonLumped)
+        {
+        if (!hits[firstNonLumped].isLumped)
+            break;
+        }
+    for (i=firstNonLumped; i<hitCount; ++i)
+        {
+        if (hits[i].isLumped == FALSE)
+            {
+            pOff = hits[i].probeOffset;
+            tOff = hits[i].targetOffset;
+            thisDiff = pOff - tOff;
+            if (!startedExon)   /* First hit in exon. */
+                {
+                startedExon = TRUE;
+                hits[i].isLumped = TRUE;
+                exon->probeStart = pOff;
+                exon->probeEnd = pOff + caTileSize;
+                exon->targetStart = tOff;
+                exon->targetEnd = tOff + caTileSize;
+                exon->hitCount = 1;
+                diagDiff = thisDiff;
+                }
+            else if (diagDiff - 2 <= thisDiff && thisDiff <= diagDiff + 2
+                    && exon->probeEnd - 2 <= pOff && pOff <= exon->probeEnd + 48
+                    && exon->targetEnd - 2 <= tOff && tOff <= exon->targetEnd + 48)
+                {
+                hits[i].isLumped = TRUE;
+                exon->probeEnd = pOff + caTileSize;
+                exon->targetEnd = tOff + caTileSize;
+                exon->hitCount += 1;
+                }
+            else if (tOff > exon->targetEnd + 48)
+                break;
+            }
+        }
+    if (!startedExon)   /* Must be all lumped together. */
+        break;
+    ++exonCount;
+    ++exon;
+    }
+
+/* If small tile size then get rid of exons with only one hit. */
+if (caTileSize == 8)
+    {
+    struct crudeExon *read = exons, *write = exons;
+    int twoFerCount = 0;
+    for (i=0; i<exonCount; ++i)
+        {
+        if (read->hitCount >= 2)
+            {
+            *write++ = *read++;
+            ++twoFerCount;
+            }
+        else
+            ++read;
+        }
+    exonCount = twoFerCount;
+    }
+return exonCount;
+}
+
+static int lumpExonsIntoGenes(struct crudeExon *exons, int exonCount, 
+    struct crudeGene *genes, struct nt4Seq *target, boolean isRc)
+/* Lump together crude exons into crude genes, and score them. */
+{
+int i;
+struct crudeGene *gene = genes;
+int geneCount = 0;
+int firstNonLumped = 0;
+int targetGapSpan = (caIsCdna ? 25000 : 200);
+int probeGapSpan = (caIsCdna ? 64 : 200);
+
+for (i=0; i<exonCount; ++i)
+    exons[i].isLumped = FALSE;
+
+for (;;)
+    {
+    boolean startedGene = FALSE;
+    int lastDiff = 0;
+    int tOff, pOff;
+    int thisDiff;
+    int exonsInThis = 0;
+
+    for ( ; firstNonLumped < exonCount; ++firstNonLumped)
+        {
+        if (!exons[firstNonLumped].isLumped)
+            break;
+        }
+    for (i=firstNonLumped; i<exonCount; ++i)
+        {
+        if (!exons[i].isLumped)
+            {
+            tOff = exons[i].targetStart;
+            pOff = exons[i].probeStart;
+            thisDiff = tOff - pOff;
+            if (!startedGene)
+                {
+                startedGene = TRUE;
+                exons[i].isLumped = TRUE;
+                lastDiff = thisDiff;
+                exonsInThis = 1;
+                gene->target = target;
+                gene->isRc = isRc;
+                gene->probeStart = exons[i].probeStart;
+                gene->probeEnd = exons[i].probeEnd;
+                gene->targetStart = exons[i].targetStart;
+                gene->targetEnd = exons[i].targetEnd;
+                gene->score = exons[i].hitCount * exons[i].hitCount;
+                }
+            else if (gene->targetEnd - 10 <= tOff && tOff <= gene->targetEnd + targetGapSpan
+                     && gene->probeEnd - 10 <= pOff && pOff <= gene->probeEnd + probeGapSpan
+                     && lastDiff - 2 <= thisDiff)
+                {
+                exons[i].isLumped = TRUE;
+                gene->targetEnd = exons[i].targetEnd;
+                gene->probeEnd = exons[i].probeEnd;
+                gene->score += exons[i].hitCount * exons[i].hitCount;
+                exonsInThis += 1;
+                lastDiff = thisDiff;
+                }
+            else if (tOff > gene->targetEnd + targetGapSpan)
+                break;
+            }
+        }
+    if (!startedGene)
+        break;
+    gene->score += exonsInThis;
+    ++geneCount;
+    ++gene;
+    }
+return geneCount;
+}
+
+static int copyExonsIntoGenes(struct crudeExon *exons, int exonCount, 
+    struct crudeGene *genes, struct nt4Seq *target, boolean isRc)
+/* Make crude genes that are just one per exon.  What a kludge! */
+{
+int i;
+for (i=0; i<exonCount; ++i)
+    {
+    genes[i].target = target;
+    genes[i].isRc = isRc;
+    genes[i].probeStart = exons[i].probeStart;
+    genes[i].probeEnd = exons[i].probeEnd;
+    genes[i].targetStart = exons[i].targetStart;
+    genes[i].targetEnd = exons[i].targetEnd;
+    genes[i].score = exons[i].hitCount * exons[i].hitCount;
+    }
+return exonCount;
+}
+
+static boolean makeGoodTile(DNA *dna, bits32 *retTile16, bits16 *retTile8, int tileSize)
+/* Turn next base pairs into a tile.  Return FALSE
+ * if it wouldn't be a good tile. */
+{
+int i;
+int repMod;
+int endRep;
+int maxRep = (tileSize / 2);
+
+/* Make sure no N's in tile */
+for (i=0; i<tileSize; ++i)
+    {
+    if (ntVal[(int)dna[i]] < 0)
+        return FALSE;
+    }
+
+/* Make sure that tile isn't part of a pattern. */ 
+for (repMod = 1; repMod <= maxRep; repMod += 1)
+    {
+    boolean allSame = TRUE;
+    endRep = tileSize - repMod;
+    for (i=0; i<endRep; ++i)
+        {
+        if (dna[i] != dna[i+repMod])
+            {
+            allSame = FALSE;
+            break;
+            }
+        }
+    if (allSame)
+        return FALSE;
+    }
+
+if (tileSize > 8)
+    *retTile16 = packDna16(dna);
+else
+    *retTile8 = packDna8(dna);
+
+return TRUE;
+}
+
+struct probeTile
+/* A tile from the probe and the offset where it came from. */
+    {
+    struct probeTile *next;
+    int offset;
+    bits32 tile16;
+    bits16 tile8;
+    };
+
+#define tileHashBits 16
+#define tileHashSize (1<<tileHashBits)
+#define tileHashMask (tileHashSize-1)
+#define tileHashFunc(tile) ((tile)&tileHashMask)
+
+static struct probeTile **makeTileHash()
+{
+struct probeTile **table;
+int tableSize = tileHashSize * sizeof(table[0]);
+
+table = needLargeMem(tableSize);
+memset(table, 0, tableSize);
+return table;
+}
+
+
+struct fastProber
+/* Structure that has hash list of probeSeq tiles for fast searching */
+    {
+    struct probeTile **hash;
+    struct probeTile *probes;
+    int probeSize;
+    };
+
+static struct fastProber *makeFastProber(DNA *probeDna, int probeSize)
+{
+int maxProbeCount = probeSize - caTileSize + 1;
+int probeCount = 0;
+struct probeTile *probes;
+struct probeTile *probe;
+struct probeTile **hash;
+int i;
+struct fastProber *fp;
+
+if (maxProbeCount <= 0)
+    return NULL;
+AllocVar(fp);
+fp->hash = hash = makeTileHash();
+fp->probeSize = probeSize;
+fp->probes = probes = needMem(maxProbeCount * sizeof(probes[0]) );
+for (i=0; i<maxProbeCount; ++i)
+    {
+    probe = &probes[probeCount];
+    if (makeGoodTile(probeDna+i, &probe->tile16, &probe->tile8, caTileSize))
+        {
+        int hashIx; 
+        probe->tile8 &= wobbleMask;
+        hashIx = (caTileSize > 8 ? tileHashFunc(probe->tile16) : tileHashFunc(probe->tile8));
+        probe->offset = i;
+        probe->next = hash[hashIx];
+        hash[hashIx] = probe;
+        ++probeCount;
+        }
+    }
+return fp;
+}
+
+static void freeFastProber(struct fastProber **pFp)
+{
+struct fastProber *fp = *pFp;
+if (fp != NULL)
+    {
+    freeMem(fp->probes);
+    freeMem(fp->hash);
+    freez(pFp);
+    }
+}
+
+static int makeIndividualHits16(struct probeTile **hash, bits32 *bases, int baseOffset, int baseWordCount,
+    struct crudeHit *hits, int maxHitCount, int hitCount)
+/* Scan a short segment for individual hits. */
+{
+struct probeTile *probe;
+int i;
+for (i=0; i<baseWordCount; ++i)
+    {
+    if ((probe = hash[tileHashFunc(bases[i])]) != NULL)
+        {
+        do
+            {
+            if (bases[i] == probe->tile16)
+                {
+                if (hitCount >= maxHitCount)
+                    {
+                    warn("Too many hits, only taking first %d", maxHitCount);
+                    goto END_HIT_LOOP;
+                    }
+                hits[hitCount].probeOffset = probe->offset;
+                hits[hitCount].targetOffset = ((i+baseOffset) * caTileSize);
+                ++hitCount;
+                break;
+                }
+            probe = probe->next;
+            }
+        while (probe != NULL);
+        }
+    }
+END_HIT_LOOP:
+return hitCount;
+}
+
+static int makeHits16(struct fastProber *fp, struct nt4Seq *target, struct crudeHit *hits,
+    int maxHitCount)
+/* Scan entire target for hits to probe. */
+{
+bits32 *bases = target->bases;
+struct probeTile **hash = fp->hash;
+unsigned long acc;
+int hitCount = 0;
+int i;
+int baseWordCount = (target->baseCount/caTileSize);
+bits32 *endBases = bases + baseWordCount;
+int chunkSize = 8;
+int chunkCount = baseWordCount/chunkSize;
+int baseOffset = 0;
+
+for (i=0; i<chunkCount; ++i)
+    {
+    acc = ((unsigned long)(hash[tileHashFunc(bases[0])])
+        |  (unsigned long)(hash[tileHashFunc(bases[1])])
+        |  (unsigned long)(hash[tileHashFunc(bases[2])])
+        |  (unsigned long)(hash[tileHashFunc(bases[3])])
+        |  (unsigned long)(hash[tileHashFunc(bases[4])])
+        |  (unsigned long)(hash[tileHashFunc(bases[5])])
+        |  (unsigned long)(hash[tileHashFunc(bases[6])])
+        |  (unsigned long)(hash[tileHashFunc(bases[7])]));
+    if (acc)
+        {
+        hitCount = makeIndividualHits16(hash, bases, baseOffset, chunkSize, hits, maxHitCount, hitCount);
+        if (hitCount >= maxHitCount)
+            break;
+        }
+    bases += chunkSize;
+    baseOffset += chunkSize;
+    }
+if (bases != endBases)
+    hitCount = makeIndividualHits16(hash, bases, baseOffset, endBases-bases, hits, maxHitCount, hitCount);
+return hitCount;
+}
+
+void squeezeHits8(struct fastProber *fp, 
+    short *compactDiagBuf, int compactDiagBufByteSize, 
+    int startToff, int lastCompactOff, int lastCompareOff,
+    struct crudeHit *hits, int lastCompactedHit, int hitCount,
+    int *retLastCompactedHit, int *retHitCount)
+/* Get rid of isolated hits by dumping ones where there is only one
+ * hit on their diagonal. */
+{
+int diagOffset = fp->probeSize+2;
+int diag;
+int i;
+struct crudeHit *hit, *writeHit;
+int compactDiagBufArraySize = compactDiagBufByteSize/sizeof(short);
+
+memset(compactDiagBuf, 0, compactDiagBufByteSize);
+for (i=lastCompactedHit; i<hitCount; ++i)
+    {
+    hit = hits+i;
+    diag = (hit->targetOffset - startToff) - hit->probeOffset + diagOffset;
+    assert(diag >= 0 && diag < compactDiagBufArraySize);
+    compactDiagBuf[diag] += 1;
+    }
+writeHit = hits+lastCompactedHit;
+for (i=lastCompactedHit; i<hitCount; ++i)
+    {
+    hit = hits+i;
+    if (hit->targetOffset >= lastCompactOff)
+        break;
+    diag = (hit->targetOffset - startToff) - hit->probeOffset + diagOffset;
+    if (compactDiagBuf[diag] > 1)
+        *writeHit++ = *hit;
+    }    
+*retLastCompactedHit = (writeHit - hits);
+for (;i<hitCount; ++i)
+    {
+    hit = hits+i;
+    *writeHit++ = *hit;
+    }
+*retHitCount = (writeHit - hits);
+}
+
+
+static int makeHits8(struct fastProber *fp, struct nt4Seq *target, struct crudeHit *hits,
+    int maxHitCount)
+/* Scan entire target for hits to probe. */
+{
+bits16 *bases = (bits16*)target->bases;
+struct probeTile **hash = fp->hash;
+struct probeTile *pbt;
+int hitCount = 0;
+int i;
+int baseWordCount = (target->baseCount/caTileSize);
+int tOffset = 0;
+
+/* Handle big/little endian problem. */
+bits32 endianTest = 0x12345678;
+bits16 *endianPt = (bits16*)(void*)(&endianTest);
+boolean needSwap = (*endianPt == 0x5678);
+int swapOffset[2];
+int swapIx = 0;
+
+/* Every so often we throw out singleton hits. The variables below
+ * manage this. */
+int compactWindowSizePower = 10;
+int compactWindowSize = (1<<compactWindowSizePower);
+int compactModMask = compactWindowSize-1;
+int compactOverlap = 50;
+int lastCompactedHit = 0;
+int compactBufIntSize = (compactWindowSize+compactOverlap+fp->probeSize+4);
+int compactBufSize = (compactBufIntSize*sizeof(short));
+short *compactDiagBuf = needLargeMem(compactBufSize);
+
+if (needSwap)
+    {
+    swapOffset[0] = 8;
+    swapOffset[1] = -8;
+    }
+else
+    {
+    swapOffset[0] = swapOffset[1] = 0;
+    }
+
+assert(tileHashBits == (8*sizeof(bits16)));
+for (i=0; i<baseWordCount; ++i)
+    {
+    if ((pbt = hash[*bases++ & wobbleMask]) != NULL)
+        {
+        if (hitCount < maxHitCount)
+            {
+            hits[hitCount].probeOffset = pbt->offset;
+            hits[hitCount].targetOffset = tOffset + swapOffset[swapIx];
+            ++hitCount;
+            }
+        else
+            {
+            warn("Got too many hits, only keeping first %d\n", hitCount);
+            break;
+            }
+        }
+    tOffset += caTileSize;
+    if ((tOffset&compactModMask) == 0)
+        {
+        int startToff = tOffset - compactWindowSize - compactOverlap;
+        int lastCompactOff = startToff + compactWindowSize;
+        int lastCompareOff = tOffset;
+
+        squeezeHits8(fp, compactDiagBuf, compactBufSize, 
+            startToff,  lastCompactOff, lastCompareOff, 
+            hits, lastCompactedHit, hitCount, &lastCompactedHit, &hitCount);
+        }
+    swapIx = 1 - swapIx;  /* Toggle between 0 and 1. */
+    }
+freeMem(compactDiagBuf);
+return hitCount;
+}
+
+static int cmpHitsTargetFirst(const void *va, const void *vb)
+/* Compare function to sort hit array by ascending
+ * target offset followed by ascending probe offset. */
+{
+struct crudeHit *a = (struct crudeHit *)va;
+struct crudeHit *b = (struct crudeHit *)vb;
+long diff;
+if ((diff = a->targetOffset - b->targetOffset) != 0)
+    return diff;
+return a->probeOffset - b->probeOffset;
+}
+
+static int cmpExonsTargetFirst(const void *va, const void *vb)
+/* Compare function to sort exons by ascending target
+ * offset followed by ascending probe offset. */
+{
+struct crudeExon *a = (struct crudeExon *)va;
+struct crudeExon *b = (struct crudeExon *)vb;
+long diff;
+if ((diff = a->targetStart - b->targetStart) != 0)
+    return diff;
+return a->probeStart - b->probeStart;
+}
+
+
+#define maxHitsAtOnce 120000
+/* Maximum number of hits to allow on a single scan.
+ * If we get more than this need to toss out a bad tile
+ * or something... */
+
+static int makeHits(struct fastProber *fp, struct nt4Seq *target, struct crudeHit *hits,
+    int maxHitCount)
+/* Scan entire target for hits to probe. */
+{
+if (caTileSize == 8)
+    return makeHits8(fp, target, hits, maxHitCount);
+else if (caTileSize == 16)
+    return makeHits16(fp, target, hits, maxHitCount);
+else
+    {
+    errAbort("Can only do tile sizes of 8 or 16 in makeHits");
+    return 0;
+    }
+}
+
+static int findCrudeGenes(struct fastProber *fp, struct nt4Seq *target,
+    struct crudeGene *genes, int maxGeneCount, boolean isRc)
+/* Scan target with probe, and arrange hits into crude genes. */
+{
+struct crudeHit *hits;
+struct crudeExon *exons;
+int hitCount, exonCount, geneCount = 0;
+
+if (fp == NULL)
+    return 0;
+assert(maxGeneCount >= maxHitsAtOnce);
+hits = needMem(maxHitsAtOnce*sizeof(*hits));
+exons = needMem(maxHitsAtOnce*sizeof(*exons));
+hitCount = makeHits(fp, target, hits, maxHitsAtOnce);
+
+if (hitCount > 0)
+    {
+    qsort(hits, hitCount, sizeof(hits[0]), cmpHitsTargetFirst);
+    exonCount = lumpHitsIntoExons(hits, hitCount, exons);
+    qsort(exons, exonCount, sizeof(exons[0]), cmpExonsTargetFirst);
+    if (caIsCdna)
+        geneCount = lumpExonsIntoGenes(exons, exonCount, genes, target, isRc);
+    else
+        geneCount = copyExonsIntoGenes(exons, exonCount, genes, target, isRc);
+    }
+freeMem(hits);
+freeMem(exons);
+return geneCount;
+}
+
+static int cmpGenesByScore(const void *va, const void *vb)
+/* cmp function to sort leaving highest scores first. */
+{
+struct crudeGene *a = (struct crudeGene *)va;
+struct crudeGene *b = (struct crudeGene *)vb;
+return b->score - a->score;
+}
+
+static int countGenesBetter(struct crudeGene *genes, int geneCount, int cutoff)
+/* Count number of genes (in sorted list) with scores better than cutoff */
+{
+int i;
+for (i=0; i<geneCount; ++i)
+    {
+    if (genes[i].score <= cutoff)
+        break;
+    }
+return i;
+}
+
+static int filterPoorGenes(struct crudeGene *genes, int geneCount)
+/* Sort gene list by score and remove bottom scorers. 
+ * This is gauranteed to get rid of half of genes on list or 
+ * more. */
+{
+int bestScore, worstScore;
+int newGeneCount;
+int halfGeneCount = geneCount/2;
+
+qsort(genes, geneCount, sizeof(genes[0]), cmpGenesByScore);
+bestScore = genes[0].score;
+worstScore = genes[geneCount-1].score;
+
+/* If scores are clustered with half or more at the top,
+ * we have to be crude and just lop off bottom half of scores. */
+if (bestScore == genes[halfGeneCount].score)
+    {
+    warn("Bunches of genes, all scoring the same. Program is "
+         "throwing out half out of necessity.\n");
+    return geneCount/2;
+    }
+
+/* Drop bottom score until have gotten rid of at least half. */
+newGeneCount = geneCount;
+while (newGeneCount > halfGeneCount)
+    {
+    worstScore = genes[newGeneCount-1].score;
+    newGeneCount = countGenesBetter(genes, newGeneCount, worstScore);
+    }
+return newGeneCount;
+}
+
+static int chromIx(struct nt4Seq *one, struct nt4Seq **chrome, int chromeCount)
+{
+int i;
+for (i=0; i<chromeCount; ++i)
+    {
+    if (one == chrome[i])
+        return i;
+    }
+assert(FALSE);
+return -1;
+}
+
+static int countPrettyGood(struct crudeGene *crudeGenes, int geneCount, int fraction, int minScore)
+/* Count up # of genes that are not in bottom fraction. (For fraction 4, count
+ * all but bottom quarter. */
+{
+int count = 0;
+int i;
+int threshold = crudeGenes->score;  /* Top score */
+
+threshold = (threshold + fraction/2)/fraction;
+if (threshold < minScore)
+    threshold = minScore;
+for (i=0; i<geneCount; ++i)
+    {
+    if (crudeGenes[i].score >= threshold)
+        ++count;
+    else
+        break;
+    }
+return count;
+}
+
+static int wormDnaMatchScores[256][256];
+
+void initWormDnaMatchScores()
+/* Initialize our big sloppy pairwise comparison table. */
+{
+int i,j;
+static boolean initted = FALSE;
+
+if (initted) return;
+initted = TRUE;
+for (i=0; i<256; ++i)
+    for (j=0; j<256; ++j)
+        wormDnaMatchScores[i][j] = -4;
+wormDnaMatchScores['a']['a'] = 2;
+wormDnaMatchScores['t']['t'] = 2;
+wormDnaMatchScores['A']['A'] = 2;
+wormDnaMatchScores['T']['T'] = 2;
+wormDnaMatchScores['c']['c'] = 3;
+wormDnaMatchScores['g']['g'] = 3;
+wormDnaMatchScores['C']['C'] = 3;
+wormDnaMatchScores['G']['G'] = 3;
+}
+
+#ifdef OLD
+void scoreNoninsertingExtensions(struct crudeGene *crudeGene, DNA *probe, int probeSize)
+/* Fetch target DNA the size of probe and see how good of a score we
+ * can come up with. */
+{
+int i;
+int pStart = crudeGene->probeStart;
+int size = crudeGene->probeEnd - pStart;
+int score = 0;
+DNA *target = nt4Unpack(crudeGene->target, crudeGene->targetStart, size);
+DNA p,t;
+probe += pStart;
+for (i=0; i < size; ++i)
+    {
+    p = probe[i];
+    t = target[i];
+    score += wormDnaMatchScores[p][t];
+    }
+freeMem(target);
+}
+#endif 
+
+void scoreNoninsertingExtensions(struct crudeGene *crudeGene, DNA *probe, int probeSize)
+/* Old fetch target DNA the size of probe and see how good of a score we
+ * can come up with. */
+{
+int i, size;
+int score = 0, maxScore = 0;
+struct nt4Seq *targetChrom = crudeGene->target;
+DNA *target;
+DNA p,t;
+
+/* Figure out what DNA to fetch - trying to get all of target that
+ * corresponds to all of probe, but clipping if at ends of chromosome. */
+int pTileStart = crudeGene->probeStart;
+int tTileStart = crudeGene->targetStart;
+int pStart = 0, pEnd = probeSize;
+int tStart = tTileStart - pTileStart;
+int tEnd = tStart + probeSize;
+if (tStart < 0)
+    {
+    pStart -= tStart;
+    tStart = 0;
+    }
+if (tEnd > targetChrom->baseCount)
+    {
+    int diff = tEnd - targetChrom->baseCount;
+    tEnd -= diff;
+    pEnd -= diff;
+    }
+size = tEnd - tStart;
+if (crudeGene->isRc)
+    reverseComplement(probe, probeSize);
+if (size > 0)
+    {
+    target = nt4Unpack(targetChrom, tStart, size);
+    for (i = 0; i<size; ++i)
+        {
+        assert(i + pStart < probeSize);
+        p = probe[i + pStart];
+        t = target[i];
+        score += wormDnaMatchScores[(int)p][(int)t];
+        if (score < 0)
+            score = 0;
+        if (score > maxScore)
+            maxScore = score;
+        }            
+    freeMem(target);
+    }
+crudeGene->score = maxScore;
+if (crudeGene->isRc)
+    reverseComplement(probe, probeSize);
+}
+
+
+struct crudeAli *crudeAliFind(DNA *probe, int probeSize, 
+    struct nt4Seq **chrome, int chromeCount, int tileSize, int minScore)
+/* Returns a list of crude alignments.  (You can free this with slFreeList() */
+{
+int oneGeneCount;
+int i;
+int chromeIx;
+int geneCount = 0;
+int maxGeneCount = 2*maxHitsAtOnce;
+int isRc;
+struct nt4Seq *target;
+struct crudeGene *crudeGenes = needMem(maxGeneCount*sizeof(*crudeGenes));
+struct fastProber *fps[2];
+struct crudeAli *aliList = NULL, *ali;
+int goodGeneCount;
+
+initWormDnaMatchScores();
+caTileSize = tileSize;
+caIsCdna = (tileSize >= 14);
+fps[0] = makeFastProber(probe, probeSize);
+reverseComplement(probe, probeSize);
+fps[1] = makeFastProber(probe, probeSize);
+reverseComplement(probe, probeSize);
+for (chromeIx = 0; chromeIx < chromeCount; ++chromeIx)
+    {
+    target = chrome[chromeIx];
+    for (isRc = 0; isRc <= 1; ++isRc)
+        {
+        /* Get crude idea of genes on one strand. */
+        oneGeneCount = findCrudeGenes(fps[isRc], target, 
+            crudeGenes+geneCount, maxGeneCount-geneCount, isRc);
+            
+        /* Increment gene count and if necessary compact list. */
+        geneCount += oneGeneCount;
+        if (maxGeneCount - geneCount < maxHitsAtOnce)
+            geneCount = filterPoorGenes(crudeGenes, geneCount);
+        }
+    if (maxGeneCount - geneCount < maxHitsAtOnce)
+        break;
+    }
+
+/* Sort genes by initial promise and get rid of some trash. */
+    {
+    int bestScore, worstScore;
+    qsort(crudeGenes, geneCount, sizeof(crudeGenes[0]), cmpGenesByScore);
+    bestScore = crudeGenes[0].score;
+    worstScore = crudeGenes[geneCount-1].score;
+    if (bestScore > worstScore)
+        {
+        int cutOff = bestScore/10;
+        goodGeneCount = geneCount = countGenesBetter(crudeGenes, geneCount, cutOff);
+        }
+    else if (bestScore >= minScore)
+        goodGeneCount = geneCount;
+    else
+        goodGeneCount = 0;
+    }
+
+if (tileSize == 8)
+    {
+    goodGeneCount = countPrettyGood(crudeGenes, geneCount, 4, 4);
+    geneCount = goodGeneCount;
+    for (i=0; i<geneCount; ++i)
+        scoreNoninsertingExtensions(crudeGenes+i, probe, probeSize);
+    qsort(crudeGenes, geneCount, sizeof(crudeGenes[0]), cmpGenesByScore);
+    goodGeneCount = countPrettyGood(crudeGenes, geneCount, 4, minScore);
+    }
+for (i=0; i<goodGeneCount; ++i)
+    {
+    AllocVar(ali);
+    ali->chromIx = chromIx(crudeGenes[i].target, chrome, chromeCount);
+    ali->start = crudeGenes[i].targetStart;
+    ali->end = crudeGenes[i].targetEnd;
+    ali->score = crudeGenes[i].score;
+    ali->strand = (crudeGenes[i].isRc ? '-' : '+');
+    slAddHead(&aliList, ali);
+    }
+slReverse(&aliList);
+freeFastProber(&fps[0]);
+freeFastProber(&fps[1]);
+freeMem(crudeGenes);
+
+return aliList;
+}
+
diff --git a/jkOwnLib/ffAliHelp.c b/jkOwnLib/ffAliHelp.c
new file mode 100644
index 0000000..76f6892
--- /dev/null
+++ b/jkOwnLib/ffAliHelp.c
@@ -0,0 +1,434 @@
+/* ffAliHelp - Helper routines for things that produce (rather than just
+ * consume) ffAli type alignments. */
+/* Copyright 2000-2003 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "fuzzyFind.h"
+#include "dnaseq.h"
+
+
+void ffCat(struct ffAli **pA, struct ffAli **pB)
+/* Concatenate B to the end of A. Eat up second list
+ * in process. */
+{
+struct ffAli *a = *pA;
+struct ffAli *b = *pB;
+
+/* If list to add is empty our job is real easy. */
+if (b == NULL)
+    return;
+
+/* If list to add into is empty, then just switch in the
+ * second list. */
+if (a == NULL)
+    {
+    *pA = *pB;
+    *pB = NULL;
+    return;
+    }
+
+/* Neither list empty.  Find rightmost element of first list
+ * and cross-link it with leftmost element of second list. */
+while (a->right != NULL) a = a->right;
+b->left = a;
+a->right = b;
+*pB = NULL;
+}
+
+void ffAliSort(struct ffAli **pList, int (*compare )(const void *elem1,  const void *elem2))
+/* Sort a doubly linked list of ffAlis. */
+{
+/* Get head of list and handle easy special empty case. */
+struct ffAli *r = *pList;
+if (r == NULL) return;
+
+/* Since first pointer is "left", in order to reuse slSort, have
+ * to jump through some minor hoops. First go to right end of list,
+ * then sort it. */
+while (r->right) r = r->right;
+slSort(&r, compare);
+
+/* We're sorted, but our right links are all broken.  Fix this. */
+slReverse(&r);
+r = ffMakeRightLinks(r);
+*pList = r;
+}
+
+int ffCmpHitsHayFirst(const void *va, const void *vb)
+/* Compare function to sort hit array by ascending
+ * target offset followed by ascending query offset. */
+{
+const struct ffAli *a = *((struct ffAli **)va);
+const struct ffAli *b = *((struct ffAli **)vb);
+int diff;
+if ((diff = a->hStart - b->hStart) != 0)
+    return diff;
+return a->nStart - b->nStart;
+}
+
+int ffCmpHitsNeedleFirst(const void *va, const void *vb)
+/* Compare function to sort hit array by ascending
+ * query offset followed by ascending target offset. */
+{
+const struct ffAli *a = *((struct ffAli **)va);
+const struct ffAli *b = *((struct ffAli **)vb);
+int diff;
+if ((diff = a->nStart - b->nStart) != 0)
+    return diff;
+return a->hStart - b->hStart;
+}
+
+void ffExpandExactRight(struct ffAli *ali, DNA *needleEnd, DNA *hayEnd)
+/* Expand aligned segment to right as far as can exactly. */
+{
+DNA *nEnd = ali->nEnd;
+DNA *hEnd = ali->hEnd;
+while (nEnd < needleEnd && hEnd < hayEnd)
+    {
+    if (*nEnd != *hEnd)
+        break;
+    nEnd += 1;
+    hEnd += 1;
+    }
+ali->nEnd = nEnd;
+ali->hEnd = hEnd;
+return;
+}
+
+void ffExpandExactLeft(struct ffAli *ali, DNA *needleStart, DNA *hayStart)
+/* Expand aligned segment to left as far as can exactly. */
+{
+DNA *nStart = ali->nStart-1;
+DNA *hStart = ali->hStart-1;
+while (nStart >= needleStart && hStart >= hayStart)
+    {
+    if (*nStart != *hStart)
+        break;
+    nStart -= 1;
+    hStart -= 1;
+    }
+ali->nStart = nStart + 1;
+ali->hStart = hStart + 1;
+return;
+}
+
+struct ffAli *ffMergeClose(struct ffAli *aliList, 
+	DNA *needleStart, DNA *hayStart)
+/* Remove overlapping areas needle in alignment. Assumes ali is sorted on
+ * ascending nStart field. Also merge perfectly abutting neighbors or
+ * ones that could be merged at the expense of just a few mismatches.*/
+{
+struct ffAli *mid, *ali;
+int closeEnough = -3;
+
+if (aliList == NULL)
+    return NULL;
+for (mid = aliList->right; mid != NULL; mid = mid->right)
+    {
+    for (ali = aliList; ali != mid; ali = ali->right)
+	{
+	char *nStart, *nEnd;
+	int nOverlap;
+	nStart = max(ali->nStart, mid->nStart);
+	nEnd = min(ali->nEnd, mid->nStart);
+	nOverlap = nEnd - nStart;
+	/* Overlap or perfectly abut in needle, and needle/hay
+	 * offset the same. */
+	if (nOverlap >= closeEnough)
+	    {
+	    int aliDiag = (ali->nStart - needleStart) - (ali->hStart - hayStart);
+	    int midDiag = (mid->nStart - needleStart) - (mid->hStart - hayStart);
+	    if (aliDiag == midDiag)
+		{
+		/* Make mid encompass both, and make ali empty. */
+		mid->nStart = min(ali->nStart, mid->nStart);
+		mid->nEnd = max(ali->nEnd, mid->nEnd);
+		mid->hStart = min(ali->hStart, mid->hStart);
+		mid->hEnd = max(ali->hEnd, mid->hEnd);
+		ali->hStart = ali->hEnd = mid->hStart;
+		ali->nEnd = ali->nStart = mid->nStart;;
+		}
+	    }
+	}
+    }
+aliList = ffRemoveEmptyAlis(aliList, TRUE);
+return aliList;
+}
+
+
+int ffScoreIntron(DNA a, DNA b, DNA y, DNA z, int orientation)
+/* Return a better score the closer an intron is to
+ * consensus. */
+{
+int score = 0;
+int revScore = 0;
+
+if (orientation >= 0)
+    {
+    if (a == 'g' || a == 'G') ++score;
+    if (b == 't' || b == 'T') ++score;
+    if (y == 'a' || y == 'A') ++score;
+    if (z == 'g' || z == 'G') ++score;
+    }
+
+if (orientation <= 0)
+    {
+    if (a == 'c' || a == 'C') ++revScore;
+    if (b == 't' || b == 'T') ++revScore;
+    if (y == 'a' || y == 'A') ++revScore;
+    if (z == 'c' || z == 'C') ++revScore;
+    }
+
+return score > revScore ? score : revScore;
+}
+
+
+static int slideIntron(struct ffAli *left, struct ffAli *right, int orientation)
+/* Slides space between alignments if possible to match
+ * intron consensus better.  Returns how much it slid intron. */
+{
+DNA *nLeft = left->nEnd;
+DNA *hLeft = left->hEnd;
+DNA *nRight = right->nStart;
+DNA *hRight = right->hStart;
+DNA nl, nr, hl, hr;
+DNA *nLeftEnd = left->nStart;
+DNA *nRightEnd = right->nEnd;
+DNA *nBestLeft = NULL;
+int bestScore = -0x7fffffff;
+int curScore;
+int offset;
+
+if (hRight-hLeft < 4)   /* Too short to be an intron. */
+    return 0;
+if (nRight-nLeft > 2)   /* Too big of a gap to be an intron. */
+    return 0;
+
+/* Slide as far to the left as possible without inserting mismatches. */
+while (nLeft > nLeftEnd)
+    {
+    nl = nLeft[-1];
+    hl = hLeft[-1];
+    nr = nRight[-1];
+    hr = hRight[-1];
+    if (!(nl == 'n' && nr == 'n'))  /* N's in needle freely slide. */
+        {
+        if (nr != hr)
+            break;
+        }
+    nLeft -= 1;
+    hLeft -= 1;
+    nRight -= 1;
+    hRight -= 1;
+    }
+/* Slide as far to the right as possible computing
+   intron score as you go. */
+while (nRight < nRightEnd)
+    {
+    curScore = ffScoreIntron(hLeft[0], hLeft[1], hRight[-2], hRight[-1], orientation);
+    if (curScore > bestScore)
+        {
+        bestScore = curScore;
+        nBestLeft = nLeft;
+        }
+    nl = nLeft[0];
+    hl = hLeft[0];
+    if (nl != 'n' && nl != hl)
+        break;
+    nr = nRight[0];
+    hr = hRight[0];
+    nLeft += 1;
+    hLeft += 1;
+    nRight += 1;
+    hRight += 1;
+    }
+if (nBestLeft == NULL)
+    return 0;
+offset = nBestLeft - left->nEnd;
+if (offset == 0)
+    return offset;
+left->nEnd += offset;
+left->hEnd += offset;
+right->nStart += offset;
+right->hStart += offset;
+return offset;
+}
+
+
+boolean ffSlideOrientedIntrons(struct ffAli *ali, int orient)
+/* Slide introns (or spaces between aligned blocks)
+ * to match consensus on given strand. */
+{
+struct ffAli *left = ali, *right;
+boolean slid = FALSE;
+if (left == NULL)
+    return FALSE;
+while((right = left->right) != NULL)
+    {
+    if (slideIntron(left, right, orient))
+        slid = TRUE;
+    left = right;
+    }
+return slid;
+}
+
+boolean ffSlideIntrons(struct ffAli *ali)
+/* Slide introns (or spaces between aligned blocks)
+ * to match consensus.  Return TRUE if any slid. */
+{
+int orient = ffIntronOrientation(ali);
+return ffSlideOrientedIntrons(ali, orient);
+}
+
+struct ffAli *ffRemoveEmptyAlis(struct ffAli *ali, boolean doFree)
+/* Remove empty blocks from list. Optionally free empties too. */
+{
+struct ffAli *leftAli;
+struct ffAli *startAli;
+struct ffAli *rightAli;
+
+if (ali == NULL)
+    return NULL;
+
+/* Figure out left most non-empty ali. */
+while (ali->left)
+    ali = ali->left;
+while (ali)
+    {
+    /* If current ali is empty, chuck it out. */
+    if (ali->nEnd <= ali->nStart || ali->hEnd <= ali->hStart)
+	{
+	struct ffAli *empty = ali;
+        ali = ali->right;
+	if (doFree) freeMem(empty);
+	}
+    else
+        break;
+    }
+
+if (ali == NULL)
+    return NULL;
+
+ali->left = NULL;
+
+/* Get rid of empty middle alis. */
+startAli = leftAli = ali;
+ali = ali->right;
+while (ali)
+    {
+    rightAli = ali->right;
+    if (ali->nEnd <= ali->nStart || ali->hEnd <= ali->hStart)
+        {
+        leftAli->right = rightAli;
+        if (rightAli != NULL)
+            rightAli->left = leftAli;
+	if (doFree) freeMem(ali);
+        }
+    else
+        {
+        leftAli = ali;
+        }
+    ali = rightAli;
+    }
+return startAli;
+}
+
+struct ffAli *ffMergeHayOverlaps(struct ffAli *ali)
+/* Remove overlaps in haystack that perfectly abut in needle.
+ * These are transformed into perfectly abutting haystacks
+ * that have a gap in the needle. */
+{
+struct ffAli *a = NULL;
+struct ffAli *leftA = NULL;
+
+if (ali == NULL)
+    return NULL;
+a = ali;
+for (;;)
+    {
+    int nOverlap;
+    int hOverlap;
+    int aSize;
+
+    /* Advance to next ali */
+    leftA = a;
+    a = a->right;
+    if (a == NULL)
+        break;
+
+    nOverlap = leftA->nEnd - a->nStart;
+    hOverlap = leftA->hEnd - a->hStart;
+    aSize = a->nEnd - a->nStart;
+    if (hOverlap > 0 && hOverlap < aSize && nOverlap <= 0)
+        {
+        a->hStart += hOverlap;
+        a->nStart += hOverlap;
+        }
+    }
+return ali;
+}
+
+struct ffAli *ffMergeNeedleAlis(struct ffAli *ali, boolean doFree)
+/* Remove overlapping areas needle in alignment. Assumes ali is sorted on
+ * ascending nStart field. Also merge perfectly abutting neighbors.*/
+{
+struct ffAli *a = NULL;
+struct ffAli *leftA = NULL;
+struct ffAli *rightA;
+
+if (ali == NULL)
+    return NULL;
+rightA = ali;
+for (;;)
+    {
+    /* Advance to next ali */
+    leftA = a;
+    a = rightA;
+    if (a == NULL)
+        break;
+    rightA = a->right;
+    
+
+    /* See if can merge current alignment into left one. */
+    if (leftA != NULL)
+        {
+        int overlap = leftA->nEnd - a->nStart;
+
+        /* Deal with overlaps in needle */
+        if (overlap > 0)
+            {
+            /* See if left encompasses current segment. */
+            if (leftA->nStart <= a->nStart && leftA->nEnd >= a->nEnd)
+                {
+                /* Eliminate current segment. */
+                leftA->right = rightA;
+                if (rightA != NULL)
+                    rightA->left = leftA;
+		if (doFree) freeMem(a);
+                a = leftA;
+                }
+            else
+                {
+                /* Remove overlapping area from current segment, leave
+                 * it in left segment. */
+                a->hStart += overlap;
+                a->nStart += overlap;
+                }
+            }
+        else if (overlap == 0 && leftA->hEnd == a->hStart)
+            {
+            /* Remove current segment from list. */
+            leftA->right = rightA;
+            if (rightA != NULL)
+                rightA->left = leftA;
+            /* Fold data from current segment into left segment */
+            leftA->nEnd = a->nEnd;
+            leftA->hEnd = a->hEnd;
+	    if (doFree) freeMem(a); 
+	    a = leftA;
+            }
+        }
+    }
+return ali;
+}
+
diff --git a/jkOwnLib/ffSeedExtend.c b/jkOwnLib/ffSeedExtend.c
new file mode 100644
index 0000000..e0baaf4
--- /dev/null
+++ b/jkOwnLib/ffSeedExtend.c
@@ -0,0 +1,1284 @@
+/* ffSeedExtend - extend alignment out from ungapped seeds. */
+/* Copyright 2003 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "dnaseq.h"
+#include "localmem.h"
+#include "memalloc.h"
+#include "bits.h"
+#include "genoFind.h"
+#include "fuzzyFind.h"
+#include "supStitch.h"
+#include "bandExt.h"
+#include "gfInternal.h"
+
+
+static void extendExactRight(int qMax, int tMax, char **pEndQ, char **pEndT)
+/* Extend endQ/endT as much to the right as possible. */
+{
+int last = min(qMax, tMax);
+int i;
+char *q = *pEndQ, *t = *pEndT;
+
+for (i=0; i<last; ++i)
+    {
+    if (*q != *t)
+	break;
+    q += 1;
+    t += 1;
+    }
+*pEndQ = q;
+*pEndT = t;
+}
+
+static void extendExactLeft(int qMax, int tMax, char **pStartQ, char **pStartT)
+/* Extend startQ/startT as much to the left as possible. */
+{
+int last = min(qMax, tMax);
+int i;
+char *q = *pStartQ - 1, *t = *pStartT - 1;
+
+for (i=0; i<last; ++i)
+    {
+    if (*q != *t)
+	break;
+    q -= 1;
+    t -= 1;
+    }
+*pStartQ = q + 1;
+*pStartT = t + 1;
+}
+
+static void extendGaplessRight(int qMax, int tMax, int maxDrop, char **pEndQ, char **pEndT)
+/* Extend endQ/endT as much to the right as possible allowing mismatches
+ * but not gaps. */
+{
+int last = min(qMax, tMax);
+int i;
+char *q = *pEndQ, *t = *pEndT;
+int score = 0, bestScore = -1, bestPos = -1;
+
+for (i=0; i<last; ++i)
+    {
+    if (q[i] == t[i])
+	{
+	++score;
+	if (score > bestScore)
+	    {
+	    bestScore = score;
+	    bestPos = i;
+	    }
+	}
+    else
+	{
+	score -= 3;
+	if (bestScore - score >= maxDrop)
+	    break;
+	}
+    }
+++bestPos;
+*pEndQ = q+bestPos;
+*pEndT = t+bestPos;
+}
+
+static void extendGaplessLeft(int qMax, int tMax, int maxDrop, char **pStartQ, char **pStartT)
+/* Extend startQ/startT as much to the left as possible allowing mismatches
+ * but not gaps. */
+{
+int score = 0, bestScore = -1, bestPos = 0;
+int last = -min(qMax, tMax);
+int i;
+char *q = *pStartQ, *t = *pStartT;
+
+for (i=-1; i>=last; --i)
+    {
+    if (q[i] == t[i])
+	{
+	++score;
+	if (score > bestScore)
+	    {
+	    bestScore = score;
+	    bestPos = i;
+	    }
+	}
+    else
+	{
+	score -= 3;
+	if (bestScore - score >= maxDrop)
+	    break;
+	}
+    }
+*pStartQ = q+bestPos;
+*pStartT = t+bestPos;
+}
+
+static int ffHashFuncN(char *s, int seedSize)
+/* Return hash function for a 4k hash on sequence. */
+{
+int acc = 0;
+int i;
+for (i=0; i<seedSize; ++i)
+    {
+    acc <<= 1;
+    acc += ntVal[(int)s[i]];
+    }
+return acc&0xfff;
+}
+
+struct seqHashEl
+/* An element in a sequence hash */
+    {
+    struct seqHashEl *next;
+    char *seq;
+    };
+
+static boolean totalDegenerateN(char *s, int seedSize)
+/* Return TRUE if repeat of period 1 or 2. */
+{
+char c1 = s[0], c2 = s[1];
+int i;
+if (seedSize & 1)
+    {
+    seedSize -= 1;
+    if (c1 != s[seedSize])
+        return FALSE;
+    }
+for (i=2; i<seedSize; i += 2)
+    {
+    if (c1 != s[i] || c2 != s[i+1])
+        return FALSE;
+    }
+return TRUE;
+}
+
+static struct ffAli *ffFindExtendNmers(char *nStart, char *nEnd, char *hStart, char *hEnd,
+	int seedSize)
+/* Find perfectly matching n-mers and extend them. */
+{
+struct lm *lm = lmInit(32*1024);
+struct seqHashEl **hashTable, *hashEl, **hashSlot;
+struct ffAli *ffList = NULL, *ff;
+char *n = nStart, *h = hStart, *ne = nEnd - seedSize, *he = hEnd - seedSize;
+
+/* Hash the needle. */
+lmAllocArray(lm, hashTable, 4*1024);
+while (n <= ne)
+    {
+    if (!totalDegenerateN(n, seedSize))
+	{
+	hashSlot = ffHashFuncN(n, seedSize) + hashTable;
+	lmAllocVar(lm, hashEl);
+	hashEl->seq = n;
+	slAddHead(hashSlot, hashEl);
+	}
+    ++n;
+    }
+
+/* Scan the haystack adding hits. */
+while (h <= he)
+    {
+    for (hashEl = hashTable[ffHashFuncN(h, seedSize)]; 
+    	hashEl != NULL; hashEl = hashEl->next)
+	{
+	if (memcmp(hashEl->seq, h, seedSize) == 0)
+	    {
+	    AllocVar(ff);
+	    ff->hStart = h;
+	    ff->hEnd = h + seedSize;
+	    ff->nStart = hashEl->seq;
+	    ff->nEnd = hashEl->seq + seedSize;
+	    extendExactLeft(ff->nStart - nStart, ff->hStart - hStart, 
+		&ff->nStart, &ff->hStart);
+	    extendExactRight(nEnd - ff->nEnd, hEnd - ff->hEnd, &ff->nEnd, &ff->hEnd);
+	    ff->left = ffList;
+	    ffList = ff;
+	    }
+	}
+    ++h;
+    }
+ffList = ffMakeRightLinks(ffList);
+ffList = ffMergeClose(ffList, nStart, hStart);
+lmCleanup(&lm);
+return ffList;
+}
+
+static void clumpToExactRange(struct gfClump *clump, bioSeq *qSeq, int tileSize,
+	int frame, struct trans3 *t3, struct gfRange **pRangeList)
+/* Covert extend and merge hits in clump->hitList so that
+ * you get a list of maximal segments with no gaps or mismatches. */
+{
+struct gfSeqSource *target = clump->target;
+aaSeq *tSeq = target->seq;
+BIOPOL *qs, *ts, *qe, *te;
+struct gfHit *hit;
+int qStart = 0, tStart = 0, qEnd = 0, tEnd = 0, newQ = 0, newT = 0;
+boolean outOfIt = TRUE;		/* Logically outside of a clump. */
+struct gfRange *range;
+BIOPOL *lastQs = NULL, *lastQe = NULL, *lastTs = NULL, *lastTe = NULL;
+
+if (tSeq == NULL)
+    internalErr();
+
+/* The termination condition of this loop is a little complicated.
+ * We want to output something either when the next hit can't be
+ * merged into the previous, or at the end of the list.  To avoid
+ * duplicating the output code we're forced to complicate the loop
+ * termination logic.  Hence the check for hit == NULL to break
+ * the loop is not until near the end of the loop. */
+for (hit = clump->hitList; ; hit = hit->next)
+    {
+    if (hit != NULL)
+        {
+	newQ = hit->qStart;
+	newT = hit->tStart - target->start;
+	}
+
+    /* See if it's time to output merged (diagonally adjacent) hits. */
+    if (!outOfIt)	/* Not first time through. */
+        {
+	/* As a micro-optimization handle strings of adjacent hits
+	 * specially.  Don't do the extensions until we've merged
+	 * all adjacent hits. */
+	if (hit == NULL || newQ != qEnd || newT != tEnd)
+	    {
+	    qs = qSeq->dna + qStart;
+	    ts = tSeq->dna + tStart;
+	    qe = qSeq->dna + qEnd;
+	    te = tSeq->dna + tEnd;
+	    extendExactRight(qSeq->size - qEnd, tSeq->size - tEnd,
+		&qe, &te);
+	    extendExactLeft(qStart, tStart, &qs, &ts);
+	    if (qs != lastQs || ts != lastTs || qe != lastQe || qs !=  lastQs)
+		{
+		lastQs = qs;
+		lastTs = ts;
+		lastQe = qe;
+		lastTe = te;
+		AllocVar(range);
+		range->qStart = qs - qSeq->dna;
+		range->qEnd = qe - qSeq->dna;
+		range->tName = cloneString(tSeq->name);
+		range->tSeq = tSeq;
+		range->tStart = ts - tSeq->dna;
+		range->tEnd = te - tSeq->dna;
+		range->hitCount = qe - qs;
+		range->frame = frame;
+		range->t3 = t3;
+		slAddHead(pRangeList, range);
+		}
+	    outOfIt = TRUE;
+	    }
+	}
+    if (hit == NULL)
+        break;
+
+    if (outOfIt)
+        {
+	qStart = newQ;
+	qEnd = qStart + tileSize;
+	tStart = newT;
+	tEnd = tStart + tileSize;
+	outOfIt = FALSE;
+	}
+    else
+        {
+	qEnd = newQ + tileSize;
+	tEnd = newT + tileSize;
+	}
+    }
+}
+
+static void addExtraHits(struct gfHit *hitList, int hitSize, 
+	struct dnaSeq *qSeq, struct dnaSeq *tSeq, struct ffAli **pExtraList)
+/* Extend hits as far as possible, convert to ffAli, and add to extraList. */
+{
+struct gfHit *hit;
+struct ffAli *ff;
+char *qs = qSeq->dna, *ts = tSeq->dna;
+char *qe = qs + qSeq->size,  *te = ts + tSeq->size;
+for (hit = hitList; hit != NULL; hit = hit->next)
+    {
+    AllocVar(ff);
+    ff->nStart = ff->nEnd = qs + hit->qStart;
+    ff->hStart = ff->hEnd = ts + hit->tStart;
+    ff->nEnd += hitSize;
+    ff->hEnd += hitSize;
+    ff->left = *pExtraList;
+    ffExpandExactLeft(ff, qs, ts);
+    ffExpandExactRight(ff, qe, te);
+    *pExtraList = ff;
+    }
+}
+
+static struct ffAli *foldInExtras(struct dnaSeq *qSeq, struct dnaSeq *tSeq,
+	struct ffAli *ffList, struct ffAli *extraList)
+/* Integrate extraList into ffList and return result. 
+ * Frees bits of extraList that aren't used. */
+{
+if (extraList != NULL)
+    {
+    struct ssBundle *bun;
+    struct ssFfItem *ffi;
+    AllocVar(bun);
+    bun->qSeq = qSeq;
+    bun->genoSeq = tSeq;
+    bun->avoidFuzzyFindKludge = TRUE;
+    AllocVar(ffi);
+    ffi->ff = ffList;
+    slAddHead(&bun->ffList, ffi);
+    AllocVar(ffi);
+    ffi->ff = extraList;
+    slAddHead(&bun->ffList, ffi);
+    ssStitch(bun, ffCdna, 16, 1);
+    if (bun->ffList != NULL)
+	{
+	ffList = bun->ffList->ff;
+	bun->ffList->ff = NULL;
+	}
+    else
+	{
+        ffList = NULL;
+	}
+    ssBundleFree(&bun);
+    }
+return ffList;
+}
+
+static struct ffAli *scanIndexForSmallExons(struct genoFind *gf, struct gfSeqSource *target,
+    struct dnaSeq *qSeq, Bits *qMaskBits, int qMaskOffset, struct dnaSeq *tSeq,
+    struct lm *lm, struct ffAli *ffList)
+/* Use index to look for missing small exons. */
+{
+int qGap, tGap, tStart, qStart;
+struct ffAli *lastFf = NULL, *ff = ffList;
+struct gfHit *hitList = NULL;
+struct dnaSeq qSubSeq;
+struct ffAli *extraList = NULL;
+int tileSize = gf->tileSize;
+int biggestToFind = 200;	/* Longer should be found at an earlier stage */
+
+/* Handle problematic empty case immediately. */
+if (ffList == NULL)
+    return NULL;
+
+ZeroVar(&qSubSeq);
+
+/* Look for initial gap. */
+qGap = ff->nStart - qSeq->dna;
+tGap = ff->hStart - tSeq->dna;
+if (qGap >= tileSize && qGap <= biggestToFind && tGap >= tileSize)
+    {
+    tStart = ff->hStart - tSeq->dna;
+    if (tGap > ffIntronMax) 
+	{
+	tGap = ffIntronMax;
+	}
+    qSubSeq.dna = qSeq->dna;
+    qSubSeq.size = qGap;
+    hitList = gfFindHitsInRegion(gf, &qSubSeq, qMaskBits, qMaskOffset,
+	lm, target, tStart - tGap, tStart);
+    addExtraHits(hitList, tileSize, &qSubSeq, tSeq, &extraList);
+    }
+
+/* Look for middle gaps. */
+for (;;)
+    {
+    lastFf = ff;
+    ff = ff->right;
+    if (ff == NULL)
+	break;
+    qGap = ff->nStart - lastFf->nEnd;
+    tGap = ff->hStart - lastFf->hEnd;
+    if (qGap >= tileSize && qGap <= biggestToFind && tGap >= tileSize)
+	 {
+	 qStart = lastFf->nEnd - qSeq->dna;
+	 tStart = lastFf->hEnd - tSeq->dna;
+	 qSubSeq.dna = lastFf->nEnd;
+	 qSubSeq.size = qGap;
+	 hitList = gfFindHitsInRegion(gf, &qSubSeq, qMaskBits, qMaskOffset + qStart, 
+		lm, target, tStart, tStart + tGap);
+	 addExtraHits(hitList, tileSize, &qSubSeq, tSeq, &extraList);
+	 }
+    }
+
+/* Look for end gaps. */
+qGap = qSeq->dna + qSeq->size - lastFf->nEnd;
+tGap = tSeq->dna + tSeq->size - lastFf->hEnd;
+if (qGap >= tileSize && qGap < biggestToFind && tGap >= tileSize)
+    {
+    if (tGap > ffIntronMax) tGap = ffIntronMax;
+    qStart = lastFf->nEnd - qSeq->dna;
+    tStart = lastFf->hEnd - tSeq->dna;
+    qSubSeq.dna = lastFf->nEnd;
+    qSubSeq.size = qGap;
+    hitList = gfFindHitsInRegion(gf, &qSubSeq, qMaskBits, qMaskOffset + qStart, 
+		lm, target, tStart, tStart + tGap);
+    addExtraHits(hitList, tileSize, &qSubSeq, tSeq, &extraList);
+    }
+extraList = ffMakeRightLinks(extraList);
+ffList = foldInExtras(qSeq, tSeq, ffList, extraList);
+return ffList;
+}
+
+
+static void bandExtBefore(struct axtScoreScheme *ss, struct ffAli *ff,
+	int qGap, int tGap, struct ffAli **pExtraList)
+/* Add in blocks from a banded extension before ff into the gap
+ * and append results if any to *pExtraList. */
+{
+struct ffAli *ext;
+int minGap = min(qGap, tGap);
+int maxGap = minGap * 2;
+if (minGap > 0)
+    {
+    if (qGap > maxGap) qGap = maxGap;
+    if (tGap > maxGap) tGap = maxGap;
+    ext = bandExtFf(NULL, ss, 3, ff, ff->nStart - qGap, ff->nStart, 
+	    ff->hStart - tGap, ff->hStart, -1, maxGap);
+    ffCat(pExtraList, &ext);
+    }
+}
+
+static void bandExtAfter(struct axtScoreScheme *ss, struct ffAli *ff,
+	int qGap, int tGap, struct ffAli **pExtraList)
+/* Add in blocks from a banded extension after ff into the gap
+ * and append results if any to *pExtraList. */
+{
+struct ffAli *ext;
+int minGap = min(qGap, tGap);
+int maxGap = minGap * 2;
+if (minGap > 0)
+    {
+    if (qGap > maxGap) qGap = maxGap;
+    if (tGap > maxGap) tGap = maxGap;
+    ext = bandExtFf(NULL, ss, 3, ff, ff->nEnd, ff->nEnd + qGap,
+	    ff->hEnd, ff->hEnd + tGap, 1, maxGap);
+    ffCat(pExtraList, &ext);
+    }
+}
+	
+	
+static struct ffAli *bandedExtend(struct dnaSeq *qSeq, struct dnaSeq *tSeq, struct ffAli *ffList)
+/* Do banded extension where there is missing sequence. */
+{
+struct ffAli *extraList = NULL, *ff = ffList, *lastFf = NULL;
+struct axtScoreScheme *ss = axtScoreSchemeRnaDefault();
+int qGap, tGap;
+
+if (ff == NULL)
+    return NULL;
+
+/* Look for initial gap. */
+qGap = ff->nStart - qSeq->dna;
+tGap = ff->hStart - tSeq->dna;
+bandExtBefore(ss, ff, qGap, tGap, &extraList);
+
+/* Look for middle gaps. */
+for (;;)
+    {
+    lastFf = ff;
+    ff = ff->right;
+    if (ff == NULL)
+	break;
+    qGap = ff->nStart - lastFf->nEnd;
+    tGap = ff->hStart - lastFf->hEnd;
+    bandExtAfter(ss, lastFf, qGap, tGap, &extraList);
+    bandExtBefore(ss, ff, qGap, tGap, &extraList);
+    }
+
+/* Look for end gaps. */
+qGap = qSeq->dna + qSeq->size - lastFf->nEnd;
+tGap = tSeq->dna + tSeq->size - lastFf->hEnd;
+bandExtAfter(ss, lastFf, qGap, tGap, &extraList);
+
+ffList = foldInExtras(qSeq, tSeq, ffList, extraList);
+return ffList;
+}
+
+
+
+static struct ffAli *expandGapless(struct dnaSeq *qSeq, struct dnaSeq *tSeq, struct ffAli *ffList)
+/* Do non-banded extension sequence.  Since this is quick
+ * we'll let it overlap with existing sequence. */
+{
+struct ffAli *ff = ffList, *lastFf = NULL;
+char *nStart = qSeq->dna;
+char *nEnd = qSeq->dna + qSeq->size;
+char *hStart = tSeq->dna;
+char *hEnd = tSeq->dna + tSeq->size;
+
+/* Look for initial gap. */
+extendGaplessLeft(ff->nStart - nStart, ff->hStart - hStart, 
+	9, &ff->nStart, &ff->hStart);
+
+/* Look for middle gaps. */
+for (;;)
+    {
+    lastFf = ff;
+    ff = ff->right;
+    if (ff == NULL)
+	break;
+    extendGaplessRight(nEnd - lastFf->nEnd, hEnd - lastFf->hEnd, 9, 
+	&lastFf->nEnd, &lastFf->hEnd);
+    extendGaplessLeft(ff->nStart - nStart, ff->hStart - hStart, 9, 
+	&ff->nStart, &ff->hStart);
+    }
+extendGaplessRight(nEnd - lastFf->nEnd,
+	hEnd - lastFf->hEnd, 9,
+	&lastFf->nEnd, &lastFf->hEnd);
+return ffList;
+}
+
+
+static int seedResolvePower(int seedSize, int resolveLimit)
+/* Return how many bases to search for seed of given
+ * size. */
+{
+int res;
+if (seedSize >= 14)	/* Avoid int overflow */
+    return ffIntronMax;
+res  = (1 << (seedSize+seedSize-resolveLimit));
+if (res > ffIntronMax)
+    res = ffIntronMax;
+return res;
+}
+
+static char *scanExactLeft(char *n, int nSize, int hSize, char *hEnd, int resolveLimit)
+/* Look for first exact match to the left. */
+{
+/* Optimize a little by comparing the first character inline. */
+char n1 = *n++;
+char *hStart;
+int maxSize = seedResolvePower(nSize, resolveLimit);
+
+if (hSize > maxSize) hSize = maxSize;
+nSize -= 1;
+hStart = hEnd - hSize;
+
+hEnd -= nSize;
+while (hEnd >= hStart)
+    {
+    if (n1 == *hEnd && memcmp(n, hEnd+1, nSize) == 0)
+	return hEnd;
+    hEnd -= 1;
+    }
+return NULL;
+}
+
+static char *scanExactRight(char *n, int nSize, int hSize, char *hStart, int resolveLimit)
+/* Look for first exact match to the right. */
+{
+/* Optimize a little by comparing the first character inline. */
+char n1 = *n++;
+char *hEnd;
+int maxSize = seedResolvePower(nSize, resolveLimit);
+
+if (hSize > maxSize) hSize = maxSize;
+hEnd = hStart + hSize;
+nSize -= 1;
+
+hEnd -= nSize;
+while (hStart <= hEnd)
+    {
+    if (n1 == *hStart && memcmp(n, hStart+1, nSize) == 0)
+	return hStart;
+    hStart += 1;
+    }
+return NULL;
+}
+
+static struct ffAli *fillInExact(char *nStart, char *nEnd, char *hStart, char *hEnd, 
+	boolean isRc, boolean scanLeft, boolean scanRight, int resolveLimit)
+/* Try and add exact match to the region, adding splice sites to
+ * the area to search for small query sequences. scanRight and scanLeft
+ * specify which way to scan and which side of the splice site to
+ * include.  One or the other or neither should be set. */
+{
+struct ffAli *ff = NULL;
+char *hPos = NULL;
+int nGap = nEnd - nStart;
+int hGap = hEnd - hStart;
+int minGap = min(nGap, hGap);
+
+if (minGap <= 2)
+    return NULL;
+if (scanLeft)
+    {
+    if ((hPos = scanExactLeft(nStart, nGap, hGap, hEnd, resolveLimit)) != NULL)
+	{
+	AllocVar(ff);
+	ff->nStart = nStart;
+	ff->nEnd = nEnd;
+	ff->hStart = hPos;
+	ff->hEnd = hPos + nGap;
+	return ff;
+	}
+    }
+else
+    {
+    if ((hPos = scanExactRight(nStart, nGap, hGap, hStart, resolveLimit)) != NULL)
+	{
+	AllocVar(ff);
+	ff->nStart = nStart;
+	ff->nEnd = nEnd;
+	ff->hStart = hPos;
+	ff->hEnd = hPos + nGap;
+	return ff;
+	}
+    }
+return NULL;
+}
+
+static struct ffAli *findFromSmallerSeeds(char *nStart, char *nEnd, 
+	char *hStart, char *hEnd, boolean isRc, 
+	boolean scanLeft, boolean scanRight, int seedSize, int resolveLimit)
+/* Look for matches with smaller seeds. */
+{
+int nGap = nEnd - nStart;
+if (nGap >= seedSize)
+    {
+    struct ffAli *ffList;
+    if (scanLeft || scanRight)
+        {
+	int hGap = hEnd - hStart;
+	int maxSize = seedResolvePower(seedSize, resolveLimit);
+	if (hGap > maxSize) hGap = maxSize;
+	if (scanLeft)
+	    hStart = hEnd - hGap;
+	if (scanRight)
+	    hEnd = hStart + hGap;
+	}
+    ffList = ffFindExtendNmers(nStart, nEnd, hStart, hEnd, seedSize);
+    if (ffList != NULL)
+	{
+	struct ffAli *extensions = NULL, *ff;
+	struct axtScoreScheme *ss = axtScoreSchemeRnaDefault();
+	for (ff = ffList; ff != NULL; ff = ff->right)
+	    {
+	    bandExtBefore(ss, ff, ff->nStart - nStart, ff->hStart - hStart, &extensions);
+	    bandExtAfter(ss, ff, nEnd - ff->nEnd, hEnd - ff->hEnd, &extensions);
+	    }
+	ffCat(&ffList, &extensions);
+	}
+
+    return ffList;
+    }
+return NULL;
+}
+
+static int countT(char *s, int size)
+/* Count number of initial T's. */
+{
+int i;
+for (i=0; i<size; ++i)
+    {
+    if (s[i] != 't')
+	break;
+    }
+return i;
+}
+
+static int countA(char *s, int size)
+/* Count number of terminal A's. */
+{
+int count = 0;
+int i;
+for (i=size-1; i >= 0; --i)
+    {
+    if (s[i] == 'a')
+	++count;
+    else
+	break;
+    }
+return count;
+}
+
+struct ffAli *scanTinyOne(char *nStart, char *nEnd, char *hStart, char *hEnd, 
+	boolean isRc, boolean scanLeft, boolean scanRight, int seedSize)
+/* Try and add some exon candidates in the region. */
+{
+struct ffAli *ff;
+int nGap = nEnd - nStart;
+if (nGap > 80)		/* The index should have found things this big already. */
+    return NULL;
+if (scanLeft && isRc)
+    nStart += countT(nStart, nGap);
+if (scanRight && !isRc)
+    nEnd -= countA(nStart, nGap);
+ff = fillInExact(nStart, nEnd, hStart, hEnd, isRc, scanLeft, scanRight, 3);
+if (ff != NULL)
+    {
+    return ff;
+    }
+return findFromSmallerSeeds(nStart, nEnd, hStart, hEnd, isRc,
+	scanLeft, scanRight, seedSize, 3);
+}
+
+static struct ffAli *scanForSmallerExons( int seedSize, 
+	struct dnaSeq *qSeq, struct dnaSeq *tSeq,
+	boolean isRc, struct ffAli *ffList)
+/* Look for exons too small to be caught by index. */
+{
+struct ffAli *extraList = NULL, *ff = ffList, *lastFf = NULL, *newFf;
+
+if (ff == NULL)
+    return NULL;
+
+/* Look for initial gap. */
+newFf = scanTinyOne(qSeq->dna, ff->nStart, tSeq->dna, ff->hStart, 
+	isRc, TRUE, FALSE, seedSize); 
+ffCat(&extraList, &newFf);
+
+/* Look for middle gaps. */
+for (;;)
+    {
+    lastFf = ff;
+    ff = ff->right;
+    if (ff == NULL)
+	break;
+    newFf = scanTinyOne(lastFf->nEnd, ff->nStart, lastFf->hEnd, ff->hStart, 
+	isRc, FALSE, FALSE, seedSize);
+    ffCat(&extraList, &newFf);
+    }
+
+/* Look for end gaps. */
+newFf = scanTinyOne(lastFf->nEnd, qSeq->dna + qSeq->size, 
+	lastFf->hEnd, tSeq->dna + tSeq->size, isRc, FALSE, TRUE, seedSize);
+ffCat(&extraList, &newFf);
+
+ffList = foldInExtras(qSeq, tSeq, ffList, extraList);
+return ffList;
+}
+
+static struct ffAli *scanForTinyInternal(struct dnaSeq *qSeq, struct dnaSeq *tSeq,
+	boolean isRc, struct ffAli *ffList)
+/* Look for exons too small to be caught by index. */
+{
+struct ffAli *extraList = NULL, *ff = ffList, *lastFf = NULL, *newFf;
+
+if (ff == NULL)
+    return NULL;
+
+/* Look for middle gaps. */
+for (;;)
+    {
+    lastFf = ff;
+    ff = ff->right;
+    if (ff == NULL)
+	break;
+    newFf = fillInExact(lastFf->nEnd, ff->nStart, lastFf->hEnd, ff->hStart, isRc, 
+	FALSE, FALSE, 0);
+    ffCat(&extraList, &newFf);
+    }
+
+ffList = foldInExtras(qSeq, tSeq, ffList, extraList);
+return ffList;
+}
+
+static boolean tradeMismatchToCloseSpliceGap( struct ffAli *left, 
+	struct ffAli *right, int orientation)
+/* Try extending one side or the other to close gap caused by
+ * mismatch near splice site */
+{
+if (intronOrientation(left->hEnd+1, right->hStart) == orientation)
+    {
+    left->hEnd += 1;
+    left->nEnd += 1;
+    return TRUE;
+    }
+if (intronOrientation(left->hEnd, right->hStart-1) == orientation)
+    {
+    right->hStart -= 1;
+    right->nStart -= 1;
+    return TRUE;
+    }
+return FALSE;
+}
+
+static int calcSpliceScore(struct axtScoreScheme *ss, 
+	char a1, char a2, char b1, char b2, int orientation)
+/* Return adjustment for match/mismatch of consensus. */
+{
+int score = 0;
+int matchScore = ss->matrix['c']['c'];
+if (orientation >= 0)  /* gt/ag or gc/ag */
+    {
+    score += ss->matrix[(int)a1]['g'];
+    if (a2 != 'c')
+        score += ss->matrix[(int)a2]['t'];
+    score += ss->matrix[(int)b1]['a'];
+    score += ss->matrix[(int)b2]['g'];
+    }
+else		       /* ct/ac or ct/gc */
+    {
+    score += ss->matrix[(int)a1]['c'];
+    score += ss->matrix[(int)a2]['t'];
+    if (b1 != 'g')
+	score += ss->matrix[(int)b1]['a'];
+    score += ss->matrix[(int)b2]['c'];
+    }
+if (score >= 3* matchScore)
+    score += matchScore;
+return score;
+}
+
+static void grabAroundIntron(char *hpStart, int iPos, int iSize,
+	int modPeelSize, char *hSeq)
+/* Grap sequence on either side of intron. */
+{
+memcpy(hSeq, hpStart, iPos);
+memcpy(hSeq+iPos, hpStart+iPos+iSize, modPeelSize - iPos);
+hSeq[modPeelSize] = 0;
+}
+
+#ifdef UNTESTED
+struct ffAli *removeFf(struct ffAli *ff, struct ffAli *ffList)
+/* Remove ffAli and free it.  Return resulting list. */
+{
+struct ffAli *right = ff->right;
+struct ffAli *left;
+if (ff == ffList)
+    {
+    if (right != NULL)
+	right->left = NULL;
+    freeMem(ff);
+    return right;
+    }
+left = ff->left;
+left->right = right;
+if (right != NULL)
+    right->left = left;
+freeMem(ff);
+return ffList;
+}
+#endif /* UNTESTED */
+
+static struct ffAli *hardRefineSplice(struct ffAli *left, struct ffAli *right,
+	struct dnaSeq *qSeq, struct dnaSeq *tSeq, struct ffAli *ffList, 
+	int orientation)
+/* Do difficult refinement of splice site.  See if
+ * can get nice splice sites without breaking too much.  */
+{
+/* Strategy: peel back about 6 bases on either side of intron.
+ * Then try positioning the intron at each position in the
+ * peeled area and assessing score. */
+int peelSize = 12;
+char nSeq[12+1], hSeq[12+1+1];
+char nSym[25], hSym[25];
+int symCount;
+int seqScore, spliceScore, score, maxScore = 0;
+int nGap = right->nStart - left->nEnd;
+int hGap = right->hStart - left->hEnd;
+int peelLeft = (peelSize - nGap)/2;
+int intronSize = hGap - nGap;
+char *npStart = left->nEnd - peelLeft;
+char *npEnd = npStart + peelSize;
+char *hpStart = left->hEnd - peelLeft;
+char *hpEnd = npEnd + (right->hStart - right->nStart);
+struct axtScoreScheme *ss = axtScoreSchemeRnaDefault();
+static int modSize[3] = {0, 1, -1};
+int modIx;
+int bestPos = -1, bestMod = 0;
+int iPos;
+
+memcpy(nSeq, npStart, peelSize);
+nSeq[peelSize] = 0;
+for (modIx=0; modIx < ArraySize(modSize); ++modIx)
+    {
+    int modOne = modSize[modIx];
+    int modPeelSize = peelSize - modOne;
+    int iSize = intronSize + modOne;
+    for (iPos=0; iPos <= modPeelSize; iPos++)
+        {
+	grabAroundIntron(hpStart, iPos, iSize, modPeelSize, hSeq);
+	if (bandExt(TRUE, ss, 2, nSeq, peelSize, hSeq, modPeelSize, 1,
+		sizeof(hSym), &symCount, nSym, hSym, NULL, NULL))
+	    {
+	    seqScore = axtScoreSym(ss, symCount, nSym, hSym);
+	    spliceScore = calcSpliceScore(ss, hpStart[iPos], hpStart[iPos+1],
+		    hpStart[iPos+iSize-2], hpStart[iPos+iSize-1], orientation);
+	    score = seqScore + spliceScore;
+	    if (score > maxScore)
+		{
+		maxScore = score;
+		bestPos = iPos;
+		bestMod = modOne;
+		}
+	    }
+	}
+    }
+if (maxScore > 0)
+    {
+    int modPeelSize = peelSize - bestMod;
+    int i,diff, cutSymIx = 0;
+    int nIx, hIx;
+    struct ffAli *ff;
+
+    /* Regenerate the best alignment. */
+    grabAroundIntron(hpStart, bestPos, intronSize + bestMod, modPeelSize, hSeq); 
+    bandExt(TRUE, ss, 2, nSeq, peelSize, hSeq, modPeelSize, 1,
+	    sizeof(hSym), &symCount, nSym, hSym, NULL, NULL);
+
+    /* Peel back surrounding ffAli's */
+    if (left->nStart > npStart || right->nEnd < npEnd)
+	{
+	/* It would take a lot of code to handle this case. 
+	 * I believe it is rare enough that it's not worth
+	 * it.  This verbosity will help keep track of how
+	 * often it comes up. */
+	verbose(2, "Unable to peel in hardRefineSplice\n");
+	return ffList;
+	}
+    diff = left->nEnd - npStart;
+    left->nEnd -= diff;
+    left->hEnd -= diff;
+    diff = right->nStart - npEnd;
+    right->nStart -= diff;
+    right->hStart -= diff;
+
+    /* Step through base by base alignment from the left until
+     * hit intron, converting it into ffAli format. */
+    nIx = hIx = 0;
+    ff = left;
+    for (i=0; i<symCount; ++i)
+	{
+	if (hIx == bestPos)
+	    {
+	    cutSymIx = i;
+	    break;
+	    }
+	if (hSym[i] == '-')
+	    {
+	    ff = NULL;
+	    nIx += 1;
+	    }
+	else if (nSym[i] == '-')
+	    {
+	    ff = NULL;
+	    hIx += 1;
+	    }
+	else
+	    {
+	    if (ff == NULL)
+		{
+		AllocVar(ff);
+		ff->left = left;
+		ff->right = right;
+		left->right = ff;
+		right->left = ff;
+		left = ff;
+		ff->nStart = ff->nEnd = npStart + nIx;
+		ff->hStart = ff->hEnd = hpStart + hIx;
+		}
+	    ++nIx;
+	    ++hIx;
+	    ff->nEnd += 1;
+	    ff->hEnd += 1;
+	    }
+	}
+
+    /* Step through base by base alignment from the right until
+     * hit intron, converting it into ffAli format. */
+    ff = right;
+    hIx = nIx = 0;	/* Index from right side. */
+    for (i = symCount-1; i >= cutSymIx; --i)
+	{
+	if (hSym[i] == '-')
+	    {
+	    ff = NULL;
+	    nIx += 1;
+	    }
+	else if (nSym[i] == '-')
+	    {
+	    ff = NULL;
+	    hIx += 1;
+	    }
+	else
+	    {
+	    if (ff == NULL)
+		{
+		AllocVar(ff);
+		ff->left = left;
+		ff->right = right;
+		left->right = ff;
+		right->left = ff;
+		left = ff;
+		ff->nStart = ff->nEnd = npEnd - nIx;
+		ff->hStart = ff->hEnd = hpEnd - hIx;
+		}
+	    ++nIx;
+	    ++hIx;
+	    ff->nStart -= 1;
+	    ff->hStart -= 1;
+	    }
+	}
+    }
+return ffList;
+}
+
+
+static struct ffAli *refineSpliceSites(struct dnaSeq *qSeq, struct dnaSeq *tSeq,
+	struct ffAli *ffList)
+/* Try and get a little closer to splice site consensus
+ * by jiggle things a little. */
+{
+int orientation = ffIntronOrientation(ffList);
+struct ffAli *ff, *nextFf;
+if (orientation == 0)
+    return ffList;
+if (ffSlideOrientedIntrons(ffList, orientation))
+    ffList = ffRemoveEmptyAlis(ffList, TRUE);
+for (ff = ffList; ff != NULL; ff = nextFf)
+    {
+    int nGap, hGap;
+    if ((nextFf = ff->right) == NULL)
+	break;
+    nGap = nextFf->nStart - ff->nEnd;
+    hGap = nextFf->hStart - ff->hEnd;
+    if (nGap > 0 && nGap <= 6 && hGap >= 30)
+	{
+	if (nGap == 1)
+	    {
+	    if (tradeMismatchToCloseSpliceGap(ff, nextFf, orientation))
+	        continue;
+	    }
+	ffList = hardRefineSplice(ff, nextFf, qSeq, tSeq, ffList, orientation);
+	}
+    }
+return ffList;
+}
+
+
+static boolean smoothOneGap(struct ffAli *left, struct ffAli *right, struct ffAli *ffList)
+/* If and necessary connect left and right - either directly or
+ * with a small intermediate ffAli inbetween.  Do not bother to
+ * merge directly abutting regions,  this happens later.  Returns
+ * TRUE if any smoothing done. */ 
+{
+int nGap = right->nStart - left->nEnd;
+int hGap = right->hStart - left->hEnd;
+if (nGap > 0 && hGap > 0 && nGap < 10 && hGap < 10)
+    {
+    int sizeDiff = nGap - hGap;
+    if (sizeDiff < 0) sizeDiff = -sizeDiff;
+    if (sizeDiff <= 3)
+	{
+	struct axtScoreScheme *ss = axtScoreSchemeRnaDefault();
+	char hSym[20], nSym[20];
+	int symCount;
+	if (bandExt(TRUE, ss, 3, left->nEnd, nGap, left->hEnd, hGap, 1,
+		sizeof(hSym), &symCount, nSym, hSym, NULL, NULL))
+	    {
+	    int gapPenalty = -ffCalcCdnaGapPenalty(hGap, nGap) * ss->matrix['a']['a'];
+	    int score = axtScoreSym(ss, symCount, nSym, hSym);
+	    if (score >= gapPenalty)
+		{
+		struct ffAli *l, *r;
+		l = ffAliFromSym(symCount, nSym, hSym, NULL, left->nEnd, left->hEnd);
+		r = ffRightmost(l);
+		left->right = l;
+		l->left = left;
+		r->right = right;
+		right->left = r;
+		return TRUE;
+		}
+	    }
+	}
+    }
+return FALSE;
+}
+
+
+static struct ffAli *smoothSmallGaps(struct dnaSeq *qSeq, struct dnaSeq *tSeq,
+	struct ffAli *ffList)
+/* Fill in small double sided gaps where possible. */
+{
+struct ffAli *left = ffList, *right;
+boolean smoothed = FALSE;
+
+if (ffList == NULL) return NULL;
+for (;;)
+    {
+    if ((right = left->right) == NULL)
+	break;
+    if (smoothOneGap(left, right, ffList))
+	smoothed = TRUE;
+    left = right;
+    }
+if (smoothed)
+    {
+    ffList = ffMergeNeedleAlis(ffList, TRUE);
+    }
+return ffList;
+}
+
+int aPenalty(char *s, int size)
+/* Penalty for polyA/polyT */
+{
+int aCount = 0, tCount = 0;
+int i;
+char c;
+for (i=0; i<size; ++i)
+    {
+    c = s[i];
+    if (c == 'a') ++aCount;
+    if (c == 't') ++tCount;
+    }
+if (tCount > aCount) aCount = tCount;
+if (aCount >= size)
+    return aCount-1;
+else if (aCount >= size*0.75)
+    return aCount * 0.90;
+else
+    return 0;
+}
+
+static int trimGapPenalty(int hGap, int nGap, char *iStart, char *iEnd, int orientation)
+/* Calculate gap penalty for routine below. */
+{
+int penalty =  ffCalcGapPenalty(hGap, nGap, ffCdna);
+if (hGap > 2 || nGap > 2)	/* Not just a local extension. */
+				/* Score gap to favor introns. */
+    {
+    penalty <<= 1;
+    if (nGap > 0)	/* Intron gaps are not in n side at all. */
+	 penalty += 3;
+    			/* Good splice sites give you bonus 2,
+			 * bad give you penalty of six. */
+    penalty += 6 - 2*ffScoreIntron(iStart[0], iStart[1], 
+    	iEnd[-2], iEnd[-1], orientation);
+    }
+return penalty;
+}
+
+
+static struct ffAli *trimFlakyEnds(struct dnaSeq *qSeq, struct dnaSeq *tSeq,
+	struct ffAli *ffList)
+/* Get rid of small initial and terminal exons that seem to just
+ * be chance alignments.  Looks for splice sites and non-degenerate
+ * sequence to keep things. */
+{
+int orientation = ffIntronOrientation(ffList);
+struct ffAli *left, *right;
+char *iStart, *iEnd;
+int blockScore, gapPenalty;
+
+/* If one or less block then don't bother. */
+if (ffAliCount(ffList) < 2)
+    return ffList;
+
+/* Trim beginnings. */
+left = ffList;
+right = ffList->right;
+while (right != NULL)
+    {
+    blockScore = ffScoreMatch(left->nStart, left->hStart, 
+    	left->nEnd-left->nStart);
+    blockScore -= aPenalty(left->nStart, left->nEnd - left->nStart);
+    iStart = left->hEnd;
+    iEnd = right->hStart;
+    gapPenalty = trimGapPenalty(iEnd-iStart, 
+    	right->nStart - left->nEnd, iStart, iEnd, orientation);
+    if (gapPenalty >= blockScore)
+        {
+	freeMem(left);
+	ffList = right;
+	right->left = NULL;
+	}
+    else
+        break;
+    left = right;
+    right = right->right;
+    }
+
+right = ffRightmost(ffList);
+if (right == ffList)
+    return ffList;
+left = right->left;
+while (left != NULL)
+    {
+    blockScore = ffScoreMatch(right->nStart, right->hStart, 
+    	right->nEnd-right->nStart);
+    blockScore -= aPenalty(right->nStart, right->nEnd - right->nStart);
+    iStart = left->hEnd;
+    iEnd = right->hStart;
+    gapPenalty = trimGapPenalty(iEnd-iStart, 
+    	right->nStart - left->nEnd, iStart, iEnd, orientation);
+    if (gapPenalty >= blockScore)
+        {
+	freeMem(right);
+	left->right = NULL;
+	}
+    else
+        break;
+    right = left;
+    left = left->left;
+    }
+return ffList;
+}
+
+
+static void refineBundle(struct genoFind *gf, 
+	struct dnaSeq *qSeq,  Bits *qMaskBits, int qMaskOffset,
+	struct dnaSeq *tSeq, struct lm *lm, struct ssBundle *bun, boolean isRc)
+/* Refine bundle - extending alignments and looking for smaller exons. */
+{
+struct ssFfItem *ffi;
+struct gfSeqSource *target = gfFindNamedSource(gf, tSeq->name);
+
+/* First do gapless expansions and restitch. */
+for (ffi = bun->ffList; ffi != NULL; ffi = ffi->next)
+    {
+    ffi->ff = expandGapless(qSeq, tSeq, ffi->ff);
+    }
+ssStitch(bun, ffCdna, 16, 16);
+
+for (ffi = bun->ffList; ffi != NULL; ffi = ffi->next)
+    {
+    ffi->ff = scanIndexForSmallExons(gf, target, qSeq, qMaskBits, qMaskOffset, 
+	tSeq, lm, ffi->ff);
+    ffi->ff = bandedExtend(qSeq, tSeq, ffi->ff);
+    ffi->ff = scanForSmallerExons(gf->tileSize, qSeq, tSeq, isRc, ffi->ff);
+    ffi->ff = refineSpliceSites(qSeq, tSeq, ffi->ff);
+    ffi->ff = scanForTinyInternal(qSeq, tSeq, isRc, ffi->ff);
+    ffi->ff = smoothSmallGaps(qSeq, tSeq, ffi->ff);
+    ffi->ff = trimFlakyEnds(qSeq, tSeq, ffi->ff);
+    }
+}
+
+
+struct ssBundle *ffSeedExtInMem(struct genoFind *gf, struct dnaSeq *qSeq, Bits *qMaskBits, 
+	int qOffset, struct lm *lm, int minScore, boolean isRc)
+/* Do seed and extend type alignment */
+{
+struct ssBundle *bunList = NULL, *bun;
+int hitCount;
+struct gfClump *clumpList, *clump;
+struct gfRange *rangeList = NULL, *range;
+struct dnaSeq *tSeq;
+
+clumpList = gfFindClumpsWithQmask(gf, qSeq, qMaskBits, qOffset, lm, &hitCount);
+for (clump = clumpList; clump != NULL; clump = clump->next)
+    clumpToExactRange(clump, qSeq, gf->tileSize, 0, NULL, &rangeList);
+slSort(&rangeList, gfRangeCmpTarget);
+rangeList = gfRangesBundle(rangeList, ffIntronMax);
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    range->qStart += qOffset;
+    range->qEnd += qOffset;
+    tSeq = range->tSeq;
+    AllocVar(bun);
+    bun->qSeq = qSeq;
+    bun->genoSeq = tSeq;
+    bun->ffList = gfRangesToFfItem(range->components, qSeq);
+    bun->isProt = FALSE;
+    bun->avoidFuzzyFindKludge = TRUE;
+    ssStitch(bun, ffCdna, 16, 10);
+    refineBundle(gf, qSeq, qMaskBits, qOffset, tSeq, lm, bun, isRc);
+    slAddHead(&bunList, bun);
+    }
+gfRangeFreeList(&rangeList);
+gfClumpFreeList(&clumpList);
+return bunList;
+}
+
diff --git a/jkOwnLib/fuzzyFind.c b/jkOwnLib/fuzzyFind.c
new file mode 100644
index 0000000..69a23c2
--- /dev/null
+++ b/jkOwnLib/fuzzyFind.c
@@ -0,0 +1,1522 @@
+/* Copyright 1999-2003 Jim Kent.  All rights reserved. */
+/* fuzzyFind - searches a large DNA sequence (the haystack) for 
+ * a smaller DNA sequence (the needle).  What makes this tricky
+ * is that the match need not be exact.
+ *
+ * The algorithm looks for exact matches to (typically ten) evenly 
+ * spaced subsequences of the needle long enough for the match to
+ * occur only once or less by chance in the haystack.  If
+ * in fact they occur more than 3 times, the subsequence is
+ * extended by a base.
+ *
+ * Next these ten-mers (called "tiles" in the code)
+ * are extended as far as possible exactly.  Each tile at
+ * this point may match the haystack in multiple places.
+ *
+ * Next the "weave" routines try to find a good 
+ * way to link the tiles together.  Good is scored
+ * by a routine which awards a point for a matching
+ * base, and subtracts the log-base-two of gaps.  It
+ * penalizes an additionallly if a tile is
+ * placed before instead of after a previous tile.
+ *
+ * Now that a preliminary alignment exists, the algorithm
+ * searches for exact matches between tiles. These matches
+ * are constrained to be long enough that they only occur
+ * once in the space between tiles.  These matches are 
+ * extended as far as they can be exactly, and added as 
+ * further tiles to the alignment list.
+ *
+ * Finally the tiles are extended inexactly until they
+ * abutt each other, or until even inexact extension is
+ * fruitless.  
+ * 
+ * The inexact extension is perhaps the trickiest part of the
+ * algorithm.  It's implemented in expandLeft and expandRight.
+ * In these the extension is first taken as far as it can go
+ * exactly.  Then if four of the next five bases match it's
+ * taken five bases further. Then a break is generated, and the
+ * next significant match between the needle and haystack is
+ * scanned for.
+ */
+
+
+#include "common.h"
+#include "dnautil.h"
+#include "localmem.h"
+#include "errabort.h"
+#include "fuzzyFind.h"
+#include "obscure.h"
+
+/* ffMemory routines - 
+ *    FuzzyFinder allocates memory internally from the
+ *    following routines, which allocate blocks from the
+ *    main allocator and then dole them out.
+ *
+ *    At the end of fuzzy-finding, the actual alignment
+ *    is copied to more permanent memory, and all the
+ *    blocks freed.  This saves from having to remember
+ *    to free every little thing, and also is faster.
+ *
+ *    If memory can't be allocated this will throw
+ *    back to the root of the fuzzy-finder system.
+ *
+ *    (In typical usage this only allocates about
+ *    as much memory as the size of the DNA
+ *    you're scanning though.)
+ *    
+ */
+
+/* debugging stuff. */
+void dumpFf(struct ffAli *left, DNA *needle, DNA *hay); 
+
+/* settable parameter, defaults to constant value */
+static jmp_buf ffRecover;
+
+static void ffAbort()
+/* Abort fuzzy finding. */
+{
+longjmp(ffRecover, -1);
+}
+
+static struct lm *ffMemPool = NULL;
+
+static void ffMemInit()
+/* Initialize fuzzyFinder local memory system. */
+{
+ffMemPool = lmInit(2048);
+}
+
+static void ffMemCleanup()
+/* Free up fuzzyFinder local memory system. */
+{
+lmCleanup(&ffMemPool);
+}
+
+static void *ffNeedMem(size_t size)
+/* Allocate from fuzzyFinder local memory system. */
+{
+return lmAlloc(ffMemPool, size);
+}
+
+static void makeFreqTable(DNA *dna, int dnaSize, double freq[4])
+{
+int histo[4];
+double total;
+int i;
+
+dnaBaseHistogram(dna, dnaSize, histo);
+total = histo[0] + histo[1] + histo[2] + histo[3];
+if (total == 0) total = 1;
+for (i=0; i<4; ++i)
+    freq[i] = (double)histo[i] / total;
+}
+
+static double oligoProb(DNA *oligo, int size, double freq[4])
+{
+double prob = 1.0;
+int i;
+int baseVal;
+
+for (i=0; i<size; ++i)
+    {
+    if ((baseVal = ntVal[(int)oligo[i]]) >= 0)
+        prob *= freq[baseVal];
+    }
+return prob;
+}
+
+static boolean findImprobableOligo(DNA *needle, int needleLength, double maxProb, double freq[4],
+    DNA **rOligo, int *rOligoLength, double *rOligoProb)
+/* Find an oligo that's got less than maxProb probability of matching to
+ * random DNA with the given base frequency distribution. */
+{
+int i;
+double totalProb = 1.0;
+int base;
+int startIx = 0;
+
+for (i=0;i<needleLength;++i)
+    {
+    if ((base = ntVal[(int)needle[i]]) < 0)
+        {
+        totalProb = 1.0;
+        startIx = i+1;
+        }
+    else
+        {
+        if ((totalProb *= freq[base]) <= maxProb)
+            {
+            *rOligo = needle+startIx;
+            *rOligoLength = i-startIx+1;
+            *rOligoProb = totalProb;
+            return TRUE;
+            }
+        }
+    }
+return FALSE;
+}
+
+
+static boolean hasRepeat(DNA *oligo, int oligoLen)
+/* Returns TRUE if oligo has an internal repeat mod 1, 2, or 3. */
+{
+int mod;
+int i;
+DNA b;
+boolean gotRepeat;
+int repSize;
+int maxRep = (oligoLen+1)/2;
+
+b = oligo[0];
+gotRepeat = TRUE;
+for (i=1; i<oligoLen; ++i)
+    {
+    if (oligo[i] != b)
+        {
+        gotRepeat = FALSE;
+        break;
+        }
+    }
+if (gotRepeat)
+    return TRUE;
+
+gotRepeat = TRUE;
+for (i=2; i<oligoLen; ++i)
+    {
+    if (oligo[i&1] != oligo[i])
+        {
+        gotRepeat = FALSE;
+        break;
+        }
+    }
+if (gotRepeat)
+    return TRUE;
+
+for (repSize = 3; repSize <= maxRep; ++repSize)
+    {
+    mod = 0;
+    gotRepeat = TRUE;
+    for (i=repSize; i<oligoLen; ++i)
+        {
+        if (oligo[mod] != oligo[i])
+            {
+            gotRepeat = FALSE;
+            break;
+            }
+        if (++mod == repSize)
+            mod = 0;
+        }
+    if (gotRepeat)
+        return TRUE;
+    }
+return gotRepeat;
+}
+
+
+
+static boolean ffFindGoodOligo(DNA *needle, int needleLength, double maxProb, double freq[4],
+    DNA **rOligo, int *rOligoLength, double *rOligoProb)
+/* Find an oligo that's suitably improbable and doesn't contain 
+ * short internal repeats. */
+{
+int oligoLen;
+DNA *oligo;
+
+/* Loop around until you get one that doesn't repeat. */
+for (;;)
+    {
+    if (!findImprobableOligo(needle, needleLength, maxProb, freq, rOligo, rOligoLength, rOligoProb))
+        return FALSE;
+    oligoLen = *rOligoLength;
+    oligo = *rOligo;
+    if (hasRepeat(oligo, oligoLen))
+        {
+        DNA *newNeedle = oligo+oligoLen;
+        int newSize = needleLength - (newNeedle-needle);
+        if (newSize <= 0)
+            return FALSE;
+        needle = newNeedle;
+        needleLength = newSize;
+        }
+    else
+        return TRUE;
+    }
+}
+
+static boolean leftNextMatch(struct ffAli *ali, DNA *ns, DNA *ne, DNA *hs, DNA *he, 
+    int gapPenalty, int maxSkip)
+/* Scan to the left for something that matches the next bit of the needle
+ * in the haystack. */
+{
+int haySize = he - hs;
+int needleSize = ne - ns;
+int diagSize = haySize + needleSize;
+int matchSize;
+int i;
+
+/* We take care of bigger skips on the "tile" level. */
+if (diagSize > maxSkip)
+    diagSize = maxSkip;
+/* Scan diagonally... */
+/*
+0 1 2 3
+1 2 3 4
+2 3 4 5
+3 4 5 6
+*/
+for (i=1; i<=diagSize; ++i)
+    {
+    int hOff = i;
+    int nOff = 0;
+    int hDiff = hOff - haySize;
+    matchSize = gapPenalty + digitsBaseTwo(i);
+    if (hDiff > 0)
+        {
+        nOff += hDiff;
+        hOff -= hDiff;
+        }
+    for (;hOff >= 0; --hOff, ++nOff)
+        {
+        int needleLeft = needleSize - nOff;
+        int hayLeft = haySize - hOff;
+        if (matchSize > needleLeft) break;
+        if (matchSize > hayLeft) continue;
+        if (ne[-nOff-1] == he[-hOff-1] && memcmp(ne-nOff-matchSize, he-hOff-matchSize, matchSize) == 0)
+            {
+            ali->nStart = ne - nOff - matchSize;
+            ali->nEnd = ne - nOff;
+            ali->hStart = he - hOff - matchSize;
+            ali->hEnd = he- hOff;
+            return TRUE;
+            }
+        }
+    }
+return FALSE;
+}
+
+
+static boolean rightNextMatch(struct ffAli *ali, DNA *ns, DNA *ne, DNA *hs, DNA *he, 
+    int gapPenalty, int maxSkip)
+/* Scan to the right for something that matches the next bit of the needle
+ * in the haystack. */
+{
+int haySize = he - hs;
+int needleSize = ne - ns;
+int diagSize = haySize + needleSize;
+int matchSize;
+int i;
+
+/* We take care of bigger skips on the "tile" level. */
+if (diagSize > maxSkip)
+    diagSize = maxSkip;
+/* Scan diagonally... */
+/*
+0 1 2 3
+1 2 3 4
+2 3 4 5
+3 4 5 6
+*/
+for (i=1; i<=diagSize; ++i)
+    {
+    int hOff = i;
+    int nOff = 0;
+    int hDiff = hOff - haySize;
+    matchSize = gapPenalty + digitsBaseTwo(i);
+    if (hDiff > 0)
+        {
+        nOff += hDiff;
+        hOff -= hDiff;
+        }
+    for (;hOff >= 0; --hOff, ++nOff)
+        {
+        int needleLeft = needleSize - nOff;
+        int hayLeft = haySize - hOff;
+        if (matchSize > needleLeft) break;
+        if (matchSize > hayLeft) continue;
+        if (ns[nOff] == hs[hOff] && memcmp(ns+nOff, hs+hOff, matchSize) == 0)
+            {
+            ali->nStart = ns + nOff;
+            ali->nEnd = ns + nOff + matchSize;
+            ali->hStart = hs + hOff;
+            ali->hEnd = hs + hOff + matchSize;
+            return TRUE;
+            }
+        }
+    }
+return FALSE;
+}
+
+static boolean expandRight(struct ffAli *ali, DNA *needleStart, DNA *needleEnd,
+    DNA *hayStart, DNA *hayEnd, int numSkips, int gapPenalty, int maxSkip);
+
+
+static boolean expandLeft(struct ffAli *ali, DNA *needleStart, DNA *needleEnd,
+    DNA *hayStart, DNA *hayEnd, int numSkips, int gapPenalty, int maxSkip)
+/* Given a matching segment, try to expand the aligned parts to the
+ * right. */
+{
+DNA *ns = ali->nStart;
+DNA *hs = ali->hStart;
+int score;
+DNA *oldNs = ns;
+
+for (;;)
+    {
+    while (ns > needleStart && hs > hayStart && ns[-1] == hs[-1])
+        {
+        --hs;
+        --ns;
+        }
+    if (ns <= needleStart || hs <= hayStart)
+        {
+        ali->nStart = ns;
+        ali->hStart = hs;
+        return ns != oldNs;
+        }
+    /* Find fuzzy score to the left. */
+        {
+        int windowSize = 5;
+        int nSize = ns-needleStart;
+        int hSize = hs-hayStart;
+        if (windowSize > nSize) windowSize = nSize;
+        if (windowSize > hSize) windowSize = hSize;
+        if (windowSize > 0)
+            score = dnaScoreMatch(ns-windowSize, hs-windowSize, windowSize); 
+        else
+            score = -1;
+
+        if (score >= windowSize-2)
+            {
+            hs -= windowSize;
+            ns -= windowSize;
+            }
+        else if (--numSkips >= 0)
+            {
+            struct ffAli *newAli = ffNeedMem(sizeof(*newAli));
+            ali->nStart = ns;
+            ali->hStart = hs;
+            if (ns - needleStart < 3 || 
+                !leftNextMatch(newAli, needleStart, ns, hayStart, hs, gapPenalty, maxSkip))
+                {
+                return ns != oldNs; /* We did our best... */
+                }
+            newAli->right = ali;
+            newAli->left = ali->left;
+            if (ali->left)
+                ali->left->right = newAli;
+            ali->left = newAli;
+            ali = newAli;
+            expandRight(ali, needleStart, ns, hayStart, hs, 0, gapPenalty, maxSkip);
+            ns = ali->nStart;
+            hs = ali->hStart;
+            }
+        else
+            {
+            ali->nStart = ns;
+            ali->hStart = hs;
+            return ns != oldNs;
+            }
+        }
+    }
+}
+
+static boolean expandRight(struct ffAli *ali, DNA *needleStart, DNA *needleEnd,
+    DNA *hayStart, DNA *hayEnd, int numSkips, int gapPenalty, int maxSkip)
+/* Given a matched segment, try to expand it to the right. */
+{
+int score;
+DNA *ne = ali->nEnd;
+DNA *he = ali->hEnd;
+DNA *oldNe = ne;
+
+for (;;)
+    {
+    /* Expand as far to the right as you can keeping perfect match */
+    while (ne < needleEnd && he < hayEnd && *ne == *he)
+        {
+        ++he;
+        ++ne;
+        }
+
+    /* Check to see if have come to the end. */
+    if (ne >= needleEnd || he >= hayEnd)
+        {
+        ali->nEnd = ne;
+        ali->hEnd = he;
+        return oldNe != ne;
+        }
+
+    /* Find fuzzy score to the right. */
+        {
+        int windowSize = 5;
+        int nSize = needleEnd-ne;
+        int hSize = hayEnd - he;
+        if (windowSize > nSize) windowSize = nSize;
+        if (windowSize > hSize) windowSize = hSize;
+        if (windowSize > 0)
+            score = dnaScoreMatch(ne, he, windowSize); 
+        else
+            score = -1;
+
+        if (score >= windowSize-2)
+            {
+            he += windowSize;
+            ne += windowSize;
+            }
+        else if (--numSkips >= 0)
+            {
+            struct ffAli *newAli = ffNeedMem(sizeof(*newAli));
+            ali->nEnd = ne;
+            ali->hEnd = he;
+            if (needleEnd - ne < 3 || 
+                !rightNextMatch(newAli, ne, needleEnd, he, hayEnd, gapPenalty, maxSkip))
+                {
+                return oldNe != ne; /* We did our best... */
+                }
+            newAli->left = ali;
+            newAli->right = ali->right;
+            if (ali->right)
+                ali->right->left = newAli;
+            ali->right = newAli;
+            ali = newAli;
+            expandLeft(ali, ne, needleEnd, he, hayEnd, 0, gapPenalty, maxSkip);
+            ne = ali->nEnd;
+            he = ali->hEnd;
+            }
+        else 
+            {
+            ali->nEnd = ne;
+            ali->hEnd = he;
+            return oldNe != ne;
+            }
+        }
+    }
+}
+
+static boolean exactFind(DNA *needle, int nSize, DNA *hay, int hSize, int *hOffset)
+/* Look for exact match of needle in haystack. */
+{
+DNA firstC = needle[0];
+DNA *restOfNeedle = needle+1;
+int i;
+int endIx = hSize - nSize;
+int restSize = nSize-1;
+
+for (i = 0; i<=endIx; ++i)
+    {
+    if (firstC == hay[i])
+        {
+	if (memcmp(restOfNeedle, hay+i+1, restSize) == 0)
+	    {
+	    *hOffset = i;
+	    return TRUE;
+	    }
+	}
+    }
+*hOffset = -1;
+return FALSE;
+}
+
+#ifdef UNUSED
+static int countAlis(struct ffAli *ali)
+/* Count number of blocks in alignment. */
+{
+int count = 0;
+if (ali == NULL)
+    return 0;
+while (ali->left)
+    ali = ali->left;
+while (ali)
+    {
+    count += 1;
+    ali = ali->right;
+    }
+return count;
+}
+#endif /* UNUSED */
+
+
+static struct ffAli *reconsiderAlignedGaps(struct ffAli *ali)
+/* If the gap between two blocks is the same in both needle and
+ * haystack, see if we're actually better off with the two
+ * blocks merged together. */
+{
+struct ffAli *a = NULL;
+struct ffAli *left = NULL;
+
+if (ali == NULL)
+    return NULL;
+a = ali;
+for (;;)
+    {
+    int gapSize;
+
+    /* Advance to next ali */
+    left = a;
+    a = a->right;
+    if (a == NULL)
+        break;
+    gapSize = a->nStart - left->nEnd;
+    if (gapSize == a->hStart - left->hEnd)
+        {
+        int gapScore;
+        int matchScore;
+        gapScore = -ffCdnaGapPenalty(left, a);
+        matchScore = dnaScoreMatch(left->nEnd, left->hEnd, gapSize);
+        if (matchScore > gapScore)
+            {
+            /* Make current cover left. RemoveEmpty will take
+             * care of empty shell of left later. */
+            a->hStart = left->hEnd = left->hStart;
+            a->nStart = left->nEnd = left->nStart;
+            }
+        }
+    }
+return ali;
+}
+
+static struct ffAli *trimAlis(struct ffAli *aliList)
+/* If ends of an ali don't match trim them off. */
+{
+struct ffAli *ali;
+int trimCount = 0;
+for (ali = aliList; ali != NULL; ali = ali->right)
+    {
+    while (ali->nStart[0] != ali->hStart[0] && ali->nStart < ali->nEnd)
+        {
+        ali->nStart += 1;
+        ali->hStart += 1;
+        ++trimCount;
+        }
+    while (ali->nEnd[-1] != ali->hEnd[-1] && ali->nEnd > ali->nStart)
+        {
+        ali->nEnd -= 1;
+        ali->hEnd -= 1;
+        ++trimCount;
+        }
+    }
+return aliList;
+}
+
+static int extendThroughN;  /* Can extend through blocks of N's? */
+
+void setFfExtendThroughN(boolean val)
+/* Set whether or not can extend through N's. */
+{
+extendThroughN = val;
+}
+
+boolean expandThroughNRight(struct ffAli *ali, DNA *needleStart, DNA *needleEnd,
+    DNA *hayStart, DNA *hayEnd)
+/* Expand through up to three N's to the left. */
+{
+DNA *nEnd = ali->nEnd;
+DNA *hEnd = ali->hEnd;
+DNA n,h;
+boolean expanded = FALSE;
+while (nEnd < needleEnd && hEnd < hayEnd)
+    {
+    n = *nEnd;
+    h = *hEnd;
+    if ((n == h) || 
+    	(n == 'n' && 
+    	(extendThroughN || nEnd + 3 >= needleEnd || nEnd[1] != 'n' || nEnd[2] != 'n' || nEnd[3] != 'n')) ||
+	(h == 'n' && 
+	(extendThroughN || hEnd + 3 >= hayEnd || hEnd[1] != 'n' || hEnd[2] != 'n' || hEnd[3] != 'n')))
+        {
+        nEnd += 1;
+        hEnd += 1;
+        expanded = TRUE;
+        }
+    else
+        break;
+    }
+ali->nEnd = nEnd;
+ali->hEnd = hEnd;
+return expanded;
+}
+
+boolean expandThroughNLeft(struct ffAli *ali, DNA *needleStart, DNA *needleEnd,
+    DNA *hayStart, DNA *hayEnd)
+/* Expand through up to three N's to the left. */
+{
+DNA *nStart = ali->nStart-1;
+DNA *hStart = ali->hStart-1;
+DNA n,h;
+boolean expanded = FALSE;
+while (nStart >= needleStart && hStart >= hayStart)
+    {
+    n = *nStart;
+    h = *hStart;
+    if ((n == h) ||
+	(n == 'n' && (extendThroughN || nStart - 3 < needleStart || nStart[-1] != 'n' || nStart[-2] != 'n' || nStart[-3] != 'n')) ||
+	(h == 'n' && (extendThroughN || hStart - 3 < hayStart || hStart[-1] != 'n' || hStart[-2] != 'n' || hStart[-3] != 'n')))
+        {
+        nStart -= 1;
+        hStart -= 1;
+        expanded = TRUE;
+        }
+    else
+        break;
+    }
+ali->nStart = nStart + 1;
+ali->hStart = hStart + 1;
+return expanded;
+}
+
+static struct ffAli *expandAlis(struct ffAli *ali, DNA *nStart, DNA *nEnd, DNA *hStart, DNA *hEnd, 
+    int gapPenalty, int maxSkip)
+/* Expand alignment to cover in-between tiles as well. */
+{
+struct ffAli *a, *left, *right;
+DNA *ns, *ne, *hs, *he;
+boolean expanded = TRUE;
+
+while (expanded)
+    {
+    expanded = FALSE;
+    /* Loop through expanding three times. */
+    /* First just expand through N's that don't require an insertion/deletion. */
+    for (a = ali; a != NULL; a = a->right)
+        {
+        if ((left = a->left) != NULL)
+            {
+            ns = left->nEnd;
+            hs = left->hEnd;
+            }
+        else
+            {
+            ns = nStart;
+            hs = hStart;
+            }
+        if ((right = a->right) != NULL)
+            {
+            ne = right->nStart;
+            he = right->hStart;
+            }
+        else
+            {
+            ne = nEnd;
+            he = hEnd;
+            }
+        expanded |= expandThroughNLeft(a, ns, ne, hs, he);
+        expanded |= expandThroughNRight(a, ns, ne, hs, he);
+        }
+    /* Second do other expansion that doesn't require an insertion/deletion. */
+    for (a = ali; a != NULL; a = a->right)
+        {
+        if ((left = a->left) != NULL)
+            {
+            ns = left->nEnd;
+            hs = left->hEnd;
+            }
+        else
+            {
+            ns = nStart;
+            hs = hStart;
+            }
+        if ((right = a->right) != NULL)
+            {
+            ne = right->nStart;
+            he = right->hStart;
+            }
+        else
+            {
+            ne = nEnd;
+            he = hEnd;
+            }
+        expanded |= expandLeft(a, ns, ne, hs, he, 0, gapPenalty, maxSkip);
+        expanded |= expandRight(a, ns, ne, hs, he, 0, gapPenalty, maxSkip);
+        }
+    /* Finally do insertion/deletion. */
+    for (a = ali; a != NULL; a = a->right)
+        {
+        if ((left = a->left) != NULL)
+            {
+            ns = left->nEnd;
+            hs = left->hEnd;
+            }
+        else
+            {
+            ns = nStart;
+            hs = hStart;
+            }
+        if ((right = a->right) != NULL)
+            {
+            ne = right->nStart;
+            he = right->hStart;
+            }
+        else
+            {
+            ne = nEnd;
+            he = hEnd;
+            }
+        expanded |= expandLeft(a, ns, ne, hs, he, 1, gapPenalty, maxSkip);
+        expanded |= expandRight(a, ns, ne, hs, he, 1, gapPenalty, maxSkip);
+        }
+    while (ali->left)
+        ali = ali->left;
+    }
+return ali;
+}
+
+
+
+DNA *matchInMem(DNA *ns, DNA *ne, DNA *hs, DNA *he)
+{
+int nLen = ne - ns;
+DNA c = *ns++;
+he -= nLen;
+nLen -= 1;
+while (hs < he)
+    {   
+    if (*hs++ == c && memcmp(ns, hs, nLen) == 0)
+        {
+        return hs-1;
+        }
+    }
+return NULL;
+}
+
+struct ffAli *findAliBetween(DNA *tile, int tileSize, DNA *ns, DNA *ne, DNA *hs, DNA *he)
+{
+DNA *match;
+DNA *tileEnd = tile + tileSize;
+int tries = 0;
+for (;;)
+    {
+    if ((match = matchInMem(tile, tileEnd, hs, he)) == NULL)
+        return NULL;
+    if (matchInMem(tile, tileEnd, match+1, he) == NULL)
+        {
+        /* Got exactly one match, whoopie! */
+        struct ffAli *ali = ffNeedMem(sizeof(*ali));
+        ali->nStart = tile;
+        ali->nEnd = tileEnd;
+        ali->hStart = match;
+        ali->hEnd = match + (tileEnd-tile);
+        ffExpandExactLeft(ali, ns, hs);
+        ffExpandExactRight(ali, ne, he);
+        return ali;
+        }
+
+    /* Got more than one match.  Expand tile to make it more specific.
+     * In general first add base to start, then base to beginning.  If
+     * at beginning or end already are constrained.  If already spanning
+     * full needle, can't expand, so you're done. */
+    if (tile <= ns)
+        {
+        if (tileEnd >= ne)
+            return NULL;
+        ++tileEnd;
+        }
+    else if (tile >= tileEnd)
+        {
+        --tile;
+        }
+    else if (tries & 1)
+        {
+        ++tileEnd;
+        }
+    else
+        {
+        --tile;
+        }    
+    ++tries;
+    }    
+}
+
+double evalExactAli(struct ffAli *ali, DNA *ns, DNA *ne, DNA *hs, DNA *he, int numTiles,
+    double freq[4])
+{
+int haySize = he-hs;
+double prob = 1.0;
+double allPossibles = haySize*numTiles;
+
+for (;ali != NULL;ali=ali->right)
+    {
+    double p = oligoProb(ali->nStart, ali->nEnd - ali->nStart, freq) * allPossibles;
+    if (p < 1.0)
+        prob *= p;
+    }
+return prob;
+}
+
+void ffUnlink(struct ffAli **pList, struct ffAli *el)
+/* Unlink element from doubly linked list. If leftmost
+ * element update list pointer. */
+{
+struct ffAli *list = *pList;
+struct ffAli *right = el->right;
+struct ffAli *left = el->left;
+
+if (el == list)    /* If first element need to update list. */
+    *pList = right;
+if (right != NULL)
+    right->left = left;
+if (left != NULL)
+    left->right = right;
+el->left = el->right = NULL;
+}
+
+void unlinkAli(struct ffAli **pList, struct ffAli *ali)
+/* Unlink ali from list. */
+{
+ffUnlink(pList, ali);
+}
+
+struct protoGene
+    {
+    struct protoGene *left;
+    struct protoGene *right;
+    struct ffAli *hits;
+    DNA *hStart, *hEnd, *nStart, *nEnd;
+    int score;
+    };
+
+int cmpProtoSize(const void *va, const void *vb)
+/* Sort biggest size first. */
+{
+const struct protoGene *a = *((struct protoGene **)va);
+const struct protoGene *b = *((struct protoGene **)vb);
+int aSize, bSize;
+aSize = a->nEnd - a->nStart;
+bSize = b->nEnd - b->nStart;
+return (bSize - aSize);
+}
+
+int cmpProtoNeedle(const void *va, const void *vb)
+/* Sort smallest offset into needle first. */
+{
+const struct protoGene *a = *((struct protoGene **)va);
+const struct protoGene *b = *((struct protoGene **)vb);
+return (a->nStart - b->nStart);
+}
+
+int cmpProtoScore(const void *va, const void *vb)
+/* Sort biggest score first. */
+{
+const struct protoGene *a = *((struct protoGene **)va);
+const struct protoGene *b = *((struct protoGene **)vb);
+return (b->score - a->score);
+}
+
+boolean canAdd(struct protoGene *a, struct protoGene *b)
+/* Can b fit into a?  It can if it doesn't overlap
+ * by more than 1/4 with what's already there. */
+{
+struct ffAli *pa;
+DNA *bnEnd = b->nEnd;
+DNA *bnStart = b->nStart;
+DNA *bhEnd = b->hEnd;
+DNA *bhStart = b->hStart;
+int bSize = bnEnd - bnStart;
+int maxOverlap;
+for (pa = a->hits; pa != NULL; pa = pa->right)
+    {
+    int aSize = pa->nEnd - pa->nStart;
+    DNA *start = (bnStart > pa->nStart ? bnStart : pa->nStart);
+    DNA *end = (bnEnd < pa->nEnd ? bnEnd : pa->nEnd);
+    maxOverlap = (aSize < bSize ? aSize : bSize) / 4;
+    if (maxOverlap < 2) maxOverlap = 2;
+    if (end - start >= maxOverlap)
+       return FALSE;
+    start = (bhStart > pa->hStart ? bhStart : pa->hStart);
+    end = (bhEnd < pa->hEnd ? bhEnd : pa->hEnd);
+    if (end - start >= maxOverlap)
+        return FALSE;
+    }
+return TRUE;
+}
+
+boolean bestMerger(struct protoGene *list, enum ffStringency stringency,
+    DNA *ns, DNA *hs, struct protoGene **retA, struct protoGene **retB)
+/* Figure out best scoring merger in list. */
+{
+int bestScore = -0x7fffffff;
+int score;
+struct protoGene *bestA = NULL, *bestB = NULL;
+struct protoGene *a, *b;
+boolean isCdna = (stringency == ffCdna);
+
+if (list == NULL)
+    return FALSE;
+
+for (a = list; a != NULL; a = a->right)
+    {
+    for (b = a->right; b != NULL; b = b->right)
+        {
+        if (canAdd(a,b))
+            {
+            int hGap = b->hStart - a->hEnd;
+            int nGap = b->nStart - a->nEnd;
+            if (hGap < 0)
+                {
+                hGap = -8*hGap;
+                if (!isCdna || hGap < 32)
+                    hGap = (hGap*hGap);
+                }
+            if (nGap < 0)
+                nGap = -8*nGap;
+            score = -hGap - nGap*nGap;
+            if (score > bestScore)
+                {
+                bestA = a;
+                bestB = b;
+                bestScore = score;
+                }
+            }
+        }
+    }
+*retA = bestA;
+*retB = bestB;
+return bestA != NULL;
+}
+
+void mergeProtoGenes(struct protoGene **pList, struct protoGene *a, struct protoGene *b)
+/* Absorb protoGene b into protoGene a. */
+{
+ffUnlink((struct ffAli**)pList, (struct ffAli *)b);
+ffCat(&a->hits, &b->hits);
+if (a->hStart > b->hStart)
+    a->hStart = b->hStart;
+if (a->nStart > b->nStart)
+    a->nStart = b->nStart;
+if (a->hEnd < b->hEnd)
+    a->hEnd = b->hEnd;
+if (a->nEnd < b->nEnd)
+    a->nEnd = b->nEnd;
+}
+
+void lumpProtoGenes(struct protoGene **pList,
+    DNA *ns, DNA *hs, enum ffStringency stringency)
+/* Lump together as many protogenes as we can. */
+{
+struct protoGene *a, *b;
+
+while (bestMerger(*pList, stringency, ns, hs, &a, &b))
+    {
+    mergeProtoGenes(pList, a, b);
+    }
+}
+
+struct protoGene *lumpHits(struct ffAli **pHitList, DNA *ns, DNA *hs)
+/* Lump together as many hits as can. Criteria - they must be close
+ * to same "diagonal." That is the distance between them must be
+ * nearly the same in the needle and the haystack. */
+{
+struct protoGene proto;
+struct protoGene *retProto;
+struct ffAli *ali, *nextAli;
+int dif, lastDif;
+int lumpCount = 1;
+
+if ((ali = *pHitList) == NULL)
+    return NULL;
+
+/* Move first hit onto our crude exon. */
+nextAli = ali->right;
+proto.left = proto.right = NULL;
+unlinkAli(pHitList, ali);
+proto.hits = ali;
+proto.hStart = ali->hStart;
+proto.hEnd = ali->hEnd;
+proto.nStart = ali->nStart;
+proto.nEnd = ali->nEnd;
+proto.score = 0;
+lastDif = ali->hStart - ali->nStart;
+
+/* Go through rest of list and put others that are close to
+ * on the same diagonal onto this exon. */
+while ((ali = nextAli) != NULL)
+    {
+    nextAli = ali->right;
+    dif = ali->hStart - ali->nStart;
+    if (lastDif - 2 <= dif && dif <= lastDif + 2)
+        {
+        lastDif = dif;
+        unlinkAli(pHitList, ali);
+        ali->left = proto.hits;
+        proto.hits = ali;
+        proto.hEnd = ali->hEnd;
+        proto.nEnd = ali->nEnd;
+        ++lumpCount;
+        }
+    }
+proto.hits = ffMakeRightLinks(proto.hits);
+retProto = ffNeedMem(sizeof(*retProto));
+memcpy(retProto, &proto, sizeof(*retProto));
+return retProto;
+}
+
+#ifdef OLD
+void removeThrowbackHits(struct protoGene *proto)
+/* Remove hits that cause backtracking in hay coordinates. */
+{
+struct ffAli *left, *right;
+boolean gotThrowback = FALSE;
+
+right = proto->hits;
+for (;;)
+    {
+    left = right;
+    right = right->right;
+    if (right == NULL)
+        break;
+    if (left->hStart > right->hStart)
+        {
+	right->hStart = right->hEnd = left->hEnd;
+	right->nStart = right->nEnd = left->nEnd;
+	gotThrowback = TRUE;
+        }
+    }
+if (gotThrowback)
+    proto->hits = ffRemoveEmptyAlis(proto->hits, FALSE);
+}
+#endif /* OLD */
+
+
+void thinProtoList(struct protoGene **pList, int maxToTake)
+/* Reduce list to only top scoring members.  At this
+ * point protoList is singly linked on left. */
+{
+struct protoGene *newList = NULL, *pg, *next;
+int i;
+
+slSort(pList, cmpProtoScore);
+for (pg=*pList, i=0; pg != NULL && i < maxToTake; pg = next, ++i)
+    {
+    next = pg->left;
+    pg->left = newList;
+    newList = pg;
+    }
+*pList = newList;
+}
+
+static struct ffAli *weaveAli(struct ffAli *hitList, 
+    DNA *ns, DNA *ne, DNA *hs, DNA *he, double freq[4], int *rBestVal, 
+    enum ffStringency stringency)
+/* Weave together best looking alignment out of the hitList list. */
+{
+struct ffAli *ali, *lastAli;
+struct protoGene *proto, *protoList = NULL;
+int protoCount = 0;
+
+/* Sort initial hits and remove duplicates. */
+ffAliSort(&hitList, ffCmpHitsHayFirst);
+ali = hitList;
+for (;;)
+    {
+    lastAli = ali;
+    if ((ali = ali->right) == NULL)
+        break;
+    if (ali->hStart == lastAli->hStart && ali->hEnd == lastAli->hEnd
+       && ali->nStart == lastAli->nStart && ali->nEnd == lastAli->nEnd)
+       {
+       unlinkAli(&hitList, lastAli);
+       }
+    }
+
+/* Lump together things which look to be separated only by small
+ * amounts of noise. */
+while ((proto = lumpHits(&hitList, ns, hs)) != NULL)
+    {
+    proto->left = protoList;
+    protoList = proto;
+    ++protoCount;
+    }
+if (protoCount > 200)
+    {
+    thinProtoList(&protoList, 200);
+    }
+protoList = (struct protoGene *)ffMakeRightLinks((struct ffAli*)protoList);
+
+
+/* Lump together any other ones that can, starting with ones
+ * that go together best. */
+ffAliSort((struct ffAli**)(void*)&protoList, cmpProtoNeedle);
+lumpProtoGenes(&protoList, ns, hs, stringency );
+for (proto = protoList; proto != NULL; proto = proto->right)
+    {
+    ffAliSort((struct ffAli**)&proto->hits, ffCmpHitsNeedleFirst);
+/*    removeThrowbackHits(proto); */
+    proto->score = ffScore(proto->hits,stringency);
+    }
+
+/* Sort by score and return the best. */
+ffAliSort((struct ffAli **)(void*)&protoList, cmpProtoScore);
+*rBestVal = protoList->score;
+return protoList->hits;
+}
+
+/* This set of variables is set before calling the recursive tile finders - the
+ * below two routines. */
+static double rwFreq[4];
+static boolean rwIsCdna;
+static boolean rwCheckGoodEnough;
+
+static struct ffAli *rwFindTilesBetween(DNA *ns, DNA *ne, DNA *hs, DNA *he, 
+    enum ffStringency stringency, double probMax)
+/* Search for more or less regularly spaced exact matches that are
+ * in the right order. */
+{
+int searchOffset;
+int endTileOffset;
+int haySize = he - hs;
+int needleSize = ne - ns;
+int numTiles = 0;
+int bestWeaveVal;
+int tileIx;
+struct ffAli *hitList = NULL;
+struct ffAli *bestAli;
+struct ffAli *ali;
+int possibleTiles;
+double tileProbOne;
+
+possibleTiles = (haySize - nextPowerOfFour(needleSize));
+if (possibleTiles < 1) possibleTiles = 1;
+tileProbOne = probMax/possibleTiles;
+
+searchOffset = 0;
+endTileOffset = 0;
+tileIx = 0;
+for (;;)
+    {
+    DNA *tile;
+    int tileSize;
+    double tileProb;
+    DNA *h = hs;
+
+    searchOffset = endTileOffset;
+    if (!ffFindGoodOligo(ns+searchOffset, needleSize-searchOffset, tileProbOne,
+        rwFreq, &tile, &tileSize, &tileProb))
+        {
+        break;
+        }
+    /* Find all parts that match the tile. */
+    for (;;)
+        {
+        if ((h = matchInMem(tile, tile+tileSize, h, he)) == NULL)
+            break;
+        ali = ffNeedMem(sizeof(*ali));
+        ali->hStart = h;
+        ali->hEnd = ali->hStart + tileSize;
+        ali->nStart = tile;
+        ali->nEnd = tile + tileSize;
+        ali->left = hitList;
+        hitList = ali;
+        h += tileSize;
+        } 
+    endTileOffset = tile + tileSize - ns;
+    ++numTiles;
+    }
+if (hitList == NULL)
+    return NULL;
+
+hitList = ffMakeRightLinks(hitList);
+for (ali = hitList; ali != NULL; ali = ali->right)
+    {
+    ffExpandExactLeft(ali, ns, hs);
+    ffExpandExactRight(ali, ne, he);
+    }
+bestAli = weaveAli(hitList, ns, ne, hs, he, rwFreq, &bestWeaveVal, stringency);
+if (rwCheckGoodEnough)
+    {
+    double prob;
+    prob = evalExactAli(bestAli, ns, ne, hs, he, numTiles, rwFreq);
+    if (prob > 0.1)
+        return NULL;
+    rwCheckGoodEnough = FALSE;
+    }
+
+return bestAli;
+}
+
+static struct ffAli *exactAli(DNA *ns, DNA *ne, DNA *hs, DNA *he)
+/* Return alignment based on exact match. */
+{
+int exactOffset;
+if (exactFind(ns, ne-ns, hs, he-hs, &exactOffset))
+    {
+    struct ffAli *ali = ffNeedMem(sizeof(*ali));
+    ali->nStart = ns;
+    ali->nEnd = ne;
+    ali->hStart = hs + exactOffset;
+    ali->hEnd = ali->hStart + (ne - ns);
+    if (ali->hEnd > he)
+        ali->hEnd = he;
+    return ali;
+    }
+else
+    return NULL;
+}
+
+static struct ffAli *recursiveWeave(DNA *ns, DNA *ne, DNA *hs, DNA *he, 
+    enum ffStringency stringency, double probMax, int level, int orientation)
+/* Find a set of tiles, then recurse to find set of tiles between the tiles
+ * at somewhat lower stringency. */
+{
+struct ffAli *left = NULL, *right = NULL, *aliList;
+
+if ((left = exactAli(ns, ne, hs, he)) != NULL)
+    return left;
+if (stringency == ffExact)
+    return NULL;
+
+aliList = rwFindTilesBetween(ns, ne, hs, he, stringency, probMax);
+if (aliList != NULL)
+    {
+    DNA *lne, *rns, *lhe, *rhs;
+    int ndif, hdif;
+    right = aliList;
+    if (orientation == 0)
+        orientation = ffIntronOrientation(aliList);
+    for (;;)
+        {
+        /* Figure out the end points to recurse to. */
+        if (left != NULL)
+            {
+            lne = left->nEnd;
+            lhe = left->hEnd;
+            }
+        else
+            {
+            lne = ns;
+            lhe = hs;
+            }
+        if (right != NULL)
+            {
+            rns = right->nStart;
+            rhs = right->hStart;
+            }
+        else
+            {
+            rns = ne;
+            rhs = he;
+            }
+        ndif = rns-lne;
+        hdif = rhs-lhe;
+        /* If a big enough gap left recurse. */
+        if (ndif >= 5 && hdif >= 5)
+            {
+            struct ffAli *newLeft = NULL, *newRight;
+
+	    newLeft = recursiveWeave(lne, rns, lhe, rhs, stringency, probMax*2, level+1, 
+		orientation);
+            if (newLeft != NULL)
+                {
+                /* Insert new tiles between left and right. */
+                
+                /* Find right end of tile set. */
+                newRight = newLeft;
+                while (newRight->right != NULL)
+                    newRight = newRight->right;
+                
+                
+                if (left != NULL)
+                    {
+                    left->right = newLeft;
+                    newLeft->left = left;
+                    }
+                else
+                    {
+                    aliList = newLeft;
+                    }
+                if (right != NULL)
+                    {
+                    right->left = newRight;
+                    newRight->right = right;
+                    }
+                }
+            }
+        if ((left = right) == NULL)
+            break;
+        right = right->right;
+        }
+    }
+return aliList;
+}
+
+
+static struct ffAli *findWovenTiles(DNA *ns, DNA *ne, DNA *hs, DNA *he, enum ffStringency stringency)
+{
+struct ffAli *bestAli;
+int haySize = he - hs;
+int needleSize = ne - ns;
+static double tileStrinProbMult[] = { 0.0001, 0.0005, 0.0005, 0.5, };
+                                    /* exact  cDNA        tight    loose */
+if (needleSize < 2 || haySize < 2)  /* Be serious man! */
+    return NULL;
+
+/* Set up rwVariables - essentially locals except that they don't change over the course
+ * of the recursion. */
+makeFreqTable(hs, haySize, rwFreq);
+rwIsCdna = (stringency == ffCdna);
+rwCheckGoodEnough = (stringency == ffTight || stringency == ffCdna);
+
+bestAli = recursiveWeave(ns, ne, hs, he, stringency, tileStrinProbMult[stringency], 1, 0);
+
+return bestAli;
+}
+
+
+static struct ffAli *findBestAli(DNA *ns, DNA *ne, DNA *hs, DNA *he, enum ffStringency stringency)
+{
+static int iniExpGapPen[] = {0 /* (exact) */, 4 /* cDna */, 4 /* tight */, 4 /* loose */};
+static int addExpGapPen[] = {0 /* (exact) */, 3 /* cDna */, 3 /* tight */, 3 /* loose */};
+static int midTileMinSize[] ={0 /*(exact) */,12 /* cDNA */, 12 /* tight */, 4 /* loose */};
+
+struct ffAli *bestAli;
+int matchSize;
+
+matchSize = nextPowerOfFour(he-hs)+1;
+if (matchSize < midTileMinSize[stringency])
+    matchSize = midTileMinSize[stringency];
+
+bestAli = findWovenTiles(ns, ne, hs, he, stringency);
+if (bestAli == NULL)
+    return NULL;
+
+bestAli = ffMergeNeedleAlis(bestAli, FALSE);
+bestAli = expandAlis(bestAli,ns,ne,hs,he,iniExpGapPen[stringency], 1);
+bestAli = ffMergeNeedleAlis(bestAli, FALSE);
+bestAli = expandAlis(bestAli,ns,ne,hs,he,addExpGapPen[stringency], 2*matchSize);
+bestAli = trimAlis(bestAli);
+bestAli = ffMergeNeedleAlis(bestAli, FALSE);
+bestAli = ffMergeHayOverlaps(bestAli);
+bestAli = reconsiderAlignedGaps(bestAli);
+bestAli = ffRemoveEmptyAlis(bestAli, FALSE);
+bestAli = ffMergeNeedleAlis(bestAli, FALSE);
+if (stringency == ffCdna)
+    ffSlideIntrons(bestAli);
+bestAli = ffRemoveEmptyAlis(bestAli, FALSE);
+return bestAli;
+}
+
+
+static struct ffAli *saveAliToPermanentMem(struct ffAli *volatileAli)
+/* Save alignment to memory that doesn't get thrown away. */
+{
+struct ffAli *leftList = NULL;
+struct ffAli *newAli, *ali;
+struct ffAli *rightList = NULL;
+
+/* Allocate memory, copy contents and set left pointer. */
+for (ali = volatileAli; ali != NULL; ali = ali->right)
+    {
+    newAli = needMem(sizeof(*newAli));
+    if (newAli == NULL)
+        {
+        slFreeList(leftList);
+        ffAbort();
+        }
+    memcpy(newAli, ali, sizeof(*newAli));
+    newAli->left = leftList;
+    leftList = newAli;
+    }
+
+/* Set right pointer. */
+for (ali = leftList; ali != NULL; ali = ali->left)
+    {
+    ali->right = rightList;
+    rightList = ali;
+    }
+return rightList;
+}
+
+struct ffAli *ffFind(DNA *needleStart, DNA *needleEnd, DNA *hayStart, DNA *hayEnd,
+     enum ffStringency stringency)
+/* Return an alignment of needle in haystack. */
+{
+struct ffAli *bestAli;
+int status;
+
+assert(needleStart <= needleEnd);
+assert(hayStart <= hayEnd);
+
+ffMemInit();
+dnaUtilOpen();
+
+
+/* Set up error recovery. */
+status = setjmp(ffRecover);
+if (status == 0)    /* Always true except after long jump. */
+    {
+    pushAbortHandler(ffAbort);
+    bestAli = findBestAli(needleStart, needleEnd, hayStart, hayEnd, stringency);
+    ffCountGoodEnds(bestAli);
+    bestAli = saveAliToPermanentMem(bestAli);
+    }
+else    /* They long jumped here because of an error. */
+    {
+    bestAli = NULL;
+    }
+popAbortHandler();
+ffMemCleanup();
+return bestAli;
+}
+
+boolean ffFindAndScore(DNA *needle, int needleSize, DNA *haystack, int haySize,
+    enum ffStringency stringency, struct ffAli **pAli, boolean *pRcNeedle, int *pScore)
+/* Return TRUE if find an allignment using needle, or reverse complement of 
+ * needle to search haystack. DNA must be lower case. If pScore is non-NULL returns
+ * score of alignment. */
+{
+int fScore, rScore;
+struct ffAli *fAli, *rAli;
+
+/* Get forward alignment and score it. */
+fAli = ffFind(needle, needle+needleSize, haystack, haystack+haySize, stringency);
+fScore = ffScore(fAli,stringency);
+
+/* Get reverse alignment and score it. */
+reverseComplement(needle, needleSize);
+rAli = ffFind(needle, needle+needleSize, haystack, haystack+haySize, stringency);
+rScore = ffScore(rAli,stringency);
+reverseComplement(needle, needleSize);
+
+/* If no good alignment on either strand return FALSE. */
+if (fAli == NULL && rAli == NULL)
+    {
+    *pAli = NULL;
+    return FALSE;
+    }
+
+/* Return TRUE with best alignment.  Free the other one. */
+if (fScore > rScore)
+    {
+    *pAli = fAli;
+    *pRcNeedle = FALSE;
+    if (pScore != NULL)
+        *pScore = fScore;
+    ffFreeAli(&rAli);
+    }   
+else
+    {
+    *pAli = rAli;
+    *pRcNeedle = TRUE;
+    if (pScore != NULL)
+        *pScore = rScore;
+    ffFreeAli(&fAli);
+    }
+return TRUE;
+}
+
+boolean ffFindEitherStrandN(DNA *needle, int needleSize, DNA *haystack, int haySize,
+    enum ffStringency stringency, struct ffAli **pAli, boolean *pRcNeedle)
+/* Return TRUE if find an allignment using needle, or reverse complement of 
+ * needle to search haystack. DNA must be lower case. */
+{
+return ffFindAndScore(needle, needleSize, haystack, haySize, stringency, pAli, pRcNeedle, NULL);
+}
+
+boolean ffFindEitherStrand(DNA *needle, DNA *haystack, enum ffStringency stringency,
+    struct ffAli **pAli, boolean *pRcNeedle)
+/* Return TRUE if find an alignment using needle, or reverse complement of 
+ * needle to search haystack. DNA must be lower case. Needle and haystack
+ * are zero terminated. */
+{
+return ffFindEitherStrandN(needle, strlen(needle), haystack, strlen(haystack),
+stringency, pAli, pRcNeedle);
+}
diff --git a/jkOwnLib/genoFind.c b/jkOwnLib/genoFind.c
new file mode 100644
index 0000000..c551900
--- /dev/null
+++ b/jkOwnLib/genoFind.c
@@ -0,0 +1,2255 @@
+/* genoFind - Quickly find where DNA occurs in genome.. */
+/* Copyright 2001-2005 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include <signal.h>
+#include "obscure.h"
+#include "dnautil.h"
+#include "dnaseq.h"
+#include "nib.h"
+#include "twoBit.h"
+#include "fa.h"
+#include "dystring.h"
+#include "errabort.h"
+#include "sig.h"
+#include "ooc.h"
+#include "genoFind.h"
+#include "trans3.h"
+#include "binRange.h"
+
+
+char *gfSignature()
+/* Return signature that starts each command to gfServer. Helps defend 
+ * server from confused clients. */
+{
+static char signature[] = "0ddf270562684f29";
+return signature;
+}
+
+volatile boolean pipeBroke = FALSE;	/* Flag broken pipes here. */
+
+static void gfPipeHandler(int sigNum)
+/* Set broken pipe flag. */
+{
+pipeBroke = TRUE;
+}
+
+void gfCatchPipes()
+/* Set up to catch broken pipe signals. */
+{
+signal(SIGPIPE, gfPipeHandler);
+}
+
+int gfReadMulti(int sd, void *vBuf, size_t size)
+/* Read in until all is read or there is an error. */
+{
+char *buf = vBuf;
+size_t totalRead = 0;
+int oneRead;
+
+while (totalRead < size)
+    {
+    oneRead = read(sd, buf + totalRead, size - totalRead);
+    if (oneRead < 0)
+        {
+	perror("Couldn't finish large read");
+	return oneRead;
+	}
+    else if (oneRead == 0)
+    /* Avoid an infinite loop when the client closed the socket. */
+        break;
+    totalRead += oneRead;
+    }
+return totalRead;
+}
+
+void genoFindFree(struct genoFind **pGenoFind)
+/* Free up a genoFind index. */
+{
+struct genoFind *gf = *pGenoFind;
+int i;
+struct gfSeqSource *sources;
+if (gf != NULL)
+    {
+    freeMem(gf->lists);
+    freeMem(gf->listSizes);
+    freeMem(gf->allocated);
+    if ((sources = gf->sources) != NULL)
+	{
+	for (i=0; i<gf->sourceCount; ++i)
+	    bitFree(&sources[i].maskedBits);
+	freeMem(sources);
+	}
+    freez(pGenoFind);
+    }
+}
+
+int gfPowerOf20(int n)
+/* Return a 20 to the n */
+{
+int res = 20;
+while (--n > 0)
+    res *= 20;
+return res;
+}
+
+void gfCheckTileSize(int tileSize, boolean isPep)
+/* Check that tile size is legal.  Abort if not. */
+{
+if (isPep)
+    {
+    if (tileSize < 3 || tileSize > 8)
+	errAbort("protein tileSize must be between 3 and 8");
+    }
+else
+    {
+    if (tileSize < 6 || tileSize > 18)
+	errAbort("DNA tileSize must be between 6 and 18");
+    }
+}
+
+static struct genoFind *gfNewEmpty(int minMatch, int maxGap, 
+	int tileSize, int stepSize, int maxPat,
+	char *oocFile, boolean isPep, boolean allowOneMismatch)
+/* Return an empty pattern space. oocFile parameter may be NULL*/
+{
+struct genoFind *gf;
+int tileSpaceSize;
+int segSize = 0;
+
+gfCheckTileSize(tileSize, isPep);
+if (stepSize == 0)
+    stepSize = tileSize;
+AllocVar(gf);
+if (isPep)
+    {
+    if (tileSize > 5)
+        {
+	segSize = tileSize - 5;
+	}
+    tileSpaceSize = gf->tileSpaceSize = gfPowerOf20(tileSize-segSize);
+    }
+else
+    {
+    int seedBitSize;
+    if (tileSize > 12)
+        {
+	segSize = tileSize - 12;
+	}
+    seedBitSize = (tileSize-segSize)*2;
+    tileSpaceSize = gf->tileSpaceSize = (1<<seedBitSize);
+    gf->tileMask = tileSpaceSize-1;
+    }
+gf->segSize = segSize;
+gf->tileSize = tileSize;
+gf->stepSize = stepSize;
+gf->isPep = isPep;
+gf->allowOneMismatch = allowOneMismatch;
+if (segSize > 0)
+    {
+    gf->endLists = needHugeZeroedMem(tileSpaceSize * sizeof(gf->endLists[0]));
+    maxPat = BIGNUM;	/* Don't filter out overused on the big ones.  It is
+                         * unnecessary and would be quite complex. */
+    }
+else
+    {
+    gf->lists = needHugeZeroedMem(tileSpaceSize * sizeof(gf->lists[0]));
+    }
+gf->listSizes = needHugeZeroedMem(tileSpaceSize * sizeof(gf->listSizes[0]));
+gf->minMatch = minMatch;
+gf->maxGap = maxGap;
+gf->maxPat = maxPat;
+if (oocFile != NULL)
+    {
+    if (segSize > 0)
+        errAbort("Don't yet support ooc on large tile sizes");
+    oocMaskCounts(oocFile, gf->listSizes, tileSize, maxPat);
+    oocMaskSimpleRepeats(gf->listSizes, tileSize, maxPat);
+    }
+return gf;
+}
+
+static int ntLookup[256];
+
+static void initNtLookup()
+{
+static boolean initted = FALSE;
+if (!initted)
+    {
+    int i;
+    for (i=0; i<ArraySize(ntLookup); ++i)
+        ntLookup[i] = -1;
+    ntLookup['a'] = A_BASE_VAL;
+    ntLookup['c'] = C_BASE_VAL;
+    ntLookup['t'] = T_BASE_VAL;
+    ntLookup['g'] = G_BASE_VAL;
+    initted = TRUE;
+    }
+}
+
+int gfDnaTile(DNA *dna, int n)
+/* Make a packed DNA n-mer. */
+{
+int tile = 0;
+int i, c;
+for (i=0; i<n; ++i)
+    {
+    tile <<= 2;
+    if ((c = ntLookup[(int)dna[i]]) < 0)
+        return -1;
+    tile += c;
+    }
+return tile;
+}
+
+int gfPepTile(AA *pep, int n)
+/* Make up packed representation of translated protein. */
+{
+int tile = 0;
+int aa;
+while (--n >= 0)
+    {
+    tile *= 20;
+    aa = aaVal[(int)(*pep++)];
+    if (aa < 0 || aa > 19)
+        return -1;
+    tile += aa;
+    }
+return tile;
+}
+
+static void gfCountSeq(struct genoFind *gf, bioSeq *seq)
+/* Add all N-mers in seq. */
+{
+char *poly = seq->dna;
+int tileSize = gf->tileSize;
+int stepSize = gf->stepSize;
+int tileHeadSize = gf->tileSize - gf->segSize;
+int maxPat = gf->maxPat;
+int tile;
+bits32 *listSizes = gf->listSizes;
+int i, lastTile = seq->size - tileSize;
+int (*makeTile)(char *poly, int n) = (gf->isPep ? gfPepTile : gfDnaTile);
+
+initNtLookup();
+for (i=0; i<=lastTile; i += stepSize)
+    {
+    if ((tile = makeTile(poly, tileHeadSize)) >= 0)
+	{
+        if (listSizes[tile] < maxPat)
+	    {
+	    listSizes[tile] += 1;
+	    }
+	}
+    poly += stepSize;
+    }
+}
+
+static int gfCountTilesInNib(struct genoFind *gf, int stepSize, char *fileName)
+/* Count all tiles in nib file.  Returns nib size. */
+{
+FILE *f;
+int tileSize = gf->tileSize;
+int bufSize = tileSize * 16*1024;
+int nibSize, i;
+int endBuf, basesInBuf;
+struct dnaSeq *seq;
+
+printf("Counting tiles in %s\n", fileName);
+nibOpenVerify(fileName, &f, &nibSize);
+for (i=0; i < nibSize; i = endBuf)
+    {
+    endBuf = i + bufSize;
+    if (endBuf >= nibSize) endBuf = nibSize;
+    basesInBuf = endBuf - i;
+    seq = nibLdPart(fileName, f, nibSize, i, basesInBuf);
+    gfCountSeq(gf, seq);
+    freeDnaSeq(&seq);
+    }
+fclose(f);
+return nibSize;
+}
+
+long long maxTotalBases()
+/* Return maximum bases we can index. */
+{
+long long maxBases = 1024*1024;
+maxBases *= 4*1024;
+return maxBases;
+}
+
+static long long twoBitCheckTotalSize(struct twoBitFile *tbf)
+/* Return total size of sequence in two bit file.  Squawk and
+ * die if it's more than 4 gig. */
+{
+long long totalSize = twoBitTotalSize(tbf);
+if (totalSize > maxTotalBases())
+    errAbort("Sorry, can only index up to %lld bases, %s has %lld",
+	maxTotalBases(),  tbf->fileName, totalSize);
+return totalSize;
+}
+
+static void gfCountTilesInTwoBit(struct genoFind *gf, int stepSize,
+	char *fileName, int *retSeqCount, long long *retBaseCount)
+/* Count all tiles in 2bit file.  Returns number of sequences and
+ * total size of sequences in file. */
+{
+struct dnaSeq *seq;
+struct twoBitFile *tbf = twoBitOpen(fileName);
+struct twoBitIndex *index;
+int seqCount = 0;
+long long baseCount = twoBitCheckTotalSize(tbf);
+
+printf("Counting tiles in %s\n", fileName);
+for (index = tbf->indexList; index != NULL; index = index->next)
+    {
+    seq = twoBitReadSeqFragLower(tbf, index->name, 0, 0);
+    gfCountSeq(gf, seq);
+    ++seqCount;
+    freeDnaSeq(&seq);
+    }
+twoBitClose(&tbf);
+*retSeqCount = seqCount;
+*retBaseCount = baseCount;
+}
+
+static int gfAllocLists(struct genoFind *gf)
+/* Allocate index lists and set up list pointers. 
+ * Returns size of all lists. */
+{
+int oneCount;
+int count = 0;
+int i;
+bits32 *listSizes = gf->listSizes;
+bits32 **lists = gf->lists;
+bits32 *allocated = NULL;
+bits32 maxPat = gf->maxPat;
+int size;
+int usedCount = 0, overusedCount = 0;
+int tileSpaceSize = gf->tileSpaceSize;
+
+for (i=0; i<tileSpaceSize; ++i)
+    {
+    /* If pattern is too much used it's no good to us, ignore. */
+    if ((oneCount = listSizes[i]) < maxPat)
+        {
+        count += oneCount;
+        usedCount += 1;
+        }
+    else
+        {
+        overusedCount += 1;
+        }
+    }
+if (count > 0)
+    gf->allocated = allocated = needHugeMem(count*sizeof(allocated[0]));
+for (i=0; i<tileSpaceSize; ++i)
+    {
+    if ((size = listSizes[i]) < maxPat)
+        {
+        lists[i] = allocated;
+        allocated += size;
+        }
+    }
+return count;
+}
+
+static int gfAllocLargeLists(struct genoFind *gf)
+/* Allocate large index lists and set up list pointers. 
+ * Returns size of all lists. */
+{
+int count = 0;
+int i;
+bits32 *listSizes = gf->listSizes;
+bits16 **endLists = gf->endLists;
+bits16 *allocated = NULL;
+int size;
+int tileSpaceSize = gf->tileSpaceSize;
+
+for (i=0; i<tileSpaceSize; ++i)
+    count += listSizes[i];
+if (count > 0)
+    gf->allocated = allocated = needHugeMem(3*count*sizeof(allocated[0]));
+for (i=0; i<tileSpaceSize; ++i)
+    {
+    size = listSizes[i];
+    endLists[i] = allocated;
+    allocated += 3*size;
+    }
+return count;
+}
+
+
+static void gfAddSeq(struct genoFind *gf, bioSeq *seq, bits32 offset)
+/* Add all N-mers in seq.  Done after gfCountSeq. */
+{
+char *poly = seq->dna;
+int tileSize = gf->tileSize;
+int stepSize = gf->stepSize;
+int i, lastTile = seq->size - tileSize;
+int (*makeTile)(char *poly, int n) = (gf->isPep ? gfPepTile : gfDnaTile);
+int maxPat = gf->maxPat;
+int tile;
+bits32 *listSizes = gf->listSizes;
+bits32 **lists = gf->lists;
+
+initNtLookup();
+for (i=0; i<=lastTile; i += stepSize)
+    {
+    tile = makeTile(poly, tileSize);
+    if (tile >= 0)
+        {
+	if (listSizes[tile] < maxPat)
+	    {
+	    lists[tile][listSizes[tile]++] = offset;
+	    }
+	}
+    offset += stepSize;
+    poly += stepSize;
+    }
+}
+
+static void gfAddLargeSeq(struct genoFind *gf, bioSeq *seq, bits32 offset)
+/* Add all N-mers to segmented index.  Done after gfCountSeq. */
+{
+char *poly = seq->dna;
+int tileSize = gf->tileSize;
+int stepSize = gf->stepSize;
+int tileTailSize = gf->segSize;
+int tileHeadSize = tileSize - tileTailSize;
+int i, lastTile = seq->size - tileSize;
+int (*makeTile)(char *poly, int n) = (gf->isPep ? gfPepTile : gfDnaTile);
+int tileHead;
+int tileTail;
+bits32 *listSizes = gf->listSizes;
+bits16 **endLists = gf->endLists;
+bits16 *endList;
+int headCount;
+
+initNtLookup();
+for (i=0; i<=lastTile; i += stepSize)
+    {
+    tileHead = makeTile(poly, tileHeadSize);
+    tileTail = makeTile(poly + tileHeadSize, tileTailSize);
+    if (tileHead >= 0 && tileTail >= 0)
+        {
+	endList = endLists[tileHead];
+	headCount = listSizes[tileHead]++;
+	endList += headCount * 3;		/* Because have three slots per. */
+	endList[0] = tileTail;
+	endList[1] = (offset >> 16);
+	endList[2] = (offset&0xffff);
+	}
+    offset += stepSize;
+    poly += stepSize;
+    }
+}
+
+
+
+static int gfAddTilesInNib(struct genoFind *gf, char *fileName, bits32 offset,
+	int stepSize)
+/* Add all tiles in nib file.  Returns size of nib file. */
+{
+FILE *f;
+int tileSize = gf->tileSize;
+int bufSize = tileSize * 16*1024;
+int nibSize, i;
+int endBuf, basesInBuf;
+struct dnaSeq *seq;
+
+printf("Adding tiles in %s\n", fileName);
+nibOpenVerify(fileName, &f, &nibSize);
+for (i=0; i < nibSize; i = endBuf)
+    {
+    endBuf = i + bufSize;
+    if (endBuf >= nibSize) endBuf = nibSize;
+    basesInBuf = endBuf - i;
+    seq = nibLdPart(fileName, f, nibSize, i, basesInBuf);
+    gfAddSeq(gf, seq, i + offset);
+    freeDnaSeq(&seq);
+    }
+fclose(f);
+return nibSize;
+}
+
+
+static void gfZeroOverused(struct genoFind *gf)
+/* Zero out counts of overused tiles. */
+{
+bits32 *sizes = gf->listSizes;
+int tileSpaceSize = gf->tileSpaceSize, i;
+int maxPat = gf->maxPat;
+int overCount = 0;
+
+for (i=0; i<tileSpaceSize; ++i)
+    {
+    if (sizes[i] >= maxPat)
+	{
+        sizes[i] = 0;
+	++overCount;
+	}
+    }
+}
+
+static void gfZeroNonOverused(struct genoFind *gf)
+/* Zero out counts of non-overused tiles. */
+{
+bits32 *sizes = gf->listSizes;
+int tileSpaceSize = gf->tileSpaceSize, i;
+int maxPat = gf->maxPat;
+int overCount = 0;
+
+for (i=0; i<tileSpaceSize; ++i)
+    {
+    if (sizes[i] < maxPat)
+	{
+        sizes[i] = 0;
+	++overCount;
+	}
+    }
+}
+
+struct genoFind *gfIndexNibsAndTwoBits(int fileCount, char *fileNames[],
+	int minMatch, int maxGap, int tileSize, int maxPat, char *oocFile,
+	boolean allowOneMismatch, int stepSize)
+/* Make index for all nibs and .2bits in list. 
+ *      minMatch - minimum number of matching tiles to trigger alignments
+ *      maxGap   - maximum deviation from diagonal of tiles
+ *      tileSize - size of tile in nucleotides
+ *      maxPat   - maximum use of tile to not be considered a repeat
+ *      oocFile  - .ooc format file that lists repeat tiles.  May be NULL. 
+ *      allowOneMismatch - allow one mismatch in a tile.  
+ *      stepSize - space between tiles.  Zero means default (which is tileSize). */
+{
+struct genoFind *gf = gfNewEmpty(minMatch, maxGap, tileSize, stepSize,
+	maxPat, oocFile, FALSE, allowOneMismatch);
+int i;
+bits32 offset = 0, nibSize;
+char *fileName;
+struct gfSeqSource *ss;
+long long totalBases = 0, warnAt = maxTotalBases();
+int totalSeq = 0;
+
+if (allowOneMismatch)
+    errAbort("Don't currently support allowOneMismatch in gfIndexNibsAndTwoBits");
+if (stepSize == 0)
+    stepSize = gf->tileSize;
+for (i=0; i<fileCount; ++i)
+    {
+    fileName = fileNames[i];
+    if (twoBitIsFile(fileName))
+	{
+	int seqCount;
+	long long baseCount;
+        gfCountTilesInTwoBit(gf, stepSize, fileName, &seqCount, &baseCount);
+	totalBases += baseCount;
+	totalSeq += seqCount;
+	}
+    else if (nibIsFile(fileName))
+	{
+	totalBases += gfCountTilesInNib(gf, stepSize, fileName);
+	totalSeq += 1;
+	}
+    else
+        errAbort("Unrecognized file type %s", fileName);
+    /* Warn if they exceed 4 gig. */
+    if (totalBases >= warnAt)
+	errAbort("Exceeding 4 billion bases, sorry gfServer can't handle that.");
+    }
+gfAllocLists(gf);
+gfZeroNonOverused(gf);
+AllocArray(gf->sources, totalSeq);
+gf->sourceCount = totalSeq;
+ss = gf->sources;
+for (i=0; i<fileCount; ++i)
+    {
+    fileName = fileNames[i];
+    if (nibIsFile(fileName))
+	{
+	nibSize = gfAddTilesInNib(gf, fileName, offset, stepSize);
+	ss->fileName = fileName;
+	ss->start = offset;
+	offset += nibSize;
+	ss->end = offset;
+	++ss;
+	}
+    else
+        {
+	struct twoBitFile *tbf = twoBitOpen(fileName);
+	struct twoBitIndex *index;
+	char nameBuf[PATH_LEN+256];
+	for (index = tbf->indexList; index != NULL; index = index->next)
+	    {
+	    struct dnaSeq *seq = twoBitReadSeqFragLower(tbf, index->name, 0,0);
+	    gfAddSeq(gf, seq, offset);
+	    safef(nameBuf, sizeof(nameBuf), "%s:%s", fileName, index->name);
+	    ss->fileName = cloneString(nameBuf);
+	    ss->start = offset;
+	    offset += seq->size;
+	    ss->end = offset;
+	    ++ss;
+	    dnaSeqFree(&seq);
+	    }
+	twoBitClose(&tbf);
+	}
+    }
+gf->totalSeqSize = offset;
+gfZeroOverused(gf);
+printf("Done adding\n");
+return gf;
+}
+
+static void maskSimplePepRepeat(struct genoFind *gf)
+/* Remove tiles from index that represent repeats
+ * of period one and two. */
+{
+int i;
+int tileSize = gf->tileSize;
+int maxPat = gf->maxPat;
+bits32 *listSizes = gf->listSizes;
+
+for (i=0; i<20; ++i)
+    {
+    int j, k;
+    for (j=0; j<20; ++j)
+	{
+	int tile = 0;
+	for (k=0; k<tileSize; ++k)
+	    {
+	    tile *= 20;
+	    if (k&1)
+		tile += j;
+	    else
+	        tile += i;
+	    }
+	listSizes[tile] = maxPat;
+	}
+    }
+}
+
+struct dnaSeq *readMaskedNib(char *fileName, boolean mask)
+/* Read nib, optionally turning masked bits to N's. 
+ * Result is lower case where not masked. */
+{
+struct dnaSeq *seq;
+if (mask)
+    {
+    seq = nibLoadAllMasked(NIB_MASK_MIXED, fileName);
+    toggleCase(seq->dna, seq->size);
+    upperToN(seq->dna, seq->size);
+    }
+else
+    seq = nibLoadAll(fileName);
+return seq;
+}
+
+struct dnaSeq *readMaskedTwoBit(struct twoBitFile *tbf, char *seqName,
+	boolean mask)
+/* Read seq from twoBitFile, optionally turning masked bits to N's. 
+ * Result is lower case where not masked. */
+{
+struct dnaSeq *seq;
+if (mask)
+    {
+    seq = twoBitReadSeqFrag(tbf, seqName, 0, 0);
+    toggleCase(seq->dna, seq->size);
+    upperToN(seq->dna, seq->size);
+    }
+else
+    seq = twoBitReadSeqFragLower(tbf, seqName, 0, 0);
+return seq;
+}
+
+
+static void transCountBothStrands(struct dnaSeq *seq, 
+    struct genoFind *transGf[2][3])
+/* Count (unmasked) tiles in both strand of sequence. 
+ * As a side effect this will reverse-complement seq. */
+{
+int isRc, frame;
+struct trans3 *t3;
+for (isRc=0; isRc <= 1; ++isRc)
+    {
+    if (isRc)
+	reverseComplement(seq->dna, seq->size);
+    t3 = trans3New(seq);
+    for (frame = 0; frame < 3; ++frame)
+	{
+	struct genoFind *gf = transGf[isRc][frame];
+	gfCountSeq(gf, t3->trans[frame]);
+	}
+    trans3Free(&t3);
+    }
+}
+
+static void transIndexBothStrands(struct dnaSeq *seq, 
+    struct genoFind *transGf[2][3], bits32 offset[2][3],
+    int sourceIx, char *fileName)
+/* Add unmasked tiles on both strands of sequence to
+ * index.  As a side effect this will reverse-complement seq. */
+{
+int isRc, frame;
+struct trans3 *t3;
+struct gfSeqSource *ss;
+for (isRc=0; isRc <= 1; ++isRc)
+    {
+    if (isRc)
+	{
+	reverseComplement(seq->dna, seq->size);
+	}
+    t3 = trans3New(seq);
+    for (frame = 0; frame < 3; ++frame)
+	{
+	struct genoFind *gf = transGf[isRc][frame];
+	ss = gf->sources + sourceIx;
+	gfAddSeq(gf, t3->trans[frame], offset[isRc][frame]);
+	ss->fileName = cloneString(fileName);
+	ss->start = offset[isRc][frame];
+	offset[isRc][frame] += t3->trans[frame]->size;
+	ss->end = offset[isRc][frame];
+	}
+    trans3Free(&t3);
+    }
+}
+
+void gfIndexTransNibsAndTwoBits(struct genoFind *transGf[2][3], 
+    int fileCount, char *fileNames[], 
+    int minMatch, int maxGap, int tileSize, int maxPat, char *oocFile,
+    boolean allowOneMismatch, boolean doMask, int stepSize)
+/* Make translated (6 frame) index for all .nib and .2bit files. */
+{
+struct genoFind *gf;
+int i,isRc, frame;
+bits32 offset[2][3];
+char *fileName;
+struct dnaSeq *seq;
+int sourceCount = 0;
+long long totalBases = 0, warnAt = maxTotalBases();
+
+if (allowOneMismatch)
+    errAbort("Don't currently support allowOneMismatch in gfIndexTransNibsAndTwoBits");
+/* Allocate indices for all reading frames. */
+for (isRc=0; isRc <= 1; ++isRc)
+    {
+    for (frame = 0; frame < 3; ++frame)
+	{
+	transGf[isRc][frame] = gf = gfNewEmpty(minMatch, maxGap, 
+		tileSize, stepSize, maxPat, oocFile, TRUE, allowOneMismatch);
+	}
+    }
+
+/* Mask simple AA repeats (of period 1 and 2). */
+for (isRc = 0; isRc <= 1; ++isRc)
+    for (frame = 0; frame < 3; ++frame)
+	maskSimplePepRepeat(transGf[isRc][frame]);
+
+/* Scan through .nib and .2bit files once counting tiles. */
+for (i=0; i<fileCount; ++i)
+    {
+    fileName = fileNames[i];
+    printf("Counting %s\n", fileName);
+    if (nibIsFile(fileName))
+	{
+	seq = readMaskedNib(fileName, doMask);
+	transCountBothStrands(seq, transGf);
+	sourceCount += 1;
+	totalBases += seq->size;
+	freeDnaSeq(&seq);
+	}
+    else if (twoBitIsFile(fileName))
+        {
+	struct twoBitFile *tbf = twoBitOpen(fileName);
+	struct twoBitIndex *index;
+	totalBases += twoBitCheckTotalSize(tbf);
+
+	for (index = tbf->indexList; index != NULL; index = index->next)
+	    {
+	    seq = readMaskedTwoBit(tbf, index->name, doMask);
+	    transCountBothStrands(seq, transGf);
+	    sourceCount += 1;
+	    freeDnaSeq(&seq);
+	    }
+	twoBitClose(&tbf);
+	}
+    else 
+	errAbort("Unrecognized file type %s", fileName);
+    if (totalBases >= warnAt)
+	errAbort("Exceeding 4 billion bases, sorry gfServer can't handle that.");
+    }
+
+/* Get space for entries in indexed of all reading frames. */
+for (isRc=0; isRc <= 1; ++isRc)
+    {
+    for (frame = 0; frame < 3; ++frame)
+	{
+	gf = transGf[isRc][frame];
+	gfAllocLists(gf);
+	gfZeroNonOverused(gf);
+	AllocArray(gf->sources, sourceCount);
+	gf->sourceCount = sourceCount;
+	offset[isRc][frame] = 0;
+	}
+    }
+
+/* Scan through nibs a second time building index. */
+sourceCount = 0;
+for (i=0; i<fileCount; ++i)
+    {
+    fileName = fileNames[i];
+    printf("Indexing %s\n", fileName);
+    if (nibIsFile(fileName))
+	{
+	seq = readMaskedNib(fileName, doMask);
+	transIndexBothStrands(seq, transGf, offset, sourceCount, fileName);
+	freeDnaSeq(&seq);
+	sourceCount += 1;
+	}
+    else	/* .2bit file */
+        {
+	struct twoBitFile *tbf = twoBitOpen(fileName);
+	struct twoBitIndex *index;
+	for (index = tbf->indexList; index != NULL; index = index->next)
+	    {
+	    char nameBuf[PATH_LEN+256];
+	    safef(nameBuf, sizeof(nameBuf), "%s:%s", fileName, index->name);
+	    seq = readMaskedTwoBit(tbf, index->name, doMask);
+	    transIndexBothStrands(seq, transGf, offset, sourceCount, nameBuf);
+	    sourceCount += 1;
+	    freeDnaSeq(&seq);
+	    }
+	twoBitClose(&tbf);
+	}
+    }
+
+for (isRc=0; isRc <= 1; ++isRc)
+    {
+    for (frame = 0; frame < 3; ++frame)
+	{
+	gf = transGf[isRc][frame];
+	gf->totalSeqSize = offset[isRc][frame];
+	gfZeroOverused(gf);
+	}
+    }
+}
+
+static struct genoFind *gfSmallIndexSeq(struct genoFind *gf, bioSeq *seqList,
+	int minMatch, int maxGap, int tileSize, int maxPat, char *oocFile, 
+	boolean isPep, boolean maskUpper)
+/* Make index for all seqs in list. */
+{
+int seqCount = slCount(seqList);
+bioSeq *seq;
+int i;
+bits32 offset = 0;
+struct gfSeqSource *ss;
+
+if (isPep)
+    maskSimplePepRepeat(gf);
+for (seq = seqList; seq != NULL; seq = seq->next)
+    gfCountSeq(gf, seq);
+gfAllocLists(gf);
+gfZeroNonOverused(gf);
+if (seqCount > 0)
+    AllocArray(gf->sources, seqCount);
+gf->sourceCount = seqCount;
+for (i=0, seq = seqList; i<seqCount; ++i, seq = seq->next)
+    {
+    gfAddSeq(gf, seq, offset);
+    ss = gf->sources+i;
+    ss->seq = seq;
+    ss->start = offset;
+    offset += seq->size;
+    ss->end = offset;
+    if (maskUpper)
+	ss->maskedBits = maskFromUpperCaseSeq(seq);
+    }
+gf->totalSeqSize = offset;
+gfZeroOverused(gf);
+return gf;
+}
+
+static struct genoFind *gfLargeIndexSeq(struct genoFind *gf, bioSeq *seqList,
+	int minMatch, int maxGap, int tileSize, int maxPat, char *oocFile, 
+	boolean isPep, boolean maskUpper)
+/* Make index for all seqs in list. */
+{
+int seqCount = slCount(seqList);
+bioSeq *seq;
+int i;
+bits32 offset = 0;
+struct gfSeqSource *ss;
+
+for (seq = seqList; seq != NULL; seq = seq->next)
+    gfCountSeq(gf, seq);
+gfAllocLargeLists(gf);
+gfZeroNonOverused(gf);
+AllocArray(gf->sources, seqCount);
+gf->sourceCount = seqCount;
+for (i=0, seq = seqList; i<seqCount; ++i, seq = seq->next)
+    {
+    gfAddLargeSeq(gf, seq, offset);
+    ss = gf->sources+i;
+    ss->seq = seq;
+    ss->start = offset;
+    offset += seq->size;
+    ss->end = offset;
+    if (maskUpper)
+	ss->maskedBits = maskFromUpperCaseSeq(seq);
+    }
+gf->totalSeqSize = offset;
+gfZeroOverused(gf);
+return gf;
+}
+
+static void checkUniqueNames(bioSeq *seqList)
+/* Check that each sequence has a unique name. */
+{
+struct hash *hash = hashNew(18);
+bioSeq *seq;
+for (seq = seqList; seq != NULL; seq = seq->next)
+    {
+    if (hashLookup(hash, seq->name))
+        errAbort("Error: sequence name %s is repeated in the database, all names must be unique.",
+		seq->name);
+    hashAdd(hash, seq->name, NULL);
+    }
+hashFree(&hash);
+}
+
+struct genoFind *gfIndexSeq(bioSeq *seqList,
+	int minMatch, int maxGap, int tileSize, int maxPat, char *oocFile, 
+	boolean isPep, boolean allowOneMismatch, boolean maskUpper,
+	int stepSize)
+/* Make index for all seqs in list.  For DNA sequences upper case bits will
+ * be unindexed. */
+{
+checkUniqueNames(seqList);
+struct genoFind *gf = gfNewEmpty(minMatch, maxGap, tileSize, stepSize, maxPat, 
+				oocFile, isPep, allowOneMismatch);
+if (stepSize == 0)
+    stepSize = tileSize;
+if (gf->segSize > 0)
+    {
+    gfLargeIndexSeq(gf, seqList, minMatch, maxGap, tileSize, maxPat, oocFile, isPep, maskUpper);
+    }
+else
+    {
+    gfSmallIndexSeq(gf, seqList, minMatch, maxGap, tileSize, maxPat, oocFile, isPep, maskUpper);
+    }
+return gf;
+}
+
+static int bCmpSeqSource(const void *vTarget, const void *vRange)
+/* Compare function for binary search of gfSeqSource. */
+{
+const bits32 *pTarget = vTarget;
+bits32 target = *pTarget;
+const struct gfSeqSource *ss = vRange;
+
+if (target < ss->start) return -1;
+if (target >= ss->end) return 1;
+return 0;
+}
+
+static struct gfSeqSource *findSource(struct genoFind *gf, bits32 targetPos)
+/* Find source given target position. */
+{
+struct gfSeqSource *ss =  bsearch(&targetPos, gf->sources, gf->sourceCount, 
+	sizeof(gf->sources[0]), bCmpSeqSource);
+if (ss == NULL)
+    errAbort("Couldn't find source for %d", targetPos);
+return ss;
+}
+
+void gfClumpFree(struct gfClump **pClump)
+/* Free a single clump. */
+{
+struct gfClump *clump;
+if ((clump = *pClump) == NULL)
+    return;
+freez(pClump);
+}
+
+void gfClumpFreeList(struct gfClump **pList)
+/* Free a list of dynamically allocated gfClump's */
+{
+struct gfClump *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    gfClumpFree(&el);
+    }
+*pList = NULL;
+}
+
+void gfClumpDump(struct genoFind *gf, struct gfClump *clump, FILE *f)
+/* Print out info on clump */
+{
+struct gfSeqSource *ss = clump->target;
+char *name = ss->fileName;
+
+if (name == NULL) name = ss->seq->name;
+fprintf(f, "%u-%u %s %u-%u, hits %d\n", 
+	clump->qStart, clump->qEnd, name,
+	clump->tStart - ss->start, clump->tEnd - ss->start,
+	clump->hitCount);
+#ifdef SOMETIMES
+for (hit = clump->hitList; hit != NULL; hit = hit->next)
+    fprintf(f, "   q %d, t %d, diag %d\n", hit->qStart, hit->tStart, hit->diagonal);
+#endif
+}
+
+/* Fast sorting routines for sorting gfHits on diagonal. 
+ * More or less equivalent to system qsort, but with
+ * comparison function inline.  Worth a little tweaking
+ * since this is the bottleneck for the whole procedure. */
+
+static void gfHitSort2(struct gfHit **ptArray, int n);
+
+/* Some variables used by recursive function gfHitSort2
+ * across all incarnations. */
+static struct gfHit **nosTemp, *nosSwap;
+
+static void gfHitSort2(struct gfHit **ptArray, int n)
+/* This is a fast recursive sort that uses a temporary
+ * buffer (nosTemp) that has to be as big as the array
+ * that is being sorted. */
+{
+struct gfHit **tmp, **pt1, **pt2;
+int n1, n2;
+
+/* Divide area to sort in two. */
+n1 = (n>>1);
+n2 = n - n1;
+pt1 = ptArray;
+pt2 =  ptArray + n1;
+
+/* Sort each area separately.  Handle small case (2 or less elements)
+ * here.  Otherwise recurse to sort. */
+if (n1 > 2)
+    gfHitSort2(pt1, n1);
+else if (n1 == 2 && pt1[0]->diagonal > pt1[1]->diagonal)
+    {
+    nosSwap = pt1[1];
+    pt1[1] = pt1[0];
+    pt1[0] = nosSwap;
+    }
+if (n2 > 2)
+    gfHitSort2(pt2, n2);
+else if (n2 == 2 && pt2[0]->diagonal > pt2[1]->diagonal)
+    {
+    nosSwap = pt2[1];
+    pt2[1] = pt2[0];
+    pt2[0] = nosSwap;
+    }
+
+/* At this point both halves are internally sorted. 
+ * Do a merge-sort between two halves copying to temp
+ * buffer.  Then copy back sorted result to main buffer. */
+tmp = nosTemp;
+while (n1 > 0 && n2 > 0)
+    {
+    if ((*pt1)->diagonal <= (*pt2)->diagonal)
+	{
+	--n1;
+	*tmp++ = *pt1++;
+	}
+    else
+	{
+	--n2;
+	*tmp++ = *pt2++;
+	}
+    }
+/* One or both sides are now fully merged. */
+assert(tmp + n1 + n2 == nosTemp + n);
+
+/* If some of first side left to merge copy it to end of temp buf. */
+if (n1 > 0)
+    memcpy(tmp, pt1, n1 * sizeof(*tmp));
+
+/* If some of second side left to merge, we finesse it here:
+ * simply refrain from copying over it as we copy back temp buf. */
+memcpy(ptArray, nosTemp, (n - n2) * sizeof(*ptArray));
+}
+
+void gfHitSortDiagonal(struct gfHit **pList)
+/* Sort a singly linked list with Qsort and a temporary array. */
+{
+struct gfHit *list = *pList;
+if (list != NULL && list->next != NULL)
+    {
+    int count = slCount(list);
+    struct gfHit *el;
+    struct gfHit **array;
+    int i;
+    int byteSize = count*sizeof(*array);
+    array = needLargeMem(byteSize);
+    nosTemp = needLargeMem(byteSize);
+    for (el = list, i=0; el != NULL; el = el->next, i++)
+        array[i] = el;
+    gfHitSort2(array, count);
+    list = NULL;
+    for (i=0; i<count; ++i)
+        {
+        array[i]->next = list;
+        list = array[i];
+        }
+    freez(&array);
+    freez(&nosTemp);
+    slReverse(&list);
+    *pList = list;       
+    }
+}
+
+
+
+static int cmpQuerySize;
+
+#ifdef UNUSED
+static int gfHitCmpDiagonal(const void *va, const void *vb)
+/* Compare to sort based on 'diagonal' offset. */
+{
+const struct gfHit *a = *((struct gfHit **)va);
+const struct gfHit *b = *((struct gfHit **)vb);
+
+if (a->diagonal > b->diagonal)
+    return 1;
+else if (a->diagonal == b->diagonal)
+    return 0;
+else
+    return -1;
+}
+#endif /* UNUSED */
+
+static int gfHitCmpTarget(const void *va, const void *vb)
+/* Compare to sort based on target offset. */
+{
+const struct gfHit *a = *((struct gfHit **)va);
+const struct gfHit *b = *((struct gfHit **)vb);
+
+if (a->tStart > b->tStart)
+    return 1;
+else if (a->tStart == b->tStart)
+    return 0;
+else
+    return -1;
+}
+
+static int gfHitCmpQuery(const void *va, const void *vb)
+/* Compare to sort based on target offset. (Thanks AG) */
+{
+const struct gfHit *a = *((struct gfHit **)va);
+const struct gfHit *b = *((struct gfHit **)vb);
+
+if (a->qStart > b->qStart)
+    return 1;
+else if (a->qStart == b->qStart)
+    return 0;
+else
+    return -1;
+}
+
+static void gfClumpComputeQueryCoverage(struct gfClump *clumpList, 
+	int tileSize)
+/* Figure out how much of query is covered by clump list. (Thanks AG). */
+{
+struct gfClump *clump;
+struct gfHit *hit;
+struct gfHit *hitList;
+int qcov;
+int blockStart, blockEnd;
+
+for (clump = clumpList; clump != NULL; clump = clump->next)
+    {
+    hitList = clump->hitList;
+    if ( hitList != NULL)
+	{
+	slSort(&hitList, gfHitCmpQuery);
+	qcov = 0;
+	blockStart = hitList->qStart;
+	blockEnd = blockStart + tileSize;
+	for (hit = hitList; hit != NULL; hit = hit->next)
+	    {
+	    if (hit->qStart > blockEnd)
+		{
+		/* We're skipping some, so output block so far, and start new block. */
+		qcov += blockEnd - blockStart;
+		blockStart = hit->qStart;
+		blockEnd = blockStart + tileSize;
+		}
+	    else if (hit->qStart + tileSize > blockEnd)
+		{
+		/* Expand current block. */
+		blockEnd = hit->qStart + tileSize;
+		}
+	    }
+	qcov += blockEnd - blockStart;
+	clump->queryCoverage = qcov;
+	}
+    }
+}
+
+
+
+static int gfClumpCmpQueryCoverage(const void *va, const void *vb)
+/* Compare to sort based on query coverage. */
+{
+const struct gfClump *a = *((struct gfClump **)va);
+const struct gfClump *b = *((struct gfClump **)vb);
+
+return (b->queryCoverage - a->queryCoverage);
+}
+
+static void findClumpBounds(struct gfClump *clump, int tileSize)
+/* Figure out qStart/qEnd tStart/tEnd from hitList */
+{
+struct gfHit *hit;
+int x;
+hit = clump->hitList;
+if (hit == NULL)
+    return;
+clump->qStart = clump->qEnd = hit->qStart;
+clump->tStart = clump->tEnd = hit->tStart;
+for (hit = hit->next; hit != NULL; hit = hit->next)
+    {
+    x = hit->qStart;
+    if (x < clump->qStart) clump->qStart = x;
+    if (x > clump->qEnd) clump->qEnd = x;
+    x = hit->tStart;
+    if (x < clump->tStart) clump->tStart = x;
+    if (x > clump->tEnd) clump->tEnd = x;
+    }
+clump->tEnd += tileSize;
+clump->qEnd += tileSize;
+}
+
+static void targetClump(struct genoFind *gf, struct gfClump **pClumpList, struct gfClump *clump)
+/* Add target sequence to clump.  If clump had multiple targets split it into
+ * multiple clumps, one per target.  Add clump(s) to list. */
+{
+struct gfSeqSource *ss = findSource(gf, clump->tStart);
+if (ss->end >= clump->tEnd)
+    {
+    /* Usual simple case: all of clump hits single target. */
+    clump->target = ss;
+    slAddHead(pClumpList, clump);
+    }
+else
+    {
+    /* If we've gotten here, then the clump is split across multiple targets.
+     * We'll have to split it into multiple clumps... */
+    struct gfHit *hit, *nextHit, *inList, *outList, *oldList = clump->hitList;
+    int hCount;
+
+    while (oldList != NULL)
+        {
+	inList = outList = NULL;
+	hCount = 0;
+	for (hit = oldList; hit != NULL; hit = nextHit)
+	    {
+	    nextHit = hit->next;
+	    if (ss->start <= hit->tStart  && hit->tStart < ss->end)
+	        {
+		++hCount;
+		slAddHead(&inList, hit);
+		}
+	    else
+	        {
+		slAddHead(&outList, hit);
+		}
+	    }
+	slReverse(&inList);
+	slReverse(&outList);
+	if (hCount >= gf->minMatch)
+	    {
+	    struct gfClump *newClump;
+	    AllocVar(newClump);
+	    newClump->hitList = inList;
+	    newClump->hitCount = hCount;
+	    newClump->target = ss;
+	    findClumpBounds(newClump, gf->tileSize);
+	    slAddHead(pClumpList, newClump);
+	    }
+	else
+	    {
+	    inList = NULL;
+	    }
+	oldList = outList;
+	if (oldList != NULL)
+	    {
+	    ss = findSource(gf, oldList->tStart);
+	    }
+	}
+    clump->hitList = NULL;	/* We ate up the hit list. */
+    gfClumpFree(&clump);
+    }
+}
+
+static int gfNearEnough = 300;
+
+static struct gfClump *clumpNear(struct genoFind *gf, struct gfClump *oldClumps, int minMatch)
+/* Go through clump list and make sure hits are also near each other.
+ * If necessary divide clumps. */
+{
+struct gfClump *newClumps = NULL, *clump, *nextClump;
+struct gfHit *hit, *nextHit;
+int tileSize = gf->tileSize;
+bits32 lastT;
+int nearEnough = (gf->isPep ? gfNearEnough/3 : gfNearEnough);
+
+for (clump = oldClumps; clump != NULL; clump = nextClump)
+    {
+    struct gfHit *newHits = NULL, *oldHits = clump->hitList;
+    int clumpSize = 0;
+    clump->hitCount = 0;
+    clump->hitList = NULL;	/* Clump no longer owns list. */
+    nextClump = clump->next;
+    slSort(&oldHits, gfHitCmpTarget);
+    lastT = oldHits->tStart;
+    for (hit = oldHits; hit != NULL; hit = nextHit)
+        {
+	nextHit = hit->next;
+	if (hit->tStart > nearEnough + lastT)
+	     {
+	     if (clumpSize >= minMatch)
+	         {
+		 slReverse(&newHits);
+		 clump->hitList = newHits;
+		 newHits = NULL;
+		 clump->hitCount = clumpSize;
+		 findClumpBounds(clump, tileSize);
+		 targetClump(gf, &newClumps, clump);
+		 AllocVar(clump);
+		 }
+	     else
+	         {
+		 newHits = NULL;
+		 clump->hitCount = 0;
+		 }
+	     clumpSize = 0;
+	     }
+	lastT = hit->tStart;
+	slAddHead(&newHits, hit);
+	++clumpSize;
+	}
+    slReverse(&newHits);
+    clump->hitList = newHits;
+    if (clumpSize >= minMatch)
+        {
+	clump->hitCount = clumpSize;
+	findClumpBounds(clump, tileSize);
+	targetClump(gf, &newClumps, clump);
+	}
+    else
+        {
+	gfClumpFree(&clump);
+	}
+    }
+return newClumps;
+}
+
+static struct gfClump *clumpHits(struct genoFind *gf, struct gfHit *hitList, int minMatch)
+/* Clump together hits according to parameters in gf. */
+{
+struct gfClump *clumpList = NULL, *clump = NULL;
+int maxGap = gf->maxGap;
+struct gfHit *hit, *nextHit, *lastHit = NULL;
+int totalHits = 0, usedHits = 0, clumpCount = 0;
+int tileSize = gf->tileSize;
+int bucketShift = 16;		/* 64k buckets. */
+bits32 bucketSize = (1<<bucketShift);
+int bucketCount = (gf->totalSeqSize >> bucketShift) + 1;
+int nearEnough = (gf->isPep ? gfNearEnough/3 : gfNearEnough);
+bits32 boundary = bucketSize - nearEnough;
+int i;
+struct gfHit **buckets = NULL, **pb;
+
+/* Sort hit list into buckets. */
+AllocArray(buckets, bucketCount);
+for (hit = hitList; hit != NULL; hit = nextHit)
+    {
+    nextHit = hit->next;
+    pb = buckets + (hit->tStart >> bucketShift);
+    slAddHead(pb, hit);
+    }
+
+/* Sort each bucket on diagonal and clump. */
+for (i=0; i<bucketCount; ++i)
+    {
+    int clumpSize;
+    bits32 maxT;
+    struct gfHit *clumpHits;
+    pb = buckets + i;
+    gfHitSortDiagonal(pb);
+    for (hit = *pb; hit != NULL; )
+         {
+	 /* Each time through this loop will get info on a clump.  Will only
+	  * actually create clump if it is big enough though. */
+	 clumpSize = 0;
+	 clumpHits = lastHit = NULL;
+	 maxT = 0;
+	 for (; hit != NULL; hit = nextHit)
+	     {
+	     nextHit = hit->next;
+	     if (lastHit != NULL && hit->diagonal - lastHit->diagonal > maxGap)
+		 break;
+	     if (hit->tStart > maxT) maxT = hit->tStart;
+	     slAddHead(&clumpHits, hit);
+	     ++clumpSize;
+	     ++totalHits;
+	     lastHit = hit;
+	     }
+	 if (maxT > boundary && i < bucketCount-1)
+	     {
+	     /* Move clumps that are near boundary to next bucket to give them a
+	      * chance to merge with hits there. */
+	     buckets[i+1] = slCat(clumpHits, buckets[i+1]);
+	     }
+	 else if (clumpSize >= minMatch)
+	     {
+	     /* Save clumps that are large enough on list. */
+	     AllocVar(clump);
+	     slAddHead(&clumpList, clump);
+	     clump->hitCount = clumpSize;
+	     clump->hitList = clumpHits;
+	     usedHits += clumpSize;
+	     ++clumpCount;
+	     }
+	 }
+    *pb = NULL;
+    boundary += bucketSize;
+    }
+clumpList = clumpNear(gf, clumpList, minMatch);
+gfClumpComputeQueryCoverage(clumpList, tileSize);	/* Thanks AG */
+slSort(&clumpList, gfClumpCmpQueryCoverage);
+
+#ifdef DEBUG
+uglyf("Dumping clumps B\n");
+for (clump = clumpList; clump != NULL; clump = clump->next)	/* uglyf */
+    {
+    uglyf(" %d %d %s %d %d (%d hits)\n", clump->qStart, clump->qEnd, clump->target->seq->name,   clump->tStart, clump->tEnd, clump->hitCount);
+    }
+#endif /* DEBUG */
+freez(&buckets);
+return clumpList;
+}
+
+
+static struct gfHit *gfFastFindDnaHits(struct genoFind *gf, struct dnaSeq *seq, 
+	Bits *qMaskBits,  int qMaskOffset, struct lm *lm, int *retHitCount,
+	struct gfSeqSource *target, int tMin, int tMax)
+/* Find hits associated with one sequence. This is is special fast
+ * case for DNA that is in an unsegmented index. */
+{
+struct gfHit *hitList = NULL, *hit;
+int size = seq->size;
+int tileSizeMinusOne = gf->tileSize - 1;
+int mask = gf->tileMask;
+DNA *dna = seq->dna;
+int i, j;
+bits32 bits = 0;
+bits32 bVal;
+int listSize;
+bits32 qStart, *tList;
+int hitCount = 0;
+
+for (i=0; i<tileSizeMinusOne; ++i)
+    {
+    bVal = ntValNoN[(int)dna[i]];
+    bits <<= 2;
+    bits += bVal;
+    }
+for (i=tileSizeMinusOne; i<size; ++i)
+    {
+    bVal = ntValNoN[(int)dna[i]];
+    bits <<= 2;
+    bits += bVal;
+    bits &= mask;
+    listSize = gf->listSizes[bits];
+    if (listSize != 0)
+	{
+	qStart = i-tileSizeMinusOne;
+	if (qMaskBits == NULL || bitCountRange(qMaskBits, qStart+qMaskOffset, gf->tileSize) == 0)
+	    {
+	    tList = gf->lists[bits];
+	    for (j=0; j<listSize; ++j)
+		{
+		int tStart = tList[j];
+		if (target == NULL || 
+			(target == findSource(gf, tStart) && tStart >= tMin && tStart < tMax) ) 
+		    {
+		    lmAllocVar(lm, hit);
+		    hit->qStart = qStart;
+		    hit->tStart = tStart;
+		    hit->diagonal = tStart + size - qStart;
+		    slAddHead(&hitList, hit);
+		    ++hitCount;
+		    }
+		}
+	    }
+	}
+    }
+*retHitCount = hitCount;
+return hitList;
+}
+
+static struct gfHit *gfStraightFindHits(struct genoFind *gf, aaSeq *seq, 
+	Bits *qMaskBits, int qMaskOffset, struct lm *lm, int *retHitCount,
+	struct gfSeqSource *target, int tMin, int tMax)
+/* Find hits associated with one sequence in a non-segmented
+ * index where hits match exactly. */
+{
+struct gfHit *hitList = NULL, *hit;
+int size = seq->size;
+int tileSize = gf->tileSize;
+int lastStart = size - tileSize;
+char *poly = seq->dna;
+int i, j;
+int tile;
+int listSize;
+bits32 qStart, *tList;
+int hitCount = 0;
+int (*makeTile)(char *poly, int n) = (gf->isPep ? gfPepTile : gfDnaTile);
+
+initNtLookup();
+for (i=0; i<=lastStart; ++i)
+    {
+    tile = makeTile(poly+i, tileSize);
+    if (tile < 0)
+	continue;
+    listSize = gf->listSizes[tile];
+    if (listSize > 0)
+	{
+	qStart = i;
+	if (qMaskBits == NULL || bitCountRange(qMaskBits, qStart+qMaskOffset, tileSize) == 0)
+	    {
+	    tList = gf->lists[tile];
+	    for (j=0; j<listSize; ++j)
+		{
+		int tStart = tList[j];
+		if (target == NULL || 
+			(target == findSource(gf, tStart) && tStart >= tMin && tStart < tMax) ) 
+		    {
+		    lmAllocVar(lm,hit);
+		    hit->qStart = qStart;
+		    hit->tStart = tStart;
+		    hit->diagonal = tStart + size - qStart;
+		    slAddHead(&hitList, hit);
+		    ++hitCount;
+		    }
+		}
+	    }
+	}
+    }
+*retHitCount = hitCount;
+return hitList;
+}
+
+static struct gfHit *gfStraightFindNearHits(struct genoFind *gf, aaSeq *seq, 
+	Bits *qMaskBits, int qMaskOffset, struct lm *lm, int *retHitCount,
+	struct gfSeqSource *target, int tMin, int tMax)
+/* Find hits associated with one sequence in a non-segmented
+ * index where hits can mismatch in one letter. */
+{
+struct gfHit *hitList = NULL, *hit;
+int size = seq->size;
+int tileSize = gf->tileSize;
+int lastStart = size - tileSize;
+char *poly = seq->dna;
+int i, j;
+int tile;
+int listSize;
+bits32 qStart, *tList;
+int hitCount = 0;
+int varPos, varVal;	/* Variable position. */
+int (*makeTile)(char *poly, int n); 
+int alphabetSize;
+char oldChar, zeroChar;
+int *seqValLookup;
+int posMul, avoid;
+
+initNtLookup();
+if (gf->isPep)
+    {
+    makeTile = gfPepTile;
+    alphabetSize = 20;
+    zeroChar = 'A';
+    seqValLookup = aaVal;
+    }
+else
+    {
+    makeTile = gfDnaTile;
+    alphabetSize = 4;
+    zeroChar = 't';
+    seqValLookup = ntVal;
+    }
+
+for (i=0; i<=lastStart; ++i)
+    {
+    posMul = 1;
+    for (varPos = tileSize-1; varPos >=0; --varPos)
+	{
+	/* Make a tile that has zero value at variable position. */
+	oldChar = poly[i+varPos];
+	poly[i+varPos] = zeroChar;
+	tile = makeTile(poly+i, tileSize);
+	poly[i+varPos] = oldChar;
+
+	/* Avoid checking the unmodified tile multiple times. */
+	if (varPos == 0)
+	    avoid = -1;
+	else
+	    avoid = seqValLookup[(int)oldChar];
+
+	if (tile >= 0)
+	    {
+	    /* Look up all possible values of variable position. */
+	    for (varVal=0; varVal<alphabetSize; ++varVal)
+		{
+		if (varVal != avoid)
+		    {
+		    listSize = gf->listSizes[tile];
+		    if (listSize > 0)
+			{
+			qStart = i;
+			if (qMaskBits == NULL || bitCountRange(qMaskBits, qStart+qMaskOffset, tileSize) == 0)
+			    {
+			    tList = gf->lists[tile];
+			    for (j=0; j<listSize; ++j)
+				{
+				int tStart = tList[j];
+				if (target == NULL || 
+					(target == findSource(gf, tStart) 
+					&& tStart >= tMin && tStart < tMax) ) 
+				    {
+				    lmAllocVar(lm,hit);
+				    hit->qStart = qStart;
+				    hit->tStart = tStart;
+				    hit->diagonal = tStart + size - qStart;
+				    slAddHead(&hitList, hit);
+				    ++hitCount;
+				    }
+				}
+			    }
+			}
+		    }
+		tile += posMul;
+		}
+	    }
+	posMul *= alphabetSize;
+	}
+    }
+*retHitCount = hitCount;
+return hitList;
+}
+
+static struct gfHit *gfSegmentedFindHits(struct genoFind *gf, aaSeq *seq, 
+	Bits *qMaskBits, int qMaskOffset, struct lm *lm, int *retHitCount,
+	struct gfSeqSource *target, int tMin, int tMax)
+/* Find hits associated with one sequence in general case in a segmented
+ * index. */
+{
+struct gfHit *hitList = NULL, *hit;
+int size = seq->size;
+int tileSize = gf->tileSize;
+int tileTailSize = gf->segSize;
+int tileHeadSize = gf->tileSize - tileTailSize;
+int lastStart = size - tileSize;
+char *poly = seq->dna;
+int i, j;
+int tileHead, tileTail;
+int listSize;
+bits32 qStart;
+bits16 *endList;
+int hitCount = 0;
+int (*makeTile)(char *poly, int n) = (gf->isPep ? gfPepTile : gfDnaTile);
+
+
+initNtLookup();
+for (i=0; i<=lastStart; ++i)
+    {
+    if (qMaskBits == NULL || bitCountRange(qMaskBits, i+qMaskOffset, tileSize) == 0)
+	{
+	tileHead = makeTile(poly+i, tileHeadSize);
+	if (tileHead < 0)
+	    continue;
+	tileTail = makeTile(poly+i+tileHeadSize, tileTailSize);
+	if (tileTail < 0)
+	    continue;
+	listSize = gf->listSizes[tileHead];
+	qStart = i;
+	endList = gf->endLists[tileHead];
+	for (j=0; j<listSize; ++j)
+	    {
+	    if (endList[0] == tileTail)
+		{
+		int tStart = (endList[1]<<16) + endList[2];
+		if (target == NULL || 
+			(target == findSource(gf, tStart) 
+			&& tStart >= tMin && tStart < tMax) ) 
+		    {
+		    lmAllocVar(lm,hit);
+		    hit->qStart = qStart;
+		    hit->tStart = tStart;
+		    hit->diagonal = tStart + size - qStart;
+		    slAddHead(&hitList, hit);
+		    ++hitCount;
+		    }
+		}
+	    endList += 3;
+	    }
+	}
+    }
+*retHitCount = hitCount;
+return hitList;
+}
+
+static struct gfHit *gfSegmentedFindNearHits(struct genoFind *gf, 
+	aaSeq *seq, Bits *qMaskBits, int qMaskOffset, struct lm *lm, int *retHitCount,
+	struct gfSeqSource *target, int tMin, int tMax)
+/* Find hits associated with one sequence in a segmented
+ * index where one mismatch is allowed. */
+{
+struct gfHit *hitList = NULL, *hit;
+int size = seq->size;
+int tileSize = gf->tileSize;
+int tileTailSize = gf->segSize;
+int tileHeadSize = gf->tileSize - tileTailSize;
+int lastStart = size - tileSize;
+char *poly = seq->dna;
+int i, j;
+int tileHead, tileTail;
+int listSize;
+bits32 qStart;
+bits16 *endList;
+int hitCount = 0;
+int varPos, varVal;	/* Variable position. */
+int (*makeTile)(char *poly, int n); 
+int alphabetSize;
+char oldChar, zeroChar;
+int headPosMul, tailPosMul, avoid;
+boolean modTail;
+int *seqValLookup;
+
+
+initNtLookup();
+if (gf->isPep)
+    {
+    makeTile = gfPepTile;
+    alphabetSize = 20;
+    zeroChar = 'A';
+    seqValLookup = aaVal;
+    }
+else
+    {
+    makeTile = gfDnaTile;
+    alphabetSize = 4;
+    zeroChar = 't';
+    seqValLookup = ntVal;
+    }
+
+for (i=0; i<=lastStart; ++i)
+    {
+    if (qMaskBits == NULL || bitCountRange(qMaskBits, i+qMaskOffset, tileSize) == 0)
+	{
+	headPosMul = tailPosMul = 1;
+	for (varPos = tileSize-1; varPos >= 0; --varPos)
+	    {
+	    /* Make a tile that has zero value at variable position. */
+	    modTail = (varPos >= tileHeadSize);
+	    oldChar = poly[i+varPos];
+	    poly[i+varPos] = zeroChar;
+	    tileHead = makeTile(poly+i, tileHeadSize);
+	    tileTail = makeTile(poly+i+tileHeadSize, tileTailSize);
+	    poly[i+varPos] = oldChar;
+
+	    /* Avoid checking the unmodified tile multiple times. */
+	    if (varPos == 0)
+		avoid = -1;
+	    else
+		avoid = seqValLookup[(int)oldChar];
+
+	    if (tileHead >= 0 && tileTail >= 0)
+		{
+		for (varVal=0; varVal<alphabetSize; ++varVal)
+		    {
+		    if (varVal != avoid)
+			{
+			listSize = gf->listSizes[tileHead];
+			qStart = i;
+			endList = gf->endLists[tileHead];
+			for (j=0; j<listSize; ++j)
+			    {
+			    if (endList[0] == tileTail)
+				{
+				int tStart = (endList[1]<<16) + endList[2];
+				if (target == NULL || 
+					(target == findSource(gf, tStart) 
+					&& tStart >= tMin && tStart < tMax) ) 
+				    {
+				    lmAllocVar(lm,hit);
+				    hit->qStart = qStart;
+				    hit->tStart = tStart;
+				    hit->diagonal = tStart + size - qStart;
+				    slAddHead(&hitList, hit);
+				    ++hitCount;
+				    }
+				}
+			    endList += 3;
+			    }
+			}
+		    if (modTail)
+			tileTail += tailPosMul;
+		    else 
+			tileHead += headPosMul;
+		    }
+		}
+	    if (modTail)
+		tailPosMul *= alphabetSize;
+	    else 
+		headPosMul *= alphabetSize;
+	    }
+	}
+    }
+*retHitCount = hitCount;
+return hitList;
+}
+
+
+static struct gfHit *gfFindHitsWithQmask(struct genoFind *gf, bioSeq *seq,
+	Bits *qMaskBits, int qMaskOffset, struct lm *lm, int *retHitCount, 
+	struct gfSeqSource *target, int tMin, int tMax)
+/* Find hits associated with one sequence soft-masking seq according to qMaskBits.
+ * The hits will be in genome rather than chromosome coordinates. */
+{
+struct gfHit *hitList = NULL;
+if (gf->segSize == 0 && !gf->isPep && !gf->allowOneMismatch)
+    {
+    hitList = gfFastFindDnaHits(gf, seq, qMaskBits, qMaskOffset, lm, retHitCount,
+	target, tMin, tMax);
+    }
+else
+    {
+    if (gf->segSize == 0)
+	{
+	if (gf->allowOneMismatch)
+	    {
+	    hitList = gfStraightFindNearHits(gf, seq, qMaskBits, qMaskOffset, lm, 
+		retHitCount, target, tMin, tMax);
+	    }
+	else
+	    {
+	    hitList = gfStraightFindHits(gf, seq, qMaskBits, qMaskOffset, lm, retHitCount, 
+		target, tMin, tMax);
+	    }
+	}
+    else
+	{
+	if (gf->allowOneMismatch)
+	    {
+	    hitList = gfSegmentedFindNearHits(gf, seq, qMaskBits, qMaskOffset, lm, retHitCount,
+		target, tMin, tMax);
+	    }
+	else
+	    {
+	    hitList = gfSegmentedFindHits(gf, seq, qMaskBits, qMaskOffset, lm, retHitCount,
+		target, tMin, tMax);
+	    }
+	}
+    }
+return hitList;
+}
+
+#ifdef DEBUG
+static void dumpClump(struct gfClump *clump, FILE *f)
+/* Print out a clump */
+{
+struct gfSeqSource *target = clump->target;
+char *tName = target->fileName;
+if (tName == NULL) tName = target->seq->name;
+fprintf(f, "%d-%d\t%s:%d-%d\n", clump->qStart, clump->qEnd, tName, clump->tStart, clump->tEnd);
+}
+
+static void dumpClumpList(struct gfClump *clumpList, FILE *f)
+/* Dump list of clumps. */
+{
+struct gfClump *clump;
+for (clump = clumpList; clump != NULL; clump = clump->next)
+    dumpClump(clump, f);
+}
+#endif /* DEBUG */
+
+struct gfClump *gfFindClumpsWithQmask(struct genoFind *gf, bioSeq *seq, 
+	Bits *qMaskBits, int qMaskOffset,
+	struct lm *lm, int *retHitCount)
+/* Find clumps associated with one sequence soft-masking seq according to qMaskBits */
+{
+struct gfClump *clumpList = NULL;
+struct gfHit *hitList;
+int minMatch = gf->minMatch;
+
+#ifdef OLD	/* stepSize makes this obsolete. */
+if (seq->size < gf->tileSize * (gf->minMatch+1))
+     minMatch = 1;
+#endif /* OLD */
+
+hitList =  gfFindHitsWithQmask(gf, seq, qMaskBits, qMaskOffset, lm,
+	retHitCount, NULL, 0, 0);
+cmpQuerySize = seq->size;
+clumpList = clumpHits(gf, hitList, minMatch);
+return clumpList;
+}
+
+struct gfHit *gfFindHitsInRegion(struct genoFind *gf, bioSeq *seq, 
+	Bits *qMaskBits, int qMaskOffset, struct lm *lm, 
+	struct gfSeqSource *target, int tMin, int tMax)
+/* Find hits restricted to one particular region. 
+ * The hits returned by this will be in target sequence
+ * coordinates rather than concatenated whole genome
+ * coordinates as hits inside of clumps usually are.  */
+{
+int targetStart;
+struct gfHit *hitList, *hit;
+int hitCount;
+
+targetStart = target->start;
+hitList =  gfFindHitsWithQmask(gf, seq, qMaskBits, qMaskOffset, lm,
+	&hitCount, target, tMin + targetStart, tMax + targetStart);
+for (hit = hitList; hit != NULL; hit = hit->next)
+    hit->tStart -= targetStart;
+return hitList;
+}
+
+struct gfClump *gfFindClumps(struct genoFind *gf, bioSeq *seq, struct lm *lm, int *retHitCount)
+/* Find clumps associated with one sequence. */
+{
+return gfFindClumpsWithQmask(gf, seq, NULL, 0, lm, retHitCount);
+}
+
+
+void gfTransFindClumps(struct genoFind *gfs[3], aaSeq *seq, struct gfClump *clumps[3], struct lm *lm, int *retHitCount)
+/* Find clumps associated with one sequence in three translated reading frames. */
+{
+int frame;
+int oneHit;
+int hitCount = 0;
+for (frame = 0; frame < 3; ++frame)
+    {
+    clumps[frame] = gfFindClumps(gfs[frame], seq, lm, &oneHit);
+    hitCount += oneHit;
+    }
+*retHitCount = hitCount;
+}
+
+void gfTransTransFindClumps(struct genoFind *gfs[3], aaSeq *seqs[3], 
+	struct gfClump *clumps[3][3], struct lm *lm, int *retHitCount)
+/* Find clumps associated with three sequences in three translated 
+ * reading frames. Used for translated/translated protein comparisons. */
+{
+int qFrame;
+int oneHit;
+int hitCount = 0;
+
+for (qFrame = 0; qFrame<3; ++qFrame)
+    {
+    gfTransFindClumps(gfs, seqs[qFrame], clumps[qFrame], lm, &oneHit);
+    hitCount += oneHit;
+    }
+*retHitCount = hitCount;
+}
+
+void gfMakeOoc(char *outName, char *files[], int fileCount, 
+	int tileSize, bits32 maxPat, enum gfType tType)
+/* Count occurences of tiles in seqList and make a .ooc file. */
+{
+boolean dbIsPep = (tType == gftProt || tType == gftDnaX || tType == gftRnaX);
+struct genoFind *gf = gfNewEmpty(gfMinMatch, gfMaxGap, tileSize, tileSize,
+	maxPat, NULL, dbIsPep, FALSE);
+bits32 *sizes = gf->listSizes;
+int tileSpaceSize = gf->tileSpaceSize;
+bioSeq *seq, *seqList;
+bits32 sig = oocSig, psz = tileSize;
+bits32 i;
+int oocCount = 0;
+char *inName;
+FILE *f = mustOpen(outName, "w");
+
+if (gf->segSize > 0)
+    errAbort("Don't yet know how to make ooc files for large tile sizes.");
+for (i=0; i<fileCount; ++i)
+    {
+    inName = files[i];
+    printf("Loading %s\n", inName);
+    if (nibIsFile(inName))
+        {
+	seqList = nibLoadAll(inName);
+	}
+    else if (twoBitIsFile(inName))
+        {
+	seqList = twoBitLoadAll(inName);
+	for (seq = seqList; seq != NULL; seq = seq->next)
+	    toLowerN(seq->dna, seq->size);
+	}
+    else
+        {
+	seqList = faReadAllSeq(inName, tType != gftProt);
+	}
+    printf("Counting %s\n", inName);
+    for (seq = seqList; seq != NULL; seq = seq->next)
+	{
+	int isRc;
+	for (isRc = 0; isRc <= 1; ++isRc)
+	    {
+	    if (tType == gftDnaX || tType == gftRnaX)
+		{
+		struct trans3 *t3 = trans3New(seq);
+		int frame;
+		for (frame=0; frame<3; ++frame)
+		    {
+		    gfCountSeq(gf, t3->trans[frame]);
+		    }
+		trans3Free(&t3);
+		}
+	    else
+		{
+		gfCountSeq(gf, seq);
+		}
+	    if (tType == gftProt || tType == gftRnaX)
+	        break;
+	    else 
+	        {
+		reverseComplement(seq->dna, seq->size);
+		}
+	    }
+	}
+    freeDnaSeqList(&seqList);
+    }
+printf("Writing %s\n", outName);
+writeOne(f, sig);
+writeOne(f, psz);
+for (i=0; i<tileSpaceSize; ++i)
+    {
+    if (sizes[i] >= maxPat)
+	{
+	writeOne(f, i);
+	++oocCount;
+	}
+    }
+carefulClose(&f);
+genoFindFree(&gf);
+printf("Wrote %d overused %d-mers to %s\n", oocCount, tileSize, outName);
+}
+
+struct gfSeqSource *gfFindNamedSource(struct genoFind *gf, char *name)
+/* Find target of given name.  Return NULL if none. */
+{
+struct gfSeqSource *source = gf->sources;
+int count = gf->sourceCount;
+
+if (source->seq == NULL)	/* Use first source to see if seq or file. */
+    {
+    char rootName[256];
+    while (--count >= 0)
+	{
+	splitPath(source->fileName, NULL, rootName, NULL);
+	if (sameString(name, rootName))
+	     return source;
+	}
+    }
+else
+    {
+    while (--count >= 0)
+	{
+	if (sameString(source->seq->name, name))
+	    return source;
+	source += 1;
+	}
+    }
+return NULL;
+}
+
+static void mergeAdd(struct binKeeper *bk, int start, int end, struct gfSeqSource *src)
+/* Add interval to bin-keeper, merging with any existing overlapping
+ * intervals. */
+{
+struct binElement *iEl, *iList = binKeeperFind(bk, start, end);
+for (iEl = iList; iEl != NULL; iEl = iEl->next)
+    {
+    if (iEl->start < start)
+        start = iEl->start;
+    if (iEl->end > end)
+        end = iEl->end;
+    binKeeperRemove(bk, iEl->start, iEl->end, src);
+    }
+slFreeList(&iList);
+binKeeperAdd(bk, start, end, src);
+}
+
+static struct gfClump *pcrClumps(struct genoFind *gf, char *fPrimer, int fPrimerSize, 
+	char *rPrimer, int rPrimerSize, int minDistance, int maxDistance)
+/* Find possible PCR hits.  The fPrimer and rPrimer are on the same strand. */
+{
+struct gfClump *clumpList = NULL;
+int tileSize = gf->tileSize;
+int fTile;
+int fTileCount = fPrimerSize - tileSize;
+int *rTiles, rTile;
+int rTileCount = rPrimerSize - tileSize;
+int fTileIx,rTileIx,fPosIx,rPosIx;
+bits32 *fPosList, fPos, *rPosList, rPos;
+int fPosListSize, rPosListSize;
+struct hash *targetHash = newHash(0);
+
+/* Build up array of all tiles in reverse primer. */
+AllocArray(rTiles, rTileCount);
+for (rTileIx = 0; rTileIx<rTileCount; ++rTileIx)
+    {
+    rTiles[rTileIx] = gfDnaTile(rPrimer + rTileIx, tileSize);
+    if (rTiles[rTileIx] == -1)
+        errAbort("Bad char in reverse primer sequence: %s", rPrimer);
+    }
+
+/* Loop through all tiles in forward primer. */
+for (fTileIx=0; fTileIx<fTileCount; ++fTileIx)
+    {
+    fTile = gfDnaTile(fPrimer + fTileIx, tileSize);
+    if (fTile >= 0)
+        {
+	fPosListSize = gf->listSizes[fTile];
+	fPosList = gf->lists[fTile];
+	for (fPosIx=0; fPosIx < fPosListSize; ++fPosIx)
+	    {
+	    fPos = fPosList[fPosIx];
+	    /* Loop through hits to reverse primer. */
+	    for (rTileIx=0; rTileIx < rTileCount; ++rTileIx)
+	        {
+		rTile = rTiles[rTileIx];
+		rPosListSize = gf->listSizes[rTile];
+		rPosList = gf->lists[rTile];
+		for (rPosIx=0; rPosIx < rPosListSize; ++rPosIx)
+		    {
+		    rPos = rPosList[rPosIx];
+		    if (rPos > fPos)
+		        {
+			int distance = rPos - fPos;
+			if (distance >= minDistance && distance <= maxDistance)
+			    {
+			    struct gfSeqSource *target = findSource(gf, fPos);
+			    if (rPos < target->end)
+			        {
+				struct binKeeper *bk;
+				int tStart = target->start;
+				char *tName = target->fileName;
+				if (tName == NULL)
+				    tName = target->seq->name;
+				if ((bk = hashFindVal(targetHash, tName)) == NULL)
+				    {
+				    bk = binKeeperNew(0, target->end - tStart);
+				    hashAdd(targetHash, tName, bk);
+				    }
+				mergeAdd(bk, fPos - tStart, rPos - tStart, target);
+				}
+			    }
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+/* Make clumps and clean up temporary structures. */
+    {
+    struct hashEl *tList, *tEl;
+    tList = hashElListHash(targetHash);
+    for (tEl = tList; tEl != NULL; tEl = tEl->next)
+        {
+	struct binKeeper *bk = tEl->val;
+	struct binElement *bkList, *bkEl;
+	bkList = binKeeperFindAll(bk);
+	for (bkEl = bkList; bkEl != NULL; bkEl = bkEl->next)
+	    {
+	    struct gfClump *clump;
+	    AllocVar(clump);
+	    clump->target = bkEl->val;
+	    clump->tStart = bkEl->start;
+	    clump->tEnd = bkEl->end;
+	    slAddHead(&clumpList, clump);
+	    }
+	slFreeList(&bkList);
+	binKeeperFree(&bk);
+	}
+    hashElFreeList(&tList);
+    hashFree(&targetHash);
+    }
+freez(&rTiles);
+return clumpList;	
+}
+
+struct gfClump *gfPcrClumps(struct genoFind *gf, char *fPrimer, int fPrimerSize, 
+	char *rPrimer, int rPrimerSize, int minDistance, int maxDistance)
+/* Find possible PCR hits.  The fPrimer and rPrimer are on opposite strands. */
+{
+struct gfClump *clumpList;
+if (gf->segSize > 0)
+    errAbort("Can't do PCR on large tile sizes");
+if (gf->isPep)
+    errAbort("Can't do PCR on protein/translated index");
+tolowers(fPrimer);
+tolowers(rPrimer);
+reverseComplement(rPrimer, rPrimerSize);
+clumpList = pcrClumps(gf, fPrimer, fPrimerSize, rPrimer, rPrimerSize, 
+	minDistance, maxDistance);
+reverseComplement(rPrimer, rPrimerSize);
+return clumpList;
+}
+
+int gfDefaultRepMatch(int tileSize, int stepSize, boolean protTiles)
+/* Figure out appropriate step repMatch value. */
+{
+int repMatch = 1024;
+if (protTiles)
+    {
+    if (tileSize == 3)
+	repMatch = 600000;
+    else if (tileSize == 4)
+	repMatch = 30000;
+    else if (tileSize == 5)
+	repMatch = 1500;
+    else if (tileSize == 6)
+	repMatch = 75;
+    else if (tileSize <= 7)
+	repMatch = 10;
+    else
+        internalErr();
+    }
+else
+    {
+    if (tileSize == 15)
+	repMatch = 16;
+    else if (tileSize == 14)
+	repMatch = 32;
+    else if (tileSize == 13)
+	repMatch = 128;
+    else if (tileSize == 12)
+	repMatch = 256;
+    else if (tileSize == 11)
+	repMatch = 4*256;
+    else if (tileSize == 10)
+	repMatch = 16*256;
+    else if (tileSize == 9)
+	repMatch = 64*256;
+    else if (tileSize == 8)
+	repMatch = 256*256;
+    else if (tileSize == 7)
+	repMatch = 1024*256;
+    else if (tileSize == 6)
+	repMatch = 4*1024*256;
+    else
+        internalErr();
+    }
+repMatch *= tileSize;
+repMatch /= stepSize;
+return repMatch;
+}
diff --git a/jkOwnLib/gfBlatLib.c b/jkOwnLib/gfBlatLib.c
new file mode 100644
index 0000000..81d8a76
--- /dev/null
+++ b/jkOwnLib/gfBlatLib.c
@@ -0,0 +1,1613 @@
+/* gfBlatLib - stuff that blat-related clients of genoFind library or
+ * gfServer on the web use. */
+/* Copyright 2001-2005 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "net.h"
+#include "linefile.h"
+#include "sqlNum.h"
+#include "dnaseq.h"
+#include "fa.h"
+#include "fuzzyFind.h"
+#include "supStitch.h"
+#include "genoFind.h"
+#include "gfInternal.h"
+#include "errabort.h"
+#include "nib.h"
+#include "twoBit.h"
+#include "trans3.h"
+
+
+
+static int ssAliCount = 16;	/* Number of alignments returned by ssStitch. */
+
+#ifdef DEBUG
+void dumpRange(struct gfRange *r, FILE *f)
+/* Dump range to file. */
+{
+fprintf(f, "%d-%d %s %d-%d, hits %d\n", r->qStart, r->qEnd, r->tName, r->tStart, r->tEnd, r->hitCount);
+}
+
+void dumpRangeList(struct gfRange *rangeList, FILE *f)
+/* Dump range list to file for debugging. */
+{
+struct gfRange *range;
+for (range = rangeList; range != NULL; range = range->next)
+    dumpRange(range, f);
+}
+#endif /* DEBUG */
+
+void gfRangeFree(struct gfRange **pEl)
+/* Free a single dynamically allocated gfRange such as created
+ * with gfRangeLoad(). */
+{
+struct gfRange *el;
+
+if ((el = *pEl) == NULL) return;
+freeMem(el->tName);
+if (el->components != NULL)
+    gfRangeFreeList(&el->components);
+freez(pEl);
+}
+
+void gfRangeFreeList(struct gfRange **pList)
+/* Free a list of dynamically allocated gfRange's */
+{
+struct gfRange *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    gfRangeFree(&el);
+    }
+*pList = NULL;
+}
+
+static struct gfRange *gfRangeLoad(char **row)
+/* Load a gfRange from array of strings parsed from
+ * server. Dispose of this with gfRangeFree(). */
+{
+struct gfRange *ret;
+
+AllocVar(ret);
+ret->qStart = atoi(row[0]);
+ret->qEnd = atoi(row[1]);
+ret->tName = cloneString(row[2]);
+ret->tStart = atoi(row[3]);
+ret->tEnd = atoi(row[4]);
+ret->hitCount = atoi(row[5]);
+return ret;
+}
+
+int gfRangeCmpTarget(const void *va, const void *vb)
+/* Compare to sort based on target position. */
+{
+const struct gfRange *a = *((struct gfRange **)va);
+const struct gfRange *b = *((struct gfRange **)vb);
+int diff;
+
+diff = strcmp(a->tName, b->tName);
+if (diff == 0)
+    {
+    long lDiff = a->t3 - b->t3;
+    if (lDiff < 0)
+       diff = -1;
+    else if (lDiff > 0)
+       diff = 1;
+    else
+       diff = 0;
+#ifdef SOLARIS_WORKAROUND_COMPILER_BUG_BUT_FAILS_IN_64_BIT
+    diff = (unsigned long)(a->t3) - (unsigned long)(b->t3);	/* Casts needed for Solaris.  Thanks Darren Platt! */
+#endif /* SOLARIS_WORKAROUND_COMPILER_BUG_BUT_FAILS_IN_64_BIT */
+    }
+if (diff == 0)
+    diff = a->tStart - b->tStart;
+return diff;
+}
+
+static void startSeqQuery(int conn, bioSeq *seq, char *type)
+/* Send a query that involves some sequence. */
+{
+char buf[256];
+sprintf(buf, "%s%s %d", gfSignature(), type, seq->size);
+mustWriteFd(conn, buf, strlen(buf));
+if (read(conn, buf, 1) < 0)
+    errAbort("startSeqQuery: read failed: %s", strerror(errno));
+if (buf[0] != 'Y')
+    errAbort("Expecting 'Y' from server, got %c", buf[0]);
+mustWriteFd(conn, seq->dna, seq->size);
+}
+
+static void gfServerWarn(bioSeq *seq, char *warning)
+/* Write out warning. */
+{
+warn("couldn't process %s: %s", seq->name, warning);
+}
+
+static struct gfRange *gfQuerySeq(int conn, struct dnaSeq *seq)
+/* Ask server for places sequence hits. */
+{
+struct gfRange *rangeList = NULL, *range;
+char buf[256], *row[6];
+int rowSize;
+
+startSeqQuery(conn, seq, "query");
+
+/* Read results line by line and save in list, and return. */
+for (;;)
+    {
+    netRecieveString(conn, buf);
+    if (sameString(buf, "end"))
+	{
+	break;
+	}
+    else if (startsWith("Error:", buf))
+        {
+	gfServerWarn(seq, buf);
+	break;
+	}
+    else
+	{
+	rowSize = chopLine(buf, row);
+	if (rowSize < 6)
+	    errAbort("Expecting 6 words from server got %d", rowSize);
+	range = gfRangeLoad(row);
+	slAddHead(&rangeList, range);
+	}
+    }
+slReverse(&rangeList);
+return rangeList;
+}
+
+static int findTileSize(char *line)
+/* Parse through line/val pairs looking for tileSize. */
+{
+char *var, *val;
+int tileSize = 4;
+for (;;)
+    {
+    var = nextWord(&line);
+    if (var == NULL)
+         break;
+    val = nextWord(&line);
+    if (val == NULL)
+	 {
+	 internalErr();
+         break;
+	 }
+    if (sameString("tileSize", var))
+         {
+	 tileSize = atoi(val);
+	 if (tileSize <= 0)
+	     internalErr();
+	 }
+    }
+return tileSize;
+}
+
+struct gfHit *getHitsFromServer(int conn, struct lm *lm)
+/* Read a lone line of hits from server. */
+{
+char *s, *line, *q, *t;
+struct gfHit *hitList = NULL, *hit;
+s = line = netRecieveLongString(conn);
+for (;;)
+    {
+    if ((q = nextWord(&line)) == NULL)
+	 break;
+    if ((t = nextWord(&line)) == NULL)
+	 internalErr();
+    lmAllocVar(lm, hit);
+    hit->qStart = sqlUnsigned(q);
+    hit->tStart = sqlUnsigned(t);
+    slAddHead(&hitList, hit);
+    }
+freez(&s);
+slReverse(&hitList);
+return hitList;
+}
+
+static void gfQuerySeqTrans(int conn, aaSeq *seq, struct gfClump *clumps[2][3], 
+    struct lm *lm, struct gfSeqSource **retSsList, int *retTileSize)
+/* Query server for clumps where aa sequence hits translated index. */
+{
+int frame, isRc, rowSize;
+struct gfClump *clump;
+int tileSize = 0;
+char *line;
+char buf[256], *row[12];
+struct gfSeqSource *ssList = NULL, *ss;
+
+for (isRc = 0; isRc <= 1; ++isRc)
+    for (frame = 0; frame<3; ++frame)
+	clumps[isRc][frame] = NULL;
+
+/* Send sequence to server. */
+startSeqQuery(conn, seq, "protQuery");
+line = netRecieveString(conn, buf);
+if (!startsWith("Error:", line))
+    {
+    tileSize = findTileSize(line);
+
+    /* Read results line by line and save in memory. */
+    for (;;)
+	{
+	/* Read and parse first line that describes clump overall. */
+	netRecieveString(conn, buf);
+	if (sameString(buf, "end"))
+	    {
+	    break;
+	    }
+	else if (startsWith("Error:", buf))
+	    {
+	    gfServerWarn(seq, buf);
+	    break;
+	    }
+	rowSize = chopLine(buf, row);
+	if (rowSize < 8)
+	    errAbort("Expecting 8 words from server got %d", rowSize);
+	AllocVar(clump);
+	clump->qStart = sqlUnsigned(row[0]);
+	clump->qEnd = sqlUnsigned(row[1]);
+	AllocVar(ss);
+	ss->fileName = cloneString(row[2]);
+	slAddHead(&ssList, ss);
+	clump->target = ss;
+	clump->tStart = sqlUnsigned(row[3]);
+	clump->tEnd = sqlUnsigned(row[4]);
+	clump->hitCount = sqlUnsigned(row[5]);
+	isRc = ((row[6][0] == '-') ? 1 : 0);
+	frame = sqlUnsigned(row[7]);
+	slAddHead(&clumps[isRc][frame], clump);
+
+	/* Read and parse next (long) line that describes hits. */
+	clump->hitList = getHitsFromServer(conn, lm);
+	assert(slCount(clump->hitList) == clump->hitCount);
+	}
+    for (isRc = 0; isRc <= 1; ++isRc)
+	for (frame = 0; frame<3; ++frame)
+	    slReverse(&clumps[isRc][frame]);
+    }
+else
+    {
+    gfServerWarn(seq, line);
+    }
+*retSsList = ssList;
+*retTileSize = tileSize;
+}
+
+static void gfQuerySeqTransTrans(int conn, struct dnaSeq *seq, 
+    struct gfClump *clumps[2][3][3], 
+    struct lm *lm, struct gfSeqSource **retSsList, int *retTileSize)
+/* Query server for clumps where translated DNA sequence hits translated 
+ * index. */
+{
+int qFrame, tFrame, isRc, rowSize;
+struct gfClump *clump;
+int tileSize = 0;
+char *line;
+char buf[256], *row[12];
+struct gfSeqSource *ssList = NULL, *ss;
+
+for (isRc = 0; isRc <= 1; ++isRc)
+    for (qFrame = 0; qFrame<3; ++qFrame)
+	for (tFrame = 0; tFrame<3; ++tFrame)
+	    clumps[isRc][qFrame][tFrame] = NULL;
+
+/* Send sequence to server. */
+startSeqQuery(conn, seq, "transQuery");
+line = netRecieveString(conn, buf);
+if (!startsWith("Error:", line))
+    {
+    tileSize = findTileSize(line);
+
+    /* Read results line by line and save in memory. */
+    for (;;)
+	{
+	/* Read and parse first line that describes clump overall. */
+	netRecieveString(conn, buf);
+	if (sameString(buf, "end"))
+	    {
+	    break;
+	    }
+	else if (startsWith("Error:", buf))
+	    {
+	    gfServerWarn(seq, buf);
+	    break;
+	    }
+	rowSize = chopLine(buf, row);
+	if (rowSize < 9)
+	    errAbort("Expecting 9 words from server got %d", rowSize);
+	AllocVar(clump);
+	clump->qStart = sqlUnsigned(row[0]);
+	clump->qEnd = sqlUnsigned(row[1]);
+	AllocVar(ss);
+	ss->fileName = cloneString(row[2]);
+	slAddHead(&ssList, ss);
+	clump->target = ss;
+	clump->tStart = sqlUnsigned(row[3]);
+	clump->tEnd = sqlUnsigned(row[4]);
+	clump->hitCount = sqlUnsigned(row[5]);
+	isRc = ((row[6][0] == '-') ? 1 : 0);
+	qFrame = sqlUnsigned(row[7]);
+	tFrame = sqlUnsigned(row[8]);
+	slAddHead(&clumps[isRc][qFrame][tFrame], clump);
+
+	/* Read and parse next (long) line that describes hits. */
+	clump->hitList = getHitsFromServer(conn, lm);
+	assert(slCount(clump->hitList) == clump->hitCount);
+	}
+    for (isRc = 0; isRc <= 1; ++isRc)
+	for (qFrame = 0; qFrame<3; ++qFrame)
+	    for (tFrame = 0; tFrame<3; ++tFrame)
+		slReverse(&clumps[isRc][qFrame][tFrame]);
+    }
+else
+    {
+    gfServerWarn(seq, buf);
+    }
+*retSsList = ssList;
+*retTileSize = tileSize;
+}
+
+
+
+struct gfRange *gfRangesBundle(struct gfRange *exonList, int maxIntron)
+/* Bundle a bunch of 'exons' into plausable 'genes'.  It's
+ * not necessary to be precise here.  The main thing is to
+ * group together exons that are close to each other in the
+ * same target sequence. */
+{
+struct gfRange *geneList = NULL, *gene = NULL, *lastExon = NULL, *exon, *nextExon;
+
+for (exon = exonList; exon != NULL; exon = nextExon)
+    {
+    nextExon = exon->next;
+    if (lastExon == NULL || !sameString(lastExon->tName, exon->tName) 
+	|| exon->t3  != lastExon->t3
+        || exon->tStart - lastExon->tEnd > maxIntron)
+	{
+	AllocVar(gene);
+	gene->tStart = exon->tStart;
+	gene->tEnd = exon->tEnd;
+	gene->tName = cloneString(exon->tName);
+	gene->tSeq = exon->tSeq;
+	gene->qStart = exon->qStart;
+	gene->qEnd = exon->qEnd;
+	gene->hitCount = exon->hitCount;
+	gene->t3 = exon->t3;
+	slAddHead(&gene->components, exon);
+	slAddHead(&geneList, gene);
+	}
+    else
+        {
+	if (exon->qStart < gene->qStart) gene->qStart = exon->qStart;
+	if (exon->qEnd > gene->qEnd) gene->qEnd = exon->qEnd;
+	if (exon->tStart < gene->tStart) gene->tStart = exon->tStart;
+	if (exon->tEnd > gene->tEnd) gene->tEnd = exon->tEnd;
+	gene->hitCount += exon->hitCount;
+	slAddTail(&gene->components, exon);
+	}
+    lastExon = exon;
+    }
+slReverse(&geneList);
+return geneList;
+}
+
+static int usualExpansion = 500;
+
+static boolean alignComponents(struct gfRange *combined, struct ssBundle *bun, 
+	enum ffStringency stringency)
+/* Align each piece of combined->components and put result in
+ * bun->ffList. */
+{
+struct gfRange *range;
+struct dnaSeq *qSeq = bun->qSeq, *tSeq = bun->genoSeq;
+struct ssFfItem *ffi;
+struct ffAli *ali;
+int qStart, qEnd, tStart, tEnd;
+int extra = 250;
+boolean gotAny = FALSE;
+
+for (range = combined->components; range != NULL; range = range->next)
+    {
+    /* Expand to include some extra sequence around range. */
+    qStart = range->qStart - extra;
+    tStart = range->tStart - extra;
+    qEnd = range->qEnd + extra;
+    tEnd = range->tEnd + extra;
+    if (range == combined->components)
+	{
+        qStart -= extra;
+	tStart -= extra;
+	}
+    if (range->next == NULL)
+        {
+	qEnd += extra;
+	tEnd += extra;
+	}
+    if (qStart < combined->qStart) qStart = combined->qStart;
+    if (tStart < combined->tStart) tStart = combined->tStart;
+    if (qEnd > combined->qEnd) qEnd = combined->qEnd;
+    if (tEnd > combined->tEnd) tEnd = combined->tEnd;
+    ali = ffFind(qSeq->dna + qStart,
+                 qSeq->dna + qEnd,
+		 tSeq->dna + tStart - combined->tStart,
+		 tSeq->dna + tEnd - combined->tStart,
+		 stringency);
+    if (ali != NULL)
+        {
+	AllocVar(ffi);
+	ffi->ff = ali;
+	slAddHead(&bun->ffList, ffi);
+	gotAny = TRUE;
+	}
+    }
+return gotAny;
+}
+
+static int scoreAli(struct ffAli *ali, boolean isProt, 
+	enum ffStringency stringency, 
+	struct dnaSeq *tSeq, struct trans3 *t3List)
+/* Score alignment. */
+{
+int (*scoreFunc)(char *a, char *b, int size);
+struct ffAli *ff, *nextFf;
+int score = 0;
+if (isProt) 
+    scoreFunc = aaScoreMatch;
+else
+    scoreFunc = dnaScoreMatch;
+for (ff = ali; ff != NULL; ff = nextFf)
+    {
+    nextFf = ff->right;
+    score += scoreFunc(ff->nStart, ff->hStart, ff->nEnd-ff->nStart);
+    if (nextFf != NULL)
+        {
+	int nhStart = trans3GenoPos(nextFf->hStart, tSeq, t3List, FALSE);
+	int ohEnd = trans3GenoPos(ff->hEnd, tSeq, t3List, TRUE);
+	int hGap = nhStart - ohEnd;
+	int nGap = nextFf->nStart - ff->nEnd;
+	score -= ffCalcGapPenalty(hGap, nGap, stringency);
+	}
+    }
+return score;
+}
+
+static void saveAlignments(char *chromName, int chromSize, int chromOffset, 
+	struct ssBundle *bun, struct hash *t3Hash, 
+	boolean qIsRc, boolean tIsRc,
+	enum ffStringency stringency, int minMatch, struct gfOutput *out)
+/* Save significant alignments to file in .psl format. */
+{
+struct dnaSeq *tSeq = bun->genoSeq, *qSeq = bun->qSeq;
+struct ssFfItem *ffi;
+for (ffi = bun->ffList; ffi != NULL; ffi = ffi->next)
+    {
+    struct ffAli *ff = ffi->ff;
+    struct trans3 *t3List = NULL;
+    int score;
+    if (t3Hash != NULL)
+	t3List = hashMustFindVal(t3Hash, tSeq->name);
+    score = scoreAli(ff, bun->isProt, stringency, tSeq, t3List);
+    if (score >= minMatch)
+	{
+	out->out(chromName, chromSize, chromOffset, ff, tSeq, t3Hash, qSeq, 
+	    qIsRc, tIsRc, stringency, minMatch, out);
+	}
+    }
+}
+
+struct hash *gfFileCacheNew()
+/* Create hash for storing info on .nib and .2bit files. */
+{
+return hashNew(0);
+}
+
+static void gfFileCacheFreeEl(struct hashEl *el)
+/* Free up one file cache info. */
+{
+char *name = el->name;
+if (nibIsFile(name))
+    {
+    struct nibInfo *nib = el->val;
+    nibInfoFree(&nib);
+    }
+else
+    {
+    struct twoBitFile *tbf = el->val;
+    twoBitClose(&tbf);
+    }
+el->val = NULL;
+}
+
+void gfFileCacheFree(struct hash **pCache)
+/* Free up resources in cache. */
+{
+struct hash *cache = *pCache;
+if (cache != NULL)
+    {
+    hashTraverseEls(cache, gfFileCacheFreeEl);
+    hashFree(pCache);
+    }
+}
+
+static void getTargetName(char *tSpec, boolean includeFile, char *targetName)
+/* Put sequence name, optionally prefixed by file: in targetName. */
+{
+if (includeFile)
+    {
+    char seqName[128];
+    char fileName[PATH_LEN];
+    gfiGetSeqName(tSpec, seqName, fileName);
+    safef(targetName, PATH_LEN, "%s:%s", fileName, seqName);
+    }
+else
+    gfiGetSeqName(tSpec, targetName, NULL);
+}
+
+void gfAlignStrand(int *pConn, char *tSeqDir, struct dnaSeq *seq,
+    boolean isRc, int minMatch, struct hash *tFileCache, struct gfOutput *out)
+/* Search genome on server with one strand of other sequence to find homology. 
+ * Then load homologous bits of genome locally and do detailed alignment.
+ * Call 'outFunction' with each alignment that is found. */
+{
+struct ssBundle *bun;
+struct gfRange *rangeList = NULL, *range;
+struct dnaSeq *targetSeq;
+char targetName[PATH_LEN];
+
+rangeList = gfQuerySeq(*pConn, seq);
+close(*pConn);
+*pConn = -1;
+slSort(&rangeList, gfRangeCmpTarget);
+rangeList = gfRangesBundle(rangeList, ffIntronMax);
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    getTargetName(range->tName, out->includeTargetFile, targetName);
+    targetSeq = gfiExpandAndLoadCached(range, tFileCache, tSeqDir, 
+    	seq->size, &range->tTotalSize, FALSE, FALSE, usualExpansion);
+    AllocVar(bun);
+    bun->qSeq = seq;
+    bun->genoSeq = targetSeq;
+    alignComponents(range, bun, ffCdna);
+    ssStitch(bun, ffCdna, minMatch, ssAliCount);
+    saveAlignments(targetName, range->tTotalSize, range->tStart, 
+	bun, NULL, isRc, FALSE, ffCdna, minMatch, out);
+    ssBundleFree(&bun);
+    freeDnaSeq(&targetSeq);
+    }
+gfRangeFreeList(&rangeList);
+}
+
+char *clumpTargetName(struct gfClump *clump)
+/* Return target name of clump - whether it is in memory or on disk. */
+{
+struct gfSeqSource *target = clump->target;
+char *name;
+if (target->seq != NULL)
+    name = target->seq->name;
+else
+    name = target->fileName;
+if (name == NULL)
+    internalErr();
+return name;
+}
+
+static struct gfRange *seqClumpToRangeList(struct gfClump *clumpList, int frame)
+/* Convert from clump list to range list. */
+{
+struct gfRange *rangeList = NULL, *range;
+struct gfClump *clump;
+char *name;
+int tOff;
+
+for (clump = clumpList; clump != NULL; clump = clump->next)
+    {
+    tOff = clump->target->start;
+    AllocVar(range);
+    range->qStart = clump->qStart;
+    range->qEnd = clump->qEnd;
+    name = clumpTargetName(clump);
+    range->tName = cloneString(name);
+    range->tStart = clump->tStart - tOff;
+    range->tEnd = clump->tEnd - tOff;
+    range->tSeq = clump->target->seq;
+    range->frame = frame;
+    slAddHead(&rangeList, range);
+    }
+slReverse(&rangeList);
+return rangeList;
+}
+
+static struct ssBundle *gfClumpsToBundles(struct gfClump *clumpList, 
+    boolean isRc, struct dnaSeq *seq, int minScore,  
+    struct gfRange **retRangeList)
+/* Convert gfClumps to an actual alignments (ssBundles) */ 
+{
+struct ssBundle *bun, *bunList = NULL;
+struct gfRange *rangeList = NULL, *range;
+struct dnaSeq *targetSeq;
+
+rangeList = seqClumpToRangeList(clumpList, 0);
+slSort(&rangeList, gfRangeCmpTarget);
+rangeList = gfRangesBundle(rangeList, 2000);
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    targetSeq = range->tSeq;
+    gfiExpandRange(range, seq->size, targetSeq->size, FALSE, isRc, 
+    	usualExpansion);
+    range->tStart = 0;
+    range->tEnd = targetSeq->size;
+    AllocVar(bun);
+    bun->qSeq = seq;
+    bun->genoSeq = targetSeq;
+    alignComponents(range, bun, ffCdna);
+    ssStitch(bun, ffCdna, minScore, ssAliCount);
+    slAddHead(&bunList, bun);
+    }
+slReverse(&bunList);
+*retRangeList = rangeList;
+return bunList;
+}
+
+
+static void extendHitRight(int qMax, int tMax,
+	char **pEndQ, char **pEndT, int (*scoreMatch)(char a, char b), 
+	int maxDown)
+/* Extend endQ/endT as much to the right as possible. */
+{
+int maxScore = 0;
+int score = 0;
+int maxPos = -1;
+int last = min(qMax, tMax);
+int i;
+char *q = *pEndQ, *t = *pEndT;
+
+for (i=0; i<last; ++i)
+    {
+    score += scoreMatch(q[i], t[i]);
+    if (score > maxScore)
+	 {
+         maxScore = score;
+	 maxPos = i;
+	 }
+    else if (i > maxPos + maxDown)
+         {
+	 break;
+	 }
+    }
+*pEndQ = q+maxPos+1;
+*pEndT = t+maxPos+1;
+}
+
+static void extendHitLeft(int qMax, int tMax,
+	char **pStartQ, char **pStartT, int (*scoreMatch)(char a, char b),
+	int maxDown)
+/* Extend startQ/startT as much to the left as possible. */
+{
+int maxScore = 0;
+int score = 0;
+int maxPos = 0;
+int last = -min(qMax, tMax);
+int i;
+char *q = *pStartQ, *t = *pStartT;
+
+for (i=-1; i>=last; --i)
+    {
+    score += scoreMatch(q[i], t[i]);
+    if (score > maxScore)
+	 {
+         maxScore = score;
+	 maxPos = i;
+	 }
+    else if (i < maxPos - maxDown)
+         {
+	 break;
+	 }
+    }
+*pStartQ = q+maxPos;
+*pStartT = t+maxPos;
+}
+
+
+static void clumpToHspRange(struct gfClump *clump, bioSeq *qSeq, int tileSize,
+	int frame, struct trans3 *t3, struct gfRange **pRangeList, 
+	boolean isProt, boolean fastMap)
+/* Covert clump->hitList to HSPs (high scoring local sequence pair,
+ * that is longest alignment without gaps) and add resulting HSPs to
+ * rangeList. */
+{
+struct gfSeqSource *target = clump->target;
+aaSeq *tSeq = target->seq;
+BIOPOL *qs, *ts, *qe, *te;
+struct gfHit *hit;
+int qStart = 0, tStart = 0, qEnd = 0, tEnd = 0, newQ = 0, newT = 0;
+boolean outOfIt = TRUE;		/* Logically outside of a clump. */
+struct gfRange *range;
+BIOPOL *lastQs = NULL, *lastQe = NULL, *lastTs = NULL, *lastTe = NULL;
+int (*scoreMatch)(char a, char b) = (isProt ? aaScore2 : dnaScore2);
+int maxDown, minSpan;
+
+if (fastMap)
+    {
+    maxDown = 1;
+    minSpan = 50;
+    }
+else
+    {
+    maxDown = 10;
+    minSpan = 0;
+    }
+
+
+if (tSeq == NULL)
+    internalErr();
+
+/* The termination condition of this loop is a little complicated.
+ * We want to output something either when the next hit can't be
+ * merged into the previous, or at the end of the list.  To avoid
+ * duplicating the output code we're forced to complicate the loop
+ * termination logic.  Hence the check for hit == NULL to break
+ * the loop is not until near the end of the loop. */
+for (hit = clump->hitList; ; hit = hit->next)
+    {
+    if (hit != NULL)
+        {
+	newQ = hit->qStart;
+	newT = hit->tStart - target->start;
+	}
+
+    /* See if it's time to output merged (diagonally adjacent) hits. */
+    if (!outOfIt)	/* Not first time through. */
+        {
+	/* As a micro-optimization handle strings of adjacent hits
+	 * specially.  Don't do the extensions until we've merged
+	 * all adjacent hits. */
+	if (hit == NULL || newQ != qEnd || newT != tEnd)
+	    {
+	    qs = qSeq->dna + qStart;
+	    ts = tSeq->dna + tStart;
+	    qe = qSeq->dna + qEnd;
+	    te = tSeq->dna + tEnd;
+	    extendHitRight(qSeq->size - qEnd, tSeq->size - tEnd,
+		&qe, &te, scoreMatch, maxDown);
+	    extendHitLeft(qStart, tStart, &qs, &ts, scoreMatch, maxDown);
+	    if (qs != lastQs || ts != lastTs || qe != lastQe || qs !=  lastQs)
+		{
+		lastQs = qs;
+		lastTs = ts;
+		lastQe = qe;
+		lastTe = te;
+		if (qe - qs >= minSpan)
+		    {
+		    AllocVar(range);
+		    range->qStart = qs - qSeq->dna;
+		    range->qEnd = qe - qSeq->dna;
+		    range->tName = cloneString(tSeq->name);
+		    range->tSeq = tSeq;
+		    range->tStart = ts - tSeq->dna;
+		    range->tEnd = te - tSeq->dna;
+		    range->hitCount = qe - qs;
+		    range->frame = frame;
+		    range->t3 = t3;
+		    assert(range->tEnd <= tSeq->size);
+		    slAddHead(pRangeList, range);
+		    }
+		}
+	    outOfIt = TRUE;
+	    }
+	}
+    if (hit == NULL)
+        break;
+
+    if (outOfIt)
+        {
+	qStart = newQ;
+	qEnd = qStart + tileSize;
+	tStart = newT;
+	tEnd = tStart + tileSize;
+	outOfIt = FALSE;
+	}
+    else
+        {
+	qEnd = newQ + tileSize;
+	tEnd = newT + tileSize;
+	}
+    }
+}
+
+struct ssFfItem *gfRangesToFfItem(struct gfRange *rangeList, aaSeq *qSeq)
+/* Convert ranges to ssFfItem's. */
+{
+AA *q = qSeq->dna;
+struct ffAli *ffList = NULL, *ff;
+struct gfRange *range;
+struct ssFfItem *ffi;
+
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    aaSeq *tSeq = range->tSeq;
+    AA *t = tSeq->dna;
+    AllocVar(ff);
+    ff->nStart = q + range->qStart;
+    ff->nEnd = q + range->qEnd;
+    ff->hStart = t + range->tStart;
+    ff->hEnd = t + range->tEnd;
+    ff->left = ffList;
+    ffList = ff;
+    }
+AllocVar(ffi);
+ffi->ff = ffMakeRightLinks(ffList);
+return ffi;
+}
+
+static struct ssBundle *fastMapClumpsToBundles(struct genoFind *gf, struct gfClump *clumpList, bioSeq *qSeq)
+/* Convert gfClumps ffAlis. */
+{
+struct gfClump *clump;
+struct gfRange *rangeList = NULL, *range;
+bioSeq *targetSeq;
+struct ssBundle *bunList = NULL, *bun;
+
+for (clump = clumpList; clump != NULL; clump = clump->next)
+    clumpToHspRange(clump, qSeq, gf->tileSize, 0, NULL, &rangeList, FALSE, TRUE);
+slReverse(&rangeList);
+slSort(&rangeList, gfRangeCmpTarget);
+rangeList = gfRangesBundle(rangeList, 256);
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    targetSeq = range->tSeq;
+    AllocVar(bun);
+    bun->qSeq = qSeq;
+    bun->genoSeq = targetSeq;
+    bun->ffList = gfRangesToFfItem(range->components, qSeq);
+    bun->isProt = FALSE;
+    slAddHead(&bunList, bun);
+    }
+gfRangeFreeList(&rangeList);
+return bunList;
+}
+
+static void gfAlignSomeClumps(struct genoFind *gf,  struct gfClump *clumpList, 
+    bioSeq *seq, boolean isRc,  int minMatch, 
+    struct gfOutput *out, boolean isProt, enum ffStringency stringency)
+/* Convert gfClumps to an actual alignment that gets saved via 
+ * outFunction/outData. */
+{
+struct gfClump *clump;
+struct gfRange *rangeList = NULL, *range;
+bioSeq *targetSeq;
+struct ssBundle *bun;
+int intronMax = ffIntronMax;
+
+if (isProt)
+    intronMax /= 3;
+for (clump = clumpList; clump != NULL; clump = clump->next)
+    {
+    clumpToHspRange(clump, seq, gf->tileSize, 0, NULL, &rangeList, isProt, FALSE);
+    }
+slReverse(&rangeList);
+slSort(&rangeList, gfRangeCmpTarget);
+rangeList = gfRangesBundle(rangeList, intronMax);
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    targetSeq = range->tSeq;
+    AllocVar(bun);
+    bun->qSeq = seq;
+    bun->genoSeq = targetSeq;
+    bun->ffList = gfRangesToFfItem(range->components, seq);
+    bun->isProt = isProt;
+    ssStitch(bun, stringency, minMatch, ssAliCount);
+    saveAlignments(targetSeq->name, targetSeq->size, 0, 
+	bun, NULL, isRc, FALSE, stringency, minMatch, out);
+    ssBundleFree(&bun);
+    }
+gfRangeFreeList(&rangeList);
+}
+
+void gfAlignAaClumps(struct genoFind *gf,  struct gfClump *clumpList, 
+    aaSeq *seq, boolean isRc,  int minMatch, 
+    struct gfOutput *out)
+{
+gfAlignSomeClumps(gf, clumpList, seq, isRc, minMatch, out, TRUE, ffTight);
+}
+
+int rangeScore(struct gfRange *range, struct dnaSeq *qSeq)
+/* Return score associated with range. */
+{
+struct gfRange *comp;
+struct dnaSeq *tSeq;
+int score = 0;
+for (comp = range->components; comp != NULL; comp = comp->next)
+    {
+    tSeq = comp->tSeq;
+    score += dnaScoreMatch(tSeq->dna + range->tStart, qSeq->dna + range->qStart, 
+        range->tEnd - range->tStart);
+    if (comp->next != NULL)
+        score -= 4;
+    }
+return score;
+}
+
+
+void gfFindAlignAaTrans(struct genoFind *gfs[3], aaSeq *qSeq, struct hash *t3Hash, 
+	boolean tIsRc, int minMatch, struct gfOutput *out)
+/* Look for qSeq alignment in three translated reading frames. Save alignment
+ * via outFunction/outData. */
+{
+struct gfClump *clumps[3];
+int frame;
+struct gfClump *clump;
+struct gfRange *rangeList = NULL, *range;
+aaSeq *targetSeq;
+struct ssBundle *bun;
+int tileSize = gfs[0]->tileSize;
+struct trans3 *t3;
+int hitCount;
+struct lm *lm = lmInit(0);
+
+gfTransFindClumps(gfs, qSeq, clumps, lm, &hitCount);
+for (frame=0; frame<3; ++frame)
+    {
+    for (clump = clumps[frame]; clump != NULL; clump = clump->next)
+	{
+	clumpToHspRange(clump, qSeq, tileSize, frame, NULL, &rangeList, TRUE, FALSE);
+	}
+    }
+slReverse(&rangeList);
+slSort(&rangeList, gfRangeCmpTarget);
+rangeList = gfRangesBundle(rangeList, ffIntronMax/3);
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    targetSeq = range->tSeq;
+    t3 = hashMustFindVal(t3Hash, targetSeq->name);
+    AllocVar(bun);
+    bun->qSeq = qSeq;
+    bun->genoSeq = targetSeq;
+    bun->ffList = gfRangesToFfItem(range->components, qSeq);
+    bun->isProt = TRUE;
+    bun->t3List = t3;
+    ssStitch(bun, ffCdna, minMatch, ssAliCount);
+    saveAlignments(targetSeq->name, t3->seq->size, 0, 
+	bun, t3Hash, FALSE, tIsRc, ffCdna, minMatch, out);
+    ssBundleFree(&bun);
+    }
+gfRangeFreeList(&rangeList);
+for (frame=0; frame<3; ++frame)
+    gfClumpFreeList(&clumps[frame]);
+lmCleanup(&lm);
+}
+
+void rangeCoorTimes3(struct gfRange *rangeList)
+/* Multiply coordinates on range list times three (to go from
+ * amino acid to nucleotide. */
+{
+struct gfRange *range;
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    range->qStart *= 3;
+    range->qEnd *= 3;
+    range->tStart = range->tStart*3;
+    range->tEnd = range->tEnd*3;
+    }
+}
+
+static void loadHashT3Ranges(struct gfRange *rangeList, 
+	char *tSeqDir, struct hash *tFileCache, int qSeqSize, boolean isRc, 
+	struct hash **retT3Hash, struct dnaSeq **retSeqList,
+	struct slRef **retT3RefList)
+/* Load DNA in ranges into memory, and put translation in a hash
+ * that gets returned. */
+{
+struct hash *t3Hash = newHash(10);
+struct dnaSeq *targetSeq, *tSeqList = NULL;
+struct slRef *t3RefList = NULL;
+struct gfRange *range;
+
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    struct trans3 *t3, *oldT3;
+
+    targetSeq = gfiExpandAndLoadCached(range, tFileCache,
+    	tSeqDir, qSeqSize*3, &range->tTotalSize, TRUE, isRc, usualExpansion);
+    slAddHead(&tSeqList, targetSeq);
+    freez(&targetSeq->name);
+    targetSeq->name = cloneString(range->tName);
+    t3 = trans3New(targetSeq);
+    refAdd(&t3RefList, t3);
+    t3->start = range->tStart;
+    t3->end = range->tEnd;
+    t3->nibSize = range->tTotalSize;
+    t3->isRc = isRc;
+    if ((oldT3 = hashFindVal(t3Hash, range->tName)) != NULL)
+	{
+	slAddTail(&oldT3->next, t3);
+	}
+    else
+	{
+	hashAdd(t3Hash, range->tName, t3);
+	}
+    }
+*retT3Hash = t3Hash;
+*retSeqList = tSeqList;
+*retT3RefList = t3RefList;
+}
+
+
+void gfAlignTrans(int *pConn, char *tSeqDir, aaSeq *seq, int minMatch, 
+    struct hash *tFileCache, struct gfOutput *out)
+/* Search indexed translated genome on server with an amino acid sequence. 
+ * Then load homologous bits of genome locally and do detailed alignment.
+ * Call 'outFunction' with each alignment that is found. */
+{
+struct ssBundle *bun;
+struct gfClump *clumps[2][3], *clump;
+struct gfRange *rangeList = NULL, *range, *rl;
+struct dnaSeq *targetSeq, *tSeqList = NULL;
+char targetName[PATH_LEN];
+int tileSize;
+int frame, isRc = 0;
+struct hash *t3Hash = NULL;
+struct slRef *t3RefList = NULL, *ref;
+struct gfSeqSource *ssList = NULL, *ss;
+struct trans3 *t3;
+struct lm *lm = lmInit(0);
+
+/* Get clumps from server. */
+gfQuerySeqTrans(*pConn, seq, clumps, lm, &ssList, &tileSize);
+close(*pConn);
+*pConn = -1;
+
+for (isRc = 0; isRc <= 1;  ++isRc)
+    {
+    /* Figure out which parts of sequence we need to load. */
+    for (frame = 0; frame < 3; ++frame)
+	{
+	rl = seqClumpToRangeList(clumps[isRc][frame], frame);
+	rangeList = slCat(rangeList, rl);
+	}
+    /* Convert from amino acid to nucleotide coordinates. */
+    rangeCoorTimes3(rangeList);
+    slSort(&rangeList, gfRangeCmpTarget);
+    rangeList = gfRangesBundle(rangeList, ffIntronMax);
+    loadHashT3Ranges(rangeList, tSeqDir, tFileCache, seq->size, 
+    	isRc, &t3Hash, &tSeqList, &t3RefList);
+
+    /* The old range list was not very precise - it was just to get
+     * the DNA loaded.  */
+    gfRangeFreeList(&rangeList);
+
+
+    /* Patch up clump list and associated sequence source to refer
+     * to bits of genome loaded into memory.  Create new range list
+     * by extending hits in clumps. */
+    for (frame = 0; frame < 3; ++frame)
+	{
+	for (clump = clumps[isRc][frame]; clump != NULL; clump = clump->next)
+	    {
+	    struct gfSeqSource *ss = clump->target;
+	    t3 = trans3Find(t3Hash, clumpTargetName(clump), clump->tStart*3, clump->tEnd*3);
+	    ss->seq = t3->trans[frame];
+	    ss->start = t3->start/3;
+	    ss->end = t3->end/3;
+	    clumpToHspRange(clump, seq, tileSize, frame, t3, &rangeList, TRUE, FALSE);
+	    }
+	}
+    slReverse(&rangeList);
+    slSort(&rangeList, gfRangeCmpTarget);
+    rangeList = gfRangesBundle(rangeList, ffIntronMax/3);
+
+    /* Do detailed alignment of each of the clustered ranges. */
+    for (range = rangeList; range != NULL; range = range->next)
+	{
+	targetSeq = range->tSeq;
+	AllocVar(bun);
+	bun->qSeq = seq;
+	bun->genoSeq = targetSeq;
+	bun->ffList = gfRangesToFfItem(range->components, seq);
+	bun->isProt = TRUE;
+	t3 = hashMustFindVal(t3Hash, range->tName);
+	bun->t3List = t3;
+	ssStitch(bun, ffCdna, minMatch, ssAliCount);
+	getTargetName(range->tName, out->includeTargetFile, targetName);
+	saveAlignments(targetName, t3->nibSize, 0, 
+	    bun, t3Hash, FALSE, isRc, ffCdna, minMatch, out);
+	ssBundleFree(&bun);
+	}
+
+    /* Cleanup for this strand of database. */
+    gfRangeFreeList(&rangeList);
+    freeHash(&t3Hash);
+    for (ref = t3RefList; ref != NULL; ref = ref->next)
+        {
+	struct trans3 *t3 = ref->val;
+	trans3Free(&t3);
+	}
+    slFreeList(&t3RefList);
+    freeDnaSeqList(&tSeqList);
+    }
+
+/* Final cleanup. */
+for (isRc=0; isRc<=1; ++isRc)
+    for (frame=0; frame<3; ++frame)
+	gfClumpFreeList(&clumps[isRc][frame]);
+for (ss = ssList; ss != NULL; ss = ss->next)
+    freeMem(ss->fileName);
+slFreeList(&ssList);
+lmCleanup(&lm);
+}
+
+void untranslateRangeList(struct gfRange *rangeList, int qFrame, int tFrame, 
+	struct hash *t3Hash, struct trans3 *t3, int tOffset)
+/* Translate coordinates from protein to dna. */
+{
+struct gfRange *range;
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    range->qStart = 3*range->qStart + qFrame;
+    range->qEnd = 3*range->qEnd + qFrame;
+    range->tStart = 3*range->tStart + tFrame;
+    range->tEnd = 3*range->tEnd + tFrame;
+    if (t3Hash)
+	t3 = trans3Find(t3Hash, range->tSeq->name, range->tStart + tOffset, range->tEnd + tOffset);
+    range->tSeq = t3->seq;
+    range->t3 = t3;
+    }
+}
+
+void gfAlignTransTrans(int *pConn, char *tSeqDir, struct dnaSeq *qSeq, 
+	boolean qIsRc, int minMatch, struct hash *tFileCache, 
+	struct gfOutput *out, boolean isRna)
+/* Search indexed translated genome on server with an dna sequence.  Translate
+ * this sequence in three frames. Load homologous bits of genome locally
+ * and do detailed alignment.  Call 'outFunction' with each alignment
+ * that is found. */
+{
+struct gfClump *clumps[2][3][3], *clump;
+char targetName[PATH_LEN];
+int qFrame, tFrame, tIsRc;
+struct gfSeqSource *ssList = NULL, *ss;
+struct lm *lm = lmInit(0);
+int tileSize;
+struct gfRange *rangeList = NULL, *rl, *range;
+struct trans3 *qTrans = trans3New(qSeq), *t3;
+struct slRef *t3RefList = NULL, *t3Ref;
+struct hash *t3Hash = NULL;
+struct dnaSeq *tSeqList = NULL;
+enum ffStringency stringency = (isRna ? ffCdna : ffLoose);
+
+/* Query server for clumps. */
+gfQuerySeqTransTrans(*pConn, qSeq, clumps, lm, &ssList, &tileSize);
+close(*pConn);
+*pConn = -1;
+
+for (tIsRc=0; tIsRc <= 1; ++tIsRc)
+    {
+    /* Figure out which ranges need to be loaded and load them. */
+    for (qFrame = 0; qFrame < 3; ++qFrame)
+        {
+        for (tFrame = 0; tFrame < 3; ++tFrame)
+            {
+	    rl = seqClumpToRangeList(clumps[tIsRc][qFrame][tFrame], tFrame);
+	    rangeList = slCat(rangeList, rl);
+	    }
+	}
+    rangeCoorTimes3(rangeList);
+    slSort(&rangeList, gfRangeCmpTarget);
+    rangeList = gfRangesBundle(rangeList, ffIntronMax);
+    loadHashT3Ranges(rangeList, tSeqDir, tFileCache,
+    	qSeq->size/3, tIsRc, &t3Hash, &tSeqList, &t3RefList);
+
+    /* The old range list was not very precise - it was just to get
+     * the DNA loaded.  */
+    gfRangeFreeList(&rangeList);
+
+    /* Patch up clump list and associated sequence source to refer
+     * to bits of genome loaded into memory.  Create new range list
+     * by extending hits in clumps. */
+    for (qFrame = 0; qFrame < 3; ++qFrame)
+	{
+	for (tFrame = 0; tFrame < 3; ++tFrame)
+	    {
+	    for (clump = clumps[tIsRc][qFrame][tFrame]; clump != NULL; clump = clump->next)
+		{
+		struct gfSeqSource *ss = clump->target;
+		struct gfRange *rangeSet = NULL;
+		t3 = trans3Find(t3Hash, clumpTargetName(clump), clump->tStart*3, clump->tEnd*3);
+		ss->seq = t3->trans[tFrame];
+		ss->start = t3->start/3;
+		ss->end = t3->end/3;
+		clumpToHspRange(clump, qTrans->trans[qFrame], tileSize, tFrame, t3, &rangeSet, TRUE, FALSE);
+		untranslateRangeList(rangeSet, qFrame, tFrame, NULL, t3, t3->start);
+		rangeList = slCat(rangeSet, rangeList);
+		}
+	    }
+	}
+    slReverse(&rangeList);
+    slSort(&rangeList, gfRangeCmpTarget);
+    rangeList = gfRangesBundle(rangeList, ffIntronMax);
+
+    for (range = rangeList; range != NULL; range = range->next)
+	{
+	struct dnaSeq *targetSeq = range->tSeq;
+	struct ssBundle *bun;
+
+	AllocVar(bun);
+	bun->qSeq = qSeq;
+	bun->genoSeq = targetSeq;
+	bun->ffList = gfRangesToFfItem(range->components, qSeq);
+	ssStitch(bun, stringency, minMatch, ssAliCount);
+	getTargetName(range->tName, out->includeTargetFile, targetName);
+	t3 = range->t3;
+	saveAlignments(targetName, t3->nibSize, t3->start, 
+	    bun, NULL, qIsRc, tIsRc, stringency, minMatch, out);
+	ssBundleFree(&bun);
+	}
+
+    /* Cleanup for this strand of database. */
+    gfRangeFreeList(&rangeList);
+    freeHash(&t3Hash);
+    for (t3Ref = t3RefList; t3Ref != NULL; t3Ref = t3Ref->next)
+        {
+	struct trans3 *t3 = t3Ref->val;
+	trans3Free(&t3);
+	}
+    slFreeList(&t3RefList);
+    freeDnaSeqList(&tSeqList);
+    }
+trans3Free(&qTrans);
+for (ss = ssList; ss != NULL; ss = ss->next)
+    freeMem(ss->fileName);
+slFreeList(&ssList);
+lmCleanup(&lm);
+}
+
+
+static struct ssBundle *gfTransTransFindBundles(struct genoFind *gfs[3], struct dnaSeq *qSeq, 
+	struct hash *t3Hash, boolean isRc, int minMatch, boolean isRna)
+/* Look for alignment to three translations of qSeq in three translated reading frames. 
+ * Save alignment via outFunction/outData. */
+{
+struct trans3 *qTrans = trans3New(qSeq);
+int qFrame, tFrame;
+struct gfClump *clumps[3][3], *clump;
+struct gfRange *rangeList = NULL, *range;
+int tileSize = gfs[0]->tileSize;
+bioSeq *targetSeq;
+struct ssBundle *bun, *bunList = NULL;
+int hitCount;
+struct lm *lm = lmInit(0);
+enum ffStringency stringency = (isRna ? ffCdna : ffLoose);
+
+gfTransTransFindClumps(gfs, qTrans->trans, clumps, lm, &hitCount);
+for (qFrame = 0; qFrame<3; ++qFrame)
+    {
+    for (tFrame=0; tFrame<3; ++tFrame)
+	{
+	for (clump = clumps[qFrame][tFrame]; clump != NULL; clump = clump->next)
+	    {
+	    struct gfRange *rangeSet = NULL;
+	    clumpToHspRange(clump, qTrans->trans[qFrame], tileSize, tFrame, NULL, &rangeSet, TRUE, FALSE);
+	    untranslateRangeList(rangeSet, qFrame, tFrame, t3Hash, NULL, 0);
+	    rangeList = slCat(rangeSet, rangeList);
+	    }
+	}
+    }
+slSort(&rangeList, gfRangeCmpTarget);
+rangeList = gfRangesBundle(rangeList, 2000);
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    targetSeq = range->tSeq;
+    AllocVar(bun);
+    bun->qSeq = qSeq;
+    bun->genoSeq = targetSeq;
+    bun->ffList = gfRangesToFfItem(range->components, qSeq);
+    ssStitch(bun, stringency, minMatch, ssAliCount);
+    slAddHead(&bunList, bun);
+    }
+for (qFrame = 0; qFrame<3; ++qFrame)
+    for (tFrame=0; tFrame<3; ++tFrame)
+	gfClumpFreeList(&clumps[qFrame][tFrame]);
+gfRangeFreeList(&rangeList);
+trans3Free(&qTrans);
+lmCleanup(&lm);
+slReverse(&bunList);
+return bunList;
+}
+
+static void addToBigBundleList(struct ssBundle **pOneList, struct hash *bunHash, 
+	struct ssBundle **pBigList, struct dnaSeq *query)
+/* Add bundles in one list to bigList, consolidating bundles that refer
+ * to the same target sequence.  This will destroy oneList in the process. */
+{
+struct ssBundle *oneBun, *bigBun;
+
+for (oneBun = *pOneList; oneBun != NULL; oneBun = oneBun->next)
+    {
+    char *name = oneBun->genoSeq->name;
+    if ((bigBun = hashFindVal(bunHash, name)) == NULL)
+        {
+	AllocVar(bigBun);
+	slAddHead(pBigList, bigBun);
+	hashAdd(bunHash, name, bigBun);
+	bigBun->qSeq = query;
+	bigBun->genoSeq = oneBun->genoSeq;
+	bigBun->isProt = oneBun->isProt;
+	bigBun->avoidFuzzyFindKludge = oneBun->avoidFuzzyFindKludge;
+	}
+    bigBun->ffList = slCat(bigBun->ffList, oneBun->ffList);
+    oneBun->ffList = NULL;
+    }
+ssBundleFreeList(pOneList);
+}
+
+static boolean jiggleSmallExons(struct ffAli *ali, struct dnaSeq *nSeq, struct dnaSeq *hSeq)
+/* See if can jiggle small exons to match splice sites a little
+ * better. */
+{
+struct ffAli *left, *mid, *right;
+int orient;
+boolean creeped = FALSE;
+
+if (ffAliCount(ali) < 3)
+    return FALSE;
+orient = ffIntronOrientation(ali);
+left = ali;
+mid = left->right;
+right = mid->right;
+while (right != NULL)
+    {
+    int midSizeN = mid->nEnd - mid->nStart;
+    if (midSizeN < 10 && mid->hStart - left->hEnd > 1 && right->hStart - mid->hEnd > 1)
+        {
+	DNA *spLeft, *spRight;	/* Splice sites on either side of exon. */
+	DNA exonX[10+2+2];    /* Storage for exon with splice sites. */
+	DNA *match;
+	static int creeps[4][2] = { {2, 2}, {2, 1}, {1, 2}, {1, 1},};
+	int creepIx, creepL, creepR;
+	DNA *hs = mid->hStart, *he = mid->hEnd;
+	DNA *hMin = left->hEnd,  *hMax = right->hStart;
+	if (orient >= 0)
+	    {
+	    spLeft = "ag";
+	    spRight = "gt";
+	    }
+	else
+	    {
+	    spLeft = "ac";
+	    spRight = "ct";
+	    }
+        for (creepIx=0; creepIx<4; ++creepIx)
+	    {
+	    creepL = creeps[creepIx][0];
+	    creepR = creeps[creepIx][1];
+	    /* Check to see if we already match consensus, and if so just bail. */
+	    if (hs[-1] == spLeft[1] && he[0] == spRight[0])
+	        {
+		if ((creepL == 1 || hs[-2] == spLeft[0]) 
+			&& (creepR == 1 || he[1] == spRight[1]))
+		    {
+		    break;
+		    }
+		}
+	    memcpy(exonX, spLeft + 2 - creepL, creepL);
+	    memcpy(exonX + creepL, mid->nStart, midSizeN);
+	    memcpy(exonX + creepL + midSizeN, spRight, creepR);
+	    match = memMatch(exonX, midSizeN + creepR + creepL, hMin, hMax - hMin);
+	    if (match != NULL)
+	        {
+		mid->hStart = match + creepL;
+		mid->hEnd = mid->hStart + (he - hs);
+		creeped = TRUE;
+		break;
+		}
+	    }
+	}
+    left = mid;
+    mid = right;
+    right = right->right;
+    }
+if (creeped)
+    ffSlideIntrons(ali);
+return creeped;
+}
+
+static struct ffAli *refineSmallExons(struct ffAli *ff, 
+	struct dnaSeq *nSeq, struct dnaSeq *hSeq)
+/* Tweak small exons slightly - refining positions to match splice
+ * sites if possible and looking a little harder for small first
+ * and last exons. */
+{
+if (jiggleSmallExons(ff, nSeq, hSeq))
+    ff = ffRemoveEmptyAlis(ff, TRUE);
+return ff;
+}
+
+static void refineSmallExonsInBundle(struct ssBundle *bun)
+/* Tweak small exons slightly - refining positions to match splice
+ * sites if possible and looking a little harder for small first
+ * and last exons. */
+{
+struct ssFfItem *fi;    /* Item list - memory owned by bundle. */
+
+for (fi = bun->ffList; fi != NULL; fi = fi->next)
+    {
+    fi->ff = refineSmallExons(fi->ff, bun->qSeq, bun->genoSeq);
+    }
+}
+
+#ifdef DEBUG
+void dumpBunList(struct ssBundle *bunList)
+/* Write out summary info on bundle list. */
+{
+int totalItems = 0;
+int totalBlocks = 0;
+int totalBases = 0;
+struct ssBundle *bun;
+for (bun = bunList; bun != NULL; bun = bun->next)
+    {
+    struct ssFfItem *item;
+    for (item = bun->ffList; item != NULL; item = item->next)
+	{
+	printf("item: ");
+	struct ffAli *ff;
+	for (ff = item->ff; ff != NULL; ff = ff->right)
+	    {
+	    totalBases += ff->hEnd - ff->hStart;
+	    totalBlocks += 1;
+	    printf("%d,", ff->hEnd - ff->hStart);
+	    }
+	printf("\n");
+	totalItems += 1;
+	}
+    }
+printf("total bundles %d, alignments %d, blocks %d, bases %d\n", 
+    slCount(bunList), totalItems, totalBlocks, totalBases);
+}
+#endif /* DEBUG */
+
+static void gfAlignSomeClumps(struct genoFind *gf,  struct gfClump *clumpList, 
+    bioSeq *seq, boolean isRc,  int minMatch, 
+    struct gfOutput *out, boolean isProt, enum ffStringency stringency);
+
+void gfLongDnaInMem(struct dnaSeq *query, struct genoFind *gf, 
+   boolean isRc, int minScore, Bits *qMaskBits, 
+   struct gfOutput *out, boolean fastMap, boolean band)
+/* Chop up query into pieces, align each, and stitch back
+ * together again. */
+{
+int hitCount;
+int maxSize = MAXSINGLEPIECESIZE;
+int preferredSize = 4500;
+int overlapSize = 250;
+struct dnaSeq subQuery = *query;
+struct lm *lm = lmInit(0);
+int subOffset, subSize, nextOffset;
+DNA saveEnd, *endPos;
+struct ssBundle *oneBunList = NULL, *bigBunList = NULL, *bun;
+struct hash *bunHash = newHash(8);
+
+for (subOffset = 0; subOffset<query->size; subOffset = nextOffset)
+    {
+    struct gfClump *clumpList;
+    struct gfRange *rangeList = NULL;
+
+    /* Figure out size of this piece.  If query is
+     * maxSize or less do it all.   Otherwise just
+     * do prefered size, and set it up to overlap
+     * with surrounding pieces by overlapSize.  */
+    if (subOffset == 0 && query->size <= maxSize)
+	nextOffset = subSize = query->size;
+    else
+        {
+	subSize = preferredSize;
+	if (subSize + subOffset >= query->size)
+	    {
+	    subSize = query->size - subOffset;
+	    nextOffset = query->size;
+	    }
+	else
+	    {
+	    nextOffset = subOffset + preferredSize - overlapSize;
+	    }
+	}
+    subQuery.dna = query->dna + subOffset;
+    subQuery.size = subSize;
+    endPos = &subQuery.dna[subSize];
+    saveEnd = *endPos;
+    *endPos = 0;
+    if (band)
+	{
+	oneBunList = ffSeedExtInMem(gf, &subQuery, qMaskBits, subOffset, lm, minScore, isRc);
+	}
+    else
+	{
+	clumpList = gfFindClumpsWithQmask(gf, &subQuery, qMaskBits, subOffset, lm, &hitCount);
+	if (fastMap)
+	    {
+	    oneBunList = fastMapClumpsToBundles(gf, clumpList, &subQuery);
+	    }
+	else
+	    {
+	    oneBunList = gfClumpsToBundles(clumpList, isRc, &subQuery, minScore, &rangeList);
+	    gfRangeFreeList(&rangeList);
+	    }
+	gfClumpFreeList(&clumpList);
+	}
+    addToBigBundleList(&oneBunList, bunHash, &bigBunList, query);
+    *endPos = saveEnd;
+    }
+#ifdef DEBUG
+dumpBunList(bigBunList);
+#endif /* DEBUG */
+for (bun = bigBunList; bun != NULL; bun = bun->next)
+    {
+    ssStitch(bun, ffCdna, minScore, ssAliCount);
+    if (!fastMap && !band)
+	refineSmallExonsInBundle(bun);
+    saveAlignments(bun->genoSeq->name, bun->genoSeq->size, 0, 
+	bun, NULL, isRc, FALSE, ffCdna, minScore, out);
+    }
+ssBundleFreeList(&bigBunList);
+freeHash(&bunHash);
+lmCleanup(&lm);
+}
+
+
+void gfLongTransTransInMem(struct dnaSeq *query, struct genoFind *gfs[3], 
+   struct hash *t3Hash, boolean qIsRc, boolean tIsRc, boolean qIsRna,
+   int minScore, struct gfOutput *out)
+/* Chop up query into pieces, align each in translated space, and stitch back
+ * together again as nucleotides. */
+{
+enum ffStringency stringency = (qIsRna ? ffCdna : ffLoose);
+int maxSize = 1500;
+int preferredSize = 1200;	/* PreferredSize - overlapSize might need to be multiple of 3. */
+int overlapSize = 270;
+struct dnaSeq subQuery = *query;
+int subOffset, subSize, nextOffset;
+DNA saveEnd, *endPos;
+struct ssBundle *oneBunList = NULL, *bigBunList = NULL, *bun;
+struct hash *bunHash = newHash(8);
+
+for (subOffset = 0; subOffset<query->size; subOffset = nextOffset)
+    {
+    /* Figure out size of this piece.  If query is
+     * maxSize or less do it all.   Otherwise just
+     * do prefered size, and set it up to overlap
+     * with surrounding pieces by overlapSize.  */
+    if (subOffset == 0 && query->size <= maxSize)
+	nextOffset = subSize = query->size;
+    else
+        {
+	subSize = preferredSize;
+	if (subSize + subOffset >= query->size)
+	    {
+	    subSize = query->size - subOffset;
+	    nextOffset = query->size;
+	    }
+	else
+	    {
+	    nextOffset = subOffset + preferredSize - overlapSize;
+	    }
+	}
+    subQuery.dna = query->dna + subOffset;
+    subQuery.size = subSize;
+    endPos = &subQuery.dna[subSize];
+    saveEnd = *endPos;
+    *endPos = 0;
+    oneBunList = gfTransTransFindBundles(gfs, &subQuery, t3Hash, qIsRc, minScore, qIsRna);
+    addToBigBundleList(&oneBunList, bunHash, &bigBunList, query);
+    *endPos = saveEnd;
+    }
+for (bun = bigBunList; bun != NULL; bun = bun->next)
+    {
+    ssStitch(bun, ffCdna, minScore, ssAliCount);
+    saveAlignments(bun->genoSeq->name, bun->genoSeq->size, 0, 
+	bun, NULL, qIsRc, tIsRc, stringency, minScore, out);
+    }
+hashFree(&bunHash);
+ssBundleFreeList(&bigBunList);
+}
+
diff --git a/jkOwnLib/gfClientLib.c b/jkOwnLib/gfClientLib.c
new file mode 100644
index 0000000..48acd78
--- /dev/null
+++ b/jkOwnLib/gfClientLib.c
@@ -0,0 +1,223 @@
+/* gfClientLib - stuff that both blat and pcr clients of
+ * genoFind use. */
+/* Copyright 2001-2005 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "hash.h"
+#include "linefile.h"
+#include "obscure.h"
+#include "dnaseq.h"
+#include "fa.h"
+#include "nib.h"
+#include "twoBit.h"
+#include "repMask.h"
+#include "gfClientLib.h"
+
+void gfClientFileArray(char *fileName, char ***retFiles, int *retFileCount)
+/* Check if file if .2bit or .nib or .fa.  If so return just that
+ * file in a list of one.  Otherwise read all file and treat file
+ * as a list of filenames.  */
+{
+boolean gotSingle = FALSE;
+char *buf;		/* This will leak memory but won't matter. */
+
+if (nibIsFile(fileName) || twoBitIsSpec(fileName)
+    || sameString(fileName, "stdin")
+    || endsWith(fileName, ".Z")
+    || endsWith(fileName, ".gz")
+    || endsWith(fileName, ".bz2"))
+    gotSingle = TRUE;
+/* Detect .fa files (where suffix is not standardized)
+ * by first character being a '>'. */
+else
+    {
+    FILE *f = mustOpen(fileName, "r");
+    char c = fgetc(f);
+    fclose(f);
+    if (c == '>')
+        gotSingle = TRUE;
+    }
+if (gotSingle)
+    {
+    char **files;
+    *retFiles = AllocArray(files, 1);
+    files[0] = cloneString(fileName);
+    *retFileCount = 1;
+    return;
+    }
+else
+    {
+    readAllWords(fileName, retFiles, retFileCount, &buf);
+    }
+}
+
+
+void gfClientUnmask(struct dnaSeq *seqList)
+/* Unmask all sequences. */
+{
+struct dnaSeq *seq;
+for (seq = seqList; seq != NULL; seq = seq->next)
+    faToDna(seq->dna, seq->size);
+}
+
+static void maskFromOut(struct dnaSeq *seqList, char *outFile, float minRepDivergence)
+/* Mask DNA sequence by putting bits more than 85% identical to
+ * repeats as defined in RepeatMasker .out file to upper case. */
+{
+struct lineFile *lf = lineFileOpen(outFile, TRUE);
+struct hash *hash = newHash(0);
+struct dnaSeq *seq;
+char *line;
+
+for (seq = seqList; seq != NULL; seq = seq->next)
+    hashAdd(hash, seq->name, seq);
+if (!lineFileNext(lf, &line, NULL))
+    errAbort("Empty mask file %s\n", lf->fileName);
+if (!startsWith("There were no", line))	/* No repeats is ok. Not much work. */
+    {
+    if (!startsWith("   SW", line))
+	errAbort("%s isn't a RepeatMasker .out file.", lf->fileName);
+    if (!lineFileNext(lf, &line, NULL) || !startsWith("score", line))
+	errAbort("%s isn't a RepeatMasker .out file.", lf->fileName);
+    lineFileNext(lf, &line, NULL);  /* Blank line. */
+    while (lineFileNext(lf, &line, NULL))
+	{
+	char *words[32];
+	struct repeatMaskOut rmo;
+	int wordCount;
+	int seqSize;
+	int repSize;
+	wordCount = chopLine(line, words);
+	if (wordCount < 14)
+	    errAbort("%s line %d - error in repeat mask .out file\n", lf->fileName, lf->lineIx);
+	repeatMaskOutStaticLoad(words, &rmo);
+	/* If repeat is more than 15% divergent don't worry about it. */
+	if (rmo.percDiv + rmo.percDel + rmo.percInc <= minRepDivergence)
+	    {
+	    if((seq = hashFindVal(hash, rmo.qName)) == NULL)
+		errAbort("%s is in %s but not corresponding sequence file, files out of sync?\n", 
+			rmo.qName, lf->fileName);
+	    seqSize = seq->size;
+	    if (rmo.qStart <= 0 || rmo.qStart > seqSize || rmo.qEnd <= 0 
+	    	|| rmo.qEnd > seqSize || rmo.qStart > rmo.qEnd)
+		{
+		warn("Repeat mask sequence out of range (%d-%d of %d in %s)\n",
+		    rmo.qStart, rmo.qEnd, seqSize, rmo.qName);
+		if (rmo.qStart <= 0)
+		    rmo.qStart = 1;
+		if (rmo.qEnd > seqSize)
+		    rmo.qEnd = seqSize;
+		}
+	    repSize = rmo.qEnd - rmo.qStart + 1;
+	    if (repSize > 0)
+		toUpperN(seq->dna + rmo.qStart - 1, repSize);
+	    }
+	}
+    }
+freeHash(&hash);
+lineFileClose(&lf);
+}
+
+static void maskNucSeqList(struct dnaSeq *seqList, char *seqFileName, char *maskType,
+	boolean hardMask, float minRepDivergence)
+/* Apply masking to simple nucleotide sequence by making masked nucleotides
+ * upper case (since normal DNA sequence is lower case for us). */
+{
+struct dnaSeq *seq;
+char *outFile = NULL, outNameBuf[512];
+
+if (sameWord(maskType, "upper"))
+    {
+    /* Already has dna to be masked in upper case. */
+    }
+else if (sameWord(maskType, "lower"))
+    {
+    for (seq = seqList; seq != NULL; seq = seq->next)
+	toggleCase(seq->dna, seq->size);
+    }
+else
+    {
+    /* Masking from a RepeatMasker .out file. */
+    if (sameWord(maskType, "out"))
+	{
+	sprintf(outNameBuf, "%s.out", seqFileName);
+	outFile = outNameBuf;
+	}
+    else
+	{
+	outFile = maskType;
+	}
+    gfClientUnmask(seqList);
+    maskFromOut(seqList, outFile, minRepDivergence);
+    }
+if (hardMask)
+    {
+    for (seq = seqList; seq != NULL; seq = seq->next)
+	upperToN(seq->dna, seq->size);
+    }
+}
+
+bioSeq *gfClientSeqList(int fileCount, char *files[], 
+	boolean isProt, boolean isTransDna, char *maskType, 
+	float minRepDivergence, boolean showStatus)
+/* From an array of .fa and .nib file names, create a
+ * list of dnaSeqs, which are set up so that upper case is masked and lower case
+ * is unmasked sequence. (This is the opposite of the input, but set so that
+ * we can use lower case as our primary DNA sequence, which historically predates
+ * our use of lower case masking.)  Protein sequence on the other hand is
+ * all upper case. */
+
+{
+int i;
+char *fileName;
+bioSeq *seqList = NULL, *seq;
+boolean doMask = (maskType != NULL);
+
+for (i=0; i<fileCount; ++i)
+    {
+    struct dnaSeq *list = NULL, sseq;
+    ZeroVar(&sseq);
+    fileName = files[i];
+    if (nibIsFile(fileName))
+	list = nibLoadAllMasked(NIB_MASK_MIXED|NIB_BASE_NAME, fileName);
+    else if (twoBitIsSpec(fileName))
+	list = twoBitLoadAll(fileName);
+    else if (isProt)
+      list = faReadAllPep(fileName);
+    else
+      list = faReadAllMixed(fileName);
+
+    /* If necessary mask sequence from file. */
+    if (doMask)
+	{
+	maskNucSeqList(list, fileName, maskType, isTransDna, minRepDivergence);
+	}
+    else
+        {
+	/* If not masking send everything to proper case here. */
+	for (seq = list; seq != NULL; seq = seq->next)
+	    {
+	    if (isProt)
+		faToProtein(seq->dna, seq->size);
+	    else
+		faToDna(seq->dna, seq->size);
+	    }
+	}
+    /* Move local list to end of bigger list. */
+    seqList = slCat(seqList, list);
+    }
+if (showStatus)
+    {
+    /* Total up size and sequence count and report. */
+    int count = 0; 
+    unsigned long totalSize = 0;
+    for (seq = seqList; seq != NULL; seq = seq->next)
+        {
+	totalSize += seq->size;
+	count += 1;
+	}
+    printf("Loaded %lu letters in %d sequences\n", totalSize, count);
+    }
+return seqList;
+}
+
diff --git a/jkOwnLib/gfInternal.c b/jkOwnLib/gfInternal.c
new file mode 100644
index 0000000..f932e18
--- /dev/null
+++ b/jkOwnLib/gfInternal.c
@@ -0,0 +1,141 @@
+/* Some stuff shared by gfClient and gfPcr. 
+ * Copyright 2001-2004 Jim Kent. All rights reserved. */
+
+#include "common.h"
+#include "linefile.h"
+#include "dnaseq.h"
+#include "genoFind.h"
+#include "gfInternal.h"
+#include "errabort.h"
+#include "nib.h"
+#include "twoBit.h"
+
+
+
+static int extendRespect(int oldX, int newX)
+/* Return newX modified slightly so as to be in same frame as oldX. */
+{
+int frame = oldX % 3;
+newX = newX - (newX % 3) + frame;
+return newX;
+}
+
+void gfiExpandRange(struct gfRange *range, int qSize, int tSize, 
+	boolean respectFrame, boolean isRc, int expansion)
+/* Expand range to cover an additional 500 bases on either side. */
+{
+int x;
+
+x = range->qStart - expansion;
+if (x < 0) x = 0;
+range->qStart = x;
+
+x = range->qEnd + expansion;
+if (x > qSize) x = qSize;
+range->qEnd = x;
+
+x = range->tStart - expansion;
+if (x < 0) x = 0;
+if (respectFrame && !isRc) 
+    {
+    x = extendRespect(range->tStart, x);
+    }
+range->tStart = x;
+
+x = range->tEnd + expansion;
+if (x > tSize) x = tSize;
+if (respectFrame && isRc)
+    {
+    x = extendRespect(range->tEnd, x);
+    if (x > tSize)
+        x -= 3;
+    }
+range->tEnd = x;
+}
+
+struct dnaSeq *gfiExpandAndLoadCached(struct gfRange *range, 
+	struct hash *tFileCache, char *tSeqDir, int querySize, 
+	int *retTotalSeqSize, boolean respectFrame, boolean isRc, int expansion)
+/* Expand range to cover an additional expansion bases on either side.
+ * Load up target sequence and return. (Done together because don't
+ * know target size before loading.) */
+{
+struct dnaSeq *target = NULL;
+char fileName[PATH_LEN+256];
+
+safef(fileName, sizeof(fileName), "%s/%s", tSeqDir, range->tName);
+if (nibIsFile(fileName))
+    {
+    struct nibInfo *nib = hashFindVal(tFileCache, fileName);
+    if (nib == NULL)
+        {
+	nib = nibInfoNew(fileName);
+	hashAdd(tFileCache, fileName, nib);
+	}
+    if (isRc)
+	reverseIntRange(&range->tStart, &range->tEnd, nib->size);
+    gfiExpandRange(range, querySize, nib->size, respectFrame, isRc, expansion);
+    target = nibLdPart(fileName, nib->f, nib->size, 
+    	range->tStart, range->tEnd - range->tStart);
+    if (isRc)
+	{
+	reverseComplement(target->dna, target->size);
+	reverseIntRange(&range->tStart, &range->tEnd, nib->size);
+	}
+    *retTotalSeqSize = nib->size;
+    }
+else
+    {
+    struct twoBitFile *tbf = NULL;
+    char *tSeqName = strchr(fileName, ':');
+    int tSeqSize = 0;
+    if (tSeqName == NULL)
+        errAbort("No colon in .2bit response from gfServer");
+    *tSeqName++ = 0;
+    tbf = hashFindVal(tFileCache, fileName);
+    if (tbf == NULL)
+        {
+	tbf = twoBitOpen(fileName);
+	hashAdd(tFileCache, fileName, tbf);
+	}
+    tSeqSize = twoBitSeqSize(tbf, tSeqName);
+    if (isRc)
+	reverseIntRange(&range->tStart, &range->tEnd, tSeqSize);
+    gfiExpandRange(range, querySize, tSeqSize, respectFrame, isRc, expansion);
+    target = twoBitReadSeqFragLower(tbf, tSeqName, range->tStart, range->tEnd);
+    if (isRc)
+	{
+	reverseComplement(target->dna, target->size);
+	reverseIntRange(&range->tStart, &range->tEnd, tSeqSize);
+	}
+    *retTotalSeqSize = tSeqSize;
+    }
+return target;
+}
+
+void gfiGetSeqName(char *spec, char *name, char *file)
+/* Extract sequence name and optionally file name from spec, 
+ * which includes nib and 2bit files.  (The file may be NULL
+ * if you don't care.) */
+{
+if (nibIsFile(spec))
+    {
+    splitPath(spec, NULL, name, NULL);
+    if (file != NULL)
+        strcpy(file, spec);
+    }
+else
+    {
+    char *s = strchr(spec, ':');
+    if (s == NULL)
+	errAbort("Expecting colon in %s", spec);
+    strcpy(name, s+1);
+    if (file != NULL)
+        {
+	int fileNameSize = s - spec;
+	memcpy(file, spec, fileNameSize);
+	file[fileNameSize] = 0;
+	}
+    }
+}
+
diff --git a/jkOwnLib/gfInternal.h b/jkOwnLib/gfInternal.h
new file mode 100644
index 0000000..e43e412
--- /dev/null
+++ b/jkOwnLib/gfInternal.h
@@ -0,0 +1,64 @@
+/* gfInternal - some stuff that connects modules but we
+ * don't want widely advertised in the blat code. */
+
+struct gfRange
+/* A range of bases found by genoFind.  Recursive
+ * data structure.  Lowest level roughly corresponds
+ * to an exon. */
+    {
+    struct gfRange *next;  /* Next in singly linked list. */
+    int qStart;	/* Start in query */
+    int qEnd;	/* End in query */
+    char *tName;	  /* Target name.  Allocated here. */
+    struct dnaSeq *tSeq;  /* Target Seq. May be NULL in a .nib.  Not allocated here. */
+    int tStart;	/* Start in target */
+    int tEnd;	/* End in target */
+    struct gfRange *components;	/* Components of range. */
+    int hitCount;	/* Number of hits. */
+    int frame;		/* Reading frame (just for translated alignments) */
+    struct trans3 *t3;	/* Translated frame or NULL. */
+    int tTotalSize;	/* Size of entire target sequence, not just loaded parts.  Not set until late in the game. */
+    char tStrand;	/* Just for PCR. */
+    };
+
+void gfRangeFree(struct gfRange **pEl);
+/* Free a single dynamically allocated gfRange such as created
+ * with gfRangeLoad(). */
+
+void gfRangeFreeList(struct gfRange **pList);
+/* Free a list of dynamically allocated gfRange's */
+
+int gfRangeCmpTarget(const void *va, const void *vb);
+/* Compare to sort based on target position. */
+
+struct gfRange *gfRangesBundle(struct gfRange *exonList, int maxIntron);
+/* Bundle a bunch of 'exons' into plausable 'genes'.  It's
+ * not necessary to be precise here.  The main thing is to
+ * group together exons that are close to each other in the
+ * same target sequence. */
+
+struct ssFfItem *gfRangesToFfItem(struct gfRange *rangeList, aaSeq *qSeq);
+/* Convert ranges to ssFfItem's. */
+
+struct ssBundle *ffSeedExtInMem(struct genoFind *gf, struct dnaSeq *qSeq, Bits *qMaskBits, 
+	int qOffset, struct lm *lm, int minScore, boolean isRc);
+/* Do seed and extend type alignment */
+
+void dumpBuns(struct ssBundle *bunList);  /* uglyf */
+void dumpFf(struct ffAli *left, DNA *needle, DNA *hay);/* uglyf */
+
+void gfiExpandRange(struct gfRange *range, int qSize, int tSize, 
+	boolean respectFrame, boolean isRc, int expansion);
+/* Expand range to cover an additional 500 bases on either side. */
+
+struct dnaSeq *gfiExpandAndLoadCached(struct gfRange *range, 
+	struct hash *tFileCache, char *tSeqDir, int querySize, 
+	int *retTotalSeqSize, boolean respectFrame, boolean isRc, int expansion);
+/* Expand range to cover an additional expansion bases on either side.
+ * Load up target sequence and return. (Done together because don't
+ * know target size before loading.) */
+
+void gfiGetSeqName(char *spec, char *name, char *file);
+/* Extract sequence name and optionally file name from spec, 
+ * which includes nib and 2bit files.  (The file may be NULL
+ * if you don't care.) */
diff --git a/jkOwnLib/gfOut.c b/jkOwnLib/gfOut.c
new file mode 100644
index 0000000..bafa6e6
--- /dev/null
+++ b/jkOwnLib/gfOut.c
@@ -0,0 +1,603 @@
+/* gfOut - stuff to manage output for genoFind system -
+ * currently supports psl, axt, blast, and wu-blast. 
+ *
+ * Copyright 2001-2003 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "dystring.h"
+#include "dnautil.h"
+#include "axt.h"
+#include "maf.h"
+#include "trans3.h"
+#include "psl.h"
+#include "genoFind.h"
+
+
+struct pslxData
+/* This is the data structure put in gfOutput.data for psl/pslx output. */
+    {
+    FILE *f;			/* Output file. */
+    boolean saveSeq;		/* Save sequence too? */
+    };
+
+struct axtData
+/* This is the data structure put in gfOutput.data for axt/blast output. */
+    {
+    struct axtBundle *bundleList;	/* List of bundles. */
+    char *databaseName;		/* Just used for blast. */
+    int databaseSeqCount;	/* Just used for blast. */
+    double databaseLetters; /* Just used for blast. */
+    char *blastType;	/* 'blast' or 'wublast' or 'xml' or 'blast8' or 'blast9' */
+    double minIdentity; /* Just used for blast. */
+    };
+
+static void savePslx(char *chromName, int chromSize, int chromOffset,
+	struct ffAli *ali, struct dnaSeq *tSeq, struct dnaSeq *qSeq, 
+	boolean isRc, enum ffStringency stringency, int minMatch, FILE *f,
+	struct hash *t3Hash, boolean reportTargetStrand, boolean targetIsRc,
+	struct hash *maskHash, int minIdentity, 
+	boolean qIsProt, boolean tIsProt, boolean saveSeq)
+/* Analyse one alignment and if it looks good enough write it out to file in
+ * psl format (or pslX format - if saveSeq is TRUE).  */
+{
+/* This function was stolen from psLayout and slightly extensively to cope
+ * with protein as well as DNA aligments. */
+struct ffAli *ff, *nextFf;
+struct ffAli *right = ffRightmost(ali);
+DNA *needle = qSeq->dna;
+DNA *hay = tSeq->dna;
+int nStart = ali->nStart - needle;
+int nEnd = right->nEnd - needle;
+int hStart, hEnd; 
+int nInsertBaseCount = 0;
+int nInsertCount = 0;
+int hInsertBaseCount = 0;
+int hInsertCount = 0;
+int matchCount = 0;
+int mismatchCount = 0;
+int repMatch = 0;
+int countNs = 0;
+DNA *np, *hp, n, h;
+int blockSize;
+int i;
+struct trans3 *t3List = NULL;
+Bits *maskBits = NULL;
+
+if (maskHash != NULL)
+    maskBits = hashMustFindVal(maskHash, tSeq->name);
+if (t3Hash != NULL)
+    t3List = hashMustFindVal(t3Hash, tSeq->name);
+hStart = trans3GenoPos(ali->hStart, tSeq, t3List, FALSE) + chromOffset;
+hEnd = trans3GenoPos(right->hEnd, tSeq, t3List, TRUE) + chromOffset;
+
+/* Count up matches, mismatches, inserts, etc. */
+for (ff = ali; ff != NULL; ff = nextFf)
+    {
+    nextFf = ff->right;
+    blockSize = ff->nEnd - ff->nStart;
+    np = ff->nStart;
+    hp = ff->hStart;
+    for (i=0; i<blockSize; ++i)
+	{
+	n = np[i];
+	h = hp[i];
+	if (n == 'n' || h == 'n')
+	    ++countNs;
+	else
+	    {
+	    if (n == h)
+		{
+		if (maskBits != NULL)
+		    {
+		    int seqOff = hp + i - hay;
+		    if (bitReadOne(maskBits, seqOff))
+		        ++repMatch;
+		    else
+		        ++matchCount;
+		    }
+		else
+		    ++matchCount;
+		}
+	    else
+		++mismatchCount;
+	    }
+	}
+    if (nextFf != NULL)
+	{
+	int nhStart = trans3GenoPos(nextFf->hStart, tSeq, t3List, FALSE) + chromOffset;
+	int ohEnd = trans3GenoPos(ff->hEnd, tSeq, t3List, TRUE) + chromOffset;
+	int hGap = nhStart - ohEnd;
+	int nGap = nextFf->nStart - ff->nEnd;
+
+	if (nGap != 0)
+	    {
+	    ++nInsertCount;
+	    nInsertBaseCount += nGap;
+	    }
+	if (hGap != 0)
+	    {
+	    ++hInsertCount;
+	    hInsertBaseCount += hGap;
+	    }
+	}
+    }
+
+
+/* See if it looks good enough to output, and output. */
+/* if (score >= minMatch) Moved to higher level */
+    {
+    int gaps = nInsertCount + (stringency == ffCdna ? 0: hInsertCount);
+    if ((matchCount + repMatch + mismatchCount) > 0)
+	{
+	int id = roundingScale(1000, matchCount + repMatch - 2*gaps, matchCount + repMatch + mismatchCount);
+	if (id >= minIdentity)
+	    {
+	    if (isRc)
+		{
+		int temp;
+		int oSize = qSeq->size;
+		temp = nStart;
+		nStart = oSize - nEnd;
+		nEnd = oSize - temp;
+		}
+	    if (targetIsRc)
+		{
+		int temp;
+		temp = hStart;
+		hStart = chromSize - hEnd;
+		hEnd = chromSize - temp;
+		}
+	    fprintf(f, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%c",
+		matchCount, mismatchCount, repMatch, countNs, nInsertCount, nInsertBaseCount, hInsertCount, hInsertBaseCount,
+		(isRc ? '-' : '+'));
+	    if (reportTargetStrand)
+		fprintf(f, "%c", (targetIsRc ? '-' : '+') );
+	    fprintf(f, "\t%s\t%d\t%d\t%d\t"
+			 "%s\t%d\t%d\t%d\t%d\t",
+		qSeq->name, qSeq->size, nStart, nEnd,
+		chromName, chromSize, hStart, hEnd,
+		ffAliCount(ali));
+	    for (ff = ali; ff != NULL; ff = ff->right)
+		fprintf(f, "%ld,", (long)(ff->nEnd - ff->nStart));
+	    fprintf(f, "\t");
+	    for (ff = ali; ff != NULL; ff = ff->right)
+		fprintf(f, "%ld,", (long)(ff->nStart - needle));
+	    fprintf(f, "\t");
+	    for (ff = ali; ff != NULL; ff = ff->right)
+		fprintf(f, "%d,", trans3GenoPos(ff->hStart, tSeq, t3List, FALSE) + chromOffset);
+	    if (saveSeq)
+		{
+		fputc('\t', f);
+		for (ff = ali; ff != NULL; ff = ff->right)
+		    {
+		    mustWrite(f, ff->nStart, ff->nEnd - ff->nStart);
+		    fputc(',', f);
+		    }
+		fputc('\t', f);
+		for (ff = ali; ff != NULL; ff = ff->right)
+		    {
+		    mustWrite(f, ff->hStart, ff->hEnd - ff->hStart);
+		    fputc(',', f);
+		    }
+		}
+	    fprintf(f, "\n");
+	    if (ferror(f))
+		{
+		perror("");
+		errAbort("Write error to .psl");
+		}
+	    }
+	}
+    }
+}
+
+static void pslOut(char *chromName, int chromSize, int chromOffset, struct ffAli *ali, 
+	struct dnaSeq *tSeq, struct hash *t3Hash, struct dnaSeq *qSeq, 
+	boolean qIsRc, boolean tIsRc, 
+	enum ffStringency stringency, int minMatch, struct gfOutput *out)
+/* Save psl for more complex alignments. */
+{
+struct pslxData *outForm = out->data;
+
+savePslx(chromName, chromSize, chromOffset, ali, tSeq, qSeq,
+    qIsRc, stringency, minMatch, outForm->f, t3Hash, 
+    out->reportTargetStrand, tIsRc,
+    out->maskHash, out->minGood, 
+    out->qIsProt, out->tIsProt, outForm->saveSeq);
+}
+
+static struct ffAli *ffNextBreak(struct ffAli *ff, int maxInsert, 
+	bioSeq *tSeq, struct trans3 *t3List)
+/* Return ffAli after first gap in either sequence longer than maxInsert,
+ * or after first gap in both sequences.  Return may legitimately
+ * be NULL. */
+{
+struct ffAli *rt = ff->right;
+int hGap, nGap;
+int nhStart, ohEnd;
+for (;;)
+    {
+    if (rt == NULL)
+        break;
+    nhStart = trans3GenoPos(rt->hStart, tSeq, t3List, FALSE);
+    ohEnd = trans3GenoPos(ff->hEnd, tSeq, t3List, TRUE);
+    hGap = nhStart - ohEnd;
+    nGap = rt->nStart - ff->nEnd;
+    if (hGap != 0 && nGap != 0)
+        break;
+    if (hGap < 0 || nGap < 0)
+        break;
+    if (hGap > maxInsert || nGap > maxInsert)
+        break;
+    ff = rt;
+    rt = ff->right;
+    }
+return rt;
+}
+
+
+static void saveAxtBundle(char *chromName, int chromSize, int chromOffset,
+	struct ffAli *ali, 
+	struct dnaSeq *tSeq, struct hash *t3Hash, struct dnaSeq *qSeq, 
+	boolean qIsRc, boolean tIsRc, 
+	enum ffStringency stringency, int minMatch, struct gfOutput *out)
+/* Save alignment to axtBundle. */
+{
+struct axtData *ad = out->data;
+struct ffAli *sAli, *eAli, *ff, *rt, *eFf = NULL;
+struct axt *axt;
+struct dyString *q = newDyString(1024), *t = newDyString(1024);
+struct axtBundle *gab;
+struct trans3 *t3List = NULL;
+
+if (t3Hash != NULL)
+    t3List = hashMustFindVal(t3Hash, tSeq->name);
+AllocVar(gab);
+gab->tSize = chromSize;
+gab->qSize = qSeq->size;
+for (sAli = ali; sAli != NULL; sAli = eAli)
+    {
+    eAli = ffNextBreak(sAli, 8, tSeq, t3List);
+    dyStringClear(q);
+    dyStringClear(t);
+    for (ff = sAli; ff != eAli; ff = ff->right)
+        {
+	dyStringAppendN(q, ff->nStart, ff->nEnd - ff->nStart);
+	dyStringAppendN(t, ff->hStart, ff->hEnd - ff->hStart);
+	rt = ff->right;
+	if (rt != eAli)
+	    {
+	    int nGap = rt->nStart - ff->nEnd;
+	    int nhStart = trans3GenoPos(rt->hStart, tSeq, t3List, FALSE) 
+	    	+ chromOffset;
+	    int ohEnd = trans3GenoPos(ff->hEnd, tSeq, t3List, TRUE) 
+	    	+ chromOffset;
+	    int hGap = nhStart - ohEnd;
+	    int gap = max(nGap, hGap);
+	    if (nGap < 0 || hGap < 0)
+		{
+	        errAbort("Negative gap size in %s vs %s", tSeq->name, qSeq->name);
+		}
+	    if (nGap == gap)
+	        {
+		dyStringAppendN(q, ff->nEnd, gap);
+		dyStringAppendMultiC(t, '-', gap);
+		}
+	    else
+	        {
+		dyStringAppendN(t, ff->hEnd, gap);
+		dyStringAppendMultiC(q, '-', gap);
+		}
+	    }
+	eFf = ff;	/* Keep track of last block in bunch */
+	}
+    assert(t->stringSize == q->stringSize);
+    AllocVar(axt);
+    axt->qName = cloneString(qSeq->name);
+    axt->qStart = sAli->nStart - qSeq->dna;
+    axt->qEnd = eFf->nEnd - qSeq->dna;
+    axt->qStrand = (qIsRc ? '-' : '+');
+    axt->tName = cloneString(chromName);
+    axt->tStart = trans3GenoPos(sAli->hStart, tSeq, t3List, FALSE) + chromOffset;
+    axt->tEnd = trans3GenoPos(eFf->hEnd, tSeq, t3List, TRUE) + chromOffset;
+    axt->tStrand = (tIsRc ? '-' : '+');
+    axt->symCount = t->stringSize;
+    axt->qSym = cloneString(q->string);
+    axt->tSym = cloneString(t->string);
+    axt->frame = trans3Frame(sAli->hStart, t3List);
+    if (out->qIsProt)
+	axt->score = axtScoreProteinDefault(axt);
+    else 
+	axt->score = axtScoreDnaDefault(axt);
+    slAddHead(&gab->axtList, axt);
+    }
+slReverse(&gab->axtList);
+dyStringFree(&q);
+dyStringFree(&t);
+slAddHead(&ad->bundleList, gab);
+}
+
+static void axtQueryOut(struct gfOutput *out, FILE *f)
+/* Do axt oriented output - at end of processing query. */
+{
+struct axtData *aod = out->data;
+struct axtBundle *gab;
+for (gab = aod->bundleList; gab != NULL; gab = gab->next)
+    {
+    struct axt *axt;
+    for (axt = gab->axtList; axt != NULL; axt = axt->next)
+	axtWrite(axt, f);
+    }
+axtBundleFreeList(&aod->bundleList);
+}
+
+static void mafHead(struct gfOutput *out, FILE *f)
+/* Write maf header. */
+{
+mafWriteStart(f, "blastz");
+}
+
+static void mafQueryOut(struct gfOutput *out, FILE *f)
+/* Do axt oriented output - at end of processing query. */
+{
+struct axtData *aod = out->data;
+struct axtBundle *gab;
+for (gab = aod->bundleList; gab != NULL; gab = gab->next)
+    {
+    struct axt *axt;
+    for (axt = gab->axtList; axt != NULL; axt = axt->next)
+	{
+	struct mafAli temp;
+	mafFromAxtTemp(axt, gab->tSize, gab->qSize, &temp);
+	mafWrite(f, &temp);
+	}
+    }
+axtBundleFreeList(&aod->bundleList);
+}
+
+static int axtMatchCount(struct axt *axt)
+/* Return matches. */
+{
+int matchCount = 0;
+int i;
+for (i=0; i<axt->symCount; ++i)
+    {
+    if (axt->qSym[i] == axt->tSym[i])
+        ++matchCount;
+    }
+return matchCount;
+}
+
+static double axtIdRatio(struct axt *axt)
+/* Return matches/total. */
+{
+int matchCount = axtMatchCount(axt);
+return (double)matchCount/(double)axt->symCount;
+}
+
+static double axtListRatio(struct axt *axt)
+/* Return matches/total. */
+{
+int matchCount = 0;
+int symCount = 0;
+for (; axt != NULL; axt = axt->next)
+    {
+    matchCount += axtMatchCount(axt);
+    symCount += axt->symCount;
+    }
+return (double)matchCount/(double)symCount;
+}
+
+static void sim4QueryOut(struct gfOutput *out, FILE *f)
+/* Do sim4-like output - at end of processing query. */
+{
+struct axtData *aod = out->data;
+struct axtBundle *gab;
+slReverse(&aod->bundleList);
+
+for (gab = aod->bundleList; gab != NULL; gab = gab->next)
+    {
+    struct axt *axt = gab->axtList;
+    // check minIdentity of the entire alignment
+    int goodPpt = 1000 * axtListRatio(axt);
+    if (!(goodPpt >= out->minGood))
+	continue; 
+    fprintf(f, "\n");
+    fprintf(f, "seq1 = %s, %d bp\n", axt->qName, gab->qSize);
+    fprintf(f, "seq2 = %s, %d bp\n", axt->tName, gab->tSize);
+    fprintf(f, "\n");
+    if (axt->qStrand == '-')
+	fprintf(f, "(complement)\n");
+    for (; axt != NULL; axt = axt->next)
+	{
+	fprintf(f, "%d-%d  ", axt->qStart+1, axt->qEnd);
+	fprintf(f, "(%d-%d)   ", axt->tStart+1, axt->tEnd);
+	fprintf(f, "%1.0f%% ", 100.0 * axtIdRatio(axt));
+	if (axt->qStrand == '-')
+	     fprintf(f, "<-\n");
+	else
+	     fprintf(f, "->\n");
+	}
+    }
+axtBundleFreeList(&aod->bundleList);
+}
+
+static void blastQueryOut(struct gfOutput *out, FILE *f)
+/* Output blast on query. */
+{
+struct axtData *aod = out->data;
+axtBlastOut(aod->bundleList, out->queryIx, out->qIsProt, f,
+	aod->databaseName, aod->databaseSeqCount, aod->databaseLetters,
+	aod->blastType, "blat", aod->minIdentity);
+axtBundleFreeList(&aod->bundleList);
+}
+
+static struct gfOutput *gfOutputInit(int goodPpt, boolean qIsProt, boolean tIsProt)
+/* Allocate and initialize gfOutput.   You'll need to fill in 
+ * gfOutput.out at a minimum, and likely gfOutput.data before
+ * using though. */
+{
+struct gfOutput *out;
+AllocVar(out);
+out->minGood = goodPpt;
+out->qIsProt = qIsProt;
+out->tIsProt = tIsProt;
+return out;
+}
+
+static void pslHead(struct gfOutput *out, FILE *f)
+/* Write out psl head */
+{
+pslWriteHead(f);
+}
+
+struct gfOutput *gfOutputPsl(int goodPpt, 
+	boolean qIsProt, boolean tIsProt, FILE *f, 
+	boolean saveSeq, boolean noHead)
+/* Set up psl/pslx output */
+{
+struct gfOutput *out = gfOutputInit(goodPpt, qIsProt, tIsProt);
+struct pslxData *pslData;
+
+AllocVar(pslData);
+pslData->saveSeq = saveSeq;
+pslData->f = f;
+out->out = pslOut;
+out->data = pslData;
+if (!noHead)
+    out->fileHead = pslHead;
+return out;
+}
+
+struct gfOutput *gfOutputAxtMem(int goodPpt, boolean qIsProt, 
+	boolean tIsProt)
+/* Setup output for in memory axt output. */
+{
+struct gfOutput *out = gfOutputInit(goodPpt, qIsProt, tIsProt);
+struct axtData *ad;
+AllocVar(ad);
+out->out = saveAxtBundle;
+out->data = ad;
+return out;
+}
+
+struct gfOutput *gfOutputAxt(int goodPpt, boolean qIsProt, 
+	boolean tIsProt, FILE *f)
+/* Setup output for axt format. */
+{
+struct gfOutput *out = gfOutputAxtMem(goodPpt, qIsProt, tIsProt);
+out->queryOut = axtQueryOut;
+return out;
+}
+
+struct gfOutput *gfOutputMaf(int goodPpt, boolean qIsProt, 
+	boolean tIsProt, FILE *f)
+/* Setup output for maf format. */
+{
+struct gfOutput *out = gfOutputAxtMem(goodPpt, qIsProt, tIsProt);
+out->queryOut = mafQueryOut;
+out->fileHead = mafHead;
+return out;
+}
+
+struct gfOutput *gfOutputSim4(int goodPpt, boolean qIsProt, boolean tIsProt, 
+	char *databaseName)
+/* Set up to output in sim4 format. */
+{
+struct gfOutput *out = gfOutputAxtMem(goodPpt, qIsProt, tIsProt);
+struct axtData *ad = out->data;
+if (qIsProt || tIsProt)
+    errAbort("sim4 output is not available for protein query sequences.");
+ad->databaseName = databaseName;
+out->queryOut = sim4QueryOut;
+return out;
+}
+
+struct gfOutput *gfOutputBlast(int goodPpt, 
+	boolean qIsProt, boolean tIsProt, 
+	char *databaseName, int databaseSeqCount, double databaseLetters,
+	char *blastType, double minIdentity, FILE *f)
+/* Setup output for blast format. */
+{
+struct gfOutput *out = gfOutputAxtMem(goodPpt, qIsProt, tIsProt);
+struct axtData *ad = out->data;
+ad->databaseName = databaseName;
+ad->databaseSeqCount = databaseSeqCount;
+ad->databaseLetters = databaseLetters;
+ad->blastType = blastType;
+ad->minIdentity = minIdentity;
+out->queryOut = blastQueryOut;
+return out;
+}
+
+struct gfOutput *gfOutputAny(char *format, 
+	int goodPpt, boolean qIsProt, boolean tIsProt, 
+	boolean noHead, char *databaseName,
+	int databaseSeqCount, double databaseLetters,
+	double minIdentity,
+	FILE *f)
+/* Initialize output in a variety of formats in file or memory. 
+ * Parameters:
+ *    format - either 'psl', 'pslx', 'sim4', 'blast', 'wublast', 'axt', 'xml'
+ *    goodPpt - minimum identity of alignments to output in parts per thousand
+ *    qIsProt - true if query side is a protein.
+ *    tIsProt - true if target (database) side is a protein.
+ *    noHead - if true suppress header in psl/pslx output.
+ *    databaseName - name of database.  Only used for blast output
+ *    databaseSeq - number of sequences in database - only for blast
+ *    databaseLetters - number of bases/aas in database - only blast
+ *    minIdentity - minimum identity - only blast
+ *    FILE *f - file.  
+ */
+{
+struct gfOutput *out = NULL;
+static char *blastTypes[] = {"blast", "wublast", "blast8", "blast9", "xml"};
+
+if (format == NULL)
+    format = "psl";
+if (sameWord(format, "psl"))
+    out = gfOutputPsl(goodPpt, qIsProt, tIsProt, f, FALSE, noHead);
+else if (sameWord(format, "pslx"))
+    out = gfOutputPsl(goodPpt, qIsProt, tIsProt, f, TRUE, noHead);
+else if (sameWord(format, "sim4"))
+    out = gfOutputSim4(goodPpt, qIsProt, tIsProt, databaseName);
+else if (stringArrayIx(format, blastTypes, ArraySize(blastTypes)) >= 0)
+    out = gfOutputBlast(goodPpt, qIsProt, tIsProt, 
+	    databaseName, databaseSeqCount, databaseLetters, format, 
+	    minIdentity, f);
+else if (sameWord(format, "axt"))
+    out = gfOutputAxt(goodPpt, qIsProt, tIsProt, f);
+else if (sameWord(format, "maf"))
+    out = gfOutputMaf(goodPpt, qIsProt, tIsProt, f);
+else
+    errAbort("Unrecognized output format '%s'", format);
+return out;
+}
+
+void gfOutputQuery(struct gfOutput *out, FILE *f)
+/* Finish writing out results for a query to file. */
+{
+++out->queryIx;
+if (out->queryOut != NULL)
+    out->queryOut(out, f);
+}
+
+void gfOutputHead(struct gfOutput *out, FILE *f)
+/* Write out header if any. */
+{
+if (out->fileHead != NULL)
+    out->fileHead(out, f);
+}
+
+void gfOutputFree(struct gfOutput **pOut)
+/* Free up output */
+{
+struct gfOutput *out = *pOut;
+if (out != NULL)
+    {
+    freeMem(out->data);
+    freez(pOut);
+    }
+}
diff --git a/jkOwnLib/gfPcrLib.c b/jkOwnLib/gfPcrLib.c
new file mode 100644
index 0000000..da8fcdb
--- /dev/null
+++ b/jkOwnLib/gfPcrLib.c
@@ -0,0 +1,571 @@
+/* gfPcrLib - Routines to help do in silico PCR.
+ * Copyright 2004-2005 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "options.h"
+#include "dystring.h"
+#include "fa.h"
+#include "net.h"
+#include "genoFind.h"
+#include "sqlNum.h"
+#include "gfInternal.h"
+#include "gfPcrLib.h"
+
+
+/**** Input and Output Handlers *****/
+
+void gfPcrOutputFree(struct gfPcrOutput **pOut)
+/* Free up a gfPcrOutput structure. */
+{
+struct gfPcrOutput *out = *pOut;
+if (pOut != NULL)
+    {
+    freeMem(out->name);
+    freeMem(out->fPrimer);
+    freeMem(out->rPrimer);
+    freeMem(out->seqName);
+    freeMem(out->dna);
+    freez(pOut);
+    }
+}
+
+void gfPcrOutputFreeList(struct gfPcrOutput **pList)
+/* Free up a list of gfPcrOutput structures. */
+{
+struct gfPcrOutput *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    gfPcrOutputFree(&el);
+    }
+*pList = NULL;
+}
+
+void gfPcrInputStaticLoad(char **row, struct gfPcrInput *ret)
+/* Load a row from gfPcrInput table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+{
+ret->name = row[0];
+ret->fPrimer = row[1];
+ret->rPrimer = row[2];
+}
+
+struct gfPcrInput *gfPcrInputLoad(char **row)
+/* Load a gfPcrInput from row fetched with select * from gfPcrInput
+ * from database.  Dispose of this with gfPcrInputFree(). */
+{
+struct gfPcrInput *ret;
+
+AllocVar(ret);
+ret->name = cloneString(row[0]);
+ret->fPrimer = cloneString(row[1]);
+ret->rPrimer = cloneString(row[2]);
+return ret;
+}
+
+struct gfPcrInput *gfPcrInputLoadAll(char *fileName) 
+/* Load all gfPcrInput from a whitespace-separated file.
+ * Dispose of this with gfPcrInputFreeList(). */
+{
+struct gfPcrInput *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[3];
+
+while (lineFileRow(lf, row))
+    {
+    el = gfPcrInputLoad(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+
+void gfPcrInputFree(struct gfPcrInput **pEl)
+/* Free a single dynamically allocated gfPcrInput such as created
+ * with gfPcrInputLoad(). */
+{
+struct gfPcrInput *el;
+
+if ((el = *pEl) == NULL) return;
+freeMem(el->name);
+freeMem(el->fPrimer);
+freeMem(el->rPrimer);
+freez(pEl);
+}
+
+void gfPcrInputFreeList(struct gfPcrInput **pList)
+/* Free a list of dynamically allocated gfPcrInput's */
+{
+struct gfPcrInput *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    gfPcrInputFree(&el);
+    }
+*pList = NULL;
+}
+
+
+
+/**** Handle Refinement (after Index has given us approximate position) *****/
+
+static boolean goodMatch(char *a, char *b, int size)
+/* Return TRUE if there are 2 matches per mismatch. */
+{
+int score = 0, i;
+for (i=0; i<size; ++i)
+   {
+   if (a[i] == b[i])
+       score += 1;
+   else
+       score -= 2;
+   }
+return score >= 0;
+}
+
+static void upperMatch(char *dna, char *primer, int size)
+/* Uppercase DNA where it matches primer. */
+{
+int i;
+for (i=0; i<size; ++i)
+    {
+    if (dna[i] == primer[i])
+        dna[i] = toupper(dna[i]);
+    }
+}
+
+static void outputFa(struct gfPcrOutput *out, FILE *f, char *url)
+/* Output match in fasta format. */
+{
+int fPrimerSize = strlen(out->fPrimer);
+int rPrimerSize = strlen(out->rPrimer);
+int productSize = out->rPos - out->fPos;
+char *dna = cloneStringZ(out->dna, productSize);
+char *rrPrimer = cloneString(out->rPrimer);
+char *ffPrimer = cloneString(out->fPrimer);
+struct dyString *faLabel = newDyString(0);
+char *name = out->name;
+
+/* Create fasta header with position, possibly empty name, and upper cased primers with position optionally hyperlinked. */
+touppers(rrPrimer);
+touppers(ffPrimer);
+if (url != NULL)
+    {
+    dyStringAppend(faLabel, "<A HREF=\"");
+    dyStringPrintf(faLabel, url, out->seqName, out->fPos+1, out->rPos);
+    dyStringAppend(faLabel, "\">");
+    }
+dyStringPrintf(faLabel, "%s:%d%c%d", 
+	out->seqName, out->fPos+1, out->strand, out->rPos);
+if (url != NULL)
+    dyStringAppend(faLabel, "</A>");
+if (name != NULL)
+    dyStringPrintf(faLabel, " %s", name);
+dyStringPrintf(faLabel, " %dbp %s %s",
+	out->rPos - out->fPos, ffPrimer, rrPrimer);
+
+/* Flip reverse primer to be in same direction and case as sequence. */
+reverseComplement(rrPrimer, rPrimerSize);
+tolowers(rrPrimer);
+
+/* Capitalize where sequence and primer match, and write out sequence. */
+upperMatch(dna, out->fPrimer, fPrimerSize);
+upperMatch(dna + productSize - rPrimerSize, rrPrimer, rPrimerSize);
+faWriteNext(f, faLabel->string, dna, productSize);
+
+/* Clean up. */
+freez(&dna);
+freez(&rrPrimer);
+freez(&ffPrimer);
+dyStringFree(&faLabel)
+}
+
+static int countMatch(char *a, char *b, int size)
+/* Count number of letters in a, b that match */
+{
+int count = 0, i;
+for (i=0; i<size; ++i)
+    if (a[i] == b[i])
+       ++count;
+return count;
+}
+
+static int getBedScore(struct gfPcrOutput *out)
+/* Return a score in BED range (0-1000). */
+{
+int size = out->rPos - out->fPos;
+int fPrimerSize = strlen(out->fPrimer);
+int rPrimerSize = strlen(out->rPrimer);
+int match = countMatch(out->dna, out->fPrimer, fPrimerSize);
+assert(size > 0);
+reverseComplement(out->rPrimer, rPrimerSize);
+match += countMatch(out->dna + size - rPrimerSize, out->rPrimer, rPrimerSize);
+reverseComplement(out->rPrimer, rPrimerSize);
+return round(1000.0 * match / (double)(fPrimerSize + rPrimerSize));
+}
+
+static void outputBed(struct gfPcrOutput *out, FILE *f, char *url)
+/* Output match in BED 6 format. */
+{
+char *name = out->name;
+if (name == NULL) name = "n/a";
+fprintf(f, "%s\t%d\t%d\t", out->seqName, out->fPos, out->rPos);
+fprintf(f, "%s\t", name);
+fprintf(f, "%d\t", getBedScore(out));
+fprintf(f, "%c\n", out->strand);
+}
+
+static void outputBed12(struct gfPcrOutput *out, FILE *f, char *url)
+/* Output match in BED 12 format (a block for each primer). */
+{
+int fPrimerSize = strlen(out->fPrimer);
+int rPrimerSize = strlen(out->rPrimer);
+char *name = out->name;
+if (name == NULL) name = "n/a";
+fprintf(f, "%s\t%d\t%d\t%s\t", out->seqName, out->fPos, out->rPos, name);
+fprintf(f, "%d\t%c\t", getBedScore(out), out->strand);
+fprintf(f, "%d\t%d\t", out->fPos, out->rPos);
+fprintf(f, "0\t2\t%d,%d,\t0,%d\n", fPrimerSize, rPrimerSize,
+	out->rPos - out->fPos - rPrimerSize);
+}
+
+static void outputPsl(struct gfPcrOutput *out, FILE *f, char *url)
+/* Output match in PSL format. */
+{
+int match;
+int size = out->rPos - out->fPos;
+int fPrimerSize = strlen(out->fPrimer);
+int rPrimerSize = strlen(out->rPrimer);
+int bothSize = fPrimerSize + rPrimerSize;
+int gapSize = size - bothSize;
+char *name = out->name;
+if (name == NULL) name = "n/a";
+match = countMatch(out->dna, out->fPrimer, fPrimerSize);
+reverseComplement(out->rPrimer, rPrimerSize);
+assert(size > 0);
+match += countMatch(out->dna + size - rPrimerSize, out->rPrimer, rPrimerSize);
+reverseComplement(out->rPrimer, rPrimerSize);
+
+fprintf(f, "%d\t", match);
+fprintf(f, "%d\t", bothSize - match);
+fprintf(f, "0\t0\t");	/* repMatch, nCount. */
+fprintf(f, "1\t%d\t", gapSize);   /* qNumInsert, qBaseInsert */
+fprintf(f, "1\t%d\t", gapSize);   /* tNumInsert, tBaseInsert */
+fprintf(f, "%c\t", out->strand);
+fprintf(f, "%s\t", name);
+fprintf(f, "%d\t", size);
+fprintf(f, "0\t%d\t", size);	/* qStart, qEnd */
+fprintf(f, "%s\t%d\t", out->seqName, out->seqSize);
+fprintf(f, "%d\t%d\t", out->fPos, out->rPos);
+fprintf(f, "2\t");
+if (out->strand == '+')
+    {
+    fprintf(f, "%d,%d,\t", fPrimerSize, rPrimerSize);
+    fprintf(f, "%d,%d,\t", 0,size - rPrimerSize);
+    fprintf(f, "%d,%d,\n", out->fPos, out->rPos - rPrimerSize);
+    }
+else
+    {
+    fprintf(f, "%d,%d,\t", rPrimerSize, fPrimerSize);
+    fprintf(f, "%d,%d,\t", 0,size - fPrimerSize);
+    fprintf(f, "%d,%d,\n", out->fPos, out->rPos - fPrimerSize);
+    }
+}
+
+typedef void (*outFunction)(struct gfPcrOutput *out, FILE *f, char *url) ;
+
+static outFunction gfPcrOutputFunction(char *outType)
+/* Return a pointer to output function for the given output type. */
+{
+outFunction output = NULL;
+if (sameWord(outType, "fa"))
+    output = outputFa;
+else if (sameWord(outType, "bed"))
+    output = outputBed;
+else if (sameWord(outType, "bed12"))
+    output = outputBed12;
+else if (sameWord(outType, "psl"))
+    output = outputPsl;
+else
+    errAbort("Unrecognized pcr output type %s", outType);
+return output;
+}
+
+void gfPcrOutputWriteList(struct gfPcrOutput *outList, char *outType, 
+	char *url, FILE *f)
+/* Write list of outputs in specified format (either "fa" or "bed") 
+ * to file.  If url is non-null it should be a printf formatted
+ * string that takes %s, %d, %d for chromosome, start, end. */
+{
+outFunction output = gfPcrOutputFunction(outType);
+struct gfPcrOutput *out;
+for (out = outList; out != NULL; out = out->next)
+    output(out, f, url);
+}
+
+void gfPcrOutputWriteOne(struct gfPcrOutput *out, char *outType, 
+	char *url, FILE *f)
+/* Write a single output in specified format (either "fa" or "bed") 
+ * to file.  If url is non-null it should be a printf formatted
+ * string that takes %s, %d, %d for chromosome, start, end. */
+{
+outFunction output = gfPcrOutputFunction(outType);
+output(out, f, url);
+}
+
+void gfPcrOutputWriteAll(struct gfPcrOutput *outList, 
+	char *outType, char *url, char *fileName)
+/* Create file of outputs in specified format (either "fa" or "bed") 
+ * to file.  If url is non-null it should be a printf formatted
+ * string that takes %s, %d, %d for chromosome, start, end. */
+{
+FILE *f = mustOpen(fileName, "w");
+gfPcrOutputWriteList(outList, outType, url, f);
+carefulClose(&f);
+}
+
+
+static void pcrLocalStrand(char *pcrName, 
+	struct dnaSeq *seq,  int seqOffset, char *seqName, int seqSize,
+	int maxSize, char *fPrimer, int fPrimerSize, char *rPrimer, int rPrimerSize,
+	int minPerfect, int minGood,
+	char strand, struct gfPcrOutput **pOutList)
+/* Do detailed PCR scan on one strand and report results. */
+{
+char *fDna = seq->dna, *rDna;
+char *endDna = fDna + seq->size;
+char *fpPerfect = fPrimer + fPrimerSize - minPerfect;
+char *rpPerfect = rPrimer;
+char *fpMatch, *rpMatch;
+int goodSize = minGood - minPerfect;
+struct gfPcrOutput  *out;
+int matchSize;
+
+reverseComplement(rPrimer, rPrimerSize);
+for (;;)
+    {
+    fpMatch = memMatch(fpPerfect, minPerfect, fDna, endDna - fDna);
+    if (fpMatch == NULL)
+        break;
+    rDna = fpMatch;
+    for (;;)
+        {
+	int fPos, rPos, fGoodPos, rGoodPos, fTrim, rTrim;
+	rpMatch = memMatch(rpPerfect, minPerfect, rDna, endDna - rDna);
+	if (rpMatch == NULL)
+	    break;
+	fPos = fpMatch - (fPrimerSize - minPerfect) - seq->dna;
+	rPos = rpMatch + rPrimerSize - seq->dna;
+
+	/* deal with primers dangling off either end of the target sequence */
+	if (fPos < 0)
+	    {
+	    fTrim = 0 - fPos;
+	    fPos = 0;
+	    }
+	else
+	    fTrim = 0;
+
+	if (rPos > seq->size)
+	    {
+	    rTrim = rPos - seq->size;
+	    rPos = seq->size;
+	    }
+	else
+	    rTrim = 0;
+
+	fGoodPos = fpMatch - goodSize - seq->dna;
+	rGoodPos = rpMatch + minPerfect - seq->dna;
+
+	fGoodPos = max(fGoodPos, 0);
+	rGoodPos = min(rGoodPos, seq->size);
+
+	matchSize = rPos - fPos;
+
+	int fGoodSize = fGoodPos - fPos;
+	int rGoodSize = rPos - rGoodPos;
+	fGoodSize = min(fGoodSize, goodSize);
+	rGoodSize = min(rGoodSize, goodSize);
+
+        if (rPos >= 0 && fPos >= 0 && fPos < seq->size && matchSize <= maxSize)
+	    {
+	    /* If matches well enough create output record. */
+	    if (goodMatch(seq->dna + fGoodPos, fpPerfect - fGoodSize, fGoodSize) &&
+	        goodMatch(seq->dna + rGoodPos, rpPerfect + minPerfect, rGoodSize))
+		{
+
+		/* Truncate the copy of the primers going into the out-> record using rTrim and fTrim if needed. */
+		AllocVar(out);
+		out->name  = cloneString(pcrName);
+		out->fPrimer = cloneString(fPrimer + fTrim);
+		out->rPrimer = cloneStringZ(rPrimer, rPrimerSize - rTrim);
+		reverseComplement(out->rPrimer, rPrimerSize - rTrim);
+		out->seqName = cloneString(seqName);
+		out->seqSize = seqSize;
+		out->fPos = fPos + seqOffset;
+		out->rPos = rPos + seqOffset;
+		out->strand = strand;
+		out->dna = cloneStringZ(seq->dna + fPos, matchSize);
+		
+
+		/* Dealing with the strand of darkness....  Here we just have to swap
+		 * forward and reverse primers to flip strands, and reverse complement
+		 * the amplified area.. */
+		if (strand == '-')
+		    {
+		    char *temp = out->rPrimer;
+		    out->rPrimer = out->fPrimer;
+		    out->fPrimer = temp;
+		    reverseComplement(out->dna, matchSize);
+		    }
+		slAddHead(pOutList, out);
+		}
+	    }
+	rDna = rpMatch+1;
+	}
+    fDna = fpMatch + 1;
+    }
+reverseComplement(rPrimer, rPrimerSize);
+}
+
+void gfPcrLocal(char *pcrName, 
+	struct dnaSeq *seq, int seqOffset, char *seqName, int seqSize,
+	int maxSize, char *fPrimer, int fPrimerSize, char *rPrimer, int rPrimerSize,
+	int minPerfect, int minGood, char strand, struct gfPcrOutput **pOutList)
+/* Do detailed PCR scan on DNA already loaded into memory and put results
+ * (in reverse order) on *pOutList. */
+{
+/* For PCR primers reversing search strand just means switching
+ * order of primers. */
+if (strand == '-')
+    pcrLocalStrand(pcrName, seq, seqOffset, seqName, seqSize, maxSize, 
+	rPrimer, rPrimerSize, fPrimer, fPrimerSize, 
+	minPerfect, minGood, strand, pOutList);
+else
+    pcrLocalStrand(pcrName, seq, seqOffset, seqName, seqSize, maxSize, 
+	fPrimer, fPrimerSize, rPrimer, rPrimerSize, 
+	minPerfect, minGood, strand, pOutList);
+}
+
+struct gfRange *gfPcrGetRanges(char *host, char *port, char *fPrimer, char *rPrimer,
+	int maxSize)
+/* Query gfServer with primers and convert response to a list of gfRanges. */
+{
+char buf[256];
+int conn = gfConnect(host, port);
+struct gfRange *rangeList = NULL, *range;
+
+/* Query server and put results into rangeList. */
+safef(buf, sizeof(buf), "%spcr %s %s %d", gfSignature(), fPrimer, rPrimer, maxSize);
+mustWriteFd(conn, buf, strlen(buf));
+for (;;)
+    {
+    if (netGetString(conn, buf) == NULL)
+	break;
+    if (sameString(buf, "end"))
+	break;
+    else if (startsWith("Error:", buf))
+	errAbort("%s", buf);
+    else
+	{
+	char *s = buf;
+	char *name, *start, *end, *strand;
+	name = nextWord(&s);
+	start = nextWord(&s);
+	end = nextWord(&s);
+	strand = nextWord(&s);
+	if (strand == NULL)
+	    errAbort("Truncated gfServer response");
+	AllocVar(range);
+	range->tName = cloneString(name);
+	range->tStart = atoi(start);
+	range->tEnd = atoi(end);
+	range->tStrand = strand[0];
+	slAddHead(&rangeList, range);
+	}
+    }
+close(conn);
+slReverse(&rangeList);
+return rangeList;
+}
+
+static void gfPcrOneViaNet(
+	char *host, char *port, char *seqDir,
+	char *pcrName, char *fPrimer, char *rPrimer, int maxSize,
+	int minPerfect, int minGood,
+	struct hash *tFileCache, struct gfPcrOutput **pOutList)
+/* Query gfServer for likely primer hits, load DNA to do detailed
+ * examination, and output hits to head of *pOutList.. */
+{
+struct gfRange *rangeList = NULL, *range;
+int fPrimerSize = strlen(fPrimer);
+int rPrimerSize = strlen(rPrimer);
+int maxPrimerSize = max(fPrimerSize, rPrimerSize);
+int minPrimerSize = min(fPrimerSize, rPrimerSize);
+
+tolowers(fPrimer);
+tolowers(rPrimer);
+
+/* Check for obvious user mistake. */
+if (minPrimerSize < minGood || minPrimerSize < minPerfect)
+    errAbort("Need longer primer in pair %s (%dbp) %s (%dbp).  Minimum size is %d\n",
+	fPrimer, fPrimerSize, rPrimer, rPrimerSize, minGood);
+
+/* Load ranges and do more detailed snooping. */
+rangeList = gfPcrGetRanges(host, port, fPrimer, rPrimer, maxSize);
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    int tSeqSize;
+    char seqName[PATH_LEN];
+    struct dnaSeq *seq = gfiExpandAndLoadCached(range,
+	tFileCache, seqDir,  0, &tSeqSize, FALSE, FALSE, maxPrimerSize);
+    gfiGetSeqName(range->tName, seqName, NULL);
+    gfPcrLocal(pcrName, seq, range->tStart, seqName, tSeqSize, maxSize, 
+	    fPrimer, fPrimerSize, rPrimer, rPrimerSize, 
+	    minPerfect, minGood, range->tStrand, pOutList);
+    dnaSeqFree(&seq);
+    }
+gfRangeFreeList(&rangeList);
+}
+
+
+struct gfPcrOutput *gfPcrViaNet(char *host, char *port, char *seqDir, 
+	struct gfPcrInput *inList, int maxSize, int minPerfect, int minGood)
+/* Do PCRs using gfServer index, returning list of results. */
+{
+struct hash *tFileCache = gfFileCacheNew();
+struct gfPcrInput *in;
+struct gfPcrOutput *outList = NULL;
+
+for (in = inList; in != NULL; in = in->next)
+    {
+    gfPcrOneViaNet(host, port, seqDir,
+    	in->name, in->fPrimer, in->rPrimer, maxSize,
+	minPerfect, minGood,
+    	tFileCache, &outList);
+    }
+gfFileCacheFree(&tFileCache);
+slReverse(&outList);
+return outList;
+}
+
+char *gfPcrMakePrimer(char *s)
+/* Make primer (lowercased DNA) out of text.  Complain if
+ * it is too short or too long. */
+{
+int size = dnaFilteredSize(s);
+int realSize;
+char *primer = needMem(size+1);
+dnaFilter(s, primer);
+realSize = size - countChars(primer, 'n');
+if (realSize < 10 || realSize < size/2)
+   errAbort("%s does not seem to be a good primer", s);
+return primer;
+}
+
diff --git a/jkOwnLib/gfWebLib.c b/jkOwnLib/gfWebLib.c
new file mode 100644
index 0000000..57ed706
--- /dev/null
+++ b/jkOwnLib/gfWebLib.c
@@ -0,0 +1,92 @@
+/* gfWebLib - some helper routines for the webBlat and webPcr.
+ * Copyright 2004-2005 Jim Kent.  All rights reserved. */
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "cheapcgi.h"
+#include "gfWebLib.h"
+
+
+struct gfServerAt *gfWebFindServer(struct gfServerAt *serverList, char *varName)
+/* Find active server (that matches contents of CGI variable varName). */
+{
+struct gfServerAt *server = serverList;
+if (cgiVarExists(varName))
+     {
+     char *db = cgiString(varName);
+     for (server = serverList; server != NULL; server = server->next)
+          {
+	  if (sameString(db, server->name))
+	      break;
+	  }
+     if (server == NULL)
+          errAbort("%s %s not found", varName, db);
+     }
+return server;
+}
+
+struct gfWebConfig *gfWebConfigRead(char *fileName)
+/* Read configuration file into globals. */
+{
+struct gfWebConfig *cfg;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *line, *word;
+struct hash *uniqHash = newHash(0), *uniqTransHash = newHash(0), *hash;
+
+AllocVar(cfg);
+cfg->company = "";
+while (lineFileNextReal(lf, &line))
+    {
+    word = nextWord(&line);
+    if (sameWord("company", word))
+        {
+	cfg->company = cloneString(trimSpaces(line));
+	}
+    else if (sameWord("gfServer", word) || sameWord("gfServerTrans", word))
+        {
+	struct gfServerAt *server;
+	char *dupe = cloneString(line);
+	AllocVar(server);
+	server->host = nextWord(&dupe);
+	server->port = nextWord(&dupe);
+	server->seqDir = nextWord(&dupe);
+	server->name = trimSpaces(dupe);
+	if (server->name == NULL || server->name[0] == 0)
+	    errAbort("Badly formed gfServer command line %d of %s:\n%s",
+	    	lf->lineIx, fileName, line);
+	if (sameString("gfServerTrans", word))
+	    {
+	    slAddTail(&cfg->transServerList, server);
+	    hash = uniqTransHash;
+	    }
+	else
+	    {
+	    slAddTail(&cfg->serverList, server);
+	    hash = uniqHash;
+	    }
+	if (hashLookup(hash, server->name))
+	    errAbort("Duplicate %s name %s line %d of %s",
+	    	word, server->name, lf->lineIx, fileName);
+	hashAdd(hash, server->name, NULL);
+	}
+    else if (sameWord("tempDir", word))
+        {
+	cfg->tempDir = cloneString(trimSpaces(line));
+	}
+    else if (sameWord("background", word))
+        {
+	cfg->background = cloneString(trimSpaces(line));
+	}
+    else
+        {
+	errAbort("Unrecognized command %s line %d of  %s", word, lf->lineIx, fileName);
+	}
+    }
+
+if (cfg->serverList == NULL && cfg->transServerList == NULL)
+    errAbort("no gfServer's specified in %s", fileName);
+freeHash(&uniqHash);
+freeHash(&uniqTransHash);
+return cfg;
+}
+
diff --git a/jkOwnLib/makefile b/jkOwnLib/makefile
new file mode 100644
index 0000000..e8cd6e0
--- /dev/null
+++ b/jkOwnLib/makefile
@@ -0,0 +1,19 @@
+include ../inc/common.mk
+
+O = bandExt.o crudeali.o ffAliHelp.o ffSeedExtend.o fuzzyFind.o \
+    genoFind.o gfBlatLib.o gfClientLib.o gfInternal.o gfOut.o gfPcrLib.o gfWebLib.o ooc.o \
+    patSpace.o splix.o supStitch.o trans3.o xenbig.o xensmall.o 
+
+T = ../lib/$(MACHTYPE)/jkOwnLib.a
+
+$(T): $(O) ../lib/$(MACHTYPE)
+	ar rcus $(T) $(O)
+
+../lib/$(MACHTYPE):
+	mkdir ../lib/$(MACHTYPE)
+
+clean:
+	rm -f ${O} ../lib/$(MACHTYPE)/jkOwnLib.a
+
+tags:
+	etags ../inc/*.h ../lib/*.h ../lib/*.c  ../hg/inc/*.h ../hg/lib/*.h ../hg/lib/*.c ../hg/hgTracks/hgTracks.c ../hg/hgc/hgc.c ../hg/hgTrackUi/hgTrackUi.c
diff --git a/jkOwnLib/ooc.c b/jkOwnLib/ooc.c
new file mode 100644
index 0000000..d2901a0
--- /dev/null
+++ b/jkOwnLib/ooc.c
@@ -0,0 +1,77 @@
+/* ooc.c - Stuff to handle overused N-mers (tiles) in genome
+ * indexing schemes. */
+/* Copyright 2001-2003 Jim Kent.  All rights reserved. */
+#include "common.h"
+#include "ooc.h"
+#include "sig.h"
+
+
+void oocMaskCounts(char *oocFile, bits32 *tileCounts, int tileSize, bits32 maxPat)
+/* Set items of tileCounts to maxPat if they are in oocFile. 
+ * Effectively masks this out of index.*/
+{
+if (oocFile != NULL)
+    {
+    bits32 sig, psz;
+    FILE *f = mustOpen(oocFile, "rb");
+    boolean mustSwap = FALSE;
+
+    mustReadOne(f, sig);
+    mustReadOne(f, psz);
+    if (sig == oocSig)
+	mustSwap = FALSE;
+    else if (sig == oocSigSwapped)
+	{
+	mustSwap = TRUE;
+	psz = byteSwap32(psz);
+	}
+    else
+        errAbort("Bad signature on %s\n", oocFile);
+    if (psz != tileSize)
+        errAbort("Oligo size mismatch in %s. Expecting %d got %d\n", 
+            oocFile, tileSize, psz);
+    if (mustSwap)
+	{
+	union {bits32 whole; UBYTE bytes[4];} u,v;
+	while (readOne(f, u))
+	    {
+	    v.bytes[0] = u.bytes[3];
+	    v.bytes[1] = u.bytes[2];
+	    v.bytes[2] = u.bytes[1];
+	    v.bytes[3] = u.bytes[0];
+	    tileCounts[v.whole] = maxPat;
+	    }
+	}
+    else
+	{
+	bits32 oli;
+	while (readOne(f, oli))
+	    tileCounts[oli] = maxPat;
+	}
+    fclose(f);
+    }
+}
+
+void oocMaskSimpleRepeats(bits32 *tileCounts, int seedSize, bits32 maxPat)
+/* Mask out simple repeats in index . */
+{
+int i, j, k;
+int tileMask = (1<<(seedSize+seedSize))-1;
+for (i=0; i<4; ++i)
+    {
+    for (j=0; j<4; ++j)
+        {
+        bits32 repeat = 0;
+        for (k=0; k<8; ++k)
+            {
+            repeat <<= 2;
+            repeat |= i;
+            repeat <<= 2;
+            repeat |= j;
+            }
+        repeat &= tileMask;
+        tileCounts[repeat] = maxPat;
+        }
+    }
+}
+
diff --git a/jkOwnLib/patSpace.c b/jkOwnLib/patSpace.c
new file mode 100644
index 0000000..80f1de7
--- /dev/null
+++ b/jkOwnLib/patSpace.c
@@ -0,0 +1,463 @@
+/* patSpace - a homology finding algorithm that occurs mostly in 
+ * pattern space (as opposed to offset space). */
+/* Copyright 1999-2003 Jim Kent.  All rights reserved. */
+#include "common.h"
+#include "portable.h"
+#include "dnaseq.h"
+#include "ooc.h"
+#include "patSpace.h"
+
+
+#define blockSize (256)
+
+#define BIGONE	/* define this for 32 bit version. */
+
+#ifdef BIGONE
+
+#define maxBlockCount (2*230*1024 - 1)
+#define psBits bits32
+/* psBits is the size of an index word.  If 16 bits
+ * patSpace will use less memory, but be limited to
+ * 16 meg or less genome size. */
+
+#else /* BIGONE */
+
+#define maxBlockCount (64*1024 - 1)
+#define psBits bits16
+/* psBits is the size of an index word.  If 16 bits
+ * patSpace will use less memory, but be limited to
+ * 16 meg or less genome size. */
+
+#endif /* BIGONE */
+
+
+#define maxPatCount (1024*16)    /* Maximum allowed count for one pattern. */
+
+struct blockPos
+/* Structure that stores where in a BAC we are - 
+ * essentially an unpacked block index. */
+    {
+    bits16 bacIx;          /* Which bac. */
+    bits16 seqIx;          /* Which subsequence in bac. */
+    struct dnaSeq *seq; /* Pointer to subsequence. */
+    int offset;         /* Start position of block within subsequence. */
+    int size;           /* Size of block within subsequence. */
+    };
+
+struct patSpace
+/* A pattern space - something that holds an index of all 10-mers in
+ * genome. */
+    {
+    psBits **lists;                      /* A list for each 10-mer */
+    psBits *listSizes;                   /* Size of list for each 10-mer */
+    psBits *allocated;                   /* Storage space for all lists. */
+    int    blocksUsed;			 /* Number of blocks used, <= maxBlockCount */
+    int posBuf[maxBlockCount];           /* Histogram of hits to each block. */
+    int hitBlocks[maxBlockCount];        /* Indexes of blocks with hits. */
+    struct blockPos blockPos[maxBlockCount]; /* Relates block to sequence. */
+    psBits maxPat;                       /* Max # of times pattern can occur
+                                          * before it is ignored. */
+    int minMatch;                        /* Minimum number of tile hits needed
+                                          * to trigger a clump hit. */
+    int maxGap;                          /* Max gap between tiles in a clump. */
+    int seedSize;			 /* Size of alignment seed. */
+    int seedSpaceSize;                    /* Number of possible seed values. */
+    };
+
+void freePatSpace(struct patSpace **pPatSpace)
+/* Free up a pattern space. */
+{
+struct patSpace *ps = *pPatSpace;
+if (ps != NULL)
+    {
+    freeMem(ps->allocated);
+    freez(pPatSpace);
+    }
+}
+
+void tooManyBlocks()
+/* Complain about too many blocks and abort. */
+{
+errAbort("Too many blocks, can only handle %d\n", maxBlockCount);
+}
+
+static void fixBlockSize(struct blockPos *bp, int blockIx)
+/* Update size field from rest of blockPos. */
+{
+struct dnaSeq *seq = bp->seq;
+int size = seq->size - bp->offset;
+if (size > blockSize)
+	size = blockSize;
+bp->size = size;
+}
+
+static struct patSpace *newPatSpace(int minMatch, int maxGap, int seedSize)
+/* Return an empty pattern space. */
+{
+struct patSpace *ps;
+int seedBitSize = seedSize*2;
+int seedSpaceSize;
+
+AllocVar(ps);
+ps->seedSize = seedSize;
+seedSpaceSize = ps->seedSpaceSize = (1<<seedBitSize);
+ps->lists = needLargeZeroedMem(seedSpaceSize * sizeof(ps->lists[0]));
+ps->listSizes = needLargeZeroedMem(seedSpaceSize * sizeof(ps->listSizes[0]));
+ps->minMatch = minMatch;
+ps->maxGap = maxGap;
+return ps;
+}
+
+static void countPatSpace(struct patSpace *ps, struct dnaSeq *seq)
+/* Add up number of times each pattern occurs in sequence into ps->listSizes. */
+{
+int size = seq->size;
+int mask = ps->seedSpaceSize-1;
+DNA *dna = seq->dna;
+int i;
+int bits = 0;
+int bVal;
+int ls;
+
+for (i=0; i<ps->seedSize-1; ++i)
+    {
+    bVal = ntValNoN[(int)dna[i]];
+    bits <<= 2;
+    bits += bVal;
+    }
+for (i=ps->seedSize-1; i<size; ++i)
+    {
+    bVal = ntValNoN[(int)dna[i]];
+    bits <<= 2;
+    bits += bVal;
+    bits &= mask;
+    ls = ps->listSizes[bits];
+    if (ls < maxPatCount)
+        ps->listSizes[bits] = ls+1;
+    }
+}
+
+static int allocPatSpaceLists(struct patSpace *ps)
+/* Allocate pat space lists and set up list pointers. 
+ * Returns size of all lists. */
+{
+int oneCount;
+int count = 0;
+int i;
+psBits *listSizes = ps->listSizes;
+psBits **lists = ps->lists;
+psBits *allocated;
+psBits maxPat = ps->maxPat;
+int size;
+int usedCount = 0, overusedCount = 0;
+int seedSpaceSize = ps->seedSpaceSize;
+
+for (i=0; i<seedSpaceSize; ++i)
+    {
+    /* If pattern is too much used it's no good to us, ignore. */
+    if ((oneCount = listSizes[i]) < maxPat)
+        {
+        count += oneCount;
+        usedCount += 1;
+        }
+    else
+        {
+        overusedCount += 1;
+        }
+    }
+ps->allocated = allocated = needLargeMem(count*sizeof(allocated[0]));
+for (i=0; i<seedSpaceSize; ++i)
+    {
+    if ((size = listSizes[i]) < maxPat)
+        {
+        lists[i] = allocated;
+        allocated += size;
+        }
+    }
+return count;
+}
+
+static int addToPatSpace(struct patSpace *ps, int bacIx, int seqIx, struct dnaSeq *seq,int startBlock)
+/* Add contents of one sequence to pattern space. Returns end block. */
+{
+int size = seq->size;
+int mask = ps->seedSpaceSize-1;
+DNA *dna = seq->dna;
+int i;
+int bits = 0;
+int bVal;
+int blockMod = blockSize;
+int curCount;
+psBits maxPat = ps->maxPat;
+psBits *listSizes = ps->listSizes;
+psBits **lists = ps->lists;
+struct blockPos *bp = &ps->blockPos[startBlock];
+
+bp->bacIx = bacIx;
+bp->seqIx = seqIx;
+bp->seq = seq;
+bp->offset = 0;
+fixBlockSize(bp, startBlock);
+++bp;
+for (i=0; i<ps->seedSize-1; ++i)
+    {
+    bVal = ntValNoN[(int)dna[i]];
+    bits <<= 2;
+    bits += bVal;
+    }
+for (i=ps->seedSize-1; i<size; ++i)
+    {
+    bVal = ntValNoN[(int)dna[i]];
+    bits <<= 2;
+    bits += bVal;
+    bits &= mask;
+    if ((curCount = listSizes[bits]) < maxPat)
+        {
+        listSizes[bits] = curCount+1;
+        lists[bits][curCount] = startBlock;
+        }
+    if (--blockMod == 0)
+        {
+        if (++startBlock >= maxBlockCount)
+	    tooManyBlocks();
+        blockMod = blockSize;
+	bp->bacIx = bacIx;
+	bp->seqIx = seqIx;
+	bp->seq = seq;
+	bp->offset = i - (ps->seedSize-1) + 1;
+	fixBlockSize(bp, startBlock);
+	++bp;
+        }
+    }
+for (i=0; i<ps->seedSize-1; ++i)
+    {
+    if (--blockMod == 0)
+        {
+        if (++startBlock >= maxBlockCount)
+	    tooManyBlocks();
+        blockMod = blockSize;
+        }
+    }
+if (blockMod != blockSize)
+    ++startBlock;
+return startBlock;
+}
+
+struct patSpace *makePatSpace(
+    struct dnaSeq **seqArray,       /* Array of sequence lists. */
+    int seqArrayCount,              /* Size of above array. */
+    int seedSize,	            /* Alignment seed size - 10 or 11. Must match oocFileName */
+    char *oocFileName,              /* File with tiles to filter out, may be NULL. */
+    int minMatch,                   /* Minimum # of matching tiles.  4 is good. */
+    int maxGap                      /* Maximum gap size - 32k is good for 
+                                       cDNA (introns), 500 is good for DNA assembly. */
+    )
+/* Allocate a pattern space and fill from sequences.  (Each element of
+   seqArray is a list of sequences. */
+{
+struct patSpace *ps = newPatSpace(minMatch, maxGap,seedSize);
+int i;
+int startIx = 0;
+int total = 0;
+struct dnaSeq *seq;
+psBits maxPat;
+psBits *listSizes;
+int seedSpaceSize = ps->seedSpaceSize;
+
+maxPat = ps->maxPat = maxPatCount;
+for (i=0; i<seqArrayCount; ++i)
+    {
+    for (seq = seqArray[i]; seq != NULL; seq = seq->next)
+        {
+        total += seq->size;
+        countPatSpace(ps, seq);
+        }
+    }
+
+listSizes = ps->listSizes;
+
+/* Scan through over-popular patterns and set their count to value 
+ * where they won't be added to pat space. */
+oocMaskCounts(oocFileName, listSizes, ps->seedSize, maxPat);
+
+/* Get rid of simple repeats as well. */
+oocMaskSimpleRepeats(listSizes, ps->seedSize, maxPat);
+
+
+allocPatSpaceLists(ps);
+
+/* Zero out pattern counts that aren't oversubscribed. */
+for (i=0; i<ps->seedSpaceSize; ++i)
+    {
+    if (listSizes[i] < maxPat)
+        listSizes[i] = 0;
+    }
+for (i=0; i<seqArrayCount; ++i)
+    {
+	int j;
+    for (seq = seqArray[i], j=0; seq != NULL; seq = seq->next, ++j)
+        {
+        startIx = addToPatSpace(ps, i, j, seq, startIx);
+        if (startIx >= maxBlockCount)
+	    tooManyBlocks();
+        }
+    }
+ps->blocksUsed = startIx;
+
+/* Zero local over-popular patterns. */
+for (i=0; i<seedSpaceSize; ++i)
+    {
+    if (listSizes[i] >= maxPat)
+        listSizes[i] = 0;
+    }
+
+return ps;
+}
+
+
+void bfFind(struct patSpace *ps, int block, struct blockPos *ret)
+/* Find dna sequence and position within sequence that corresponds to block. */
+{
+assert(block >= 0 && block < maxBlockCount);
+*ret = ps->blockPos[block];
+}
+
+
+static struct patClump *newClump(struct patSpace *ps, struct blockPos *first, struct blockPos *last)
+/* Make new clump . */
+{
+struct dnaSeq *seq = first->seq;
+int seqIx = first->seqIx;
+int bacIx = first->bacIx;
+int start = first->offset;
+int end = last->offset+last->size;
+int extraAtEnds = blockSize/2;
+struct patClump *cl;
+
+start -= extraAtEnds;
+if (start < 0)
+    start = 0;
+end += extraAtEnds;
+if (end >seq->size)
+    end = seq->size;
+AllocVar(cl);
+cl->bacIx = bacIx;
+cl->seqIx = seqIx;
+cl->seq = seq;
+cl->start = start;
+cl->size = end-start;
+return cl;
+}
+
+
+static struct patClump *clumpHits(struct patSpace *ps,
+    int hitBlocks[], int hitCount, int posBuf[], 
+    DNA *dna, int dnaSize)
+/* Clumps together hits and returns a list. */
+{
+/* Clump together hits. */
+int block;
+int i;
+int maxGap = ps->maxGap;
+struct blockPos first, cur, pre;
+struct patClump *patClump = NULL, *cl;
+
+bfFind(ps, hitBlocks[0], &first);
+pre = first;
+for (i=1; i<hitCount; ++i)
+    {
+    block = hitBlocks[i];
+    bfFind(ps, block, &cur);
+    if (cur.seq != pre.seq || cur.offset - (pre.offset + pre.size) > maxGap)
+        {
+        /* Write old clump and start new one. */
+        cl = newClump(ps, &first, &pre);
+        slAddHead(&patClump, cl);
+        first = cur;
+        }
+    else
+        {
+        /* Extend old clump. */
+        }
+    pre = cur;
+    }
+/* Write hitOut last clump. */
+cl = newClump(ps, &first, &pre);
+slAddHead(&patClump, cl);
+slReverse(&patClump);
+return patClump;
+}
+
+struct patClump *patSpaceFindOne(struct patSpace *ps, DNA *dna, int dnaSize)
+/* Find occurrences of DNA in patSpace. */
+{
+int lastStart = dnaSize - ps->seedSize;
+int i,j;
+int pat;
+int hitBlockCount = 0;
+int totalSigHits = 0;
+DNA *tile = dna;
+int blocksUsed = ps->blocksUsed;
+int *posBuf = ps->posBuf;
+int *hitBlocks = ps->hitBlocks;
+int minMatch = ps->minMatch;
+
+memset(ps->posBuf, 0, sizeof(ps->posBuf[0]) * blocksUsed);
+for (i=0; i<=lastStart; i += ps->seedSize)
+    {
+    psBits *list;
+    psBits count;
+
+    pat = 0;
+    for (j=0; j<ps->seedSize; ++j)
+        {
+        int bVal = ntValNoN[(int)tile[j]];
+        pat <<= 2;
+        pat += bVal;
+        }
+    list = ps->lists[pat];
+    if ((count = ps->listSizes[pat]) > 0)
+        {
+        for (j=0; j<count; ++j)
+            posBuf[list[j]] += 1;            
+        }
+    tile += ps->seedSize;
+    }
+
+/* Scan through array that records counts of hits at positions. */
+for (i=0; i<blocksUsed-1; ++i)
+    {
+    /* Save significant hits in a more compact array */
+    int a = posBuf[i], b = posBuf[i+1];
+    int sum = a + b;
+    if (sum >= minMatch)
+        {
+        if (a > 0)
+            {
+            if (hitBlockCount == 0 || hitBlocks[hitBlockCount-1] != i)
+                {
+                hitBlocks[hitBlockCount++] = i;
+                totalSigHits += a;
+                }
+            }
+        if (b > 0)
+            {
+            hitBlocks[hitBlockCount++] = i+1;
+            totalSigHits += b;
+            }
+        }
+    }
+
+/* Output data with significant hits. */
+if (hitBlockCount > 0 && totalSigHits*ps->seedSize*8 > dnaSize)
+    {
+    return clumpHits(ps, hitBlocks, hitBlockCount, posBuf, dna, 
+        dnaSize);
+    }        
+else
+    return NULL;
+}
+
+
+
+
diff --git a/jkOwnLib/splix.c b/jkOwnLib/splix.c
new file mode 100644
index 0000000..231c6c9
--- /dev/null
+++ b/jkOwnLib/splix.c
@@ -0,0 +1,152 @@
+/* splix - splat (speedy local alignment tool)  index.  Index that helps map short reads
+ * quickly to the genome. */
+/* This file is copyright 2008 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "splix.h"
+#include "net.h"
+#include <sys/mman.h>
+
+static void *pointerOffset(void *pt, bits64 offset)
+/* A little wrapper around pointer arithmetic in terms of bytes. */
+{
+char *s = pt;
+return s + offset;
+}
+
+struct splix *splixRead(char *fileName, boolean memoryMap)
+/* Read in a splix from a file.  Does this via memory mapping if you like,
+ * which will be faster typically for about 100 reads, and slower for more
+ * than that (_much_ slower for thousands of reads and more). */
+{
+/* Open file (low level), read in header, and check it. */
+int fd = open(fileName, O_RDONLY);
+if (fd < 0)
+    errnoAbort("Can't open %s", fileName);
+struct splixFileHeader h;
+if (read(fd, &h, sizeof(h)) < sizeof(h))
+    errnoAbort("Couldn't read header of file %s", fileName);
+if (h.magic != SPLIX_MAGIC)
+    errAbort("%s does not seem to be a splix file.", fileName);
+if (h.majorVersion > SPLIX_MAJOR_VERSION)
+    errAbort("%s is a newer, incompatible version of splix format. "
+             "This program works on version %d and below. "
+	     "%s is version %d.",  fileName, SPLIX_MAJOR_VERSION, fileName, h.majorVersion);
+
+struct splix *splix;
+
+/* Get a pointer to data in memory, via memory map, or allocation and read. */
+struct splixFileHeader *header ;
+if (memoryMap)
+    {
+#ifdef MACHTYPE_sparc
+    header = (struct splixFileHeader *)mmap(NULL, h.size, PROT_READ, MAP_SHARED, fd, 0);
+#else
+    header = mmap(NULL, h.size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0);
+#endif
+    if (header == (void*)(-1))
+	errnoAbort("Couldn't mmap %s, sorry", fileName);
+    }
+else
+    {
+    header = needHugeMem(h.size);
+    if (lseek(fd, 0, SEEK_SET) < 0)
+	errnoAbort("Couldn't seek back to start of splix file %s.  "
+		   "Splix files must be random access files, not pipes and the like"
+		   , fileName);
+    if (netReadAll(fd, header, h.size) < h.size)
+        errnoAbort("Couldn't read all of splix file %s.", fileName);
+    }
+
+/* Allocate wrapper structure and fill it in. */
+AllocVar(splix);
+splix->header = header;
+splix->isMapped = memoryMap;
+
+/* Make an array for easy access to chromosome names. */
+int chromCount = header->chromCount;
+char **chromNames = AllocArray(splix->chromNames, chromCount);
+char *s = pointerOffset(header, sizeof(*header) );
+int i;
+for (i=0; i<chromCount; ++i)
+    {
+    chromNames[i] = s;
+    s += strlen(s)+1;
+    }
+
+/* Keep track of where we are in memmap. */
+bits64 mapOffset = sizeof(*header) + header->chromNamesSize;
+
+/* Point into chromSizes array. */
+bits32 *chromSizes = splix->chromSizes 
+	= pointerOffset(header, mapOffset);
+mapOffset += sizeof(bits32) * chromCount;
+if (chromCount&1)
+    mapOffset += sizeof(bits32);	/* Take care of padding to 8 bytes */
+
+verbose(2, "total dna size %lld in %d chromosomes\n", (long long)header->dnaDiskSize, header->chromCount);
+splix->allDna = pointerOffset(header, mapOffset);
+mapOffset += header->dnaDiskSize;
+
+/* Calculate chromOffset array. */
+bits32 offset = 0;
+bits32 *chromOffsets = AllocArray(splix->chromOffsets, chromCount);
+for (i=0; i<chromCount; ++i)
+    {
+    chromOffsets[i] = offset;
+    offset += chromSizes[i] + 1;
+    verbose(2, "splix contains %s,  %d bases, %d offset\n", 
+    	splix->chromNames[i], (int)splix->chromSizes[i], (int)chromOffsets[i]);
+    }
+
+/* Deal with array of sizes */
+splix->slotSizes = pointerOffset(header, mapOffset);
+mapOffset += splixSlotCount * sizeof(bits32);
+
+/* Allocate index array and fill in slots. */
+char **slots = AllocArray(splix->slots, splixSlotCount);
+for (i=0; i<splixSlotCount; ++i)
+    {
+    bits32 slotSize = splix->slotSizes[i];;
+    if (slotSize)
+	{
+	slots[i] = pointerOffset(header, mapOffset);
+	mapOffset += slotSize * 4 * (sizeof(bits32) + sizeof(bits16));
+	}
+    }
+
+assert(mapOffset == header->size);	/* Sanity check */
+return splix;
+}
+
+void splixFree(struct splix **pSplix)
+/* Free up resources associated with index. */
+{
+struct splix *splix = *pSplix;
+if (splix != NULL)
+    {
+    if (splix->isMapped)
+	munmap((void *)splix->header, splix->header->size);
+    else
+	freeMem(splix->header);
+    freez(pSplix);
+    }
+}
+
+int splixOffsetToChromIx(struct splix *splix, bits32 tOffset)
+/* Figure out index of chromosome containing tOffset */
+{
+int i;
+int chromCount = splix->header->chromCount;
+/* TODO - convert to binary search */
+for (i=0; i<chromCount; ++i)
+    {
+    int chromStart = splix->chromOffsets[i];
+    int chromEnd = chromStart + splix->chromSizes[i];
+    if (tOffset >= chromStart && tOffset < chromEnd)
+        return i;
+    }
+errAbort("tOffset %d out of range\n", tOffset);
+return -1;
+}
+
diff --git a/jkOwnLib/supStitch.c b/jkOwnLib/supStitch.c
new file mode 100644
index 0000000..90317dc
--- /dev/null
+++ b/jkOwnLib/supStitch.c
@@ -0,0 +1,912 @@
+/* supStitch stitches together a bundle of ffAli alignments that share
+ * a common query and target sequence into larger alignments if possible.
+ * This is commonly used when the query sequence was broken up into
+ * overlapping blocks in the initial alignment, and also to look for
+ * introns larger than fuzzyFinder can handle. */
+/* Copyright 2000-2005 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "dnautil.h"
+#include "dlist.h"
+#include "fuzzyFind.h"
+#include "localmem.h"
+#include "patSpace.h"
+#include "trans3.h"
+#include "supStitch.h"
+#include "chainBlock.h"
+
+
+static void ssFindBestBig(struct ffAli *ffList, bioSeq *qSeq, bioSeq *tSeq,
+	enum ffStringency stringency, boolean isProt, struct trans3 *t3List,
+	struct ffAli **retBestAli, int *retScore, struct ffAli **retLeftovers);
+
+void ssFfItemFree(struct ssFfItem **pEl)
+/* Free a single ssFfItem. */
+{
+struct ssFfItem *el;
+if ((el = *pEl) != NULL)
+    {
+    ffFreeAli(&el->ff);
+    freez(pEl);
+    }
+}
+
+void ssFfItemFreeList(struct ssFfItem **pList)
+/* Free a list of ssFfItems. */
+{
+struct ssFfItem *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    ssFfItemFree(&el);
+    }
+*pList = NULL;
+}
+
+void ssBundleFree(struct ssBundle **pEl)
+/* Free up one ssBundle */
+{
+struct ssBundle *el;
+if ((el = *pEl) != NULL)
+    {
+    ssFfItemFreeList(&el->ffList);
+    freez(pEl);
+    }
+}
+
+void ssBundleFreeList(struct ssBundle **pList)
+/* Free up list of ssBundles */
+{
+struct ssBundle *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    ssBundleFree(&el);
+    }
+*pList = NULL;
+}
+
+void dumpNearCrossover(char *what, DNA *n, DNA *h, int size)
+/* Print sequence near crossover */
+{
+printf("%s: ", what);
+mustWrite(stdout, n, size);
+printf("\n");
+printf("%s: ", what);
+mustWrite(stdout, h, size);
+printf("\n");
+}
+
+void dumpFf(struct ffAli *left, DNA *needle, DNA *hay)
+/* Print info on ffAli. */
+{
+struct ffAli *ff;
+for (ff = left; ff != NULL; ff = ff->right)
+    {
+    printf("(%ld - %ld)[%ld-%ld] ", (long)(ff->hStart-hay), (long)(ff->hEnd-hay),
+	(long)(ff->nStart - needle), (long)(ff->nEnd - needle));
+    }
+printf("\n");
+}
+
+void dumpBuns(struct ssBundle *bunList)
+/* Print diagnostic info on bundles. */
+{
+struct ssBundle *bun;
+struct ssFfItem *ffl;
+for (bun = bunList; bun != NULL; bun = bun->next)
+    {
+    struct dnaSeq *qSeq = bun->qSeq;        /* Query sequence (not owned by bundle.) */
+    struct dnaSeq *genoSeq = bun->genoSeq;     /* Genomic sequence (not owned by bundle.) */
+    printf("Bundle of %d between %s and %s\n", slCount(bun->ffList), qSeq->name, genoSeq->name);
+    for (ffl = bun->ffList; ffl != NULL; ffl = ffl->next)
+	{
+	dumpFf(ffl->ff, bun->qSeq->dna, bun->genoSeq->dna);
+	}
+    }
+}
+
+
+static int bioScoreMatch(boolean isProt, char *a, char *b, int size)
+/* Return score of match (no inserts) between two bio-polymers. */
+{
+if (isProt)
+    {
+    return dnaOrAaScoreMatch(a, b, size, 2, -1, 'X');
+    }
+else
+    {
+    return dnaOrAaScoreMatch(a, b, size, 1, -1, 'n');
+    }
+}
+
+
+static int findCrossover(struct ffAli *left, struct ffAli *right, int overlap, boolean isProt)
+/* Find ideal crossover point of overlapping blocks.  That is
+ * the point where we should start using the right block rather
+ * than the left block.  This point is an offset from the start
+ * of the overlapping region (which is the same as the start of the
+ * right block). */
+{
+int bestPos = 0;
+char *nStart = right->nStart;
+char *lhStart = left->hEnd - overlap;
+char *rhStart = right->hStart;
+int i;
+int (*scoreMatch)(char a, char b);
+int score, bestScore;
+
+if (isProt)
+    {
+    scoreMatch = aaScore2;
+    score = bestScore = aaScoreMatch(nStart, rhStart, overlap);
+    }
+else
+    {
+    scoreMatch = dnaScore2;
+    score = bestScore = dnaScoreMatch(nStart, rhStart, overlap);
+    }
+
+for (i=0; i<overlap; ++i)
+    {
+    char n = nStart[i];
+    score += scoreMatch(lhStart[i], n);
+    score -= scoreMatch(rhStart[i], n);
+    if (score > bestScore)
+	{
+	bestScore = score;
+	bestPos = i+1;
+	}
+    }
+return bestPos;
+}
+
+static void trans3Offsets(struct trans3 *t3List, AA *startP, AA *endP,
+	int *retStart, int *retEnd)
+/* Figure out offset of peptide in context of larger sequences. */
+{
+struct trans3 *t3;
+int frame;
+aaSeq *seq;
+
+for (t3 = t3List; t3 != NULL; t3 = t3->next)
+    {
+    for (frame = 0; frame < 3; ++frame)
+        {
+	seq = t3->trans[frame];
+	if (seq->dna <= startP && startP < seq->dna + seq->size)
+	    {
+	    *retStart = 3*(startP - seq->dna)+frame + t3->start;
+	    *retEnd = 3*(endP - seq->dna)+frame + t3->start;
+	    return;
+	    }
+	}
+    }
+internalErr();
+}
+
+static boolean isMonotonic(struct ffAli *left)
+/* Return TRUE if this is monotonic on both query and target */
+{
+struct ffAli *right;
+
+while ((right = left->right) != NULL)
+    {
+    if (left->nEnd <= right->nStart && left->hEnd <= right->hStart)
+	left = right;
+    else
+	{
+	verbose(2, "not monotonic dn %d, dh %d\n", (int)(right->nStart - left->nEnd), 
+		(int)(right->hStart - right->hEnd));
+        return FALSE;
+	}
+    }
+return TRUE;
+}
+
+static struct ffAli *forceMonotonic(struct ffAli *aliList,
+	struct dnaSeq *qSeq, struct dnaSeq *tSeq, enum ffStringency stringency,
+	boolean isProt, struct trans3 *t3List)
+/* Remove any blocks that violate strictly increasing order in both coordinates. 
+ * This is not optimal, but it turns out to be very rarely used. */
+{
+if (!isProt)
+    {
+    if (!isMonotonic(aliList))
+	{
+	struct ffAli *leftovers = NULL;
+	int score;
+	ssFindBestBig(aliList, qSeq, tSeq, stringency, isProt, t3List, &aliList, &score,
+	   &leftovers);
+	ffFreeAli(&leftovers);
+	}
+    }
+return aliList;
+}
+
+struct ffAli *smallMiddleExons(struct ffAli *aliList, 
+	struct ssBundle *bundle, 
+	enum ffStringency stringency)
+/* Look for small exons in the middle. */
+{
+if (bundle->t3List != NULL)
+    return aliList;	/* Can't handle intense translated stuff. */
+else
+    {
+    struct dnaSeq *qSeq =  bundle->qSeq;
+    struct dnaSeq *genoSeq = bundle->genoSeq;
+    struct ffAli *right, *left = NULL, *newLeft, *newRight;
+
+    left = aliList;
+    for (right = aliList->right; right != NULL; right = right->right)
+        {
+	if (right->hStart - left->hEnd >= 3 && right->nStart - left->nEnd >= 3)
+	    {
+	    newLeft = ffFind(left->nEnd, right->nStart, left->hEnd, right->hStart, stringency);
+	    if (newLeft != NULL)
+	        {
+		newLeft = forceMonotonic(newLeft, qSeq, genoSeq, 
+		    stringency, bundle->isProt, bundle->t3List );
+		newRight = ffRightmost(newLeft);
+                if (left != NULL)
+                    {
+                    left->right = newLeft;
+                    newLeft->left = left;
+                    }
+                else
+                    {
+                    aliList = newLeft;
+                    }
+                if (right != NULL)
+                    {
+                    right->left = newRight;
+                    newRight->right = right;
+                    }
+		}
+	    }
+	left = right;
+	}
+    }
+return aliList;
+}
+
+struct ssNode
+/* Node of superStitch graph. */
+    {
+    struct ssEdge *waysIn;	/* Edges leading into this node. */
+    struct ffAli *ff;           /* Alignment block associated with node. */
+    struct ssEdge *bestWayIn;   /* Dynamic programming best edge in. */
+    int cumScore;               /* Dynamic programming score of edge. */
+    int nodeScore;              /* Score of this node. */
+    };
+
+struct ssEdge
+/* Edge of superStitch graph. */
+    {
+    struct ssEdge *next;         /* Next edge in waysIn list. */
+    struct ssNode *nodeIn;       /* The node that leads to this edge. */
+    int score;                   /* Score you get taking this edge. */
+    int overlap;                 /* Overlap between two nodes. */
+    int crossover;               /* Offset from overlap where crossover occurs. */
+    };
+
+struct ssGraph
+/* Super stitcher graph for dynamic programming to find best
+ * way through. */
+    {
+    int nodeCount;		/* Number of nodes. */
+    struct ssNode *nodes;       /* Array of nodes. */
+    int edgeCount;              /* Number of edges. */
+    struct ssEdge *edges;       /* Array of edges. */
+    };
+
+static void ssGraphFree(struct ssGraph **pGraph)
+/* Free graph. */
+{
+struct ssGraph *graph;
+if ((graph = *pGraph) != NULL)
+    {
+    freeMem(graph->nodes);
+    freeMem(graph->edges);
+    freez(pGraph);
+    }
+}
+
+boolean tripleCanFollow(struct ffAli *a, struct ffAli *b, aaSeq *qSeq, struct trans3 *t3List)
+/* Figure out if a can follow b in any one of three reading frames of haystack. */
+{
+int ahStart, ahEnd, bhStart, bhEnd;
+trans3Offsets(t3List, a->hStart, a->hEnd, &ahStart, &ahEnd);
+trans3Offsets(t3List, b->hStart, b->hEnd, &bhStart, &bhEnd);
+return  (a->nStart < b->nStart && a->nEnd < b->nEnd && ahStart < bhStart && ahEnd < bhEnd);
+}
+
+
+static struct ssGraph *ssGraphMake(struct ffAli *ffList, bioSeq *qSeq,
+	enum ffStringency stringency, boolean isProt, struct trans3 *t3List)
+/* Make a graph corresponding to ffList */
+{
+int nodeCount = ffAliCount(ffList);
+int maxEdgeCount = (nodeCount+1)*(nodeCount)/2;
+int edgeCount = 0;
+struct ssEdge *edges, *e;
+struct ssNode *nodes;
+struct ssGraph *graph;
+struct ffAli *ff, *mid;
+int i, midIx;
+int overlap;
+boolean canFollow;
+
+if (nodeCount == 1)
+    maxEdgeCount = 1;
+    
+AllocVar(graph);
+graph->nodeCount = nodeCount;
+graph->nodes = AllocArray(nodes, nodeCount+1);
+for (i=1, ff = ffList; i<=nodeCount; ++i, ff = ff->right)
+    {
+    nodes[i].ff = ff;
+    nodes[i].nodeScore = bioScoreMatch(isProt, ff->nStart, ff->hStart, ff->hEnd - ff->hStart);
+    }
+
+graph->edges = AllocArray(edges, maxEdgeCount);
+for (mid = ffList, midIx=1; mid != NULL; mid = mid->right, ++midIx)
+    {
+    int midScore;
+    struct ssNode *midNode = &nodes[midIx];
+    e = &edges[edgeCount++];
+    assert(edgeCount <= maxEdgeCount);
+    e->nodeIn = &nodes[0];
+    e->score = midScore = midNode->nodeScore;
+    midNode->waysIn = e;
+    for (ff = ffList,i=1; ff != mid; ff = ff->right,++i)
+	{
+	int mhStart = 0, mhEnd = 0;
+	if (t3List)
+	    {
+	    canFollow = tripleCanFollow(ff, mid, qSeq, t3List);
+	    trans3Offsets(t3List, mid->hStart, mid->hEnd, &mhStart, &mhEnd);
+	    }
+	else 
+	    {
+	    canFollow = (ff->nStart < mid->nStart && ff->nEnd < mid->nEnd 
+			&& ff->hStart < mid->hStart && ff->hEnd < mid->hEnd);
+	    }
+	if (canFollow)
+	    {
+	    struct ssNode *ffNode = &nodes[i];
+	    int score;
+	    int hGap;
+	    int nGap;
+	    int crossover;
+
+	    nGap = mid->nStart - ff->nEnd;
+	    if (t3List)
+	        {
+		int fhStart, fhEnd;
+		trans3Offsets(t3List, ff->hStart, ff->hEnd, &fhStart, &fhEnd);
+		hGap = mhStart - fhEnd;
+		}
+	    else
+		{
+		hGap = mid->hStart - ff->hEnd;
+		}
+	    e = &edges[edgeCount++];
+	    assert(edgeCount <= maxEdgeCount);
+	    e->nodeIn = ffNode;
+	    e->overlap = overlap = -nGap;
+	    if (overlap > 0)
+		{
+		int midSize = mid->hEnd - mid->hStart;
+		int ffSize = ff->hEnd - ff->hStart;
+		int newMidScore, newFfScore;
+		e->crossover = crossover = findCrossover(ff, mid, overlap, isProt);
+		newMidScore = bioScoreMatch(isProt, mid->nStart, mid->hStart, midSize-overlap+crossover);
+		newFfScore = bioScoreMatch(isProt, ff->nStart+crossover, ff->hStart+crossover,
+				ffSize-crossover);
+		score = newMidScore - ffNode->nodeScore + newFfScore;
+		nGap = 0;
+		hGap -= overlap;
+		}
+	    else
+		{
+		score = midScore;
+		}
+	    score -= ffCalcGapPenalty(hGap, nGap, stringency);
+	    e->score = score;
+	    slAddHead(&midNode->waysIn, e);
+	    }
+	}
+    slReverse(&midNode->waysIn);
+    }
+return graph;
+}
+
+static struct ssNode *ssDynamicProgram(struct ssGraph *graph)
+/* Do dynamic programming to find optimal path though
+ * graph.  Return best ending node (with back-trace
+ * pointers and score set). */
+{
+int veryBestScore = -0x3fffffff;
+struct ssNode *veryBestNode = NULL;
+int nodeIx;
+
+for (nodeIx = 1; nodeIx <= graph->nodeCount; ++nodeIx)
+    {
+    int bestScore = -0x3fffffff;
+    int score;
+    struct ssEdge *bestEdge = NULL;
+    struct ssNode *curNode = &graph->nodes[nodeIx];
+    struct ssEdge *edge;
+
+    for (edge = curNode->waysIn; edge != NULL; edge = edge->next)
+	{
+	score = edge->score + edge->nodeIn->cumScore;
+	if (score > bestScore)
+	    {
+	    bestScore = score;
+	    bestEdge = edge;
+	    }
+	}
+    curNode->bestWayIn = bestEdge;
+    curNode->cumScore = bestScore;
+    if (bestScore >= veryBestScore)
+	{
+	veryBestScore = bestScore;
+	veryBestNode = curNode;
+	}
+    }
+return veryBestNode;
+}
+
+static void ssGraphFindBest(struct ssGraph *graph, struct ffAli **retBestAli, 
+   int *retScore, struct ffAli **retLeftovers)
+/* Traverse graph and put best alignment in retBestAli.  Return score.
+ * Put blocks not part of best alignment in retLeftovers. */
+{
+struct ssEdge *edge;
+struct ssNode *node;
+struct ssNode *startNode = &graph->nodes[0];
+struct ffAli *bestAli = NULL, *leftovers = NULL;
+struct ffAli *ff, *left = NULL;
+int i;
+int overlap, crossover, crossDif;
+
+/* Find best path and save score. */
+node = ssDynamicProgram(graph);
+*retScore = node->cumScore;
+
+/* Trace back and trim overlaps. */
+while (node != startNode)
+    {
+    ff = node->ff;
+    ff->right = bestAli;
+    bestAli = ff;
+    node->ff = NULL;
+    edge = node->bestWayIn;
+    if ((overlap = edge->overlap) > 0)
+	{
+	left = edge->nodeIn->ff;
+	crossover = edge->crossover;
+	crossDif = overlap-crossover;
+	left->hEnd -= crossDif;
+	left->nEnd -= crossDif;
+	ff->hStart += crossover;
+	ff->nStart += crossover;
+	}
+    node = node->bestWayIn->nodeIn;
+    }
+
+/* Make left links. */
+left = NULL;
+for (ff = bestAli; ff != NULL; ff = ff->right)
+    {
+    ff->left = left;
+    left = ff;
+    }
+
+/* Make leftover list. */
+for (i=1, node=graph->nodes+1; i<=graph->nodeCount; ++i,++node)
+    {
+    if ((ff = node->ff) != NULL)
+	{
+	ff->left = leftovers;
+	leftovers = ff;
+	}
+    }
+leftovers = ffMakeRightLinks(leftovers);
+
+*retBestAli = bestAli;
+*retLeftovers = leftovers;
+}
+
+static void ssFindBestSmall(struct ffAli *ffList, bioSeq *qSeq, bioSeq *tSeq,
+	enum ffStringency stringency, boolean isProt, struct trans3 *t3List,
+	struct ffAli **retBestAli, int *retScore, struct ffAli **retLeftovers)
+/* Build a graph and do a dynamic program on it to find best chains. 
+ * For small ffLists this is faster than the stuff in chainBlock. */
+{
+struct ssGraph *graph = ssGraphMake(ffList, qSeq, stringency, isProt, t3List);
+ssGraphFindBest(graph, retBestAli, retScore, retLeftovers);
+*retBestAli = forceMonotonic(*retBestAli, qSeq, tSeq, stringency, isProt, t3List);
+ssGraphFree(&graph);
+}
+
+
+
+static enum ffStringency ssStringency;
+static boolean ssIsProt;
+
+static int ssGapCost(int dq, int dt, void *data)
+/* Return gap penalty.  This just need be a lower bound on 
+ * the penalty actually. */
+{
+int cost;
+if (dt < 0) dt = 0;
+if (dq < 0) dq = 0;
+cost = ffCalcGapPenalty(dt, dq, ssStringency);
+return cost;
+}
+
+
+static int findOverlap(struct cBlock *a, struct cBlock *b)
+/* Figure out how much a and b overlap on either sequence. */
+{
+int dq = b->qStart - a->qEnd;
+int dt = b->tStart - a->tEnd;
+return -min(dq, dt);
+}
+
+static int ssConnectCost(struct cBlock *a, struct cBlock *b, void *data)
+/* Calculate connection cost - including gap score
+ * and overlap adjustments if any. */
+{
+struct ffAli *aFf = a->data, *bFf = b->data;
+int overlapAdjustment = 0;
+int overlap = findOverlap(a, b);
+int dq = b->qStart - a->qEnd;
+int dt = b->tStart - a->tEnd;
+
+if (overlap > 0)
+    {
+    int aSize = aFf->hEnd - aFf->hStart;
+    int bSize = bFf->hEnd - bFf->hStart;
+    if (overlap >= bSize || overlap >= aSize)
+	{
+	/* Give stiff overlap adjustment for case where
+	 * one block completely enclosed in the other on
+	 * either sequence. This will make it never happen. */
+	overlapAdjustment = a->score + b->score;
+	}
+    else
+        {
+	/* More normal case - partial overlap on one or both strands. */
+	int crossover = findCrossover(aFf, bFf, overlap, ssIsProt);
+	int remain = overlap - crossover;
+	overlapAdjustment =
+	    bioScoreMatch(ssIsProt, aFf->nEnd - remain, aFf->hEnd - remain, 
+	    	remain)
+	  + bioScoreMatch(ssIsProt, bFf->nStart, bFf->hStart, 
+	  	crossover);
+	dq -= overlap;
+	dt -= overlap;
+	}
+    }
+return overlapAdjustment + ssGapCost(dq, dt, data);
+}
+
+
+static void ssFindBestBig(struct ffAli *ffList, bioSeq *qSeq, bioSeq *tSeq,
+	enum ffStringency stringency, boolean isProt, struct trans3 *t3List,
+	struct ffAli **retBestAli, int *retScore, struct ffAli **retLeftovers)
+/* Go set up things to call chainBlocks to find best way to string together
+ * blocks in alignment. */
+{
+struct cBlock *boxList = NULL, *box, *prevBox;
+struct ffAli *ff, *farRight = NULL;
+struct lm *lm = lmInit(0);
+int boxSize;
+DNA *firstH = tSeq->dna;
+struct chain *chainList, *chain, *bestChain;
+int tMin = BIGNUM, tMax = -BIGNUM;
+
+
+/* Make up box list for chainer. */
+for (ff = ffList; ff != NULL; ff = ff->right)
+    {
+    lmAllocVar(lm, box);
+    boxSize = ff->nEnd - ff->nStart;
+    box->qStart = ff->nStart - qSeq->dna;
+    box->qEnd = box->qStart + boxSize;
+    if (t3List)
+        {
+	trans3Offsets(t3List, ff->hStart, ff->hEnd, &box->tStart, &box->tEnd);
+	}
+    else
+        {
+	box->tStart = ff->hStart - firstH;
+	box->tEnd = box->tStart + boxSize;
+	}
+    box->data = ff;
+    box->score = bioScoreMatch(isProt, ff->nStart, ff->hStart, boxSize);
+    if (tMin > box->tStart) tMin = box->tStart;
+    if (tMax < box->tEnd) tMax = box->tEnd;
+    slAddHead(&boxList, box);
+    }
+
+/* Adjust boxes so that tMin is always 0. */
+for (box = boxList; box != NULL; box = box->next)
+    {
+    box->tStart -= tMin;
+    box->tEnd -= tMin;
+    }
+tMax -= tMin;
+
+ssStringency = stringency;
+ssIsProt = isProt;
+chainList = chainBlocks(qSeq->name, qSeq->size, '+', "tSeq", tMax, &boxList,
+	ssConnectCost, ssGapCost, NULL, NULL);
+
+/* Fixup crossovers on best (first) chain. */
+bestChain = chainList;
+prevBox = bestChain->blockList;
+for (box = prevBox->next; box != NULL; box = box->next)
+    {
+    int overlap = findOverlap(prevBox, box);
+    if (overlap > 0)
+        {
+	struct ffAli *left = prevBox->data;
+	struct ffAli *right = box->data;
+	int crossover = findCrossover(left, right, overlap, isProt);
+        int remain = overlap - crossover;
+	left->nEnd -= remain;
+	left->hEnd -= remain;
+	right->nStart += crossover;
+	right->hStart += crossover;
+	}
+    prevBox = box;
+    }
+
+/* Copy stuff from first chain to bestAli. */
+farRight = NULL;
+for (box = chainList->blockList; box != NULL; box = box->next)
+    {
+    ff = box->data;
+    ff->left = farRight;
+    farRight = ff;
+    }
+*retBestAli = ffMakeRightLinks(farRight);
+
+/* Copy stuff from other chains to leftovers. */
+farRight = NULL;
+for (chain = chainList->next; chain != NULL; chain = chain->next)
+    {
+    for (box = chain->blockList; box != NULL; box = box->next)
+        {
+        ff = box->data;
+	ff->left = farRight;
+	farRight = ff;
+	}
+    }
+*retLeftovers = ffMakeRightLinks(farRight);
+
+*retScore = bestChain->score;
+for (chain = chainList; chain != NULL; chain = chain->next)
+    chain->blockList = NULL;	/* Don't want to free this, it's local. */
+chainFreeList(&chainList);
+lmCleanup(&lm);
+}
+
+static void ssFindBest(struct ffAli *ffList, bioSeq *qSeq, bioSeq *tSeq,
+	enum ffStringency stringency, boolean isProt, struct trans3 *t3List,
+	struct ffAli **retBestAli, int *retScore, struct ffAli **retLeftovers)
+/* String together blocks in alignment into chains. */
+{
+int count = ffAliCount(ffList);
+if (count >= 10)
+    {
+    ssFindBestBig(ffList, qSeq, tSeq, stringency, isProt, t3List,
+    	retBestAli, retScore, retLeftovers);
+    }
+else
+    {
+    ssFindBestSmall(ffList, qSeq, tSeq, stringency, isProt, t3List,
+    	retBestAli, retScore, retLeftovers);
+    }
+}
+
+struct ffAli *cutAtBigIntrons(struct ffAli *ffList, int maxIntron, 
+	int *pScore, enum ffStringency stringency,
+	struct ffAli **returnLeftovers)
+/* Return ffList up to the first intron that's too big.
+ * Put the rest of the blocks back onto the leftovers list. */
+{
+struct ffAli *prevFf, *ff, *cutFf = NULL;
+prevFf = ffList;
+for (ff = prevFf->right; ff != NULL; ff = ff->right)
+    {
+    int dt = ff->hStart - prevFf->hEnd;
+    if (dt > maxIntron)
+        {
+	cutFf = prevFf;
+	break;
+	}
+    prevFf = ff;
+    }
+if (cutFf != NULL)
+    {
+    ff = cutFf->right;
+    cutFf->right = NULL;
+    ff->left = NULL;
+    ffCat(returnLeftovers, &ff);
+    *pScore = ffScore(ffList, stringency);
+    }
+return ffList;
+}
+
+void ssStitch(struct ssBundle *bundle, enum ffStringency stringency, 
+	int minScore, int maxToReturn)
+/* Glue together mrnas in bundle as much as possible. Returns number of
+ * alignments after stitching. Updates bundle->ffList with stitched
+ * together version. */
+{
+struct dnaSeq *qSeq =  bundle->qSeq;
+struct dnaSeq *genoSeq = bundle->genoSeq;
+struct ffAli *ffList = NULL;
+struct ssFfItem *ffl;
+struct ffAli *bestPath;
+int score;
+boolean firstTime = TRUE;
+
+if (bundle->ffList == NULL)
+    return;
+
+/* The score may improve when we stitch together more alignments,
+ * so don't let minScore be too harsh at this stage. */
+if (minScore > 20)
+    minScore = 20;
+
+/* Create ffAlis for all in bundle and move to one big list. */
+for (ffl = bundle->ffList; ffl != NULL; ffl = ffl->next)
+    {
+    ffCat(&ffList, &ffl->ff);
+    }
+slFreeList(&bundle->ffList);
+
+ffAliSort(&ffList, ffCmpHitsNeedleFirst);
+ffList = ffMergeClose(ffList, qSeq->dna, genoSeq->dna);
+
+while (ffList != NULL)
+    {
+    ssFindBest(ffList, qSeq, genoSeq, stringency, 
+    	bundle->isProt, bundle->t3List,
+    	&bestPath, &score, &ffList);
+
+    bestPath = ffMergeNeedleAlis(bestPath, TRUE);
+    bestPath = ffRemoveEmptyAlis(bestPath, TRUE);
+    if (!bestPath)
+	{
+	ffFreeAli(&ffList);
+	break;
+	}
+    bestPath = ffMergeHayOverlaps(bestPath);
+    bestPath = ffRemoveEmptyAlis(bestPath, TRUE);
+    bestPath = forceMonotonic(bestPath, qSeq, genoSeq, stringency,
+    	bundle->isProt, bundle->t3List);
+
+    if (firstTime && stringency == ffCdna && bundle->avoidFuzzyFindKludge == FALSE)
+	{
+	/* Only look for middle exons the first time.  Next times
+	 * this might regenerate most of the first alignment... */
+	bestPath = smallMiddleExons(bestPath, bundle, stringency);
+	}
+    bestPath = ffMergeNeedleAlis(bestPath, TRUE);
+    if (ffIntronMax != ffIntronMaxDefault)
+	{
+	bestPath = cutAtBigIntrons(bestPath, ffIntronMax, &score, stringency,
+		&ffList);
+	}
+    if (!bundle->isProt)
+	ffSlideIntrons(bestPath);
+    bestPath = ffRemoveEmptyAlis(bestPath, TRUE);
+    if (score >= minScore)
+	{
+	AllocVar(ffl);
+	ffl->ff = bestPath;
+	slAddHead(&bundle->ffList, ffl);
+	}
+    else
+	{
+	ffFreeAli(&bestPath);
+	ffFreeAli(&ffList);
+	break;
+	}
+    firstTime = FALSE;
+    if (--maxToReturn <= 0)
+	{
+	ffFreeAli(&ffList);
+	break;
+	}
+    }
+slReverse(&bundle->ffList);
+return;
+}
+
+static struct ssBundle *findBundle(struct ssBundle *list,  
+	struct dnaSeq *genoSeq)
+/* Find bundle in list that has matching genoSeq pointer, or NULL
+ * if none such.  This routine is used by psLayout but not blat. */
+{
+struct ssBundle *el;
+for (el = list; el != NULL; el = el->next)
+    if (el->genoSeq == genoSeq)
+	return el;
+return NULL;
+}
+
+struct ssBundle *ssFindBundles(struct patSpace *ps, struct dnaSeq *cSeq, 
+	char *cName, enum ffStringency stringency, boolean avoidSelfSelf)
+/* Find patSpace alignments.  This routine is used by psLayout but not blat. */
+{
+struct patClump *clumpList, *clump;
+struct ssBundle *bundleList = NULL, *bun = NULL;
+DNA *cdna = cSeq->dna;
+int totalCdnaSize = cSeq->size;
+DNA *endCdna = cdna+totalCdnaSize;
+struct ssFfItem *ffl;
+struct dnaSeq *lastSeq = NULL;
+int maxSize = 700;
+int preferredSize = 500;
+int overlapSize = 250;
+
+for (;;)
+    {
+    int cSize = endCdna - cdna;
+    if (cSize > maxSize)
+	cSize = preferredSize;
+    clumpList = patSpaceFindOne(ps, cdna, cSize);
+    for (clump = clumpList; clump != NULL; clump = clump->next)
+	{
+	struct ffAli *ff;
+	struct dnaSeq *seq = clump->seq;
+	DNA *tStart = seq->dna + clump->start;
+	if (!avoidSelfSelf || !sameString(seq->name, cSeq->name))
+	    {
+	    ff = ffFind(cdna, cdna+cSize, tStart, tStart + clump->size, stringency);
+	    if (ff != NULL)
+		{
+		if (lastSeq != seq)
+		    {
+		    lastSeq = seq;
+		    if ((bun = findBundle(bundleList, seq)) == NULL)
+			{
+			AllocVar(bun);
+			bun->qSeq = cSeq;
+			bun->genoSeq = seq;
+			bun->genoIx = clump->bacIx;
+			bun->genoContigIx = clump->seqIx;
+			slAddHead(&bundleList, bun);
+			}
+		    }
+		AllocVar(ffl);
+		ffl->ff = ff;
+		slAddHead(&bun->ffList, ffl);
+		}
+	    }
+	}
+    cdna += cSize;
+    if (cdna >= endCdna)
+	break;
+    cdna -= overlapSize;
+    slFreeList(&clumpList);
+    }
+slReverse(&bundleList);
+cdna = cSeq->dna;
+
+for (bun = bundleList; bun != NULL; bun = bun->next)
+    {
+    ssStitch(bun, stringency, 20, 16);
+    }
+return bundleList;
+}
+
diff --git a/jkOwnLib/tests/freen/freen.c b/jkOwnLib/tests/freen/freen.c
new file mode 100644
index 0000000..3202da6
--- /dev/null
+++ b/jkOwnLib/tests/freen/freen.c
@@ -0,0 +1,115 @@
+/* freen - My Pet Freen. */
+#include "common.h"
+#include "memalloc.h"
+#include "linefile.h"
+#include "hash.h"
+#include "options.h"
+#include "axt.h"
+
+
+void usage()
+/* Print usage and exit. */
+{
+errAbort("usage: freen something");
+}
+
+int xenAlignAffine(char *query, int querySize, char *target, int targetSize, 
+	struct axtScoreScheme *ss, FILE *f, boolean printExtraAtEnds);
+/* Use dynamic programming to do protein/protein alignment. */
+
+
+void freen(char *out)
+/* Test some hair-brained thing. */
+{
+char *a = "CVMVFTVSCSKMSSIVDRDDSSIFDGLVEEDDKDKAKRVSRNKSEKKRRDQFNVLIKELG"
+"SMLPGNARKMDKSTVLQKSIDFLRKHKETTAQSDASEIRQDWKPTFLSNEEFTQLMLEAL"
+"DGFFLAIMTDGSIIYVSESVTSLLEHLPSDLVDQSIFNFIPEGEHSEVYKILSTHLLESD"
+"SLTPEYLKSKNQLEFCCHMLRGTIDPKEPSTYEYVRFIGNFKSLTSVSTSTHNGFEGTIQ"
+"RTHRPSYEDRVCFVATVRLATPQFIKEMCTVEEPNEEFTSRHSLEWKFLFLDHRAPPIIG"
+"YLPFEVLGTSGYDYYHVDDLENLAKCHEHLMQYGKGKSCYYRFLTKGQQWIWLQTHYYIT"
+"YHQWNSRPEFIVCTHTVVSYAEVRAERRRELGIEESLPETAADKSQDSGSDNRINTVSLK"
+"EALERFDHSPTPSASSRSSRKSSHTAVSDPSSTPTKIPTDTSTPPRQHLPAHEKMTQRRS"
+"SFSSQSINSQSVGPSLTQPAMSQAANLPIPQGMSQFQFSAQLGAMQHLKDQLEQRTRMIE"
+"ANIHRQQEELRKIQEQLQMVHGQGLQMFLQQSNPGLNFGSVQLSSGNSNIQQLTPVNMQG"
+"QVVPANQVQSGHISTGQHMIQQQTLQSTSTQQSQQSVMSGHSQQTSLPSQTPSTLTAPLY"
+"NTMVISQPAAGSMVQIPSSMPQNSTQSATVTTFTQDRQIRFSQGQQLVTKLVTAPVACGA"
+"VMVPSTMLMGQVVTAYPTFATQQQQAQTLSVTQQQQQQQQQPPQQQQQQQQSSQEQQLPS"
+"VQQPAQAQLGQPPQQFLQTSRLLHGNPSTQLILSAAFPLQQSTFPPSHHQQHQPQQQQQL"
+"PRHRTDSLTDPSKVQPQ";
+char *b = "CVMVFTVSCSKMSSIVDRDDSSIFDGLVEEDDKDKAKRVSRNKSEKKRRDQFNVLIKELG"
+"SMLPGNARKMDKSTVLQKSIDFLRKHKETTAQSDASEIRQDWKPTFLSNEEFTQLMLEAL"
+"DGFFLAIMTDGSIIYVSESVTSLLEHLPSDLVDQSIFNFIPEGEHSEVYKILSTHLLESD"
+"SLTPEYLKSKNQLEFCCHMLRGTIDPKEPSTYEYVRFIGNFKSLTSVSTSTHNGFEGTIQ"
+"RTHRPSYEDRVCFVATVRLATPQFIKEMCTVEEPNEEFTSRHSLEWKFLFLDHRAPPIIG"
+"xQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
+"YHQWNSRPEFIVCTHTVVSYAEVRAERRRELGIEESLPETAADKSQDSGSDNRINTVSLK"
+"EALERFDHSPTPSASSRSSRKSSHTAVSDPSSTPTKIPTDTSTPPRQHLPAHEKMTQRRS"
+"SFSSQSINSQSVGPSLTQPAMSQAANLPIPQGMSQFQFSAQLGAMQHLKDQLEQRTRMIE"
+"ANIHRQQEELRKIQEQLQMVHGQGLQMFLQQSNPGLNFGSVQLSSGNSNIQQLTPVNMQG"
+"QVVPANQVQSGHISTGQHMIQQQTLQSTSTQQSQQSVMSGHSQQTSLPSQTPSTLTAPLY"
+"NTMVISQPAAGSMVQIPSSMPQNSTQSATVTTFTQDRQIRFSQGQQLVTKLVTAPVACGA"
+"VMVPSTMLMGQVVTAYPTFATQQQQAQTLSVTQQQQQQQQQPPQQQQQQQQSSQEQQLPS"
+"VQQPAQAQLGQPPQQFLQTSRLLHGNPSTQLILSAAFPLQQSTFPPSHHQQHQPQQQQQL"
+"PRHRTDSLTDPSKVQPQ";
+char *c = "CVMVFTVSCSKMSSIVDRDDSSIFDGLVEEDDKDKAKRVSRNKSEKKRRDQFNVLIKELG"
+"xMLPGNARKMDKSTVLQKSIDFLRKHKETTAQSDASEIRQDWKPTFLSNEEFTQLMLEAL"
+"xxFFLAIMTDGSIIYVSESVTSLLEHLPSDLVDQSIFNFIPEGEHSEVYKILSTHLLESD"
+"xxxPEYLKSKNQLEFCCHMLRGTIDPKEPSTYEYVRFIGNFKSLTSVSTSTHNGFEGTIQ"
+"xxxxPSYEDRVCFVATVRLATPQFIKEMCTVEEPNEEFTSRHSLEWKFLFLDHRAPPIIG"
+"xxxxxVLGTSGYDYYHVDDLENLAKCHEHLMQYGKGKSCYYRFLTKGQQWIWLQTHYYIT"
+"xxxxxxRPEFIVCTHTVVSYAEVRAERRRELGIEESLPETAADKSQDSGSDNRINTVSLK"
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+"xxxxxxxxSQSVGPSLTQPAMSQAANLPIPQGMSQFQFSAQLGAMQHLKDQLEQRTRMIE"
+"xxxxxxxxxLRKIQEQLQMVHGQGLQMFLQQSNPGLNFGSVQLSSGNSNIQQLTPVNMQG"
+"xxxxxxxxxxGHISTGQHMIQQQTLQSTSTQQSQQSVMSGHSQQTSLPSQTPSTLTAPLY"
+"xxxxxxxxxxxSMVQIPSSMPQNSTQSATVTTFTQDRQIRFSQGQQLVTKLVTAPVACGA"
+"xxxxxxxxxxxxVTAYPTFATQQQQAQTLSVTQQQQQQQQQPPQQQQQQQQSSQEQQLPS"
+"xxxxxxxxxxxxxQQFLQTSRLLHGNPSTQLILSAAFPLQQSTFPPSHHQQHQPQQQQQL"
+"PRHRTDSLTDPSKVQPQ";
+char *d = "CVMVFTVSCSKMSSIVDRDDSSIFDGLVEEDDKDKAKRVSRNKSEKKRRDQFNVLIKELG"
+"SMLPGNARKMDKSTVLQKSIDFLRKHKETTAQSDASEIRQDWKPTFLSNEEFTQLMLEAL"
+"DGFFLAIMTDGSIIYVSESVTSLLEHLPSDLVDQSIFNFIPEGEHSEVYKILSTHLLESD"
+"SLTPEYLKSKNQLEFCCHMLRGTIDPKEPSTYEYVRFIGNFKSLTSVSTSTHNGFEGTIQ"
+"RTHRPSYEDRVCFVATVRLATPQFIKEMCTVEEPNEEFTSRHSLEWKFLFLDHRAPPIIG"
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+"YHQWNSRPEFIVCTHTVVSYAEVRAERRRELGIEESLPETAADKSQDSGSDNRINTVSLK"
+"EALERFDHSPTPSASSRSSRKSSHTAVSDPSSTPTKIPTDTSTPPRQHLPAHEKMTQRRS"
+"SFSSQSINSQSVGPSLTQPAMSQAANLPIPQGMSQFQFSAQLGAMQHLKDQLEQRTRMIE"
+"ANIHRQQEELRKIQEQLQMVHGQGLQMFLQQSNPGLNFGSVQLSSGNSNIQQLTPVNMQG"
+"QVVPANQVQSGHISTGQHMIQQQTLQSTSTQQSQQSVMSGHSQQTSLPSQTPSTLTAPLY"
+"NTMVISQPAAGSMVQIPSSMPQNSTQSATVTTFTQDRQIRFSQGQQLVTKLVTAPVACGA"
+"VMVPSTMLMGQVVTAYPTFATQQQQAQTLSVTQQQQQQQQQPPQQQQQQQQSSQEQQLPS"
+"VQQPAQAQLGQPPQQFLQTSRLLHGNPSTQLILSAAFPLQQSTFPPSHHQQHQPQQQQQL"
+"PRHRTDSLTDPSKVQPQ";
+char *e = "CVMVFTVSCSKMSSIVDRDDSSIFDGLVEEDDKDKAKRVSRNKSEKKRRDQFNVLIKELG"
+"XXXXXXXXXXXXXXXXXXXXXXXXXHKETTAQSDASEIRQDWKPTFLSNEEFTQLMLEAL"
+"XXXXXXXXXXXXXXXXXXXXXXXXEHLPSDLVDQSIFNFIPEGEHSEVYKILSTHLLESD"
+"XXXXXXXXXXXXXXXXXXXXXXXIDPKEPSTYEYVRFIGNFKSLTSVSTSTHNGFEGTIQ"
+"XXXXXXXXXXXXXXXXXXXXXXQFIKEMCTVEEPNEEFTSRHSLEWKFLFLDHRAPPIIG"
+"XXXXXVXXXXXXXXXXXXXXXNLAKCHEHLMQYGKGKSCYYRFLTKGQQWIWLQTHYYIT"
+"XXXXXXXXXXXXXXXXXXXXAEVRAERRRELGIEESLPETAADKSQDSGSDNRINTVSLK"
+"XXXXXXXXXXXXXXXXXXXRKSSHTAVSDPSSTPTKIPTDTSTPPRQHLPAHEKMTQRRS"
+"XXXXXXXXXXXXXXXXXXPAMSQAANLPIPQGMSQFQFSAQLGAMQHLKDQLEQRTRMIE"
+"XXXXXXXXXXXXXXXXXQMVHGQGLQMFLQQSNPGLNFGSVQLSSGNSNIQQLTPVNMQG"
+"XXXXXXXXXXXXXXXXQHMIQQQTLQSTSTQQSQQSVMSGHSQQTSLPSQTPSTLTAPLY"
+"XXXXXXXXXXXXXXXIPSSMPQNSTQSATVTTFTQDRQIRFSQGQQLVTKLVTAPVACGA"
+"XXXXXXXXXXXXXXAYPTFATQQQQAQTLSVTQQQQQQQQQPPQQQQQQQQSSQEQQLPS"
+"XXXXXXXXXXXXXQQFLQTSRLLHGNPSTQLILSAAFPLQQSTFPPSHHQQHQPQQQQQL"
+"PRHRTDSLTDPSKVQPQ";
+a = cloneString(a);
+// tolowers(a);
+b = cloneString(b);
+// tolowers(b);
+xenAlignAffine(a, strlen(a), b, strlen(b), axtScoreSchemeProteinDefault(), stdout, FALSE);
+}
+
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+pushCarefulMemHandler(100000000);
+if (argc != 2)
+   usage();
+freen(argv[1]);
+return 0;
+}
diff --git a/jkOwnLib/tests/freen/makefile b/jkOwnLib/tests/freen/makefile
new file mode 100644
index 0000000..a69961f
--- /dev/null
+++ b/jkOwnLib/tests/freen/makefile
@@ -0,0 +1,13 @@
+include ../../../inc/common.mk
+
+L += $(MYSQLLIBS) -lm
+MYLIBDIR = ../../../lib/$(MACHTYPE)
+MYLIBS =  $(MYLIBDIR)/jkOwnLib.a $(MYLIBDIR)/jkweb.a
+
+O = freen.o
+
+hello: freen.o
+	${CC} ${COPT} ${CFLAGS} -o ${BINDIR}/freen $O $(MYLIBS) $L
+
+clean::
+	rm -f ${O}
diff --git a/jkOwnLib/trans3.c b/jkOwnLib/trans3.c
new file mode 100644
index 0000000..6949317
--- /dev/null
+++ b/jkOwnLib/trans3.c
@@ -0,0 +1,133 @@
+/* trans3 - a sequence and three translated reading frames. */
+/* Copyright 2000-2003 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "dnaseq.h"
+#include "trans3.h"
+
+
+struct trans3 *trans3New(struct dnaSeq *seq)
+/* Create a new set of translated sequences. */
+{
+struct trans3 *t3;
+int frame;
+int lastPos = seq->size - 1;
+
+AllocVar(t3);
+t3->name = seq->name;
+t3->seq = seq;
+t3->end = seq->size;
+for (frame=0; frame<3; ++frame)
+    {
+    /* Position and frame are the same except in the
+     * very rare case where we are trying to translate 
+     * something less than 3 bases.  In this case this
+     * somewhat cryptic construction will force it to
+     * return empty sequences for the missing frames
+     * avoiding an assert in translateSeq. */
+    int pos = frame;
+    if (pos > lastPos) pos = lastPos;
+    t3->trans[frame] = translateSeq(seq, pos, FALSE);
+    }
+return t3;
+}
+
+void trans3Free(struct trans3 **pT3)
+/* Free a trans3 structure. */
+{
+struct trans3 *t3 = *pT3;
+if (t3 != NULL)
+    {
+    freeDnaSeq(&t3->trans[0]);
+    freeDnaSeq(&t3->trans[1]);
+    freeDnaSeq(&t3->trans[2]);
+    freez(pT3);
+    }
+}
+
+void trans3FreeList(struct trans3 **pList)
+/* Free a list of dynamically allocated trans3's */
+{
+struct trans3 *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    trans3Free(&el);
+    }
+*pList = NULL;
+}
+
+struct trans3 *trans3Find(struct hash *t3Hash, char *name, int start, int end)
+/* Find trans3 in hash which corresponds to sequence of given name and includes
+ * bases between start and end. */
+{
+struct trans3 *t3;
+for (t3 = hashFindVal(t3Hash, name); t3 != NULL; t3 = t3->next)
+    {
+    if (t3->start <= start && t3->end >= end)
+        return t3;
+    }
+internalErr();
+return NULL;
+}
+
+void trans3Offset(struct trans3 *t3List, AA *aa, int *retOffset, int *retFrame)
+/* Figure out offset of peptide in context of larger sequences. */
+{
+struct trans3 *t3;
+int frame;
+aaSeq *seq;
+
+for (t3 = t3List; t3 != NULL; t3 = t3->next)
+    {
+    for (frame = 0; frame < 3; ++frame)
+        {
+	seq = t3->trans[frame];
+	if (seq->dna <= aa && aa < seq->dna + seq->size)
+	    {
+	    *retOffset = aa - seq->dna + t3->start/3;
+	    *retFrame = frame;
+	    return;
+	    }
+	}
+    }
+internalErr();
+}
+
+int trans3GenoPos(char *pt, bioSeq *seq, struct trans3 *t3List, boolean isEnd)
+/* Convert from position in one of three translated frames in
+ * t3List to genomic offset. If t3List is NULL then just use seq
+ * instead. */
+{
+int offset, frame;
+if (t3List != NULL)
+    {
+    /* Special processing at end. The end coordinate is
+     * not included.  In most cases this makes things
+     * easier.  Here we have to move it back one
+     * amino acid, so that in the edge case it will
+     * be included in the block that's loaded.  Then
+     * we move it back. */
+    if (isEnd)
+        pt -= 1;
+    trans3Offset(t3List, pt, &offset, &frame);
+    if (isEnd)
+        offset += 1;
+    return 3*offset + frame;
+    }
+else
+   {
+   return pt - seq->dna;
+   }
+}
+
+int trans3Frame(char *pt, struct trans3 *t3List)
+/* Figure out which frame pt is in or 0 if no frame. */
+{
+if (t3List == NULL)
+    return 0;
+else
+    return 1 + trans3GenoPos(pt, NULL, t3List, FALSE)%3;
+}
+
diff --git a/jkOwnLib/version.doc b/jkOwnLib/version.doc
new file mode 100644
index 0000000..2627761
--- /dev/null
+++ b/jkOwnLib/version.doc
@@ -0,0 +1,54 @@
+1 - bandExt.c tested.  blat directs alignment to new routines with -band flag.
+    Main new routine is gfSeedExtInMem in ffSeedExtend.c
+2 - Added new gfFindHitsInRegion to genoFind.c.  Calling this in refineFf
+    when start of qSeq and tSeq not aligning to get single tiled >=11mer hits. 
+3 - Adding tiled >=11mer hits in middle and end as well.
+4 - Adding search for sliding 8-mer seeds and also perfect matches plus
+    splice sites for small exons to find bits not aligning.
+5 - Fixed crash bug from trying to ffMergeClose empty lists.
+6 - Bumped sliding seed size to 11.  Implementing dynamic-programming
+    splice finder that weighs both splice consensus and matches/mismatches
+    in area.
+7 - It successfully aligns all refSeq that map to 22 to 22.  It shows
+    339 'perfect' alignments rather than 331 in old version.  It is
+    still quite a bit (10x) slower than old way,  seemingly concentrated
+    mostly on some specific sequences.
+8 - A little faster from making gfFindInRegion actually filter out
+    ones out of region.  Still slow though.  Up to 340 perfect.
+9 - Up to 341 perfect.  Still a bug in the exact scanning thing.
+10 - Up to 344 perfect.  Running in 25s vs. 36 for old version. (Fixed
+     exact scanning problem with polyA tails).
+11 - Tested on mrna.33 vs. human genome.  Fixed a couple of crash bugs
+     that emerged in the splice site hard cleanup.  On this larger set
+     it appears to be a bit slower than the older blat. Looks like down
+     to 342 perfect on chr22 test set (but 329 in old version, looks
+     like a change in pslPretty).
+12 - Attempt to fill small double-gaps with global banded aligner.  Up
+     to 346 perfect.  Put in a stringent gapless aligner right after initial 
+     seeding.  Up to 347 perfect.  Run time 20s.
+13 - Fixed bug where degenerate 11-mer seeds not filtered out of
+     look for tiny exons phase.  Time slightly improved.  Alignments of
+     NM_017424 improved (but not perfect because of sequencing error.)
+     Clamped exact search size to intronMax (750k) as intended.  In
+     case of looking for 12-15-mer it would exceed this before.  
+     No longer adding splice sites to exact match.  This caused as
+     many problems as it solves because the exon may include some
+     bleed-over at the point where it is called.  Still 347
+     perfect.  Run time 17s.
+14 - Tested all ESTs against build31.  Fixed one crash bug that came
+     up.   The EST time is 412 CPU hours vs. 282 for the unbanded.
+     Longest job is 5.17 hours vs. 1.57.
+15 - Reorganized code so that it there is not so much crossover between
+     modules working with ffAlis.  Removed last use of fuzzyFind in 
+     the -band case.  Put in search for tiny internal exact matches
+     that requires less perfect matches.
+16 - Changing supStitch so that it stops when getting less than minScore
+     as well as after specified number of iterations.  Making ffSeedExtend
+     initially call supStitch with 8 rather than 1 iteration.  This fixes
+     a missed exon on a case in chr19 with a very tricky tandem repeat.
+     Further bumped up supStitch call to 16, and allowing more extension,
+     even including some overlap to help in another case Yontao found.
+     Still perfect 347 matches on 22.   Run time 20s.
+17 - Having it trim ends that look suspicious.  It looks now like 
+     this new system works well for mRNAs, but it still is not optimal
+     for ESTs.  This is released as blat.21
diff --git a/jkOwnLib/xenbig.c b/jkOwnLib/xenbig.c
new file mode 100644
index 0000000..9798c72
--- /dev/null
+++ b/jkOwnLib/xenbig.c
@@ -0,0 +1,1223 @@
+/* xenbig.c - Routines to do big xeno alignments by breaking them into
+ * pieces, calling the small aligner, and then stitching them back
+ * together again. */
+/* Copyright 2000-2003 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "dlist.h"
+#include "hash.h"
+#include "portable.h"
+#include "dnautil.h"
+#include "nt4.h"
+#include "crudeali.h"
+#include "wormdna.h"
+#include "xenalign.h"
+
+
+struct contig
+/* A contiguously aligned sequence pair. */
+    {
+    char *name;
+    char *queryFile;
+    char *query;
+    int qStart, qEnd;
+    int qOffset, qEndOffset;
+    char qStrand;
+    char *target;
+    int tStart, tEnd;
+    int tOffset, tEndOffset;
+    char tStrand;
+    int score;
+    char *qSym;     /* Query symbols (nucleotides and insert char) */
+    char *tSym;     /* Target symbols (nucleotides and insert char) */
+    char *hSym;     /* "Hidden" state symbols. */
+    int symCount;
+    boolean isComplete;
+    };
+
+static void freeContig(struct contig **pContig)
+/* Free up a contig. */
+{
+struct contig *contig = *pContig;
+if (contig != NULL)
+    {
+    freeMem(contig->name);
+    freeMem(contig->target);
+    freeMem(contig->qSym);
+    freeMem(contig->tSym);
+    freeMem(contig->hSym);
+    freez(pContig);
+    }
+}
+
+static void freeContigList(struct dlList **pContigList)
+/* Free up list of contigs. */
+{
+struct dlNode *node;
+struct contig *contig;
+
+for (node = (*pContigList)->head; node->next != NULL; node = node->next)
+    {
+    contig = node->val;
+    freeContig(&contig);
+    }
+freeDlList(pContigList);
+}
+
+static void checkComplete(struct dlList *contigList)
+/* Make sure all the contigs on the list are complete. */
+{
+struct dlNode *node;
+struct contig *contig;
+
+for (node = contigList->head; node->next != NULL; node = node->next)
+    {
+    contig = node->val;
+    if (!contig->isComplete)
+        {
+        errAbort("Contig %s:%d-%d %c %s:%d-%d %c isn't complete",
+            contig->query, contig->qStart, contig->qEnd, contig->qStrand,
+            contig->target, contig->tStart, contig->tEnd, contig->tStrand);
+        }
+    }
+}
+
+static int cmpContigQueryStart(const void *va, const void *vb)
+/* Compare two contigs by start position and then by inverse
+ * stop position. (This ensures that if one contig completely
+ * encompasses another it will appear on list first.) */
+{
+struct contig **pA = (struct contig **)va;
+struct contig **pB = (struct contig **)vb;
+struct contig *a = *pA, *b = *pB;
+int dif;
+
+dif = a->qStart - b->qStart;
+if (dif == 0)
+   //dif = a->tStart - b->tStart;
+   dif = b->qEnd - a->qEnd;
+return dif;
+}
+
+static void writeContig(struct contig *contig, FILE *out, 
+	boolean compactOutput, boolean newFormat)
+/* Write out one contig to file */
+{
+int i;
+int size = contig->symCount;
+#define maxLineSize 50
+char buf[maxLineSize+1];
+int lineSize;
+int j;
+int qIx = 0, tIx = 0;
+char *qSyms = contig->qSym;
+char *tSyms = contig->tSym;
+
+if (newFormat)
+    {
+    fprintf(out, "%s align %d.%d%% of %d %s %s:%d-%d %c %s:%d-%d %c\n",
+	contig->name, contig->score/10, contig->score%10, size, 
+	contig->queryFile, contig->query, contig->qStart, contig->qEnd, contig->qStrand,
+	contig->target, contig->tStart, contig->tEnd, contig->tStrand);
+    }
+else
+    {
+    fprintf(out, "%s align %d.%d%% of %d %s:%d-%d %c %s:%d-%d %c\n",
+	contig->name, contig->score/10, contig->score%10, size, 
+	contig->query, contig->qStart, contig->qEnd, contig->qStrand,
+	contig->target, contig->tStart, contig->tEnd, contig->tStrand);
+    }
+if (compactOutput)
+    {
+    mustWrite(out, contig->qSym, size);
+    fputc('\n', out);
+    mustWrite(out, contig->tSym, size);
+    fputc('\n', out);
+    mustWrite(out, contig->hSym, size);
+    fputc('\n', out);
+    }
+else
+    {
+    for (i=0; i<size; i += lineSize)
+        {
+        /* Figure out how long this line is going to be. */
+        lineSize = size - i;
+        if (lineSize > maxLineSize)
+            lineSize = maxLineSize;
+        buf[lineSize] = 0;
+    
+        /* Print query symbols */
+        memcpy(buf, contig->qSym + i, lineSize);
+        fprintf(out, "%5d %s\n", qIx, buf);
+
+        /* Print matching symbols */
+        fprintf(out, "%5s ", "");
+        for (j=0; j<lineSize; ++j)
+            {
+            int off = j+i;
+            char q = qSyms[off];
+            char t = tSyms[off];
+            char c = (q == t ? '|' : ' ');
+            fputc(c, out);
+            }
+        fputc('\n', out);
+
+        /* Print target symbols */
+        memcpy(buf, contig->tSym + i, lineSize);
+        fprintf(out, "%5d %s\n", tIx, buf);
+
+        /* Print hidden symbols */
+        memcpy(buf, contig->hSym + i, lineSize);
+        fprintf(out, "%5s %s\n", "", buf);
+
+        /* Figure out how far we have advanced */
+        for (j=0; j<lineSize; ++j)
+            {
+            int off = j+i;
+            char q = qSyms[off];
+            char t = tSyms[off];
+            if (q != '-')
+                ++qIx;
+            if (t != '-')
+                ++tIx;
+            }
+        /* Print blank line */
+        fputc('\n', out);
+        }
+    }
+#undef lineSize
+}
+
+struct cluster
+/* A set of compatable contigs - one that might eventually be merged. */
+    {
+    struct dlList *contigs;
+    char *query;
+    int qStart, qEnd;
+    int qOffset, qEndOffset;
+    char qStrand;
+    char *target;
+    int tStart, tEnd;
+    int tOffset, tEndOffset;
+    char tStrand;
+    int score;
+    };
+
+#ifdef UNUSED
+static int cmpCluster(const void *va, const void *vb)
+/* Compare two clusters. */
+{
+struct cluster **pA = (struct cluster **)va;
+struct cluster **pB = (struct cluster **)vb;
+struct cluster *a = *pA, *b = *pB;
+
+return b->score - a->score;
+}
+#endif /* UNUSED */
+
+static boolean contigsOverlap(struct contig *a, struct contig *b, 
+    int *retQueryOverlap, int *retTargetOverlap)
+/* Returns TRUE is contigs overlap. */
+{
+int overlap;
+int start, end;
+
+/* Check overlap in query. */
+start = max(a->qStart, b->qStart);
+end = min(a->qEnd, b->qEnd);
+overlap = end - start;
+if (overlap > 0)
+    *retQueryOverlap = overlap;
+else
+    return FALSE;
+
+/* Check overlap in target. */
+start = max(a->tStart, b->tStart);
+end = min(a->tEnd, b->tEnd);
+overlap = end - start;
+if (overlap > 0)
+    *retTargetOverlap = overlap;
+else
+    return FALSE;
+return TRUE;
+}
+
+static int findSymIx(char *qSym, int qIx, int *retSymIx)
+/* Convert from query to symbol index, dealing with insert chars. */
+{
+char q;
+int symIx;
+int qCount = 0;
+
+for (symIx = 0; ; ++symIx)
+    {
+    if (qCount == qIx)
+        {
+        *retSymIx = symIx;
+        return TRUE;
+        }
+    if ((q = *qSym++) == 0)
+        {
+        warn("findSymIx gone past end");
+        return FALSE;
+        }
+    if (q != '-')
+        ++qCount;
+    }
+}
+
+static boolean mergeIntoAdjacentClusters(struct dlList *clusterList, struct dlNode *contigNode)
+/* If can merge contig into cluster list, do it and return TRUE.
+ * else return FALSE. */
+{
+struct contig *contig = contigNode->val;  /* The contig we're trying to fold in. */
+struct dlNode *clusterNode;               /* Node of a single cluster. */
+struct cluster *cluster;                  /* A cluster. */
+
+for (clusterNode = clusterList->head; clusterNode->next != NULL; clusterNode = clusterNode->next)
+    {
+    cluster = clusterNode->val;
+    if ((contig->qOffset == cluster->qEndOffset - 1000 ||
+        (contig->qEndOffset == cluster->qEndOffset &&
+         contig->tEndOffset == cluster->tEndOffset)) &&
+        contig->qStrand == cluster->qStrand &&
+        contig->tStrand == cluster->tStrand &&
+        sameString(contig->target, cluster->target) &&
+        sameString(contig->query, cluster->query))
+        {
+        if (contig->qStrand == contig->tStrand)
+            {
+            if (contig->tOffset < cluster->tEndOffset + 50000
+                && contig->tOffset >= cluster->tOffset-300)
+                {
+                cluster->qEndOffset = contig->qEndOffset;
+                cluster->tEndOffset = contig->tEndOffset;
+                cluster->score += contig->score;
+                dlAddTail(cluster->contigs, contigNode);
+                return TRUE;
+                }
+            }
+        else
+            {
+            if ( contig->tEndOffset > cluster->tOffset - 50000
+                && contig->tEndOffset <= cluster->tEndOffset+300)
+                {
+                cluster->qEndOffset = contig->qEndOffset;
+                cluster->tOffset = contig->tOffset;
+                cluster->score += contig->score;
+                dlAddTail(cluster->contigs, contigNode);
+                return TRUE;
+                }
+            }
+        }
+    }
+return FALSE;
+}
+
+static void maxAlignedOverlap(char *a1, char *a2, char *b1, char *b2, int size,
+    int *retStart, int *retOverlapSize)
+/* Find maximum overlap between a and b without shifting a or
+ * b. */
+{
+int maxStart = -1;
+int maxLen = -1;
+int curStart = 0;
+int curLen = 0;
+int i;
+
+for (i=0; i<size; ++i)
+    {
+    if (a1[i] == b1[i] && a2[i] == b2[i])
+        {
+        curLen += 1;
+        if (curLen > maxLen)
+            {
+            maxLen = curLen;
+            maxStart = curStart;
+            }
+        }
+    else
+        {
+        curLen = 0;
+        curStart = i+1;
+        }
+    }
+*retStart = maxStart;
+*retOverlapSize = maxLen;
+}
+    
+static void findMaxOverlap(char *a1, char *a2, int aSize, 
+    char *b1, char *b2, int bSize,
+    int *retAstart, int *retBstart, int *retOverlapSize)
+/* Find maximum overlap between a and b and return it. */
+{
+int i;
+int maxOverlap = -1;
+int maxAstart = 0;
+int maxBstart = 0;
+int overlap;
+int minSize = min(aSize, bSize);
+int goodEnough = minSize-1;
+int start;
+
+for (i=0; i<bSize; ++i)
+    {
+    int size = bSize-i;
+    if (size > aSize)
+        size = aSize;
+    maxAlignedOverlap(a1, a2, b1+i, b2+i, size, &start, &overlap);
+    if (overlap > maxOverlap)
+        {
+        maxOverlap = overlap;
+        maxAstart = start;
+        maxBstart = i+start;
+        if (maxOverlap >= goodEnough)
+            goto RETURN_VALS;
+        }
+    }
+for (i=1; i<aSize; ++i)
+    {
+    int size = aSize-i;
+    if (size > bSize)
+        size = bSize;
+    maxAlignedOverlap(a1+i, a2+i, b1, b2, size, &start, &overlap);
+    if (overlap > maxOverlap)
+        {
+        maxOverlap = overlap;
+        maxAstart = i+start;
+        maxBstart = start;
+        if (maxOverlap >= goodEnough)
+            goto RETURN_VALS;
+        }
+    }
+RETURN_VALS:
+    {
+    *retAstart = maxAstart;
+    *retBstart = maxBstart;
+    *retOverlapSize = maxOverlap;
+    }
+}
+
+static struct contig *forwardMergeTwo(struct contig *a, struct contig *b)
+/* Make a new contig that's a merger of a and b. 
+ * Assumes that a and b overlap and are on + strand. */
+{
+int aSymOverlapStart, aSymOverlapEnd, aSymOverlapSize;
+int bSymOverlapStart, bSymOverlapEnd, bSymOverlapSize;
+int aqoStart, bqoStart;
+int overlapSize, halfOverlapSize;
+int aCopyStart, aCopyEnd, bCopyStart, bCopyEnd;
+int newSymCount;
+struct contig *c;
+int aCopySize, bCopySize;
+int qOverlap;
+
+/* Find overlapping area in symbol coordinates. */
+qOverlap = b->qStart - a->qStart;
+if (qOverlap < 0 || qOverlap > a->qEnd - a->qStart)
+    return NULL;
+if (!findSymIx(a->qSym, b->qStart - a->qStart, &aSymOverlapStart))
+    return NULL;
+aSymOverlapEnd = a->symCount;
+aSymOverlapSize = aSymOverlapEnd - aSymOverlapStart;
+bSymOverlapStart = 0;
+if (!findSymIx(b->qSym, a->qEnd - b->qStart, &bSymOverlapEnd))
+    return NULL;
+bSymOverlapSize = bSymOverlapEnd - bSymOverlapStart;
+
+/* Find subset of overlapping area that is identical
+ * in source and query symbols. */
+findMaxOverlap(a->qSym + aSymOverlapStart, 
+    a->tSym + aSymOverlapStart, aSymOverlapSize, 
+    b->qSym + bSymOverlapStart,
+    b->tSym + bSymOverlapStart, bSymOverlapSize, 
+    &aqoStart, &bqoStart, &overlapSize);
+if (overlapSize < 15)
+    return NULL;
+aSymOverlapStart += aqoStart;
+bSymOverlapStart += bqoStart;
+halfOverlapSize = overlapSize/2;
+
+/* Figure out what areas will go into new contig, and how big
+ * it will be. */
+aCopyStart = 0;
+aCopyEnd = aSymOverlapStart + halfOverlapSize;
+bCopyStart = bSymOverlapStart + halfOverlapSize;
+bCopyEnd = b->symCount;
+newSymCount = aCopyEnd - aCopyStart + bCopyEnd - bCopyStart;
+
+/* Allocate new contig with set of symbols big enough to hold
+ * merged contig. */
+AllocVar(c);
+c->query = a->query;
+c->queryFile = a->queryFile;
+c->qStart = min(a->qStart, b->qStart);
+c->qEnd = max(a->qEnd, b->qEnd);
+c->qStrand = a->qStrand;
+c->target = cloneString(a->target);
+c->tStart = a->tStart;
+c->tEnd = b->tEnd;
+c->tStrand = a->tStrand;
+c->qSym = needMem(newSymCount);
+c->tSym = needMem(newSymCount);
+c->hSym = needMem(newSymCount);
+c->symCount = newSymCount;
+
+/* Copy symbols from contig a up to half way through
+ * overlapping area */
+aCopySize = aCopyEnd - aCopyStart;
+bCopySize = bCopyEnd - bCopyStart;
+memcpy(c->qSym, a->qSym+aCopyStart, aCopySize);
+memcpy(c->tSym, a->tSym+aCopyStart, aCopySize);
+memcpy(c->hSym, a->hSym+aCopyStart, aCopySize);
+
+/* Append symbols from contig b from half way through
+ * overlapping area to end. */
+memcpy(c->qSym+aCopySize, b->qSym+bCopyStart, bCopySize);
+memcpy(c->tSym+aCopySize, b->tSym+bCopyStart, bCopySize);
+memcpy(c->hSym+aCopySize, b->hSym+bCopyStart, bCopySize);
+
+return c;
+}
+
+static void rcContigOffsets(struct contig *a, int revOff)
+/* Subtract each coordinate in contig from revOff */
+{
+int temp;
+
+temp = a->qStart;
+a->qStart = revOff - a->qEnd;
+a->qEnd = revOff - temp;
+temp = a->tStart;
+a->tStart = revOff - a->tEnd;
+a->tEnd = revOff - temp;
+}
+
+static void rcQueryOffsetsAroundSeg(struct contig *a, int segStart, int segEnd)
+/* Reverse complement offsets relative to segStart and segEnd */
+{
+int segSize = segEnd - segStart;
+int qEnd = reverseOffset(a->qStart - segStart, segSize) + segStart + 1;
+int qStart = reverseOffset(a->qEnd - segStart, segSize) + segStart + 1;
+a->qStart = qStart;
+a->qEnd = qEnd;
+}
+
+static struct contig *mergeTwo(struct contig *a, struct contig *b)
+/* Make a new contig that's a merger of a and b. 
+ * Assumes that a and b overlap and are on either strand. */
+{
+int aStart, bEnd, revOff;
+struct contig *c;
+int tStart, tEnd;
+int qStart, qEnd;
+
+/* Take care of easy forward case first. */
+if (a->qStrand == a->tStrand)
+    return forwardMergeTwo(a,b);
+
+/* Figure out a good position to do reverse complementing of
+ * offsets about.  */
+aStart = a->qStart;
+bEnd = b->qEnd;
+revOff = aStart + bEnd;
+
+/* Save target beginning and end. */
+tStart = b->tStart;
+tEnd = a->tEnd;
+
+/* Save target begin and end. */
+qStart = a->qStart;
+qEnd = b->qEnd;
+
+/* Reverse complement offsets, do merge, and reverse complement
+ * offsets back. */
+rcContigOffsets(a, revOff);
+rcContigOffsets(b, revOff);
+c = forwardMergeTwo(b,a);
+rcContigOffsets(a, revOff);
+rcContigOffsets(b, revOff);
+if (c != NULL)
+    {
+    rcContigOffsets(c, revOff);
+    c->tStart = tStart;
+    c->tEnd = tEnd;
+    assert(c->qStart == qStart && c->qEnd == qEnd);
+    }
+return c;
+}
+
+
+static void mergeWithinCluster(struct cluster *cluster)
+/* Merge all the contigs that you can merge within cluster. */
+{
+int clusterSize = dlCount(cluster->contigs);
+struct dlNode *prevNode, *curNode, *nextNode;
+struct contig *prev, *cur, *merged;
+int tOverlap, qOverlap;
+
+/* uglyf("M %d %s:%d-%d %c (%d-%d) %s:%d-%d %c (%d-%d)\n",
+    clusterSize, 
+    cluster->query, cluster->qStart, cluster->qEnd, cluster->qStrand,
+    cluster->qOffset, cluster->qEndOffset,
+    cluster->target, cluster->tStart, cluster->tEnd, cluster->tStrand,
+    cluster->tOffset, cluster->tEndOffset);
+ */
+
+if (clusterSize < 2)
+    return;     /* Wow was that easy! */
+curNode = cluster->contigs->head;
+cur = curNode->val;
+nextNode = curNode->next;
+
+for (;;)
+    {
+    /* Start of loop logic - store current position as previous, and
+     * move to next, stop if at end of list. */
+    prevNode = curNode;
+    curNode = nextNode;
+    if ((nextNode = curNode->next) == NULL)
+        break;
+    prev = cur;
+    cur = curNode->val;    
+
+    /* Figure out if current node overlaps with previous. */
+    if (contigsOverlap(prev, cur, &qOverlap, &tOverlap))
+        {
+        if ((merged = mergeTwo(prev, cur)) == NULL)
+            warn("Couldn't merge two");
+        else
+            {
+            dlRemove(prevNode);
+            freeMem(prevNode);
+            freeContig(&cur);
+            freeContig(&prev);
+            curNode->val = cur = merged;
+            }
+        }
+    }
+}
+
+static boolean clusterEncompassedBefore(struct dlList *clusterList, struct cluster *cluster)
+/* Return TRUE if clusterList up to cluster has a member that encompasses
+ * cluster. */
+{
+struct dlNode *node;
+struct cluster *c;
+
+for (node = clusterList->head; node->next != NULL; node = node->next)
+    {
+    c = node->val;
+    if (c == cluster)
+        return FALSE;
+    if (c->qStart <= cluster->qStart && c->qEnd >= cluster->qEnd &&
+        c->tStart <= cluster->tStart && c->tEnd >= cluster->tEnd &&
+        c->qStrand == cluster->qStrand &&
+        c->tStrand == cluster->tStrand &&
+        sameString(c->query, cluster->query) &&
+        sameString(c->target, cluster->target) )
+        {
+        return TRUE;
+        }            
+    }
+assert(FALSE);
+return FALSE;
+}
+
+static void clusterRemoveEncompassed(struct dlList *clusterList)
+/* Remove elements from list that are completely encompassed by
+ * another. */
+{
+struct dlNode *node, *next;
+struct cluster *cluster;
+
+for (node = clusterList->head; node->next != NULL; node = next)
+    {
+    next = node->next;
+    cluster = node->val;
+    if (clusterEncompassedBefore(clusterList, cluster))
+        {
+        dlRemove(node);
+        freeMem(node);
+        freeContigList(&cluster->contigs);
+        freeMem(cluster);
+        }
+    }
+}
+
+static boolean contigEncompassedBefore(struct dlList *contigList, struct contig *contig)
+/* Return TRUE if contigList up to contig has a member that encompasses
+ * contig. */
+{
+struct dlNode *node;
+struct contig *c;
+
+for (node = contigList->head; node->next != NULL; node = node->next)
+    {
+    c = node->val;
+    if (c == contig)
+        return FALSE;
+    if (c->qStart <= contig->qStart && c->qEnd >= contig->qEnd &&
+        c->tStart <= contig->tStart && c->tEnd >= contig->tEnd &&
+        c->qStrand == contig->qStrand &&
+        c->tStrand == contig->tStrand &&
+        sameString(c->query, contig->query) &&
+        sameString(c->target, contig->target) )
+        {
+        return TRUE;
+        }            
+    }
+assert(FALSE);
+return FALSE;
+}
+
+static void contigRemoveEncompassed(struct dlList *contigList)
+/* Remove elements from list that are completely encompassed by
+ * another. */
+{
+struct dlNode *node, *next;
+struct contig *contig;
+
+for (node = contigList->head; node->next != NULL; node = next)
+    {
+    next = node->next;
+    contig = node->val;
+    if (contigEncompassedBefore(contigList, contig))
+        {
+        dlRemove(node);
+        freeMem(node);
+        freeContig(&contig);
+        }
+    }
+}
+
+static int milliMatchScore(struct contig *contig)
+/* Return score that's fraction of symbols that match over 1000 */
+{
+int symCount = contig->symCount;
+char *qSym = contig->qSym;
+char *tSym = contig->tSym;
+int matchCount = 0;
+int i;
+
+for (i=0; i<symCount; ++i)
+    {
+    if (qSym[i] == tSym[i])
+        ++matchCount;
+    }
+return round( (1000.0 * matchCount) /  symCount);
+} 
+
+static void mergeContigs(struct dlList *contigList, int stitchMinScore)
+/* Merge together contigs where possible. Assumes query sequence for
+ * all in list is the same (though the query subsequence differs). */
+{
+struct dlList *clusterList;
+struct dlNode *contigNode, *clusterNode;
+struct dlNode *nextClusterNode;
+struct cluster *cluster;
+struct contig *contig;
+int contigCount;
+int startCount = 0;
+
+/* Make sure there's really something to do, so we don't have
+ * to NULL check so much in the rest of this routine. */
+contigCount = dlCount(contigList);
+if (contigCount < 1)
+    return;
+
+clusterList = newDlList();
+
+/* Group together contigs that overlap in both query and target
+   into clusters. */
+while ((contigNode = dlPopHead(contigList)) != NULL)
+    {
+    if (!mergeIntoAdjacentClusters(clusterList, contigNode))
+        {
+        AllocVar(cluster);
+        contig = contigNode->val;
+        cluster->contigs = newDlList();
+        dlAddTail(cluster->contigs, contigNode);
+        cluster->query = contig->query;
+        cluster->qStart = contig->qStart;
+        cluster->qEnd = contig->qEnd;
+        cluster->qOffset = contig->qOffset;
+        cluster->qEndOffset = contig->qEndOffset;
+        cluster->qStrand = contig->qStrand;
+        cluster->target = contig->target;
+        cluster->tStart = contig->tStart;
+        cluster->tEnd = contig->tEnd;
+        cluster->tOffset = contig->tOffset;
+        cluster->tEndOffset = contig->tEndOffset;
+        cluster->tStrand = contig->tStrand;
+        cluster->score = contig->score;
+        dlAddValTail(clusterList, cluster);
+        }
+    }
+
+/* Weed out clusters that are too weak. */
+for (clusterNode = clusterList->head; clusterNode->next != NULL; 
+    clusterNode = nextClusterNode)
+    {
+    nextClusterNode = clusterNode->next;
+    cluster = clusterNode->val;
+    if (cluster->score < stitchMinScore)
+        {
+        dlRemove(clusterNode);
+        freeContigList(&cluster->contigs);
+        freeMem(cluster);
+        freeMem(clusterNode);
+        }
+    }
+
+clusterRemoveEncompassed(clusterList);
+
+/* Merge contigs within cluster into a single contig, and move that contig
+ * back onto cluster list. */
+for (clusterNode = clusterList->head; clusterNode->next != NULL; clusterNode = clusterNode->next)
+    {
+    cluster = clusterNode->val;
+    mergeWithinCluster(cluster);
+    while ((contigNode = dlPopHead(cluster->contigs)) != NULL)
+        dlAddTail(contigList, contigNode);
+    freeDlList(&cluster->contigs);
+    }
+
+dlSort(contigList, cmpContigQueryStart);
+contigRemoveEncompassed(contigList);
+
+for (contigNode = contigList->head; contigNode->next != NULL; contigNode = contigNode->next)
+    {
+    char nameBuf[128];
+    char *noDir;
+    char *noDot;
+    contig = contigNode->val;
+    /* Get rid of directory and suffix parts of file name to use as
+     * base for contig name. */
+    noDir = strrchr(contig->query, '\\');
+    if (noDir == NULL)
+        noDir = strrchr(contig->query, '/');
+    if (noDir == NULL)
+        noDir = contig->query;
+    else
+        noDir += 1;
+    noDot = strrchr(noDir, '.');
+    if (noDot != NULL)
+        *noDot = 0;
+    sprintf(nameBuf, "%s.c%d", noDir, ++startCount);    
+    contig->name = cloneString(nameBuf);
+    contig->score = milliMatchScore(contig);
+    }
+
+/* Free up now gutted cluster list. */
+freeDlListAndVals(&clusterList);
+}
+
+static void finishContigs( struct dlList **pContigList, 
+    FILE *out, int stitchMinScore, boolean compactOutput, boolean newFormat)
+/* Merge together contigs that go together, write the good
+ * ones to output, and remove contigs from list.  */
+{
+struct contig *contig;
+struct dlNode *node;
+
+checkComplete(*pContigList);
+mergeContigs(*pContigList, stitchMinScore);
+for (node = (*pContigList)->head; node->next != NULL; node = node->next)
+    {
+    contig = node->val;
+    writeContig(contig, out, compactOutput, newFormat);
+    }
+freeContigList(pContigList);
+*pContigList = newDlList();
+}
+
+static int countNonGap(char *s, int size)
+/* Count number of non-gap characters in string s of given size. */
+{
+int count = 0;
+while (--size >= 0)
+    if (*s++ != '-') ++count;
+return count;
+}
+
+static void xStitch(char *inName, FILE *out, int stitchMinScore, boolean compactOutput, 
+   boolean newFormat)
+/* Do the big old stitching run putting together contents of inName
+ * into contigs in out. */
+{
+FILE *in;
+char line[512];
+int lineCount = 0;
+char *words[64];
+int wordCount;
+char *firstWord;
+char *queryName = "";
+char *queryFile = "";
+struct hash *queryFileHash = newHash(0);
+struct contig *contig = NULL;
+struct dlList *contigList = newDlList();
+int lineState = 0;   /* Keeps track of groups of four lines. */
+struct slName *queryNameList = NULL;
+int maxSymCount = 64*1024;
+char *qSymBuf = needMem(maxSymCount+1);
+char *tSymBuf = needMem(maxSymCount+1);
+char *hSymBuf = needMem(maxSymCount+1);
+int symCount = 0;
+int qSymLen = 0, tSymLen = 0, hSymLen = 0;
+
+in = mustOpen(inName, "r");
+while (fgets(line, sizeof(line), in))
+    {
+    ++lineCount;
+    if (++lineState == 5)
+        lineState = 0;
+    wordCount = chopLine(line, words);
+    if (wordCount <= 0)
+        continue;
+    firstWord = words[0];
+    if (sameString(firstWord, "Aligning"))
+        {
+        char *queryString;
+        char *targetString;
+        char queryStrand, targetStrand;
+        char *parts[8];
+        int partCount;
+
+        /* Do some preliminary checking of this line. */
+	if (newFormat)
+	    {
+	    if (wordCount < 7)
+		errAbort("Short line %d of %s", lineCount, inName);
+	    queryFile = hashStoreName(queryFileHash, words[1]);
+	    queryString = words[2];
+	    queryStrand = words[3][0];
+	    targetString = words[5];
+	    targetStrand = words[6][0];
+	    }
+	else
+	    {
+	    if (wordCount < 6)
+		errAbort("Short line %d of %s", lineCount, inName);
+	    queryString = words[1];
+	    queryStrand = words[2][0];
+	    targetString = words[4];
+	    targetStrand = words[5][0];
+	    }
+
+        /* Extract the name of the query sequence.  If it's new,
+         * then write out contigs on previous query we've accumulated
+         * so far and start a new list. */
+        partCount = chopString(queryString, ":-", parts, ArraySize(parts));
+        if (!sameString(parts[0], queryName))
+            {
+            /* Allocate new name and keep track of it. */
+            struct slName *newName = newSlName(parts[0]);
+            slAddHead(&queryNameList, newName);
+
+            /* Write out old contigs and empty out contig list. */
+            finishContigs(&contigList, out, stitchMinScore, compactOutput, newFormat);
+            queryName = newName->name;
+            }
+        
+        /* Make up a new contig, and fill it in with the data we
+         * have so far about query. */
+        AllocVar(contig);
+        dlAddValTail(contigList, contig);
+	contig->queryFile = queryFile;
+        contig->query = queryName;
+        contig->qOffset = atoi(parts[1]);
+        contig->qEndOffset = atoi(parts[2]);
+        contig->qStrand = queryStrand;
+
+        /* Parse target string and fill in contig with it's info. */
+        chopString(targetString, ":-", parts, ArraySize(parts));
+        contig->target = cloneString(parts[0]);
+        contig->tOffset = atoi(parts[1]);
+        contig->tEndOffset = atoi(parts[2]);
+        contig->tStrand = targetStrand;
+
+        /* We don't know start and end yet - set them to values
+         * that will get easily replace by max/min. */
+        contig->qStart = contig->tStart = 0x3fffffff;
+
+        lineState = -1;
+        symCount = 0;
+        }
+    else if (sameString(firstWord, "best"))
+        {
+        if (wordCount < 3)
+            errAbort("Short line %d of %s", lineCount, inName);
+        contig->score = atoi(words[2]);
+        contig->isComplete = TRUE;
+        contig->qSym = cloneStringZ(qSymBuf, symCount);
+        contig->tSym = cloneStringZ(tSymBuf, symCount);
+        contig->hSym = cloneStringZ(hSymBuf, symCount);
+        contig->symCount = symCount;
+        contig->qEnd = contig->qStart + countNonGap(qSymBuf, symCount);
+        contig->tEnd = contig->tStart + countNonGap(tSymBuf, symCount);
+        if (contig->qStrand != contig->tStrand) 
+            rcQueryOffsetsAroundSeg(contig, contig->qOffset, contig->qEndOffset);
+        }
+    else if (wordCount > 1 && (isdigit(firstWord[0]) || firstWord[0] == '-'))
+        {
+        int start, end;
+        char *sym = words[1];
+        int symLen = strlen(sym);
+        char firstChar = firstWord[0];
+        if (lineState != 0 && lineState != 2)
+            errAbort("Bummer - phasing mismatch on lineState line %d of %s!\n", lineCount, inName);
+        assert(lineState == 0 || lineState == 2);
+        start = atoi(firstWord);
+        end = start + symLen;
+        if (symCount + symLen > maxSymCount)
+            {
+            errAbort("Single contig too long line %d of %s, can only handle up to %d symbols\n",
+                lineCount, inName, maxSymCount);
+            }
+        if (lineState == 0) /* query symbols */
+            {
+            qSymLen = symLen;
+            if (isdigit(firstChar))
+                {
+                start += contig->qOffset;
+                end += contig->qOffset;
+                contig->qStart = min(contig->qStart, start);
+                contig->qEnd = max(contig->qEnd, end);
+                }
+            memcpy(qSymBuf+symCount, sym, symLen);
+            }
+        else               /* target symbols */
+            {
+            tSymLen = symLen;
+            if (tSymLen != qSymLen)
+                {
+                errAbort("Target symbol size not same as query line %d of %s",
+                    lineCount, inName);
+                }            
+            if (isdigit(firstChar))
+                {
+                start += contig->tOffset;
+                end += contig->tOffset;
+                contig->tStart = min(contig->tStart, start);
+                }
+            memcpy(tSymBuf+symCount, sym, symLen);
+            }
+        }
+    else if (firstWord[0] == '(')
+        {
+        lineState = -1;
+        }
+    else
+        {
+        assert(lineState == 1 || lineState == 3);
+        if (lineState == 3)  /* Hidden symbols. */
+            {
+            char *sym = firstWord;
+            int symLen = strlen(sym);
+            hSymLen = symLen;
+            if (hSymLen != qSymLen)
+                {
+                errAbort("Hidden symbol size not same as query line %d of %s",
+                    lineCount, inName);
+                }
+            memcpy(hSymBuf+symCount, sym, symLen);
+            symCount += symLen;
+            }        
+        }
+    } 
+finishContigs(&contigList, out, stitchMinScore, compactOutput, newFormat);
+fclose(in);
+
+slFreeList(&queryNameList);
+freeHash(&queryFileHash);
+freeMem(qSymBuf);
+freeMem(tSymBuf);
+freeMem(hSymBuf);
+}
+
+void xenStitch(char *inName, FILE *out, int stitchMinScore, boolean compactOutput)
+/* Do the big old stitching run putting together contents of inName
+ * into contigs in out.  Create output in newer format. */
+{
+xStitch(inName, out, stitchMinScore, compactOutput, TRUE);
+}
+
+void xenStitcher(char *inName, FILE *out, int stitchMinScore, boolean compactOutput)
+/* Do the big old stitching run putting together contents of inName
+ * into contigs in out.  Create output in older format. */
+{
+xStitch(inName, out, stitchMinScore, compactOutput, FALSE);
+}
+
+
+void xenAlignBig(DNA *query, int qSize, DNA *target, int tSize, FILE *f, boolean forHtml)
+/* Do a big alignment - one that has to be stitched together. */
+{
+struct crudeAli *caList, *ca;
+struct nt4Seq *nt4 = newNt4(target, tSize, "target");
+struct tempName dynTn;
+int i;
+int lqSize;
+int qMaxSize = 2000;
+int tMaxSize = 2*qMaxSize;
+int lastQsection = qSize - qMaxSize/2;
+FILE *dynFile;
+int tMin, tMax, tMid;
+int score;
+int totalAli = 0;
+double totalSize;
+
+totalSize = (double)qSize * tSize;
+if (totalSize < 10000000.0)
+    {
+    xenAlignSmall(query, qSize, target, tSize, f, forHtml);
+    return;
+    }
+makeTempName(&dynTn, "xen", ".dyn");
+dynFile = mustOpen(dynTn.forCgi, "w");
+
+for (i = 0; i<lastQsection || i == 0; i += qMaxSize/2)
+    {
+    lqSize = qSize - i;
+    if (lqSize > qMaxSize)
+        lqSize = qMaxSize;
+    caList = crudeAliFind(query+i, lqSize, &nt4, 1, 8, 12);
+    if (forHtml)
+        {
+        fputc('.', stdout);
+        fflush(stdout);
+        }
+    for (ca = caList; ca != NULL; ca = ca->next)
+        {
+        tMid = (ca->start + ca->end)/2;
+        tMin = tMid-tMaxSize/2;
+        tMax = tMin + tMaxSize;
+        if (tMin < 0)
+            tMin = 0;
+        if (tMax > tSize)
+            tMax = tSize;
+        
+        fprintf(dynFile, "Aligning query:%d-%d %c to target:%d-%d +\n",
+            i, i+lqSize, ca->strand, tMin, tMax);
+        if (ca->strand == '-')
+            {
+            reverseComplement(query+i, lqSize);
+            }
+        score = xenAlignSmall(query+i, lqSize, target+tMin, tMax-tMin, dynFile, FALSE);        
+        if (ca->strand == '-')
+            reverseComplement(query+i, lqSize);
+        fprintf(dynFile, "best score %d\n", score);
+        if (forHtml)
+            {
+            fputc('.', stdout);
+            fflush(stdout);
+            }
+        ++totalAli;
+        }
+    slFreeList(&caList);
+    }
+
+freeNt4(&nt4);
+fclose(dynFile);
+if (forHtml)
+    {
+    printf("\n %d alignments to stitch.\n", totalAli);
+    }
+xenStitcher(dynTn.forCgi, f, 150000, FALSE);
+remove(dynTn.forCgi);
+}
+
+
+void xenAlignWorm(DNA *query, int qSize, FILE *f, boolean forHtml)
+/* Do alignment against worm genome. */
+ {
+struct crudeAli *caList = NULL, *ca, *newCa;
+struct tempName dynTn;
+int i;
+int lqSize;
+int qMaxSize = 2000;
+int tMaxSize = 2*qMaxSize;
+int lastQsection = qSize - qMaxSize/2;
+FILE *dynFile;
+int tMin, tMax, tMid, tSize;
+int score;
+int chromCount;
+char **chromNames;
+struct nt4Seq **chrom;
+DNA *target;
+int sectionCount = 0;
+
+/* Get C. elegans genome and do crude alignments. */
+wormLoadNt4Genome(&chrom, &chromCount);
+wormChromNames(&chromNames, &chromCount);
+for (i = 0; i<lastQsection || i == 0; i += qMaxSize/2)
+    {
+    if (forHtml)
+        {
+        fputc('.', stdout);
+        fflush(stdout);
+        }
+    lqSize = qSize - i;
+    if (lqSize > qMaxSize)
+        lqSize = qMaxSize;
+    newCa = crudeAliFind(query+i, lqSize, chrom, chromCount, 8, 45);
+    for (ca = newCa; ca != NULL; ca = ca->next)
+        {
+        ca->qStart = i;
+        ca->qEnd = i+lqSize;
+        }
+    caList = slCat(caList,newCa);
+    ++sectionCount;
+    }
+wormFreeNt4Genome(&chrom);
+
+/* Make temporary output file. */
+makeTempName(&dynTn, "xen", ".dyn");
+dynFile = mustOpen(dynTn.forCgi, "w");
+
+/* Do dynamic programming alignment on each crude alignment. */
+if (forHtml)
+    {
+    int crudeCount = slCount(caList);
+    if (crudeCount > 2*sectionCount)
+        {
+        printf("\nThis is a difficult alignment.  It looks like the query aligns with\n"
+               "the <I>C. elegans</I> genome in %d places.  It will take about %1.0f more\n"
+               "minutes to finish.\n", (crudeCount+sectionCount/2)/sectionCount, crudeCount*0.5);
+        }
+    fflush(stdout);
+    }
+for (ca = caList; ca != NULL; ca = ca->next)
+    {
+    if (forHtml)
+        {
+        fputc('.', stdout);
+        fflush(stdout);
+        }
+    tMid = (ca->start + ca->end)/2;
+    tMin = tMid-tMaxSize/2;
+    tMax = tMin + tMaxSize;
+    wormClipRangeToChrom(chromNames[ca->chromIx], &tMin, &tMax);
+    fprintf(dynFile, "Aligning query:%d-%d %c to %s:%d-%d +\n",
+        ca->qStart, ca->qEnd, ca->strand, chromNames[ca->chromIx], tMin, tMax);
+    lqSize = ca->qEnd - ca->qStart;
+    if (ca->strand == '-')
+        reverseComplement(query+ca->qStart, lqSize);
+    tSize = tMax - tMin;
+    target = wormChromPart(chromNames[ca->chromIx], tMin, tSize);
+    score = xenAlignSmall(query+ca->qStart, lqSize, target, tSize, dynFile, FALSE);        
+    freez(&target);
+    if (ca->strand == '-')
+        reverseComplement(query+ca->qStart, lqSize);
+    fprintf(dynFile, "best score %d\n", score);
+    }
+slFreeList(&caList);
+fclose(dynFile);
+
+if (forHtml)
+    printf("\n");
+xenStitcher(dynTn.forCgi, f, 150000, FALSE);
+remove(dynTn.forCgi);
+}
+
diff --git a/jkOwnLib/xensmall.c b/jkOwnLib/xensmall.c
new file mode 100644
index 0000000..595b772
--- /dev/null
+++ b/jkOwnLib/xensmall.c
@@ -0,0 +1,471 @@
+/* xensmall.c - align using dynamic programming. */
+/* Copyright 2000-2003 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "memalloc.h"
+#include "cheapcgi.h"
+#include "dnautil.h"
+#include "xenalign.h"
+#include "pairHmm.h"
+
+
+static double calcGcRatio(DNA *a, int aSize, DNA *b, int bSize)
+/* Figure out percentage of g/c in a and b. */
+{
+int counts[4];
+int i;
+int total = 4;
+DNA base;
+int val;
+int gcCount;
+
+for (i=0; i<ArraySize(counts); ++i)
+    counts[i] = 1;
+for (i=0; i<aSize; ++i)
+    {
+    base = a[i];
+    if ((val = ntVal[(int)base]) >= 0)
+        {
+        counts[val] += 1;
+        total += 1;
+        }
+    }    
+for (i=0; i<bSize; ++i)
+    {
+    base = b[i];
+    if ((val = ntVal[(int)base]) >= 0)
+        {
+        counts[val] += 1;
+        total += 1;
+        }
+    }    
+gcCount = counts[C_BASE_VAL] + counts[G_BASE_VAL];
+return (double)gcCount/(double)total;
+}
+
+/* Our seven matrices. */
+enum sevenStateIx
+    {
+    hiFiIx = 0,
+    qSlipIx,
+    tSlipIx,
+    loFiIx,
+    c1Ix,
+    c2Ix,
+    c3Ix,
+    };
+
+
+static int loFiFromHiFiCost;
+static int loFiFromCodingCost;
+static int loFiFromInsertCost;
+
+static int hiFiFromLoFiCost;
+static int hiFiFromCodingCost;
+static int hiFiFromInsertCost;
+
+static int codingFromHiFiCost;
+static int codingFromLoFiCost;
+static int codingFromInsertCost;
+
+static int insertFromHiFiCost;
+static int insertFromLoFiCost;
+static int insertFromCodingCost;
+
+static int loFiSmallGapCost;
+static int hiFiSmallGapCost;
+static int codingSmallGapCost;
+static int largeGapExtensionCost;
+
+
+static int scaledLogOfFraction(double p, double q)
+/* return log of fraction scaled by 1000 */
+{
+return round(1000*log((double)p/q) );
+}
+
+static int transitionCost(double prob)
+/* Calculates the cost of transition of given probability */
+{
+return round(1000*(log(prob)));
+}
+
+static int c1c2MatchTable[26*32];
+static int c3MatchTable[26*32];
+static int hiFiMatchTable[26*32];
+static int loFiMatchTable[26*32];
+
+#define letterIx(a) ((a)-'a')
+
+static void makeMatchTable(int matchTable[], double matchProb, double gcRatio)
+/* Make table of match/mismatch cost/benefits for a given probability of
+ * matching and a given % of GC. */
+{
+double atRatio = 1.0 - gcRatio;
+int unlikely = round(1000*log(0.0001));
+double mismatchProb = 1.0 - matchProb;
+double freq[4];
+DNA a,b;
+int i,j;
+
+freq[A_BASE_VAL] = freq[T_BASE_VAL] = atRatio/2;
+freq[G_BASE_VAL] = freq[C_BASE_VAL] = gcRatio/2;
+
+for (i=0; i<26*32; ++i)
+        matchTable[i] = unlikely;
+
+for (i=0; i<4; ++i)
+    {
+    a =  valToNt[i];
+    for (j=0; j<4; ++j)
+        {
+        b = valToNt[j];
+        if (a == b)
+            matchTable[32*letterIx(a) + letterIx(b)] = scaledLogOfFraction(matchProb, freq[j]);
+        else
+            matchTable[32*letterIx(a) + letterIx(b)] = scaledLogOfFraction(mismatchProb, 1.0 - freq[j]);
+        }
+    }
+}
+
+static void makeWobbleMatchTable(int matchTable[], double gcRatio)
+/* Make table of match/mismatch costs for the wobble codon. */
+{
+/* Assume 53% match, 33% wobble-match 14% mismatch. */
+double atRatio = 1.0 - gcRatio;
+int unlikely = round(1000*log(0.0001));
+double freq[4];
+int i;
+double matchProb = 0.53;
+double wobbleProb = 0.33;
+double mismatchProb = 0.14*0.5;   /* Two ways to mismatch. */
+
+freq[A_BASE_VAL] = freq[T_BASE_VAL] = atRatio/2;
+freq[G_BASE_VAL] = freq[C_BASE_VAL] = gcRatio/2;
+
+for (i=0; i<26*32; ++i)
+       matchTable[i] = unlikely;
+matchTable[32*letterIx('a') + letterIx('a')] = scaledLogOfFraction(matchProb, freq[A_BASE_VAL]);
+matchTable[32*letterIx('a') + letterIx('c')] = scaledLogOfFraction(mismatchProb, freq[C_BASE_VAL]);
+matchTable[32*letterIx('a') + letterIx('g')] = scaledLogOfFraction(wobbleProb, freq[G_BASE_VAL]);
+matchTable[32*letterIx('a') + letterIx('t')] = scaledLogOfFraction(mismatchProb, freq[T_BASE_VAL]);
+
+matchTable[32*letterIx('c') + letterIx('a')] = scaledLogOfFraction(mismatchProb, freq[A_BASE_VAL]);
+matchTable[32*letterIx('c') + letterIx('c')] = scaledLogOfFraction(matchProb, freq[C_BASE_VAL]);
+matchTable[32*letterIx('c') + letterIx('g')] = scaledLogOfFraction(mismatchProb, freq[G_BASE_VAL]);
+matchTable[32*letterIx('c') + letterIx('t')] = scaledLogOfFraction(wobbleProb, freq[T_BASE_VAL]);
+
+matchTable[32*letterIx('g') + letterIx('a')] = scaledLogOfFraction(wobbleProb, freq[A_BASE_VAL]);
+matchTable[32*letterIx('g') + letterIx('c')] = scaledLogOfFraction(mismatchProb, freq[C_BASE_VAL]);
+matchTable[32*letterIx('g') + letterIx('g')] = scaledLogOfFraction(matchProb, freq[G_BASE_VAL]);
+matchTable[32*letterIx('g') + letterIx('t')] = scaledLogOfFraction(mismatchProb, freq[T_BASE_VAL]);
+
+matchTable[32*letterIx('t') + letterIx('a')] = scaledLogOfFraction(mismatchProb, freq[A_BASE_VAL]);
+matchTable[32*letterIx('t') + letterIx('c')] = scaledLogOfFraction(wobbleProb, freq[C_BASE_VAL]);
+matchTable[32*letterIx('t') + letterIx('g')] = scaledLogOfFraction(mismatchProb, freq[G_BASE_VAL]);
+matchTable[32*letterIx('t') + letterIx('t')] = scaledLogOfFraction(matchProb, freq[T_BASE_VAL]);
+}
+
+static void calcCostBenefit(double gcRatio)
+/* Figure out weights to put on all the arrows... */
+{
+loFiFromHiFiCost = transitionCost(1.0/30.0);
+codingFromHiFiCost = transitionCost(1.0/60.0);
+insertFromHiFiCost = transitionCost(1.0/1000.0);
+
+loFiFromCodingCost = transitionCost(1.0/200.0);
+hiFiFromCodingCost = transitionCost(1.0/300.0);
+insertFromCodingCost = transitionCost(1.0/1000.0);
+
+hiFiFromLoFiCost = transitionCost(1.0/100.0);
+codingFromLoFiCost = transitionCost(1.0/150.0);
+insertFromLoFiCost = transitionCost(1.0/400.0);
+
+loFiFromInsertCost = transitionCost(1.0/60.0);
+hiFiFromInsertCost = transitionCost(1.0/1000.0);
+codingFromInsertCost = transitionCost(1.0/1000.0);
+
+largeGapExtensionCost = scaledLogOfFraction(74,75);
+
+loFiSmallGapCost = scaledLogOfFraction(1,10);
+hiFiSmallGapCost = scaledLogOfFraction(1,25);
+codingSmallGapCost = scaledLogOfFraction(1,300);
+
+makeMatchTable(c1c2MatchTable, 0.92, gcRatio);
+//c1c2matchBonus = scaledLogOfFraction(0.92, 0.25);   /* 1.33 1.28 */
+//c1c2mismatchCost = scaledLogOfFraction(0.08, 0.75); /* -2.71 -2.01 */
+
+makeWobbleMatchTable(c3MatchTable, gcRatio);
+//c3matchBonus = scaledLogOfFraction(0.6, 0.25);
+//assert(c3matchBonus > 0);
+//c3mismatchCost = scaledLogOfFraction(0.4, 0.75);
+
+makeMatchTable(loFiMatchTable, 0.5, gcRatio);
+//loFiMatchBonus = scaledLogOfFraction(0.5, 0.25);
+//loFiMismatchCost = scaledLogOfFraction(0.5, 0.75);
+
+makeMatchTable(hiFiMatchTable, 0.9, gcRatio);
+//hiFiMatchBonus = scaledLogOfFraction(0.9, 0.25);
+//hiFiMismatchCost = scaledLogOfFraction(0.1, 0.75);
+}
+
+
+int xenAlignSmall(DNA *query, int querySize, DNA *target, int targetSize, FILE *f,
+    boolean printExtraAtEnds)
+/* Use dynamic programming to do small scale (querySize * targetSize < 10,000,000)
+ * alignment of DNA. */
+{
+struct phmmMatrix *a;
+struct phmmState *hf, *lf, *iq, *it, *c1, *c2, *c3;
+int qIx, tIx, sIx;  /* Query, target, and state indices */
+int rowOffset, newCellOffset;
+struct phmmAliPair *pairList;
+int matchOff, qSlipOff, tSlipOff;
+int bestScore = -0x4fffffff;
+struct phmmMommy *bestCell = NULL;
+int c1c2PairScore, c3PairScore, loFiPairScore, hiFiPairScore;
+int matchTableOffset;
+double gcRatio;
+
+/* Check that it's not too big. */
+if ((double)targetSize * querySize > 1.1E7)
+    errAbort("Can't align %d x %d, too big\n", querySize, targetSize);
+
+/* Set up graph edge costs/benefits */
+gcRatio = calcGcRatio(query, querySize, target, targetSize);
+calcCostBenefit(gcRatio);
+
+/* Initialize 7 state matrix. */
+a = phmmMatrixNew(7, query, querySize, target, targetSize);
+hf = phmmNameState(a, hiFiIx, "highFi", 'H');
+lf = phmmNameState(a, loFiIx, "lowFi", 'L');
+iq = phmmNameState(a, qSlipIx, "qSlip", 'Q');
+it = phmmNameState(a, tSlipIx, "tSlip", 'T');
+c1 = phmmNameState(a, c1Ix, "frame1", '1');
+c2 = phmmNameState(a, c2Ix, "frame2", '2');
+c3 = phmmNameState(a, c3Ix, "frame3", '3');
+
+qSlipOff = -a->qDim;
+tSlipOff = -1;
+matchOff = qSlipOff + tSlipOff;
+
+for (tIx = 1; tIx < a->tDim; tIx += 1)
+    {
+    UBYTE mommy = 0;
+    int score, tempScore;
+
+/* Macros to make me less mixed up when accessing scores from row arrays.*/
+#define matchScore lastScores[qIx-1]
+#define qSlipScore lastScores[qIx]
+#define tSlipScore scores[qIx-1]
+#define newScore scores[qIx]
+
+/* Start up state block (with all ways to enter state) */
+#define startState(state) \
+   score = 0;
+
+/* Define a transition from state while advancing over both
+ * target and query. */
+#define matchState(state, addScore) \
+   { \
+   if ((tempScore = state->matchScore + addScore) > score) \
+        { \
+        mommy = phmmPackMommy(state->stateIx, -1, -1); \
+        score = tempScore; \
+        } \
+   } 
+
+/* Define a transition from state while slipping query
+ * and advancing target. */
+#define qSlipState(state, addScore) \
+   { \
+   if ((tempScore = state->qSlipScore + addScore) > score) \
+        { \
+        mommy = phmmPackMommy(state->stateIx, 0, -1); \
+        score = tempScore; \
+        } \
+   }
+
+/* Define a transition from state while slipping target
+ * and advancing query. */
+#define tSlipState(state, addScore) \
+   { \
+   if ((tempScore = state->tSlipScore + addScore) > score) \
+        { \
+        mommy = phmmPackMommy(state->stateIx, -1, 0); \
+        score = tempScore; \
+        } \
+   }
+
+/* End a block of transitions into state. */
+#define endState(state) \
+    { \
+    struct phmmMommy *newCell = state->cells + newCellOffset; \
+    if (score <= 0) \
+        { \
+        mommy = phmmNullMommy; \
+        score = 0; \
+        } \
+    newCell->mommy = mommy; \
+    state->newScore = score; \
+    if (score > bestScore) \
+        { \
+        bestScore = score; \
+        bestCell = newCell; \
+        } \
+    } 
+
+/* End a state that you know won't produce an optimal
+ * final score. */
+#define shortEndState(state) \
+    { \
+    struct phmmMommy *newCell = state->cells + newCellOffset; \
+    if (score <= 0) \
+        { \
+        mommy = phmmNullMommy; \
+        score = 0; \
+        } \
+    newCell->mommy = mommy; \
+    state->newScore = score; \
+    }
+
+    rowOffset = tIx*a->qDim;
+    for (qIx = 1; qIx < a->qDim; qIx += 1)
+        {
+        int qBase = letterIx(a->query[qIx-1]);
+        int tBase = letterIx(a->target[tIx-1]);
+
+        newCellOffset = rowOffset + qIx;
+        
+        /* Figure the cost or bonus for pairing target and query residue here. */
+        matchTableOffset = (qBase<<5) + tBase;
+        c1c2PairScore = c1c2MatchTable[matchTableOffset];
+        c3PairScore = c3MatchTable[matchTableOffset];
+        hiFiPairScore = hiFiMatchTable[matchTableOffset];
+        loFiPairScore = loFiMatchTable[matchTableOffset];
+
+        /* Update hiFi space. */
+            {
+            startState(hf);
+            matchState(hf, hiFiPairScore);
+            qSlipState(hf, hiFiSmallGapCost);
+            tSlipState(hf, hiFiSmallGapCost);
+            matchState(iq, hiFiPairScore + hiFiFromInsertCost);
+            matchState(it, hiFiPairScore + hiFiFromInsertCost);
+            matchState(lf, hiFiPairScore + hiFiFromLoFiCost);
+            matchState(c1, hiFiPairScore + hiFiFromCodingCost);
+            matchState(c2, hiFiPairScore + hiFiFromCodingCost);
+            matchState(c3, hiFiPairScore + hiFiFromCodingCost);
+            endState(hf);
+            }
+
+        /* Update loFi space. */
+            {
+            startState(lf);
+            matchState(lf, loFiPairScore);
+            qSlipState(lf, loFiSmallGapCost);
+            tSlipState(lf, loFiSmallGapCost);
+            matchState(iq, loFiPairScore + loFiFromInsertCost);
+            matchState(it, loFiPairScore + loFiFromInsertCost);
+            matchState(hf, loFiPairScore + loFiFromHiFiCost);
+            matchState(c1, loFiPairScore + loFiFromCodingCost);
+            matchState(c2, loFiPairScore + loFiFromCodingCost);
+            matchState(c3, loFiPairScore + loFiFromCodingCost);
+            endState(lf);
+            }
+
+        /* Update query slip space. */
+            {
+            startState(iq);
+            qSlipState(iq, largeGapExtensionCost);
+            qSlipState(hf, insertFromHiFiCost);            
+            qSlipState(lf, insertFromLoFiCost);
+            qSlipState(c1, insertFromCodingCost);
+            qSlipState(c2, insertFromCodingCost);
+            qSlipState(c3, insertFromCodingCost);
+	    qSlipState(it, largeGapExtensionCost); /* Allow double gaps, T first always. */
+            shortEndState(iq);
+            }
+        
+        /* Update target slip space. */
+            {
+            startState(it);
+            tSlipState(it, largeGapExtensionCost);
+            tSlipState(hf, insertFromHiFiCost);            
+            tSlipState(lf, insertFromLoFiCost);
+            tSlipState(c1, insertFromCodingCost);
+            tSlipState(c2, insertFromCodingCost);
+            tSlipState(c3, insertFromCodingCost);
+            shortEndState(it);
+            }
+
+        /* Update coding1 space. */
+            {
+            startState(c1);
+            matchState(c3, c1c2PairScore);
+            qSlipState(c1, codingSmallGapCost);
+            tSlipState(c1, codingSmallGapCost);
+            matchState(iq, c1c2PairScore + codingFromInsertCost);
+            matchState(it, c1c2PairScore + codingFromInsertCost);
+            matchState(lf, c1c2PairScore + codingFromLoFiCost);
+            matchState(hf, c1c2PairScore + codingFromHiFiCost);
+            endState(c1);
+            }
+
+        /* Update coding2 space. */
+            {
+            startState(c2);
+            matchState(c1, c1c2PairScore);
+            qSlipState(c2, codingSmallGapCost);
+            tSlipState(c2, codingSmallGapCost);
+            matchState(iq, c1c2PairScore + codingFromInsertCost);
+            matchState(it, c1c2PairScore + codingFromInsertCost);
+            matchState(lf, c1c2PairScore + codingFromLoFiCost);
+            matchState(hf, c1c2PairScore + codingFromHiFiCost);
+            endState(c2);
+            }
+
+
+        /* Update coding3 space. */
+            {
+            startState(c3);
+            matchState(c2, c3PairScore);
+            qSlipState(c3, codingSmallGapCost);
+            tSlipState(c3, codingSmallGapCost);
+            matchState(iq, c3PairScore + codingFromInsertCost);
+            matchState(it, c3PairScore + codingFromInsertCost);
+            matchState(lf, c3PairScore + codingFromLoFiCost);
+            matchState(hf, c3PairScore + codingFromHiFiCost);
+            endState(c3);
+            }
+        }
+    /* Swap score columns so current becomes last, and last gets
+     * reused. */
+    for (sIx = 0; sIx < a->stateCount; ++sIx)
+        {
+        struct phmmState *as = &a->states[sIx];
+        int *swapTemp = as->lastScores;
+        as->lastScores = as->scores;
+        as->scores = swapTemp;
+        }
+    }
+
+/* Trace back from best scoring cell. */
+pairList = phmmTraceBack(a, bestCell);
+phmmPrintTrace(a, pairList, TRUE, f, printExtraAtEnds);
+
+slFreeList(&pairList);
+phmmMatrixFree(&a);
+return bestScore;
+#undef matchScore
+#undef qSlipScore
+#undef tSlipScore
+#undef newScore
+#undef startState
+#undef matchState
+#undef qSlipState
+#undef tSlipState
+#undef shortEndState
+#undef endState
+}
+
diff --git a/lib/README b/lib/README
new file mode 100644
index 0000000..bb63a11
--- /dev/null
+++ b/lib/README
@@ -0,0 +1,22 @@
+This directory contains general purpose, web oriented,
+and computational biology oriented modules,  as well
+as some less general stuff associated with the Intronerator
+web site.  Initially this library was created by Jim
+Kent from 1999 to 2001.  Since then other programmers have
+also added to it.  Jim continues to make substantial
+contributions.
+
+With the exception of the gifcomp.c module, all 
+modules here are free for all use - public, private,
+or commercial. The gifcomp.c module contains code
+originally distributed by CompuServe under a similar
+"free for all" license.  However this uses the LZW
+patented by UniSys, which UniSys started enforcing
+several years after CompuServe released this module.
+The last I heard UniSys did not require a license
+for non-commercial purposes, but did require a
+license for commercial purposes. This may change
+in the future, though the patent is nearing it's
+expiration date in any case.  Commercial users
+are advised to either get a license for LZW, or
+to switch from GIF to PNG.
diff --git a/lib/aliType.c b/lib/aliType.c
new file mode 100644
index 0000000..ee8b185
--- /dev/null
+++ b/lib/aliType.c
@@ -0,0 +1,30 @@
+/* aliType - some definitions for type of alignment. */
+#include "common.h"
+#include "aliType.h"
+
+
+char *gfTypeName(enum gfType type)
+/* Return string representing type. */
+{
+if (type == gftDna) return "DNA";
+if (type == gftRna) return "RNA";
+if (type == gftProt) return "protein";
+if (type == gftDnaX) return "DNAX";
+if (type == gftRnaX) return "RNAX";
+internalErr();
+return NULL;
+}
+
+enum gfType gfTypeFromName(char *name)
+/* Return type from string. */
+{
+if (sameWord(name, "DNA")) return gftDna;
+if (sameWord(name, "RNA")) return gftRna;
+if (sameWord(name, "protein")) return gftProt;
+if (sameWord(name, "prot")) return gftProt;
+if (sameWord(name, "DNAX")) return gftDnaX;
+if (sameWord(name, "RNAX")) return gftRnaX;
+errAbort("Unknown sequence type '%s'", name);
+return 0;
+}
+
diff --git a/lib/alpha/placeHolder.c b/lib/alpha/placeHolder.c
new file mode 100755
index 0000000..e69de29
diff --git a/lib/annoColumn.c b/lib/annoColumn.c
new file mode 100644
index 0000000..a10cb84
--- /dev/null
+++ b/lib/annoColumn.c
@@ -0,0 +1,41 @@
+/* annoColumn -- def. of column plus flag for inclusion in output of annoGratorQuery framework */
+
+#include "annoColumn.h"
+
+struct annoColumn *annoColumnsFromAsObject(struct asObject *asObj)
+/* Create a list of columns from asObj; by default, all are set to be included in output.
+ * Callers: do not modify any column's def! */
+{
+struct annoColumn *colList = NULL;
+struct asColumn *asCol;
+for (asCol = asObj->columnList;  asCol != NULL;  asCol = asCol->next)
+    {
+    struct annoColumn *col;
+    AllocVar(col);
+    col->def = asCol;
+    col->included = TRUE;
+    slAddHead(&colList, col);
+    }
+slReverse(&colList);
+return colList;
+}
+
+struct annoColumn *annoColumnCloneList(struct annoColumn *list)
+/* Shallow-copy a list of annoColumns.  Callers: do not modify any column's def! */
+{
+struct annoColumn *newList = NULL, *oldC;
+for (oldC = list;  oldC != NULL;  oldC = oldC->next)
+    {
+    struct annoColumn *newC = CloneVar(oldC);
+    slAddHead(&newList, newC);
+    }
+slReverse(&newList);
+return newList;
+}
+
+void annoColumnFreeList(struct annoColumn **pList)
+/* Shallow-free a list of annoColumns.  Does not free any column's def. */
+{
+slFreeList(pList);
+}
+
diff --git a/lib/annoFilter.c b/lib/annoFilter.c
new file mode 100644
index 0000000..a5c43e9
--- /dev/null
+++ b/lib/annoFilter.c
@@ -0,0 +1,307 @@
+/* annoFilter -- autoSql-driven data filtering for annoGratorQuery framework */
+
+#include "annoFilter.h"
+#include "sqlNum.h"
+
+struct annoFilter *annoFiltersFromAsObject(struct asObject *asObj)
+/* Translate a table's autoSql representation into a list of annoFilters that make
+ * sense for the table's set of fields. */
+{
+struct annoFilter *filterList = NULL;
+struct asColumn *def;
+int ix;
+for (ix = 0, def = asObj->columnList;  def != NULL;  ix++, def = def->next)
+    {
+    struct annoFilter *newF;
+    AllocVar(newF);
+    newF->columnIx = ix;
+    newF->label = cloneString(def->name);
+    newF->type = def->lowType->type;
+    newF->op = afNoFilter;
+    slAddHead(&filterList, newF);
+    }
+slReverse(&filterList);
+return filterList;
+}
+
+static void *cloneValues(void *valuesIn, enum asTypes type)
+/* If valuesIn is non-null, return a copy of values according to type. */
+{
+void *valuesOut = NULL;
+if (valuesIn != NULL)
+    {
+    if (asTypesIsFloating(type))
+	valuesOut = cloneMem(valuesIn, 2*sizeof(double));
+    else if (asTypesIsInt(type))
+	valuesOut = cloneMem(valuesIn, 2*sizeof(long long));
+    else
+	valuesOut = cloneString((char *)valuesIn);
+    }
+return valuesOut;
+}
+
+struct annoFilter *annoFilterCloneList(struct annoFilter *list)
+/* Copy a list of annoFilters. */
+{
+struct annoFilter *newList = NULL, *oldF;
+for (oldF = list;  oldF != NULL;  oldF = oldF->next)
+    {
+    struct annoFilter *newF = CloneVar(oldF);
+    newF->label = cloneString(oldF->label);
+    newF->values = cloneValues(oldF->values, oldF->type);
+    slAddHead(&newList, newF);
+    }
+slReverse(&newList);
+return newList;
+}
+
+void annoFilterFreeList(struct annoFilter **pList)
+/* Free a list of annoFilters. */
+{
+if (pList == NULL)
+    return;
+struct annoFilter *filter, *nextFilter;
+for (filter = *pList;  filter != NULL;  filter = nextFilter)
+    {
+    nextFilter = filter->next;
+    freeMem(filter->label);
+    freeMem(filter->values);
+    freeMem(filter);
+    }
+*pList = NULL;
+}
+
+static boolean annoFilterDouble(struct annoFilter *filter, double val)
+/* Compare val to double(s) in filter->values according to filter->op,
+ * return TRUE if comparison fails. */
+{
+double *filterVals = filter->values;
+if (filter->op == afInRange)
+    {
+    double min = filterVals[0], max = filterVals[1];
+    return (val < min || val > max);
+    }
+else
+    {
+    double threshold = filterVals[0];
+    switch (filter->op)
+	{
+	case afLT:
+	    return !(val < threshold);
+	case afLTE:
+	    return !(val <= threshold);
+	case afEqual:
+	    return !(val == threshold);
+	case afNotEqual:
+	    return !(val != threshold);
+	case afGTE:
+	    return !(val >= threshold);
+	case afGT:
+	    return !(val > threshold);
+	default:
+	    errAbort("annoFilterDouble: unexpected filter->op %d for %s",
+		     filter->op, filter->label);
+	}
+    }
+return FALSE;
+}
+
+static boolean annoFilterLongLong(struct annoFilter *filter, long long val)
+/* Compare val to long long(s) in filter->values according to filter->op,
+ * return TRUE if comparison fails. */
+{
+long long *filterVals = filter->values;
+if (filter->op == afInRange)
+    {
+    long long min = filterVals[0], max = filterVals[1];
+    return (val < min || val > max);
+    }
+else
+    {
+    long long threshold = filterVals[0];
+    switch (filter->op)
+	{
+	case afLT:
+	    return !(val < threshold);
+	case afLTE:
+	    return !(val <= threshold);
+	case afEqual:
+	    return !(val == threshold);
+	case afNotEqual:
+	    return !(val != threshold);
+	case afGTE:
+	    return !(val >= threshold);
+	case afGT:
+	    return !(val > threshold);
+	default:
+	    errAbort("annoFilterLongLong: unexpected filter->op %d for %s",
+		     filter->op, filter->label);
+	}
+    }
+return FALSE;
+}
+
+static boolean singleFilter(struct annoFilter *filter, char **row, int rowSize)
+/* Apply one filter, using either filterFunc or type-based filter on column value.
+ * Return TRUE if isExclude and filter passes, or if !isExclude and filter fails. */
+{
+boolean fail = FALSE;
+if (filter->filterFunc != NULL)
+    fail = filter->filterFunc(filter, row, rowSize);
+else if (filter->op == afMatch)
+    fail = !wildMatch((char *)(filter->values), row[filter->columnIx]);
+else if (filter->op == afNotMatch)
+    fail = wildMatch((char *)(filter->values), row[filter->columnIx]);
+else
+    {
+    // column is a number -- integer or floating point?
+    enum asTypes type = filter->type;
+    if (asTypesIsFloating(type))
+	fail = annoFilterDouble(filter, sqlDouble(row[filter->columnIx]));
+    else if (asTypesIsInt(type))
+	fail = annoFilterLongLong(filter, sqlLongLong(row[filter->columnIx]));
+    else
+	errAbort("annoFilterRowFails: unexpected enum asTypes %d for numeric filter op %d",
+		 type, filter->op);
+    }
+if ((filter->isExclude && !fail) || (!filter->isExclude && fail))
+    return TRUE;
+return FALSE;
+}
+
+boolean annoFilterRowFails(struct annoFilter *filterList, char **row, int rowSize,
+			   boolean *retRightJoin)
+/* Apply filters to row, using autoSql column definitions to interpret
+ * each word of row.  Return TRUE if any filter fails (or passes, if isExclude).
+ * Set retRightJoin to TRUE if a rightJoin filter has failed. */
+{
+if (filterList != NULL && slCount(filterList) != rowSize)
+    errAbort("annoFilterRowFails: filterList length %d doesn't match rowSize %d",
+	     slCount(filterList), rowSize);
+if (retRightJoin != NULL)
+    *retRightJoin = FALSE;
+struct annoFilter *filter;
+// First pass: left-join filters (failure means omit this row from output);
+for (filter = filterList;  filter != NULL;  filter = filter->next)
+    {
+    if (filter->op == afNoFilter || filter->values == NULL || filter->rightJoin)
+	continue;
+    if (singleFilter(filter, row, rowSize))
+	return TRUE;
+    }
+// Second pass: right-join filters (failure means omit not only this row, but the primary row too)
+for (filter = filterList;  filter != NULL;  filter = filter->next)
+    {
+    if (filter->op == afNoFilter || filter->values == NULL || !filter->rightJoin)
+	continue;
+    if (singleFilter(filter, row, rowSize))
+	{
+	if (retRightJoin != NULL)
+	    *retRightJoin = TRUE;
+	return TRUE;
+	}
+    }
+return FALSE;
+}
+
+boolean annoFilterWigValueFails(struct annoFilter *filterList, double value,
+				boolean *retRightJoin)
+/* Apply filters to value.  Return TRUE if any filter fails (or passes, if isExclude).
+ * Set retRightJoin to TRUE if a rightJoin filter has failed. */
+{
+if (retRightJoin != NULL)
+    *retRightJoin = FALSE;
+struct annoFilter *filter;
+// First pass: left-join filters (failure means omit this row from output);
+for (filter = filterList; filter != NULL; filter = filter->next)
+    {
+    if (filter->op == afNoFilter || filter->rightJoin)
+	continue;
+    boolean fail = annoFilterDouble(filter, value);
+    if ((filter->isExclude && !fail) || (!filter->isExclude && fail))
+	return TRUE;
+    }
+// Second pass: right-join filters (failure means omit not only this row, but the primary row too)
+for (filter = filterList; filter != NULL; filter = filter->next)
+    {
+    if (filter->op == afNoFilter || !filter->rightJoin)
+	continue;
+    boolean fail = annoFilterDouble(filter, value);
+    if ((filter->isExclude && !fail) || (!filter->isExclude && fail))
+	{
+	if (retRightJoin != NULL)
+	    *retRightJoin = TRUE;
+	return TRUE;
+	}
+    }
+return FALSE;
+}
+
+enum annoFilterOp afOpFromString(char *string)
+/* Translate string (e.g. "afNotEqual") into enum value (e.g. afNotEqual). */
+{
+if (sameString(string, "afNoFilter"))
+    return afNoFilter;
+else if (sameString(string, "afMatch"))
+    return afMatch;
+else if (sameString(string, "afNotMatch"))
+    return afNotMatch;
+else if (sameString(string, "afLT"))
+    return afLT;
+else if (sameString(string, "afLTE"))
+    return afLTE;
+else if (sameString(string, "afEqual"))
+    return afEqual;
+else if (sameString(string, "afNotEqual"))
+    return afNotEqual;
+else if (sameString(string, "afGTE"))
+    return afGTE;
+else if (sameString(string, "afGT"))
+    return afGT;
+else if (sameString(string, "afInRange"))
+    return afInRange;
+else
+    errAbort("afOpFromString: Can't translate \"%s\" into enum annoFilterOp", string);
+// happy compiler, never get here:
+return afNoFilter;
+}
+
+char *stringFromAfOp(enum annoFilterOp op)
+/* Translate op into a string.  Do not free result. */
+{
+char *str = "afNoFilter";
+switch (op)
+    {
+    case afNoFilter:
+	break;
+    case afMatch:
+	str = "afMatch";
+    case afNotMatch:
+	str = "afNotMatch";
+	break;
+    case afLT:
+	str = "afLT";
+	break;
+    case afLTE:
+	str = "afLTE";
+	break;
+    case afEqual:
+	str = "afEqual";
+	break;
+    case afNotEqual:
+	str = "afNotEqual";
+	break;
+    case afGTE:
+	str = "afGTE";
+	break;
+    case afGT:
+	str = "afGT";
+	break;
+    case afInRange:
+	str = "afInRange";
+	break;
+    default:
+	errAbort("stringFromAfOp: unrecognized enum annoFilterOp %d", op);
+    }
+return str;
+}
diff --git a/lib/annoFormatTab.c b/lib/annoFormatTab.c
new file mode 100644
index 0000000..8961d28
--- /dev/null
+++ b/lib/annoFormatTab.c
@@ -0,0 +1,224 @@
+/* annoFormatTab -- collect fields from all inputs and print them out, tab-separated. */
+
+#include "annoFormatTab.h"
+#include "annoGratorQuery.h"
+#include "dystring.h"
+
+struct annoFormatTab
+    {
+    struct annoFormatter formatter;
+    char *fileName;
+    FILE *f;
+    boolean needHeader;			// TRUE if we should print out the header
+    };
+
+static void printHeaderColumns(FILE *f, struct annoStreamer *source, boolean isFirst)
+/* Print names of included columns from this source. */
+{
+if (source->rowType == arWig)
+    {
+    // Fudge in the row's chrom, start, end as output columns even though they're not in autoSql
+    if (isFirst)
+	{
+	fputs("#chrom", f);
+	isFirst = FALSE;
+	}
+    fputs("\tstart\tend", f);
+    }
+struct annoColumn *col;
+int i;
+for (col = source->columns, i = 0;  col != NULL;  col = col->next, i++)
+    {
+    if (! col->included)
+	continue;
+    if (isFirst && i == 0)
+	fputc('#', f);
+    else
+	fputc('\t', f);
+    fputs(col->def->name, f);
+    }
+}
+
+static void aftInitialize(struct annoFormatter *vSelf, struct annoGratorQuery *query)
+/* Print header, regardless of whether we get any data after this. */
+{
+vSelf->query = query;
+struct annoFormatTab *self = (struct annoFormatTab *)vSelf;
+if (self->needHeader)
+    {
+    struct annoStreamer *primary = query->primarySource;
+    char *primaryHeader = primary->getHeader(primary);
+    if (isNotEmpty(primaryHeader))
+	printf("# Header from primary input:\n%s", primaryHeader);
+    printHeaderColumns(self->f, primary, TRUE);
+    struct annoStreamer *grator = (struct annoStreamer *)(query->integrators);
+    for (;  grator != NULL;  grator = grator->next)
+	printHeaderColumns(self->f, grator, FALSE);
+    fputc('\n', self->f);
+    self->needHeader = FALSE;
+    }
+}
+
+static double wigRowAvg(struct annoRow *row)
+/* Return the average value of floats in row->data. */
+{
+float *vector = row->data;
+int len = row->end - row->start;
+double sum = 0.0;
+int i;
+for (i = 0;  i < len;  i++)
+    sum += vector[i];
+return sum / (double)len;
+}
+
+static char **wordsFromWigRowAvg(struct annoRow *row)
+/* Return an array of strings with a single string containing the average of values in row. */
+{
+double avg = wigRowAvg(row);
+char **words;
+AllocArray(words, 1);
+char avgStr[32];
+safef(avgStr, sizeof(avgStr), "%lf", avg);
+words[0] = cloneString(avgStr);
+return words;
+}
+
+static char **wordsFromWigRowVals(struct annoRow *row)
+/* Return an array of strings with a single string containing comma-sep per-base wiggle values. */
+{
+float *vector = row->data;
+int len = row->end - row->start;
+struct dyString *dy = dyStringNew(10*len);
+int i;
+for (i = 0;  i < len;  i++)
+    dyStringPrintf(dy, "%f,", vector[i]);
+char **words;
+AllocArray(words, 1);
+words[0] = dyStringCannibalize(&dy);
+return words;
+}
+
+static char **wordsFromRow(struct annoRow *row, struct annoStreamer *source,
+			   boolean *retFreeWhenDone)
+/* If source->rowType is arWords, return its words.  Otherwise translate row->data into words. */
+{
+if (row == NULL)
+    return NULL;
+boolean freeWhenDone = FALSE;
+char **words = NULL;
+if (source->rowType == arWords || source->rowType == arVcf)
+    words = row->data;
+else if (source->rowType == arWig)
+    {
+    freeWhenDone = TRUE;
+    //#*** config options: avg? more stats? list of values?
+    boolean doAvg = FALSE;
+    if (doAvg)
+	words = wordsFromWigRowAvg(row);
+    else
+	words = wordsFromWigRowVals(row);
+    }
+else
+    errAbort("annoFormatTab: unrecognized row type %d", source->rowType);
+if (retFreeWhenDone != NULL)
+    *retFreeWhenDone = freeWhenDone;
+return words;
+}
+
+static void printColumns(FILE *f, struct annoStreamer *streamer, struct annoRow *row,
+			 boolean isFirst)
+/* Print columns in streamer's row (if NULL, print the right number of empty fields). */
+{
+boolean freeWhenDone = FALSE;
+char **words = wordsFromRow(row, streamer, &freeWhenDone);
+if (streamer->rowType == arWig)
+    {
+    // Fudge in the row's chrom, start, end as output columns even though they're not in autoSql
+    if (isFirst)
+	{
+	if (row != NULL)
+	    fputs(row->chrom, f);
+	isFirst = FALSE;
+	}
+    if (row != NULL)
+	fprintf(f, "\t%u\t%u", row->start, row->end);
+    else
+	fputs("\t\t", f);
+    }
+struct annoColumn *col;
+int i;
+for (col = streamer->columns, i = 0;  col != NULL;  col = col->next, i++)
+    {
+    if (! col->included)
+	continue;
+    if (!isFirst || i > 0)
+	fputc('\t', f);
+    if (words != NULL)
+	fputs(words[i], f);
+    }
+if (freeWhenDone)
+    {
+    freeMem(words[0]);
+    freeMem(words);
+    }
+}
+
+static void aftFormatOne(struct annoFormatter *vSelf, struct annoRow *primaryRow,
+			 struct slRef *gratorRowList)
+/* Print out tab-separated columns that we have gathered in prior calls to aftCollect,
+ * and start over fresh for the next line of output. */
+{
+struct annoFormatTab *self = (struct annoFormatTab *)vSelf;
+// How many rows did each grator give us, and what's the largest # of rows?
+int maxRows = 1;
+int i;
+struct slRef *grRef;
+int numGrators = slCount(gratorRowList);
+for (i = 0, grRef = gratorRowList;  i < numGrators;  i++, grRef = grRef->next)
+    {
+    int gratorRowCount = slCount(grRef->val);
+    if (gratorRowCount > maxRows)
+	maxRows = gratorRowCount;
+    }
+// Print out enough rows to make sure that all grator rows are included.
+struct annoStreamer *primarySource = vSelf->query->primarySource;
+for (i = 0;  i < maxRows;  i++)
+    {
+    printColumns(self->f, primarySource, primaryRow, TRUE);
+    struct annoStreamer *grator = (struct annoStreamer *)self->formatter.query->integrators;
+    for (grRef = gratorRowList;  grRef != NULL;  grRef = grRef->next, grator = grator->next)
+	{
+	struct annoRow *gratorRow = slElementFromIx(grRef->val, i);
+	printColumns(self->f, grator, gratorRow, FALSE);
+	}
+    fputc('\n', self->f);
+    }
+}
+
+static void aftClose(struct annoFormatter **pVSelf)
+/* Close file handle, free self. */
+{
+if (pVSelf == NULL)
+    return;
+struct annoFormatTab *self = *(struct annoFormatTab **)pVSelf;
+freeMem(self->fileName);
+carefulClose(&(self->f));
+annoFormatterFree(pVSelf);
+}
+
+struct annoFormatter *annoFormatTabNew(char *fileName)
+/* Return a formatter that will write its tab-separated output to fileName. */
+{
+struct annoFormatTab *aft;
+AllocVar(aft);
+struct annoFormatter *formatter = &(aft->formatter);
+formatter->getOptions = annoFormatterGetOptions;
+formatter->setOptions = annoFormatterSetOptions;
+formatter->initialize = aftInitialize;
+formatter->formatOne = aftFormatOne;
+formatter->close = aftClose;
+aft->fileName = cloneString(fileName);
+aft->f = mustOpen(fileName, "w");
+aft->needHeader = TRUE;
+return (struct annoFormatter *)aft;
+}
diff --git a/lib/annoFormatter.c b/lib/annoFormatter.c
new file mode 100644
index 0000000..34525bf
--- /dev/null
+++ b/lib/annoFormatter.c
@@ -0,0 +1,26 @@
+/* annoFormatter -- aggregates, formats and writes output from multiple sources */
+
+#include "annoFormatter.h"
+
+struct annoOption *annoFormatterGetOptions(struct annoFormatter *self)
+/* Return supported options and current settings.  Callers can modify and free when done. */
+{
+return annoOptionCloneList(self->options);
+}
+
+void annoFormatterSetOptions(struct annoFormatter *self, struct annoOption *newOptions)
+/* Free old options and use clone of newOptions. */
+{
+annoOptionFreeList(&(self->options));
+self->options = annoOptionCloneList(newOptions);
+}
+
+void annoFormatterFree(struct annoFormatter **pSelf)
+/* Free self. This should be called at the end of subclass close methods, after
+ * subclass-specific connections are closed and resources are freed. */
+{
+if (pSelf == NULL)
+    return;
+annoOptionFreeList(&((*pSelf)->options));
+freez(pSelf);
+}
diff --git a/lib/annoGrator.c b/lib/annoGrator.c
new file mode 100644
index 0000000..7a103b9
--- /dev/null
+++ b/lib/annoGrator.c
@@ -0,0 +1,222 @@
+/* annoGrator -- join two inputs on position, keeping all original fields intact. */
+
+#include "annoGrator.h"
+
+INLINE void agCheckPrimarySorting(struct annoGrator *self, struct annoRow *primaryRow)
+/* Die if primaryRow seems to have arrived out of order. */
+{
+if (self->prevPChrom == NULL)
+    self->prevPChrom = cloneString(primaryRow->chrom);
+else if (differentString(primaryRow->chrom, self->prevPChrom))
+    {
+    if (strcmp(primaryRow->chrom, self->prevPChrom) < 0)
+	errAbort("Unsorted input from primarySource (%s < %s)",
+		 primaryRow->chrom, self->prevPChrom);
+    self->prevPChrom = cloneString(primaryRow->chrom);
+    }
+else if (primaryRow->start < self->prevPStart)
+    errAbort("Unsorted input from primarySource (%s, %u < %u)",
+	     primaryRow->chrom, primaryRow->start, self->prevPStart);
+self->prevPStart = primaryRow->start;
+}
+
+//#*** use localmem for queue? one per chrom?  free when empty?  reuse structs?
+
+INLINE void agTrimToStart(struct annoGrator *self, char *chrom, uint start)
+/* If queue contains items whose end is to the left of start, splice them out. */
+{
+struct annoRow *qRow, *prevQRow = NULL, *nextQRow;
+for (qRow = self->qHead;  qRow != NULL;  qRow = nextQRow)
+    {
+    nextQRow = qRow->next;
+    int cDifRowP = strcmp(qRow->chrom, chrom);
+    if (cDifRowP > 0 || (cDifRowP == 0 && qRow->start >= start))
+	break;
+    else if (cDifRowP < 0 || qRow->end < start)
+	{
+	if (prevQRow == NULL)
+	    self->qHead = qRow->next;
+	else
+	    prevQRow->next = qRow->next;
+	if (self->qTail == qRow)
+	    self->qTail = prevQRow;
+	annoRowFree(&qRow, self->mySource);
+	}
+    else
+	prevQRow = qRow;
+    }
+}
+
+INLINE void agCheckInternalSorting(struct annoRow *newRow, struct annoRow *qTail)
+/* Die if newRow precedes qTail. */
+{
+if (qTail != NULL)
+    {
+    int cDifNewTail = strcmp(newRow->chrom, qTail->chrom);
+    if (cDifNewTail < 0)
+	errAbort("Unsorted input from internal source (%s < %s)",
+		 newRow->chrom, qTail->chrom);
+    else if (cDifNewTail == 0 && newRow->start < qTail->start)
+	errAbort("Unsorted input from internal source (%s, %u < %u)",
+		 newRow->chrom, newRow->start, qTail->start);
+    }
+}
+
+INLINE void agFetchToEnd(struct annoGrator *self, char *chrom, uint end)
+/* Fetch rows until we are sure we have all items that start to the left of end,
+ * i.e. we have an item that starts at/after end or we hit eof. */
+{
+while (!self->eof &&
+       (self->qTail == NULL || strcmp(self->qTail->chrom, chrom) < 0 || self->qTail->start < end))
+    {
+    struct annoRow *newRow = self->mySource->nextRow(self->mySource);
+    if (newRow == NULL)
+	self->eof = TRUE;
+    else
+	{
+	agCheckInternalSorting(newRow, self->qTail);
+	int cDifNewP = strcmp(newRow->chrom, chrom);
+	if (cDifNewP < 0)
+	    // newRow->chrom comes before chrom; skip over newRow
+	    annoRowFree(&newRow, (struct annoStreamer *)self);
+	else
+	    {
+	    // Add newRow to qTail
+	    if (self->qTail == NULL)
+		{
+		if (self->qHead != NULL)
+		    errAbort("qTail is NULL but qHead is non-NULL");
+		self->qHead = self->qTail = newRow;
+		}
+	    else
+		{
+		self->qTail->next = newRow;
+		self->qTail = newRow;
+		}
+	    if (cDifNewP > 0)
+		// newRow->chrom comes after chrom; we're done for now
+		break;
+	    }
+	}
+    }
+}
+
+struct annoRow *annoGratorIntegrate(struct annoGrator *self, struct annoRow *primaryRow,
+				    boolean *retRJFilterFailed)
+/* Given a single row from the primary source, get all overlapping rows from internal
+ * source, and produce joined output rows.  If retRJFilterFailed is non-NULL and any
+ * overlapping row has a rightJoin filter failure (see annoFilter.h),
+ * set retRJFilterFailed and stop. */
+{
+struct annoRow *rowList = NULL;
+agCheckPrimarySorting(self, primaryRow);
+agTrimToStart(self, primaryRow->chrom, primaryRow->start);
+agFetchToEnd(self, primaryRow->chrom, primaryRow->end);
+boolean rjFailHard = (retRJFilterFailed != NULL);
+if (rjFailHard)
+    *retRJFilterFailed = FALSE;
+struct annoRow *qRow;
+for (qRow = self->qHead;  qRow != NULL;  qRow = qRow->next)
+    {
+    if (qRow->start < primaryRow->end && qRow->end > primaryRow->start &&
+	sameString(qRow->chrom, primaryRow->chrom))
+	{
+	slAddHead(&rowList, annoRowClone(qRow, self->mySource));
+	if (rjFailHard && qRow->rightJoinFail)
+	    {
+	    *retRJFilterFailed = TRUE;
+	    break;
+	    }
+	}
+    }
+slReverse(&rowList);
+// If no rows overlapped primary, and there is a right-join, !isExclude (i.e. isInclude) filter,
+// then we need to set retRJFilterFailed because the condition was not met to include
+// the primary item.
+if (rowList == NULL && rjFailHard && self->haveRJIncludeFilter)
+    *retRJFilterFailed = TRUE;
+return rowList;
+}
+
+void annoGratorClose(struct annoStreamer **pSelf)
+/* Free self (including mySource). */
+{
+if (pSelf == NULL)
+    return;
+struct annoGrator *self = *(struct annoGrator **)pSelf;
+annoRowFreeList(&(self->qHead), self->mySource);
+self->mySource->close(&(self->mySource));
+freeMem(self->prevPChrom);
+freez(pSelf);
+}
+
+static struct annoRow *noNextRow(struct annoStreamer *self)
+/* nextRow() is N/A for annoGrator, which needs caller to use integrate() instead. */
+{
+errAbort("nextRow() called on annoGrator object, but integrate() should be called instead");
+return NULL;
+}
+
+static void agReset(struct annoGrator *self)
+/* Reset all position associated with state */
+{
+freez(&self->prevPChrom);
+self->prevPStart = 0;
+self->eof = FALSE;
+annoRowFreeList(&(self->qHead), (struct annoStreamer *)self);
+self->qTail = NULL;
+}
+
+static boolean filtersHaveRJInclude(struct annoFilter *filters)
+/* Return TRUE if filters have at least one active filter with !isExclude && rightJoin. */
+{
+struct annoFilter *filter;
+for (filter = filters;  filter != NULL;  filter = filter->next)
+    if (filter->op != afNoFilter && !filter->isExclude && filter->rightJoin)
+	return TRUE;
+return FALSE;
+}
+
+static void agSetFilters(struct annoStreamer *vSelf, struct annoFilter *newFilters)
+/* Update filters and re-evaluate self->haveRJIncludeFilter */
+{
+annoStreamerSetFilters(vSelf, newFilters);
+struct annoGrator *self = (struct annoGrator *)vSelf;
+self->haveRJIncludeFilter = filtersHaveRJInclude(vSelf->filters);
+}
+
+void annoGratorSetRegion(struct annoStreamer *vSelf, char *chrom, uint rStart, uint rEnd)
+/* Set genomic region for query, and reset internal state. */
+{
+struct annoGrator *self = (struct annoGrator *)vSelf;
+self->mySource->setRegion((struct annoStreamer *)(self->mySource), chrom, rStart, rEnd);
+agReset(self);
+}
+
+void annoGratorSetQuery(struct annoStreamer *vSelf, struct annoGratorQuery *query)
+/* Set query (to be called only by annoGratorQuery which is created after streamers). */
+{
+struct annoGrator *self = (struct annoGrator *)vSelf;
+self->streamer.query = query;
+self->mySource->setQuery((struct annoStreamer *)(self->mySource), query);
+}
+
+struct annoGrator *annoGratorNew(struct annoStreamer *mySource)
+/* Make a new integrator of columns from mySource with (positions of) rows passed to integrate().
+ * mySource becomes property of the new annoGrator. */
+{
+struct annoGrator *self;
+AllocVar(self);
+struct annoStreamer *streamer = &(self->streamer);
+annoStreamerInit(streamer, mySource->getAutoSqlObject(mySource));
+streamer->rowType = mySource->rowType;
+streamer->setFilters = agSetFilters;
+streamer->setRegion = annoGratorSetRegion;
+streamer->setQuery = annoGratorSetQuery;
+streamer->nextRow = noNextRow;
+streamer->close = annoGratorClose;
+self->integrate = annoGratorIntegrate;
+self->mySource = mySource;
+self->haveRJIncludeFilter = filtersHaveRJInclude(streamer->filters);
+return self;
+}
diff --git a/lib/annoGratorQuery.c b/lib/annoGratorQuery.c
new file mode 100644
index 0000000..10aa08a
--- /dev/null
+++ b/lib/annoGratorQuery.c
@@ -0,0 +1,153 @@
+/* annoGratorQuery -- framework for integrating genomic annotations from many sources */
+
+#include "annoGratorQuery.h"
+#include "errabort.h"
+#include "obscure.h"
+
+struct annoGratorQuery *annoGratorQueryNew(char *assemblyName, struct hash *chromSizes,
+					   struct twoBitFile *tbf,
+					   struct annoStreamer *primarySource,
+					   struct annoGrator *integrators,
+					   struct annoFormatter *formatters)
+/* Create an annoGratorQuery from all of its components, and introduce components to each other.
+ * Either chromSizes or tbf may be NULL.  integrators may be NULL.
+ * All other inputs must be non-NULL. */
+{
+if (assemblyName == NULL)
+    errAbort("annoGratorQueryNew: assemblyName can't be NULL");
+if (chromSizes == NULL && tbf == NULL)
+    errAbort("annoGratorQueryNew: chromSizes and tbf can't both be NULL");
+if (primarySource == NULL)
+    errAbort("annoGratorQueryNew: primarySource can't be NULL");
+if (formatters == NULL)
+    errAbort("annoGratorQueryNew: formatters can't be NULL");
+struct annoGratorQuery *query = NULL;
+AllocVar(query);
+if (tbf != NULL)
+    {
+    if (chromSizes != NULL)
+	{
+	// Ensure that tbf and chromSizes are consistent.
+	struct hashEl *hel;
+	struct hashCookie cookie = hashFirst(chromSizes);
+	while ((hel = hashNext(&cookie)) != NULL)
+	    {
+	    char *chrom = hel->name;
+	    int size = ptToInt(hel->val);
+	    int tbfSize = twoBitSeqSize(tbf, chrom);
+	    if (tbfSize != size)
+		errAbort("Inconsistent size for %s: %s has %d but chromSizes hash has %d",
+			 chrom, tbf->fileName, tbfSize, size);
+	    }
+	}
+    else
+	{
+	// Make our own chromSizes from tbf info.  We will leak this but I don't expect
+	// many annoGratorQuery's in the same process.
+	chromSizes = hashNew(0);
+	struct slName *tbfSeqs = twoBitSeqNames(tbf->fileName), *seq;
+	for (seq = tbfSeqs;  seq != NULL;  seq = seq->next)
+	    hashAddInt(chromSizes, seq->name, twoBitSeqSize(tbf, seq->name));
+	query->csAllocdHere = TRUE;
+	}
+    }
+query->assemblyName = cloneString(assemblyName);
+query->chromSizes = chromSizes;
+query->tbf = tbf;
+query->primarySource = primarySource;
+query->integrators = integrators;
+query->formatters = formatters;
+// Set streamers' and formatters' query pointer.
+primarySource->setQuery(primarySource, query);
+struct annoStreamer *grator = (struct annoStreamer *)(query->integrators);
+for (;  grator != NULL;  grator = grator->next)
+    grator->setQuery(grator, query);
+struct annoFormatter *formatter;
+for (formatter = query->formatters;  formatter != NULL;  formatter = formatter->next)
+    formatter->initialize(formatter, query);
+return query;
+}
+
+void annoGratorQuerySetRegion(struct annoGratorQuery *query, char *chrom, uint rStart, uint rEnd)
+/* Set genomic region for query; if chrom is NULL, position is whole genome. */
+{
+if (chrom != NULL)
+    {
+    uint chromSize = (uint)hashIntVal(query->chromSizes, chrom);
+    if (rEnd < rStart)
+	errAbort("annoGratorQuerySetRegion: rStart (%u) can't be greater than rEnd (%u)",
+		 rStart, rEnd);
+    if (rEnd > chromSize)
+	errAbort("annoGratorQuerySetRegion: rEnd (%u) can't be greater than chrom %s size (%u)",
+		 rEnd, chrom, chromSize);
+    if (rEnd == 0)
+	rEnd = chromSize;
+    }
+// Alert all streamers that they should now send data from a possibly different region:
+query->primarySource->setRegion(query->primarySource, chrom, rStart, rEnd);
+struct annoStreamer *grator = (struct annoStreamer *)(query->integrators);
+for (;  grator != NULL;  grator = grator->next)
+    grator->setRegion(grator, chrom, rStart, rEnd);
+//#*** formatters should be told too, in case the info should go in the header, or if
+//#*** they should clip output to search region....
+}
+
+void annoGratorQueryExecute(struct annoGratorQuery *query)
+/* For each annoRow from query->primarySource, invoke integrators and pass their annoRows
+ * to formatters. */
+{
+struct annoStreamer *primarySrc = query->primarySource;
+struct annoFormatter *formatter = NULL;
+struct annoRow *primaryRow = NULL;
+while ((primaryRow = primarySrc->nextRow(primarySrc)) != NULL)
+    {
+    if (primaryRow->rightJoinFail)
+	continue;
+    struct slRef *gratorRowList = NULL;
+    boolean rjFilterFailed = FALSE;
+    struct annoStreamer *grator = (struct annoStreamer *)(query->integrators);
+    for (;  grator != NULL;  grator = grator->next)
+	{
+	struct annoGrator *realGrator = (struct annoGrator *)grator;
+	struct annoRow *gratorRows = realGrator->integrate(realGrator, primaryRow, &rjFilterFailed);
+	slAddHead(&gratorRowList, slRefNew(gratorRows));
+	if (rjFilterFailed)
+	    break;
+	}
+    slReverse(&gratorRowList);
+    for (formatter = query->formatters;  formatter != NULL;  formatter = formatter->next)
+	if (!rjFilterFailed)
+	    formatter->formatOne(formatter, primaryRow, gratorRowList);
+    annoRowFree(&primaryRow, primarySrc);
+    struct slRef *oneRowList = gratorRowList;
+    grator = (struct annoStreamer *)(query->integrators);
+    for (;  oneRowList != NULL;  oneRowList = oneRowList->next, grator = grator->next)
+	annoRowFreeList((struct annoRow **)&(oneRowList->val), grator);
+    slFreeList(&oneRowList);
+    }
+}
+
+void annoGratorQueryFree(struct annoGratorQuery **pQuery)
+/* Close and free all inputs and outputs; free self. */
+{
+if (pQuery == NULL)
+    return;
+struct annoGratorQuery *query = *pQuery;
+freez(&(query->assemblyName));
+if (query->csAllocdHere)
+    hashFree(&(query->chromSizes));
+query->primarySource->close(&(query->primarySource));
+struct annoStreamer *grator = (struct annoStreamer *)(query->integrators), *nextGrator;
+for (;  grator != NULL;  grator = nextGrator)
+    {
+    nextGrator = grator->next;
+    grator->close(&grator);
+    }
+struct annoFormatter *formatter, *nextFormatter;
+for (formatter = query->formatters;  formatter != NULL;  formatter = nextFormatter)
+    {
+    nextFormatter = formatter->next;
+    formatter->close(&formatter);
+    }
+freez(pQuery);
+}
diff --git a/lib/annoOption.c b/lib/annoOption.c
new file mode 100644
index 0000000..351d47c
--- /dev/null
+++ b/lib/annoOption.c
@@ -0,0 +1,97 @@
+/* annoOption -- optionSpec-style param plus its value */
+
+#include "annoOption.h"
+
+struct annoOption *annoOptionCloneList(struct annoOption *list)
+/* Return a newly allocated copy of list. */
+{
+struct annoOption *newList = NULL, *afo;
+for (afo = list;  afo != NULL;  afo = afo->next)
+    {
+    struct annoOption *newAfo = CloneVar(afo);
+    newAfo->spec.name = cloneString(afo->spec.name);
+    newAfo->value = NULL;
+    unsigned opFlags = opFlags;
+    if (opFlags & OPTION_MULTI)
+	{
+	switch (opFlags & OPTION_TYPE_MASK)
+	    {
+	    case OPTION_STRING:
+		newAfo->value = slNameCloneList((struct slName *)(afo->value));
+		break;
+	    default:
+		errAbort("annoOptionCloneList: OPTION_MULTI implemented only for "
+			 "OPTION_STRING (not 0x%x)", opFlags);
+	    }
+	}
+    else
+	{
+	switch (opFlags & OPTION_TYPE_MASK)
+	    {
+	    // For numeric singleton values, we are overloading value.
+	    case OPTION_DOUBLE:
+	    case OPTION_FLOAT:
+	    case OPTION_LONG_LONG:
+	    case OPTION_INT:
+	    case OPTION_BOOLEAN:
+		newAfo->value = afo->value;
+		break;
+	    case OPTION_STRING:
+		newAfo->value = cloneString((char *)afo->value);
+		break;
+	    default:
+		errAbort("annoOptionCloneList: unrecognized op type 0x%x", opFlags);
+	    }
+	}
+    slAddHead(&newList, newAfo);
+    }
+slReverse(&newList);
+return newList;
+}
+
+void annoOptionFreeList(struct annoOption **pList)
+/* Free the same things that we clone above. */
+{
+if (pList == NULL)
+    return;
+struct annoOption *afo, *nextAfo;
+for (afo = *pList;  afo != NULL;  afo = nextAfo)
+    {
+    nextAfo = afo->next;
+    freeMem(afo->spec.name);
+    unsigned opFlags = opFlags;
+    if (opFlags & OPTION_MULTI)
+	{
+	switch (opFlags & OPTION_TYPE_MASK)
+	    {
+	    case OPTION_STRING:
+		slNameFreeList(&(afo->value));
+		break;
+	    default:
+		errAbort("annoOptionFreeList: OPTION_MULTI implemented only for "
+			 "OPTION_STRING (not 0x%x)", opFlags);
+	    }
+	}
+    else
+	{
+	switch (opFlags & OPTION_TYPE_MASK)
+	    {
+	    // No need to free overloaded numeric values
+	    case OPTION_DOUBLE:
+	    case OPTION_FLOAT:
+	    case OPTION_LONG_LONG:
+	    case OPTION_INT:
+	    case OPTION_BOOLEAN:
+		break;
+	    case OPTION_STRING:
+		freeMem(afo->value);
+		break;
+	    default:
+		errAbort("annoOptionFreeList: unrecognized op type 0x%x", opFlags);
+	    }
+	}
+    freeMem(afo);
+    }
+*pList = NULL;
+}
+
diff --git a/lib/annoRow.c b/lib/annoRow.c
new file mode 100644
index 0000000..cc26b26
--- /dev/null
+++ b/lib/annoRow.c
@@ -0,0 +1,105 @@
+/* annoRow -- basic data interchange unit of annoGratorQuery framework. */
+
+#include "annoRow.h"
+#include "annoStreamer.h"
+
+struct annoRow *annoRowFromStringArray(char *chrom, uint start, uint end, boolean rightJoinFail,
+				       char **wordsIn, int numCols)
+/* Allocate & return an annoRow with words cloned from wordsIn. */
+{
+struct annoRow *aRow;
+AllocVar(aRow);
+aRow->chrom = cloneString(chrom);
+aRow->start = start;
+aRow->end = end;
+aRow->rightJoinFail = rightJoinFail;
+char **words;
+AllocArray(words, numCols);
+int i;
+for (i = 0;  i < numCols;  i++)
+    words[i] = cloneString(wordsIn[i]);
+aRow->data = words;
+return aRow;
+}
+
+struct annoRow *annoRowWigNew(char *chrom, uint start, uint end, boolean rightJoinFail,
+			      float *values)
+/* Allocate & return an annoRowWig, with clone of values; length of values is (end-start). */
+{
+struct annoRow *row;
+AllocVar(row);
+row->chrom = cloneString(chrom);
+row->start = start;
+row->end = end;
+row->data = cloneMem(values, (end - start) * sizeof(values[0]));
+row->rightJoinFail = rightJoinFail;
+return row;
+}
+
+struct annoRow *annoRowClone(struct annoRow *rowIn, struct annoStreamer *source)
+/* Allocate & return a single annoRow cloned from rowIn. */
+{
+if (rowIn == NULL)
+    return NULL;
+if (source->rowType == arWords || source->rowType == arVcf)
+    return annoRowFromStringArray(rowIn->chrom, rowIn->start, rowIn->end, rowIn->rightJoinFail,
+				  rowIn->data, source->numCols);
+else if (source->rowType == arWig)
+    return annoRowWigNew(rowIn->chrom, rowIn->start, rowIn->end, rowIn->rightJoinFail,
+			 (float *)rowIn->data);
+else
+    errAbort("annoRowClone: unrecognized type %d", source->rowType);
+return NULL;
+}
+
+static void annoRowWordsFree(struct annoRow **pRow, int numCols)
+/* Free a single annoRow with type arWords. */
+{
+if (pRow == NULL)
+    return;
+struct annoRow *row = *pRow;
+freeMem(row->chrom);
+char **words = row->data;
+int i;
+for (i = 0;  i < numCols;  i++)
+    freeMem(words[i]);
+freeMem(row->data);
+freez(pRow);
+}
+
+static void annoRowWigFree(struct annoRow **pRow)
+/* Free a single annoRow with type arWig. */
+{
+if (pRow == NULL)
+    return;
+struct annoRow *row = *pRow;
+freeMem(row->chrom);
+freeMem(row->data);
+freez(pRow);
+}
+
+void annoRowFree(struct annoRow **pRow, struct annoStreamer *source)
+/* Free a single annoRow. */
+{
+if (pRow == NULL)
+    return;
+if (source->rowType == arWords || source->rowType == arVcf)
+    annoRowWordsFree(pRow, source->numCols);
+else if (source->rowType == arWig)
+    annoRowWigFree(pRow);
+else
+    errAbort("annoRowFree: unrecognized type %d", source->rowType);
+}
+
+void annoRowFreeList(struct annoRow **pList, struct annoStreamer *source)
+/* Free a list of annoRows. */
+{
+if (pList == NULL)
+    return;
+struct annoRow *row, *nextRow;
+for (row = *pList;  row != NULL;  row = nextRow)
+    {
+    nextRow = row->next;
+    annoRowFree(&row, source);
+    }
+}
diff --git a/lib/annoStreamVcf.c b/lib/annoStreamVcf.c
new file mode 100644
index 0000000..e0ffee1
--- /dev/null
+++ b/lib/annoStreamVcf.c
@@ -0,0 +1,143 @@
+/* annoStreamVcf -- subclass of annoStreamer for VCF files */
+
+#include "annoStreamVcf.h"
+#include "vcf.h"
+
+struct annoStreamVcf
+{
+    struct annoStreamer streamer;	// Parent class members & methods
+    // Private members
+    struct vcfFile *vcff;		// VCF parsed header and file object
+    struct vcfRecord *record;		// Current parsed row of VCF (need this for chromEnd)
+    char *asWords[VCF_NUM_COLS];	// Current row of VCF with genotypes squashed for autoSql
+    struct dyString *dyGt;		// Scratch space for squashing genotype columns
+    int numCols;			// Number of columns in autoSql def of VCF.
+    int numFileCols;			// Number of columns in VCF file.
+    boolean isTabix;			// True if we are accessing compressed VCF via tabix index
+//#*** we need a way to pass the VCF header to the VCF formatter.
+//#*** streamer getHeader method??
+};
+
+
+static void asvSetRegion(struct annoStreamer *vSelf, char *chrom, uint regionStart, uint regionEnd)
+/* Set region -- and free current sqlResult if there is one. */
+{
+annoStreamerSetRegion(vSelf, chrom, regionStart, regionEnd);
+struct annoStreamVcf *self = (struct annoStreamVcf *)vSelf;
+if (self->isTabix)
+    lineFileSetTabixRegion(self->vcff->lf, chrom, regionStart, regionEnd);
+else if (chrom != NULL)
+    errAbort("annoStreamVcf: setRegion not yet implemented for non-tabix VCF.");
+}
+
+static char *asvGetHeader(struct annoStreamer *vSelf)
+/* Return VCF header (e.g. for use by formatter) */
+{
+struct annoStreamVcf *self = (struct annoStreamVcf *)vSelf;
+return cloneString(self->vcff->headerString);
+}
+
+static char **nextRowUnfiltered(struct annoStreamVcf *self)
+/* Get the next VCF record and put the row text into autoSql words.
+ * Return pointer to self->asWords if we get a row, otherwise NULL. */
+{
+char *words[self->numFileCols];
+int wordCount;
+if ((wordCount = lineFileChop(self->vcff->lf, words)) <= 0)
+    return NULL;
+lineFileExpectWords(self->vcff->lf, self->numFileCols, wordCount);
+int i;
+// First 8 columns are always in the VCF file:
+for (i = 0;  i < 8;  i++)
+    {
+    freeMem(self->asWords[i]);
+    self->asWords[i] = cloneString(words[i]);
+    }
+// Depending on whether VCF contains genotypes, number of file columns may be
+// smaller or larger than number of autoSql columns:
+if (self->vcff->genotypeCount > 0)
+    {
+    self->asWords[8] = words[8];
+    dyStringClear(self->dyGt);
+    for (i = 0;  i < self->vcff->genotypeCount;  i++)
+	{
+	if (i > 0)
+	    dyStringAppendC(self->dyGt, '\t');
+	dyStringAppend(self->dyGt, words[9+i]);
+	}
+    self->asWords[9] = self->dyGt->string;
+    }
+else
+    {
+    self->asWords[8] = "";
+    self->asWords[9] = "";
+    }
+self->record = vcfRecordFromRow(self->vcff, words);
+return self->asWords;
+}
+
+static struct annoRow *asvNextRow(struct annoStreamer *vSelf)
+/* Return an annoRow encoding the next VCF record, or NULL if there are no more items. */
+{
+struct annoStreamVcf *self = (struct annoStreamVcf *)vSelf;
+char **words = nextRowUnfiltered(self);
+if (words == NULL)
+    return NULL;
+// Skip past any left-join failures until we get a right-join failure, a passing row, or EOF.
+boolean rightFail = FALSE;
+while (annoFilterRowFails(vSelf->filters, words, self->numCols, &rightFail))
+    {
+    if (rightFail)
+	break;
+    words = nextRowUnfiltered(self);
+    if (words == NULL)
+	return NULL;
+    }
+struct vcfRecord *rec = self->record;
+return annoRowFromStringArray(rec->chrom, rec->chromStart, rec->chromEnd,
+			      rightFail, words, self->numCols);
+}
+
+static void asvClose(struct annoStreamer **pVSelf)
+/* Close VCF file and free self. */
+{
+if (pVSelf == NULL)
+    return;
+struct annoStreamVcf *self = *(struct annoStreamVcf **)pVSelf;
+vcfFileFree(&(self->vcff));
+// Don't free self->record -- currently it belongs to vcff's localMem
+dyStringFree(&(self->dyGt));
+annoStreamerFree(pVSelf);
+}
+
+struct annoStreamer *annoStreamVcfNew(char *fileOrUrl, boolean isTabix, int maxRecords)
+/* Create an annoStreamer (subclass) object from a VCF file, which may
+ * or may not have been compressed and indexed by tabix. */
+{
+int maxErr = -1; // don't errAbort on VCF format warnings/errs
+struct vcfFile *vcff;
+if (isTabix)
+    vcff = vcfTabixFileMayOpen(fileOrUrl, NULL, 0, 0, maxErr, maxRecords);
+else
+    vcff = vcfFileMayOpen(fileOrUrl, maxErr, maxRecords, FALSE);
+if (vcff == NULL)
+    errAbort("Unable to open VCF: '%s'", fileOrUrl);
+struct annoStreamVcf *self;
+AllocVar(self);
+struct annoStreamer *streamer = &(self->streamer);
+struct asObject *asObj = vcfAsObj();
+annoStreamerInit(streamer, asObj);
+streamer->rowType = arVcf;
+streamer->setRegion = asvSetRegion;
+streamer->getHeader = asvGetHeader;
+streamer->nextRow = asvNextRow;
+streamer->close = asvClose;
+self->vcff = vcff;
+self->dyGt = dyStringNew(1024);
+self->isTabix = isTabix;
+self->numCols = slCount(asObj->columnList);
+self->numFileCols = 8;
+if (vcff->genotypeCount > 0)
+    self->numFileCols = 9 + vcff->genotypeCount;
+return (struct annoStreamer *)self;
+}
diff --git a/lib/annoStreamer.c b/lib/annoStreamer.c
new file mode 100644
index 0000000..202cc80
--- /dev/null
+++ b/lib/annoStreamer.c
@@ -0,0 +1,104 @@
+/* annoStreamer -- returns items sorted by genomic position to successive nextRow calls */
+
+#include "annoStreamer.h"
+#include "errabort.h"
+
+// ----------------------- annoStreamer base methods --------------------------
+
+struct asObject *annoStreamerGetAutoSqlObject(struct annoStreamer *self)
+/* Return parsed autoSql definition of this streamer's data type. */
+{
+return self->asObj;
+}
+
+void annoStreamerSetRegion(struct annoStreamer *self, char *chrom, uint rStart, uint rEnd)
+/* Set genomic region for query; if chrom is NULL, position is genome.
+ * Many subclasses should make their own setRegion method that calls this and
+ * configures their data connection to change to the new position. */
+{
+freez(&(self->chrom));
+if (chrom == NULL)
+    {
+    self->positionIsGenome = TRUE;
+    self->regionStart = self->regionEnd = 0;
+    }
+else
+    {
+    self->positionIsGenome = FALSE;
+    self->chrom = cloneString(chrom);
+    self->regionStart = rStart;
+    self->regionEnd = rEnd;
+    }
+}
+
+static char *annoStreamerGetHeader(struct annoStreamer *self)
+/* Default method: return NULL. */
+{
+return NULL;
+}
+
+struct annoFilter *annoStreamerGetFilters(struct annoStreamer *self)
+/* Return supported filters with current settings.  Callers can modify and free when done. */
+{
+return annoFilterCloneList(self->filters);
+}
+
+void annoStreamerSetFilters(struct annoStreamer *self, struct annoFilter *newFilters)
+/* Free old filters and use clone of newFilters. */
+{
+annoFilterFreeList(&(self->filters));
+self->filters = annoFilterCloneList(newFilters);
+}
+
+struct annoColumn *annoStreamerGetColumns(struct annoStreamer *self)
+/* Return supported columns with current settings.  Callers can modify and free when done. */
+{
+return annoColumnCloneList(self->columns);
+}
+
+void annoStreamerSetColumns(struct annoStreamer *self, struct annoColumn *newColumns)
+/* Free old columns and use clone of newColumns. */
+{
+annoColumnFreeList(&(self->columns));
+self->columns = annoColumnCloneList(newColumns);
+}
+
+void annoStreamerSetQuery(struct annoStreamer *self, struct annoGratorQuery *query)
+/* Set query (to be called only by annoGratorQuery which is created after streamers). */
+{
+self->query = query;
+}
+
+void annoStreamerInit(struct annoStreamer *self, struct asObject *asObj)
+/* Initialize a newly allocated annoStreamer with default annoStreamer methods and
+ * default filters and columns based on asObj.
+ * In general, subclasses' constructors will call this first; override nextRow, close,
+ * and probably setRegion and setQuery; and then initialize their private data. */
+{
+self->getAutoSqlObject = annoStreamerGetAutoSqlObject;
+self->setRegion = annoStreamerSetRegion;
+self->getHeader = annoStreamerGetHeader;
+self->getFilters = annoStreamerGetFilters;
+self->setFilters = annoStreamerSetFilters;
+self->getColumns = annoStreamerGetColumns;
+self->setColumns = annoStreamerSetColumns;
+self->setQuery = annoStreamerSetQuery;
+self->positionIsGenome = TRUE;
+self->asObj = asObj;
+self->filters = annoFiltersFromAsObject(asObj);
+self->columns = annoColumnsFromAsObject(asObj);
+self->numCols = slCount(asObj->columnList);
+}
+
+void annoStreamerFree(struct annoStreamer **pSelf)
+/* Free self. This should be called at the end of subclass close methods, after
+ * subclass-specific connections are closed and resources are freed. */
+{
+if (pSelf == NULL)
+    return;
+struct annoStreamer *self = *pSelf;
+freez(&(self->chrom));
+annoFilterFreeList(&(self->filters));
+annoColumnFreeList(&(self->columns));
+freez(pSelf);
+}
diff --git a/lib/apacheLog.c b/lib/apacheLog.c
new file mode 100644
index 0000000..728100f
--- /dev/null
+++ b/lib/apacheLog.c
@@ -0,0 +1,208 @@
+/* apacheLog - stuff to parse out apache web server logs, currently
+ * just the access log. */
+
+#include "common.h"
+#include "obscure.h"
+#include "apacheLog.h"
+
+
+void apacheAccessLogFree(struct apacheAccessLog **pLl)
+/* Free up apacheAccessLog. */
+{
+struct apacheAccessLog *ll = *pLl;
+if (ll != NULL)
+    {
+    freeMem(ll->buf);
+    freez(pLl);
+    }
+}
+
+
+static void badFormat(struct apacheAccessLog **pLl, char *line, char *fileName, 
+	int lineIx, char *message)
+/* Complain about format if verbose flag is on.  Free up
+ * *pLl */
+{
+if (verboseLevel()  > 1)
+    {
+    if (fileName != NULL)
+	warn("%s line %d: %s", fileName, lineIx, message);
+    else
+	warn("%s", message);
+    }
+}
+
+static void unterminatedQuote(struct apacheAccessLog **pLl, char *line, 
+	char *fileName, int lineIx)
+/* Complain about unterminated quote. */
+{
+badFormat(pLl, line, fileName, lineIx, 
+	"missing closing quote");
+}
+
+static void shortLine(struct apacheAccessLog **pLl, char *line, 
+	char *fileName, int lineIx)
+/* Complain about short line. */
+{
+badFormat(pLl, line, fileName, lineIx, 
+	"short line");
+}
+
+static void badTimeStamp(struct apacheAccessLog **pLl, char *line, 
+	char *fileName, int lineIx)
+/* Complain about bad time stamp. */
+{
+badFormat(pLl, line, fileName, lineIx, 
+	"bad time stamp");
+}
+
+time_t apacheAccessLogTimeToTick(char *timeStamp)
+/* Convert something like 27/Aug/2009:09:25:32 to Unix timestamp (seconds since 1970).
+ * On error returns zero. */
+
+{
+struct tm tm;
+ZeroVar(&tm);
+if (strptime(timeStamp, "%d/%b/%Y:%T", &tm) != NULL)
+    return mktime(&tm);
+else
+    return 0;
+}
+
+struct apacheAccessLog *apacheAccessLogParse(char *line, 
+	char *fileName, int lineIx)
+/* Return a apacheAccessLog from line.  Return NULL if there's a parsing 
+ * problem, but don't abort. */
+{
+struct apacheAccessLog *ll;
+char *buf, *s, *e;
+AllocVar(ll);
+ll->buf = buf = cloneString(line);
+ll->ip = nextWord(&buf);
+ll->dash1 = nextWord(&buf);
+ll->dash2 = nextWord(&buf);
+if (buf == NULL)
+    {
+    shortLine(&ll, line, fileName, lineIx);
+    return NULL;
+    }
+
+/* Parse out bracket enclosed timeStamp and time zone. */
+s = strchr(buf, '[');
+if (s == NULL)
+    {
+    badTimeStamp(&ll, line, fileName, lineIx);
+    return NULL;
+    }
+s += 1;
+e = strchr(s, ']');
+if (e == NULL)
+    {
+    badTimeStamp(&ll, line, fileName, lineIx);
+    return NULL;
+    }
+*e = 0;
+ll->timeStamp = nextWord(&s);
+if (!isdigit(ll->timeStamp[0]))
+    {
+    badTimeStamp(&ll, line, fileName, lineIx);
+    return NULL;
+    }
+ll->timeZone = nextWord(&s);
+
+/* Convert time stamp to Unix tick. */
+ll->tick = apacheAccessLogTimeToTick(ll->timeStamp);
+
+
+buf = e+2;
+if (buf[0] != '"')
+    {
+    badFormat(&ll, line, fileName, lineIx, "Missing quote after time stamp");
+    return NULL;
+    }
+if (!parseQuotedString(buf, buf, &e))
+    {
+    unterminatedQuote(&ll, line, fileName, lineIx);
+    return NULL;
+    }
+ll->method = nextWord(&buf);
+ll->url = nextWord(&buf);
+ll->httpVersion = nextWord(&buf);
+if (ll->url == NULL)
+    {
+    badFormat(&ll, line, fileName, lineIx, "Missing URL");
+    return NULL;
+    }
+buf = e;
+s = nextWord(&buf);
+if (!isdigit(s[0]))
+    {
+    badFormat(&ll, line, fileName, lineIx, "Non-numerical status code");
+    return NULL;
+    }
+ll->status = atoi(s);
+ll->num1 = nextWord(&buf);
+if (buf == NULL)
+    {
+    shortLine(&ll, line, fileName, lineIx);
+    return NULL;
+    }
+if (buf[0] != '"')
+    {
+    badFormat(&ll, line, fileName, lineIx, "Missing quote after request");
+    return NULL;
+    }
+if (!parseQuotedString(buf, buf, &e))
+    {
+    unterminatedQuote(&ll, line, fileName, lineIx);
+    return NULL;
+    }
+if (!sameString(buf, "-"))
+    ll->referrer = buf;
+buf = e + 1;
+if (buf[0] != '"')
+    {
+    badFormat(&ll, line, fileName, lineIx, "Missing quote after referrer");
+    return NULL;
+    }
+if (!parseQuotedString(buf, buf, &e))
+    {
+    unterminatedQuote(&ll, line, fileName, lineIx);
+    return NULL;
+    }
+ll->program = buf;
+
+/* Parse out elapsed time if it's there. */
+ll->runTime = -1;		/* Marker for unset. */
+char *runTime = nextWord(&e);
+char *label = nextWord(&e);
+if (label != NULL)
+    {
+    if (!isdigit(runTime[0]))
+        {
+	badFormat(&ll, line, fileName, lineIx, "non-numerical seconds");
+	return NULL;
+	}
+    int x = atoi(runTime);
+    if (sameString(label, "seconds"))
+        ll->runTime = x*1000;
+    else if (sameString(label, "microseconds"))
+        ll->runTime = x/1000;
+    }
+
+return ll;
+}
+
+int apacheAccessLogCmpTick(const void *va, const void *vb)
+/* Compare items to sort by tick (which tracks timestamp) */
+{
+const struct apacheAccessLog *a = *((struct apacheAccessLog **)va);
+const struct apacheAccessLog *b = *((struct apacheAccessLog **)vb);
+if (a->tick < b->tick)
+    return -1;
+else if (a->tick == b->tick)
+    return 0;
+else
+    return 1;
+}
+
diff --git a/lib/asParse.c b/lib/asParse.c
new file mode 100644
index 0000000..7e69e1f
--- /dev/null
+++ b/lib/asParse.c
@@ -0,0 +1,563 @@
+/* asParse - parse out an autoSql .as file. */
+
+#include "common.h"
+#include "linefile.h"
+#include "tokenizer.h"
+#include "dystring.h"
+#include "asParse.h"
+
+
+/* n.b. switched double/float from %f to %g to partially address losing
+ * precision.  Values like 2e-12 were being rounded to 0.0 with %f.  While %g
+ * doesn't match the precision of the database fields, specifying a larger
+ * precision with %g resulted in numbers like 1.9999999999999999597733e-12,
+ *  which might impact load time.  This issue needs more investigation.*/
+struct asTypeInfo asTypes[] = {
+    {t_double,  "double",  FALSE, FALSE, "double",            "double",        "Double",   "Double",   "%g",   "FloatField"},
+    {t_float,   "float",   FALSE, FALSE, "float",             "float",         "Float",    "Float",    "%g",   "FloatField"},
+    {t_char,    "char",    FALSE, FALSE, "char",              "char",          "Char",     "Char",     "%c",   "CharField"},
+    {t_int,     "int",     FALSE, FALSE, "int",               "int",           "Signed",   "Signed",   "%d",   "IntegerField"},
+    {t_uint,    "uint",    TRUE,  FALSE, "int unsigned",      "unsigned",      "Unsigned", "Unsigned", "%u",   "PositiveIntegerField"},
+    {t_short,   "short",   FALSE, FALSE, "smallint",          "short",         "Short",    "Signed",   "%d",   "SmallIntegerField"},
+    {t_ushort,  "ushort",  TRUE,  FALSE, "smallint unsigned", "unsigned short","Ushort",   "Unsigned", "%u",   "SmallPositiveIntegerField"},
+    {t_byte,    "byte",    FALSE, FALSE, "tinyint",           "signed char",   "Byte",     "Signed",   "%d",   "SmallIntegerField"},
+    {t_ubyte,   "ubyte",   TRUE,  FALSE, "tinyint unsigned",  "unsigned char", "Ubyte",    "Unsigned", "%u",   "SmallPositiveIntegerField"},
+    {t_off,     "bigint",  FALSE, FALSE, "bigint",            "long long",     "LongLong", "LongLong", "%lld", "BigIntegerField"},
+    {t_string,  "string",  FALSE, TRUE,  "varchar(255)",      "char *",        "String",   "String",   "%s",   "CharField"},
+    {t_lstring, "lstring", FALSE, TRUE,  "longblob",          "char *",        "String",   "String",   "%s",   "TextField"},
+    {t_enum,    "enum",    FALSE, FALSE, "enum",              "!error!",       "Enum",     "Enum",     NULL,   "CharField"},
+    {t_set,     "set",     FALSE, FALSE, "set",               "unsigned",      "Set",      "Set",      NULL,   NULL},
+    {t_object,  "object",  FALSE, FALSE, "longblob",          "!error!",       "Object",   "Object",   NULL,   "TextField"},
+    {t_object,  "table",   FALSE, FALSE, "longblob",          "!error!",       "Object",   "Object",   NULL,   "TextField"},
+    {t_simple,  "simple",  FALSE, FALSE, "longblob",          "!error!",       "Simple",   "Simple",   NULL,   "TextField"},
+};
+
+static struct asTypeInfo *findLowType(struct tokenizer *tkz)
+/* Return low type info.  Squawk and die if s doesn't
+ * correspond to one. */
+{
+char *s = tkz->string;
+int i;
+for (i=0; i<ArraySize(asTypes); ++i)
+    {
+    if (sameWord(asTypes[i].name, s))
+	return &asTypes[i];
+    }
+tokenizerErrAbort(tkz, "Unknown type '%s'", s);
+return NULL;
+}
+
+static void sqlSymDef(struct asColumn *col, struct dyString *dy)
+/* print symbolic column definition for sql */
+{
+dyStringPrintf(dy, "%s(", col->lowType->sqlName);
+struct slName *val;
+for (val = col->values; val != NULL; val = val->next)
+    {
+    dyStringPrintf(dy, "\"%s\"", val->name);
+    if (val->next != NULL)
+        dyStringAppend(dy, ", ");
+    }
+dyStringPrintf(dy, ") ");
+}
+
+struct dyString *asColumnToSqlType(struct asColumn *col)
+/* Convert column to a sql type spec in returned dyString */
+{
+struct asTypeInfo *lt = col->lowType;
+struct dyString *type = dyStringNew(32);
+if ((lt->type == t_enum) || (lt->type == t_set))
+    sqlSymDef(col, type);
+else if (col->isList || col->isArray)
+    dyStringPrintf(type, "longblob");
+else if (lt->type == t_char)
+    dyStringPrintf(type, "char(%d)", col->fixedSize ? col->fixedSize : 1);
+else
+    dyStringPrintf(type, "%s", lt->sqlName);
+return type;
+}
+
+char *asTypeNameFromSqlType(char *sqlType)
+/* Return the autoSql type name (not enum) for the given SQL type, or NULL.
+ * Don't attempt to free result. */
+{
+if (sqlType == NULL)
+    return NULL;
+// We need to strip '(...)' strings from all types except 'varchar' which must be 'varchar(255)'
+int len = strlen(sqlType) + 8;
+char buf[len];
+if (startsWith("varchar", sqlType))
+    safecpy(buf, len, "varchar(255)");
+else
+    {
+    safecpy(buf, len, sqlType);
+    char *leftParen = strstr(buf, " (");
+    if (leftParen == NULL)
+	leftParen = strchr(buf, '(');
+    if (leftParen != NULL)
+	{
+	char *rightParen = strrchr(leftParen, ')');
+	if (rightParen != NULL)
+	    {
+	    strcpy(leftParen, rightParen+1);
+	    }
+	}
+    }
+int i;
+for (i = 0;  i < ArraySize(asTypes);  i++)
+    if (sameString(buf, asTypes[i].sqlName))
+	return asTypes[i].name;
+return NULL;
+}
+
+static struct asColumn *mustFindColumn(struct asObject *table, char *colName)
+/* Return column or die. */
+{
+struct asColumn *col;
+
+for (col = table->columnList; col != NULL; col = col->next)
+    {
+    if (sameWord(col->name, colName))
+	return col;
+    }
+errAbort("Couldn't find column %s", colName);
+return NULL;
+}
+
+static struct asObject *findObType(struct asObject *objList, char *obName)
+/* Find object with given name. */
+{
+struct asObject *obj;
+for (obj = objList; obj != NULL; obj = obj->next)
+    {
+    if (sameWord(obj->name, obName))
+	return obj;
+    }
+return NULL;
+}
+
+static void asParseColArraySpec(struct tokenizer *tkz, struct asObject *obj,
+                                struct asColumn *col)
+/* parse the array length specification for a column */
+{
+if (col->lowType->type == t_simple)
+    col->isArray = TRUE;
+else
+    col->isList = TRUE;
+tokenizerMustHaveNext(tkz);
+if (isdigit(tkz->string[0]))
+    {
+    col->fixedSize = atoi(tkz->string);
+    tokenizerMustHaveNext(tkz);
+    }
+else if (isalpha(tkz->string[0]))
+    {
+#ifdef OLD
+    if (obj->isSimple)
+        tokenizerErrAbort(tkz, "simple objects can't include variable length arrays\n");
+#endif /* OLD */
+    col->linkedSizeName = cloneString(tkz->string);
+    col->linkedSize = mustFindColumn(obj, col->linkedSizeName);
+    col->linkedSize->isSizeLink = TRUE;
+    tokenizerMustHaveNext(tkz);
+    }
+else
+    tokenizerErrAbort(tkz, "must have column name or integer inside []'s\n");
+tokenizerMustMatch(tkz, "]");
+}
+
+static void asParseColSymSpec(struct tokenizer *tkz, struct asObject *obj,
+                              struct asColumn *col)
+/* parse the enum or set symbolic values for a column */
+{
+tokenizerMustHaveNext(tkz);
+while (tkz->string[0] != ')')
+    {
+    slSafeAddHead(&col->values, slNameNew(tkz->string));
+    /* look for `,' or `)', but allow `,' after last token */
+    tokenizerMustHaveNext(tkz);
+    if (!((tkz->string[0] == ',') || (tkz->string[0] == ')')))
+        tokenizerErrAbort(tkz, "expected `,' or `)' got `%s'", tkz->string);
+    if (tkz->string[0] != ')')
+        tokenizerMustHaveNext(tkz);
+    }
+tokenizerMustMatch(tkz, ")");
+slReverse(&col->values);
+}
+
+static void asParseColDef(struct tokenizer *tkz, struct asObject *obj)
+/* Parse a column definintion */
+{
+struct asColumn *col;
+AllocVar(col);
+
+col->lowType = findLowType(tkz);
+tokenizerMustHaveNext(tkz);
+
+if (col->lowType->type == t_object || col->lowType->type == t_simple)
+    {
+    col->obName = cloneString(tkz->string);
+    tokenizerMustHaveNext(tkz);
+    }
+
+if (tkz->string[0] == '[')
+    asParseColArraySpec(tkz, obj, col);
+else if (tkz->string[0] == '(')
+    asParseColSymSpec(tkz, obj, col);
+
+col->name = cloneString(tkz->string);
+tokenizerMustHaveNext(tkz);
+tokenizerMustMatch(tkz, ";");
+col->comment = cloneString(tkz->string);
+tokenizerMustHaveNext(tkz);
+if (col->lowType->type == t_char && col->fixedSize != 0)
+    col->isList = FALSE;	/* It's not really a list... */
+slAddHead(&obj->columnList, col);
+}
+
+static struct asObject *asParseTableDef(struct tokenizer *tkz)
+/* Parse a table or object definintion */
+{
+struct asObject *obj;
+AllocVar(obj);
+if (sameWord(tkz->string, "table"))
+    obj->isTable = TRUE;
+else if (sameWord(tkz->string, "simple"))
+    obj->isSimple = TRUE;
+else if (sameWord(tkz->string, "object"))
+    ;
+else
+    tokenizerErrAbort(tkz, "Expecting 'table' or 'object' got '%s'", tkz->string);
+tokenizerMustHaveNext(tkz);
+obj->name = cloneString(tkz->string);
+tokenizerMustHaveNext(tkz);
+obj->comment = cloneString(tkz->string);
+
+/* parse columns */
+tokenizerMustHaveNext(tkz);
+tokenizerMustMatch(tkz, "(");
+while (tkz->string[0] != ')')
+    asParseColDef(tkz, obj);
+slReverse(&obj->columnList);
+return obj;
+}
+
+static void asLinkEmbeddedObjects(struct asObject *obj, struct asObject *objList)
+/* Look up any embedded objects. */
+{
+struct asColumn *col;
+for (col = obj->columnList; col != NULL; col = col->next)
+    {
+    if (col->obName != NULL)
+        {
+        if ((col->obType = findObType(objList, col->obName)) == NULL)
+            errAbort("%s used but not defined", col->obName);
+        if (obj->isSimple)
+            {
+            if (!col->obType->isSimple)
+                errAbort("Simple object %s with embedded non-simple object %s",
+                    obj->name, col->name);
+            }
+        }
+    }
+}
+
+static struct asObject *asParseTokens(struct tokenizer *tkz)
+/* Parse file into a list of objects. */
+{
+struct asObject *objList = NULL;
+struct asObject *obj;
+
+while (tokenizerNext(tkz))
+    {
+    obj = asParseTableDef(tkz);
+    if (findObType(objList, obj->name))
+        tokenizerErrAbort(tkz, "Duplicate definition of %s", obj->name);
+    slAddTail(&objList, obj);
+    }
+
+for (obj = objList; obj != NULL; obj = obj->next)
+    asLinkEmbeddedObjects(obj, objList);
+
+return objList;
+}
+
+char *asTypesIntSizeDescription(enum asTypes type)
+/* Return description of integer size.  Do not free. */
+{
+int size = asTypesIntSize(type);
+switch (size)
+    {
+    case 1:
+	return "byte";
+    case 2:
+	return "short integer";
+    case 4:
+	return "integer";
+    case 8:
+	return "long long integer";
+    default:
+        errAbort("Unexpected error in asTypesIntSizeDescription: expecting integer type size of 1, 2, 4, or 8.  Got %d.", size);
+	return NULL; // happy compiler, never gets here
+    
+    }
+}
+
+int asTypesIntSize(enum asTypes type)
+/* Return size in bytes of any integer type - short, long, unsigned, etc. */
+{
+switch (type)
+    {
+    case t_int:
+    case t_uint:
+	return 4;
+    case t_short:
+    case t_ushort:
+	return 2;
+    case t_byte:
+    case t_ubyte:
+	return 1;
+    case t_off:
+	return 8;
+    default:
+        errAbort("Unexpected error in  asTypesIntSize: expecting integer type.  Got %d.", type);
+	return 0; // happy compiler, never gets here
+    }
+}
+
+boolean asTypesIsUnsigned(enum asTypes type)
+/* Return TRUE if it's any integer type - short, long, unsigned, etc. */
+{
+switch (type)
+    {
+    case t_uint:
+    case t_ushort:
+    case t_ubyte:
+       return TRUE;
+    default:
+       return FALSE;
+    }
+}
+
+boolean asTypesIsInt(enum asTypes type)
+/* Return TRUE if it's any integer type - short, long, unsigned, etc. */
+{
+switch (type)
+    {
+    case t_int:
+    case t_uint:
+    case t_short:
+    case t_ushort:
+    case t_byte:
+    case t_ubyte:
+    case t_off:
+       return TRUE;
+    default:
+       return FALSE;
+    }
+}
+
+boolean asTypesIsFloating(enum asTypes type)
+/* Return TRUE if it's any floating point type - float or double. */
+{
+switch (type)
+    {
+    case t_float:
+    case t_double:
+       return TRUE;
+    default:
+       return FALSE;
+    }
+}
+
+static struct asObject *asParseLineFile(struct lineFile *lf)
+/* Parse open line file.  Closes lf as a side effect. */
+{
+struct tokenizer *tkz = tokenizerOnLineFile(lf);
+struct asObject *objList = asParseTokens(tkz);
+tokenizerFree(&tkz);
+return objList;
+}
+
+
+void asColumnFree(struct asColumn **pAs)
+/* free a single asColumn */
+{
+struct asColumn *as = *pAs;
+if (as != NULL)
+    {
+    freeMem(as->name);
+    freeMem(as->comment);
+    freez(pAs);
+    }
+}
+
+
+void asColumnFreeList(struct asColumn **pList)
+/* free a list of asColumn */
+{
+struct asColumn *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    asColumnFree(&el);
+    }
+*pList = NULL;
+}
+
+void asObjectFree(struct asObject **pAs)
+/* free a single asObject */
+{
+struct asObject *as = *pAs;
+if (as != NULL)
+    {
+    freeMem(as->name);
+    freeMem(as->comment);
+    asColumnFreeList(&as->columnList);
+    freez(pAs);
+    }
+}
+
+
+void asObjectFreeList(struct asObject **pList)
+/* free a list of asObject */
+{
+struct asObject *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    asObjectFree(&el);
+    }
+*pList = NULL;
+}
+
+struct asObject *asParseFile(char *fileName)
+/* Parse autoSql .as file. */
+{
+return asParseLineFile(lineFileOpen(fileName, TRUE));
+}
+
+
+struct asObject *asParseText(char *text)
+/* Parse autoSql from text (as opposed to file). */
+{
+char *dupe = cloneString(text);
+struct lineFile *lf = lineFileOnString("text", TRUE, dupe);
+struct asObject *objList = asParseLineFile(lf);
+freez(&dupe);
+return objList;
+}
+
+struct asColumn *asColumnFind(struct asObject *asObj, char *name)
+// Return named column.
+{
+struct asColumn *asCol = NULL;
+if (asObj!= NULL)
+    {
+    for (asCol = asObj->columnList; asCol != NULL; asCol = asCol->next)
+        if (sameString(asCol->name, name))
+             break;
+    }
+return asCol;
+}
+
+boolean asCompareObjs(char *name1, struct asObject *as1, char *name2, struct asObject *as2, int numColumnsToCheck,
+ int *retNumColumnsSame, boolean abortOnDifference)
+/* Compare as-objects as1 and as2 making sure several important fields show they are the same name and type.
+ * If difference found, print it to stderr.  If abortOnDifference, errAbort.
+ * Othewise, return TRUE if the objects columns match through the first numColumnsToCheck fields. 
+ * If retNumColumnsSame is not NULL, then it will be set to the number of contiguous matching columns. */
+{
+boolean differencesFound = FALSE;
+struct asColumn *col1 = as1->columnList, *col2 = as2->columnList;
+int checkCount = 0;
+int verboseLevel = 2;
+if (abortOnDifference)
+    verboseLevel = 1;
+if (as1->isTable != as2->isTable)
+    {
+    verbose(verboseLevel,"isTable does not match: %s=[%d]  %s=[%d]", name1, as1->isTable, name2, as2->isTable);
+    differencesFound = TRUE;
+    }
+else if (as1->isSimple != as2->isSimple)
+    {
+    verbose(verboseLevel,"isSimple does not match: %s=[%d]  %s=[%d]", name1, as1->isSimple, name2, as2->isSimple);
+    differencesFound = TRUE;
+    }
+else
+    {
+    if (!as1->isTable)
+	{
+	errAbort("asCompareObjLists only supports Table .as objects at this time.");
+	}
+    for (col1 = as1->columnList, col2 = as2->columnList; 
+	 col1 != NULL && col2 != NULL && checkCount < numColumnsToCheck; 
+	 col1 = col1->next, col2 = col2->next, ++checkCount)
+	{
+	if (!sameOk(col1->name, col2->name))
+	    {
+	    verbose(verboseLevel,"column #%d names do not match: %s=[%s]  %s=[%s]\n"
+		, checkCount+1, name1, col1->name, name2, col2->name);
+	    differencesFound = TRUE;
+	    break;
+	    }
+	else if (col1->isSizeLink != col2->isSizeLink)
+	    {
+	    verbose(verboseLevel,"column #%d isSizeLink do not match: %s=[%d]  %s=[%d]\n"
+		, checkCount+1, name1, col1->isSizeLink, name2, col2->isSizeLink);
+	    differencesFound = TRUE;
+	    break;
+	    }
+	else if (col1->isList != col2->isList)
+	    {
+	    verbose(verboseLevel,"column #%d isList do not match: %s=[%d]  %s=[%d]\n"
+		, checkCount+1, name1, col1->isList, name2, col2->isList);
+	    differencesFound = TRUE;
+	    break;
+	    }
+	else if (col1->isArray != col2->isArray)
+	    {
+	    verbose(verboseLevel,"column #%d isArray do not match: %s=[%d]  %s=[%d]\n"
+		, checkCount+1, name1, col1->isArray, name2, col2->isArray);
+	    differencesFound = TRUE;
+	    break;
+	    }
+	else if (!sameOk(col1->lowType->name, col2->lowType->name))
+	    {
+	    verbose(verboseLevel,"column #%d type names do not match: %s=[%s]  %s=[%s]\n"
+		, checkCount+1, name1, col1->lowType->name, name2, col2->lowType->name);
+	    differencesFound = TRUE;
+	    break;
+	    }
+	else if (col1->fixedSize != col2->fixedSize)
+	    {
+	    verbose(verboseLevel,"column #%d fixedSize do not match: %s=[%d]  %s=[%d]\n"
+		, checkCount+1, name1, col1->fixedSize, name2, col2->fixedSize);
+	    differencesFound = TRUE;
+	    break;
+	    }
+	else if (!sameOk(col1->linkedSizeName, col2->linkedSizeName))
+	    {
+	    verbose(verboseLevel,"column #%d linkedSizeName do not match: %s=[%s]  %s=[%s]\n"
+		, checkCount+1, name1, col1->linkedSizeName, name2, col2->linkedSizeName);
+	    differencesFound = TRUE;
+	    break;
+	    }
+	}
+    if (!differencesFound && checkCount < numColumnsToCheck)
+	errAbort("Unexpected error in asCompareObjLists: asked to compare %d columns in %s and %s, but only found %d in one or both asObjects."
+	    , numColumnsToCheck, name1, name2, checkCount);
+    }
+if (differencesFound)
+    {
+    if (abortOnDifference)
+    	errAbort("asObjects differ.");
+    else
+    	verbose(verboseLevel,"asObjects differ. Matching field count=%d\n", checkCount);
+    }
+if (retNumColumnsSame)
+    *retNumColumnsSame = checkCount;
+return (!differencesFound);
+}
diff --git a/lib/axt.c b/lib/axt.c
new file mode 100644
index 0000000..3272d63
--- /dev/null
+++ b/lib/axt.c
@@ -0,0 +1,1038 @@
+/* AXT - A simple alignment format with four lines per
+ * alignment.  The first specifies the names of the
+ * two sequences that align and the position of the
+ * alignment, as well as the strand.  The next two
+ * lines contain the alignment itself including dashes
+ * for inserts.  The alignment is separated from the
+ * next alignment with a blank line. 
+ *
+ * This file contains routines to read such alignments.
+ * Note that though the coordinates are one based and
+ * closed on disk, they get converted to our usual half
+ * open zero based in memory. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "obscure.h"
+#include "linefile.h"
+#include "dnautil.h"
+#include "axt.h"
+
+
+void axtFree(struct axt **pEl)
+/* Free an axt. */
+{
+struct axt *el = *pEl;
+if (el != NULL)
+    {
+    freeMem(el->qName);
+    freeMem(el->tName);
+    freeMem(el->qSym);
+    freeMem(el->tSym);
+    freez(pEl);
+    }
+}
+
+void axtFreeList(struct axt **pList)
+/* Free a list of dynamically allocated axt's */
+{
+struct axt *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    axtFree(&el);
+    }
+*pList = NULL;
+}
+
+
+struct axt *axtReadWithPos(struct lineFile *lf, off_t *retOffset)
+/* Read next axt, and if retOffset is not-NULL, fill it with
+ * offset of start of axt. */
+{
+char *words[10], *line;
+int wordCount, symCount;
+struct axt *axt;
+
+wordCount = lineFileChop(lf, words);
+if (retOffset != NULL)
+    *retOffset = lineFileTell(lf);
+if (wordCount <= 0)
+    return NULL;
+if (wordCount < 8)
+    {
+    errAbort("Expecting at least 8 words line %d of %s got %d\n", lf->lineIx, lf->fileName,
+    	wordCount);
+    }
+AllocVar(axt);
+
+axt->qName = cloneString(words[4]);
+axt->qStart = lineFileNeedNum(lf, words, 5) - 1;
+axt->qEnd = lineFileNeedNum(lf, words, 6);
+axt->qStrand = words[7][0];
+axt->tName = cloneString(words[1]);
+axt->tStart = lineFileNeedNum(lf, words, 2) - 1;
+axt->tEnd = lineFileNeedNum(lf, words, 3);
+axt->tStrand = '+';
+if (wordCount > 8)
+    axt->score = lineFileNeedNum(lf, words, 8);
+lineFileNeedNext(lf, &line, NULL);
+axt->symCount = symCount = strlen(line);
+axt->tSym = cloneMem(line, symCount+1);
+lineFileNeedNext(lf, &line, NULL);
+if (strlen(line) != symCount)
+    errAbort("Symbol count %d != %d inconsistent between sequences line %d and prev line of %s",
+    	symCount, (int)strlen(line), lf->lineIx, lf->fileName);
+axt->qSym = cloneMem(line, symCount+1);
+lineFileNext(lf, &line, NULL);	/* Skip blank line */
+return axt;
+}
+
+struct axt *axtRead(struct lineFile *lf)
+/* Read in next record from .axt file and return it.
+ * Returns NULL at EOF. */
+{
+return axtReadWithPos(lf, NULL);
+}
+
+void axtWrite(struct axt *axt, FILE *f)
+/* Output axt to axt file. */
+{
+static int ix = 0;
+fprintf(f, "%d %s %d %d %s %d %d %c",
+	ix++, axt->tName, axt->tStart+1, axt->tEnd, 
+	axt->qName, axt->qStart+1, axt->qEnd, axt->qStrand);
+fprintf(f, " %d", axt->score);
+fputc('\n', f);
+mustWrite(f, axt->tSym, axt->symCount);
+fputc('\n', f);
+mustWrite(f, axt->qSym, axt->symCount);
+fputc('\n', f);
+fputc('\n', f);
+if ((strlen(axt->tSym) != strlen(axt->qSym)) || (axt->symCount > strlen(axt->tSym)))
+    fprintf(stderr,"Symbol count %d != %d || %d > %d inconsistent in %s in "
+	    "record %d.\n",
+	    (int)strlen(axt->qSym), (int)strlen(axt->tSym), axt->symCount,
+	    (int)strlen(axt->tSym), axt->qName, ix);
+}
+
+int axtCmpQuery(const void *va, const void *vb)
+/* Compare to sort based on query position. */
+{
+const struct axt *a = *((struct axt **)va);
+const struct axt *b = *((struct axt **)vb);
+int dif;
+dif = strcmp(a->qName, b->qName);
+if (dif == 0)
+    dif = a->qStart - b->qStart;
+return dif;
+}
+
+int axtCmpTarget(const void *va, const void *vb)
+/* Compare to sort based on target position. */
+{
+const struct axt *a = *((struct axt **)va);
+const struct axt *b = *((struct axt **)vb);
+int dif;
+dif = strcmp(a->tName, b->tName);
+if (dif == 0)
+    dif = a->tStart - b->tStart;
+return dif;
+}
+
+int axtCmpScore(const void *va, const void *vb)
+/* Compare to sort based on score. */
+{
+const struct axt *a = *((struct axt **)va);
+const struct axt *b = *((struct axt **)vb);
+return b->score - a->score;
+}
+
+int axtCmpTargetScoreDesc(const void *va, const void *vb)
+/* Compare to sort based on target name and score descending. */
+{
+const struct axt *a = *((struct axt **)va);
+const struct axt *b = *((struct axt **)vb);
+int dif;
+dif = strcmp(a->tName, b->tName);
+if (dif == 0)
+    dif = b->score - a->score;
+return dif;
+}
+
+boolean axtCheck(struct axt *axt, struct lineFile *lf)
+/* Return FALSE if there's a problem with axt. */
+{
+int tSize = countNonDash(axt->tSym, axt->symCount);
+int qSize = countNonDash(axt->qSym, axt->symCount);
+if (tSize != axt->tEnd - axt->tStart)
+    {
+    warn("%d non-dashes, but %d bases to cover at line %d of %s", 
+    	tSize, axt->tEnd - axt->tStart, lf->lineIx, lf->fileName);
+    return FALSE;
+    }
+if (qSize != axt->qEnd - axt->qStart)
+    {
+    warn("%d non-dashes, but %d bases to cover at line %d of %s", 
+    	tSize, axt->qEnd - axt->qStart, lf->lineIx, lf->fileName);
+    return FALSE;
+    }
+return TRUE;
+}
+
+int axtScoreUngapped(struct axtScoreScheme *ss, char *q, char *t, int size)
+/* Score ungapped alignment. */
+{
+int score = 0;
+int i;
+for (i=0; i<size; ++i)
+    score += ss->matrix[(int)q[i]][(int)t[i]];
+return score;
+}
+
+int axtScoreSym(struct axtScoreScheme *ss, int symCount, char *qSym, char *tSym)
+/* Return score without setting up an axt structure. */
+{
+int i;
+char q,t;
+int score = 0;
+boolean lastGap = FALSE;
+int gapStart = ss->gapOpen;
+int gapExt = ss->gapExtend;
+
+dnaUtilOpen();
+for (i=0; i<symCount; ++i)
+    {
+    q = qSym[i];
+    t = tSym[i];
+    if (q == '-' || t == '-')
+        {
+	if (lastGap)
+	    score -= gapExt;
+	else
+	    {
+	    /* Use gapStart+gapExt to be consistent with blastz: */
+	    score -= (gapStart + gapExt);
+	    lastGap = TRUE;
+	    }
+	}
+    else
+        {
+	score += ss->matrix[(int)q][(int)t];
+	lastGap = FALSE;
+	}
+    }
+return score;
+}
+
+boolean gapNotMasked(char q, char t)
+/* return true if gap on one side and upper case on other side */
+{
+if (q=='-' && t=='-')
+    return FALSE;
+if (q=='-' && t<'a')
+    return TRUE;
+if (t=='-' && q<'a')
+    return TRUE;
+return FALSE;
+}
+
+
+int axtScoreSymFilterRepeats(struct axtScoreScheme *ss, int symCount, char *qSym, char *tSym)
+/* Return score without setting up an axt structure. Do not penalize gaps if repeat masked (lowercase)*/
+{
+int i;
+char q,t;
+int score = 0;
+boolean lastGap = FALSE;
+int gapStart = ss->gapOpen;
+int gapExt = ss->gapExtend;
+
+dnaUtilOpen();
+for (i=0; i<symCount; ++i)
+    {
+    q = qSym[i];
+    t = tSym[i];
+    if ((q == '-' || t == '-') && gapNotMasked(q,t))
+        {
+	if (lastGap)
+	    score -= gapExt;
+	else
+	    {
+	    /* Use gapStart+gapExt to be consistent with blastz: */
+	    score -= (gapStart + gapExt);
+	    lastGap = TRUE;
+	    }
+	}
+    else
+        {
+	score += ss->matrix[(int)q][(int)t];
+	lastGap = FALSE;
+	}
+    }
+return score;
+}
+
+int axtScoreFilterRepeats(struct axt *axt, struct axtScoreScheme *ss)
+/* Return calculated score of axt. */
+{
+return axtScoreSymFilterRepeats(ss, axt->symCount, axt->qSym, axt->tSym);
+}
+
+int axtScore(struct axt *axt, struct axtScoreScheme *ss)
+/* Return calculated score of axt. */
+{
+return axtScoreSym(ss, axt->symCount, axt->qSym, axt->tSym);
+}
+
+int axtScoreDnaDefault(struct axt *axt)
+/* Score DNA-based axt using default scheme. */
+{
+static struct axtScoreScheme *ss;
+if (ss == NULL)
+    ss = axtScoreSchemeDefault();
+return axtScore(axt, ss);
+}
+
+int axtScoreProteinDefault(struct axt *axt)
+/* Score protein-based axt using default scheme. */
+{
+static struct axtScoreScheme *ss;
+if (ss == NULL)
+    ss = axtScoreSchemeProteinDefault();
+return axtScore(axt, ss);
+}
+
+boolean axtGetSubsetOnT(struct axt *axt, struct axt *axtOut,
+			int newStart, int newEnd, struct axtScoreScheme *ss,
+			boolean includeEdgeGaps)
+/* Return FALSE if axt is not in the new range.  Otherwise, set axtOut to
+ * a subset that goes from newStart to newEnd in target coordinates. 
+ * If includeEdgeGaps, don't trim target gaps before or after the range. */
+{
+if (axt == NULL)
+    return FALSE;
+if (newStart < axt->tStart)
+    newStart = axt->tStart;
+if (newEnd > axt->tEnd)
+    newEnd = axt->tEnd;
+if (includeEdgeGaps ? (newEnd < newStart) : (newEnd <= newStart)) 
+    return FALSE;
+if (newStart == axt->tStart && newEnd == axt->tEnd)
+    {
+    axt->score = axtScore(axt, ss);
+    *axtOut = *axt;
+    return TRUE;
+    }
+else
+    {
+    struct axt a = *axt;
+    char *tSymStart = skipIgnoringDash(a.tSym, newStart - a.tStart, TRUE);
+    char *tSymEnd = skipIgnoringDash(tSymStart, newEnd - newStart, FALSE);
+    if (includeEdgeGaps)
+	{
+	while (tSymStart > a.tSym)
+	    if (*(--tSymStart) != '-')
+		{
+		tSymStart++;
+		break;
+		}
+	while (tSymEnd < a.tSym + a.symCount)
+	    if (*(++tSymEnd) != '-')
+		{
+		tSymEnd--;
+		break;
+		}
+	if (newEnd == newStart && tSymEnd > tSymStart)
+	    {
+	    if (*tSymStart != '-')
+		tSymStart++;
+	    if (*(tSymEnd-1) != '-')
+		tSymEnd--;
+	    }
+	}
+    int symCount = tSymEnd - tSymStart;
+    char *qSymStart = a.qSym + (tSymStart - a.tSym);
+    a.qStart += countNonDash(a.qSym, qSymStart - a.qSym);
+    a.qEnd = a.qStart + countNonDash(qSymStart, symCount);
+    a.tStart = newStart;
+    a.tEnd = newEnd;
+    a.symCount = symCount;
+    a.qSym = qSymStart;
+    a.tSym = tSymStart;
+    a.score = axtScore(&a, ss);
+    if ((a.qStart < a.qEnd && a.tStart < a.tEnd) ||
+	(includeEdgeGaps && (a.qStart < a.qEnd || a.tStart < a.tEnd)))
+	{
+	*axtOut = a;
+	return TRUE;
+	}
+    return FALSE;
+    }
+}
+
+void axtSubsetOnT(struct axt *axt, int newStart, int newEnd, 
+	struct axtScoreScheme *ss, FILE *f)
+/* Write out subset of axt that goes from newStart to newEnd
+ * in target coordinates. */
+{
+struct axt axtSub;
+if (axtGetSubsetOnT(axt, &axtSub, newStart, newEnd, ss, FALSE))
+    axtWrite(&axtSub, f);
+}
+
+int axtTransPosToQ(struct axt *axt, int tPos)
+/* Convert from t to q coordinates */
+{
+char *tSym = skipIgnoringDash(axt->tSym, tPos - axt->tStart, TRUE);
+int symIx = tSym - axt->tSym;
+int qPos = countNonDash(axt->qSym, symIx);
+return qPos + axt->qStart;
+}
+
+static void shortScoreScheme(struct lineFile *lf)
+/* Complain about score file being to short. */
+{
+errAbort("Scoring matrix file %s too short\n", lf->fileName);
+}
+
+static void propagateCase(struct axtScoreScheme *ss)
+/* Propagate score matrix from lower case to mixed case
+ * in matrix. */
+{
+static int twoCase[2][4] = {{'a', 'c', 'g', 't'},{'A','C','G','T'},};
+int i1,i2,j1,j2;
+
+/* Propagate to other case combinations. */
+for (i1=0; i1<=1; ++i1)
+    for (i2=0; i2<=1; ++i2)
+       {
+       if (i1 == 0 && i2 == 0)
+           continue;
+       for (j1=0; j1<4; ++j1)
+	   for (j2=0; j2<4; ++j2)
+	      {
+	      ss->matrix[twoCase[i1][j1]][twoCase[i2][j2]] = ss->matrix[twoCase[0][j1]][twoCase[0][j2]];
+	      }
+       }
+}
+
+struct axtScoreScheme *axtScoreSchemeDefault()
+/* Return default scoring scheme (after blastz).  Do NOT axtScoreSchemeFree
+ * this. */
+{
+static struct axtScoreScheme *ss;
+
+if (ss != NULL)
+    return ss;
+AllocVar(ss);
+
+/* Set up lower case elements of matrix. */
+ss->matrix['a']['a'] = 91;
+ss->matrix['a']['c'] = -114;
+ss->matrix['a']['g'] = -31;
+ss->matrix['a']['t'] = -123;
+
+ss->matrix['c']['a'] = -114;
+ss->matrix['c']['c'] = 100;
+ss->matrix['c']['g'] = -125;
+ss->matrix['c']['t'] = -31;
+
+ss->matrix['g']['a'] = -31;
+ss->matrix['g']['c'] = -125;
+ss->matrix['g']['g'] = 100;
+ss->matrix['g']['t'] = -114;
+
+ss->matrix['t']['a'] = -123;
+ss->matrix['t']['c'] = -31;
+ss->matrix['t']['g'] = -114;
+ss->matrix['t']['t'] = 91;
+
+propagateCase(ss);
+ss->gapOpen = 400;
+ss->gapExtend = 30;
+return ss;
+}
+
+struct axtScoreScheme *axtScoreSchemeSimpleDna(int match, int misMatch, int gapOpen, int gapExtend)
+/* Return a relatively simple scoring scheme for DNA. */
+{
+static struct axtScoreScheme *ss;
+AllocVar(ss);
+
+/* Set up lower case elements of matrix. */
+ss->matrix['a']['a'] = match;
+ss->matrix['a']['c'] = -misMatch;
+ss->matrix['a']['g'] = -misMatch;
+ss->matrix['a']['t'] = -misMatch;
+
+ss->matrix['c']['a'] = -misMatch;
+ss->matrix['c']['c'] = match;
+ss->matrix['c']['g'] = -misMatch;
+ss->matrix['c']['t'] = -misMatch;
+
+ss->matrix['g']['a'] = -misMatch;
+ss->matrix['g']['c'] = -misMatch;
+ss->matrix['g']['g'] = match;
+ss->matrix['g']['t'] = -misMatch;
+
+ss->matrix['t']['a'] = -misMatch;
+ss->matrix['t']['c'] = -misMatch;
+ss->matrix['t']['g'] = -misMatch;
+ss->matrix['t']['t'] = match;
+
+propagateCase(ss);
+ss->gapOpen = gapOpen;
+ss->gapExtend = gapExtend;
+return ss;
+}
+
+struct axtScoreScheme *axtScoreSchemeRnaDefault()
+/* Return default scoring scheme for RNA/DNA alignments
+ * within the same species.  Do NOT axtScoreSchemeFree */
+{
+static struct axtScoreScheme *ss;
+if (ss == NULL)
+    ss = axtScoreSchemeSimpleDna(100, 200, 300, 300);
+return ss;
+}
+
+struct axtScoreScheme *axtScoreSchemeRnaFill()
+/* Return scoreing scheme a little more relaxed than 
+ * RNA/DNA defaults for filling in gaps. */
+{
+static struct axtScoreScheme *ss;
+if (ss == NULL)
+    ss = axtScoreSchemeSimpleDna(100, 100, 200, 200);
+return ss;
+}
+
+struct axtScoreScheme *axtScoreSchemeFromBlastzMatrix(char *text, int gapOpen, int gapExtend)
+/* return scoring schema from a string in the following format */
+/* 91,-90,-25,-100,-90,100,-100,-25,-25,-100,100,-90,-100,-25,-90,91 */
+{
+char *matrixDna[32];
+struct axtScoreScheme *ss = axtScoreSchemeDefault();
+int matrixSize = chopString(text, ",", matrixDna, 32);
+if (matrixSize != 16)
+    return ss;
+if (ss == NULL)
+    return NULL;
+ss->gapOpen = gapOpen;
+ss->gapExtend = gapExtend;
+ss->matrix['a']['a'] = atoi(matrixDna[0]);
+ss->matrix['a']['c'] = atoi(matrixDna[1]);
+ss->matrix['a']['g'] = atoi(matrixDna[2]);
+ss->matrix['a']['t'] = atoi(matrixDna[3]);
+
+ss->matrix['c']['a'] = atoi(matrixDna[4]);
+ss->matrix['c']['c'] = atoi(matrixDna[5]);
+ss->matrix['c']['g'] = atoi(matrixDna[6]);
+ss->matrix['c']['t'] = atoi(matrixDna[7]);
+
+ss->matrix['g']['a'] = atoi(matrixDna[8]);
+ss->matrix['g']['c'] = atoi(matrixDna[9]);
+ss->matrix['g']['g'] = atoi(matrixDna[10]);
+ss->matrix['g']['t'] = atoi(matrixDna[11]);
+
+ss->matrix['t']['a'] = atoi(matrixDna[12]);
+ss->matrix['t']['c'] = atoi(matrixDna[13]);
+ss->matrix['t']['g'] = atoi(matrixDna[14]);
+ss->matrix['t']['t'] = atoi(matrixDna[15]);
+return ss;
+}
+
+char blosumText[] = {
+"#  Matrix made by matblas from blosum62.iij\n"
+"#  * column uses minimum score\n"
+"#  BLOSUM Clustered Scoring Matrix in 1/2 Bit Units\n"
+"#  Blocks Database = /data/blocks_5.0/blocks.dat\n"
+"#  Cluster Percentage: >= 62\n"
+"#  Entropy =   0.6979, Expected =  -0.5209\n"
+"   A  R  N  D  C  Q  E  G  H  I  L  K  M  F  P  S  T  W  Y  V  B  Z  X  *\n"
+"A  4 -1 -2 -2  0 -1 -1  0 -2 -1 -1 -1 -1 -2 -1  1  0 -3 -2  0 -2 -1  0 -4 \n"
+"R -1  5  0 -2 -3  1  0 -2  0 -3 -2  2 -1 -3 -2 -1 -1 -3 -2 -3 -1  0 -1 -4 \n"
+"N -2  0  6  1 -3  0  0  0  1 -3 -3  0 -2 -3 -2  1  0 -4 -2 -3  3  0 -1 -4 \n"
+"D -2 -2  1  6 -3  0  2 -1 -1 -3 -4 -1 -3 -3 -1  0 -1 -4 -3 -3  4  1 -1 -4 \n"
+"C  0 -3 -3 -3  9 -3 -4 -3 -3 -1 -1 -3 -1 -2 -3 -1 -1 -2 -2 -1 -3 -3 -2 -4 \n"
+"Q -1  1  0  0 -3  5  2 -2  0 -3 -2  1  0 -3 -1  0 -1 -2 -1 -2  0  3 -1 -4 \n"
+"E -1  0  0  2 -4  2  5 -2  0 -3 -3  1 -2 -3 -1  0 -1 -3 -2 -2  1  4 -1 -4 \n"
+"G  0 -2  0 -1 -3 -2 -2  6 -2 -4 -4 -2 -3 -3 -2  0 -2 -2 -3 -3 -1 -2 -1 -4 \n"
+"H -2  0  1 -1 -3  0  0 -2  8 -3 -3 -1 -2 -1 -2 -1 -2 -2  2 -3  0  0 -1 -4 \n"
+"I -1 -3 -3 -3 -1 -3 -3 -4 -3  4  2 -3  1  0 -3 -2 -1 -3 -1  3 -3 -3 -1 -4 \n"
+"L -1 -2 -3 -4 -1 -2 -3 -4 -3  2  4 -2  2  0 -3 -2 -1 -2 -1  1 -4 -3 -1 -4 \n"
+"K -1  2  0 -1 -3  1  1 -2 -1 -3 -2  5 -1 -3 -1  0 -1 -3 -2 -2  0  1 -1 -4 \n"
+"M -1 -1 -2 -3 -1  0 -2 -3 -2  1  2 -1  5  0 -2 -1 -1 -1 -1  1 -3 -1 -1 -4 \n"
+"F -2 -3 -3 -3 -2 -3 -3 -3 -1  0  0 -3  0  6 -4 -2 -2  1  3 -1 -3 -3 -1 -4 \n"
+"P -1 -2 -2 -1 -3 -1 -1 -2 -2 -3 -3 -1 -2 -4  7 -1 -1 -4 -3 -2 -2 -1 -2 -4 \n"
+"S  1 -1  1  0 -1  0  0  0 -1 -2 -2  0 -1 -2 -1  4  1 -3 -2 -2  0  0  0 -4 \n"
+"T  0 -1  0 -1 -1 -1 -1 -2 -2 -1 -1 -1 -1 -2 -1  1  5 -2 -2  0 -1 -1  0 -4 \n"
+"W -3 -3 -4 -4 -2 -2 -3 -2 -2 -3 -2 -3 -1  1 -4 -3 -2 11  2 -3 -4 -3 -2 -4 \n"
+"Y -2 -2 -2 -3 -2 -1 -2 -3  2 -1 -1 -2 -1  3 -3 -2 -2  2  7 -1 -3 -2 -1 -4 \n"
+"V  0 -3 -3 -3 -1 -2 -2 -3 -3  3  1 -2  1 -1 -2 -2  0 -3 -1  4 -3 -2 -1 -4 \n"
+"B -2 -1  3  4 -3  0  1 -1  0 -3 -4  0 -3 -3 -2  0 -1 -4 -3 -3  4  1 -1 -4 \n"
+"Z -1  0  0  1 -3  3  4 -2  0 -3 -3  1 -1 -3 -1  0 -1 -3 -2 -2  1  4 -1 -4 \n"
+"X  0 -1 -1 -1 -2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -2  0  0 -2 -1 -1 -1 -1 -1 -4 \n"
+"* -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4  1 \n"
+};
+
+static void badProteinMatrixLine(int lineIx, char *fileName)
+/* Explain line syntax for protein matrix and abort */
+{
+errAbort("Expecting letter and 25 numbers line %d of %s", lineIx, fileName);
+}
+
+struct axtScoreScheme *axtScoreSchemeFromProteinText(char *text, char *fileName)
+/* Parse text into a scoring scheme.  This should be in BLAST protein matrix
+ * format as in blosumText above. */
+{
+char *line, *nextLine;
+int lineIx = 0;
+int realCount = 0;
+char columns[24];
+char *row[25];
+int i;
+struct axtScoreScheme *ss;
+
+AllocVar(ss);
+for (line = text; line != NULL; line = nextLine)
+    {
+    nextLine = strchr(line, '\n');
+    if (nextLine != NULL)
+        *nextLine++ = 0;
+    ++lineIx;
+    line = skipLeadingSpaces(line);
+    if (line[0] == '#' || line[0] == 0)
+        continue;
+    ++realCount;
+    if (realCount == 1)
+        {
+	int wordCount = chopLine(line, row);
+	if (wordCount != 24)
+	    errAbort("Not a good protein matrix - expecting 24 letters line %d of %s", lineIx, fileName);
+	for (i=0; i<wordCount; ++i)
+	    {
+	    char *letter = row[i];
+	    if (strlen(letter) != 1)
+		errAbort("Not a good protein matrix - got word not letter line %d of %s", lineIx, fileName);
+	    columns[i] = letter[0];
+	    }
+	}
+    else
+        {
+	int wordCount = chopLine(line, row);
+	char letter, lcLetter;
+	if (wordCount != 25)
+	    badProteinMatrixLine(lineIx, fileName);
+	letter = row[0][0];
+	if (strlen(row[0]) != 1 || isdigit(letter))
+	    badProteinMatrixLine(lineIx, fileName);
+	lcLetter = tolower(letter);
+	for (i=1; i<wordCount; ++i)
+	    {
+	    char *s = row[i];
+	    int val;
+	    char otherLetter, lcOtherLetter;
+	    if (s[0] == '-') ++s;
+	    if (!isdigit(s[0]))
+		badProteinMatrixLine(lineIx, fileName);
+	    otherLetter = columns[i-1];
+	    lcOtherLetter = tolower(otherLetter);
+	    val = atoi(row[i]);
+	    ss->matrix[(int)letter][(int)otherLetter] = val;
+	    ss->matrix[(int)lcLetter][(int)otherLetter] = val;
+	    ss->matrix[(int)letter][(int)lcOtherLetter] = val;
+	    ss->matrix[(int)lcLetter][(int)lcOtherLetter] = val;
+	    }
+	}
+    }
+if (realCount < 25)
+    errAbort("Unexpected end of %s", fileName);
+return ss;
+}
+
+struct axtScoreScheme *axtScoreSchemeProteinDefault()
+/* Returns default protein scoring scheme.  This is
+ * scaled to be compatible with the blastz one. */
+{
+static struct axtScoreScheme *ss;
+int i,j;
+if (ss != NULL)
+    return ss;
+ss = axtScoreSchemeFromProteinText(blosumText, "blosum62");
+for (i=0; i<128; ++i)
+    for (j=0; j<128; ++j)
+        ss->matrix[i][j] *= 19;
+ss->gapOpen = 11 * 19;
+ss->gapExtend = 1 * 19;
+return ss;
+}
+
+void axtScoreSchemeFree(struct axtScoreScheme **pObj)
+/* Free up score scheme. */
+{
+freez(pObj);
+}
+
+struct axtScoreScheme *axtScoreSchemeProteinRead(char *fileName)
+{
+char *string;
+struct axtScoreScheme *ss;
+
+readInGulp(fileName, &string, NULL);
+ss = axtScoreSchemeFromProteinText(string, fileName);
+freeMem(string);
+
+return ss;
+}
+
+struct axtScoreScheme *axtScoreSchemeReadLf(struct lineFile *lf )
+/* Read in scoring scheme from file. Looks like
+    A    C    G    T
+    91 -114  -31 -123
+    -114  100 -125  -31
+    -31 -125  100 -114
+    -123  -31 -114   91
+    O = 400, E = 30
+*/
+{
+char *line, *row[4], *parts[32];
+int i,j, partCount;
+struct axtScoreScheme *ss;
+boolean gotO = FALSE, gotE = FALSE;
+static int trans[4] = {'a', 'c', 'g', 't'};
+
+AllocVar(ss);
+ss->extra = NULL;
+if (!lineFileRow(lf, row))
+    shortScoreScheme(lf);
+if (row[0][0] != 'A' || row[1][0] != 'C' || row[2][0] != 'G' 
+	|| row[3][0] != 'T')
+    errAbort("%s doesn't seem to be a score matrix file", lf->fileName);
+for (i=0; i<4; ++i)
+    {
+    if (!lineFileRow(lf, row))
+	shortScoreScheme(lf);
+    for (j=0; j<4; ++j)
+	ss->matrix[trans[i]][trans[j]] = lineFileNeedNum(lf, row, j);
+    }
+if (lineFileNext(lf, &line, NULL))
+    {
+    ss->extra = cloneString(line);
+    partCount = chopString(line, " =,\t", parts, ArraySize(parts));
+    for (i=0; i<partCount-1; i += 2)
+	{
+	if (sameString(parts[i], "O"))
+	    {
+	    gotO = TRUE;
+	    ss->gapOpen = atoi(parts[i+1]);
+	    }
+	if (sameString(parts[i], "E"))
+	    {
+	    gotE = TRUE;
+	    ss->gapExtend = atoi(parts[i+1]);
+	    }
+	}
+    if (!gotO || !gotE)
+	errAbort("Expecting O = and E = in last line of %s", lf->fileName);
+    if (ss->gapOpen <= 0 || ss->gapExtend <= 0)
+	errAbort("Must have positive gap scores");
+    }
+else
+    {
+    ss->gapOpen = 400;
+    ss->gapExtend = 30;
+    }
+propagateCase(ss);
+return ss;
+}
+
+struct axtScoreScheme *axtScoreSchemeRead(char *fileName)
+/* Read in scoring scheme from file. Looks like
+    A    C    G    T
+    91 -114  -31 -123
+    -114  100 -125  -31
+    -31 -125  100 -114
+    -123  -31 -114   91
+    O = 400, E = 30
+*/
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+struct axtScoreScheme *ss = axtScoreSchemeReadLf(lf);
+return ss;
+}
+
+void axtScoreSchemeDnaWrite(struct axtScoreScheme *ss, FILE *f, char *name)
+/* output the score dna based score matrix in meta Data format to File f,
+name should be set to the name of the program that is using the matrix */
+{
+if (ss == NULL)
+    return;
+if (f == NULL)
+    return;
+fprintf(f, "##matrix=%s 16 %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
+        name,
+    ss->matrix['a']['a'],
+    ss->matrix['a']['c'],
+    ss->matrix['a']['g'],
+    ss->matrix['a']['t'],
+
+    ss->matrix['c']['a'],
+    ss->matrix['c']['c'],
+    ss->matrix['c']['g'],
+    ss->matrix['c']['t'],
+
+    ss->matrix['g']['a'],
+    ss->matrix['g']['c'],
+    ss->matrix['g']['g'],
+    ss->matrix['g']['t'],
+
+    ss->matrix['t']['a'],
+    ss->matrix['t']['c'],
+    ss->matrix['t']['g'],
+    ss->matrix['t']['t']);
+fprintf(f, "##gapPenalties=%s O=%d E=%d\n", name, ss->gapOpen, ss->gapExtend);
+if (ss->extra!=NULL)
+    {
+    stripChar(ss->extra,' ');
+    stripChar(ss->extra,'"');
+    fprintf(f, "##blastzParms=%s\n", ss->extra);
+    }
+}
+
+void axtSwap(struct axt *axt, int tSize, int qSize)
+/* Flip target and query on one axt. */
+{
+struct axt old = *axt;
+
+/* Copy non-strand dependent stuff */
+axt->qName = old.tName;
+axt->tName = old.qName;
+axt->qSym = old.tSym;
+axt->tSym = old.qSym;
+axt->qStart = old.tStart;
+axt->qEnd = old.tEnd;
+axt->tStart = old.qStart;
+axt->tEnd = old.qEnd;
+
+/* Copy strand dependent stuff. */
+assert(axt->tStrand != '-');
+
+if (axt->qStrand == '-')
+    {
+    /* axt's are really set up so that the target is on the
+     * + strand and the query is on the minus strand.
+     * Therefore we need to reverse complement both 
+     * strands while swapping to preserve this. */
+    reverseIntRange(&axt->tStart, &axt->tEnd, qSize);
+    reverseIntRange(&axt->qStart, &axt->qEnd, tSize);
+    reverseComplement(axt->qSym, axt->symCount);
+    reverseComplement(axt->tSym, axt->symCount);
+    }
+}
+
+void axtBundleFree(struct axtBundle **pObj)
+/* Free a axtBundle. */
+{
+struct axtBundle *obj = *pObj;
+if (obj != NULL)
+    {
+    axtFreeList(&obj->axtList);
+    freez(pObj);
+    }
+}
+
+void axtBundleFreeList(struct axtBundle **pList)
+/* Free a list of axtBundles. */
+{
+struct axtBundle *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    axtBundleFree(&el);
+    }
+*pList = NULL;
+}
+
+void axtAddBlocksToBoxInList(struct cBlock **pList, struct axt *axt)
+/* Add blocks (gapless subalignments) from (non-NULL!) axt to block list. 
+ * Note: list will be in reverse order of axt blocks. */
+{
+boolean thisIn, lastIn = FALSE;
+int qPos = axt->qStart, tPos = axt->tStart;
+int qStart = 0, tStart = 0;
+int i;
+
+for (i=0; i<=axt->symCount; ++i)
+    {
+    int advanceQ = (isalpha(axt->qSym[i]) ? 1 : 0);
+    int advanceT = (isalpha(axt->tSym[i]) ? 1 : 0);
+    thisIn = (advanceQ && advanceT);
+    if (thisIn)
+        {
+	if (!lastIn)
+	    {
+	    qStart = qPos;
+	    tStart = tPos;
+	    }
+	}
+    else
+        {
+	if (lastIn)
+	    {
+	    int size = qPos - qStart;
+	    assert(size == tPos - tStart);
+	    if (size > 0)
+	        {
+		struct cBlock *b;
+		AllocVar(b);
+		b->qStart = qStart;
+		b->qEnd = qPos;
+		b->tStart = tStart;
+		b->tEnd = tPos;
+		slAddHead(pList, b);
+		}
+	    }
+	}
+    lastIn = thisIn;
+    qPos += advanceQ;
+    tPos += advanceT;
+    }
+}
+
+void axtPrintTraditionalExtra(struct axt *axt, int maxLine,
+			      struct axtScoreScheme *ss, FILE *f,
+			      boolean reverseTPos, boolean reverseQPos)
+/* Print out an alignment with line-breaks.  If reverseTPos is true, then
+ * the sequence has been reverse complemented, so show the coords starting
+ * at tEnd and decrementing down to tStart; likewise for reverseQPos. */
+{
+int qPos = axt->qStart;
+int tPos = axt->tStart;
+int symPos;
+int aDigits = digitsBaseTen(axt->qEnd);
+int bDigits = digitsBaseTen(axt->tEnd);
+int digits = max(aDigits, bDigits);
+int qFlipOff = axt->qEnd + axt->qStart;
+int tFlipOff = axt->tEnd + axt->tStart;
+
+for (symPos = 0; symPos < axt->symCount; symPos += maxLine)
+    {
+    /* Figure out which part of axt to use for this line. */
+    int lineSize = axt->symCount - symPos;
+    int lineEnd, i;
+    if (lineSize > maxLine)
+        lineSize = maxLine;
+    lineEnd = symPos + lineSize;
+
+    /* Draw query line including numbers. */
+    fprintf(f, "%0*d ", digits, (reverseQPos ? qFlipOff - qPos: qPos+1));
+    for (i=symPos; i<lineEnd; ++i)
+        {
+	char c = axt->qSym[i];
+	fputc(c, f);
+	if (c != '.' && c != '-')
+	    ++qPos;
+	}
+    fprintf(f, " %0*d\n", digits, (reverseQPos? qFlipOff - qPos + 1 : qPos));
+
+    /* Draw line with match/mismatch symbols. */
+    spaceOut(f, digits+1);
+    for (i=symPos; i<lineEnd; ++i)
+        {
+	char q = axt->qSym[i];
+	char t = axt->tSym[i];
+	char out = ' ';
+	if (q == t)
+	    out = '|';
+	else if (ss != NULL && ss->matrix[(int)q][(int)t] > 0)
+	    out = '+';
+	fputc(out, f);
+	}
+    fputc('\n', f);
+
+    /* Draw target line including numbers. */
+    fprintf(f, "%0*d ", digits, (reverseTPos ? tFlipOff - tPos : tPos+1));
+    for (i=symPos; i<lineEnd; ++i)
+        {
+	char c = axt->tSym[i];
+	fputc(c, f);
+	if (c != '.' && c != '-')
+	    ++tPos;
+	}
+    fprintf(f, " %0*d\n", digits, (reverseTPos ? tFlipOff - tPos + 1: tPos));
+
+    /* Draw extra empty line. */
+    fputc('\n', f);
+    }
+}
+
+double axtIdWithGaps(struct axt *axt)
+/* Return ratio of matching bases to total symbols in alignment. */
+{
+int i;
+int matchCount = 0;
+for (i=0; i<axt->symCount; ++i)
+    {
+    if (toupper(axt->qSym[i]) == toupper(axt->tSym[i]))
+        ++matchCount;
+    }
+return (double)matchCount/axt->symCount;
+}
+
+void axtPrintTraditional(struct axt *axt, int maxLine, struct axtScoreScheme *ss, FILE *f)
+/* Print out an alignment with line-breaks. */
+{
+axtPrintTraditionalExtra(axt, maxLine, ss, f, FALSE, FALSE);
+}
+
+double axtCoverage(struct axt *axt, int qSize, int tSize)
+/* Return % of q and t covered. */
+{
+double cov = axt->tEnd - axt->tStart + axt->qEnd - axt->qStart;
+return cov/(qSize+tSize);
+}
+
+void axtOutPretty(struct axt *axt, int lineSize, FILE *f)
+/* Output axt in pretty format. */
+{
+char *q = axt->qSym;
+char *t = axt->tSym;
+int size = axt->symCount;
+int oneSize, sizeLeft = size;
+int i;
+
+fprintf(f, ">%s:%d%c%d %s:%d-%d %d\n", 
+	axt->qName, axt->qStart, axt->qStrand, axt->qEnd,
+	axt->tName, axt->tStart, axt->tEnd, axt->score);
+while (sizeLeft > 0)
+    {
+    oneSize = sizeLeft;
+    if (oneSize > lineSize)
+        oneSize = lineSize;
+    mustWrite(f, q, oneSize);
+    fputc('\n', f);
+
+    for (i=0; i<oneSize; ++i)
+        {
+	if (toupper(q[i]) == toupper(t[i]) && isalpha(q[i]))
+	    fputc('|', f);
+	else
+	    fputc(' ', f);
+	}
+    fputc('\n', f);
+
+    if (oneSize > lineSize)
+        oneSize = lineSize;
+    mustWrite(f, t, oneSize);
+    fputc('\n', f);
+    fputc('\n', f);
+    sizeLeft -= oneSize;
+    q += oneSize;
+    t += oneSize;
+    }
+}
diff --git a/lib/axtAffine.c b/lib/axtAffine.c
new file mode 100644
index 0000000..27e184f
--- /dev/null
+++ b/lib/axtAffine.c
@@ -0,0 +1,781 @@
+/* axtAffine - do alignment of two (shortish) sequences with
+ * affine gap scoring, and return the result as an axt. 
+ * This file is copyright 2000-2004 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "pairHmm.h"
+#include "axt.h"
+
+
+
+boolean axtAffineSmallEnough(double querySize, double targetSize)
+/* Return TRUE if it is reasonable to align sequences of given sizes
+ * with axtAffine. */
+{
+return targetSize * querySize <= 1.0E8;
+}
+
+static void affineAlign(char *query, int querySize, 
+	char *target, int targetSize, struct axtScoreScheme *ss,
+	struct phmmMatrix **retMatrix, struct phmmAliPair **retPairList,
+	int *retScore)
+/* Use dynamic programming to do alignment including affine gap
+ * scores. */
+{
+struct phmmMatrix *a;
+struct phmmState *hf, *iq, *it;
+int qIx, tIx, sIx;  /* Query, target, and state indices */
+int rowOffset, newCellOffset;
+int bestScore = -0x4fffffff;
+struct phmmMommy *bestCell = NULL;
+int matchPair;
+int gapStart, gapExt;
+
+/* Check that it's not too big. */
+if (!axtAffineSmallEnough(querySize, targetSize))
+    errAbort("Can't align %d x %d, too big\n", querySize, targetSize);
+
+gapStart = -ss->gapOpen;
+gapExt = -ss->gapExtend;
+
+/* Initialize 3 state matrix (match, query insert, target insert). */
+a = phmmMatrixNew(3, query, querySize, target, targetSize);
+hf = phmmNameState(a, 0, "match", 'M');
+iq = phmmNameState(a, 1, "qSlip", 'Q');
+it = phmmNameState(a, 2, "tSlip", 'T');
+
+for (tIx = 1; tIx < a->tDim; tIx += 1)
+    {
+    UBYTE mommy = 0;
+    int score, tempScore;
+
+/* Macros to make me less mixed up when accessing scores from row arrays.*/
+#define matchScore lastScores[qIx-1]
+#define qSlipScore lastScores[qIx]
+#define tSlipScore scores[qIx-1]
+#define newScore scores[qIx]
+
+/* Start up state block (with all ways to enter state) */
+#define startState(state) \
+   score = 0;
+
+/* Define a transition from state while advancing over both
+ * target and query. */
+#define matchState(state, addScore) \
+   { \
+   if ((tempScore = state->matchScore + addScore) > score) \
+        { \
+        mommy = phmmPackMommy(state->stateIx, -1, -1); \
+        score = tempScore; \
+        } \
+   } 
+
+/* Define a transition from state while slipping query
+ * and advancing target. */
+#define qSlipState(state, addScore) \
+   { \
+   if ((tempScore = state->qSlipScore + addScore) > score) \
+        { \
+        mommy = phmmPackMommy(state->stateIx, 0, -1); \
+        score = tempScore; \
+        } \
+   }
+
+/* Define a transition from state while slipping target
+ * and advancing query. */
+#define tSlipState(state, addScore) \
+   { \
+   if ((tempScore = state->tSlipScore + addScore) > score) \
+        { \
+        mommy = phmmPackMommy(state->stateIx, -1, 0); \
+        score = tempScore; \
+        } \
+   }
+
+/* End a block of transitions into state. */
+#define endState(state) \
+    { \
+    struct phmmMommy *newCell = state->cells + newCellOffset; \
+    if (score <= 0) \
+        { \
+        mommy = phmmNullMommy; \
+        score = 0; \
+        } \
+    newCell->mommy = mommy; \
+    state->newScore = score; \
+    if (score > bestScore) \
+        { \
+        bestScore = score; \
+        bestCell = newCell; \
+        } \
+    } 
+
+/* End a state that you know won't produce an optimal
+ * final score. */
+#define shortEndState(state) \
+    { \
+    struct phmmMommy *newCell = state->cells + newCellOffset; \
+    if (score <= 0) \
+        { \
+        mommy = phmmNullMommy; \
+        score = 0; \
+        } \
+    newCell->mommy = mommy; \
+    state->newScore = score; \
+    }
+
+
+    rowOffset = tIx*a->qDim;
+    for (qIx = 1; qIx < a->qDim; qIx += 1)
+        {
+        newCellOffset = rowOffset + qIx;
+        
+        /* Figure the cost or bonus for pairing target and query residue here. */
+        matchPair = ss->matrix[(int)a->query[qIx-1]][(int)a->target[tIx-1]];
+
+        /* Update hiFi space. */
+            {
+            startState(hf);
+            matchState(hf, matchPair);
+            matchState(iq, matchPair);
+            matchState(it, matchPair);
+            endState(hf);
+            }
+
+        /* Update query slip space. */
+            {
+            startState(iq);
+            qSlipState(iq, gapExt);
+            qSlipState(hf, gapStart);            
+	    qSlipState(it, gapStart);	/* Allow double gaps, T first always. */
+            shortEndState(iq);
+            }
+        
+        /* Update target slip space. */
+            {
+            startState(it);
+            tSlipState(it, gapExt);
+            tSlipState(hf, gapStart);            
+            shortEndState(it);
+            }
+
+        }
+    /* Swap score columns so current becomes last, and last gets
+     * reused. */
+    for (sIx = 0; sIx < a->stateCount; ++sIx)
+        {
+        struct phmmState *as = &a->states[sIx];
+        int *swapTemp = as->lastScores;
+        as->lastScores = as->scores;
+        as->scores = swapTemp;
+        }
+    }
+
+/* Trace back from best scoring cell. */
+*retPairList = phmmTraceBack(a, bestCell);
+*retMatrix = a;
+*retScore = bestScore;
+
+#undef matchScore
+#undef qSlipScore
+#undef tSlipScore
+#undef newScore
+#undef startState
+#undef matchState
+#undef qSlipState
+#undef tSlipState
+#undef shortEndState
+#undef endState
+}
+
+struct axt *axtAffine(bioSeq *query, bioSeq *target, struct axtScoreScheme *ss)
+/* Return alignment if any of query and target using scoring scheme. */
+{
+struct axt *axt;
+int score;
+struct phmmMatrix *matrix;
+struct phmmAliPair *pairList;
+
+affineAlign(query->dna, query->size, target->dna, target->size, ss,
+	&matrix, &pairList, &score);
+axt = phhmTraceToAxt(matrix, pairList, score, query->name, target->name);
+phmmMatrixFree(&matrix);
+slFreeList(&pairList);
+return axt;
+}
+
+
+/* ----- axtAffine2Level begins ----- 
+
+ Written by Galt Barber, December 2004
+ I wrote this on my own time and am donating this
+ to the public domain.  The original concept 
+ was Don Speck's, as described by Kevin Karplus.
+
+ @article{Grice97,
+     author = "J. A. Grice and R. Hughey and D. Speck",
+     title = "Reduced space sequence alignment",
+     journal = cabios,
+     volume=13,
+     number=1,
+     year=1997,
+     month=feb,
+     pages="45-53"
+     }
+								 
+
+*/
+
+#define WORST 0xC0000000 /* WORST Score approx neg. inf. 0x80000000 overflowed, reduced by half */
+
+
+/* m d i notation: match, delete, insert in query */
+
+struct cell2L 
+{
+int  bestm;   /* best score array */
+int  bestd;                         
+int  besti;                          
+char backm;   /* back trace array */
+char backd;                         
+char backi;                          
+};
+
+#ifdef DEBUG
+void dump2L(struct cell2L* c)
+/* print matrix cell for debugging 
+   I redirect output to a file 
+   and look at it with a web browser
+   to see the long lines
+*/
+{
+    printf("%04d%c %04d%c %04d%c   ",
+     c->bestd, c->backd,
+     c->bestm, c->backm,
+     c->besti, c->backi
+     );
+}     
+#endif
+
+void kForwardAffine(
+struct cell2L *cells,  /* dyn prg arr cells */
+int row,      /* starting row base */
+int rowmax,   /* ending row */
+int rdelta,   /* convert between real targ seq row and logical row */                             
+int cmost,    /* track right edge, shrink as traces back */
+int lv,       /* width of array including sentinel col 0 */ 
+char *q,      /* query and target seqs */
+char *t,
+struct axtScoreScheme *ss,  /* score scheme passed in */
+int *bestbestOut,  /* return best overall found, and it's row and col */
+int *bestrOut,
+int *bestcOut,
+char *bestdirOut
+)
+/*
+Calculates filling dynprg mtx forward.
+ Called 3 times from affine2Level.
+
+row is offset into the actual best and back arrays,
+ so rdelta serves as a conversion between
+ the real target seq row and the logical row
+ used in best and back arrays.
+
+cmost is a column limiter that lets us avoid
+ unused areas of the array when doing the
+ backtrace 2nd pass. This can be an average
+ of half of the total array saved.
+
+*/
+{
+int r=0, rr=0;
+int gapOpen  =ss->gapOpen;    
+int gapExtend=ss->gapExtend;  
+int doubleGap=ss->gapExtend;  // this can be gapOpen or gapExtend, or custom ?
+struct cell2L *cellp,*cellc;  /* current and previous row base */
+struct cell2L *u,*d,*l,*s;    /* up,diag,left,self pointers to hopefully speed things up */
+int c=0;
+int bestbest = *bestbestOut; /* make local copy of best best */
+cellc = cells+(row-1)*lv;     /* start it off one row back coming into loop */
+
+#ifdef DEBUG
+for(c=0;c<=cmost;c++) /* show prev row */
+    { dump2L(cellc+c); }
+printf("\n");
+#endif
+
+for(r=row; r<=rowmax; r++)
+    {
+    cellp = cellc;
+    cellc += lv;    /* initialize pointers to curr and prev rows */
+    
+    rr = r+rdelta;
+
+    d = cellp;   /* diag is prev row, prev col */
+    l = cellc;   /* left is curr row, prev col */
+    u = d+1;     /*   up is prev row, curr col */
+    s = l+1;     /* self is curr row, curr col */
+    
+    /* handle col 0 sentinel as a delete */
+    l->bestm=WORST; 
+    l->bestd=d->bestd-gapExtend;
+    l->besti=WORST;                 
+    l->backm='x';
+    l->backd='d';
+    l->backi='x';
+    if (rr==1)    /* special case row 1 col 0 */
+	{
+	l->bestd=-gapOpen;
+	l->backd='m';
+	}
+#ifdef DEBUG
+    dump2L(cellc); 
+#endif
+    
+    for(c=1; c<=cmost; c++)
+	{
+
+	int best=WORST;
+	int try  =WORST;
+	char dir=' ';
+	/* note: is matrix symmetrical? if not we could have dim 1 and 2 backwards */
+	int subst = ss->matrix[(int)q[c-1]][(int)t[rr-1]];  /* score for pairing target and query. */
+
+	/* find best M match query and target */
+	best=WORST;
+	try=d->bestd;    
+	if (try > best)
+	    {
+	    best=try;
+	    dir='d';
+	    }
+	try=d->bestm;   
+	if (try > best)
+	    {
+	    best=try;
+	    dir='m';
+	    }
+	try=d->besti;   
+	if (try > best)
+	    {
+	    best=try;
+	    dir='i';
+	    }
+	try=0;                   /* local ali can start anywhere */
+	if (try > best)
+	    {
+	    best=try;
+	    dir='s';         
+	    }
+	best += subst;
+	s->bestm = best;
+	s->backm = dir;
+	if (best > bestbest)
+	    {
+	    bestbest=best;
+	    *bestbestOut=best;
+	    *bestrOut=rr;
+	    *bestcOut=c;
+	    *bestdirOut=dir;
+	    }
+
+	/* find best D delete in query */
+	best=WORST;
+	try=u->bestd - gapExtend;
+	if (try > best)
+	    {
+	    best=try;
+	    dir='d';
+	    }
+	try=u->bestm - gapOpen;    
+	if (try > best)
+	    {
+	    best=try;
+	    dir='m';
+	    }
+	try=u->besti - doubleGap;    
+	if (try > best)
+	    {
+	    best=try;
+	    dir='i';
+	    }
+	s->bestd = best;
+	s->backd = dir;
+	if (best > bestbest)
+	    {
+	    bestbest=best;
+	    *bestbestOut=best;
+	    *bestrOut=rr;
+	    *bestcOut=c;
+	    *bestdirOut=dir;
+	    }
+
+	/* find best I insert in query */
+	best=WORST;
+	try=l->bestd - doubleGap;
+	if (try > best)
+	    {
+	    best=try;
+	    dir='d';
+	    }
+	try=l->bestm - gapOpen;    
+	if (try > best)
+	    {
+	    best=try;
+	    dir='m';
+	    }
+	try=l->besti - gapExtend;    
+	if (try > best)
+	    {
+	    best=try;
+	    dir='i';
+	    }
+	s->besti = best;
+	s->backi = dir;
+	if (best > bestbest)
+	    {
+	    bestbest=best;
+	    *bestbestOut=best;
+	    *bestrOut=rr;
+	    *bestcOut=c;
+	    *bestdirOut=dir;
+	    }
+
+#ifdef DEBUG
+    dump2L(cellc+c); 
+#endif
+
+	d++;l++;u++;s++;
+
+	}
+#ifdef DEBUG
+printf("\n");
+#endif
+  
+    }
+} 
+
+
+
+struct axt *axtAffine2Level(bioSeq *query, bioSeq *target, struct axtScoreScheme *ss)
+/* 
+
+   (Moving boundary version, allows target T size twice as large in same ram)
+
+   Return alignment if any of query and target using scoring scheme. 
+   
+   2Level uses an economical amount of ram and should work for large target sequences.
+   
+   If Q is query size and T is target size and M is memory size, then
+   Total memory used M = 30*Q*sqrt(T).  When the target is much larger than the query
+   this method saves ram, and average runtime is only 50% greater, or 1.5 QT.  
+   If Q=5000 and T=245,522,847 for hg17 chr1, then M = 2.2 GB ram.  
+   axtAffine would need M=3QT = 3.4 TB.
+   Of course massive alignments will be painfully slow anyway.
+
+   Works for protein as well as DNA given the correct scoreScheme.
+  
+   NOTES:
+   Double-gap cost is equal to gap-extend cost, but gap-open would also work.
+   On very large target, score integer may overflow.
+   Input sequences not checked for invalid chars.
+   Input not checked but query should be shorter than target.
+   
+*/
+{
+struct axt *axt=needMem(sizeof(struct axt));
+
+char *q = query->dna;
+char *t = target->dna;
+
+int Q= query->size;
+int T=target->size;
+int lv=Q+1;                    /* Q+1 is used so often let's call it lv for q-width */
+int lw=T+1;                    /* T+1 is used so often let's call it lw for t-height */
+
+
+int r = 0;                                 /* row matrix index */
+int c = 0;                                 /* col matrix index */
+char dir=' ';                              /* dir for bt */
+int bestbest = WORST;                      /* best score in entire mtx */
+
+int k=0;                                   /* save every kth row (k decreasing) */
+int ksize = 0;                             /* T+1 saved rows as ksize, ksize-1,...,1*/
+int arrsize = 0;                           /* dynprg array size, +1 for 0 sentinel col. */
+struct cell2L *cells = NULL;               /* best score dyn prog array */
+int ki = 0;                                /* base offset into array */
+int cmost = Q;                             /* track right edge shrinkage during backtrace */
+int kmax = 0;                              /* rows range from ki to kmax */
+int rr = 0;                                /* maps ki base to actual target seq */
+int nrows = 0;                             /* num rows to do, usually k or less */
+int bestr = 0;                             /* remember best r,c,dir for local ali */
+int bestc = 0;           
+char bestdir = 0;
+int temp = 0;
+
+
+char *btq=NULL;      /* temp pointers to track ends of string while accumulating */
+char *btt=NULL;
+
+ksize = (int) (-1 + sqrt(8*lw+1))/2;    
+if (((ksize*(ksize+1))/2) < lw) 
+    {ksize++;}
+arrsize = (ksize+1) * lv;                 /* dynprg array size, +1 for lastrow that moves back up. */
+cells = needLargeMem(arrsize * sizeof(struct cell2L));   /* best score dyn prog array */
+
+#ifdef DEBUG
+printf("\n k=%d \n ksize=%d \n arrsize=%d \n Q,lv=%d,%d T=%d \n \n",k,ksize,arrsize,Q,lv,T);
+#endif
+
+axt->next = NULL;
+axt->qName = cloneString(query->name);
+axt->tName = cloneString(target->name);
+axt->qStrand ='+';
+axt->tStrand ='+';
+axt->frame = 0;
+axt->score=0;
+axt->qStart=0;
+axt->tStart=0;
+axt->qEnd=0;
+axt->tEnd=0;
+axt->symCount=0;
+axt->qSym=NULL;
+axt->tSym=NULL;
+
+if ((Q==0) || (T==0))
+    {
+    axt->qSym=cloneString("");
+    axt->tSym=cloneString("");
+    freez(&cells);
+    return axt; 
+    }
+
+
+
+/* initialize origin corner */
+    cells[0].bestm=0;
+    cells[0].bestd=WORST;
+    cells[0].besti=WORST;                 
+    cells[0].backm='x';
+    cells[0].backd='x';
+    cells[0].backi='x';
+#ifdef DEBUG
+    dump2L(cells); 
+#endif
+
+/* initialize row 0 col 1 */
+    cells[1].bestm=WORST;
+    cells[1].bestd=WORST;
+    cells[1].besti=-ss->gapOpen;
+    cells[1].backm='x';
+    cells[1].backd='x';
+    cells[1].backi='m';
+#ifdef DEBUG
+    dump2L(cells+1); 
+#endif
+
+/* initialize first row of sentinels */
+for (c=2;c<lv;c++)
+    {
+    cells[c].bestm=WORST;
+    cells[c].bestd=WORST;
+    cells[c].besti=cells[c-1].besti-ss->gapExtend;
+    cells[c].backm='x';
+    cells[c].backd='x';
+    cells[c].backi='i';
+#ifdef DEBUG
+    dump2L(cells+c); 
+#endif
+    }
+#ifdef DEBUG
+printf("\n");
+printf("\n");
+#endif
+
+k=ksize;
+
+ki++;  /* advance to next row */
+
+r=1;   /* r is really the rows all done */
+while(1)
+    {
+    nrows = k;  /* do k rows at a time, save every kth row on 1st pass */
+    if (nrows > (lw-r)) {nrows=lw-r;}  /* may get less than k on last set */
+    kmax = ki+nrows-1;
+
+    kForwardAffine(cells, ki, kmax, r-ki, cmost, lv, q, t, ss, &bestbest, &bestr, &bestc, &bestdir);
+#ifdef DEBUG
+printf("\n");
+#endif
+
+    r += nrows;
+
+    if (nrows == k)   /* got full set of k rows */
+	{
+	/* compress, save every kth row */     
+	/* optimize as a mem-copy */
+	memcpy(cells+ki*lv,cells+kmax*lv,sizeof(struct cell2L) *lv);    
+	}
+
+    if (r >= lw){break;} /* we are done */
+    
+    ki++;
+    k--;        /* decreasing k is "moving boundary" */
+}
+
+#ifdef DEBUG
+printf("\nFWD PASS DONE. bestbest=%d bestr=%d bestc=%d bestdir=%c \n\n",bestbest,bestr,bestc,bestdir);
+#endif
+
+/* start doing backtrace */
+    
+/* adjust for reverse pass */
+
+/* for local we automatically skip to bestr, bestc to begin tb */
+
+if (bestbest <= 0)  /* null alignment */
+    {
+    bestr=0;
+    bestc=0;
+    /* bestdir won't matter */
+    }
+
+r = bestr;
+c = bestc;
+dir = bestdir;
+cmost = c;
+
+axt->qEnd=bestc;
+axt->tEnd=bestr;
+
+temp = (2*ksize)+1;
+ki = (int)(temp-sqrt((temp*temp)-(8*r)))/2;
+rr = ((2*ksize*ki)+ki-(ki*ki))/2;
+kmax = ki+(r-rr);
+k = ksize - ki;
+
+
+/* now that we jumped back into saved start-points,
+   let's fill the array forward and start backtrace from there.
+*/
+
+#ifdef DEBUG
+printf("bestr=%d, bestc=%d, bestdir=%c k=%d, ki=%d, kmax=%d\n",bestr,bestc,bestdir,k,ki,kmax);
+#endif
+
+kForwardAffine(cells, ki+1, kmax, rr-ki, cmost, lv, q, t, ss, &bestbest, &bestr, &bestc, &bestdir);
+   
+#ifdef DEBUG
+printf("\n(initial)BKWD PASS DONE. cmost=%d r=%d c=%d dir=%c \n\n",cmost,r,c,dir);
+#endif
+
+
+/* backtrace */   
+
+/* handling for resulting ali'd strings when very long */
+
+axt->symCount=0;
+axt->qSym = needLargeMem((Q+T+1)*sizeof(char));
+axt->tSym = needLargeMem((Q+T+1)*sizeof(char));
+btq=axt->qSym;
+btt=axt->tSym;
+while(1)
+    {
+    while(1)
+	{
+#ifdef DEBUG
+	printf("bt: r=%d, c=%d, dir=%c \n",r,c,dir);
+#endif
+
+	
+    	if ((r==0) && (c==0)){break;} /* hit origin, done */
+	if (r<rr){break;} /* ran out of targ seq, backup and reload */
+	if (dir=='x'){errAbort("unexpected error backtracing");} /* x only at origin */
+	if (dir=='s'){break;}   /* hit start, local ali */
+	if (dir=='m') /* match */
+	    {
+	    *btq++=q[c-1];  /* accumulate alignment output strings */
+	    *btt++=t[r-1];  /* accumulate alignment output strings */
+	    axt->symCount++; 
+	    dir = cells[lv*(ki+r-rr)+c].backm;  /* follow backtrace */
+	    r--;            /* adjust coords to move in dir spec'd by back ptr */
+	    c--;
+	    cmost--;        /* decreases as query seq is aligned, so saves on unused areas */
+	    }
+	else
+	    {
+	    if (dir=='d')  /* delete in query (gap) */
+		{
+		*btq++='-';     /* accumulate alignment output strings */
+    		*btt++=t[r-1];  /* accumulate alignment output strings */
+    		axt->symCount++; 
+		dir = cells[lv*(ki+r-rr)+c].backd;  /* follow backtrace */
+    		r--;            /* adjust coords to move in dir spec'd by back ptr */
+		}
+	    else    /* insert in query (gap) */
+		{
+		*btq++=q[c-1];  /* accumulate alignment output strings */
+    		*btt++='-';     /* accumulate alignment output strings */
+    		axt->symCount++; 
+		dir = cells[lv*(ki+r-rr)+c].backi;  /* follow backtrace */
+    		c--;
+    		cmost--;        /* decreases as query seq is aligned, so saves on unused areas */
+		}
+	    }
+	
+	}
+
+    /* back up and do it again */
+    ki--;
+    k++;   /* k grows as we move back up */ 
+    rr-=k;
+    kmax = ki+k-1;
+
+    /* check for various termination conditions to stop main loop */
+    if (ki < 0) {break;}
+    if ((r==0)&&(c==0)) {break;}
+    if (dir=='s') {break;}
+
+    /* re-calculate array from previous saved kth row going back
+       this is how we save memory, but have to regenerate half on average
+       we are re-using the same call 
+     */
+
+#ifdef DEBUG
+printf("bestr=%d, bestc=%d, bestdir=%c k=%d, ki=%d, kmax=%d\n",bestr,bestc,bestdir,k,ki,kmax);
+#endif
+
+
+    kForwardAffine(cells, ki+1, kmax, rr-ki, cmost, lv, q, t, ss, &bestbest, &bestr, &bestc, &bestdir);
+
+#ifdef DEBUG
+    printf("\nBKWD PASS DONE. cmost=%d r=%d c=%d\n\n",cmost,r,c);
+#endif
+
+    }
+
+axt->qStart=c;
+axt->tStart=r;
+
+/* reverse backwards trace and zero-terminate strings */
+
+reverseBytes(axt->qSym,axt->symCount);
+reverseBytes(axt->tSym,axt->symCount);
+axt->qSym[axt->symCount]=0;
+axt->tSym[axt->symCount]=0;
+
+axt->score=bestbest;
+
+
+/* 
+should I test stringsize and if massively smaller, realloc string to save ram? 
+*/
+
+freez(&cells);
+
+return axt;
+}
+
+
+
diff --git a/lib/bPlusTree.c b/lib/bPlusTree.c
new file mode 100644
index 0000000..4af4144
--- /dev/null
+++ b/lib/bPlusTree.c
@@ -0,0 +1,440 @@
+/* bptFile - B+ Trees.  These are a method of indexing data similar to binary trees, but 
+ * with many children rather than just two at each node. They work well when stored on disk,
+ * since typically only two or three disk accesses are needed to locate any particular
+ * piece of data.  This implementation is *just* for disk based storage.  For memory
+ * use the rbTree instead. Currently the implementation is just useful for data warehouse
+ * type applications.  That is it implements a function to create a b+ tree from bulk data
+ * (bptFileCreate) and a function to lookup a value given a key (bptFileFind) but not functions
+ * to add or delete individual items.
+ *
+ * The layout of the file on disk is:
+ *    header
+ *    root node
+ *    (other nodes)
+ * In general when the tree is first built the higher level nodes are stored before the
+ * lower level nodes.  It is possible if a b+ tree is dynamically updated for this to
+ * no longer be strictly true, but actually currently the b+ tree code here doesn't implement
+ * dynamic updates - it just creates a b+ tree from a sorted list.
+ *
+ * Each node can be one of two types - index or leaf.  The index nodes contain pointers
+ * to child nodes.  The leaf nodes contain the actual data. 
+ *
+ * The layout of the file header is:
+ *       <magic number>  4 bytes - The value bptSig (0x78CA8C91)
+ *       <block size>    4 bytes - Number of children per block (not byte size of block)
+ *       <key size>      4 bytes - Number of significant bytes in key
+ *       <val size>      4 bytes - Number of bytes in value
+ *       <item count>    8 bytes - Number of items in index
+ *       <reserved2>     4 bytes - Always 0 for now
+ *       <reserved3>     4 bytes - Always 0 for now
+ * The magic number may be byte-swapped, in which case all numbers in the file
+ * need to be byte-swapped. 
+ *
+ * The nodes start with a header:
+ *       <is leaf>       1 byte  - 1 for leaf nodes, 0 for index nodes.
+ *       <reserved>      1 byte  - Always 0 for now.
+ *       <count>         2 bytes - The number of children/items in node
+ * This is followed by count items.  For the index nodes the items are
+ *       <key>           key size bytes - always written most significant byte first
+ *       <offset>        8 bytes - Offset of child node in index file.
+ * For leaf nodes the items are
+ *       <key>           key size bytes - always written most significant byte first
+ *       <val>           val sized bytes - the value associated with the key.
+ * Note in general the leaf nodes may not be the same size as the index nodes, though in
+ * the important case where the values are file offsets they will be.
+ */
+
+#include "common.h"
+#include "sig.h"
+#include "udc.h"
+#include "bPlusTree.h"
+
+/* This section of code deals with locating a value in a b+ tree. */
+
+struct bptFile *bptFileAttach(char *fileName, struct udcFile *udc)
+/* Open up index file on previously open file, with header at current file position. */
+{
+/* Open file and allocate structure to hold info from header etc. */
+struct bptFile *bpt = needMem(sizeof(*bpt));
+bpt->fileName = fileName;
+bpt->udc = udc;
+
+/* Read magic number at head of file and use it to see if we are proper file type, and
+ * see if we are byte-swapped. */
+bits32 magic;
+boolean isSwapped = FALSE;
+udcMustReadOne(udc, magic);
+if (magic != bptSig)
+    {
+    magic = byteSwap32(magic);
+    isSwapped = bpt->isSwapped = TRUE;
+    if (magic != bptSig)
+       errAbort("%s is not a bpt b-plus tree index file", fileName);
+    }
+
+/* Read rest of defined bits of header, byte swapping as needed. */
+bpt->blockSize = udcReadBits32(udc, isSwapped);
+bpt->keySize = udcReadBits32(udc, isSwapped);
+bpt->valSize = udcReadBits32(udc, isSwapped);
+bpt->itemCount = udcReadBits64(udc, isSwapped);
+
+/* Skip over reserved bits of header. */
+bits32 reserved32;
+udcMustReadOne(udc, reserved32);
+udcMustReadOne(udc, reserved32);
+
+/* Save position of root block of b+ tree. */
+bpt->rootOffset = udcTell(udc);
+
+return bpt;
+}
+
+void bptFileDetach(struct bptFile **pBpt)
+/* Detach and free up cirTree file opened with cirTreeFileAttach. */
+{
+freez(pBpt);
+}
+
+struct bptFile *bptFileOpen(char *fileName)
+/* Open up index file - reading header and verifying things. */
+{
+return bptFileAttach(cloneString(fileName), udcFileOpen(fileName, udcDefaultDir()));
+}
+
+void bptFileClose(struct bptFile **pBpt)
+/* Close down and deallocate index file. */
+{
+struct bptFile *bpt = *pBpt;
+if (bpt != NULL)
+    {
+    udcFileClose(&bpt->udc);
+    freeMem(bpt->fileName);
+    bptFileDetach(pBpt);
+    }
+}
+
+static boolean rFind(struct bptFile *bpt, bits64 blockStart, void *key, void *val)
+/* Find value corresponding to key.  If found copy value to memory pointed to by val and return 
+ * true. Otherwise return false. */
+{
+/* Seek to start of block. */
+udcSeek(bpt->udc, blockStart);
+
+/* Read block header. */
+UBYTE isLeaf;
+UBYTE reserved;
+bits16 i, childCount;
+udcMustReadOne(bpt->udc, isLeaf);
+udcMustReadOne(bpt->udc, reserved);
+boolean isSwapped = bpt->isSwapped;
+childCount = udcReadBits16(bpt->udc, isSwapped);
+
+UBYTE keyBuf[bpt->keySize];   /* Place to put a key, buffered on stack. */
+
+if (isLeaf)
+    {
+    for (i=0; i<childCount; ++i)
+        {
+	udcMustRead(bpt->udc, keyBuf, bpt->keySize);
+	udcMustRead(bpt->udc, val, bpt->valSize);
+	if (memcmp(key, keyBuf, bpt->keySize) == 0)
+	    return TRUE;
+	}
+    return FALSE;
+    }
+else
+    {
+    /* Read and discard first key. */
+    udcMustRead(bpt->udc, keyBuf, bpt->keySize);
+
+    /* Scan info for first file offset. */
+    bits64 fileOffset = udcReadBits64(bpt->udc, isSwapped);
+
+    /* Loop through remainder. */
+    for (i=1; i<childCount; ++i)
+	{
+	udcMustRead(bpt->udc, keyBuf, bpt->keySize);
+	if (memcmp(key, keyBuf, bpt->keySize) < 0)
+	    break;
+	fileOffset = udcReadBits64(bpt->udc, isSwapped);
+	}
+    return rFind(bpt, fileOffset, key, val);
+    }
+}
+
+void rTraverse(struct bptFile *bpt, bits64 blockStart, void *context, 
+    void (*callback)(void *context, void *key, int keySize, void *val, int valSize) )
+/* Recursively go across tree, calling callback at leaves. */
+{
+/* Seek to start of block. */
+udcSeek(bpt->udc, blockStart);
+
+/* Read block header. */
+UBYTE isLeaf;
+UBYTE reserved;
+bits16 i, childCount;
+udcMustReadOne(bpt->udc, isLeaf);
+udcMustReadOne(bpt->udc, reserved);
+boolean isSwapped = bpt->isSwapped;
+childCount = udcReadBits16(bpt->udc, isSwapped);
+
+char keyBuf[bpt->keySize], valBuf[bpt->valSize];
+if (isLeaf)
+    {
+    for (i=0; i<childCount; ++i)
+        {
+	udcMustRead(bpt->udc, keyBuf, bpt->keySize);
+	udcMustRead(bpt->udc, valBuf, bpt->valSize);
+	callback(context, keyBuf, bpt->keySize, valBuf, bpt->valSize);
+	}
+    }
+else
+    {
+    bits64 fileOffsets[childCount];
+    /* Loop through to get file offsets of children. */
+    for (i=0; i<childCount; ++i)
+	{
+	udcMustRead(bpt->udc, keyBuf, bpt->keySize);
+	fileOffsets[i] = udcReadBits64(bpt->udc, isSwapped);
+	}
+    /* Loop through recursing on child offsets. */
+    for (i=0; i<childCount; ++i)
+	rTraverse(bpt, fileOffsets[i], context, callback);
+    }
+}
+
+boolean bptFileFind(struct bptFile *bpt, void *key, int keySize, void *val, int valSize)
+/* Find value associated with key.  Return TRUE if it's found. 
+*  Parameters:
+*     bpt - file handle returned by bptFileOpen
+*     key - pointer to key string, which needs to be bpt->keySize long
+*     val - pointer to where to put retrieved value
+*/
+{
+/* Check key size vs. file key size, and act appropriately.  If need be copy key to a local
+ * buffer and zero-extend it. */
+if (keySize > bpt->keySize)
+    return FALSE;
+char keyBuf[keySize];
+if (keySize != bpt->keySize)
+    {
+    memcpy(keyBuf, key, keySize);
+    memset(keyBuf+keySize, 0, bpt->keySize - keySize);
+    key = keyBuf;
+    }
+
+/* Make sure the valSize matches what's in file. */
+if (valSize != bpt->valSize)
+    errAbort("Value size mismatch between bptFileFind (valSize=%d) and %s (valSize=%d)",
+    	valSize, bpt->fileName, bpt->valSize);
+
+/* Call recursive finder. */
+return rFind(bpt, bpt->rootOffset, key, val);
+}
+
+void bptFileTraverse(struct bptFile *bpt, void *context,
+    void (*callback)(void *context, void *key, int keySize, void *val, int valSize) )
+/* Traverse bPlusTree on file, calling supplied callback function at each
+ * leaf item. */
+{
+return rTraverse(bpt, bpt->rootOffset, context, callback);
+}
+
+
+/* This section of code deals with making balanced b+ trees given a sorted array as input.
+ * The difficult part is mostly just calculating the offsets of various things.  As an example
+ * if you had the sorted array:
+ *   01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
+ * and wanted to create a tree of block size 4, the resulting tree would have three levels
+ * as so:
+ *  01 17
+ *  01 05 09 13   17 21 25
+ *  01 02 03 04   05 06 07 08  09 10 11 12   13 14 15 16   17 18 19 20   21 22 23 24  25 26 27
+ */
+
+static int xToY(int x, unsigned y)
+/* Return x to the Y power, with y usually small. */
+{
+int i, val = 1;
+for (i=0; i<y; ++i)
+    val *= x;
+return val;
+}
+
+static int bptCountLevels(int maxBlockSize, int itemCount)
+/* Count up number of levels needed in tree of given maximum block size. */
+{
+int levels = 1;
+while (itemCount > maxBlockSize)
+    {
+    itemCount = (itemCount + maxBlockSize - 1)  / maxBlockSize;
+    levels += 1;
+    }
+return levels;
+}
+
+
+static bits32 writeIndexLevel(bits16 blockSize, 
+	void *itemArray, int itemSize, int itemCount, 
+	bits32 indexOffset, int level, 
+	void (*fetchKey)(const void *va, char *keyBuf), bits32 keySize, bits32 valSize,
+	FILE *f)
+/* Write out a non-leaf level. */
+{
+char *items = itemArray;
+
+/* Calculate number of nodes to write at this level. */
+int slotSizePer = xToY(blockSize, level);   // Number of items per slot in node
+int nodeSizePer = slotSizePer * blockSize;  // Number of items per node
+int nodeCount = (itemCount + nodeSizePer - 1)/nodeSizePer;	
+
+/* Calculate sizes and offsets. */
+int bytesInIndexBlock = (bptBlockHeaderSize + blockSize * (keySize+sizeof(bits64)));
+int bytesInLeafBlock = (bptBlockHeaderSize + blockSize * (keySize+valSize));
+bits64 bytesInNextLevelBlock = (level == 1 ? bytesInLeafBlock : bytesInIndexBlock);
+bits64 levelSize = nodeCount * bytesInIndexBlock;
+bits64 endLevel = indexOffset + levelSize;
+bits64 nextChild = endLevel;
+
+UBYTE isLeaf = FALSE;
+UBYTE reserved = 0;
+
+int i,j;
+char keyBuf[keySize+1];
+keyBuf[keySize] = 0;
+for (i=0; i<itemCount; i += nodeSizePer)
+    {
+    /* Calculate size of this block */
+    bits16 countOne = (itemCount - i + slotSizePer - 1)/slotSizePer;
+    if (countOne > blockSize)
+        countOne = blockSize;
+
+    /* Write block header. */
+    writeOne(f, isLeaf);
+    writeOne(f, reserved);
+    writeOne(f, countOne);
+
+    /* Write out the slots that are used one by one, and do sanity check. */
+    int slotsUsed = 0;
+    int endIx = i + nodeSizePer;
+    if (endIx > itemCount)
+        endIx = itemCount;
+    for (j=i; j<endIx; j += slotSizePer)
+        {
+	void *item = items + j*itemSize;
+	memset(keyBuf, 0, keySize);
+	(*fetchKey)(item, keyBuf);
+	mustWrite(f, keyBuf, keySize);
+	writeOne(f, nextChild);
+	nextChild += bytesInNextLevelBlock;
+	++slotsUsed;
+	}
+    assert(slotsUsed == countOne);
+
+    /* Write out empty slots as all zero. */
+    int slotSize = keySize + sizeof(bits64);
+    for (j=countOne; j<blockSize; ++j)
+	repeatCharOut(f, 0, slotSize);
+    }
+return endLevel;
+}
+
+static void writeLeafLevel(bits16 blockSize, void *itemArray, int itemSize, int itemCount, 
+	void (*fetchKey)(const void *va, char *keyBuf), bits32 keySize,
+	void* (*fetchVal)(const void *va), bits32 valSize,
+	FILE *f)
+/* Write out leaf level blocks. */
+{
+char *items = itemArray;
+int i,j;
+UBYTE isLeaf = TRUE;
+UBYTE reserved = 0;
+bits16 countOne;
+int countLeft = itemCount;
+char keyBuf[keySize+1];
+keyBuf[keySize] = 0;
+for (i=0; i<itemCount; i += countOne)
+    {
+    /* Write block header */
+    if (countLeft > blockSize)
+        countOne = blockSize;
+    else
+        countOne = countLeft;
+    writeOne(f, isLeaf);
+    writeOne(f, reserved);
+    writeOne(f, countOne);
+
+    /* Write out position in genome and in file for each item. */
+    for (j=0; j<countOne; ++j)
+        {
+	assert(i+j < itemCount);
+	void *item = items + (i+j)*itemSize;
+	memset(keyBuf, 0, keySize);
+	(*fetchKey)(item, keyBuf);
+	mustWrite(f, keyBuf, keySize);
+	mustWrite(f, (*fetchVal)(item), valSize);
+	}
+    
+    /* Pad out any unused bits of last block with zeroes. */
+    int slotSize = keySize + valSize;
+    for (j=countOne; j<blockSize; ++j)
+	repeatCharOut(f, 0, slotSize);
+
+    countLeft -= countOne;
+    }
+}
+
+void bptFileBulkIndexToOpenFile(void *itemArray, int itemSize, bits64 itemCount, bits32 blockSize,
+	void (*fetchKey)(const void *va, char *keyBuf), bits32 keySize,
+	void* (*fetchVal)(const void *va), bits32 valSize, FILE *f)
+/* Create a b+ tree index from a sorted array, writing output starting at current position
+ * of an already open file.  See bptFileCreate for explanation of parameters. */
+{
+bits32 magic = bptSig;
+bits32 reserved = 0;
+writeOne(f, magic);
+writeOne(f, blockSize);
+writeOne(f, keySize);
+writeOne(f, valSize);
+writeOne(f, itemCount);
+writeOne(f, reserved);
+writeOne(f, reserved);
+bits64 indexOffset = ftell(f);
+
+/* Write non-leaf nodes. */
+int levels = bptCountLevels(blockSize, itemCount);
+int i;
+for (i=levels-1; i > 0; --i)
+    {
+    bits32 endLevelOffset = writeIndexLevel(blockSize, itemArray, itemSize, itemCount, indexOffset, 
+    	i, fetchKey, keySize, valSize, f);
+    indexOffset = ftell(f);
+    if (endLevelOffset != indexOffset)
+        internalErr();
+    }
+
+/* Write leaf nodes */
+writeLeafLevel(blockSize, itemArray, itemSize, itemCount, 
+	fetchKey, keySize, fetchVal, valSize, f);
+}
+
+void bptFileCreate(
+	void *itemArray, 	/* Sorted array of things to index. */
+	int itemSize, 		/* Size of each element in array. */
+	bits64 itemCount, 	/* Number of elements in array. */
+	bits32 blockSize,	/* B+ tree block size - # of children for each node. */
+	void (*fetchKey)(const void *va, char *keyBuf),  /* Given item, copy key to keyBuf */ 
+	bits32 keySize,					 /* Size of key */
+	void* (*fetchVal)(const void *va), 		 /* Given item, return pointer to value */
+	bits32 valSize, 				 /* Size of value */
+	char *fileName)                                  /* Name of output file. */
+/* Create a b+ tree index file from a sorted array. */
+
+{
+/* Open file and write header. */
+FILE *f = mustOpen(fileName, "wb");
+bptFileBulkIndexToOpenFile(itemArray, itemSize, itemCount, blockSize, fetchKey, keySize, 
+	fetchVal, valSize, f);
+carefulClose(&f);
+}
+
diff --git a/lib/bamFile.c b/lib/bamFile.c
new file mode 100644
index 0000000..fd52631
--- /dev/null
+++ b/lib/bamFile.c
@@ -0,0 +1,667 @@
+/* bamFile -- interface to binary alignment format files using Heng Li's samtools lib. */
+
+#include "common.h"
+#include "portable.h"
+#include "bamFile.h"
+#ifdef USE_BAM
+#include "htmshell.h"
+#include "udc.h"
+
+#ifndef KNETFILE_HOOKS
+static char *getSamDir()
+/* Return the name of a trash dir for samtools to run in (it creates files in current dir)
+ * and make sure the directory exists. */
+{
+static char *samDir = NULL;
+char *dirName = "samtools";
+if (samDir == NULL)
+    {
+    mkdirTrashDirectory(dirName);
+    size_t len = strlen(trashDir()) + 1 + strlen(dirName) + 1;
+    samDir = needMem(len);
+    safef(samDir, len, "%s/%s", trashDir(), dirName);
+    }
+return samDir;
+}
+#endif//ndef KNETFILE_HOOKS
+
+boolean bamFileExists(char *fileOrUrl)
+/* Return TRUE if we can successfully open the bam file and its index file. */
+{
+char *bamFileName = fileOrUrl;
+samfile_t *fh = samopen(bamFileName, "rb", NULL);
+boolean usingUrl = TRUE; 
+usingUrl = (strstr(fileOrUrl, "tp://") || strstr(fileOrUrl, "https://"));
+if (fh != NULL)
+    {
+#ifndef KNETFILE_HOOKS
+    // When file is an URL, this caches the index file in addition to validating:
+    // Since samtools's url-handling code saves the .bai file to the current directory,
+    // chdir to a trash directory before calling bam_index_load, then chdir back.
+    char *runDir = getCurrentDir();
+    char *samDir = getSamDir();
+    if (usingUrl)
+	setCurrentDir(samDir);
+#endif//ndef KNETFILE_HOOKS
+    bam_index_t *idx = bam_index_load(bamFileName);
+#ifndef KNETFILE_HOOKS
+    if (usingUrl)
+	setCurrentDir(runDir);
+#endif//ndef KNETFILE_HOOKS
+    samclose(fh);
+    if (idx == NULL)
+	{
+	warn("bamFileExists: failed to read index corresponding to %s", bamFileName);
+	return FALSE;
+	}
+    free(idx); // Not freeMem, freez etc -- sam just uses malloc/calloc.
+    return TRUE;
+    }
+return FALSE;
+}
+
+samfile_t *bamOpen(char *fileOrUrl, char **retBamFileName)
+/* Return an open bam file, dealing with FUSE caching if need be. 
+ * Return parameter if NON-null will return the file name after FUSing */
+{
+char *bamFileName = fileOrUrl;
+if (retBamFileName != NULL)
+    *retBamFileName = bamFileName;
+
+#ifdef BAM_VERSION
+// suppress too verbose messages in samtools >= 0.1.18; see redmine #6491
+// This variable didn't exist in older versions of samtools (where BAM_VERSION wasn't defined).
+bam_verbose = 1;
+#endif
+
+samfile_t *fh = samopen(bamFileName, "rb", NULL);
+if (fh == NULL)
+    {
+    boolean usingUrl = (strstr(fileOrUrl, "tp://") || strstr(fileOrUrl, "https://"));
+    struct dyString *urlWarning = dyStringNew(0);
+    if (usingUrl)
+	{
+	dyStringAppend(urlWarning,
+		       ". If you are able to access the URL with your web browser, "
+		       "please try reloading this page.");
+	}
+    errAbort("Failed to open %s%s", fileOrUrl, urlWarning->string);
+    }
+return fh;
+}
+
+void bamClose(samfile_t **pSamFile)
+/* Close down a samefile_t */
+{
+if (pSamFile != NULL)
+    {
+    samclose(*pSamFile);
+    *pSamFile = NULL;
+    }
+}
+
+void bamFetchAlreadyOpen(samfile_t *samfile, bam_index_t *idx, char *bamFileName, 
+			 char *position, bam_fetch_f callbackFunc, void *callbackData)
+/* With the open bam file, return items the same way with the callbacks as with bamFetch() */
+/* except in this case use an already-open bam file and index (use bam_index_load and free() for */
+/* the index). It seems a little strange to pass the filename in with the open bam, but */
+/* it's just used to report errors. */
+{
+int chromId, start, end;
+int ret = bam_parse_region(samfile->header, position, &chromId, &start, &end);
+if (ret != 0 && startsWith("chr", position))
+    ret = bam_parse_region(samfile->header, position+strlen("chr"), &chromId, &start, &end);
+if (ret != 0)
+    // If the bam file does not cover the current chromosome, OK
+    return;
+ret = bam_fetch(samfile->x.bam, idx, chromId, start, end, callbackData, callbackFunc);
+if (ret != 0)
+    warn("bam_fetch(%s, %s (chromId=%d) failed (%d)", bamFileName, position, chromId, ret);
+}
+
+void bamFetch(char *fileOrUrl, char *position, bam_fetch_f callbackFunc, void *callbackData,
+		 samfile_t **pSamFile)
+/* Open the .bam file, fetch items in the seq:start-end position range,
+ * and call callbackFunc on each bam item retrieved from the file plus callbackData.
+ * This handles BAM files with "chr"-less sequence names, e.g. from Ensembl. 
+ * The pSamFile parameter is optional.  If non-NULL it will be filled in, just for
+ * the benefit of the callback function, with the open samFile.  */
+{
+char *bamFileName = NULL;
+samfile_t *fh = bamOpen(fileOrUrl, &bamFileName);
+boolean usingUrl = TRUE;
+usingUrl = (strstr(fileOrUrl, "tp://") || strstr(fileOrUrl, "https://"));
+if (pSamFile != NULL)
+    *pSamFile = fh;
+#ifndef KNETFILE_HOOKS
+// Since samtools' url-handling code saves the .bai file to the current directory,
+// chdir to a trash directory before calling bam_index_load, then chdir back.
+char *runDir = getCurrentDir();
+char *samDir = getSamDir();
+if (usingUrl)
+    setCurrentDir(samDir);
+#endif//ndef KNETFILE_HOOKS
+bam_index_t *idx = bam_index_load(bamFileName);
+#ifndef KNETFILE_HOOKS
+if (usingUrl)
+    setCurrentDir(runDir);
+#endif//ndef KNETFILE_HOOKS
+if (idx == NULL)
+    warn("bam_index_load(%s) failed.", bamFileName);
+else
+    {
+    bamFetchAlreadyOpen(fh, idx, bamFileName, position, callbackFunc, callbackData);
+    free(idx); // Not freeMem, freez etc -- sam just uses malloc/calloc.
+    }
+bamClose(&fh);
+}
+
+boolean bamIsRc(const bam1_t *bam)
+/* Return TRUE if alignment is on - strand. */
+{
+const bam1_core_t *core = &bam->core;
+return (core->flag & BAM_FREVERSE);
+}
+
+void bamGetSoftClipping(const bam1_t *bam, int *retLow, int *retHigh, int *retClippedQLen)
+/* If retLow is non-NULL, set it to the number of "soft-clipped" (skipped) bases at
+ * the beginning of the query sequence and quality; likewise for retHigh at end.
+ * For convenience, retClippedQLen is the original query length minus soft clipping
+ * (and the length of the query sequence that will be returned). */
+{
+unsigned int *cigarPacked = bam1_cigar(bam);
+const bam1_core_t *core = &bam->core;
+char op;
+int n = bamUnpackCigarElement(cigarPacked[0], &op);
+int low = (op == 'S') ? n : 0;
+n = bamUnpackCigarElement(cigarPacked[core->n_cigar-1], &op);
+int high = (op == 'S') ? n : 0;
+if (retLow != NULL)
+    *retLow = low;
+if (retHigh != NULL)
+    *retHigh = high;
+if (retClippedQLen != NULL)
+    *retClippedQLen = (core->l_qseq - low - high);
+}
+
+
+void bamUnpackQuerySequence(const bam1_t *bam, boolean useStrand, char *qSeq)
+/* Fill in qSeq with the nucleotide sequence encoded in bam.  The BAM format 
+ * reverse-complements query sequence when the alignment is on the - strand,
+ * so if useStrand is given we rev-comp it back to restore the original query 
+ * sequence. */
+{
+const bam1_core_t *core = &bam->core;
+int qLen = core->l_qseq;
+uint8_t *packedQSeq = bam1_seq(bam);
+int i;
+for (i = 0; i < qLen; i++)
+    qSeq[i] = bam_nt16_rev_table[bam1_seqi(packedQSeq, i)];
+qSeq[i] = '\0';
+if (useStrand && bamIsRc(bam))
+    reverseComplement(qSeq, qLen);
+}
+
+char *bamGetQuerySequence(const bam1_t *bam, boolean useStrand)
+/* Allocate and return the nucleotide sequence encoded in bam.  The BAM format 
+ * reverse-complements query sequence when the alignment is on the - strand,
+ * so if useStrand is given we rev-comp it back to restore the original query 
+ * sequence. */
+{
+const bam1_core_t *core = &bam->core;
+int qLen = core->l_qseq;
+char *qSeq = needMem(qLen+1);
+bamUnpackQuerySequence(bam, useStrand, qSeq);
+return qSeq;
+}
+
+UBYTE *bamGetQueryQuals(const bam1_t *bam, boolean useStrand)
+/* Return the base quality scores encoded in bam as an array of ubytes. */
+{
+const bam1_core_t *core = &bam->core;
+int qLen = core->l_qseq;
+UBYTE *arr = needMem(qLen);
+boolean isRc = useStrand && bamIsRc(bam);
+UBYTE *qualStr = bam1_qual(bam);
+int i;
+for (i = 0;  i < core->l_qseq;  i++)
+    {
+    int offset = isRc ? (qLen - 1 - i) : i;
+    arr[i] = (qualStr[0] == 255) ? 255 : qualStr[offset];
+    }
+return arr;
+}
+
+void bamUnpackCigar(const bam1_t *bam, struct dyString *dyCigar)
+/* Unpack CIGAR string into dynamic string */
+{
+unsigned int *cigarPacked = bam1_cigar(bam);
+const bam1_core_t *core = &bam->core;
+int i;
+for (i = 0;  i < core->n_cigar;  i++)
+    {
+    char op;
+    int n = bamUnpackCigarElement(cigarPacked[i], &op);
+    dyStringPrintf(dyCigar, "%d", n);
+    dyStringAppendC(dyCigar, op);
+    }
+}
+
+char *bamGetCigar(const bam1_t *bam)
+/* Return a BAM-enhanced CIGAR string, decoded from the packed encoding in bam. */
+{
+const bam1_core_t *core = &bam->core;
+struct dyString *dyCigar = dyStringNew(min(8, core->n_cigar*4));
+bamUnpackCigar(bam, dyCigar);
+return dyStringCannibalize(&dyCigar);
+}
+
+void bamShowCigarEnglish(const bam1_t *bam)
+/* Print out cigar in English e.g. "20 (mis)Match, 1 Deletion, 3 (mis)Match" */
+{
+unsigned int *cigarPacked = bam1_cigar(bam);
+const bam1_core_t *core = &bam->core;
+int i;
+for (i = 0;  i < core->n_cigar;  i++)
+    {
+    char op;
+    int n = bamUnpackCigarElement(cigarPacked[i], &op);
+    if (i > 0)
+	printf(", ");
+    switch (op)
+	{
+	case 'M': // match or mismatch (gapless aligned block)
+	    printf("%d (mis)Match", n);
+	    break;
+	case '=': // match
+	    printf("%d Match", n);
+	    break;
+	case 'X': // mismatch
+	    printf("%d Mismatch", n);
+	    break;
+	case 'I': // inserted in query
+	    printf("%d Insertion", n);
+	    break;
+	case 'S': // skipped query bases at beginning or end ("soft clipping")
+	    printf("%d Skipped", n);
+	    break;
+	case 'D': // deleted from query
+	    printf("%d Deletion", n);
+	    break;
+	case 'N': // long deletion from query (intron as opposed to small del)
+	    printf("%d deletioN", n);
+	    break;
+	case 'H': // skipped query bases not stored in record's query sequence ("hard clipping")
+	    printf("%d Hard clipped query", n);
+	    break;
+	case 'P': // P="silent deletion from padded reference sequence"
+	    printf("%d Padded / silent deletion", n);
+	    break;
+	default:
+	    errAbort("bamShowCigarEnglish: unrecognized CIGAR op %c -- update me", op);
+	}
+    }
+}
+
+static void descFlag(unsigned flag, unsigned bitMask, char *desc, boolean makeRed,
+	      boolean *retFirst)
+/* Describe a flag bit (or multi-bit mask) if it is set in flag. */
+{
+if ((flag & bitMask) == bitMask) // *all* bits in bitMask are set in flag
+    {
+    if (!*retFirst)
+	printf(" | ");
+    printf("<span%s>(<TT>0x%02x</TT>) %s</span>",
+	   (makeRed ? " style='color: red'" : ""), bitMask, desc);
+    *retFirst = FALSE;
+    }
+}
+
+void bamShowFlagsEnglish(const bam1_t *bam)
+/* Print out flags in English, e.g. "Mate is on '-' strand; Properly paired". */
+{
+const bam1_core_t *core = &bam->core;
+unsigned flag = core->flag;
+boolean first = TRUE;
+descFlag(flag, BAM_FDUP, "Optical or PCR duplicate", TRUE, &first);
+descFlag(flag, BAM_FQCFAIL, "QC failure", TRUE, &first);
+descFlag(flag, BAM_FSECONDARY, "Not primary alignment", TRUE, &first);
+descFlag(flag, BAM_FREAD2, "Read 2 of pair", FALSE, &first);
+descFlag(flag, BAM_FREAD1, "Read 1 of pair", FALSE, &first);
+descFlag(flag, BAM_FMREVERSE, "Mate is on '-' strand", FALSE, &first);
+descFlag(flag, BAM_FREVERSE, "Read is on '-' strand", FALSE, &first);
+descFlag(flag, BAM_FMUNMAP, "Mate is unmapped", TRUE, &first);
+if (flag & BAM_FUNMAP)
+    errAbort("Read is unmapped (what is it doing here?!?)");
+descFlag(flag, (BAM_FPROPER_PAIR | BAM_FPAIRED), "Properly paired", FALSE, &first);
+if ((flag & BAM_FPAIRED) && !(flag & BAM_FPROPER_PAIR))
+    descFlag(flag, BAM_FPAIRED, "Not properly paired", TRUE, &first);
+}
+
+int bamGetTargetLength(const bam1_t *bam)
+/* Tally up the alignment's length on the reference sequence from
+ * bam's packed-int CIGAR representation. */
+{
+unsigned int *cigarPacked = bam1_cigar(bam);
+const bam1_core_t *core = &bam->core;
+int tLength=0;
+int i;
+for (i = 0;  i < core->n_cigar;  i++)
+    {
+    char op;
+    int n = bamUnpackCigarElement(cigarPacked[i], &op);
+    switch (op)
+	{
+	case 'M': // match or mismatch (gapless aligned block)
+	case '=': // match
+	case 'X': // mismatch
+	    tLength += n;
+	    break;
+	case 'I': // inserted in query
+	    break;
+	case 'D': // deleted from query
+	case 'N': // long deletion from query (intron as opposed to small del)
+	    tLength += n;
+	    break;
+	case 'S': // skipped query bases at beginning or end ("soft clipping")
+	case 'H': // skipped query bases not stored in record's query sequence ("hard clipping")
+	case 'P': // P="silent deletion from padded reference sequence" -- ignore these.
+	    break;
+	default:
+	    errAbort("bamGetTargetLength: unrecognized CIGAR op %c -- update me", op);
+	}
+    }
+return tLength;
+}
+
+bam1_t *bamClone(const bam1_t *bam)
+/* Return a newly allocated copy of bam. */
+{
+// Using typecasts to get around compiler complaints about bam being const:
+bam1_t *newBam = cloneMem((void *)bam, sizeof(*bam));
+newBam->data = cloneMem((void *)bam->data, bam->data_len*sizeof(bam->data[0]));
+return newBam;
+}
+
+void bamShowTags(const bam1_t *bam)
+/* Print out tags in HTML: bold key, no type indicator for brevity. */
+{
+// adapted from part of bam.c bam_format1:
+uint8_t *s = bam1_aux(bam);
+while (s < bam->data + bam->data_len)
+    {
+    uint8_t type, key[2];
+    key[0] = s[0]; key[1] = s[1];
+    s += 2; type = *s; ++s;
+    printf(" <B>%c%c</B>:", key[0], key[1]);
+    if (type == 'A') { printf("%c", *s); ++s; }
+    else if (type == 'C') { printf("%u", *s); ++s; }
+    else if (type == 'c') { printf("%d", *(int8_t*)s); ++s; }
+    else if (type == 'S') { printf("%u", *(uint16_t*)s); s += 2; }
+    else if (type == 's') { printf("%d", *(int16_t*)s); s += 2; }
+    else if (type == 'I') { printf("%u", *(uint32_t*)s); s += 4; }
+    else if (type == 'i') { printf("%d", *(int32_t*)s); s += 4; }
+    else if (type == 'f') { printf("%g", *(float*)s); s += 4; }
+    else if (type == 'd') { printf("%lg", *(double*)s); s += 8; }
+    else if (type == 'Z' || type == 'H')
+	{
+	htmTextOut(stdout, (char *)s);
+	s += strlen((char *)s) + 1;
+	}
+    }
+putc('\n', stdout);
+}
+
+char *bamGetTagString(const bam1_t *bam, char *tag, char *buf, size_t bufSize)
+/* If bam's tags include the given 2-character tag, place the value into 
+ * buf (zero-terminated, trunc'd if nec) and return a pointer to buf,
+ * or NULL if tag is not present. */
+{
+if (tag == NULL)
+    errAbort("NULL tag passed to bamGetTagString");
+if (! (isalpha(tag[0]) && isalnum(tag[1]) && tag[2] == '\0'))
+    errAbort("bamGetTagString: invalid tag '%s'", htmlEncode(tag));
+char *val = NULL;
+// adapted from part of bam.c bam_format1:
+uint8_t *s = bam1_aux(bam);
+while (s < bam->data + bam->data_len)
+    {
+    uint8_t type, key[2];
+    key[0] = s[0]; key[1] = s[1];
+    s += 2; type = *s; ++s;
+    if (key[0] == tag[0] && key[1] == tag[1])
+	{
+	if (type == 'A') { snprintf(buf, bufSize, "%c", *s);}
+	else if (type == 'C') { snprintf(buf, bufSize, "%u", *s); }
+	else if (type == 'c') { snprintf(buf, bufSize, "%d", *s); }
+	else if (type == 'S') { snprintf(buf, bufSize, "%u", *(uint16_t*)s); }
+	else if (type == 's') { snprintf(buf, bufSize, "%d", *(int16_t*)s); }
+	else if (type == 'I') { snprintf(buf, bufSize, "%u", *(uint32_t*)s); }
+	else if (type == 'i') { snprintf(buf, bufSize, "%d", *(int32_t*)s); }
+	else if (type == 'f') { snprintf(buf, bufSize, "%g", *(float*)s); }
+	else if (type == 'd') { snprintf(buf, bufSize, "%lg", *(double*)s); }
+	else if (type == 'Z' || type == 'H') strncpy(buf, (char *)s, bufSize);
+	else buf[0] = '\0';
+	buf[bufSize-1] = '\0'; // TODO: is this nec?? see man pages
+	val = buf;
+	break;
+	}
+    else
+	{
+	if (type == 'A' || type == 'C' || type == 'c') { ++s; }
+	else if (type == 'S' || type == 's') { s += 2; }
+	else if (type == 'I' || type == 'i' || type == 'f') { s += 4; }
+	else if (type == 'd') { s += 8; }
+	else if (type == 'Z' || type == 'H')
+	    {
+	    while (*s++);
+	    }
+	}
+    }
+return val;
+}
+
+void bamUnpackAux(const bam1_t *bam, struct dyString *dy)
+/* Unpack the tag:type:val part of bam into dy */
+{
+// adapted from part of bam.c bam_format1:
+uint8_t *s = bam1_aux(bam);
+boolean firstTime = TRUE;
+while (s < bam->data + bam->data_len)
+    {
+    if (firstTime)
+        firstTime = FALSE;
+    else
+        dyStringAppendC(dy, '\t');
+    dyStringAppendC(dy, *s++);
+    dyStringAppendC(dy, *s++);
+    dyStringAppendC(dy, ':');
+    dyStringAppendC(dy, s[0]);
+    dyStringAppendC(dy, ':');
+    uint8_t type = *s++;
+    if (type == 'A') { dyStringPrintf(dy, "%c", *s); ++s; }
+    else if (type == 'C') { dyStringPrintf(dy, "%u", *s); ++s; }
+    else if (type == 'c') { dyStringPrintf(dy, "%d", *s); ++s; }
+    else if (type == 'S') { dyStringPrintf(dy, "%u", *(uint16_t*)s); s += 2; }
+    else if (type == 's') { dyStringPrintf(dy, "%d", *(int16_t*)s); s += 2; }
+    else if (type == 'I') { dyStringPrintf(dy, "%u", *(uint32_t*)s); s += 4; }
+    else if (type == 'i') { dyStringPrintf(dy, "%d", *(int32_t*)s); s += 4; }
+    else if (type == 'f') { dyStringPrintf(dy, "%g", *(float*)s); s += 4; }
+    else if (type == 'd') { dyStringPrintf(dy, "%lg", *(double*)s); s += 8; }
+    else if (type == 'Z' || type == 'H')
+	{
+	dyStringAppend(dy, (char *)s);
+	s += strlen((char *)s) + 1;
+	}
+    }
+}
+
+struct bamChromInfo *bamChromList(samfile_t *fh)
+{
+/* Return list of chromosomes from bam header. We make no attempty to normalize chromosome names to UCSC format,
+   so list may contain things like "1" for "chr1", "I" for "chrI", "MT" for "chrM" etc. */
+int i;
+struct bamChromInfo *list = NULL;
+bam_header_t *bamHeader = fh->header;
+if(bamHeader == NULL)
+    return NULL;
+for(i = 0; i < bamHeader->n_targets; i++)
+    {
+    struct bamChromInfo *info = NULL;
+    AllocVar(info);
+    info->name = cloneString(bamHeader->target_name[i]);
+    info->size = bamHeader->target_len[i];
+    slAddHead(&list, info);
+    }
+slReverse(&list);
+return list;
+}
+
+#else
+// If we're not compiling with samtools, make stub routines so compile won't fail:
+
+boolean bamFileExists(char *bamFileName)
+/* Return TRUE if we can successfully open the bam file and its index file. */
+{
+warn(COMPILE_WITH_SAMTOOLS, "bamFileExists");
+return FALSE;
+}
+
+samfile_t *bamOpen(char *fileOrUrl, char **retBamFileName)
+/* Return an open bam file */
+{
+warn(COMPILE_WITH_SAMTOOLS, "bamOpenUdc");
+return FALSE;
+}
+
+void bamClose(samfile_t **pSamFile)
+/* Close down a samefile_t */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamClose");
+}
+
+void bamFetch(char *fileOrUrl, char *position, bam_fetch_f callbackFunc, void *callbackData,
+	      samfile_t **pSamFile)
+/* Open the .bam file, fetch items in the seq:start-end position range,
+ * and call callbackFunc on each bam item retrieved from the file plus callbackData.
+ * This handles BAM files with "chr"-less sequence names, e.g. from Ensembl.
+ * The pSamFile parameter is optional.  If non-NULL it will be filled in, just for
+ * the benefit of the callback function, with the open samFile.  */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamFetch");
+}
+
+boolean bamIsRc(const bam1_t *bam)
+/* Return TRUE if alignment is on - strand. */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamIsRc");
+return FALSE;
+}
+
+void bamGetSoftClipping(const bam1_t *bam, int *retLow, int *retHigh, int *retClippedQLen)
+/* If retLow is non-NULL, set it to the number of "soft-clipped" (skipped) bases at
+ * the beginning of the query sequence and quality; likewise for retHigh at end.
+ * For convenience, retClippedQLen is the original query length minus soft clipping
+ * (and the length of the query sequence that will be returned). */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamGetSoftClipping");
+}
+
+char *bamGetQuerySequence(const bam1_t *bam, boolean useStrand)
+/* Return the nucleotide sequence encoded in bam.  The BAM format
+ * reverse-complements query sequence when the alignment is on the - strand,
+ * so if useStrand is given we rev-comp it back to restore the original query
+ * sequence. */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamGetQuerySequence");
+return NULL;
+}
+
+UBYTE *bamGetQueryQuals(const bam1_t *bam, boolean useStrand)
+/* Return the base quality scores encoded in bam as an array of ubytes. */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamGetQueryQuals");
+return NULL;
+}
+
+char *bamGetCigar(const bam1_t *bam)
+/* Return a BAM-enhanced CIGAR string, decoded from the packed encoding in bam. */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamGetCigar");
+return NULL;
+}
+
+void bamShowCigarEnglish(const bam1_t *bam)
+/* Print out cigar in English e.g. "20 (mis)Match, 1 Deletion, 3 (mis)Match" */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamShowCigarEnglish");
+}
+
+void bamShowFlagsEnglish(const bam1_t *bam)
+/* Print out flags in English, e.g. "Mate is on '-' strand; Properly paired". */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamShowFlagsEnglish");
+}
+
+int bamGetTargetLength(const bam1_t *bam)
+/* Tally up the alignment's length on the reference sequence from
+ * bam's packed-int CIGAR representation. */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamGetTargetLength");
+return 0;
+}
+
+bam1_t *bamClone(const bam1_t *bam)
+/* Return a newly allocated copy of bam. */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamClone");
+return NULL;
+}
+
+void bamShowTags(const bam1_t *bam)
+/* Print out tags in HTML: bold key, no type indicator for brevity. */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamShowTags");
+}
+
+char *bamGetTagString(const bam1_t *bam, char *tag, char *buf, size_t bufSize)
+/* If bam's tags include the given 2-character tag, place the value into
+ * buf (zero-terminated, trunc'd if nec) and return a pointer to buf,
+ * or NULL if tag is not present. */
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamGetTagString");
+return NULL;
+}
+
+struct bamChromInfo *bamChromList(samfile_t *fh)
+{
+errAbort(COMPILE_WITH_SAMTOOLS, "bamChromList");
+return NULL;
+}
+
+#endif//ndef USE_BAM
+
+static void bamChromInfoFree(struct bamChromInfo **pInfo)
+/* Free up one chromInfo */
+{
+struct bamChromInfo *info = *pInfo;
+if (info != NULL)
+    {
+    freeMem(info->name);
+    freez(pInfo);
+    }
+}
+
+void bamChromInfoFreeList(struct bamChromInfo **pList)
+/* Free a list of dynamically allocated bamChromInfo's */
+{
+struct bamChromInfo *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    bamChromInfoFree(&el);
+    }
+*pList = NULL;
+}
+
diff --git a/lib/base64.c b/lib/base64.c
new file mode 100644
index 0000000..a813a66
--- /dev/null
+++ b/lib/base64.c
@@ -0,0 +1,129 @@
+#include "common.h"
+#include "base64.h"
+
+
+char *base64Encode(char *input, size_t inplen)
+/* Use base64 to encode a string.  Returns one long encoded
+ * string which need to be freeMem'd. Note: big-endian algorithm.
+ * For some applications you may need to break the base64 output
+ * of this function into lines no longer than 76 chars.
+ */
+{
+char b64[] = B64CHARS;
+int words = (inplen+2)/3;
+int remains = inplen % 3;
+char *result = (char *)needMem(4*words+1);
+size_t i=0, j=0;
+int word = 0;
+unsigned char *p = (unsigned char*) input;  
+/* p must be unsigned char*,  because without "unsigned",
+sign extend messes up last group outputted
+when the value of the chars following last in input
+happens to be char 0x80 or higher */
+for(i=1; i<=words; i++)
+    {
+    word = 0;
+    word |= *p++;
+    word <<= 8;
+    word |= *p++;
+    word <<= 8;
+    word |= *p++;
+    if (i==words && remains>0)
+	{
+	word &= 0x00FFFF00;
+    	if (remains==1)
+    	    word &= 0x00FF0000;
+	}
+    result[j++]=b64[word >> 18 & 0x3F];
+    result[j++]=b64[word >> 12 & 0x3F];
+    result[j++]=b64[word >> 6 & 0x3F];
+    result[j++]=b64[word & 0x3F];
+    }
+result[j] = 0;
+if (remains >0) result[j-1] = '=';    
+if (remains==1) result[j-2] = '=';    
+return result;
+}
+
+
+boolean base64Validate(char *input)
+/* Return true if input is valid base64.
+ * Note that the input string is changed by 
+ * eraseWhiteSpace(). */
+{
+size_t i = 0, l = 0;
+char *p = input;
+boolean validB64 = TRUE;
+
+/* remove whitespace which is unnecessary and  */
+eraseWhiteSpace(input);  
+
+l = strlen(p);
+for(i=0;i<l;i++)
+    {
+    char c = ' ';
+    if (!strchr(B64CHARS,c=*p++))
+        {
+        if (c != '=')
+            {
+            validB64 = FALSE;
+            break;
+            }
+        }
+    }
+if (l%4)
+    validB64 = FALSE;
+return validB64;
+}
+
+char *base64Decode(char *input, size_t *returnSize)
+/* Use base64 to decode a string.  Return decoded
+ * string which will be freeMem'd. Note: big-endian algorithm.
+ * Call eraseWhiteSpace() and check for invalid input 
+ * before passing in input if needed.  
+ * Optionally set return size for use with binary data.
+ */
+{
+static int *map=NULL;
+char b64[] = B64CHARS;
+size_t inplen = strlen(input);
+int words = (inplen+3)/4;
+char *result = (char *)needMem(3*words+1);
+size_t i=0, j=0;
+int word = 0;
+char *p = input;
+
+if (!map)
+    {
+    int i = 0;
+    map = needMem(256*sizeof(int));
+    for (i = 0; i < 256; ++i)
+	{
+	map[i]=0;
+	}
+    for (i = 0; i < 64; ++i)
+	{
+	map[(int)b64[i]]=i;
+	}
+    }
+for(i=0; i<words; i++)
+    {
+    word = 0;
+    word |= map[(int)*p++];
+    word <<= 6;
+    word |= map[(int)*p++];
+    word <<= 6;
+    word |= map[(int)*p++];
+    word <<= 6;
+    word |= map[(int)*p++];
+    result[j++]=word >> 16 & 0xFF;
+    result[j++]=word >> 8 & 0xFF;
+    result[j++]=word & 0xFF;
+    }
+result[j] = 0;
+if (returnSize)
+    *returnSize = j;
+     
+return result;
+}
+
diff --git a/lib/basicBed.c b/lib/basicBed.c
new file mode 100644
index 0000000..1295c65
--- /dev/null
+++ b/lib/basicBed.c
@@ -0,0 +1,1632 @@
+/* basicBed contains the basic code for Browser Extensible Data (bed) files and tables.
+ * The idea behind bed is that the first three fields are defined and required.
+ * A total of 15 fields are defined, and the file can contain any number of these.
+ * In addition after any number of defined fields there can be custom fields that
+ * are not defined in the bed spec.
+ *
+ * There's additional bed-related code in src/hg/inc/bed.h.  This module contains the
+ * stuff that's independent of the database and other genomic structures. */
+
+
+#include "common.h"
+#include "hash.h"
+#include "linefile.h"
+#include "dystring.h"
+#include "sqlNum.h"
+#include "sqlList.h"
+#include "rangeTree.h"
+#include "binRange.h"
+#include "asParse.h"
+#include "basicBed.h"
+
+
+void bedStaticLoad(char **row, struct bed *ret)
+/* Load a row from bed table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+{
+ret->chrom = row[0];
+ret->chromStart = sqlUnsigned(row[1]);
+ret->chromEnd = sqlUnsigned(row[2]);
+ret->name = row[3];
+}
+
+struct bed *bedLoad(char **row)
+/* Load a bed from row fetched with select * from bed
+ * from database.  Dispose of this with bedFree(). */
+{
+struct bed *ret;
+AllocVar(ret);
+ret->chrom = cloneString(row[0]);
+ret->chromStart = sqlUnsigned(row[1]);
+ret->chromEnd = sqlUnsigned(row[2]);
+ret->name = cloneString(row[3]);
+return ret;
+}
+
+struct bed *bedCommaIn(char **pS, struct bed *ret)
+/* Create a bed out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new bed */
+{
+char *s = *pS;
+
+if (ret == NULL)
+    AllocVar(ret);
+ret->chrom = sqlStringComma(&s);
+ret->chromStart = sqlUnsignedComma(&s);
+ret->chromEnd = sqlUnsignedComma(&s);
+ret->name = sqlStringComma(&s);
+*pS = s;
+return ret;
+}
+
+void bedFree(struct bed **pEl)
+/* Free a single dynamically allocated bed such as created
+ * with bedLoad(). */
+{
+struct bed *el;
+
+if ((el = *pEl) == NULL) return;
+freeMem(el->chrom);
+freeMem(el->name);
+freeMem(el->blockSizes);
+freeMem(el->chromStarts);
+freeMem(el->expIds);
+freeMem(el->expScores);
+freez(pEl);
+}
+
+void bedFreeList(struct bed **pList)
+/* Free a list of dynamically allocated bed's */
+{
+struct bed *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    bedFree(&el);
+    }
+*pList = NULL;
+}
+
+void bedOutput(struct bed *el, FILE *f, char sep, char lastSep) 
+/* Print out bed.  Separate fields with sep. Follow last field with lastSep. */
+{
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->chrom);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%u", el->chromStart);
+fputc(sep,f);
+fprintf(f, "%u", el->chromEnd);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->name);
+if (sep == ',') fputc('"',f);
+fputc(lastSep,f);
+}
+
+/* --------------- End of AutoSQL generated code. --------------- */
+
+int bedCmp(const void *va, const void *vb)
+/* Compare to sort based on chrom,chromStart. */
+{
+const struct bed *a = *((struct bed **)va);
+const struct bed *b = *((struct bed **)vb);
+int dif;
+dif = strcmp(a->chrom, b->chrom);
+if (dif == 0)
+    dif = a->chromStart - b->chromStart;
+return dif;
+}
+
+int bedCmpEnd(const void *va, const void *vb)
+/* Compare to sort based on chrom,chromEnd. */
+{
+const struct bed *a = *((struct bed **)va);
+const struct bed *b = *((struct bed **)vb);
+int dif;
+dif = strcmp(a->chrom, b->chrom);
+if (dif == 0)
+    dif = a->chromEnd - b->chromEnd;
+return dif;
+}
+
+int bedCmpScore(const void *va, const void *vb)
+/* Compare to sort based on score - lowest first. */
+{
+const struct bed *a = *((struct bed **)va);
+const struct bed *b = *((struct bed **)vb);
+return a->score - b->score;
+}
+
+int bedCmpPlusScore(const void *va, const void *vb)
+/* Compare to sort based on chrom,chromStart. */
+{
+const struct bed *a = *((struct bed **)va);
+const struct bed *b = *((struct bed **)vb);
+int dif;
+dif = strcmp(a->chrom, b->chrom);
+if (dif == 0)
+    {
+    dif = (a->chromStart - b->chromStart) * 1000 +(a->score - b->score);
+    }
+return dif;
+}
+
+int bedCmpSize(const void *va, const void *vb)
+/* Compare to sort based on size of element (end-start == size) */
+{
+const struct bed *a = *((struct bed **)va);
+const struct bed *b = *((struct bed **)vb);
+int a_size = a->chromEnd - a->chromStart;
+int b_size = b->chromEnd - b->chromStart;
+return (a_size - b_size);
+}
+
+int bedCmpChromStrandStart(const void *va, const void *vb)
+/* Compare to sort based on chrom,strand,chromStart. */
+{
+const struct bed *a = *((struct bed **)va);
+const struct bed *b = *((struct bed **)vb);
+int dif;
+dif = strcmp(a->chrom, b->chrom);
+if (dif == 0)
+    dif = strcmp(a->strand, b->strand);
+if (dif == 0)
+    dif = a->chromStart - b->chromStart;
+return dif;
+}
+
+struct bedLine *bedLineNew(char *line)
+/* Create a new bedLine based on tab-separated string s. */
+{
+struct bedLine *bl;
+char *s, c;
+
+AllocVar(bl);
+bl->chrom = cloneString(line);
+s = strchr(bl->chrom, '\t');
+if (s == NULL)
+    errAbort("Expecting tab in bed line %s", line);
+*s++ = 0;
+c = *s;
+if (isdigit(c) || (c == '-' && isdigit(s[1])))
+    {
+    bl->chromStart = atoi(s);
+    bl->line = s;
+    return bl;
+    }
+else
+    {
+    errAbort("Expecting start position in second field of %s", line);
+    return NULL;
+    }
+}
+
+void bedLineFree(struct bedLine **pBl)
+/* Free up memory associated with bedLine. */
+{
+struct bedLine *bl;
+
+if ((bl = *pBl) != NULL)
+    {
+    freeMem(bl->chrom);
+    freez(pBl);
+    }
+}
+
+void bedLineFreeList(struct bedLine **pList)
+/* Free a list of dynamically allocated bedLine's */
+{
+struct bedLine *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    bedLineFree(&el);
+    }
+*pList = NULL;
+}
+
+
+int bedLineCmp(const void *va, const void *vb)
+/* Compare to sort based on query. */
+{
+const struct bedLine *a = *((struct bedLine **)va);
+const struct bedLine *b = *((struct bedLine **)vb);
+int dif;
+dif = strcmp(a->chrom, b->chrom);
+if (dif == 0)
+    dif = a->chromStart - b->chromStart;
+return dif;
+}
+
+
+void bedSortFile(char *inFile, char *outFile)
+/* Sort a bed file (in place, overwrites old file. */
+{
+struct lineFile *lf = NULL;
+FILE *f = NULL;
+struct bedLine *blList = NULL, *bl;
+char *line;
+int lineSize;
+
+verbose(2, "Reading %s\n", inFile);
+lf = lineFileOpen(inFile, TRUE);
+while (lineFileNext(lf, &line, &lineSize))
+    {
+    if (line[0] == '#')
+        continue;
+    bl = bedLineNew(line);
+    slAddHead(&blList, bl);
+    }
+lineFileClose(&lf);
+
+verbose(2, "Sorting\n");
+slSort(&blList, bedLineCmp);
+
+verbose(2, "Writing %s\n", outFile);
+f = mustOpen(outFile, "w");
+for (bl = blList; bl != NULL; bl = bl->next)
+    {
+    fprintf(f, "%s\t%s\n", bl->chrom, bl->line);
+    if (ferror(f))
+        {
+	perror("Writing error\n");
+	errAbort("%s is truncated, sorry.", outFile);
+	}
+    }
+fclose(f);
+}
+
+struct bed *bedLoad3(char **row)
+/* Load first three fields of bed. */
+{
+struct bed *ret;
+AllocVar(ret);
+ret->chrom = cloneString(row[0]);
+ret->chromStart = sqlUnsigned(row[1]);
+ret->chromEnd = sqlUnsigned(row[2]);
+return ret;
+}
+
+struct bed *bedLoad5(char **row)
+/* Load first five fields of bed. */
+{
+struct bed *ret;
+AllocVar(ret);
+ret->chrom = cloneString(row[0]);
+ret->chromStart = sqlUnsigned(row[1]);
+ret->chromEnd = sqlUnsigned(row[2]);
+ret->name = cloneString(row[3]);
+ret->score = sqlSigned(row[4]);
+return ret;
+}
+
+struct bed *bedLoad6(char **row)
+/* Load first six fields of bed. */
+{
+struct bed *ret = bedLoad5(row);
+safef(ret->strand, sizeof(ret->strand), "%s", row[5]);
+return ret;
+}
+
+/* it turns out that it isn't just hgLoadBed and custom tracks
+ *	that may encounter the r,g,b specification.  Any program that
+ *	reads bed files may enconter them, so take care of them
+ *	at any time.  The strchr() function is very fast which will
+ *	be a failure in the vast majority of cases parsing integers,
+ *	therefore, this shouldn't be too severe a performance hit.
+ */
+static int itemRgbColumn(char *column9)
+{
+int itemRgb = 0;
+/*  Allow comma separated list of rgb values here   */
+char *comma = strchr(column9, ',');
+if (comma)
+    {
+    if (-1 == (itemRgb = bedParseRgb(column9)))
+	errAbort("ERROR: expecting r,g,b specification, "
+		    "found: '%s'", column9);
+    }
+else
+    itemRgb = sqlUnsigned(column9);
+return itemRgb;
+}
+
+struct bed *bedLoad12(char **row)
+/* Load a bed from row fetched with select * from bed
+ * from database.  Dispose of this with bedFree(). */
+{
+struct bed *ret;
+int sizeOne;
+
+AllocVar(ret);
+ret->blockCount = sqlSigned(row[9]);
+ret->chrom = cloneString(row[0]);
+ret->chromStart = sqlUnsigned(row[1]);
+ret->chromEnd = sqlUnsigned(row[2]);
+ret->name = cloneString(row[3]);
+ret->score = sqlSigned(row[4]);
+strcpy(ret->strand, row[5]);
+ret->thickStart = sqlUnsigned(row[6]);
+ret->thickEnd = sqlUnsigned(row[7]);
+ret->itemRgb = itemRgbColumn(row[8]);
+sqlSignedDynamicArray(row[10], &ret->blockSizes, &sizeOne);
+assert(sizeOne == ret->blockCount);
+sqlSignedDynamicArray(row[11], &ret->chromStarts, &sizeOne);
+assert(sizeOne == ret->blockCount);
+return ret;
+}
+
+struct bed *bedLoadN(char *row[], int wordCount)
+/* Convert a row of strings to a bed. */
+{
+struct bed * bed;
+int count;
+
+AllocVar(bed);
+bed->chrom = cloneString(row[0]);
+bed->chromStart = sqlUnsigned(row[1]);
+bed->chromEnd = sqlUnsigned(row[2]);
+if (wordCount > 3)
+     bed->name = cloneString(row[3]);
+if (wordCount > 4)
+     bed->score = sqlSigned(row[4]);
+if (wordCount > 5)
+     bed->strand[0] = row[5][0];
+if (wordCount > 6)
+     bed->thickStart = sqlUnsigned(row[6]);
+else
+     bed->thickStart = bed->chromStart;
+if (wordCount > 7)
+     bed->thickEnd = sqlUnsigned(row[7]);
+else
+     bed->thickEnd = bed->chromEnd;
+if (wordCount > 8)
+    bed->itemRgb = itemRgbColumn(row[8]);
+if (wordCount > 9)
+    bed->blockCount = sqlUnsigned(row[9]);
+if (wordCount > 10)
+    sqlSignedDynamicArray(row[10], &bed->blockSizes, &count);
+if (wordCount > 11)
+    sqlSignedDynamicArray(row[11], &bed->chromStarts, &count);
+if (wordCount > 12)
+    bed->expCount = sqlUnsigned(row[12]);
+if (wordCount > 13)
+    sqlSignedDynamicArray(row[13], &bed->expIds, &count);
+if (wordCount > 14)
+    sqlFloatDynamicArray(row[14], &bed->expScores, &count);
+return bed;
+}
+
+struct bed *bedLoadNAllChrom(char *fileName, int numFields, char* chrom) 
+/* Load bed entries from a tab-separated file that have the given chrom.
+ * Dispose of this with bedFreeList(). */
+{
+struct bed *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[numFields];
+
+while (lineFileRow(lf, row))
+    {
+    el = bedLoadN(row, numFields);
+    if(chrom == NULL || sameString(el->chrom, chrom))
+        slAddHead(&list, el);
+    else
+        bedFree(&el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct bed *bedLoadNAll(char *fileName, int numFields) 
+/* Load all bed from a tab-separated file.
+ * Dispose of this with bedFreeList(). */
+{
+return bedLoadNAllChrom(fileName, numFields, NULL);
+}
+
+struct bed *bedLoadAll(char *fileName)
+/* Determines how many fields are in a bedFile and load all beds from
+ * a tab-separated file.  Dispose of this with bedFreeList(). */
+{
+struct bed *list = NULL;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *line, *row[bedKnownFields];
+
+while (lineFileNextReal(lf, &line))
+    {
+    int numFields = chopByWhite(line, row, ArraySize(row));
+    if (numFields < 4)
+	errAbort("file %s doesn't appear to be in bed format. At least 4 fields required, got %d", fileName, numFields);
+    slAddHead(&list, bedLoadN(row, numFields));
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+void bedLoadAllReturnFieldCount(char *fileName, struct bed **retList, int *retFieldCount)
+/* Load bed of unknown size and return number of fields as well as list of bed items.
+ * Ensures that all lines in bed file have same field count. */
+{
+struct bed *list = NULL;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *line, *row[bedKnownFields];
+int fieldCount = 0;
+
+while (lineFileNextReal(lf, &line))
+    {
+    int numFields = chopByWhite(line, row, ArraySize(row));
+    if (numFields < 4)
+	errAbort("file %s doesn't appear to be in bed format. At least 4 fields required, got %d", 
+		fileName, numFields);
+    if (fieldCount == 0)
+        fieldCount = numFields;
+    else
+        if (fieldCount != numFields)
+	    errAbort("Inconsistent number of fields in file. %d on line %d of %s, %d previously.",
+	        numFields, lf->lineIx, lf->fileName, fieldCount);
+    slAddHead(&list, bedLoadN(row, fieldCount));
+    }
+lineFileClose(&lf);
+slReverse(&list);
+*retList = list;
+*retFieldCount = fieldCount;
+}
+
+static void bedOutputN_Opt(struct bed *el, int wordCount, FILE *f,
+	char sep, char lastSep, boolean useItemRgb)
+/* Write a bed of wordCount fields, optionally interpreting field nine
+	as R,G,B values. */
+{
+int i;
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->chrom);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%u", el->chromStart);
+fputc(sep,f);
+fprintf(f, "%u", el->chromEnd);
+if (wordCount <= 3)
+    {
+    fputc(lastSep, f);
+    return;
+    }
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->name);
+if (sep == ',') fputc('"',f);
+if (wordCount <= 4)
+    {
+    fputc(lastSep, f);
+    return;
+    }
+fputc(sep,f);
+fprintf(f, "%d", el->score);
+if (wordCount <= 5)
+    {
+    fputc(lastSep, f);
+    return;
+    }
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->strand);
+if (sep == ',') fputc('"',f);
+if (wordCount <= 6)
+    {
+    fputc(lastSep, f);
+    return;
+    }
+fputc(sep,f);
+fprintf(f, "%u", el->thickStart);
+if (wordCount <= 7)
+    {
+    fputc(lastSep, f);
+    return;
+    }
+fputc(sep,f);
+fprintf(f, "%u", el->thickEnd);
+if (wordCount <= 8)
+    {
+    fputc(lastSep, f);
+    return;
+    }
+fputc(sep,f);
+if (useItemRgb)
+    fprintf(f, "%d,%d,%d", (el->itemRgb & 0xff0000) >> 16,
+        (el->itemRgb & 0xff00) >> 8, (el->itemRgb & 0xff));
+else
+    fprintf(f, "%u", el->itemRgb);
+if (wordCount <= 9)
+    {
+    fputc(lastSep, f);
+    return;
+    }
+fputc(sep,f);
+fprintf(f, "%d", el->blockCount);
+if (wordCount <= 10)
+    {
+    fputc(lastSep, f);
+    return;
+    }
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->blockCount; ++i)
+    {
+    fprintf(f, "%d", el->blockSizes[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+if (wordCount <= 11)
+    {
+    fputc(lastSep, f);
+    return;
+    }
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->blockCount; ++i)
+    {
+    fprintf(f, "%d", el->chromStarts[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+
+if (wordCount <= 12)
+    {
+    fputc(lastSep, f);
+    return;
+    }
+fputc(sep,f);
+fprintf(f, "%d", el->expCount);
+
+if (wordCount <= 13)
+    {
+    fputc(lastSep, f);
+    return;
+    }
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->expCount; ++i)
+    {
+    fprintf(f, "%d", el->expIds[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+
+
+if (wordCount <= 14)
+    {
+    fputc(lastSep, f);
+    return;
+    }
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->expCount; ++i)
+    {
+    fprintf(f, "%g", el->expScores[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+
+
+fputc(lastSep,f);
+}
+
+void bedOutputN(struct bed *el, int wordCount, FILE *f, char sep, char lastSep)
+/* Write a bed of wordCount fields. */
+{
+bedOutputN_Opt(el, wordCount, f, sep, lastSep, FALSE);
+}
+
+void bedOutputNitemRgb(struct bed *el, int wordCount, FILE *f,
+	char sep, char lastSep)
+/* Write a bed of wordCount fields, interpret column 9 as RGB. */
+{
+bedOutputN_Opt(el, wordCount, f, sep, lastSep, TRUE);
+}
+
+
+int bedTotalBlockSize(struct bed *bed)
+/* Return total size of all blocks. */
+{
+int total = 0;
+int i;
+if (bed->blockCount == 0)
+    return bed->chromEnd - bed->chromStart;
+for (i=0; i<bed->blockCount; ++i)
+    total += bed->blockSizes[i];
+return total;
+}
+
+int bedBlockSizeInRange(struct bed *bed, int rangeStart, int rangeEnd)
+/* Get size of all parts of all exons between rangeStart and rangeEnd. */
+{
+int total = 0;
+int i;
+for (i=0; i<bed->blockCount; ++i)
+    {
+    int start = bed->chromStart + bed->chromStarts[i];
+    int end = start + bed->blockSizes[i];
+    total += positiveRangeIntersection(start, end, rangeStart, rangeEnd);
+    }
+return total;
+}
+
+int bedTotalThickBlockSize(struct bed *bed)
+/* Return total size of all thick blocks. */
+{
+return bedBlockSizeInRange(bed, bed->thickStart, bed->thickEnd);
+}
+
+int bedStartThinSize(struct bed *bed)
+/* Return total size of all blocks before thick part. */
+{
+return bedBlockSizeInRange(bed, bed->chromStart, bed->thickStart);
+}
+
+int bedEndThinSize(struct bed *bed)
+/* Return total size of all blocks after thick part. */
+{
+return bedBlockSizeInRange(bed, bed->thickEnd, bed->chromEnd);
+}
+
+struct bed *bedFromPsl(struct psl *psl)
+/* Convert a single psl to a bed structure */
+{
+struct bed *bed;
+int i, blockCount, *chromStarts, chromStart;
+
+/* A tiny bit of error checking on the psl. */
+if (psl->qStart >= psl->qEnd || psl->qEnd > psl->qSize 
+    || psl->tStart >= psl->tEnd || psl->tEnd > psl->tSize)
+    {
+    errAbort("mangled psl format for %s", psl->qName);
+    }
+
+/* Allocate bed and fill in from psl. */
+AllocVar(bed);
+bed->chrom = cloneString(psl->tName);
+bed->chromStart = bed->thickStart = chromStart = psl->tStart;
+bed->chromEnd = bed->thickEnd = psl->tEnd;
+bed->score = 1000 - 2*pslCalcMilliBad(psl, TRUE);
+if (bed->score < 0) bed->score = 0;
+bed->strand[0] = psl->strand[0];
+bed->blockCount = blockCount = psl->blockCount;
+bed->blockSizes = (int *)cloneMem(psl->blockSizes,(sizeof(int)*psl->blockCount));
+if (pslIsProtein(psl))
+    {
+    /* Convert blockSizes from protein to dna. */
+    for (i=0; i<blockCount; ++i)
+	bed->blockSizes[i] *= 3;
+    }
+bed->chromStarts = chromStarts = (int *)cloneMem(psl->tStarts, (sizeof(int)*psl->blockCount));
+bed->name = cloneString(psl->qName);
+
+/* Switch minus target strand to plus strand. */
+if (psl->strand[1] == '-')
+    {
+    int chromSize = psl->tSize;
+    reverseInts(bed->blockSizes, blockCount);
+    reverseInts(chromStarts, blockCount);
+    for (i=0; i<blockCount; ++i)
+	chromStarts[i] = chromSize - chromStarts[i] - bed->blockSizes[i];
+    if (bed->strand[0] == '-')
+	bed->strand[0] = '+';
+    else
+	bed->strand[0] = '-';
+    }
+
+/* Convert coordinates to relative. */
+for (i=0; i<blockCount; ++i)
+    chromStarts[i] -= chromStart;
+return bed;
+}
+
+void makeItBed12(struct bed *bedList, int numFields)
+/* If it's less than bed 12, make it bed 12. The numFields */
+/* param is for how many fields the bed *currently* has. */
+{
+int i = 1;
+struct bed *cur;
+for (cur = bedList; cur != NULL; cur = cur->next)
+    {
+    /* it better be bigger than bed 3. */
+    if (numFields < 4)
+	{
+	char name[50];
+	safef(name, ArraySize(name), "item.%d", i+1);
+	cur->name = cloneString(name);
+	}
+    if (numFields < 5)
+	cur->score = 1000;
+    if (numFields < 6)
+	{
+	cur->strand[0] = '?';
+	cur->strand[1] = '\0';
+	}
+    if (numFields < 8)
+	{
+	cur->thickStart = cur->chromStart;
+	cur->thickEnd = cur->chromEnd;
+	}
+    if (numFields < 9)
+	cur->itemRgb = 0;
+    if (numFields < 12)
+	{
+	cur->blockSizes = needMem(sizeof(int));
+	cur->chromStarts = needMem(sizeof(int));
+	cur->blockCount = 1;
+	cur->chromStarts[0] = 0;
+	cur->blockSizes[0] = cur->chromEnd - cur->chromStart;
+	}
+    i++;
+    }
+}
+
+struct bed *lmCloneBed(struct bed *bed, struct lm *lm)
+/* Make a copy of bed in local memory. */
+{
+struct bed *newBed;
+if (bed == NULL)
+    return NULL;
+lmAllocVar(lm, newBed);
+newBed->chrom = lmCloneString(lm, bed->chrom);
+newBed->chromStart = bed->chromStart;
+newBed->chromEnd = bed->chromEnd;
+newBed->name = lmCloneString(lm, bed->name);
+newBed->score = bed->score;
+strncpy(newBed->strand, bed->strand, sizeof(bed->strand));
+newBed->thickStart = bed->thickStart;
+newBed->thickEnd = bed->thickEnd;
+newBed->itemRgb = bed->itemRgb;
+newBed->blockCount = bed->blockCount;
+if (bed->blockCount > 0)
+    {
+    newBed->blockSizes = lmCloneMem(lm, bed->blockSizes, 
+    	sizeof(bed->blockSizes[0]) * bed->blockCount);
+    newBed->chromStarts = lmCloneMem(lm, bed->chromStarts, 
+    	sizeof(bed->chromStarts[0]) * bed->blockCount);
+    }
+newBed->expCount = bed->expCount;
+if (bed->expCount > 0)
+    {
+    newBed->expIds = lmCloneMem(lm, bed->expIds, 
+    	sizeof(bed->expIds[0]) * bed->expCount);
+    newBed->expScores = lmCloneMem(lm, bed->expScores, 
+    	sizeof(bed->expScores[0]) * bed->expCount);
+    }
+return(newBed);
+}
+
+
+struct bed *cloneBed(struct bed *bed)
+/* Make an all-newly-allocated copy of a single bed record. */
+{
+struct bed *newBed;
+if (bed == NULL)
+    return NULL;
+AllocVar(newBed);
+newBed->chrom = cloneString(bed->chrom);
+newBed->chromStart = bed->chromStart;
+newBed->chromEnd = bed->chromEnd;
+newBed->name = cloneString(bed->name);
+newBed->score = bed->score;
+strncpy(newBed->strand, bed->strand, sizeof(bed->strand));
+newBed->thickStart = bed->thickStart;
+newBed->thickEnd = bed->thickEnd;
+newBed->itemRgb = bed->itemRgb;
+newBed->blockCount = bed->blockCount;
+if (bed->blockCount > 0)
+    {
+    newBed->blockSizes = needMem(sizeof(int) * bed->blockCount);
+    memcpy(newBed->blockSizes, bed->blockSizes,
+	   sizeof(int) * bed->blockCount);
+    newBed->chromStarts = needMem(sizeof(int) * bed->blockCount);
+    memcpy(newBed->chromStarts, bed->chromStarts,
+	   sizeof(int) * bed->blockCount);
+    }
+newBed->expCount = bed->expCount;
+if (bed->expCount > 0)
+    {
+    newBed->expIds = needMem(sizeof(int) * bed->expCount);
+    memcpy(newBed->expIds, bed->expIds,
+	   sizeof(int) * bed->expCount);
+    newBed->expScores = needMem(sizeof(float) * bed->expCount);
+    memcpy(newBed->expScores, bed->expScores,
+	   sizeof(float) * bed->expCount);
+    }
+return(newBed);
+}
+
+
+struct bed *cloneBedList(struct bed *bedList)
+/* Make an all-newly-allocated list copied from bed. */
+{
+struct bed *bedListOut = NULL, *bed=NULL;
+
+for (bed=bedList;  bed != NULL;  bed=bed->next)
+    {
+    struct bed *newBed = cloneBed(bed);
+    slAddHead(&bedListOut, newBed);
+    }
+
+slReverse(&bedListOut);
+return bedListOut;
+}
+
+struct bed *bedListNextDifferentChrom(struct bed *bedList)
+/* Return next bed in list that is from a different chrom than the start of the list. */
+{
+char *firstChrom = bedList->chrom;
+struct bed *bed;
+for (bed = bedList->next; bed != NULL; bed = bed->next)
+    if (!sameString(firstChrom, bed->chrom))
+        break;
+return bed;
+}
+
+struct bed *bedCommaInN(char **pS, struct bed *ret, int fieldCount)
+/* Create a bed out of a comma separated string looking for fieldCount
+ * fields. This will fill in ret if non-null, otherwise will return a
+ * new bed */
+{
+char *s = *pS;
+int i;
+
+if (ret == NULL)
+    AllocVar(ret);
+ret->chrom = sqlStringComma(&s);
+ret->chromStart = sqlUnsignedComma(&s);
+ret->chromEnd = sqlUnsignedComma(&s);
+if (fieldCount > 3)
+    ret->name = sqlStringComma(&s);
+if (fieldCount > 4)
+    ret->score = sqlUnsignedComma(&s);
+if (fieldCount > 5)
+    sqlFixedStringComma(&s, ret->strand, sizeof(ret->strand));
+if (fieldCount > 6)
+    ret->thickStart = sqlUnsignedComma(&s);
+else
+    ret->thickStart = ret->chromStart;
+if (fieldCount > 7)
+    ret->thickEnd = sqlUnsignedComma(&s);
+else
+     ret->thickEnd = ret->chromEnd;
+if (fieldCount > 8)
+    ret->itemRgb = sqlUnsignedComma(&s);
+if (fieldCount > 9)
+    ret->blockCount = sqlUnsignedComma(&s);
+if (fieldCount > 10)
+    {
+    s = sqlEatChar(s, '{');
+    AllocArray(ret->blockSizes, ret->blockCount);
+    for (i=0; i<ret->blockCount; ++i)
+	{
+	ret->blockSizes[i] = sqlSignedComma(&s);
+	}
+    s = sqlEatChar(s, '}');
+    s = sqlEatChar(s, ',');
+    }
+if(fieldCount > 11)
+    {
+    s = sqlEatChar(s, '{');
+    AllocArray(ret->chromStarts, ret->blockCount);
+    for (i=0; i<ret->blockCount; ++i)
+	{
+	ret->chromStarts[i] = sqlSignedComma(&s);
+	}
+    s = sqlEatChar(s, '}');
+    s = sqlEatChar(s, ',');
+    }
+if (fieldCount > 12)
+    ret->expCount = sqlSignedComma(&s);
+if (fieldCount > 13)
+    {
+    s = sqlEatChar(s, '{');
+    AllocArray(ret->expIds, ret->expCount);
+    for (i=0; i<ret->expCount; ++i)
+	{
+	ret->expIds[i] = sqlSignedComma(&s);
+	}
+    s = sqlEatChar(s, '}');
+    s = sqlEatChar(s, ',');
+    }
+if (fieldCount > 14)
+    {
+    s = sqlEatChar(s, '{');
+    AllocArray(ret->expScores, ret->expCount);
+    for (i=0; i<ret->expCount; ++i)
+	{
+	ret->expScores[i] = sqlFloatComma(&s);
+	}
+    s = sqlEatChar(s, '}');
+    s = sqlEatChar(s, ',');
+    }
+*pS = s;
+return ret;
+}
+
+struct hash *readBedToBinKeeper(char *sizeFileName, char *bedFileName, int wordCount)
+/* Read a list of beds and return results in hash of binKeeper structure for fast query
+ * See also bedsIntoKeeperHash, which takes the beds read into a list already, but
+ * dispenses with the need for the sizeFile. */
+{
+struct binKeeper *bk; 
+struct bed *bed;
+struct lineFile *lf = lineFileOpen(sizeFileName, TRUE);
+struct lineFile *bf = lineFileOpen(bedFileName , TRUE);
+struct hash *hash = newHash(0);
+char *chromRow[2];
+char *row[3] ;
+
+assert (wordCount == 3);
+while (lineFileRow(lf, chromRow))
+    {
+    char *name = chromRow[0];
+    int size = lineFileNeedNum(lf, chromRow, 1);
+
+    if (hashLookup(hash, name) != NULL)
+        warn("Duplicate %s, ignoring all but first\n", name);
+    else
+        {
+        bk = binKeeperNew(0, size);
+        assert(size > 1);
+	hashAdd(hash, name, bk);
+        }
+    }
+while (lineFileNextRow(bf, row, ArraySize(row)))
+    {
+    bed = bedLoadN(row, wordCount);
+    bk = hashMustFindVal(hash, bed->chrom);
+    binKeeperAdd(bk, bed->chromStart, bed->chromEnd, bed);
+    }
+lineFileClose(&bf);
+lineFileClose(&lf);
+return hash;
+}
+
+int bedParseRgb(char *itemRgb)
+/*      parse a string: "r,g,b" into three unsigned char values
+        returned as 24 bit number, or -1 for failure */
+{
+char dupe[64];
+int wordCount;
+char *row[4];
+
+strncpy(dupe, itemRgb, sizeof(dupe));
+wordCount = chopString(dupe, ",", row, ArraySize(row));
+
+if ((wordCount != 3) || (!isdigit(row[0][0]) ||
+    !isdigit(row[1][0]) || !isdigit(row[2][0])))
+        return (-1);
+
+return ( ((atoi(row[0]) & 0xff) << 16) |
+        ((atoi(row[1]) & 0xff) << 8) |
+        (atoi(row[2]) & 0xff) );
+}
+
+long long bedTotalSize(struct bed *bedList)
+/* Add together sizes of all beds in list. */
+{
+long long total=0;
+struct bed *bed;
+for (bed = bedList; bed != NULL; bed = bed->next)
+    total += (bed->chromEnd - bed->chromStart);
+return total;
+}
+
+void bedIntoRangeTree(struct bed *bed, struct rbTree *rangeTree)
+/* Add all blocks in bed to range tree.  For beds without blocks,
+ * add entire bed. */
+{
+int i;
+if (bed->blockCount == 0)
+    rangeTreeAdd(rangeTree, bed->chromStart, bed->chromEnd);
+else
+    {
+    for (i=0; i < bed->blockCount; ++i)
+	{
+	int start = bed->chromStart + bed->chromStarts[i];
+	int end = start + bed->blockSizes[i];
+	rangeTreeAdd(rangeTree, start, end);
+	}
+    }
+}
+
+struct rbTree *bedToRangeTree(struct bed *bed)
+/* Convert bed into a range tree. */
+{
+struct rbTree *rangeTree = rangeTreeNew();
+bedIntoRangeTree(bed, rangeTree);
+return rangeTree;
+}
+
+int bedRangeTreeOverlap(struct bed *bed, struct rbTree *rangeTree)
+/* Return number of bases bed overlaps with rangeTree. */
+{
+int totalOverlap = 0;
+if (bed->blockCount == 0)
+    totalOverlap = rangeTreeOverlapSize(rangeTree, bed->chromStart, bed->chromEnd);
+else
+    {
+    int i;
+    for (i=0; i < bed->blockCount; ++i)
+	{
+	int start = bed->chromStart + bed->chromStarts[i];
+	int end = start + bed->blockSizes[i];
+	totalOverlap += rangeTreeOverlapSize(rangeTree, start, end);
+	}
+    }
+return totalOverlap;
+}
+
+int bedSameStrandOverlap(struct bed *a, struct bed *b)
+/* Return amount of block-level overlap on same strand between a and b */
+{
+/* Make sure on same strand, chromosome, and that overlap
+ * at the non-block level. */
+if (a->strand[0] != b->strand[0])
+    return 0;
+if (!sameString(a->chrom, b->chrom))
+    return 0;
+int outerOverlap = rangeIntersection(a->chromStart, a->chromEnd, 
+	b->chromStart, b->chromEnd);
+if (outerOverlap <= 0)
+    return 0;
+
+/* If both beds are non-blocked then we're pretty much done. */
+if (a->blockCount == 0 && b->blockCount == 0)
+    return outerOverlap;
+
+/* Otherwise make up a range tree containing regions covered by a,
+ * and figure out how much b overlaps it.. */
+struct rbTree *rangeTree = bedToRangeTree(a);
+int overlap = bedRangeTreeOverlap(b, rangeTree);
+
+/* Clean up and return result. */
+rangeTreeFree(&rangeTree);
+return overlap;
+}
+
+boolean bedExactMatch(struct bed *oldBed, struct bed *newBed)
+/* Return TRUE if it's an exact match. */
+{
+if (oldBed->blockCount != newBed->blockCount)
+    return FALSE;
+int oldSize = bedTotalBlockSize(oldBed);
+int newSize = bedTotalBlockSize(newBed);
+int overlap = bedSameStrandOverlap(oldBed, newBed);
+return  (oldSize == newSize && oldSize == overlap);
+}
+
+boolean bedCompatibleExtension(struct bed *oldBed, struct bed *newBed)
+/* Return TRUE if newBed is a compatible extension of oldBed, meaning
+ * all internal exons and all introns of old bed are contained, in the 
+ * same order in the new bed. */
+{
+/* New bed must have at least as many exons as old bed... */
+if (oldBed->blockCount > newBed->blockCount)
+    return FALSE;
+
+/* New bed must also must also encompass old bed. */
+if (newBed->chromStart > oldBed->chromStart)
+    return FALSE;
+if (newBed->chromEnd < oldBed->chromEnd)
+    return FALSE;
+
+/* Look for an exact match */
+int oldSize = bedTotalBlockSize(oldBed);
+int newSize = bedTotalBlockSize(newBed);
+int overlap = bedSameStrandOverlap(oldBed, newBed);
+if (oldSize == newSize && oldSize == overlap)
+    return TRUE;
+
+/* If overlap is smaller than old size then we can't be a superset. */
+if (overlap < oldSize)
+    return FALSE;
+
+/* If we're a single exon bed then we're done. */
+if (oldBed->blockCount <= 1)
+    return TRUE;
+
+/* Otherwise we look for first intron start in old bed, and then
+ * flip through new bed until we find an intron that starts at the
+ * same place. */
+int oldFirstIntronStart = oldBed->chromStart + oldBed->chromStarts[0] + oldBed->blockSizes[0];
+int newLastBlock = newBed->blockCount-1, oldLastBlock = oldBed->blockCount-1;
+int newIx, oldIx;
+for (newIx=0; newIx < newLastBlock; ++newIx)
+    {
+    int iStartNew = newBed->chromStart + newBed->chromStarts[newIx] + newBed->blockSizes[newIx];
+    if (iStartNew == oldFirstIntronStart)
+        break;
+    }
+if (newIx == newLastBlock)
+    return FALSE;
+
+/* Now we go through all introns in old bed, and make sure they match. */
+for (oldIx=0; oldIx < oldLastBlock; ++oldIx, ++newIx)
+    {
+    int iStartOld = oldBed->chromStart + oldBed->chromStarts[oldIx] + oldBed->blockSizes[oldIx];
+    int iEndOld = oldBed->chromStart + oldBed->chromStarts[oldIx+1];
+    int iStartNew = newBed->chromStart + newBed->chromStarts[newIx] + newBed->blockSizes[newIx];
+    int iEndNew = newBed->chromStart + newBed->chromStarts[newIx+1];
+    if (iStartOld != iStartNew || iEndOld != iEndNew)
+        return FALSE;
+    }
+
+/* Finally, make sure that the new bed doesn't contain any introns that overlap with the
+ * last exon of the old bed */
+for(; newIx < newLastBlock; ++newIx)
+    {
+    int iStartNew = newBed->chromStart + newBed->chromStarts[newIx] + newBed->blockSizes[newIx];
+    if (iStartNew < oldBed->chromEnd)
+        return FALSE;
+    else if (iStartNew >= oldBed->chromEnd)
+        break;
+    }
+
+return TRUE;
+}
+
+struct bed3 *bed3New(char *chrom, int start, int end)
+/* Make new bed3. */
+{
+struct bed3 *bed;
+AllocVar(bed);
+bed->chrom = cloneString(chrom);
+bed->chromStart = start;
+bed->chromEnd = end;
+return bed;
+}
+
+struct bed *bedThickOnly(struct bed *in)
+/* Return a bed that only has the thick part. (Which is usually the CDS). */
+{
+if (in->thickStart >= in->thickEnd)
+     return NULL;
+if (in->expCount != 0 || in->expIds != NULL || in->expScores != NULL)
+   errAbort("Sorry, bedThickOnly only works on beds with up to 12 fields.");
+
+/* Allocate output, and fill in simple fields. */
+struct bed *out;
+AllocVar(out);
+out->chrom = cloneString(in->chrom);
+out->chromStart = out->thickStart = in->thickStart;
+out->chromEnd = out->thickEnd = in->thickEnd;
+out->name = cloneString(in->name);
+out->strand[0] = in->strand[0];
+out->score = in->score;
+out->itemRgb = in->itemRgb;
+
+/* If need be fill in blocks. */
+if (in->blockCount > 0)
+   {
+   /* Count up blocks inside CDS. */
+   int i;
+   int outBlockCount = 0;
+   for (i=0; i<in->blockCount; ++i)
+       {
+       int start = in->chromStart + in->chromStarts[i];
+       int end = start + in->blockSizes[i];
+       if (start < in->thickStart) start = in->thickStart;
+       if (end > in->thickEnd) end = in->thickEnd;
+       if (start < end)
+           outBlockCount += 1;
+	}
+
+    /* This trivieal case shouldn't happen, but just in case, we deal with it. */
+    if (outBlockCount == 0)
+        {
+	freeMem(out);
+	return NULL;
+	}
+
+    /* Allocate block arrays for output. */
+    out->blockCount = outBlockCount;
+    AllocArray(out->chromStarts, outBlockCount);
+    AllocArray(out->blockSizes, outBlockCount);
+
+    /* Scan through input one more time, copying to out. */
+    int outBlockIx = 0;
+    for (i=0; i<in->blockCount; ++i)
+	{
+	int start = in->chromStart + in->chromStarts[i];
+	int end = start + in->blockSizes[i];
+	if (start < in->thickStart) start = in->thickStart;
+	if (end > in->thickEnd) end = in->thickEnd;
+	if (start < end)
+	    {
+	    out->chromStarts[outBlockIx] = start - out->chromStart;
+	    out->blockSizes[outBlockIx] = end - start;
+	    outBlockIx += 1;
+	    }
+	}
+    }
+return out;
+}
+
+struct bed *bedThickOnlyList(struct bed *inList)
+/* Return a list of beds that only are the thick part of input. */
+{
+struct bed *outList = NULL, *out, *in;
+for (in = inList; in != NULL; in = in->next)
+    {
+    if ((out = bedThickOnly(in)) != NULL)
+        slAddHead(&outList, out);
+    }
+slReverse(&outList);
+return outList;
+}
+
+char *bedAsDef(int bedFieldCount, int totalFieldCount)
+/* Return an autoSql definition for a bed of given number of fields. 
+ * Normally totalFieldCount is equal to bedFieldCount.  If there are extra
+ * fields they are just given the names field16, field17, etc and type string. */
+{
+if (bedFieldCount < 3 || bedFieldCount > 15)
+    errAbort("bedFieldCount is %d, but must be between %d and %d in bedAsDef", bedFieldCount, 3, 15);
+struct dyString *dy = dyStringNew(0);
+dyStringAppend(dy, 
+    "table bed\n"
+    "\"Browser Extensible Data\"\n"
+    "   (\n"
+    "   string chrom;       \"Reference sequence chromosome or scaffold\"\n"
+    "   uint   chromStart;  \"Start position in chromosome\"\n"
+    "   uint   chromEnd;    \"End position in chromosome\"\n"
+    );
+if (bedFieldCount >= 4)
+    dyStringAppend(dy, "   string name;        \"Name of item.\"\n");
+if (bedFieldCount >= 5)
+    dyStringAppend(dy, "   uint score;          \"Score (0-1000)\"\n");
+if (bedFieldCount >= 6)
+    dyStringAppend(dy, "   char[1] strand;     \"+ or - for strand\"\n");
+if (bedFieldCount >= 7)
+    dyStringAppend(dy, "   uint thickStart;   \"Start of where display should be thick (start codon)\"\n");
+if (bedFieldCount >= 8)
+    dyStringAppend(dy, "   uint thickEnd;     \"End of where display should be thick (stop codon)\"\n");
+if (bedFieldCount >= 9)
+    dyStringAppend(dy, "   uint reserved;     \"Used as itemRgb as of 2004-11-22\"\n");
+if (bedFieldCount >= 10)
+    dyStringAppend(dy, "   int blockCount;    \"Number of blocks\"\n");
+if (bedFieldCount >= 11)
+    dyStringAppend(dy, "   int[blockCount] blockSizes; \"Comma separated list of block sizes\"\n");
+if (bedFieldCount >= 12)
+    dyStringAppend(dy, "   int[blockCount] chromStarts; \"Start positions relative to chromStart\"\n");
+if (bedFieldCount >= 13)
+    dyStringAppend(dy, "   int expCount;	\"Experiment count\"\n");
+if (bedFieldCount >= 14)
+    dyStringAppend(dy, "   int[expCount] expIds;	\"Comma separated list of experiment ids. Always 0,1,2,3....\"\n");
+if (bedFieldCount >= 15)
+    dyStringAppend(dy, "   float[expCount] expScores; \"Comma separated list of experiment scores.\"\n");
+int i;
+for (i=bedFieldCount+1; i<=totalFieldCount; ++i)
+    dyStringPrintf(dy, "string field%d;	\"Undocumented field\"\n", i+1);
+dyStringAppend(dy, "   )\n");
+return dyStringCannibalize(&dy);
+}
+
+
+boolean asCompareObjAgainstStandardBed(struct asObject *asYours, int numColumnsToCheck, boolean abortOnDifference)
+/* Compare user's .as object asYours to the standard BED.
+ * abortOnDifference specifies whether to warn or abort if they differ within the first numColumnsToCheck columns.
+ * Returns TRUE if they match. */
+{
+boolean result = FALSE;
+struct asObject *asStandard = NULL;
+if (numColumnsToCheck > 15)
+    errAbort("There are only 15 standard BED columns defined and you have asked for %d.", numColumnsToCheck);
+if (numColumnsToCheck < 3)
+    errAbort("All BED files have at least the first 3 columns the same.");
+char *asStandardText = bedAsDef(15,15);
+asStandard = asParseText(asStandardText);
+result = asCompareObjs("Yours", asYours, "BED Standard", asStandard, numColumnsToCheck, NULL, abortOnDifference);
+freeMem(asStandardText);
+asObjectFreeList(&asStandard);
+return result;
+}
+
+
+void loadAndValidateBed(char *row[], int wordCount, int fieldCount, struct lineFile *lf, struct bed * bed, struct asObject *as, boolean isCt)
+/* Convert a row of strings to a bed and validate the contents.  Abort with message if invalid data. Optionally validate bedPlus via asObject.
+ * If a customTrack, then some errors are tolerated. */
+{
+int count;
+int *blockSizes = NULL;
+int tempBlockSizes[1024];
+int *chromStarts;
+int tempChromStarts[1024];
+int *expIds;
+int tempExpIds[1024];
+float *expScores;
+float tempExpScores[1024];
+
+bed->chrom = row[0];  // note this value is not cloned for speed, callers may need to clone it.
+
+// This check is usually redundant since the caller should be checking it against actual chromInfo names
+// however hgLoadBed might not always have that info available.
+if (strlen(bed->chrom) >= BB_MAX_CHROM_STRING)  // must leave room for 0 terminator
+    lineFileAbort(lf, "chrom [%s] is too long (must not exceed %d characters)", bed->chrom, BB_MAX_CHROM_STRING - 1);
+if (strlen(bed->chrom) < 1)
+    lineFileAbort(lf, "chrom cannot be blank or empty");
+
+lineFileAllInts(lf, row, 1, &bed->chromStart, FALSE, 4, "integer", FALSE);
+
+lineFileAllInts(lf, row, 2, &bed->chromEnd, FALSE, 4, "integer", FALSE);
+
+if (bed->chromEnd < bed->chromStart)
+    lineFileAbort(lf, "chromStart after chromEnd (%u > %u)",
+    	bed->chromStart, bed->chromEnd);
+if (wordCount > 3)
+    {
+    bed->name = row[3];
+    if (strlen(bed->name) > 255)
+	lineFileAbort(lf, "name [%s] is too long (must not exceed 255 characters)", bed->name);
+    if (isCt)
+	bed->name = cloneString(bed->name);
+    }
+if (wordCount > 4)
+    {
+    lineFileAllInts(lf, row, 4, &bed->score, TRUE, 4, "integer", FALSE);
+    if (!isCt && (bed->score < 0 || bed->score > 1000))
+	    lineFileAbort(lf, "score (%d) must be between 0 and 1000", bed->score);
+    }
+
+if (wordCount > 5)
+    {
+    if (!isCt && strlen(row[5]) > 1)
+      lineFileAbort(lf, "Expecting + or - or . in strand, found [%s]",row[5]);
+    bed->strand[0] = row[5][0];
+    bed->strand[1] = 0;
+    if (bed->strand[0] != '+' && bed->strand[0] != '-' && bed->strand[0] != '.')
+      lineFileAbort(lf, "Expecting + or - or . in strand, found [%s]",row[5]);
+    }
+if (wordCount > 6)
+    lineFileAllInts(lf, row, 6, &bed->thickStart, FALSE, 4, "integer", FALSE);
+else
+    bed->thickStart = bed->chromStart;
+if (wordCount > 7)
+    {
+    lineFileAllInts(lf, row, 7, &bed->thickEnd, FALSE, 4, "integer", FALSE);
+    if (bed->thickEnd < bed->thickStart)
+     lineFileAbort(lf, "thickStart after thickEnd");
+    if ((bed->thickStart != 0) &&
+     ((bed->thickStart < bed->chromStart) ||
+      (bed->thickStart > bed->chromEnd)))
+     lineFileAbort(lf,
+	 "thickStart out of range (chromStart to chromEnd, or 0 if no CDS)");
+    if ((bed->thickEnd != 0) &&
+     ((bed->thickEnd < bed->chromStart) ||
+      (bed->thickEnd > bed->chromEnd)))
+     lineFileAbort(lf,
+	 "thickEnd out of range for %s:%u-%u, thick:%u-%u (chromStart to chromEnd, or 0 if no CDS)",
+		   bed->name, bed->chromStart, bed->chromEnd,
+		   bed->thickStart, bed->thickEnd);
+    }
+else
+     bed->thickEnd = bed->chromEnd;
+
+if (wordCount > 8)
+    {
+    if (strchr(row[8],','))
+	{
+	unsigned char colors[4];
+	char *saveColorString = cloneString(row[8]);
+	int numColors = lineFileAllIntsArray(lf, row, 8, colors, sizeof colors, FALSE, 1, "integer", FALSE);
+	if (numColors == 3)
+	    {
+	    bed->itemRgb = (((unsigned)colors[0]) << 2*8) | (((unsigned)colors[1]) << 1*8) | (unsigned)colors[2];
+	    }
+	else
+	    lineFileAbort(lf, "Expecting color to consist of r,g,b values from 0 to 255. Got [%s]", saveColorString);
+	freeMem(saveColorString);
+	}
+    else 
+	{
+	lineFileAllInts(lf, row, 8, &bed->itemRgb, FALSE, 4, "integer", FALSE);
+	}
+    }
+
+if (wordCount > 9)
+    {
+    lineFileAllInts(lf, row, 9, &bed->blockCount, FALSE, 4, "integer", FALSE);
+    if (!(bed->blockCount >= 1))
+	lineFileAbort(lf, "Expecting blockCount (%d) to be 1 or more.", bed->blockCount);
+    
+    }
+if (wordCount > 10)
+    {
+    if (isCt)
+	{
+	AllocArray(bed->blockSizes,bed->blockCount+1); // having +1 allows us to detect incorrect size
+        count = lineFileAllIntsArray(lf, row, 10, bed->blockSizes, bed->blockCount+1, TRUE, 4, "integer", TRUE);
+	blockSizes = bed->blockSizes;
+	}
+    else
+	{
+        count = lineFileAllIntsArray(lf, row, 10, tempBlockSizes, sizeof tempBlockSizes, TRUE, 4, "integer", TRUE);
+	blockSizes = tempBlockSizes;
+	}
+    if (count != bed->blockCount)
+	lineFileAbort(lf, "Expecting %d elements in blockSizes list, found at least %d", bed->blockCount, count);
+    int i;
+    for (i=0; i < bed->blockCount;  i++)
+	{
+        if (!(blockSizes[i] > 0))
+		lineFileAbort(lf, "BED blockSizes must be greater than 0, blockSize[%d] = %d", i, blockSizes[i]);
+	}
+    }
+if (wordCount > 11)
+    {
+    int i;
+    if (isCt)
+	{
+	AllocArray(bed->chromStarts,bed->blockCount+1); // having +1 allows us to detect incorrect size
+        count = lineFileAllIntsArray(lf, row, 11, bed->chromStarts, bed->blockCount+1, TRUE, 4, "integer", TRUE);
+	chromStarts = bed->chromStarts;
+	}
+    else
+	{
+        count = lineFileAllIntsArray(lf, row, 11, tempChromStarts, sizeof tempChromStarts, TRUE, 4, "integer", TRUE);
+	chromStarts = tempChromStarts;
+	}
+    if (count != bed->blockCount)
+	lineFileAbort(lf, "Expecting %d elements in chromStarts list, found at least %d", bed->blockCount, count);
+    // tell the user if they appear to be using absolute starts rather than
+    // relative... easy to forget!  Also check block order, coord ranges...
+    if (chromStarts[0] != 0)
+	lineFileAbort(lf,
+	    "BED blocks must span chromStart to chromEnd.  "
+	    "BED chromStarts[0] = %d, must be 0 so that (chromStart + "
+	    "chromStarts[0]) equals chromStart.", chromStarts[0]);
+
+    for (i=1; i < bed->blockCount;  i++)
+	{
+
+/*
+printf("%d:%d %s %s s:%d c:%u cs:%u ce:%u csI:%d bsI:%d ls:%d le:%d<BR>\n", lineIx, i, bed->chrom, bed->name, bed->score, bed->blockCount, bed->chromStart, bed->chromEnd, bed->chromStarts[i], bed->blockSizes[i], lastStart, lastEnd);
+*/
+	// extra check to give user help for a common problem
+	if (chromStarts[i]+bed->chromStart >= bed->chromEnd)
+	    {
+	    if (chromStarts[i] >= bed->chromStart)
+		lineFileAbort(lf, "BED chromStarts offsets must be relative to chromStart, "
+				  "not absolute.  Try subtracting chromStart from each offset "
+				  "in chromStarts.");
+	    else
+		lineFileAbort(lf, "BED chromStarts[i]+chromStart must be less than chromEnd.");
+	    }
+	// chrom blocks must ascend without overlap
+        if (!(chromStarts[i] >= chromStarts[i-1] + blockSizes[i-1]))
+		lineFileAbort(lf, "BED blocks must be in ascending order without overlap. Blocks %d and %d overlap.", i-1, i);
+	}
+
+    // last block-end must match chromEnd
+    i = bed->blockCount-1;
+    if ((bed->chromStart + chromStarts[i] + blockSizes[i]) != bed->chromEnd)
+	{
+	lineFileAbort(lf, "BED blocks must span chromStart to chromEnd.  (chromStart + "
+			  "chromStarts[last] + blockSizes[last]) must equal chromEnd.");
+	}
+    }
+
+if (wordCount > 12)
+    // get the microarray/colored-exon fields
+    {
+    lineFileAllInts(lf, row, 12, &bed->expCount, TRUE, 4, "integer", TRUE);
+    if (!(bed->expCount >= 1))
+	lineFileAbort(lf, "Expecting expCount (%d) to be 1 or more.", bed->expCount);
+    if (isCt)
+	{
+	AllocArray(bed->expIds,bed->expCount+1); // having +1 allows us to detect incorrect size
+        count = lineFileAllIntsArray(lf, row, 13, bed->expIds, bed->expCount+1, TRUE, 4, "integer", TRUE);
+	expIds = bed->expIds;
+	}
+    else
+	{
+        count = lineFileAllIntsArray(lf, row, 13, tempExpIds, sizeof tempExpIds, TRUE, 4, "integer", TRUE);
+	expIds = tempExpIds;
+	}
+    if (count != bed->expCount)
+	lineFileAbort(lf, "expecting %d elements in expIds list (bed field 14)", bed->expCount);
+    if (wordCount == 15)
+	{
+	if (isCt)
+	    {
+	    sqlFloatDynamicArray(row[14], &bed->expScores, &count);
+	    expScores = bed->expScores;
+	    }
+	else
+	    {
+	    count = sqlFloatArray(row[14], tempExpScores, sizeof tempExpScores);
+	    expScores = tempExpScores;
+	    }
+	if (count != bed->expCount)
+	    lineFileAbort(lf, "expecting %d elements in expScores list (bed field 15)", bed->expCount);
+	}
+    }
+
+/* Check bedPlus fields are formatted right. */
+/* This could form the basis of an .as-validator independent of BED. I suppose it could go in asParse.c */
+if (as)
+    {
+    struct hash* linkHash = NULL;
+    /* Validate as-fields */
+    struct asColumn *asCol = NULL;
+    asCol = as->columnList;
+    int i;
+    // Pre-scan ALL fields for linked fields
+    for (i=0; i<fieldCount; ++i)
+	{
+	enum asTypes type = asCol->lowType->type;
+	if (! (asCol->isList || asCol->isArray))
+	    {
+	    if (asTypesIsInt(type))
+		{
+		if (asCol->isSizeLink) // save the field value and index for later use in validating a list size.
+		    {
+		    int listSize = 0;  // big enough to hold the list count
+		    lineFileAllInts(lf, row, i, &listSize, TRUE, 4, "integer", TRUE);
+		    if (!linkHash)
+			linkHash = newHash(4);
+		    hashAddInt(linkHash, asCol->name, listSize);
+		    }
+		}
+	    }
+	asCol = asCol->next;
+	}    
+    /* Validate bed-plus fields */
+    asCol = slElementFromIx(as->columnList, wordCount);
+    for (i=wordCount; i<fieldCount; ++i)
+	{
+	enum asTypes type = asCol->lowType->type;
+	if (! (asCol->isList || asCol->isArray))
+	    {
+	    if (asTypesIsInt(type))
+		lineFileAllInts(lf, row, i, NULL, !asTypesIsUnsigned(type), asTypesIntSize(type), asTypesIntSizeDescription(type), FALSE);
+	    else if (asTypesIsFloating(type))
+		lineFileNeedDouble(lf, row, i);
+	    else if (type == t_string)
+		{
+		if (strlen(row[i]) > 255)
+		    lineFileAbort(lf, "expecting length (%llu) of string (%s) not to exceed 255 in field %s", (unsigned long long)strlen(row[i]), row[i], asCol->name);
+		}
+	    }
+	else if (asCol->isList)
+	    {
+	    if (asTypesIsInt(type))
+		{
+		count = lineFileAllIntsArray(lf, row, i, NULL, 1024,
+		    !asTypesIsUnsigned(type), asTypesIntSize(type), asTypesIntSizeDescription(type), FALSE);
+		if (asCol->fixedSize > 0)
+		    {
+		    if (asCol->fixedSize != count)
+			lineFileAbort(lf, "expecting %d elements in %s list, found %d", asCol->fixedSize, asCol->name, count);
+		    }
+		else
+		    {
+		    if (!linkHash)
+			lineFileAbort(lf, "linked field %s was not found; it is required for determining listSize of %s"
+			    , asCol->linkedSizeName, asCol->name);
+		    int listSize = hashIntValDefault(linkHash, asCol->linkedSizeName, -1);
+		    if (listSize == -1)
+			lineFileAbort(lf, "linked field %s was not found; it is required for determining listSize of %s"
+			    , asCol->linkedSizeName, asCol->name);
+		    if (!(listSize >= 1))
+			lineFileAbort(lf, "invalid list size %d for list %s must be 1 or greater, empty lists are not allowed", listSize, asCol->name);
+		    if (!(listSize == count))
+			lineFileAbort(lf, "expecting %d elements in %s list, found %d", listSize, asCol->name, count);
+		    }
+		}
+	    }
+	asCol = asCol->next;
+	}
+    hashFree(&linkHash);
+    }
+
+}
+
diff --git a/lib/bbiRead.c b/lib/bbiRead.c
new file mode 100644
index 0000000..85079df
--- /dev/null
+++ b/lib/bbiRead.c
@@ -0,0 +1,738 @@
+/* bbiRead - Big Binary Indexed file.  Stuff that's common between bigWig and bigBed on the 
+ * read side. */
+
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "obscure.h"
+#include "localmem.h"
+#include "zlibFace.h"
+#include "bPlusTree.h"
+#include "hmmstats.h"
+#include "cirTree.h"
+#include "udc.h"
+#include "bbiFile.h"
+
+struct bbiZoomLevel *bbiBestZoom(struct bbiZoomLevel *levelList, int desiredReduction)
+/* Return zoom level that is the closest one that is less than or equal to 
+ * desiredReduction. */
+{
+if (desiredReduction < 0)
+   errAbort("bad value %d for desiredReduction in bbiBestZoom", desiredReduction);
+if (desiredReduction <= 1)
+    return NULL;
+int closestDiff = BIGNUM;
+struct bbiZoomLevel *closestLevel = NULL;
+struct bbiZoomLevel *level;
+
+for (level = levelList; level != NULL; level = level->next)
+    {
+    int diff = desiredReduction - level->reductionLevel;
+    if (diff >= 0 && diff < closestDiff)
+        {
+	closestDiff = diff;
+	closestLevel = level;
+	}
+    }
+return closestLevel;
+}
+
+boolean bbiFileCheckSigs(char *fileName, bits32 sig, char *typeName)
+/* check file signatures at beginning and end of file */
+{
+int fd = mustOpenFd(fileName, O_RDONLY);
+bits32 magic;
+boolean isSwapped = FALSE;
+
+// look for signature at the beginning of the file
+mustReadFd(fd, &magic, sizeof(magic));
+
+if (magic != sig)
+    {
+    magic = byteSwap32(magic);
+    isSwapped = TRUE;
+    if (magic != sig)
+        return FALSE;
+    }
+
+// look for signature at the end of the file
+mustLseek(fd, -sizeof(magic), SEEK_END);
+mustReadFd(fd, &magic, sizeof(magic));
+mustCloseFd(&fd);
+
+if (isSwapped)
+    {
+    magic = byteSwap32(magic);
+    if (magic != sig)
+        return FALSE;
+    }
+else
+    {
+    if (magic != sig)
+        return FALSE;
+    }
+
+return TRUE;
+}
+
+struct bbiFile *bbiFileOpen(char *fileName, bits32 sig, char *typeName)
+/* Open up big wig or big bed file. */
+{
+/* This code needs to agree with code in two other places currently - bigBedFileCreate,
+ * and bigWigFileCreate.  I'm thinking of refactoring to share at least between
+ * bigBedFileCreate and bigWigFileCreate.  It'd be great so it could be structured
+ * so that it could send the input in one chromosome at a time, and send in the zoom
+ * stuff only after all the chromosomes are done.  This'd potentially reduce the memory
+ * footprint by a factor of 2 or 4.  Still, for now it works. -JK */
+struct bbiFile *bbi;
+AllocVar(bbi);
+bbi->fileName = cloneString(fileName);
+struct udcFile *udc = bbi->udc = udcFileOpen(fileName, udcDefaultDir());
+
+/* Read magic number at head of file and use it to see if we are proper file type, and
+ * see if we are byte-swapped. */
+bits32 magic;
+boolean isSwapped = FALSE;
+udcMustRead(udc, &magic, sizeof(magic));
+if (magic != sig)
+    {
+    magic = byteSwap32(magic);
+    isSwapped = TRUE;
+    if (magic != sig)
+       errAbort("%s is not a %s file", fileName, typeName);
+    }
+bbi->typeSig = sig;
+bbi->isSwapped = isSwapped;
+
+/* Read rest of defined bits of header, byte swapping as needed. */
+bbi->version = udcReadBits16(udc, isSwapped);
+bbi->zoomLevels = udcReadBits16(udc, isSwapped);
+bbi->chromTreeOffset = udcReadBits64(udc, isSwapped);
+bbi->unzoomedDataOffset = udcReadBits64(udc, isSwapped);
+bbi->unzoomedIndexOffset = udcReadBits64(udc, isSwapped);
+bbi->fieldCount = udcReadBits16(udc, isSwapped);
+bbi->definedFieldCount = udcReadBits16(udc, isSwapped);
+bbi->asOffset = udcReadBits64(udc, isSwapped);
+bbi->totalSummaryOffset = udcReadBits64(udc, isSwapped);
+bbi->uncompressBufSize = udcReadBits32(udc, isSwapped);
+
+/* Skip over reserved area. */
+udcSeek(udc, 64);
+
+/* Read zoom headers. */
+int i;
+struct bbiZoomLevel *level, *levelList = NULL;
+for (i=0; i<bbi->zoomLevels; ++i)
+    {
+    AllocVar(level);
+    level->reductionLevel = udcReadBits32(udc, isSwapped);
+    level->reserved = udcReadBits32(udc, isSwapped);
+    level->dataOffset = udcReadBits64(udc, isSwapped);
+    level->indexOffset = udcReadBits64(udc, isSwapped);
+    slAddHead(&levelList, level);
+    }
+slReverse(&levelList);
+bbi->levelList = levelList;
+
+/* Attach B+ tree of chromosome names and ids. */
+udcSeek(udc, bbi->chromTreeOffset);
+bbi->chromBpt =  bptFileAttach(fileName, udc);
+
+return bbi;
+}
+
+void bbiFileClose(struct bbiFile **pBwf)
+/* Close down a big wig/big bed file. */
+{
+struct bbiFile *bwf = *pBwf;
+if (bwf != NULL)
+    {
+    cirTreeFileDetach(&bwf->unzoomedCir);
+    slFreeList(&bwf->levelList);
+    slFreeList(&bwf->levelList);
+    bptFileDetach(&bwf->chromBpt);
+    udcFileClose(&bwf->udc);
+    freeMem(bwf->fileName);
+    freez(pBwf);
+    }
+}
+
+
+struct fileOffsetSize *bbiOverlappingBlocks(struct bbiFile *bbi, struct cirTreeFile *ctf,
+	char *chrom, bits32 start, bits32 end, bits32 *retChromId)
+/* Fetch list of file blocks that contain items overlapping chromosome range. */
+{
+struct bbiChromIdSize idSize;
+if (!bptFileFind(bbi->chromBpt, chrom, strlen(chrom), &idSize, sizeof(idSize)))
+    return NULL;
+if (bbi->isSwapped)
+    idSize.chromId = byteSwap32(idSize.chromId);
+if (retChromId != NULL)
+    *retChromId = idSize.chromId;
+return cirTreeFindOverlappingBlocks(ctf, idSize.chromId, start, end);
+}
+
+struct chromNameCallbackContext
+/* Some stuff that the bPlusTree traverser needs for context. */
+    {
+    struct bbiChromInfo *list;		/* The list we are building. */
+    boolean isSwapped;			/* Need to byte-swap things? */
+    };
+
+static void chromNameCallback(void *context, void *key, int keySize, void *val, int valSize)
+/* Callback that captures chromInfo from bPlusTree. */
+{
+struct chromNameCallbackContext *c = context;
+struct bbiChromInfo *info;
+struct bbiChromIdSize *idSize = val;
+assert(valSize == sizeof(*idSize));
+AllocVar(info);
+info->name = cloneStringZ(key, keySize);
+info->id = idSize->chromId;
+info->size = idSize->chromSize;
+if (c->isSwapped)
+    {
+    info->id = byteSwap32(info->id);
+    info->size = byteSwap32(info->size);
+    }
+slAddHead(&c->list, info);
+}
+
+struct bbiChromInfo *bbiChromList(struct bbiFile *bbi)
+/* Return list of chromosomes. */
+{
+struct chromNameCallbackContext context;
+context.list = NULL;
+context.isSwapped = bbi->isSwapped;
+bptFileTraverse(bbi->chromBpt, &context, chromNameCallback);
+slReverse(&context.list);
+return context.list;
+}
+
+bits32 bbiChromSize(struct bbiFile *bbi, char *chrom)
+/* Return chromosome size, or 0 if no such chromosome in file. */
+{
+struct bbiChromIdSize idSize;
+if (!bptFileFind(bbi->chromBpt, chrom, strlen(chrom), &idSize, sizeof(idSize)))
+    return 0;
+return idSize.chromSize;
+}
+
+void bbiChromInfoFree(struct bbiChromInfo **pInfo)
+/* Free up one chromInfo */
+{
+struct bbiChromInfo *info = *pInfo;
+if (info != NULL)
+    {
+    freeMem(info->name);
+    freez(pInfo);
+    }
+}
+
+void bbiChromInfoFreeList(struct bbiChromInfo **pList)
+/* Free a list of dynamically allocated bbiChromInfo's */
+{
+struct bbiChromInfo *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    bbiChromInfoFree(&el);
+    }
+*pList = NULL;
+}
+
+void bbiAttachUnzoomedCir(struct bbiFile *bbi)
+/* Make sure unzoomed cir is attached. */
+{
+if (bbi->unzoomedCir == NULL)
+    {
+    udcSeek(bbi->udc, bbi->unzoomedIndexOffset);
+    bbi->unzoomedCir = cirTreeFileAttach(bbi->fileName, bbi->udc);
+    }
+}
+
+enum bbiSummaryType bbiSummaryTypeFromString(char *string)
+/* Return summary type given a descriptive string. */
+{
+if (sameWord(string, "mean") || sameWord(string, "average"))
+    return bbiSumMean;
+else if (sameWord(string, "max") || sameWord(string, "maximum"))
+    return bbiSumMax;
+else if (sameWord(string, "min") || sameWord(string, "minimum"))
+    return bbiSumMin;
+else if (sameWord(string, "coverage") || sameWord(string, "dataCoverage"))
+    return bbiSumCoverage;
+else if (sameWord(string, "std"))
+    return bbiSumStandardDeviation;
+else
+    {
+    errAbort("Unknown bbiSummaryType %s", string);
+    return bbiSumMean;	/* Keep compiler quiet. */
+    }
+}
+
+char *bbiSummaryTypeToString(enum bbiSummaryType type)
+/* Convert summary type from enum to string representation. */
+{
+switch (type)
+    {
+    case bbiSumMean:
+        return "mean";
+    case bbiSumMax:
+        return "max";
+    case bbiSumMin:
+        return "min";
+    case bbiSumCoverage:
+        return "coverage";
+    case bbiSumStandardDeviation:
+        return "std";
+    default:
+	errAbort("Unknown bbiSummaryType %d", (int)type);
+	return NULL;
+    }
+}
+
+#ifdef UNUSED
+static void bbiSummaryOnDiskRead(struct bbiFile *bbi, struct bbiSummaryOnDisk *sum)
+/* Read in summary from file. */
+{
+struct udcFile *udc = bbi->udc;
+boolean isSwapped = bbi->isSwapped;
+sum->chromId = udcReadBits32(udc, isSwapped);
+sum->start = udcReadBits32(udc, isSwapped);
+sum->end = udcReadBits32(udc, isSwapped);
+sum->validCount = udcReadBits32(udc, isSwapped);
+udcMustReadOne(udc, sum->minVal);
+udcMustReadOne(udc, sum->maxVal);
+udcMustReadOne(udc, sum->sumData);
+udcMustReadOne(udc, sum->sumSquares);
+}
+#endif /* UNUSED */
+
+static struct bbiSummary *bbiSummaryFromOnDisk(struct bbiSummaryOnDisk *in)
+/* Create a bbiSummary unlinked to anything from input in onDisk format. */
+{
+struct bbiSummary *out;
+AllocVar(out);
+out->chromId = in->chromId;
+out->start = in->start;
+out->end = in->end;
+out->validCount = in->validCount;
+out->minVal = in->minVal;
+out->maxVal = in->maxVal;
+out->sumData = in->sumData;
+out->sumSquares = in->sumSquares;
+return out;
+}
+
+static struct bbiSummary *bbiSummariesInRegion(struct bbiZoomLevel *zoom, struct bbiFile *bbi, 
+	int chromId, bits32 start, bits32 end)
+/* Return list of all summaries in region at given zoom level of bbiFile. */
+{
+struct bbiSummary *sumList = NULL, *sum;
+struct udcFile *udc = bbi->udc;
+udcSeek(udc, zoom->indexOffset);
+struct cirTreeFile *ctf = cirTreeFileAttach(bbi->fileName, bbi->udc);
+struct fileOffsetSize *blockList = cirTreeFindOverlappingBlocks(ctf, chromId, start, end);
+struct fileOffsetSize *block, *beforeGap, *afterGap;
+
+/* Set up for uncompression optionally. */
+char *uncompressBuf = NULL;
+if (bbi->uncompressBufSize > 0)
+    uncompressBuf = needLargeMem(bbi->uncompressBufSize);
+
+
+/* This loop is a little complicated because we merge the read requests for efficiency, but we 
+ * have to then go back through the data one unmerged block at a time. */
+for (block = blockList; block != NULL; )
+    {
+    /* Find contigious blocks and read them into mergedBuf. */
+    fileOffsetSizeFindGap(block, &beforeGap, &afterGap);
+    bits64 mergedOffset = block->offset;
+    bits64 mergedSize = beforeGap->offset + beforeGap->size - mergedOffset;
+    udcSeek(udc, mergedOffset);
+    char *mergedBuf = needLargeMem(mergedSize);
+    udcMustRead(udc, mergedBuf, mergedSize);
+    char *blockBuf = mergedBuf;
+
+    /* Loop through individual blocks within merged section. */
+    for (;block != afterGap; block = block->next)
+        {
+	/* Uncompress if necessary. */
+	char *blockPt, *blockEnd;
+	if (uncompressBuf)
+	    {
+	    blockPt = uncompressBuf;
+	    int uncSize = zUncompress(blockBuf, block->size, uncompressBuf, bbi->uncompressBufSize);
+	    blockEnd = blockPt + uncSize;
+	    }
+	else
+	    {
+	    blockPt = blockBuf;
+	    blockEnd = blockPt + block->size;
+	    }
+
+	/* Figure out bounds and number of items in block. */
+	int blockSize = blockEnd - blockPt;
+	struct bbiSummaryOnDisk *dSum;
+	int itemSize = sizeof(*dSum);
+	assert(blockSize % itemSize == 0);
+	int itemCount = blockSize / itemSize;
+
+	/* Read in items and convert to memory list format. */
+	int i;
+	for (i=0; i<itemCount; ++i)
+	    {
+	    dSum = (void *)blockPt;
+	    blockPt += sizeof(*dSum);
+	    if (dSum->chromId == chromId)
+		{
+		int s = max(dSum->start, start);
+		int e = min(dSum->end, end);
+		if (s < e)
+		    {
+		    sum = bbiSummaryFromOnDisk(dSum);
+		    slAddHead(&sumList, sum);
+		    }
+		}
+	    }
+	assert(blockPt == blockEnd);
+	blockBuf += block->size;
+        }
+    freeMem(mergedBuf);
+    }
+freeMem(uncompressBuf);
+slFreeList(&blockList);
+cirTreeFileDetach(&ctf);
+slReverse(&sumList);
+return sumList;
+}
+
+static bits32 bbiSummarySlice(struct bbiFile *bbi, bits32 baseStart, bits32 baseEnd, 
+	struct bbiSummary *sumList, struct bbiSummaryElement *el)
+/* Update retVal with the average value if there is any data in interval.  Return number
+ * of valid data bases in interval. */
+{
+bits32 validCount = 0;
+
+if (sumList != NULL)
+    {
+    double minVal = sumList->minVal;
+    double maxVal = sumList->maxVal;
+    double sumData = 0, sumSquares = 0;
+
+    struct bbiSummary *sum;
+    for (sum = sumList; sum != NULL && sum->start < baseEnd; sum = sum->next)
+	{
+	int overlap = rangeIntersection(baseStart, baseEnd, sum->start, sum->end);
+	if (overlap > 0)
+	    {
+	    double overlapFactor = (double)overlap / (sum->end - sum->start);
+	    validCount += sum->validCount * overlapFactor;
+	    sumData += sum->sumData * overlapFactor;
+	    sumSquares += sum->sumSquares * overlapFactor;
+	    if (maxVal < sum->maxVal)
+		maxVal = sum->maxVal;
+	    if (minVal > sum->minVal)
+		minVal = sum->minVal;
+	    }
+	}
+    if (validCount > 0)
+	{
+	el->validCount = validCount;
+	el->minVal = minVal;
+	el->maxVal = maxVal;
+	el->sumData = sumData;
+	el->sumSquares = sumSquares;
+	}
+    }
+return validCount;
+}
+
+static int bbiChromId(struct bbiFile *bbi, char *chrom)
+/* Return chromosome size */
+{
+struct bbiChromIdSize idSize;
+if (!bptFileFind(bbi->chromBpt, chrom, strlen(chrom), &idSize, sizeof(idSize)))
+    return -1;
+return idSize.chromId;
+}
+
+static boolean bbiSummaryArrayFromZoom(struct bbiZoomLevel *zoom, struct bbiFile *bbi, 
+	char *chrom, bits32 start, bits32 end,
+	int summarySize, struct bbiSummaryElement *summary)
+/* Look up region in index and get data at given zoom level.  Summarize this data
+ * in the summary array. */
+{
+boolean result = FALSE;
+int chromId = bbiChromId(bbi, chrom);
+if (chromId < 0)
+    return FALSE;
+struct bbiSummary *sum, *sumList = bbiSummariesInRegion(zoom, bbi, chromId, start, end);
+if (sumList != NULL)
+    {
+    int i;
+    bits32 baseStart = start, baseEnd;
+    bits32 baseCount = end - start;
+    sum = sumList;
+    for (i=0; i<summarySize; ++i)
+        {
+	/* Calculate end of this part of summary */
+	baseEnd = start + (bits64)baseCount*(i+1)/summarySize;
+
+        /* Advance sum to skip over parts we are no longer interested in. */
+	while (sum != NULL && sum->end <= baseStart)
+	    sum = sum->next;
+
+	if (bbiSummarySlice(bbi, baseStart, baseEnd, sum, &summary[i]))
+	    result = TRUE;
+
+	/* Next time round start where we left off. */
+	baseStart = baseEnd;
+	}
+    slFreeList(&sumList);
+    }
+return result;
+}
+
+static bits32 bbiIntervalSlice(struct bbiFile *bbi, bits32 baseStart, bits32 baseEnd, 
+	struct bbiInterval *intervalList, struct bbiSummaryElement *el)
+/* Update retVal with the average value if there is any data in interval.  Return number
+ * of valid data bases in interval. */
+{
+double validCount = 0;
+
+if (intervalList != NULL)
+    {
+    struct bbiInterval *interval;
+    double sumData = 0, sumSquares = 0;
+    double minVal = intervalList->val;
+    double maxVal = intervalList->val;
+
+    for (interval = intervalList; interval != NULL && interval->start < baseEnd; 
+	    interval = interval->next)
+	{
+	int overlap = rangeIntersection(baseStart, baseEnd, interval->start, interval->end);
+	if (overlap > 0)
+	    {
+	    int intervalSize = interval->end - interval->start;
+	    double overlapFactor = (double)overlap / intervalSize;
+	    double intervalWeight = intervalSize * overlapFactor;
+	    validCount += intervalWeight;
+	    sumData += interval->val * intervalWeight;
+	    sumSquares += interval->val * interval->val * intervalWeight;
+	    if (maxVal < interval->val)
+		maxVal = interval->val;
+	    if (minVal > interval->val)
+		minVal = interval->val;
+	    }
+	}
+    el->validCount = round(validCount);
+    el->minVal = minVal;
+    el->maxVal = maxVal;
+    el->sumData = sumData;
+    el->sumSquares = sumSquares;
+    }
+return round(validCount);
+}
+
+
+static boolean bbiSummaryArrayFromFull(struct bbiFile *bbi, 
+	char *chrom, bits32 start, bits32 end, BbiFetchIntervals fetchIntervals,
+	int summarySize, struct bbiSummaryElement *summary)
+/* Summarize data, not using zoom. */
+{
+struct bbiInterval *intervalList = NULL, *interval;
+struct lm *lm = lmInit(0);
+intervalList = (*fetchIntervals)(bbi, chrom, start, end, lm);
+boolean result = FALSE;
+if (intervalList != NULL);
+    {
+    int i;
+    bits32 baseStart = start, baseEnd;
+    bits32 baseCount = end - start;
+    interval = intervalList;
+    for (i=0; i<summarySize; ++i)
+        {
+	/* Calculate end of this part of summary */
+	baseEnd = start + (bits64)baseCount*(i+1)/summarySize;
+	int end1 = baseEnd;
+	if (end1 == baseStart)
+	    end1 = baseStart+1;
+
+        /* Advance interval to skip over parts we are no longer interested in. */
+	while (interval != NULL && interval->end <= baseStart)
+	    interval = interval->next;
+
+	if (bbiIntervalSlice(bbi, baseStart, end1, interval, &summary[i]))
+	    result = TRUE;
+
+	/* Next time round start where we left off. */
+	baseStart = baseEnd;
+	}
+    }
+lmCleanup(&lm);
+return result;
+}
+
+boolean bbiSummaryArrayExtended(struct bbiFile *bbi, char *chrom, bits32 start, bits32 end,
+	BbiFetchIntervals fetchIntervals,
+	int summarySize, struct bbiSummaryElement *summary)
+/* Fill in summary with  data from indicated chromosome range in bigWig file. 
+ * Returns FALSE if no data at that position. */
+{
+boolean result = FALSE;
+
+/* Protect from bad input. */
+if (start >= end)
+    return result;
+bzero(summary, summarySize * sizeof(summary[0]));
+
+/* Figure out what size of data we want.  We actually want to get 2 data points per summary
+ * value if possible to minimize the effect of a data point being split between summary pixels. */
+bits32 baseSize = end - start; 
+int fullReduction = (baseSize/summarySize);
+int zoomLevel = fullReduction/2;
+if (zoomLevel < 0)
+    zoomLevel = 0;
+
+/* Get the closest zoom level less than what we're looking for. */
+struct bbiZoomLevel *zoom = bbiBestZoom(bbi->levelList, zoomLevel);
+if (zoom != NULL)
+    result = bbiSummaryArrayFromZoom(zoom, bbi, chrom, start, end, summarySize, summary);
+else
+    result = bbiSummaryArrayFromFull(bbi, chrom, start, end, fetchIntervals, summarySize, summary);
+return result;
+}
+
+boolean bbiSummaryArray(struct bbiFile *bbi, char *chrom, bits32 start, bits32 end,
+	BbiFetchIntervals fetchIntervals,
+	enum bbiSummaryType summaryType, int summarySize, double *summaryValues)
+/* Fill in summaryValues with  data from indicated chromosome range in bigWig file.
+ * Be sure to initialize summaryValues to a default value, which will not be touched
+ * for regions without data in file.  (Generally you want the default value to either
+ * be 0.0 or nan("") depending on the application.)  Returns FALSE if no data
+ * at that position. */
+{
+struct bbiSummaryElement *elements;
+AllocArray(elements, summarySize);
+boolean ret = bbiSummaryArrayExtended(bbi, chrom, start, end, 
+	fetchIntervals, summarySize, elements);
+if (ret)
+    {
+    int i;
+    double covFactor = (double)summarySize/(end - start);
+    for (i=0; i<summarySize; ++i)
+        {
+	struct bbiSummaryElement *el = &elements[i];
+	if (el->validCount > 0)
+	    {
+	    double val;
+	    switch (summaryType)
+		{
+		case bbiSumMean:
+		    val = el->sumData/el->validCount;
+		    break;
+		case bbiSumMax:
+		    val = el->maxVal;
+		    break;
+		case bbiSumMin:
+		    val = el->minVal;
+		    break;
+		case bbiSumCoverage:
+		    val = covFactor*el->validCount;
+		    break;
+		case bbiSumStandardDeviation:
+		    val = calcStdFromSums(el->sumData, el->sumSquares, el->validCount);
+		    break;
+		default:
+		    internalErr();
+		    val = 0.0;
+		    break;
+		}
+	    summaryValues[i] = val;
+	    }
+	}
+    }
+freeMem(elements);
+return ret;
+}
+
+struct bbiSummaryElement bbiTotalSummary(struct bbiFile *bbi)
+/* Return summary of entire file! */
+{
+struct udcFile *udc = bbi->udc;
+boolean isSwapped = bbi->isSwapped;
+struct bbiSummaryElement res;
+ZeroVar(&res);
+
+if (bbi->totalSummaryOffset != 0)
+    {
+    udcSeek(udc, bbi->totalSummaryOffset);
+    res.validCount = udcReadBits64(udc, isSwapped);
+    res.minVal = udcReadDouble(udc, isSwapped);
+    res.maxVal = udcReadDouble(udc, isSwapped);
+    res.sumData = udcReadDouble(udc, isSwapped);
+    res.sumSquares = udcReadDouble(udc, isSwapped);
+    }
+else if (bbi->version == 1)
+    /* Require version 1 so as not to have to deal with compression.  Should not happen
+     * to have NULL totalSummaryOffset for non-empty version 2+ file anyway. */
+    {
+    /* Find most extreme zoom. */
+    struct bbiZoomLevel *bestZoom = NULL, *zoom;
+    bits32 bestReduction = 0;
+    for (zoom = bbi->levelList; zoom != NULL; zoom = zoom->next)
+	{
+	if (zoom->reductionLevel > bestReduction)
+	    {
+	    bestReduction = zoom->reductionLevel;
+	    bestZoom = zoom;
+	    }
+	}
+
+    if (bestZoom != NULL)
+	{
+	udcSeek(udc, bestZoom->dataOffset);
+	bits32 zoomSectionCount = udcReadBits32(udc, isSwapped);
+	bits32 i;
+	for (i=0; i<zoomSectionCount; ++i)
+	    {
+	    /* Read, but ignore, position. */
+	    bits32 chromId, chromStart, chromEnd;
+	    chromId = udcReadBits32(udc, isSwapped);
+	    chromStart = udcReadBits32(udc, isSwapped);
+	    chromEnd = udcReadBits32(udc, isSwapped);
+
+	    /* First time through set values, rest of time add to them. */
+	    if (i == 0)
+		{
+		res.validCount = udcReadBits32(udc, isSwapped);
+		res.minVal = udcReadFloat(udc, isSwapped);
+		res.maxVal = udcReadFloat(udc, isSwapped);
+		res.sumData = udcReadFloat(udc, isSwapped);
+		res.sumSquares = udcReadFloat(udc, isSwapped);
+		}
+	    else
+		{
+		res.validCount += udcReadBits32(udc, isSwapped);
+		float minVal = udcReadFloat(udc, isSwapped);
+		if (minVal < res.minVal) res.minVal = minVal;
+		float maxVal = udcReadFloat(udc, isSwapped);
+		if (maxVal > res.maxVal) res.maxVal = maxVal;
+		res.sumData += udcReadFloat(udc, isSwapped);
+		res.sumSquares += udcReadFloat(udc, isSwapped);
+		}
+	    }
+	}
+    }
+return res;
+}
+
+time_t bbiUpdateTime(struct bbiFile *bbi)
+/* return bbi->udc->updateTime */
+{
+struct udcFile *udc = bbi->udc;
+return udcUpdateTime(udc);
+}
diff --git a/lib/bbiWrite.c b/lib/bbiWrite.c
new file mode 100644
index 0000000..1801388
--- /dev/null
+++ b/lib/bbiWrite.c
@@ -0,0 +1,581 @@
+#include "common.h"
+#include "hash.h"
+#include "linefile.h"
+#include "sqlNum.h"
+#include "localmem.h"
+#include "zlibFace.h"
+#include "cirTree.h"
+#include "bPlusTree.h"
+#include "bbiFile.h"
+#include "obscure.h"
+
+void bbiWriteDummyHeader(FILE *f)
+/* Write out all-zero header, just to reserve space for it. */
+{
+repeatCharOut(f, 0, 64);
+}
+
+void bbiWriteDummyZooms(FILE *f)
+/* Write out zeroes to reserve space for ten zoom levels. */
+{
+repeatCharOut(f, 0, bbiMaxZoomLevels * 24);
+}
+
+void bbiSummaryElementWrite(FILE *f, struct bbiSummaryElement *sum)
+/* Write out summary element to file. */
+{
+writeOne(f, sum->validCount);
+writeOne(f, sum->minVal);
+writeOne(f, sum->maxVal);
+writeOne(f, sum->sumData);
+writeOne(f, sum->sumSquares);
+}
+
+static int bbiChromInfoCmp(const void *va, const void *vb)
+/* Sort bbiChromInfo.  Unlike most of our sorts this is single rather
+ * than double indirect. */
+{
+const struct bbiChromInfo *a = (const struct bbiChromInfo *)va;
+const struct bbiChromInfo *b = (const struct bbiChromInfo *)vb;
+return strcmp(a->name, b->name);
+}
+
+
+void bbiWriteChromInfo(struct bbiChromUsage *usageList, int blockSize, FILE *f)
+/* Write out information on chromosomes to file. */
+{
+int chromCount = slCount(usageList);
+struct bbiChromUsage *usage;
+
+/* Allocate and fill in array from list. */
+struct bbiChromInfo *chromInfoArray;
+AllocArray(chromInfoArray, chromCount);
+int i;
+int maxChromNameSize = 0;
+for (i=0, usage = usageList; i<chromCount; ++i, usage = usage->next)
+    {
+    char *chromName = usage->name;
+    int len = strlen(chromName);
+    if (len > maxChromNameSize)
+        maxChromNameSize = len;
+    chromInfoArray[i].name = chromName;
+    chromInfoArray[i].id = usage->id;
+    chromInfoArray[i].size = usage->size;
+    }
+
+/* Sort so the b-Tree actually works. */
+qsort(chromInfoArray, chromCount, sizeof(chromInfoArray[0]), bbiChromInfoCmp);
+
+/* Write chromosome bPlusTree */
+int chromBlockSize = min(blockSize, chromCount);
+bptFileBulkIndexToOpenFile(chromInfoArray, sizeof(chromInfoArray[0]), chromCount, chromBlockSize,
+    bbiChromInfoKey, maxChromNameSize, bbiChromInfoVal, 
+    sizeof(chromInfoArray[0].id) + sizeof(chromInfoArray[0].size), 
+    f);
+
+freeMem(chromInfoArray);
+}
+
+void bbiWriteFloat(FILE *f, float val)
+/* Write out floating point val to file.  Mostly to convert from double... */
+{
+writeOne(f, val);
+}
+
+struct hash *bbiChromSizesFromFile(char *fileName)
+/* Read two column file into hash keyed by chrom. */
+{
+struct hash *hash = hashNew(0);
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[2];
+while (lineFileRow(lf, row))
+    hashAddInt(hash, row[0], sqlUnsigned(row[1]));
+
+lineFileClose(&lf);
+return hash;
+}
+
+void bbiChromInfoKey(const void *va, char *keyBuf)
+/* Get key field out of bbiChromInfo. */
+{
+const struct bbiChromInfo *a = ((struct bbiChromInfo *)va);
+strcpy(keyBuf, a->name);
+}
+
+void *bbiChromInfoVal(const void *va)
+/* Get val field out of bbiChromInfo. */
+{
+const struct bbiChromInfo *a = ((struct bbiChromInfo *)va);
+return (void*)(&a->id);
+}
+
+void bbiChromUsageFree(struct bbiChromUsage **pUsage)
+/* free a single bbiChromUsage structure */
+{
+struct bbiChromUsage *usage = *pUsage;
+if (usage != NULL)
+    {
+    freeMem(usage->name);
+    freez(pUsage);
+    }
+}
+
+void bbiChromUsageFreeList(struct bbiChromUsage **pList)
+/* free a list of bbiChromUsage structures */
+{
+struct bbiChromUsage *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    bbiChromUsageFree(&el);
+    }
+*pList = NULL;
+}
+
+struct bbiChromUsage *bbiChromUsageFromBedFile(struct lineFile *lf, 
+	struct hash *chromSizesHash, int *retMinDiff, double *retAveSize, bits64 *retBedCount)
+/* Go through bed file and collect chromosomes and statistics. */
+{
+char *row[3];
+struct hash *uniqHash = hashNew(0);
+struct bbiChromUsage *usage = NULL, *usageList = NULL;
+int lastStart = -1;
+bits32 id = 0;
+bits64 totalBases = 0, bedCount = 0;
+int minDiff = BIGNUM;
+
+lineFileRemoveInitialCustomTrackLines(lf);
+
+for (;;)
+    {
+    int rowSize = lineFileChopNext(lf, row, ArraySize(row));
+    if (rowSize == 0)
+        break;
+    lineFileExpectWords(lf, 3, rowSize);
+    char *chrom = row[0];
+    int start = lineFileNeedNum(lf, row, 1);
+    int end = lineFileNeedNum(lf, row, 2);
+    if (start > end)
+        {
+	    errAbort("end (%d) before start (%d) line %d of %s",
+	    	end, start, lf->lineIx, lf->fileName);
+	}
+    ++bedCount;
+    totalBases += (end - start);
+    if (usage == NULL || differentString(usage->name, chrom))
+        {
+	if (hashLookup(uniqHash, chrom))
+	    {
+	    errAbort("%s is not sorted at line %d.  Please use \"sort -k1,1 -k2,2n\" or bedSort and try again.",
+	    	lf->fileName, lf->lineIx);
+	    }
+	hashAdd(uniqHash, chrom, NULL);
+	struct hashEl *chromHashEl = hashLookup(chromSizesHash, chrom);
+	if (chromHashEl == NULL)
+	    errAbort("%s is not found in chromosome sizes file", chrom);
+	int chromSize = ptToInt(chromHashEl->val);
+	AllocVar(usage);
+	usage->name = cloneString(chrom);
+	usage->id = id++;
+	usage->size = chromSize;
+	slAddHead(&usageList, usage);
+	lastStart = -1;
+	}
+    if (end > usage->size)
+        errAbort("End coordinate %d bigger than %s size of %d line %d of %s", end, usage->name, usage->size, lf->lineIx, lf->fileName);
+    usage->itemCount += 1;
+    if (lastStart >= 0)
+        {
+	int diff = start - lastStart;
+	if (diff < minDiff)
+	    {
+	    if (diff < 0)
+		errAbort("%s is not sorted at line %d.  Please use \"sort -k1,1 -k2,2n\" or bedSort and try again.",
+		    lf->fileName, lf->lineIx);
+	    minDiff = diff;
+	    }
+	}
+    lastStart = start;
+    }
+slReverse(&usageList);
+*retMinDiff = minDiff;
+*retAveSize = (double)totalBases/bedCount;
+*retBedCount = bedCount;
+freeHash(&uniqHash);
+return usageList;
+}
+
+int bbiCountSectionsNeeded(struct bbiChromUsage *usageList, int itemsPerSlot)
+/* Count up number of sections needed for data. */
+{
+struct bbiChromUsage *usage;
+int count = 0;
+for (usage = usageList; usage != NULL; usage = usage->next)
+    {
+    int countOne = (usage->itemCount + itemsPerSlot - 1)/itemsPerSlot;
+    count += countOne;
+    verbose(2, "%s %d, %d blocks of %d\n", usage->name, usage->itemCount, countOne, itemsPerSlot);
+    }
+return count;
+}
+
+
+void bbiAddToSummary(bits32 chromId, bits32 chromSize, bits32 start, bits32 end, 
+	bits32 validCount, double minVal, double maxVal, double sumData, double sumSquares,  
+	int reduction, struct bbiSummary **pOutList)
+/* Add data range to summary - putting it onto top of list if possible, otherwise
+ * expanding list. */
+{
+struct bbiSummary *sum = *pOutList;
+if (end > chromSize)	// Avoid pathological clipping situation on bad input
+    end = chromSize;
+while (start < end)
+    {
+    /* See if need to allocate a new summary. */
+    if (sum == NULL || sum->chromId != chromId || sum->end <= start)
+        {
+	struct bbiSummary *newSum;
+	AllocVar(newSum);
+	newSum->chromId = chromId;
+	if (sum == NULL || sum->chromId != chromId || sum->end + reduction <= start)
+	    newSum->start = start;
+	else
+	    newSum->start = sum->end;
+	newSum->end = newSum->start + reduction;
+	if (newSum->end > chromSize)
+	    newSum->end = chromSize;
+	newSum->minVal = minVal;
+	newSum->maxVal = maxVal;
+	sum = newSum;
+	slAddHead(pOutList, sum);
+	}
+
+    /* Figure out amount of overlap between current summary and item */
+    int overlap = rangeIntersection(start, end, sum->start, sum->end);
+    if (overlap <= 0) 
+	{
+        warn("%u %u doesn't intersect %u %u, chromId %u chromSize %u", start, end, sum->start, sum->end, chromId, chromSize);
+	internalErr();
+	}
+    int itemSize = end - start;
+    double overlapFactor = (double)overlap/itemSize;
+
+    /* Fold overlapping bits into output. */
+    sum->validCount += overlapFactor * validCount;
+    if (sum->minVal > minVal)
+        sum->minVal = minVal;
+    if (sum->maxVal < maxVal)
+        sum->maxVal = maxVal;
+    sum->sumData += overlapFactor * sumData;
+    sum->sumSquares += overlapFactor * sumSquares;
+
+    /* Advance over overlapping bits. */
+    start += overlap;
+    }
+}
+
+void bbiAddRangeToSummary(bits32 chromId, bits32 chromSize, bits32 start, bits32 end, 
+	double val, int reduction, struct bbiSummary **pOutList)
+/* Add chromosome range to summary - putting it onto top of list if possible, otherwise
+ * expanding list. */
+{
+int size = end-start;
+double sum = size*val;
+double sumSquares = sum*val;
+bbiAddToSummary(chromId, chromSize, start, end, size, val, val, sum, sumSquares, reduction, pOutList);
+}
+
+struct bbiSummary *bbiReduceSummaryList(struct bbiSummary *inList, 
+	struct bbiChromInfo *chromInfoArray, int reduction)
+/* Reduce summary list to another summary list. */
+{
+struct bbiSummary *outList = NULL;
+struct bbiSummary *sum;
+for (sum = inList; sum != NULL; sum = sum->next)
+    bbiAddToSummary(sum->chromId, chromInfoArray[sum->chromId].size, sum->start, sum->end, sum->validCount, sum->minVal,
+    	sum->maxVal, sum->sumData, sum->sumSquares, reduction, &outList);
+slReverse(&outList);
+return outList;
+}
+
+bits64 bbiTotalSummarySize(struct bbiSummary *list)
+/* Return size on disk of all summaries. */
+{
+struct bbiSummary *el;
+bits64 total = 0;
+for (el = list; el != NULL; el = el->next)
+    total += sizeof(struct bbiSummaryOnDisk);
+return total;
+}
+
+
+static bits64 bbiSummaryFetchOffset(const void *va, void *context)
+/* Fetch bbiSummary file offset for r-tree */
+{
+const struct bbiSummary *a = *((struct bbiSummary **)va);
+return a->fileOffset;
+}
+
+static struct cirTreeRange bbiSummaryFetchKey(const void *va, void *context)
+/* Fetch bbiSummary key for r-tree */
+{
+struct cirTreeRange res;
+const struct bbiSummary *a = *((struct bbiSummary **)va);
+res.chromIx = a->chromId;
+res.start = a->start;
+res.end = a->end;
+return res;
+}
+
+
+static bits64 bbiWriteSummaryAndIndexComp(struct bbiSummary *summaryList, 
+	int blockSize, int itemsPerSlot, FILE *f)
+/* Write out summary and index to summary uncompressed, returning start position of
+ * summary index. */
+{
+bits32 i, count = slCount(summaryList);
+struct bbiSummary **summaryArray;
+AllocArray(summaryArray, count);
+writeOne(f, count);
+struct bbiSummary *summary = summaryList;
+
+/* Figure out max size of uncompressed and compressed blocks. */
+bits32 itemSize = sizeof(summary->chromId) + sizeof(summary->start) + sizeof(summary->end) + sizeof(summary->validCount) + 4*sizeof(float);
+int uncBufSize = itemSize * itemsPerSlot;
+char uncBuf[uncBufSize];
+int compBufSize = zCompBufSize(uncBufSize);
+char compBuf[compBufSize];
+
+/* Loop through compressing and writing one slot at a time. */
+bits32 itemsLeft = count;
+int sumIx = 0;
+while (itemsLeft > 0)
+    {
+    bits32 itemsInSlot = itemsLeft;
+    if (itemsInSlot > itemsPerSlot)
+         itemsInSlot = itemsPerSlot;
+    char *writePt = uncBuf;
+
+    bits64 filePos = ftell(f);
+    for (i=0; i<itemsInSlot; ++i)
+        {
+	summaryArray[sumIx++] = summary;
+	memWriteOne(&writePt, summary->chromId);
+	memWriteOne(&writePt, summary->start);
+	memWriteOne(&writePt, summary->end);
+	memWriteOne(&writePt, summary->validCount);
+	memWriteFloat(&writePt, summary->minVal);
+	memWriteFloat(&writePt, summary->maxVal);
+	memWriteFloat(&writePt, summary->sumData);
+	memWriteFloat(&writePt, summary->sumSquares);
+	summary->fileOffset = filePos;
+	summary = summary->next;
+	if (summary == NULL)
+	    break;
+	}
+
+    bits32 uncSize = writePt - uncBuf;
+    int compSize = zCompress(uncBuf, uncSize, compBuf, compBufSize);
+    mustWrite(f, compBuf, compSize);
+
+    itemsLeft -= itemsInSlot;
+    }
+bits64 indexOffset = ftell(f);
+cirTreeFileBulkIndexToOpenFile(summaryArray, sizeof(summaryArray[0]), count,
+    blockSize, itemsPerSlot, NULL, bbiSummaryFetchKey, bbiSummaryFetchOffset, 
+    indexOffset, f);
+freez(&summaryArray);
+return indexOffset;
+}
+
+static bits64 bbiWriteSummaryAndIndexUnc(struct bbiSummary *summaryList, 
+	int blockSize, int itemsPerSlot, FILE *f)
+/* Write out summary and index to summary compressed, returning start position of
+ * summary index. */
+{
+bits32 i, count = slCount(summaryList);
+struct bbiSummary **summaryArray;
+AllocArray(summaryArray, count);
+writeOne(f, count);
+struct bbiSummary *summary;
+for (summary = summaryList, i=0; summary != NULL; summary = summary->next, ++i)
+    {
+    summaryArray[i] = summary;
+    summary->fileOffset = ftell(f);
+    writeOne(f, summary->chromId);
+    writeOne(f, summary->start);
+    writeOne(f, summary->end);
+    writeOne(f, summary->validCount);
+    bbiWriteFloat(f, summary->minVal);
+    bbiWriteFloat(f, summary->maxVal);
+    bbiWriteFloat(f, summary->sumData);
+    bbiWriteFloat(f, summary->sumSquares);
+    }
+bits64 indexOffset = ftell(f);
+cirTreeFileBulkIndexToOpenFile(summaryArray, sizeof(summaryArray[0]), count,
+    blockSize, itemsPerSlot, NULL, bbiSummaryFetchKey, bbiSummaryFetchOffset, 
+    indexOffset, f);
+freez(&summaryArray);
+return indexOffset;
+}
+
+bits64 bbiWriteSummaryAndIndex(struct bbiSummary *summaryList, 
+	int blockSize, int itemsPerSlot, boolean doCompress, FILE *f)
+/* Write out summary and index to summary, returning start position of
+ * summary index. */
+{
+if (doCompress)
+    return bbiWriteSummaryAndIndexComp(summaryList, blockSize, itemsPerSlot, f);
+else
+    return bbiWriteSummaryAndIndexUnc(summaryList, blockSize, itemsPerSlot, f);
+}
+
+struct cirTreeRange bbiBoundsArrayFetchKey(const void *va, void *context)
+/* Fetch bbiBoundsArray key for r-tree */
+{
+const struct bbiBoundsArray *a = ((struct bbiBoundsArray *)va);
+return a->range;
+}
+
+bits64 bbiBoundsArrayFetchOffset(const void *va, void *context)
+/* Fetch bbiBoundsArray file offset for r-tree */
+{
+const struct bbiBoundsArray *a = ((struct bbiBoundsArray *)va);
+return a->offset;
+}
+
+struct bbiSumOutStream *bbiSumOutStreamOpen(int allocCount, FILE *f, boolean doCompress)
+/* Allocate new bbiSumOutStream. */
+{
+struct bbiSumOutStream *stream;
+AllocVar(stream);
+AllocArray(stream->array, allocCount);
+stream->allocCount = allocCount;
+stream->f = f;
+stream->doCompress = doCompress;
+return stream;
+}
+
+void bbiSumOutStreamFlush(struct bbiSumOutStream *stream)
+/* Flush out any pending input. */
+{
+if (stream->elCount != 0)
+    {
+    int uncSize = stream->elCount * sizeof(stream->array[0]);
+    if (stream->doCompress)
+        {
+	int compBufSize = zCompBufSize(uncSize);
+	char compBuf[compBufSize];
+	int compSize = zCompress(stream->array, uncSize, compBuf, compBufSize);
+	mustWrite(stream->f, compBuf, compSize);
+	}
+    else
+        {
+	mustWrite(stream->f, stream->array, uncSize);
+	}
+    stream->elCount = 0;
+    }
+}
+
+void bbiSumOutStreamClose(struct bbiSumOutStream **pStream)
+/* Free up bbiSumOutStream */
+{
+struct bbiSumOutStream *stream = *pStream;
+if (stream != NULL)
+    {
+    bbiSumOutStreamFlush(stream);
+    freeMem(stream->array);
+    freez(pStream);
+    }
+}
+
+void bbiSumOutStreamWrite(struct bbiSumOutStream *stream, struct bbiSummary *sum)
+/* Write out next one to stream. */
+{
+int elCount = stream->elCount;
+struct bbiSummaryOnDisk *a = &stream->array[elCount];
+a->chromId = sum->chromId;
+a->start = sum->start;
+a->end = sum->end;
+a->validCount = sum->validCount;
+a->minVal = sum->minVal;
+a->maxVal = sum->maxVal;
+a->sumData = sum->sumData;
+a->sumSquares = sum->sumSquares;
+elCount += 1;
+stream->elCount = elCount;
+if (elCount >= stream->allocCount)
+    bbiSumOutStreamFlush(stream);    
+}
+
+void bbiOutputOneSummaryFurtherReduce(struct bbiSummary *sum, 
+	struct bbiSummary **pTwiceReducedList, 
+	int doubleReductionSize, struct bbiBoundsArray **pBoundsPt, 
+	struct bbiBoundsArray *boundsEnd, bits32 chromSize, struct lm *lm, 
+	struct bbiSumOutStream *stream)
+/* Write out sum to file, keeping track of minimal info on it in *pBoundsPt, and also adding
+ * it to second level summary. */
+{
+/* Get place to store file offset etc and make sure we have not gone off end. */
+struct bbiBoundsArray *bounds = *pBoundsPt;
+assert(bounds < boundsEnd);
+*pBoundsPt += 1;
+
+/* Fill in bounds info. */
+bounds->offset = ftell(stream->f);
+bounds->range.chromIx = sum->chromId;
+bounds->range.start = sum->start;
+bounds->range.end = sum->end;
+
+/* Write out summary info. */
+bbiSumOutStreamWrite(stream, sum);
+
+/* Fold summary info into pTwiceReducedList. */
+struct bbiSummary *twiceReduced = *pTwiceReducedList;
+if (twiceReduced == NULL || twiceReduced->chromId != sum->chromId 
+	|| twiceReduced->start + doubleReductionSize < sum->end)
+    {
+    lmAllocVar(lm, twiceReduced);
+    *twiceReduced = *sum;
+    slAddHead(pTwiceReducedList, twiceReduced);
+    }
+else
+    {
+    twiceReduced->end = sum->end;
+    twiceReduced->validCount += sum->validCount;
+    if (sum->minVal < twiceReduced->minVal) twiceReduced->minVal = sum->minVal;
+    if (sum->maxVal > twiceReduced->maxVal) twiceReduced->maxVal = sum->maxVal;
+    twiceReduced->sumData += sum->sumData;
+    twiceReduced->sumSquares += sum->sumSquares;
+    }
+}
+
+struct bbiSummary *bbiSummarySimpleReduce(struct bbiSummary *list, int reduction, struct lm *lm)
+/* Do a simple reduction - where among other things the reduction level is an integral
+ * multiple of the previous reduction level, and the list is sorted. Allocate result out of lm. */
+{
+struct bbiSummary *newList = NULL, *sum, *newSum = NULL;
+for (sum = list; sum != NULL; sum = sum->next)
+    {
+    if (newSum == NULL || newSum->chromId != sum->chromId || sum->end > newSum->start + reduction)
+        {
+	lmAllocVar(lm, newSum);
+	*newSum = *sum;
+	slAddHead(&newList, newSum);
+	}
+    else
+        {
+	assert(newSum->end < sum->end);	// check sorted input assumption
+	newSum->end = sum->end;
+	newSum->validCount += sum->validCount;
+	if (newSum->minVal > sum->minVal) newSum->minVal = sum->minVal;
+	if (newSum->maxVal < sum->maxVal) newSum->maxVal = sum->maxVal;
+	newSum->sumData += sum->sumData;
+	newSum->sumSquares += sum->sumSquares;
+	}
+    }
+slReverse(&newList);
+return newList;
+}
+
diff --git a/lib/bigBed.c b/lib/bigBed.c
new file mode 100644
index 0000000..5875373
--- /dev/null
+++ b/lib/bigBed.c
@@ -0,0 +1,253 @@
+/* bigBed - interface to binary file with bed-style values (that is a bunch of
+ * possibly overlapping regions. */
+
+#include "common.h"
+#include "hash.h"
+#include "linefile.h"
+#include "localmem.h"
+#include "obscure.h"
+#include "dystring.h"
+#include "rangeTree.h"
+#include "cirTree.h"
+#include "bPlusTree.h"
+#include "basicBed.h"
+#include "asParse.h"
+#include "zlibFace.h"
+#include "sig.h"
+#include "udc.h"
+#include "bbiFile.h"
+#include "bigBed.h"
+
+struct bbiFile *bigBedFileOpen(char *fileName)
+/* Open up big bed file. */
+{
+return bbiFileOpen(fileName, bigBedSig, "big bed");
+}
+
+boolean bigBedFileCheckSigs(char *fileName)
+/* check file signatures at beginning and end of file */
+{
+return bbiFileCheckSigs(fileName, bigBedSig, "big bed");
+}
+
+struct bigBedInterval *bigBedIntervalQuery(struct bbiFile *bbi, char *chrom,
+	bits32 start, bits32 end, int maxItems, struct lm *lm)
+/* Get data for interval.  Return list allocated out of lm.  Set maxItems to maximum
+ * number of items to return, or to 0 for all items. */
+{
+struct bigBedInterval *el, *list = NULL;
+int itemCount = 0;
+bbiAttachUnzoomedCir(bbi);
+bits32 chromId;
+struct fileOffsetSize *blockList = bbiOverlappingBlocks(bbi, bbi->unzoomedCir,
+	chrom, start, end, &chromId);
+struct fileOffsetSize *block, *beforeGap, *afterGap;
+struct udcFile *udc = bbi->udc;
+boolean isSwapped = bbi->isSwapped;
+struct dyString *dy = dyStringNew(32);
+
+/* Set up for uncompression optionally. */
+char *uncompressBuf = NULL;
+if (bbi->uncompressBufSize > 0)
+    uncompressBuf = needLargeMem(bbi->uncompressBufSize);
+
+for (block = blockList; block != NULL; )
+    {
+    /* Find contigious blocks and read them into mergedBuf. */
+    fileOffsetSizeFindGap(block, &beforeGap, &afterGap);
+    bits64 mergedOffset = block->offset;
+    bits64 mergedSize = beforeGap->offset + beforeGap->size - mergedOffset;
+    udcSeek(udc, mergedOffset);
+    char *mergedBuf = needLargeMem(mergedSize);
+    udcMustRead(udc, mergedBuf, mergedSize);
+    char *blockBuf = mergedBuf;
+
+    /* Loop through individual blocks within merged section. */
+    for (;block != afterGap; block = block->next)
+        {
+	/* Uncompress if necessary. */
+	char *blockPt, *blockEnd;
+	if (uncompressBuf)
+	    {
+	    blockPt = uncompressBuf;
+	    int uncSize = zUncompress(blockBuf, block->size, uncompressBuf, bbi->uncompressBufSize);
+	    blockEnd = blockPt + uncSize;
+	    }
+	else
+	    {
+	    blockPt = blockBuf;
+	    blockEnd = blockPt + block->size;
+	    }
+
+	while (blockPt < blockEnd)
+	    {
+	    /* Read next record into local variables. */
+	    bits32 chr = memReadBits32(&blockPt, isSwapped);	// Read and discard chromId
+	    bits32 s = memReadBits32(&blockPt, isSwapped);
+	    bits32 e = memReadBits32(&blockPt, isSwapped);
+	    int c;
+	    dyStringClear(dy);
+	    while ((c = *blockPt++) >= 0)
+		{
+		if (c == 0)
+		    break;
+		dyStringAppendC(dy, c);
+		}
+
+	    /* If we're actually in range then copy it into a new  element and add to list. */
+	    if (chr == chromId && rangeIntersection(s, e, start, end) > 0)
+		{
+		++itemCount;
+		if (maxItems > 0 && itemCount > maxItems)
+		    break;
+
+		lmAllocVar(lm, el);
+		el->start = s;
+		el->end = e;
+		if (dy->stringSize > 0)
+		    el->rest = lmCloneString(lm, dy->string);
+		slAddHead(&list, el);
+		}
+	    }
+	if (maxItems > 0 && itemCount > maxItems)
+	    break;
+	blockBuf += block->size;
+        }
+    if (maxItems > 0 && itemCount > maxItems)
+        break;
+    freez(&mergedBuf);
+    }
+freeMem(uncompressBuf);
+dyStringFree(&dy);
+slFreeList(&blockList);
+slReverse(&list);
+return list;
+}
+
+int bigBedIntervalToRow(struct bigBedInterval *interval, char *chrom, char *startBuf, char *endBuf,
+	char **row, int rowSize)
+/* Convert bigBedInterval into an array of chars equivalent to what you'd get by
+ * parsing the bed file. The startBuf and endBuf are used to hold the ascii representation of
+ * start and end.  Note that the interval->rest string will have zeroes inserted as a side effect.
+ */
+{
+int fieldCount = 3;
+sprintf(startBuf, "%u", interval->start);
+sprintf(endBuf, "%u", interval->end);
+row[0] = chrom;
+row[1] = startBuf;
+row[2] = endBuf;
+if (!isEmpty(interval->rest))
+    {
+    int wordCount = chopByWhite(interval->rest, row+3, rowSize-3);
+    fieldCount += wordCount;
+    }
+return fieldCount;
+}
+
+static struct bbiInterval *bigBedCoverageIntervals(struct bbiFile *bbi,
+	char *chrom, bits32 start, bits32 end, struct lm *lm)
+/* Return intervals where the val is the depth of coverage. */
+{
+/* Get list of overlapping intervals */
+struct bigBedInterval *bi, *biList = bigBedIntervalQuery(bbi, chrom, start, end, 0, lm);
+if (biList == NULL)
+    return NULL;
+
+/* Make a range tree that collects coverage. */
+struct rbTree *rangeTree = rangeTreeNew();
+for (bi = biList; bi != NULL; bi = bi->next)
+    rangeTreeAddToCoverageDepth(rangeTree, bi->start, bi->end);
+struct range *range, *rangeList = rangeTreeList(rangeTree);
+
+/* Convert rangeList to bbiInterval list. */
+struct bbiInterval *bwi, *bwiList = NULL;
+for (range = rangeList; range != NULL; range = range->next)
+    {
+    lmAllocVar(lm, bwi);
+    bwi->start = range->start;
+    if (bwi->start < start)
+       bwi->start = start;
+    bwi->end = range->end;
+    if (bwi->end > end)
+       bwi->end = end;
+    bwi->val = ptToInt(range->val);
+    slAddHead(&bwiList, bwi);
+    }
+slReverse(&bwiList);
+
+/* Clean up and go home. */
+rangeTreeFree(&rangeTree);
+return bwiList;
+}
+
+boolean bigBedSummaryArrayExtended(struct bbiFile *bbi, char *chrom, bits32 start, bits32 end,
+	int summarySize, struct bbiSummaryElement *summary)
+/* Get extended summary information for summarySize evenly spaced elements into
+ * the summary array. */
+{
+return bbiSummaryArrayExtended(bbi, chrom, start, end, bigBedCoverageIntervals,
+	summarySize, summary);
+}
+
+boolean bigBedSummaryArray(struct bbiFile *bbi, char *chrom, bits32 start, bits32 end,
+	enum bbiSummaryType summaryType, int summarySize, double *summaryValues)
+/* Fill in summaryValues with  data from indicated chromosome range in bigBed file.
+ * Be sure to initialize summaryValues to a default value, which will not be touched
+ * for regions without data in file.  (Generally you want the default value to either
+ * be 0.0 or nan("") depending on the application.)  Returns FALSE if no data
+ * at that position. */
+{
+return bbiSummaryArray(bbi, chrom, start, end, bigBedCoverageIntervals,
+	summaryType, summarySize, summaryValues);
+}
+
+char *bigBedAutoSqlText(struct bbiFile *bbi)
+/* Get autoSql text if any associated with file.  Do a freeMem of this when done. */
+{
+if (bbi->asOffset == 0)
+    return NULL;
+struct udcFile *f = bbi->udc;
+udcSeek(f, bbi->asOffset);
+return udcReadStringAndZero(f);
+}
+
+struct asObject *bigBedAs(struct bbiFile *bbi)
+/* Get autoSql object definition if any associated with file. */
+{
+if (bbi->asOffset == 0)
+    return NULL;
+char *asText = bigBedAutoSqlText(bbi);
+struct asObject *as = asParseText(asText);
+freeMem(asText);
+return as;
+}
+
+struct asObject *bigBedAsOrDefault(struct bbiFile *bbi)
+// Get asObject associated with bigBed - if none exists in file make it up from field counts.
+{
+struct asObject *as = bigBedAs(bbi);
+if (as == NULL)
+    as = asParseText(bedAsDef(bbi->definedFieldCount, bbi->fieldCount));
+return as;
+}
+
+struct asObject *bigBedFileAsObjOrDefault(char *fileName)
+// Get asObject associated with bigBed file, or the default.
+{
+struct bbiFile *bbi = bigBedFileOpen(fileName);
+if (bbi)
+    {
+    struct asObject *as = bigBedAsOrDefault(bbi);
+    bbiFileClose(&bbi);
+    return as;
+    }
+return NULL;
+}
+
+bits64 bigBedItemCount(struct bbiFile *bbi)
+/* Return total items in file. */
+{
+udcSeek(bbi->udc, bbi->unzoomedDataOffset);
+return udcReadBits64(bbi->udc, bbi->isSwapped);
+}
diff --git a/lib/binRange.c b/lib/binRange.c
new file mode 100644
index 0000000..ab7ca60
--- /dev/null
+++ b/lib/binRange.c
@@ -0,0 +1,392 @@
+/* binRange Stuff to handle binning - which helps us restrict 
+ * our attention to the parts of database that contain info
+ * about a particular window on a chromosome. This scheme
+ * will work without modification for chromosome sizes up
+ * to half a gigaBase.  The finest sized bin is 128k (1<<17).
+ * The next coarsest is 8x as big (1<<13).  There's a hierarchy
+ * of bins with the chromosome itself being the final bin.
+ * Features are put in the finest bin they'll fit in. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "binRange.h"
+
+
+/* add one new level to get coverage past chrom sizes of 512 Mb
+ *	effective limit is now the size of an integer since chrom start
+ *	and end coordinates are always being used in int's == 2Gb-1 */
+static int binOffsetsExtended[] =
+	{4096+512+64+8+1, 512+64+8+1, 64+8+1, 8+1, 1, 0};
+
+static int binOffsets[] = {512+64+8+1, 64+8+1, 8+1, 1, 0};
+#define _binFirstShift 17	/* How much to shift to get to finest bin. */
+#define _binNextShift 3		/* How much to shift to get to next larger bin. */
+
+int binLevelsExtended()
+/* Return number of levels to bins. */
+{
+return ArraySize(binOffsetsExtended);
+}
+
+int binLevels()
+/* Return number of levels to bins. */
+{
+return ArraySize(binOffsets);
+}
+
+int binFirstShift()
+/* Return amount to shift a number to get to finest bin. */
+{
+return _binFirstShift;
+}
+
+int binNextShift()
+/* Return amount to shift a number to get to next coarser bin. */
+{
+return _binNextShift;
+}
+
+int binOffsetExtended(int level)
+/* Return offset for bins of a given level. */
+{
+assert(level >= 0 && level < ArraySize(binOffsetsExtended));
+return binOffsetsExtended[level] + _binOffsetOldToExtended;
+}
+
+int binOffset(int level)
+/* Return offset for bins of a given level. */
+{
+assert(level >= 0 && level < ArraySize(binOffsets));
+return binOffsets[level];
+}
+
+static int binFromRangeStandard(int start, int end)
+/* Given start,end in chromosome coordinates assign it
+ * a bin.   There's a bin for each 128k segment, for each
+ * 1M segment, for each 8M segment, for each 64M segment,
+ * and for each chromosome (which is assumed to be less than
+ * 512M.)  A range goes into the smallest bin it will fit in. */
+{
+int startBin = start, endBin = end-1, i;
+startBin >>= _binFirstShift;
+endBin >>= _binFirstShift;
+for (i=0; i<ArraySize(binOffsets); ++i)
+    {
+    if (startBin == endBin)
+        return binOffsets[i] + startBin;
+    startBin >>= _binNextShift;
+    endBin >>= _binNextShift;
+    }
+errAbort("start %d, end %d out of range in findBin (max is 512M)", start, end);
+return 0;
+}
+
+static int binFromRangeExtended(int start, int end)
+/* Given start,end in chromosome coordinates assign it
+ * a bin.   There's a bin for each 128k segment, for each
+ * 1M segment, for each 8M segment, for each 64M segment,
+ * for each 512M segment, and one top level bin for 4Gb.
+ *	Note, since start and end are int's, the practical limit
+ *	is up to 2Gb-1, and thus, only four result bins on the second
+ *	level.
+ * A range goes into the smallest bin it will fit in. */
+{
+int startBin = start, endBin = end-1, i;
+startBin >>= _binFirstShift;
+endBin >>= _binFirstShift;
+for (i=0; i<ArraySize(binOffsetsExtended); ++i)
+    {
+    if (startBin == endBin)
+	return _binOffsetOldToExtended + binOffsetsExtended[i] + startBin;
+    startBin >>= _binNextShift;
+    endBin >>= _binNextShift;
+    }
+errAbort("start %d, end %d out of range in findBin (max is 2Gb)", start, end);
+return 0;
+}
+
+int binFromRange(int start, int end)
+/* return bin that this start-end segment is in */
+{
+if (end <= BINRANGE_MAXEND_512M)
+    return binFromRangeStandard(start, end);
+else
+    return binFromRangeExtended(start, end);
+}
+
+static int binFromRangeBinKeeperExtended(int start, int end)
+/* This is just like binFromRangeExtended() above, but it doesn't limit
+ * the answers to the range from _binOffsetOldToExtended and up.
+ *	It simply uses the whole new bin scheme as if it was the only
+ *	one.
+ */
+{
+int startBin = start, endBin = end-1, i;
+startBin >>= _binFirstShift;
+endBin >>= _binFirstShift;
+for (i=0; i<ArraySize(binOffsetsExtended); ++i)
+    {
+    if (startBin == endBin)
+	return binOffsetsExtended[i] + startBin;
+    startBin >>= _binNextShift;
+    endBin >>= _binNextShift;
+    }
+errAbort("start %d, end %d out of range in findBin (max is 2Gb)", start, end);
+return 0;
+}
+
+struct binKeeper *binKeeperNew(int minPos, int maxPos)
+/* Create new binKeeper that can cover range. */
+{
+int binCount;
+struct binKeeper *bk;
+if (minPos < 0 || maxPos < 0 || minPos > maxPos)
+    errAbort("bad range %d,%d in binKeeperNew", minPos, maxPos);
+
+binCount = binFromRangeBinKeeperExtended(maxPos-1, maxPos) + 1;
+AllocVar(bk);
+bk->minPos = minPos;
+bk->maxPos = maxPos;
+bk->binCount = binCount;
+AllocArray(bk->binLists, binCount);
+return bk;
+}
+
+void binKeeperFree(struct binKeeper **pBk)
+/* Free up a bin keeper. */
+{
+struct binKeeper *bk = *pBk;
+if (bk != NULL)
+    {
+    int i;
+    for (i=0; i<bk->binCount; ++i)
+	slFreeList(&bk->binLists[i]);
+    freeMem(bk->binLists);
+    freez(pBk);
+    }
+}
+
+void binKeeperAdd(struct binKeeper *bk, int start, int end, void *val)
+/* Add item to binKeeper. */ 
+{
+int bin;
+struct binElement *el;
+if (start < bk->minPos || end > bk->maxPos || start > end)
+    errAbort("(%d %d) out of range (%d %d) in binKeeperAdd", 
+    	start, end, bk->minPos, bk->maxPos);
+bin = binFromRangeBinKeeperExtended(start, end);
+assert(bin < bk->binCount);
+AllocVar(el);
+el->start = start;
+el->end = end;
+el->val = val;
+slAddHead(&bk->binLists[bin], el);
+}
+
+int binElementCmpStart(const void *va, const void *vb)
+/* Compare to sort based on start. */
+{
+const struct binElement *a = *((struct binElement **)va);
+const struct binElement *b = *((struct binElement **)vb);
+return a->start - b->start;
+}
+
+struct binElement *binKeeperFind(struct binKeeper *bk, int start, int end)
+/* Return a list of all items in binKeeper that intersect range.
+ * Free this list with slFreeList. */
+{
+struct binElement *list = NULL, *newEl, *el;
+int startBin, endBin;
+int i,j;
+
+if (start < bk->minPos) start = bk->minPos;
+if (end > bk->maxPos) end = bk->maxPos;
+if (start >= end) return NULL;
+startBin = (start>>_binFirstShift);
+endBin = ((end-1)>>_binFirstShift);
+for (i=0; i<ArraySize(binOffsetsExtended); ++i)
+    {
+    int offset = binOffsetsExtended[i];
+    for (j=startBin+offset; j<=endBin+offset; ++j)
+        {
+	for (el=bk->binLists[j]; el != NULL; el = el->next)
+	    {
+	    if (rangeIntersection(el->start, el->end, start, end) > 0)
+	        {
+		newEl = CloneVar(el);
+		slAddHead(&list, newEl);
+		}
+	    }
+	}
+    startBin >>= _binNextShift;
+    endBin >>= _binNextShift;
+    }
+return list;
+}
+
+boolean binKeeperAnyOverlap(struct binKeeper *bk, int start, int end)
+/* Return TRUE if start/end overlaps with any items in binKeeper. */
+{
+struct binElement *el;
+int startBin, endBin;
+int i,j;
+
+if (start < bk->minPos) start = bk->minPos;
+if (end > bk->maxPos) end = bk->maxPos;
+if (start >= end) return FALSE;
+startBin = (start>>_binFirstShift);
+endBin = ((end-1)>>_binFirstShift);
+for (i=0; i<ArraySize(binOffsetsExtended); ++i)
+    {
+    int offset = binOffsetsExtended[i];
+    for (j=startBin+offset; j<=endBin+offset; ++j)
+        {
+	for (el=bk->binLists[j]; el != NULL; el = el->next)
+	    {
+	    if (rangeIntersection(el->start, el->end, start, end) > 0)
+	        {
+		return TRUE;
+		}
+	    }
+	}
+    startBin >>= _binNextShift;
+    endBin >>= _binNextShift;
+    }
+return FALSE;
+}
+
+void binKeeperReplaceVal(struct binKeeper *bk, int start, int end,
+	void *oldVal, void *newVal)
+/* Replace occurences of old val in range from start->end with newVal */
+{
+struct binElement *el;
+int startBin, endBin;
+int i,j;
+
+if (start < bk->minPos) start = bk->minPos;
+if (end > bk->maxPos) end = bk->maxPos;
+if (start >= end) return;
+startBin = (start>>_binFirstShift);
+endBin = ((end-1)>>_binFirstShift);
+for (i=0; i<ArraySize(binOffsetsExtended); ++i)
+    {
+    int offset = binOffsetsExtended[i];
+    for (j=startBin+offset; j<=endBin+offset; ++j)
+        {
+	for (el=bk->binLists[j]; el != NULL; el = el->next)
+	    {
+	    if (rangeIntersection(el->start, el->end, start, end) > 0)
+	        {
+		if (el->val == oldVal)
+		    {
+		    el->val = newVal;
+		    }
+		}
+	    }
+	}
+    startBin >>= _binNextShift;
+    endBin >>= _binNextShift;
+    }
+}
+
+
+struct binElement *binKeeperFindSorted(struct binKeeper *bk, int start, int end)
+/* Like binKeeperFind, but sort list on start coordinates. */
+{
+struct binElement *list = binKeeperFind(bk, start, end);
+slSort(&list, binElementCmpStart);
+return list;
+}
+
+struct binElement *binKeeperFindAll(struct binKeeper *bk)
+/* Get all elements sorted. */
+{
+return binKeeperFindSorted(bk, bk->minPos, bk->maxPos);
+}
+
+struct binElement *binKeeperFindLowest(struct binKeeper *bk, int start, int end)
+/* Find the lowest overlapping range. Quick even if search range large */
+{
+struct binElement *first = NULL, *el;
+int startBin = (start>>_binFirstShift), endBin = ((end-1)>>_binFirstShift);
+int i,j;
+
+/* Search the possible range of bins at each level, looking for lowest.  Once
+ * an overlaping range is found at a level, continue with next level, however
+ * must search an entire bin as they are not ordered. */
+for (i=0; i<ArraySize(binOffsetsExtended); ++i)
+    {
+    int offset = binOffsetsExtended[i];
+    boolean foundOne = FALSE;
+    for (j=startBin+offset; (j<=endBin+offset) && (!foundOne); ++j)
+        {
+	for (el=bk->binLists[j]; el != NULL; el = el->next)
+	    {
+            if ((rangeIntersection(el->start, el->end, start, end) > 0)
+                && ((first == NULL) || (el->start < first->start)
+                    || ((el->start == first->start)
+                        && (el->end < first->end))))
+                {
+                first = el;
+                foundOne = TRUE;
+		}
+	    }
+	}
+    startBin >>= _binNextShift;
+    endBin >>= _binNextShift;
+    }
+return first;
+}
+
+
+void binKeeperRemove(struct binKeeper *bk, int start, int end, void *val)
+/* Remove item from binKeeper. */ 
+{
+int bin = binFromRangeBinKeeperExtended(start, end);
+struct binElement **pList = &bk->binLists[bin], *newList = NULL, *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    if (el->val == val && el->start == start && el->end == end)
+        {
+	freeMem(el);
+	}
+    else
+        {
+	slAddHead(&newList, el);
+	}
+    }
+slReverse(&newList);
+*pList = newList;
+}
+
+struct binKeeperCookie binKeeperFirst(struct binKeeper *bk)
+/* Return an object to use by binKeeperNext() to traverse the binElements.
+ * The first call to binKeeperNext() will return the first entry in the
+ * table. */
+{
+struct binKeeperCookie cookie;
+cookie.bk = bk;
+cookie.blIdx = 0;
+cookie.nextBel = bk->binLists[0];
+return cookie;
+}
+
+struct binElement* binKeeperNext(struct binKeeperCookie *cookie)
+/* Return the next entry in the binKeeper table.  */
+{
+/* if we don't have a next, move down bin list until we find one */
+while ((cookie->nextBel == NULL)
+       && (++cookie->blIdx < cookie->bk->binCount))
+    cookie->nextBel = cookie->bk->binLists[cookie->blIdx];
+if (cookie->blIdx >= cookie->bk->binCount)
+    return NULL;  /* no more */
+else
+    {
+    struct binElement* bel = cookie->nextBel;
+    cookie->nextBel = cookie->nextBel->next;
+    return bel;
+    }
+}
diff --git a/lib/bits.c b/lib/bits.c
new file mode 100644
index 0000000..9695ead
--- /dev/null
+++ b/lib/bits.c
@@ -0,0 +1,280 @@
+/* bits - handle operations on arrays of bits. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "bits.h"
+
+
+
+static Bits oneBit[8] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};
+static Bits leftMask[8] = {0xFF, 0x7F, 0x3F, 0x1F,  0xF,  0x7,  0x3,  0x1,};
+static Bits rightMask[8] = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF,};
+int bitsInByte[256];
+
+static boolean inittedBitsInByte = FALSE;
+
+void bitsInByteInit()
+/* Initialize bitsInByte array. */
+{
+int i;
+
+if (!inittedBitsInByte)
+    {
+    inittedBitsInByte = TRUE;
+    for (i=0; i<256; ++i)
+        {
+	int count = 0;
+	if (i&1)
+	    count = 1;
+	if (i&2)
+	    ++count;
+	if (i&4)
+	    ++count;
+	if (i&8)
+	    ++count;
+	if (i&0x10)
+	    ++count;
+	if (i&0x20)
+	    ++count;
+	if (i&0x40)
+	    ++count;
+	if (i&0x80)
+	    ++count;
+	bitsInByte[i] = count;
+	}
+    }
+}
+
+Bits *bitAlloc(int bitCount)
+/* Allocate bits. */
+{
+int byteCount = ((bitCount+7)>>3);
+return needLargeZeroedMem(byteCount);
+}
+
+Bits *bitRealloc(Bits *b, int bitCount, int newBitCount)
+/* Resize a bit array.  If b is null, allocate a new array */
+{
+int byteCount = ((bitCount+7)>>3);
+int newByteCount = ((newBitCount+7)>>3);
+return needLargeZeroedMemResize(b, byteCount, newByteCount);
+}
+
+Bits *bitClone(Bits* orig, int bitCount)
+/* Clone bits. */
+{
+int byteCount = ((bitCount+7)>>3);
+Bits* bits = needLargeZeroedMem(byteCount);
+memcpy(bits, orig, byteCount);
+return bits;
+}
+
+void bitFree(Bits **pB)
+/* Free bits. */
+{
+freez(pB);
+}
+
+void bitSetOne(Bits *b, int bitIx)
+/* Set a single bit. */
+{
+b[bitIx>>3] |= oneBit[bitIx&7];
+}
+
+void bitClearOne(Bits *b, int bitIx)
+/* Clear a single bit. */
+{
+b[bitIx>>3] &= ~oneBit[bitIx&7];
+}
+
+void bitSetRange(Bits *b, int startIx, int bitCount)
+/* Set a range of bits. */
+{
+if (bitCount <= 0)
+    return;
+int endIx = (startIx + bitCount - 1);
+int startByte = (startIx>>3);
+int endByte = (endIx>>3);
+int startBits = (startIx&7);
+int endBits = (endIx&7);
+int i;
+
+if (startByte == endByte)
+    {
+    b[startByte] |= (leftMask[startBits] & rightMask[endBits]);
+    return;
+    }
+b[startByte] |= leftMask[startBits];
+for (i = startByte+1; i<endByte; ++i)
+    b[i] = 0xff;
+b[endByte] |= rightMask[endBits];
+}
+
+
+boolean bitReadOne(Bits *b, int bitIx)
+/* Read a single bit. */
+{
+return (b[bitIx>>3] & oneBit[bitIx&7]) != 0;
+}
+
+int bitCountRange(Bits *b, int startIx, int bitCount)
+/* Count number of bits set in range. */
+{
+if (bitCount <= 0)
+    return 0;
+int endIx = (startIx + bitCount - 1);
+int startByte = (startIx>>3);
+int endByte = (endIx>>3);
+int startBits = (startIx&7);
+int endBits = (endIx&7);
+int i;
+int count = 0;
+
+if (!inittedBitsInByte)
+    bitsInByteInit();
+if (startByte == endByte)
+    return bitsInByte[b[startByte] & leftMask[startBits] & rightMask[endBits]];
+count = bitsInByte[b[startByte] & leftMask[startBits]];
+for (i = startByte+1; i<endByte; ++i)
+    count += bitsInByte[b[i]];
+count += bitsInByte[b[endByte] & rightMask[endBits]];
+return count;
+}
+
+int bitFind(Bits *b, int startIx, boolean val, int bitCount)
+/* Find the index of the the next set bit. */
+{
+unsigned char notByteVal = val ? 0 : 0xff;
+int iBit = startIx;
+int endByte = ((bitCount-1)>>3);
+int iByte;
+
+/* scan initial byte */
+while (((iBit & 7) != 0) && (iBit < bitCount))
+    {
+    if (bitReadOne(b, iBit) == val)
+        return iBit;
+    iBit++;
+    }
+
+/* scan byte at a time, if not already in last byte */
+iByte = (iBit >> 3);
+if (iByte < endByte)
+    {
+    while ((iByte < endByte) && (b[iByte] == notByteVal))
+        iByte++;
+    iBit = iByte << 3;
+    }
+
+/* scan last byte */
+while (iBit < bitCount)
+    {
+    if (bitReadOne(b, iBit) == val)
+        return iBit;
+    iBit++;
+    }
+ return bitCount;  /* not found */
+}
+
+int bitFindSet(Bits *b, int startIx, int bitCount)
+/* Find the index of the the next set bit. */
+{
+return bitFind(b, startIx, TRUE, bitCount);
+}
+
+int bitFindClear(Bits *b, int startIx, int bitCount)
+/* Find the index of the the next clear bit. */
+{
+return bitFind(b, startIx, FALSE, bitCount);
+}
+
+void bitClear(Bits *b, int bitCount)
+/* Clear many bits (possibly up to 7 beyond bitCount). */
+{
+int byteCount = ((bitCount+7)>>3);
+zeroBytes(b, byteCount);
+}
+
+void bitClearRange(Bits *b, int startIx, int bitCount)
+/* Clear a range of bits. */
+{
+if (bitCount <= 0)
+    return;
+int endIx = (startIx + bitCount - 1);
+int startByte = (startIx>>3);
+int endByte = (endIx>>3);
+int startBits = (startIx&7);
+int endBits = (endIx&7);
+int i;
+
+if (startByte == endByte)
+    {
+    b[startByte] &= ~(leftMask[startBits] & rightMask[endBits]);
+    return;
+    }
+b[startByte] &= ~leftMask[startBits];
+for (i = startByte+1; i<endByte; ++i)
+    b[i] = 0x00;
+b[endByte] &= ~rightMask[endBits];
+}
+
+void bitAnd(Bits *a, Bits *b, int bitCount)
+/* And two bitmaps.  Put result in a. */
+{
+int byteCount = ((bitCount+7)>>3);
+while (--byteCount >= 0)
+    {
+    *a = (*a & *b++);
+    a++;
+    }
+}
+
+void bitOr(Bits *a, Bits *b, int bitCount)
+/* Or two bitmaps.  Put result in a. */
+{
+int byteCount = ((bitCount+7)>>3);
+while (--byteCount >= 0)
+    {
+    *a = (*a | *b++);
+    a++;
+    }
+}
+
+void bitXor(Bits *a, Bits *b, int bitCount)
+{
+int byteCount = ((bitCount+7)>>3);
+while (--byteCount >= 0)
+    {
+    *a = (*a ^ *b++);
+    a++;
+    }
+}
+
+void bitNot(Bits *a, int bitCount)
+/* Flip all bits in a. */
+{
+int byteCount = ((bitCount+7)>>3);
+while (--byteCount >= 0)
+    {
+    *a = ~*a;
+    a++;
+    }
+}
+
+void bitPrint(Bits *a, int startIx, int bitCount, FILE* out)
+/* Print part or all of bit map as a string of 0s and 1s.  Mostly useful for
+ * debugging */
+{
+int i;
+for (i = startIx; i < bitCount; i++)
+    {
+    if (bitReadOne(a, i))
+        fputc('1', out);
+    else
+        fputc('0', out);
+    }
+fputc('\n', out);
+}
+
diff --git a/lib/blastOut.c b/lib/blastOut.c
new file mode 100644
index 0000000..042a3f0
--- /dev/null
+++ b/lib/blastOut.c
@@ -0,0 +1,830 @@
+/* blastOut.c - stuff to output an alignment in blast format. */
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "axt.h"
+#include "obscure.h"
+#include "genoFind.h"
+
+
+struct axtRef
+/* A reference to an axt. */
+    {
+    struct axtRef *next;
+    struct axt *axt;
+    };
+
+static int axtRefCmpScore(const void *va, const void *vb)
+/* Compare to sort based on score. */
+{
+const struct axtRef *a = *((struct axtRef **)va);
+const struct axtRef *b = *((struct axtRef **)vb);
+return b->axt->score - a->axt->score;
+}
+
+struct targetHits
+/* Collection of hits to a single target. */
+    {
+    struct targetHits *next;
+    char *name;	    	    /* Target name */
+    int size;		    /* Target size */
+    struct axtRef *axtList; /* List of axts, sorted by score. */
+    int score;		    /* Score of best element */
+    };
+
+static void targetHitsFree(struct targetHits **pObj)
+/* Free one target hits structure. */
+{
+struct targetHits *obj = *pObj;
+if (obj != NULL)
+    {
+    freeMem(obj->name);
+    slFreeList(&obj->axtList);
+    freez(pObj);
+    }
+}
+
+static void targetHitsFreeList(struct targetHits **pList)
+/* Free a list of dynamically allocated targetHits's */
+{
+struct targetHits *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    targetHitsFree(&el);
+    }
+*pList = NULL;
+}
+
+
+static int targetHitsCmpScore(const void *va, const void *vb)
+/* Compare to sort based on score. */
+{
+const struct targetHits *a = *((struct targetHits **)va);
+const struct targetHits *b = *((struct targetHits **)vb);
+
+return b->score - a->score;
+}
+
+static int blastzToWublastScore(int bzScore)
+/* Convert from 100 points/match blastz score to 5 points/match
+ * wu-blast score. */
+{
+return bzScore/19;
+}
+
+static double blastzScoreToWuBits(int bzScore, boolean isProt)
+/* Convert from blastz score to bit score.  The magic number's
+ * here are taken from comparing wu-blast scores to axtScores on
+ * a couple of sequences.  This doesn't really seem to be a bit
+ * score.  It's not very close to 2 bits per base. */
+{
+int wuScore = blastzToWublastScore(bzScore);
+if (isProt)
+    return wuScore * 0.3545;
+else
+    return wuScore * 0.1553;
+}
+
+static double blastzScoreToWuExpectation(int bzScore, double databaseSize)
+/* I'm puzzled by the wu-blast expectation score.  I would
+ * think it would be  databaseSize / (2^bitScore)  but
+ * it's not.   I think the best I can do is approximate
+ * it with something scaled to be close to this expectation. */
+{
+double logProbOne = -log(2) * bzScore / 32.1948;
+return databaseSize * exp(logProbOne);
+}
+
+static int blastzScoreToNcbiBits(int bzScore)
+/* Convert blastz score to bit score in NCBI sense. */
+{
+return round(bzScore * 0.0205);
+}
+
+static int blastzScoreToNcbiScore(int bzScore)
+/* Conver blastz score to NCBI matrix score. */
+{
+return round(bzScore * 0.0529);
+}
+
+static double blastzScoreToNcbiExpectation(int bzScore)
+/* Convert blastz score to expectation in NCBI sense. */
+{
+double bits = bzScore * 0.0205;
+double logProb = -bits*log(2);
+return 3.0e9 * exp(logProb);
+}
+
+static double expectationToProbability(double e)
+/* Convert expected number of hits to probability of at least
+ * one hit.  This is a crude approximation, but actually pretty precise
+ * for e < 0.1, which is all that really matters.... */
+{
+if (e < 0.999)
+    return e;
+else
+    return 0.999;
+}
+
+static int countMatches(char *a, char *b, int size)
+/* Count number of characters that match between a and b. */
+{
+int count = 0;
+int i;
+for (i=0; i<size; ++i)
+    if (toupper(a[i]) == toupper(b[i]))
+        ++count;
+return count;
+}
+
+static int countGaps(char *a, char *b, int size)
+/* Count number of inserts in either strand. */
+{
+int count = 0;
+int i;
+for (i=0; i<size; ++i)
+   {
+   if (a[i] == '-')
+       ++count;
+   if (b[i] == '-')
+       ++count;
+   }
+return count;
+}
+
+static int countGapOpens(char *a, char *b, int size)
+/* Count number of inserts in either strand. */
+{
+int i, count = 0;
+boolean inGap = FALSE;
+for (i=0; i<size; ++i)
+    {
+    if (a[i] == '-' || b[i] == '-')
+        {
+	if (!inGap)
+	    {
+	    ++count;
+	    inGap = TRUE;
+	    }
+	}
+    else
+        {
+	inGap = FALSE;
+	}
+    }
+return count;
+}
+
+
+static int countPositives(char *a, char *b, int size)
+/* Count positive (not necessarily identical) protein matches. */
+{
+int count = 0;
+int i;
+struct axtScoreScheme *ss = axtScoreSchemeProteinDefault();
+for (i=0; i<size; ++i)
+    {
+    if (ss->matrix[(int)a[i]][(int)b[i]] > 0)
+        ++count;
+    }
+return count;
+}
+
+static int plusStrandPos(int pos, int size, char strand, boolean isEnd)
+/* Return position on plus strand, one based. */
+{
+if (strand == '-')
+    {
+    pos = size - pos;
+    if (isEnd)
+       ++pos;
+    }
+else
+    {
+    if (!isEnd)
+        ++pos;
+    }
+return pos;
+}
+
+static int calcDigitCount(struct axt *axt, int tSize, int qSize)
+/* Figure out how many digits needed for blast position display. */
+{
+int tDig, qDig;
+if (axt->qStrand == '-')
+    qDig = digitsBaseTen(qSize - axt->qStart + 1);
+else
+    qDig = digitsBaseTen(axt->qEnd);
+if (axt->tStrand == '-')
+    tDig = digitsBaseTen(tSize - axt->tStart + 1);
+else
+    tDig = digitsBaseTen(axt->tEnd);
+return max(tDig, qDig);
+}
+
+static void blastiodAxtOutput(FILE *f, struct axt *axt, int tSize, int qSize, 
+	int lineSize, boolean isProt, boolean isTranslated)
+/* Output base-by-base part of alignment in blast-like fashion. */
+{
+int tOff = axt->tStart;
+int dt = (isTranslated ? 3 : 1);
+int qOff = axt->qStart;
+int lineStart, lineEnd, i;
+int digits = calcDigitCount(axt, tSize, qSize);
+struct axtScoreScheme *ss = NULL;
+
+if (isProt)
+    ss = axtScoreSchemeProteinDefault();
+for (lineStart = 0; lineStart < axt->symCount; lineStart = lineEnd)
+    {
+    lineEnd = lineStart + lineSize;
+    if (lineEnd > axt->symCount) lineEnd = axt->symCount;
+    fprintf(f, "Query: %-*d ", digits, plusStrandPos(qOff, qSize, axt->qStrand, FALSE));
+    for (i=lineStart; i<lineEnd; ++i)
+	{
+	char c = axt->qSym[i];
+	fputc(c, f);
+	if (c != '-')
+	    ++qOff;
+	}
+    fprintf(f, " %-d\n", plusStrandPos(qOff, qSize, axt->qStrand, TRUE));
+    fprintf(f, "       %*s ", digits, " ");
+    for (i=lineStart; i<lineEnd; ++i)
+        {
+	char q, t, c;
+	q = axt->qSym[i];
+	t = axt->tSym[i];
+	if (isProt)
+	    {
+	    if (q == t)
+	        c = q;
+	    else if (ss->matrix[(int)q][(int)t] > 0)
+	        c = '+';
+	    else
+	        c = ' ';
+	    }
+	else
+	    c = ((toupper(q) == toupper(t)) ? '|' : ' ');
+
+	fputc(c, f);
+	}
+    fprintf(f, "\n");
+    fprintf(f, "Sbjct: %-*d ", digits, plusStrandPos(tOff, tSize, axt->tStrand, FALSE));
+    for (i=lineStart; i<lineEnd; ++i)
+	{
+	char c = axt->tSym[i];
+	fputc(c, f);
+	if (c != '-')
+	    tOff += dt;
+	}
+    fprintf(f, " %-d\n", plusStrandPos(tOff, tSize, axt->tStrand, TRUE));
+    fprintf(f, "\n");
+    }
+}
+
+static struct targetHits *bundleIntoTargets(struct axtBundle *abList)
+/* BLAST typically outputs everything on the same query and target
+ * in one clump.  This routine rearranges axts in abList to do this. */
+{
+struct targetHits *targetList = NULL, *target;
+struct hash *targetHash = newHash(10);
+struct axtBundle *ab;
+struct axtRef *ref;
+
+/* Build up a list of targets in database hit by query sorted by
+ * score of hits. */
+for (ab = abList; ab != NULL; ab = ab->next)
+    {
+    struct axt *axt;
+    for (axt = ab->axtList; axt != NULL; axt = axt->next)
+	{
+	target = hashFindVal(targetHash, axt->tName);
+	if (target == NULL)
+	    {
+	    AllocVar(target);
+	    slAddHead(&targetList, target);
+	    hashAdd(targetHash, axt->tName, target);
+	    target->name = cloneString(axt->tName);
+	    target->size = ab->tSize;
+	    }
+	if (axt->score > target->score)
+	    target->score = axt->score;
+	AllocVar(ref);
+	ref->axt = axt;
+	slAddHead(&target->axtList, ref);
+	}
+    }
+slSort(&targetList, targetHitsCmpScore);
+for (target = targetList; target != NULL; target = target->next)
+    slSort(&target->axtList, axtRefCmpScore);
+
+hashFree(&targetHash);
+return targetList;
+}
+
+static char *nameForStrand(char strand)
+/* Return Plus/Minus for +/- */
+{
+if (strand == '-')
+    return "Minus";
+else
+    return "Plus";
+}
+
+static char *progType(boolean isProt, struct axtBundle *ab, boolean isUpper)
+/* Return blast 'program' */
+{
+if (!isProt)
+    return isUpper ? "BLASTN" : "blastn";
+else
+    {
+    if (ab->axtList->frame != 0)
+        return isUpper ? "TBLASTN" : "tblastn";
+    else
+        return isUpper ? "BLASTP" : "blastp";
+    }
+}
+
+static void wuBlastOut(struct axtBundle *abList, int queryIx, boolean isProt, 
+	FILE *f, 
+	char *databaseName, int databaseSeqCount, double databaseLetterCount, 
+	char *ourId)
+/* Do wublast-like output at end of processing query. */
+{
+char asciiNum[32];
+struct targetHits *targetList = NULL, *target;
+char *queryName;
+int isRc;
+int querySize = abList->qSize;
+boolean isTranslated = (abList->axtList->frame != 0);
+
+/* Print out stuff that doesn't depend on query or database. */
+if (ourId == NULL)
+    ourId = "axtBlastOut";
+fprintf(f, "%s 2.0MP-WashU [%s]\n", progType(isProt, abList, TRUE), ourId);
+fprintf(f, "\n");
+fprintf(f, "Copyright (C) 2000-2002 Jim Kent\n");
+fprintf(f, "All Rights Reserved\n");
+fprintf(f, "\n");
+fprintf(f, "Reference:  Kent, WJ. (2002) BLAT - The BLAST-like alignment tool\n");
+fprintf(f, "\n");
+if (!isProt)
+    {
+    fprintf(f, "Notice:  this program and its default parameter settings are optimized to find\n");
+    fprintf(f, "nearly identical sequences very rapidly.  For slower but more sensitive\n");
+    fprintf(f, "alignments please use other methods.\n");
+    fprintf(f, "\n");
+    }
+
+/* Print query and database info. */
+queryName = abList->axtList->qName;
+fprintf(f, "Query=  %s\n", queryName);
+fprintf(f, "        (%d letters; record %d)\n", abList->qSize, queryIx);
+fprintf(f, "\n");
+fprintf(f, "Database:  %s\n",  databaseName);
+sprintLongWithCommas(asciiNum, databaseLetterCount);
+fprintf(f, "           %d sequences; %s total letters\n",  databaseSeqCount, asciiNum);
+fprintf(f, "Searching....10....20....30....40....50....60....70....80....90....100%% done\n");
+fprintf(f, "\n");
+
+targetList = bundleIntoTargets(abList);
+
+/* Print out summary of hits. */
+fprintf(f, "                                                                     Smallest\n");
+fprintf(f, "                                                                       Sum\n");
+fprintf(f, "                                                              High  Probability\n");
+fprintf(f, "Sequences producing High-scoring Segment Pairs:              Score  P(N)      N\n");
+fprintf(f, "\n");
+for (target = targetList; target != NULL; target = target->next)
+    {
+    double expectation = blastzScoreToWuExpectation(target->score, databaseLetterCount);
+    double p = expectationToProbability(expectation);
+    fprintf(f, "%-61s %4d  %8.1e %2d\n", target->name, 
+    	blastzToWublastScore(target->score), p, slCount(target->axtList));
+    }
+
+/* Print out details on each target. */
+for (target = targetList; target != NULL; target = target->next)
+    {
+    fprintf(f, "\n\n>%s\n", target->name);
+    fprintf(f, "        Length = %d\n", target->size);
+    fprintf(f, "\n");
+    for (isRc=0; isRc <= 1; ++isRc)
+	{
+	boolean saidStrand = FALSE;
+	char strand = (isRc ? '-' : '+');
+	char *strandName = nameForStrand(strand);
+	struct axtRef *ref;
+	struct axt *axt;
+	for (ref = target->axtList; ref != NULL; ref = ref->next)
+	    {
+	    axt = ref->axt;
+	    if (axt->qStrand == strand)
+		{
+		int matches = countMatches(axt->qSym, axt->tSym, axt->symCount);
+		int positives = countPositives(axt->qSym, axt->tSym, axt->symCount);
+		if (!saidStrand)
+		    {
+		    saidStrand = TRUE;
+		    if (!isProt)
+			fprintf(f, "  %s Strand HSPs:\n\n", strandName);
+		    }
+		fprintf(f, " Score = %d (%2.1f bits), Expect = %5.1e, P = %5.1e\n",
+		     blastzToWublastScore(axt->score), 
+		     blastzScoreToWuBits(axt->score, isProt),
+		     blastzScoreToWuExpectation(axt->score, databaseLetterCount),
+		     blastzScoreToWuExpectation(axt->score, databaseLetterCount));
+		fprintf(f, " Identities = %d/%d (%d%%), Positives = %d/%d (%d%%)",
+		     matches, axt->symCount, round(100.0 * matches / axt->symCount),
+		     positives, axt->symCount, round(100.0 * positives / axt->symCount));
+		if (isProt)
+		    {
+		    if (axt->frame != 0)
+		        fprintf(f, ", Frame = %c%d", axt->tStrand, axt->frame);
+		    fprintf(f, "\n");
+		    }
+		else
+		    fprintf(f, ", Strand = %s / Plus\n", strandName);
+		fprintf(f, "\n");
+		blastiodAxtOutput(f, axt, target->size, querySize, 60, isProt, isTranslated);
+		}
+	    }
+	}
+    }
+
+/* Cleanup time. */
+targetHitsFreeList(&targetList);
+}
+
+static void ncbiPrintE(FILE *f, double e)
+/* Print a small number NCBI style. */
+{
+if (e <= 0.0)
+    fprintf(f, "0.0");
+else if (e <= 1.0e-100)
+    {
+    char buf[256], *s;
+    safef(buf, sizeof(buf), "%e", e);
+    s = strchr(buf, 'e');
+    if (s == NULL)
+	fprintf(f, "0.0");
+    else
+        fprintf(f, "%s", s);
+    }
+else
+    fprintf(f, "%1.0e", e);
+}
+
+/* special global variable needed for Known Genes track building.  Fan 1/21/03 */
+int answer_for_kg;
+static void ncbiBlastOut(struct axtBundle *abList, int queryIx, boolean isProt, 
+	FILE *f, char *databaseName, int databaseSeqCount, 
+	double databaseLetterCount, char *ourId, double minIdentity)
+/* Do ncbiblast-like output at end of processing query. */
+{
+char asciiNum[32];
+struct targetHits *targetList = NULL, *target;
+char *queryName;
+int querySize = abList->qSize;
+boolean isTranslated = (abList->axtList->frame != 0);
+
+/* Print out stuff that doesn't depend on query or database. */
+if (ourId == NULL)
+    ourId = "axtBlastOut";
+fprintf(f, "%s 2.2.11 [%s]\n", progType(isProt, abList, TRUE), ourId);
+fprintf(f, "\n");
+fprintf(f, "Reference:  Kent, WJ. (2002) BLAT - The BLAST-like alignment tool\n");
+fprintf(f, "\n");
+
+/* Print query and database info. */
+queryName = abList->axtList->qName;
+fprintf(f, "Query= %s\n", queryName);
+fprintf(f, "         (%d letters)\n", abList->qSize);
+fprintf(f, "\n");
+fprintf(f, "Database: %s \n",  databaseName);
+sprintLongWithCommas(asciiNum, databaseLetterCount);
+fprintf(f, "           %d sequences; %s total letters\n",  databaseSeqCount, asciiNum);
+fprintf(f, "\n");
+fprintf(f, "Searching.done\n");
+
+targetList = bundleIntoTargets(abList);
+
+/* Print out summary of hits. */
+fprintf(f, "                                                                 Score    E\n");
+fprintf(f, "Sequences producing significant alignments:                      (bits) Value\n");
+fprintf(f, "\n");
+for (target = targetList; target != NULL; target = target->next)
+    {
+    struct axtRef *ref;
+    struct axt *axt;
+    int matches;
+    double identity, expectation;
+    int bit;
+    
+    for (ref = target->axtList; ref != NULL; ref = ref->next)
+	{
+	axt = ref->axt;
+	
+	matches = countMatches(axt->qSym, axt->tSym, axt->symCount);
+	identity = round(100.0 * matches / axt->symCount);
+	/* skip output if minIdentity not reached */
+	if (identity < minIdentity) continue;
+    
+    	bit = blastzScoreToNcbiBits(axt->score);
+        expectation = blastzScoreToNcbiExpectation(axt->score);
+    	fprintf(f, "%-67s  %4d   ", target->name, bit);
+    	ncbiPrintE(f, expectation);
+    	fprintf(f, "\n");
+    	}
+    }
+fprintf(f, "\n");
+
+/* Print out details on each target. */
+for (target = targetList; target != NULL; target = target->next)
+    {
+    struct axtRef *ref;
+    struct axt *axt;
+    int matches, gaps;
+    char *oldName;
+    
+    int ii = 0;
+    double identity;
+    oldName = strdup("");
+
+    for (ref = target->axtList; ref != NULL; ref = ref->next)
+	{
+	ii++;
+	axt = ref->axt;
+	
+	matches = countMatches(axt->qSym, axt->tSym, axt->symCount);
+	identity = round(100.0 * matches / axt->symCount);
+	
+	/* skip output if minIdentity not reached */
+	if (identity < minIdentity) continue;
+        
+	/* print target sequence name and length only once */ 
+	if (!sameWord(oldName, target->name))
+	    {
+	    fprintf(f, "\n\n>%s \n", target->name);
+	    fprintf(f, "          Length = %d\n", target->size);
+	    oldName = strdup(target->name);
+	    }
+
+	fprintf(f, "\n");
+	fprintf(f, " Score = %d bits (%d), Expect = ",
+	     blastzScoreToNcbiBits(axt->score),
+	     blastzScoreToNcbiScore(axt->score));
+	ncbiPrintE(f, blastzScoreToNcbiExpectation(axt->score));
+	fprintf(f, "\n");
+	
+	if (isProt)
+	    {
+	    int positives = countPositives(axt->qSym, axt->tSym, axt->symCount);
+	    gaps = countGaps(axt->qSym, axt->tSym, axt->symCount);
+	    fprintf(f, " Identities = %d/%d (%d%%),",
+		 matches, axt->symCount, round(100.0 * matches / axt->symCount));
+	    fprintf(f, " Positives = %d/%d (%d%%),",
+		 positives, axt->symCount, round(100.0 * positives / axt->symCount));
+	    fprintf(f, " Gaps = %d/%d (%d%%)\n",
+		 gaps, axt->symCount, round(100.0 * gaps / axt->symCount));
+	    if (axt->frame != 0) 
+		fprintf(f, " Frame = %c%d\n", axt->tStrand, axt->frame);
+	    /* set the special global variable, answer_for_kg.  
+   	       This is needed for Known Genes track building.  Fan 1/21/03 */
+            answer_for_kg=axt->symCount - matches;
+	    }
+	else
+	    {
+	    fprintf(f, " Identities = %d/%d (%d%%)\n",
+		 matches, axt->symCount, round(100.0 * matches / axt->symCount));
+	    /* blast displays dna searches as +- instead of blat's default -+ */
+	    if (!isTranslated)
+		if ((axt->qStrand == '-') && (axt->tStrand == '+'))
+		    {
+		    reverseIntRange(&axt->qStart, &axt->qEnd, querySize);
+		    reverseIntRange(&axt->tStart, &axt->tEnd, target->size);
+		    reverseComplement(axt->qSym, axt->symCount);
+		    reverseComplement(axt->tSym, axt->symCount);
+		    axt->qStrand = '+';
+		    axt->tStrand = '-';
+		    }
+	    fprintf(f, " Strand = %s / %s\n", nameForStrand(axt->qStrand),
+		nameForStrand(axt->tStrand));
+	    }
+	fprintf(f, "\n");
+	blastiodAxtOutput(f, axt, target->size, querySize, 60, isProt, isTranslated);
+	}
+    }
+
+fprintf(f, "  Database: %s\n", databaseName);
+
+/* Cleanup time. */
+targetHitsFreeList(&targetList);
+}
+
+static void xmlBlastOut(struct axtBundle *abList, int queryIx, boolean isProt, 
+	FILE *f, char *databaseName, int databaseSeqCount, 
+	double databaseLetterCount, char *ourId)
+/* Do ncbi blast xml-like output at end of processing query. 
+ * WARNING - still not completely baked.  Format at NCBI seems
+ * to be missing some end tags actually when I checked. -jk */
+{
+char *queryName = abList->axtList->qName;
+int querySize = abList->qSize;
+int hitNum = 0;
+struct targetHits *targetList = NULL, *target;
+
+if (ourId == NULL)
+    ourId = "axtBlastOut";
+fprintf(f, "<?xml version=\"1.0\"?>\n");
+fprintf(f, "<!DOCTYPE BlastOutput PUBLIC \"-//NCBI//NCBI BlastOutput/EN\" \"NCBI_BlastOutput.dtd\">\n");
+fprintf(f, "<BlastOutput>\n");
+fprintf(f, "  <BlastOutput_program>%s</BlastOutput_program>\n", 
+	progType(isProt, abList, FALSE));
+fprintf(f, "  <BlastOutput_version>%s 2.2.4 [%s]</BlastOutput_version>\n",
+	progType(isProt, abList, FALSE), ourId);
+fprintf(f, "  <BlastOutput_reference>~Reference: Kent, WJ. (2002) BLAT - The BLAST-like alignment tool</BlastOutput_reference>\n");
+fprintf(f, "  <BlastOutput_db>%s</BlastOutput_db>\n", databaseName);
+fprintf(f, "  <BlastOutput_query-ID>%d</BlastOutput_query-ID>\n", queryIx);
+fprintf(f, "  <BlastOutput_query-def>%s</BlastOutput_query-def>\n", queryName);
+fprintf(f, "  <BlastOutput_query-len>%d</BlastOutput_query-len>\n", querySize);
+
+if (isProt)
+    {
+    fprintf(f, "  <BlastOutput_param>\n");
+    fprintf(f, "    <Parameters_matrix>BLOSUM62</Parameters_matrix>\n");
+    fprintf(f, "    <Parameters_expect>0.001</Parameters_expect>\n");
+    fprintf(f, "    <Parameters_expect>10</Parameters_expect>\n");
+    fprintf(f, "    <Parameters_gap-extend>1</Parameters_gap-extend>\n");
+    fprintf(f, "  </BlastOutput_param>\n");
+    }
+
+fprintf(f, "  <BlastOutput_iterations>\n");
+fprintf(f, "    <Iteration>\n");
+fprintf(f, "      <Iteration_iter-num>1</Iteration_iter-num>\n");
+fprintf(f, "      <Iteration_hits>\n");
+
+/* Print out details on each target. */
+targetList = bundleIntoTargets(abList);
+for (target = targetList; target != NULL; target = target->next)
+    {
+    struct axtRef *ref;
+    fprintf(f, "      <hit>\n");
+    fprintf(f, "        <Hit_num>%d</Hit_num>\n", hitNum);
+    fprintf(f, "        <Hit_id>%s</Hit_id>\n", target->name);
+    fprintf(f, "        <Hit_accession>%s</Hit_accession>\n", target->name);
+    fprintf(f, "        <Hit_len>%d</Hit_len>\n", target->size);
+    fprintf(f, "        <Hit_hsps>\n");
+    for (ref = target->axtList; ref != NULL; ref = ref->next)
+        {
+	struct axt *axt = ref->axt;
+	int hspIx = 0;
+	fprintf(f, "        <Hsp>\n");
+	fprintf(f, "          <Hsp_num>%d</Hsp_num>\n", ++hspIx);
+	fprintf(f, "          <Hsp_bit-score>%d</Hsp_bit-score>\n", 
+		blastzScoreToNcbiBits(axt->score));
+	fprintf(f, "          <Hsp_score>%d</Hsp_score>\n",
+		blastzScoreToNcbiScore(axt->score));
+	fprintf(f, "          <Hsp_evalue>%f</Hsp_evalue>\n",
+	        blastzScoreToNcbiExpectation(axt->score));
+	fprintf(f, "          <Hsp_query-from>%d</Hsp_query-from>\n", 
+		axt->qStart+1);
+	fprintf(f, "          <Hsp_query-to>%d</Hsp_query-to>\n", axt->qEnd);
+	fprintf(f, "          <Hsp_hit-from>%d</Hsp_hit-from>\n", 
+		axt->tStart+1);
+	fprintf(f, "          <Hsp_hit-to>%d</Hsp_hit-to>\n", axt->tEnd);
+	fprintf(f, "        </Hsp>\n");
+	}
+
+    fprintf(f, "        </Hit_hsps>\n");
+    }
+
+fprintf(f, "      </Iteration_hits>\n");
+fprintf(f, "    </Iteration>\n");
+fprintf(f, "  </BlastOutput_iterations>\n");
+fprintf(f, "</BlastOutput>\n");
+}
+
+static void printAxtTargetBlastTab(FILE *f, struct axt *axt, int targetSize)
+/* Print out target in tabular blast-oriented format. */
+{
+int s = axt->tStart, e = axt->tEnd;
+if (axt->tStrand == '-')
+    reverseIntRange(&s, &e, targetSize);
+if (axt->tStrand == axt->qStrand)
+    {
+    fprintf(f, "%d\t", s+1);
+    fprintf(f, "%d\t", e);
+    }
+else
+    {
+    fprintf(f, "%d\t", e);
+    fprintf(f, "%d\t", s+1);
+    }
+}
+
+static void tabBlastOut(struct axtBundle *abList, int queryIx, boolean isProt, 
+	FILE *f, char *databaseName, int databaseSeqCount, 
+	double databaseLetterCount, char *ourId, boolean withComment)
+/* Do NCBI tabular blast output. */
+{
+char *queryName = abList->axtList->qName;
+int querySize = abList->qSize;
+struct targetHits *targetList = NULL, *target;
+
+if (withComment)
+    {
+    // use date from CVS, unless checked out with -kk, then ignore.
+    char * rcsDate = "$Date: 2009/02/26 00:05:49 $";
+    char dateStamp[11];
+    if (strlen(rcsDate) > 17)
+        safencpy(dateStamp, sizeof(dateStamp), rcsDate+7, 10);
+    else
+        safecpy(dateStamp, sizeof(dateStamp), "");
+    dateStamp[10] = 0;
+    fprintf(f, "# BLAT %s [%s]\n", gfVersion, dateStamp);
+    fprintf(f, "# Query: %s\n", queryName);
+    fprintf(f, "# Database: %s\n", databaseName);
+    fprintf(f, "%s\n", 
+    	"# Fields: Query id, Subject id, % identity, alignment length, "
+	"mismatches, gap openings, q. start, q. end, s. start, s. end, "
+	"e-value, bit score");
+    }
+
+/* Print out details on each target. */
+targetList = bundleIntoTargets(abList);
+for (target = targetList; target != NULL; target = target->next)
+    {
+    struct axtRef *ref;
+    for (ref = target->axtList; ref != NULL; ref = ref->next)
+        {
+	struct axt *axt = ref->axt;
+	int matches = countMatches(axt->qSym, axt->tSym, axt->symCount);
+	int gaps = countGaps(axt->qSym, axt->tSym, axt->symCount);
+	int gapOpens = countGapOpens(axt->qSym, axt->tSym, axt->symCount);
+	fprintf(f, "%s\t", axt->qName);
+	fprintf(f, "%s\t", axt->tName);
+	fprintf(f, "%.2f\t", 100.0 * matches/axt->symCount);
+	fprintf(f, "%d\t", axt->symCount);
+	fprintf(f, "%d\t", axt->symCount - matches - gaps);
+	fprintf(f, "%d\t", gapOpens);
+	if (axt->qStrand == '-')
+	    {
+	    int s = axt->qStart, e = axt->qEnd;
+	    reverseIntRange(&s, &e, querySize);
+	    fprintf(f, "%d\t", s+1);
+	    fprintf(f, "%d\t", e);
+	    printAxtTargetBlastTab(f, axt, target->size);
+	    }
+	else
+	    {
+	    fprintf(f, "%d\t", axt->qStart + 1);
+	    fprintf(f, "%d\t", axt->qEnd);
+	    printAxtTargetBlastTab(f, axt, target->size);
+	    }
+	fprintf(f, "%3.1e\t", blastzScoreToNcbiExpectation(axt->score));
+	fprintf(f, "%d.0\n", blastzScoreToNcbiBits(axt->score));
+	}
+    }
+
+/* Cleanup time. */
+targetHitsFreeList(&targetList);
+}
+
+void axtBlastOut(struct axtBundle *abList, 
+	int queryIx, boolean isProt, FILE *f, 
+	char *databaseName, int databaseSeqCount, double databaseLetterCount, 
+	char *blastType, char *ourId, double minIdentity)
+/* Output a bundle of axt's on the same query sequence in blast format.
+ * The parameters in detail are:
+ *   ab - the list of bundles of axt's. 
+ *   f  - output file handle
+ *   databaseSeqCount - number of sequences in database
+ *   databaseLetterCount - number of bases or aa's in database
+ *   blastType - blast/wublast/blast8/blast9/xml
+ *   ourId - optional (may be NULL) thing to put in header
+ */
+{
+if (abList == NULL)
+    return;
+if (sameWord(blastType, "wublast"))
+    wuBlastOut(abList, queryIx, isProt, f, databaseName,
+   	databaseSeqCount, databaseLetterCount, ourId);
+else if (sameWord(blastType, "xml"))
+    xmlBlastOut(abList, queryIx, isProt, f, databaseName,
+        databaseSeqCount, databaseLetterCount, ourId);
+else if (sameWord(blastType, "blast"))
+    ncbiBlastOut(abList, queryIx, isProt, f, databaseName,
+        databaseSeqCount, databaseLetterCount, ourId, minIdentity);
+else if (sameWord(blastType, "blast8"))
+    tabBlastOut(abList, queryIx, isProt, f, databaseName,
+    	databaseSeqCount, databaseLetterCount, ourId, FALSE);
+else if (sameWord(blastType, "blast9"))
+    tabBlastOut(abList, queryIx, isProt, f, databaseName,
+    	databaseSeqCount, databaseLetterCount, ourId, TRUE);
+else
+    errAbort("Unrecognized blastType %s in axtBlastOut", blastType);
+}
+
diff --git a/lib/blastParse.c b/lib/blastParse.c
new file mode 100644
index 0000000..a251ddb
--- /dev/null
+++ b/lib/blastParse.c
@@ -0,0 +1,897 @@
+/* blastParse - read in blast output into C data structure. */
+
+#include "common.h"
+#include "dystring.h"
+#include "linefile.h"
+#include "dnautil.h"
+#include "sqlNum.h"
+#include "blastParse.h"
+#include "verbose.h"
+
+
+#define WARN_LEVEL 1   /* verbose level to enable warnings */
+#define TRACE_LEVEL 3  /* verbose level to enable tracing of files */
+#define DUMP_LEVEL 4   /* verbose level to enable dumping of parsed */
+
+struct blastFile *blastFileReadAll(char *fileName)
+/* Read all blast alignment in file. */
+{
+struct blastFile *bf;
+struct blastQuery *bq;
+
+bf = blastFileOpenVerify(fileName);
+while ((bq = blastFileNextQuery(bf)) != NULL)
+    {
+    slAddHead(&bf->queries, bq);
+    }
+slReverse(&bf->queries);
+lineFileClose(&bf->lf);
+return bf;
+}
+
+static void bfError(struct blastFile *bf, char *message)
+/* Print blast file error message. */
+{
+errAbort("%s:%d: %s", bf->fileName, bf->lf->lineIx, message);
+}
+
+static void bfWarn(struct blastFile *bf, char *message)
+/* Print blast file warning message. */
+{
+verbose(WARN_LEVEL, "Warning: %s:%d: %s\n", bf->fileName, bf->lf->lineIx, message);
+}
+
+static void bfUnexpectedEof(struct blastFile *bf)
+/* generate error on unexpected EOF */
+{
+errAbort("Unexpected end of file in %s\n", bf->fileName);
+}
+
+static void bfSyntax(struct blastFile *bf)
+/* General error message. */
+{
+bfError(bf, "Can't cope with BLAST output syntax");
+}
+
+static boolean isAllDigits(char *s)
+/* test if a string is all digits */
+{
+for (; *s != '\0'; s++)
+    {
+    if (!isdigit(*s))
+        return FALSE;
+    }
+return TRUE;
+}
+
+static boolean isAllDashes(char *s)
+/* test if a string is all dashes */
+{
+for (; *s != '\0'; s++)
+    {
+    if (*s != '-')
+        return FALSE;
+    }
+return TRUE;
+}
+
+static char *bfNextLine(struct blastFile *bf)
+/* Fetch next line of input trying, or NULL if not found */
+{
+char *line = NULL;
+if (lineFileNext(bf->lf, &line, NULL))
+    {
+    verbose(TRACE_LEVEL, "    => %s\n", line);
+    return line;
+    }
+else
+    {
+    verbose(TRACE_LEVEL, "    => EOF\n");
+    return NULL;
+    }
+}
+
+static boolean bfSkipBlankLines(struct blastFile *bf)
+/* skip blank lines, return FALSE on EOF */
+{
+char *line = NULL;
+while ((line = bfNextLine(bf)) != NULL)
+    {
+    if (skipLeadingSpaces(line)[0] != '\0')
+        {
+	lineFileReuse(bf->lf);
+        return TRUE;
+        }
+    }
+return FALSE; /* EOF */
+}
+
+static char *bfNeedNextLine(struct blastFile *bf)
+/* Fetch next line of input or die trying. */
+{
+char *line = bfNextLine(bf);
+if (line == NULL)
+    bfUnexpectedEof(bf);
+return line;
+}
+
+static char *bfSearchForLine(struct blastFile *bf, char *start)
+/* scan for a line starting with the specified string */
+{
+for (;;)
+    {
+    char *line = bfNextLine(bf);
+    if (line == NULL)
+	return NULL;
+    if (startsWith(start, line))
+        return line;
+    }
+}
+
+static void bfBadHeader(struct blastFile *bf)
+/* Report bad header. */
+{
+bfError(bf, "Bad first line\nShould be something like:\n"
+            "BLASTN 2.0.11 [Jan-20-2000]");
+}
+
+struct blastFile *blastFileOpenVerify(char *fileName)
+/* Open file, read and verify header. */
+{
+struct blastFile *bf;
+char *line;
+char *words[16];
+int wordCount;
+struct lineFile *lf;
+
+AllocVar(bf);
+bf->lf = lf = lineFileOpen(fileName, TRUE);
+bf->fileName = cloneString(fileName);
+
+/* Parse first line - something like: */
+line = bfNeedNextLine(bf);
+wordCount = chopLine(line, words);
+if (wordCount < 3)
+    bfBadHeader(bf);
+bf->program = cloneString(words[0]);
+bf->version = cloneString(words[1]);
+bf->buildDate = cloneString(words[2]);
+if (!wildMatch("*BLAST*", bf->program))
+    bfBadHeader(bf);
+if (!isdigit(bf->version[0]))
+    bfBadHeader(bf);
+if (bf->buildDate[0] != '[')
+    bfBadHeader(bf);
+return bf;
+}
+
+void decomma(char *s)
+/* Remove commas from string. */
+{
+char *d = s;
+char c;
+
+for (;;)
+    {
+    c = *s++;
+    if (c != ',')
+	*d++ = c;
+    if (c == 0)
+	break;
+    }
+}
+
+static void parseQueryLines(struct blastFile *bf, char *line, struct blastQuery *bq)
+/* Parse the Query= lines */
+{
+char *s, *e;
+char *words[16];
+int wordCount;
+if (bq->query != NULL)
+    bfError(bf, "already parse Query=");
+
+/* Process something like:
+ *    Query= MM39H11    00630     
+ */
+wordCount = chopLine(line, words);
+if (wordCount < 2)
+    bfError(bf, "No sequence name in query line");
+bq->query = cloneString(words[1]);
+
+for (;;)
+    {
+    line = bfNeedNextLine(bf);
+    s = skipLeadingSpaces(line);
+    if (s[0] == '(')
+        break;
+    }
+if (!isdigit(s[1]))
+    {
+    bfError(bf, "expecting something like:\n"
+                "   (45,693 letters)");
+    }
+s += 1;
+if ((e = strchr(s, ' ')) == NULL)
+    {
+    bfError(bf, "expecting something like:\n"
+                "   (45,693 letters)");
+    }
+*e = 0;
+decomma(s);
+bq->queryBaseCount = atoi(s);
+}
+
+static void parseDatabaseLines(struct blastFile *bf, char *line, struct blastQuery *bq)
+/* Process something like:
+ * Database: chr22.fa 
+ *        977 sequences; 95,550,797 total letters
+ */
+{
+static struct dyString *tmpBuf = NULL;
+char *words[16];
+int wordCount;
+if (bq->database != NULL)
+    bfError(bf, "already parse Database:");
+
+if (tmpBuf == NULL)
+    tmpBuf = dyStringNew(512);
+
+/* parse something like
+ * Database: celegans98
+ * some versions of blastp include the absolute path, but
+ * then split it across lines.
+ */
+wordCount = chopLine(line, words);
+if (wordCount < 2)
+    bfError(bf, "Expecting database name");
+dyStringClear(tmpBuf);
+dyStringAppend(tmpBuf, words[1]);
+while (line = bfNeedNextLine(bf), !isspace(line[0]))
+    {
+    dyStringAppend(tmpBuf, line);
+    }
+bq->database = cloneString(tmpBuf->string);
+
+/* Process something like:
+ *        977 sequences; 95,550,797 total letters
+ */
+wordCount = chopLine(line, words);
+if (wordCount < 3 || !isdigit(words[0][0]) || !isdigit(words[2][0]))
+    bfError(bf, "Expecting database info");
+decomma(words[0]);
+decomma(words[2]);
+bq->dbSeqCount = atoi(words[0]);
+bq->dbBaseCount = atoi(words[2]);
+}
+
+static char *roundLinePrefix = "Results from round "; // start of a round line
+
+static boolean isRoundLine(char *line)
+/* check if a line is a PSI round number line */
+{
+return startsWith(roundLinePrefix, line);
+}
+
+static void parseRoundLine(char *line, struct blastQuery *bq)
+/* round line and save current round in query
+ *   Results from round 1
+ */
+{
+char *p = skipLeadingSpaces(line + strlen(roundLinePrefix));
+bq->psiRounds = atoi(p);
+}
+
+struct blastQuery *blastFileNextQuery(struct blastFile *bf)
+/* Read all alignments associated with next query.  Return NULL at EOF. */
+{
+char *line;
+struct blastQuery *bq;
+struct blastGappedAli *bga;
+AllocVar(bq);
+
+verbose(TRACE_LEVEL, "blastFileNextQuery\n");
+
+/* find and parse Query= */
+line = bfSearchForLine(bf, "Query=");
+if (line == NULL)
+    return NULL;
+parseQueryLines(bf, line, bq);
+
+/* find and parse Database: */
+line = bfSearchForLine(bf, "Database:");
+if (line == NULL)
+    bfUnexpectedEof(bf);
+parseDatabaseLines(bf, line, bq);
+
+/* Seek to beginning of first gapped alignment. */
+for (;;)
+    {
+    line = bfNeedNextLine(bf);
+    if (line[0] == '>')
+	{
+	lineFileReuse(bf->lf);
+	break;
+	}
+    else if (isRoundLine(line))
+        parseRoundLine(line, bq);
+    else if (stringIn("No hits found", line) != NULL)
+        break;
+    }
+
+/* Read in gapped alignments. */
+while ((bga = blastFileNextGapped(bf, bq)) != NULL)
+    {
+    slAddHead(&bq->gapped, bga);
+    }
+slReverse(&bq->gapped);
+if (verboseLevel() >= DUMP_LEVEL)
+    {
+    verbose(DUMP_LEVEL, "blastFileNextQuery result:\n");
+    blastQueryPrint(bq, stderr);
+    }
+return bq;
+}
+
+static char *findNextGapped(struct blastFile *bf, struct blastQuery *bq)
+/* scan for next gapped alignment, return line or NULL if not hit */
+{
+while (TRUE)
+    {
+    if (!bfSkipBlankLines(bf))
+        return NULL;
+    char *line = bfNextLine(bf);
+    /*
+     * the last condition was added to deal with the new blast output format and is meant to find lines such as this one:
+     * TBLASTN 2.2.15 [Oct-15-2006]
+     * I am hoping that by looking for only "BLAST" this will work with things like blastp, blastn, psi-blast, etc
+     */
+    if (startsWith("  Database:", line) || (stringIn("BLAST", line) != NULL))
+        {
+	lineFileReuse(bf->lf);
+        return NULL;
+        }
+    if (line[0] == '>')
+        return line;
+    if (isRoundLine(line))
+        parseRoundLine(line, bq);
+    }
+}
+
+struct blastGappedAli *blastFileNextGapped(struct blastFile *bf, struct blastQuery *bq)
+/* Read in next gapped alignment.   Does *not* put it on bf->gapped list. 
+ * Return NULL at EOF or end of query. */
+{
+char *words[16];
+int wordCount;
+struct blastGappedAli *bga;
+struct blastBlock *bb;
+int lenSearch;
+
+verbose(TRACE_LEVEL, "blastFileNextGapped\n");
+
+char *line = findNextGapped(bf, bq);
+if (line == NULL)
+    return NULL;
+
+AllocVar(bga);
+bga->query = bq;
+bga->targetName = cloneString(line+1); 
+bga->psiRound = bq->psiRounds;
+
+/* Process something like:
+ *      Length = 100000
+ * however this follows a possible multi-line description, so be specified
+ * and limit how far we can scan
+ */
+for (lenSearch=0; lenSearch<25; lenSearch++)
+	{
+	line = bfNeedNextLine(bf);
+        if (isRoundLine(line))
+            parseRoundLine(line, bq);
+	wordCount = chopLine(line, words);
+	if (wordCount == 3 && sameString(words[0], "Length") &&  sameString(words[1], "=")
+            && isdigit(words[2][0]))
+		break;
+	}
+if (lenSearch>=25)
+    bfError(bf, "Expecting Length =");
+decomma(words[2]);
+bga->targetSize = atoi(words[2]);
+
+/* Get all the blocks. */
+while ((bb = blastFileNextBlock(bf, bq, bga)) != NULL)
+    {
+    slAddHead(&bga->blocks, bb);
+    }
+slReverse(&bga->blocks);
+return bga;
+}
+
+static int getStrand(struct blastFile *bf, char *strand)
+/* Translate "Plus" or "Minus" to +1 or -1. */
+{
+if (sameWord("Plus", strand))
+    return 1;
+else if (sameWord("Minus", strand))
+    return -1;
+else
+    {
+    bfError(bf, "Expecting Plus or Minus after Strand");
+    return 0;
+    }
+}
+
+static boolean nextBlockLine(struct blastFile *bf, struct blastQuery *bq, char **retLine)
+/* Get next block line.  Return FALSE and reuse line if it's
+ * an end of block type line. */
+{
+struct lineFile *lf = bf->lf;
+char *line;
+
+*retLine = line = bfNextLine(bf);
+if (line == NULL)
+    return FALSE;
+if (isRoundLine(line))
+    parseRoundLine(line, bq);
+
+/*
+the last condition was added to deal with the new blast output format and is meant to find lines such as this one:
+TBLASTN 2.2.15 [Oct-15-2006]
+I am hoping that by looking for only "BLAST" this will work with things like blastp, blastn, psi-blast, etc
+*/
+if (line[0] == '>' || startsWith("Query=", line) || startsWith("  Database:", line) || (stringIn("BLAST", line) != NULL))
+    {
+    lineFileReuse(lf);
+    return FALSE;
+    }
+return TRUE;
+}
+
+static double evalToDouble(char *s)
+/* Convert string from e-val to floating point rep.
+ * e-val is basically ascii floating point, but
+ * small ones may be 'e-100' instead of 1.0e-100
+ */
+{
+if (isdigit(s[0]))
+    return atof(s);
+else
+    {
+    char buf[64];
+    safef(buf, sizeof(buf), "1.0%s", s);
+    return atof(buf);
+    }
+}
+
+static boolean parseBlockLine(struct blastFile *bf, int *startRet, int *endRet,
+                           struct dyString *seq)
+/* read and parse the next target or query line, like:
+ *   Query: 26429 taccttgacattcctcagtgtgtcatcatcgttctctcctccaaacggcgagagtccgga 26488
+ *
+ * also handle broken NCBI tblastn output like:
+ *   Sbjct: 1181YYGEQRSTNGQTIQLKTQVFRRFPDDDDESEDHDDPDNAHESPEQEGAEGHFDLHYYENQ 1360
+ *
+ * Ignores and returns FALSE on bogus records generated by PSI BLAST, such as
+ *   Query: 0   --------------------------                                  
+ *   Sbjct: 38  PPGPPGVAGGNQTTVVVIYGPPGPPG                                   63
+ *   Query: 0                                                               
+ *   Sbjct: 63                                                               63
+ * If FALSE is returned, the output parameters will be unchanged.
+ */
+{
+char* line = bfNeedNextLine(bf);
+int a, b, s, e;
+char *words[16];
+int wordCount = chopLine(line, words);
+if ((wordCount < 2) || (wordCount > 4) || !(sameString("Query:", words[0]) || sameString("Sbjct:", words[0])))
+    bfSyntax(bf);
+
+/* look for one of the bad formats to ignore, as described above */
+if (((wordCount == 2) && isAllDigits(words[1]))
+    || ((wordCount == 3) && isAllDigits(words[1]) && isAllDigits(words[2]))
+    || ((wordCount == 3) && isAllDigits(words[1]) && isAllDashes(words[2])))
+    {
+    bfWarn(bf, "Ignored invalid alignment format for aligned sequence pair");
+    return FALSE;
+    }
+
+/* special handling for broken output with no space between start and
+ * sequence */
+if (wordCount == 3)
+    {
+    char *p;
+    if (!isdigit(words[1][0]) || !isdigit(words[2][0]))
+        bfSyntax(bf);
+    a = atoi(words[1]);
+    b = atoi(words[2]);
+    p = words[1];
+    while ((*p != '\0') && (isdigit(*p)))
+        p++;
+    dyStringAppend(seq, p);
+    }
+else
+    {
+    if (!isdigit(words[1][0]) || !isdigit(words[3][0]))
+        bfSyntax(bf);
+    a = atoi(words[1]);
+    b = atoi(words[3]);
+    dyStringAppend(seq, words[2]);
+    }
+s = min(a,b);
+e = max(a,b);
+*startRet = min(s, *startRet);
+*endRet = max(e, *endRet);
+return TRUE;
+}
+
+static boolean findBlockSeqPair(struct blastFile *bf, struct blastQuery *bq)
+/* scan forward for the next pair of Query:/Sbjct: sequences */
+{
+char *line;
+for (;;)
+    {
+    if (!nextBlockLine(bf, bq, &line))
+        return FALSE;
+    if (startsWith(" Score", line))
+        {
+        lineFileReuse(bf->lf);
+        return FALSE;
+        }
+    if (startsWith("Query:", line))
+        {
+        lineFileReuse(bf->lf);
+        return TRUE;
+        }
+    }
+}
+
+static void clearBlastBlock(struct blastBlock *bb, struct dyString *qString, struct dyString *tString)
+/* reset the contents of a blast block being accummulated */
+{
+bb->qStart = bb->tStart = 0x3fffffff;
+bb->qEnd = bb->tEnd = -bb->qStart;
+dyStringClear(qString);
+dyStringClear(tString);
+}
+
+static void parseBlockSeqPair(struct blastFile *bf, struct blastBlock *bb,
+                              struct dyString *qString, struct dyString *tString)
+/* parse the current pair Query:/Sbjct: sequences */
+{
+boolean isOk = TRUE;
+
+/* Query line */
+if (!parseBlockLine(bf, &bb->qStart, &bb->qEnd, qString))
+    isOk = FALSE;
+
+/* Skip next line. */
+bfNeedNextLine(bf);
+
+/* Fetch target sequence line. */
+if (!parseBlockLine(bf, &bb->tStart, &bb->tEnd, tString))
+    isOk = FALSE;
+if (!isOk)
+    {
+    // reset accumulated data so we discard everything before bogus pair
+    clearBlastBlock(bb, qString, tString);
+    }
+}
+
+
+static struct blastBlock *nextBlock(struct blastFile *bf, struct blastQuery *bq,
+                                    struct blastGappedAli *bga, boolean *skipRet)
+/* Read in next blast block.  Return NULL at EOF or end of gapped
+ * alignment. If an unparsable block is found, set skipRet to TRUE and return
+ * NULL. */
+{
+struct blastBlock *bb;
+char *line;
+char *words[16];
+int wordCount;
+char *parts[3];
+int partCount;
+static struct dyString *qString = NULL, *tString = NULL;
+
+verbose(TRACE_LEVEL,  "blastFileNextBlock\n");
+*skipRet = FALSE;
+
+/* Seek until get something like:
+ *   Score = 8770 bits (4424), Expect = 0.0
+ * or something that looks like we're done with this gapped
+ * alignment. */
+for (;;)
+    {
+    if (!nextBlockLine(bf, bq, &line))
+	return NULL;
+    if (startsWith(" Score", line))
+	break;
+    }
+AllocVar(bb);
+bb->gappedAli = bga;
+wordCount = chopLine(line, words);
+if (wordCount < 8 || !sameWord("Score", words[0]) 
+    || !isdigit(words[2][0]) || !(isdigit(words[7][0]) || words[7][0] == 'e')
+    || !startsWith("Expect", words[5]))
+    {
+    bfError(bf, "Expecting something like:\n"
+             "Score = 8770 bits (4424), Expect = 0.0");
+    }
+bb->bitScore = atof(words[2]);
+bb->eVal = evalToDouble(words[7]);
+
+/* Process something like:
+ *   Identities = 8320/9618 (86%), Gaps = 3/9618 (0%)
+ *             or
+ *   Identities = 8320/9618 (86%)
+ *             or
+ *   Identities = 10/19 (52%), Positives = 15/19 (78%), Frame = +2
+ *     (wu-tblastn)
+ *             or
+ *   Identities = 256/400 (64%), Positives = 306/400 (76%)
+ *   Frame = +1 / -2
+ *     (tblastn)
+ *
+ *   Identities = 1317/10108 (13%), Positives = 2779/10108 (27%), Gaps = 1040/10108
+ *   (10%)
+ *      - wrap on long lines
+ *
+ * Handle weird cases where the is only a `Score' line, with no `Identities'
+ * lines by skipping the alignment; they seem line small, junky alignments.
+ */
+line = bfNeedNextLine(bf);
+wordCount = chopLine(line, words);
+if (wordCount < 3 || !sameWord("Identities", words[0]))
+    {
+    if (wordCount > 1 || sameWord("Score", words[0]))
+        {
+        /* ugly hack to skip block with no identities */
+        *skipRet = TRUE;
+        blastBlockFree(&bb);
+        return NULL;
+        }
+    bfError(bf, "Expecting identity count");
+    }
+partCount = chopByChar(words[2], '/', parts, ArraySize(parts));
+if (partCount != 2 || !isdigit(parts[0][0]) || !isdigit(parts[1][0]))
+    bfSyntax(bf);
+bb->matchCount = atoi(parts[0]);
+bb->totalCount = atoi(parts[1]);
+if (wordCount >= 7 && sameWord("Gaps", words[4]))
+    {
+    if (!isdigit(words[6][0]))
+	bfSyntax(bf);
+    bb->insertCount = atoi(words[6]);
+    }
+if ((wordCount >= 11) && sameWord("Frame", words[8]))
+    {
+    bb->qStrand = '+';
+    bb->tStrand = words[10][0];
+    bb->tFrame = atoi(words[10]);
+    }
+
+line = bfNeedNextLine(bf);
+boolean wrapped = (startsWith("(", line));
+
+/* Process something like:
+ *     Strand = Plus / Plus (blastn)
+ *     Frame = +1           (tblastn)
+ *     Frame = +1 / -2      (tblastx)
+ *     <blank line>         (blastp)
+ * note that wu-tblastn puts frame on Identities line
+ */
+if (wrapped)
+    line = bfNeedNextLine(bf);
+wordCount = chopLine(line, words);
+if ((wordCount >= 5) && sameWord("Strand", words[0]))
+    {
+    bb->qStrand = getStrand(bf, words[2]);
+    bb->tStrand = getStrand(bf, words[4]);
+    }
+else if ((wordCount >= 5) && sameWord("Frame", words[0]) && (words[3][0] == '/'))
+    {
+    // Frame = +1 / -2      (tblastx)
+    bb->qStrand = (words[2][0] == '-') ? -1 : 1;
+    bb->tStrand = (words[4][0] == '-') ? -1 : 1;
+    bb->qFrame = atoi(words[2]);
+    bb->tFrame = atoi(words[4]);
+    }
+else if ((wordCount >= 3) && sameWord("Frame", words[0]))
+    {
+    // Frame = +1           (tblastn)
+    bb->qStrand = 1;
+    bb->tStrand = (words[2][0] == '-') ? -1 : 1;
+    bb->qFrame = atoi(words[2]);
+    bb->tFrame = 1;
+    }
+else if (wordCount == 0)
+    {
+    /* if we didn't parse frame, default it */
+    if (bb->qStrand == 0)
+        {
+        bb->qStrand = '+';
+        bb->tStrand = '+';
+        }
+    }
+else
+    bfError(bf, "Expecting Strand, Frame or blank line");
+
+
+/* Process alignment lines.  They come in groups of three
+ * separated by a blank line - something like:
+ * Query: 26429 taccttgacattcctcagtgtgtcatcatcgttctctcctccaaacggcgagagtccgga 26488
+ *              |||||| |||||||||| ||| ||||||||||||||||||||||| || || ||||||||
+ * Sbjct: 62966 taccttaacattcctcaatgtttcatcatcgttctctcctccaaatggtgaaagtccgga 63025
+ */
+if (qString == NULL)
+    {
+    qString = newDyString(50000);
+    tString = newDyString(50000);
+    }
+clearBlastBlock(bb, qString, tString);
+for (;;)
+    {
+    if (!findBlockSeqPair(bf, bq))
+        break;
+    parseBlockSeqPair(bf, bb, qString, tString);
+    }
+
+/* convert to [0..n) and move to strand coords if necessary */
+bb->qStart--;
+if (bb->qStrand < 0)
+    reverseIntRange(&bb->qStart, &bb->qEnd, bq->queryBaseCount);
+bb->tStart--;
+if (bb->tStrand < 0)
+    reverseIntRange(&bb->tStart, &bb->tEnd, bga->targetSize);
+bb->qSym = cloneMem(qString->string, qString->stringSize+1);
+bb->tSym = cloneMem(tString->string, tString->stringSize+1);
+return bb;
+}
+
+struct blastBlock *blastFileNextBlock(struct blastFile *bf, 
+	struct blastQuery *bq, struct blastGappedAli *bga)
+/* Read in next blast block.  Return NULL at EOF or end of
+ * gapped alignment. */
+{
+struct blastBlock *bb = NULL;
+boolean skip = FALSE;
+
+while (((bb = nextBlock(bf, bq, bga, &skip)) == NULL) && skip)
+    continue; /* skip to next one */
+
+return bb;
+}
+
+void blastFileFree(struct blastFile **pBf)
+/* Free blast file. */
+{
+struct blastFile *bf = *pBf;
+if (bf != NULL)
+    {
+    lineFileClose(&bf->lf);
+    freeMem(bf->fileName);
+    freeMem(bf->program);
+    freeMem(bf->version);
+    freeMem(bf->buildDate);
+    blastQueryFreeList(&bf->queries);
+    freez(pBf);
+    }
+}
+
+void blastFileFreeList(struct blastFile **pList)
+/* Free list of blast files. */
+{
+struct blastFile *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    blastFileFree(&el);
+    }
+*pList = NULL;
+}
+
+void blastQueryFree(struct blastQuery **pBq)
+/* Free single blastQuery. */
+{
+struct blastQuery *bq;
+if ((bq = *pBq) != NULL)
+    {
+    freeMem(bq->query);
+    freeMem(bq->database);
+    blastGappedAliFreeList(&bq->gapped);
+    freez(pBq);
+    }
+}
+
+void blastQueryFreeList(struct blastQuery **pList)
+/* Free list of blastQuery's. */
+{
+struct blastQuery *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    blastQueryFree(&el);
+    }
+*pList = NULL;
+}
+
+
+void blastGappedAliFree(struct blastGappedAli **pBga)
+/* Free blastGappedAli. */
+{
+struct blastGappedAli *bga = *pBga;
+if (bga != NULL)
+    {
+    freeMem(bga->targetName);
+    blastBlockFreeList(&bga->blocks);
+    freez(pBga);
+    }
+}
+
+void blastGappedAliFreeList(struct blastGappedAli **pList)
+/* Free blastGappedAli list. */
+{
+struct blastGappedAli *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    blastGappedAliFree(&el);
+    }
+*pList = NULL;
+}
+
+
+void blastBlockFree(struct blastBlock **pBb)
+/* Free a single blastBlock. */
+{
+struct blastBlock *bb = *pBb;
+if (bb != NULL)
+    {
+    freeMem(bb->qSym);
+    freeMem(bb->tSym);
+    freez(pBb);
+    }
+}
+
+void blastBlockFreeList(struct blastBlock **pList)
+/* Free a list of blastBlocks. */
+{
+struct blastBlock *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    blastBlockFree(&el);
+    }
+*pList = NULL;
+}
+
+void blastBlockPrint(struct blastBlock* bb, FILE* out)
+/* print a BLAST block for debugging purposes  */
+{
+fprintf(out, "    blk: %d-%d <=> %d-%d tcnt=%d mcnt=%d icnt=%d\n",
+        bb->qStart, bb->qEnd,  bb->tStart, bb->tEnd,
+        bb->totalCount, bb->matchCount, bb->insertCount);
+fprintf(out, "        Q: %s\n", bb->qSym);
+fprintf(out, "        T: %s\n", bb->tSym);
+}
+
+void blastGappedAliPrint(struct blastGappedAli* ba, FILE* out)
+/* print a BLAST gapped alignment for debugging purposes  */
+{
+struct blastBlock *bb;
+fprintf(out, "%s <=> %s", ba->query->query, ba->targetName);
+if (ba->psiRound > 0)
+    fprintf(out, " round: %d", ba->psiRound);
+fputc('\n', out);
+for (bb = ba->blocks; bb != NULL; bb = bb->next)
+    {
+    blastBlockPrint(bb, out);
+    }
+}
+
+void blastQueryPrint(struct blastQuery *bq, FILE* out)
+/* print a BLAST query for debugging purposes  */
+{
+struct blastGappedAli *ba;
+for (ba = bq->gapped; ba != NULL; ba = ba->next)
+    blastGappedAliPrint(ba, out);
+}
diff --git a/lib/boxClump.c b/lib/boxClump.c
new file mode 100644
index 0000000..5f28bd6
--- /dev/null
+++ b/lib/boxClump.c
@@ -0,0 +1,312 @@
+/* boxClump - put together 2 dimensional boxes that
+ * overlap with each other into clumps. */
+
+#include "common.h"
+#include "dlist.h"
+#include "localmem.h"
+#include "boxClump.h"
+
+
+/** Some simple utility function on globally declared 
+ ** data structures. **/
+
+
+void boxClumpFree(struct boxClump **pClump)
+/* Free boxClump. */
+{
+struct boxClump *clump = *pClump;
+if (clump != NULL)
+    {
+    slFreeList(&clump->boxList);
+    freez(pClump);
+    }
+}
+
+void boxClumpFreeList(struct boxClump **pList)
+/* Free list of boxClumps. */
+{
+struct boxClump *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    boxClumpFree(&el);
+    }
+*pList = NULL;
+}
+
+int boxClumpCmpCount(const void *va, const void *vb)
+/* Compare to sort based on count of boxes. */
+{
+const struct boxClump *a = *((struct boxClump **)va);
+const struct boxClump *b = *((struct boxClump **)vb);
+return b->boxCount - a->boxCount;
+}
+
+/** Local data structures. */
+
+struct cluster
+/* A cluster of boxes. */
+    {
+    struct box *boxList;	/* List of boxes. */
+    struct dlNode *node;	/* Position in doubly-linked list. */
+    };
+
+struct box
+/* A box in an alignment. */
+    {
+    struct box *next;		 /* Next in list (usually on cluster). */
+    struct boxIn *in;		 /* Input box position. */
+    struct cluster *cluster;     /* Cluster this is part of. */
+    };
+
+struct boxRef
+/* Reference to a box. */
+    {
+    struct boxRef *next;
+    struct box *box;
+    };
+
+
+/** Routines that cluster using mostly the local data
+ ** structures. **/
+
+
+static void mergeClusters(struct cluster *a, struct cluster *b)
+/* Merge cluster b into cluster a, and free remnants of b. */
+{
+struct box *box;
+
+/* Merging with yourself is always problematic. */
+if (a == b)
+    return;
+
+/* Point all boxes in b to a. */
+for (box = b->boxList; box != NULL; box = box->next)
+    box->cluster = a;
+
+/* Add b's boxList to end of a's. */
+a->boxList = slCat(a->boxList, b->boxList);
+
+/* Remove b from master cluster list. */
+dlRemove(b->node);
+}
+
+static boolean allStartBy(struct boxRef *refList, int qStart, int tStart)
+/* Return TRUE if qStart/qEnd of all boxes less than or equal to qStart/tStart 
+ * This is an end condition for recursion along with only having two or
+ * less boxes in the refList.  It handles the case where you have many
+ * boxes stacked on top of each other. */
+{
+struct boxRef *ref;
+for (ref = refList; ref != NULL; ref = ref->next)
+    {
+    struct boxIn *box = ref->box->in;
+    if (box->qStart > qStart || box->tStart > tStart)
+        return FALSE;
+    }
+return TRUE;
+}
+
+static boolean allSameCluster(struct boxRef *refList)
+/* Return TRUE if qStart/qEnd of all boxes is the same */
+{
+struct boxRef *ref;
+struct cluster *cluster = refList->box->cluster;
+for (ref = refList->next; ref != NULL; ref = ref->next)
+    {
+    if (ref->box->cluster != cluster)
+        return FALSE;
+    }
+return TRUE;
+}
+
+static struct lm *lm;
+/* Local memory manager used for boxRefs and other stuff. */
+
+static void rBoxJoin(struct boxRef *refList, 
+	int qStart, int qEnd, int tStart, int tEnd)
+/* Recursively cluster boxes. */
+{
+int boxCount = slCount(refList);
+
+if (boxCount <= 1)
+    {
+    /* Easy: no merging required. */
+    }
+else if (boxCount == 2)
+    {
+    /* Decide if pair overlaps and if so merge. */
+    struct box *a = refList->box;
+    struct box *b = refList->next->box;
+    if (rangeIntersection(a->in->qStart, a->in->qEnd, b->in->qStart, b->in->qEnd) > 0 &&
+        rangeIntersection(a->in->tStart, a->in->tEnd, b->in->tStart, b->in->tEnd) > 0 )
+	{
+	mergeClusters(a->cluster, b->cluster);
+	}
+    else
+        {
+	/* Two non-overlapping boxes, we don't have to do anything. */
+	}
+    }
+else if (allStartBy(refList, qStart, tStart))
+    {
+    /* If everybody contains the upper left corner, then they all can 
+     * be merged.   This is the route taken often by clumps with lots
+     * of overlap. */
+    struct cluster *aCluster = refList->box->cluster;
+    struct boxRef *ref;
+    for (ref = refList->next; ref != NULL; ref = ref->next)
+        {
+	struct cluster *bCluster = ref->box->cluster;
+	mergeClusters(aCluster, bCluster);
+	}
+    }
+else if (allSameCluster(refList))
+    {
+    /* Everything is in the same cluster, no action required. */
+    }
+else
+    {
+    /* We can't yet figure out clumping, so break
+     * up our window in two along larger dimension and
+     * recurse on both subwindows. */
+    struct boxRef *list1 = NULL, *list2 = NULL, *ref, *next;
+    if (qEnd - qStart > tEnd - tStart)
+        {
+	int mid = (qStart + qEnd)>>1;
+	for (ref = refList; ref != NULL; ref = next)
+	    {
+	    struct box *box = ref->box;
+	    next = ref->next;
+	    if (box->in->qEnd <= mid)
+	        {
+		slAddHead(&list1, ref);
+		}
+	    else if (box->in->qStart >= mid)
+	        {
+		slAddHead(&list2, ref);
+		}
+	    else
+	        {
+		/* Box crosses boundary, have to put it on both lists. */
+		slAddHead(&list1, ref);
+		lmAllocVar(lm, ref);
+		ref->box = box;
+		slAddHead(&list2, ref);
+		}
+	    }
+	rBoxJoin(list1, qStart, mid, tStart, tEnd);
+	rBoxJoin(list2, mid, qEnd, tStart, tEnd);
+	}
+    else
+        {
+	int mid = (tStart + tEnd)>>1;
+	for (ref = refList; ref != NULL; ref = next)
+	    {
+	    struct box *box = ref->box;
+	    next = ref->next;
+	    if (box->in->tEnd <= mid)
+	        {
+		slAddHead(&list1, ref);
+		}
+	    else if (box->in->tStart >= mid)
+	        {
+		slAddHead(&list2, ref);
+		}
+	    else
+	        {
+		/* Box crosses boundary, have to put it on both lists. */
+		slAddHead(&list1, ref);
+		lmAllocVar(lm, ref);
+		ref->box = box;
+		slAddHead(&list2, ref);
+		}
+	    }
+	rBoxJoin(list1, qStart, qEnd, tStart, mid);
+	rBoxJoin(list2, qStart, qEnd, mid, tEnd);
+	}
+    }
+}
+
+
+struct boxClump *boxFindClumps(struct boxIn **pBoxList)
+/* Convert list of boxes to a list of clumps.  Clumps
+ * are collections of boxes that overlap.  Note that
+ * the original boxList is overwritten as the boxes
+ * are moved from it to the clumps. */
+{
+struct boxIn *in;
+struct boxClump *clumpList = NULL, *clump;
+struct boxRef *refList = NULL, *ref;
+struct box *box;
+struct cluster *cluster;
+struct dlNode *node;
+struct dlList clusterList;
+int qStart = BIGNUM, qEnd = -BIGNUM;
+int tStart = BIGNUM, tEnd = -BIGNUM;
+
+
+dlListInit(&clusterList);
+lm = lmInit(0);
+
+/* Make local box structure, cluster, and reference
+ * for each input box.  Calculate overall bounds. */
+for (in = *pBoxList; in != NULL; in = in->next)
+    {
+    lmAllocVar(lm, box);
+    box->in = in;
+    if (in->qStart < qStart) qStart = in->qStart;
+    if (in->qEnd > qEnd) qEnd = in->qEnd;
+    if (in->tStart < tStart) tStart = in->tStart;
+    if (in->tEnd > tEnd) tEnd = in->tEnd;
+    lmAllocVar(lm,cluster);
+    lmAllocVar(lm, cluster->node);
+    cluster->node->val = cluster;
+    dlAddTail(&clusterList, cluster->node);
+    cluster->boxList = box;
+    box->cluster = cluster;
+    lmAllocVar(lm, ref);
+    ref->box = box;
+    slAddHead(&refList, ref);
+    }
+
+/* Call to recursive joiner. */
+rBoxJoin(refList, qStart, qEnd, tStart, tEnd);
+
+/* Copy from local memory and local data structures
+ * to global memory and global data structures. */
+for (node = clusterList.head; !dlEnd(node); node = node->next)
+    {
+    int boxCount = 0;
+    int qStart = BIGNUM, qEnd = -BIGNUM;
+    int tStart = BIGNUM, tEnd = -BIGNUM;
+    struct boxIn *boxList = NULL;
+    cluster = node->val;
+    for (box = cluster->boxList; box != NULL; box = box->next)
+	{
+	in = box->in;
+	slAddHead(&boxList, in);
+	if (in->qStart < qStart) qStart = in->qStart;
+	if (in->qEnd > qEnd) qEnd = in->qEnd;
+	if (in->tStart < tStart) tStart = in->tStart;
+	if (in->tEnd > tEnd) tEnd = in->tEnd;
+	++boxCount;
+	}
+    if (boxCount > 0)
+        {
+	AllocVar(clump);
+	slAddHead(&clumpList, clump);
+	clump->boxList = boxList;
+	clump->boxCount = boxCount;
+	clump->qStart = qStart;
+	clump->qEnd = qEnd;
+	clump->tStart = tStart;
+	clump->tEnd = tEnd;
+	}
+    }
+*pBoxList = NULL;
+lmCleanup(&lm);
+return clumpList;
+}
+
diff --git a/lib/boxLump.c b/lib/boxLump.c
new file mode 100644
index 0000000..0fdfbc9
--- /dev/null
+++ b/lib/boxLump.c
@@ -0,0 +1,159 @@
+/* boxLump - This will lump together boxes that overlap into the smallest
+ * box that encompasses the overlap.  It will put other boxes that 
+ * fit in the encompassing box in there too. 
+ *   It works by projecting the box list along one dimension at a
+ * time looking for gaps between boxes. This is similar in function
+ * to boxFindClumps, but a bit less precise, and quite a bit faster.
+ * in some important cases. */
+
+#include "common.h"
+#include "hash.h"
+#include "boxClump.h"
+#include "boxLump.h"
+
+
+int boxInCmpQuery(const void *va, const void *vb)
+/* Compare to sort based on query start. */
+{
+const struct boxIn *a = *((struct boxIn **)va);
+const struct boxIn *b = *((struct boxIn **)vb);
+return a->qStart - b->qStart;
+}
+
+int boxInCmpTarget(const void *va, const void *vb)
+/* Compare to sort based on query start. */
+{
+const struct boxIn *a = *((struct boxIn **)va);
+const struct boxIn *b = *((struct boxIn **)vb);
+return a->tStart - b->tStart;
+}
+
+struct boxClump *lumpOneDimension(struct boxIn *boxList, boolean onQuery)
+/* Build box clump list on one dimension. */
+{
+struct boxClump *clump = NULL, *clumpList = NULL;
+struct boxIn *box, *nextBox;
+if (onQuery)
+    slSort(&boxList, boxInCmpQuery);
+else
+    slSort(&boxList, boxInCmpTarget);
+for (box = boxList; box != NULL; box = nextBox)
+    {
+    nextBox = box->next;
+    /* Make new clump containing current box. */
+    if (clump == NULL || 
+        (onQuery && clump->qEnd < box->qStart) ||
+	(!onQuery && clump->tEnd < box->tStart) )
+        {
+	AllocVar(clump);
+	slAddHead(&clumpList, clump);
+	clump->qStart = box->qStart;
+	clump->qEnd = box->qEnd;
+	clump->tStart = box->tStart;
+	clump->tEnd = box->tEnd;
+	clump->boxCount = 1;
+	clump->boxList = box;
+	box->next = NULL;
+	}
+    else
+        {
+	if (clump->tStart > box->tStart)
+	     clump->tStart = box->tStart;
+	if (clump->tEnd < box->tEnd)
+	     clump->tEnd = box->tEnd;
+	if (clump->qEnd < box->qEnd)
+	     clump->qEnd = box->qEnd;
+	if (clump->qStart > box->qStart)
+	     clump->qStart = box->qStart;
+	clump->boxCount += 1;
+	slAddHead(&clump->boxList, box);
+	}
+    }
+return clumpList;
+}
+
+struct boxClump *boxLump(struct boxIn **pBoxList)
+/* Convert list of boxes to a list of lumps.  The lumps
+ * are a smaller number of boxes that between them contain
+ * all of the input boxes.  Note that
+ * the original boxList is overwritten as the boxes
+ * are moved from it to the lumps. */
+{
+struct boxClump *qClumpList = NULL, *tClumpList = NULL, 
+	*tClump;
+
+if (*pBoxList == NULL)
+    return NULL;
+tClumpList = lumpOneDimension(*pBoxList, FALSE);
+
+for (tClump = tClumpList; tClump != NULL; tClump = tClump->next)
+    {
+    struct boxClump *oneList = lumpOneDimension(tClump->boxList, TRUE);
+    if (slCount(oneList) > 1)
+        {
+	struct boxClump *clump;
+	for (clump = oneList; clump != NULL; clump = clump->next)
+	    {
+	    struct boxClump *subList = boxLump(&clump->boxList);
+	    qClumpList = slCat(subList, qClumpList);
+	    }
+	boxClumpFreeList(&oneList);
+	}
+    else
+	{
+	qClumpList = slCat(oneList, qClumpList);
+	}
+    tClump->boxList = NULL;
+    }
+
+boxClumpFreeList(&tClumpList);
+*pBoxList = NULL;
+return qClumpList;
+}
+
+#ifdef DEBUG
+
+int testData[][4] = 
+    {
+	/* qStart, qEnd, tStart, tEnd */
+	{0, 100,     0, 100},
+	{50, 150,    50, 150},
+	{200, 300,   200, 300},
+	{250, 350,   250, 350},
+	{0, 100,     200, 300},
+	{50, 150,    250, 350},
+	{200,300,    0, 100},
+	{250,350,    50, 150},
+	{500,600,    100,300},
+	{500,600,    500, 600},
+	{500,700,    500, 700},
+	{1000,1100,  1000,1100},
+	{1000,1100,  2000,2100},
+    };
+
+
+void testBoxLump()
+/* Test boxLump routine. */
+{
+struct boxIn *boxList = NULL, *box;
+struct boxClump *clumpList, *clump;
+int i;
+
+for (i=0; i<ArraySize(testData); ++i)
+    {
+    AllocVar(box);
+    box->qStart = testData[i][0];
+    box->qEnd = testData[i][1];
+    box->tStart = testData[i][2];
+    box->tEnd = testData[i][3];
+    slAddHead(&boxList, box);
+    }
+clumpList = boxLump(&boxList);
+for (clump = clumpList; clump != NULL; clump = clump->next)
+    {
+    printf("%d,%d,\t%d,%d\n", clump->qStart, clump->qEnd, clump->tStart, clump->tEnd);
+    for (box = clump->boxList; box != NULL; box = box->next)
+	printf("\t%d,%d\t%d,%d\n", box->qStart, box->qEnd, box->tStart, box->tEnd);
+    }
+}
+#endif /* DEBUG */
diff --git a/lib/bwgCreate.c b/lib/bwgCreate.c
new file mode 100644
index 0000000..ed9de15
--- /dev/null
+++ b/lib/bwgCreate.c
@@ -0,0 +1,1114 @@
+/* bwgCreate - create big wig files.  Implements write side of bwgInternal.h module. 
+ * See the comment in bwgInternal.h for a description of the file format. */
+
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "localmem.h"
+#include "errabort.h"
+#include "sqlNum.h"
+#include "sig.h"
+#include "zlibFace.h"
+#include "bPlusTree.h"
+#include "cirTree.h"
+#include "bbiFile.h"
+#include "bwgInternal.h"
+#include "bigWig.h"
+
+
+static int bwgBedGraphItemCmp(const void *va, const void *vb)
+/* Compare to sort based on query start. */
+{
+const struct bwgBedGraphItem *a = *((struct bwgBedGraphItem **)va);
+const struct bwgBedGraphItem *b = *((struct bwgBedGraphItem **)vb);
+int dif = (int)a->start - (int)b->start;
+if (dif == 0)
+    dif = (int)a->end - (int)b->end;
+return dif;
+}
+
+static int bwgVariableStepItemCmp(const void *va, const void *vb)
+/* Compare to sort based on query start. */
+{
+const struct bwgVariableStepItem *a = *((struct bwgVariableStepItem **)va);
+const struct bwgVariableStepItem *b = *((struct bwgVariableStepItem **)vb);
+return (int)a->start - (int)b->start;
+}
+
+void bwgDumpSummary(struct bbiSummary *sum, FILE *f)
+/* Write out summary info to file. */
+{
+fprintf(f, "summary %d:%d-%d min=%f, max=%f, sum=%f, sumSquares=%f, validCount=%d, mean=%f\n",
+     sum->chromId, sum->start, sum->end, sum->minVal, sum->maxVal, sum->sumData,
+     sum->sumSquares, sum->validCount, sum->sumData/sum->validCount);
+}
+
+static int bwgSectionWrite(struct bwgSection *section, boolean doCompress, FILE *f)
+/* Write out section to file, filling in section->fileOffset. */
+{
+UBYTE type = section->type;
+UBYTE reserved8 = 0;
+int itemSize;
+switch (section->type)
+    {
+    case bwgTypeBedGraph:
+        itemSize = 12;
+	break;
+    case bwgTypeVariableStep:
+        itemSize = 8;
+	break;
+    case bwgTypeFixedStep:
+        itemSize = 4;
+	break;
+    default:
+        itemSize = 0;  // Suppress compiler warning
+	internalErr();
+	break;
+    }
+int fixedSize = sizeof(section->chromId) + sizeof(section->start) + sizeof(section->end) + 
+     sizeof(section->itemStep) + sizeof(section->itemSpan) + sizeof(type) + sizeof(reserved8) +
+     sizeof(section->itemCount);
+int bufSize = section->itemCount * itemSize + fixedSize;
+char buf[bufSize];
+char *bufPt = buf;
+
+section->fileOffset = ftell(f);
+memWriteOne(&bufPt, section->chromId);
+memWriteOne(&bufPt, section->start);
+memWriteOne(&bufPt, section->end);
+memWriteOne(&bufPt, section->itemStep);
+memWriteOne(&bufPt, section->itemSpan);
+memWriteOne(&bufPt, type);
+memWriteOne(&bufPt, reserved8);
+memWriteOne(&bufPt, section->itemCount);
+
+int i;
+switch (section->type)
+    {
+    case bwgTypeBedGraph:
+	{
+	struct bwgBedGraphItem *item = section->items.bedGraphList;
+	for (item = section->items.bedGraphList; item != NULL; item = item->next)
+	    {
+	    memWriteOne(&bufPt, item->start);
+	    memWriteOne(&bufPt, item->end);
+	    memWriteOne(&bufPt, item->val);
+	    }
+	break;
+	}
+    case bwgTypeVariableStep:
+	{
+	struct bwgVariableStepPacked *items = section->items.variableStepPacked;
+	for (i=0; i<section->itemCount; ++i)
+	    {
+	    memWriteOne(&bufPt, items->start);
+	    memWriteOne(&bufPt, items->val);
+	    items += 1;
+	    }
+	break;
+	}
+    case bwgTypeFixedStep:
+	{
+	struct bwgFixedStepPacked *items = section->items.fixedStepPacked;
+	for (i=0; i<section->itemCount; ++i)
+	    {
+	    memWriteOne(&bufPt, items->val);
+	    items += 1;
+	    }
+	break;
+	}
+    default:
+        internalErr();
+	break;
+    }
+assert(bufSize == (bufPt - buf) );
+
+if (doCompress)
+    {
+    size_t maxCompSize = zCompBufSize(bufSize);
+    char compBuf[maxCompSize];
+    int compSize = zCompress(buf, bufSize, compBuf, maxCompSize);
+    mustWrite(f, compBuf, compSize);
+    }
+else
+    mustWrite(f, buf, bufSize);
+return bufSize;
+}
+
+
+int bwgSectionCmp(const void *va, const void *vb)
+/* Compare to sort based on chrom,start,end.  */
+{
+const struct bwgSection *a = *((struct bwgSection **)va);
+const struct bwgSection *b = *((struct bwgSection **)vb);
+int dif = strcmp(a->chrom, b->chrom);
+if (dif == 0)
+    {
+    dif = (int)a->start - (int)b->start;
+    if (dif == 0)
+	dif = (int)a->end - (int)b->end;
+    }
+return dif;
+}
+
+static struct cirTreeRange bwgSectionFetchKey(const void *va, void *context)
+/* Fetch bwgSection key for r-tree */
+{
+struct cirTreeRange res;
+const struct bwgSection *a = *((struct bwgSection **)va);
+res.chromIx = a->chromId;
+res.start = a->start;
+res.end = a->end;
+return res;
+}
+
+static bits64 bwgSectionFetchOffset(const void *va, void *context)
+/* Fetch bwgSection file offset for r-tree */
+{
+const struct bwgSection *a = *((struct bwgSection **)va);
+return a->fileOffset;
+}
+
+static boolean stepTypeLine(char *line)
+/* Return TRUE if it's a variableStep or fixedStep line. */
+{
+return (startsWithWord("variableStep", line) || startsWithWord("fixedStep", line));
+}
+
+static boolean steppedSectionEnd(char *line, int maxWords)
+/* Return TRUE if line indicates the start of another section. */
+{
+int wordCount = chopByWhite(line, NULL, 5);
+if (wordCount > maxWords)
+    return TRUE;
+return stepTypeLine(line);
+}
+
+static void parseFixedStepSection(struct lineFile *lf, boolean clipDontDie, struct lm *lm,
+	int itemsPerSlot, char *chrom, bits32 chromSize, bits32 span, bits32 sectionStart, 
+	bits32 step, struct bwgSection **pSectionList)
+/* Read the single column data in section until get to end. */
+{
+struct lm *lmLocal = lmInit(0);
+
+/* Stream through section until get to end of file or next section,
+ * adding values from single column to list. */
+char *words[1];
+char *line;
+struct bwgFixedStepItem *item, *itemList = NULL;
+int originalSectionSize = 0;
+bits32 sectionEnd = sectionStart;
+while (lineFileNextReal(lf, &line))
+    {
+    if (steppedSectionEnd(line, 1))
+	{
+        lineFileReuse(lf);
+	break;
+	}
+    chopLine(line, words);
+    lmAllocVar(lmLocal, item);
+    item->val = lineFileNeedDouble(lf, words, 0);
+    if (sectionEnd + span > chromSize)
+	{
+	warn("line %d of %s: chromosome %s has %u bases, but item ends at %u",
+	    lf->lineIx, lf->fileName, chrom, chromSize, sectionEnd + span);
+	if (!clipDontDie)
+	    noWarnAbort();
+	}
+    else
+	{
+	slAddHead(&itemList, item);
+	++originalSectionSize;
+	}
+    sectionEnd += step;
+    }
+slReverse(&itemList);
+
+/* Break up into sections of no more than items-per-slot size, and convert to packed format. */
+int sizeLeft = originalSectionSize;
+for (item = itemList; item != NULL; )
+    {
+    /* Figure out size of this section  */
+    int sectionSize = sizeLeft;
+    if (sectionSize > itemsPerSlot)
+        sectionSize = itemsPerSlot;
+    sizeLeft -= sectionSize;
+
+
+    /* Allocate and fill in section. */
+    struct bwgSection *section;
+    lmAllocVar(lm, section);
+    section->chrom = chrom;
+    section->start = sectionStart;
+    sectionStart += sectionSize * step;
+    section->end = sectionStart - step + span;
+    section->type = bwgTypeFixedStep;
+    section->itemStep = step;
+    section->itemSpan = span;
+    section->itemCount = sectionSize;
+
+    /* Allocate array for data, and copy from list to array representation */
+    struct bwgFixedStepPacked *packed;		/* An array */
+    section->items.fixedStepPacked = lmAllocArray(lm, packed, sectionSize);
+    int i;
+    for (i=0; i<sectionSize; ++i)
+        {
+	packed->val = item->val;
+	item = item->next;
+	++packed;
+	}
+
+    /* Add section to list. */
+    slAddHead(pSectionList, section);
+    }
+lmCleanup(&lmLocal);
+}
+
+static void parseVariableStepSection(struct lineFile *lf, boolean clipDontDie, struct lm *lm,
+	int itemsPerSlot, char *chrom, int chromSize, bits32 span, struct bwgSection **pSectionList)
+/* Read the single column data in section until get to end. */
+{
+struct lm *lmLocal = lmInit(0);
+
+/* Stream through section until get to end of file or next section,
+ * adding values from single column to list. */
+char *words[2];
+char *line;
+struct bwgVariableStepItem *item, *nextItem, *itemList = NULL;
+int originalSectionSize = 0;
+while (lineFileNextReal(lf, &line))
+    {
+    if (steppedSectionEnd(line, 2))
+	{
+        lineFileReuse(lf);
+	break;
+	}
+    chopLine(line, words);
+    lmAllocVar(lmLocal, item);
+    int start = lineFileNeedNum(lf, words, 0);
+    if (start <= 0)
+	{
+	errAbort("line %d of %s: zero or negative chromosome coordinate not allowed",
+	    lf->lineIx, lf->fileName);
+	}
+    item->start = start - 1;
+    item->val = lineFileNeedDouble(lf, words, 1);
+    if (item->start + span > chromSize)
+        {
+	warn("line %d of %s: chromosome %s has %u bases, but item ends at %u",
+	    lf->lineIx, lf->fileName, chrom, chromSize, item->start + span);
+	if (!clipDontDie)
+	    noWarnAbort();
+	}
+    else
+        {
+	slAddHead(&itemList, item);
+	++originalSectionSize;
+	}
+    }
+slSort(&itemList, bwgVariableStepItemCmp);
+
+/* Make sure no overlap between items. */
+if (itemList != NULL)
+    {
+    item = itemList;
+    for (nextItem = item->next; nextItem != NULL; nextItem = nextItem->next)
+        {
+	if (item->start + span > nextItem->start)
+	    errAbort("Overlap on %s between items starting at %d and %d.\n"
+	             "Please remove overlaps and try again",
+		    chrom, item->start, nextItem->start);
+	item = nextItem;
+	}
+    }
+
+/* Break up into sections of no more than items-per-slot size. */
+int sizeLeft = originalSectionSize;
+for (item = itemList; item != NULL; )
+    {
+    /* Figure out size of this section  */
+    int sectionSize = sizeLeft;
+    if (sectionSize > itemsPerSlot)
+        sectionSize = itemsPerSlot;
+    sizeLeft -= sectionSize;
+
+    /* Convert from list to array representation. */
+    struct bwgVariableStepPacked *packed, *p;		
+    p = lmAllocArray(lm, packed, sectionSize);
+    int i;
+    for (i=0; i<sectionSize; ++i)
+        {
+	p->start = item->start;
+	p->val = item->val;
+	item = item->next;
+	++p;
+	}
+
+    /* Fill in section and add it to list. */
+    struct bwgSection *section;
+    lmAllocVar(lm, section);
+    section->chrom = chrom;
+    section->start = packed[0].start;
+    section->end = packed[sectionSize-1].start + span;
+    section->type = bwgTypeVariableStep;
+    section->items.variableStepPacked = packed;
+    section->itemSpan = span;
+    section->itemCount = sectionSize;
+    slAddHead(pSectionList, section);
+    }
+lmCleanup(&lmLocal);
+}
+
+static unsigned parseUnsignedVal(struct lineFile *lf, char *var, char *val)
+/* Return val as an integer, printing error message if it's not. */
+{
+char c = val[0];
+if (!isdigit(c))
+    errAbort("Expecting numerical value for %s, got %s, line %d of %s", 
+    	var, val, lf->lineIx, lf->fileName);
+return sqlUnsigned(val);
+}
+
+static void parseSteppedSection(struct lineFile *lf, boolean clipDontDie, 
+	struct hash *chromSizeHash, char *initialLine, 
+	struct lm *lm, int itemsPerSlot, struct bwgSection **pSectionList)
+/* Parse out a variableStep or fixedStep section and add it to list, breaking it up as need be. */
+{
+/* Parse out first word of initial line and make sure it is something we recognize. */
+char *typeWord = nextWord(&initialLine);
+enum bwgSectionType type = bwgTypeFixedStep;
+if (sameString(typeWord, "variableStep"))
+    type = bwgTypeVariableStep;
+else if (sameString(typeWord, "fixedStep"))
+    type = bwgTypeFixedStep;
+else
+    errAbort("Unknown type %s\n", typeWord);
+
+/* Set up defaults for values we hope to parse out of rest of line. */
+int span = 0;
+bits32 step = 0;
+bits32 start = 0;
+char *chrom = NULL;
+
+/* Parse out var=val pairs. */
+char *varEqVal;
+while ((varEqVal = nextWord(&initialLine)) != NULL)
+    {
+    char *wordPairs[2];
+    int wc = chopByChar(varEqVal, '=', wordPairs, 2);
+    if (wc != 2)
+        errAbort("strange var=val pair line %d of %s", lf->lineIx, lf->fileName);
+    char *var = wordPairs[0];
+    char *val = wordPairs[1];
+    if (sameString(var, "chrom"))
+        chrom = cloneString(val);
+    else if (sameString(var, "span"))
+	span = parseUnsignedVal(lf, var, val);
+    else if (sameString(var, "step"))
+	step = parseUnsignedVal(lf, var, val);
+    else if (sameString(var, "start"))
+	{
+        start = parseUnsignedVal(lf, var, val);
+	}
+    else
+	errAbort("Unknown setting %s=%s line %d of %s", var, val, lf->lineIx, lf->fileName);
+    }
+
+/* Check that we have all that are required and no more, and call type-specific routine to parse
+ * rest of section. */
+if (chrom == NULL)
+    errAbort("Missing chrom= setting line %d of %s\n", lf->lineIx, lf->fileName);
+bits32 chromSize = (chromSizeHash ? hashIntVal(chromSizeHash, chrom) : BIGNUM);
+if (start > chromSize)
+    {
+    warn("line %d of %s: chromosome %s has %u bases, but item starts at %u",
+    	lf->lineIx, lf->fileName, chrom, chromSize, start);
+    if (!clipDontDie)
+        noWarnAbort();
+    }
+if (type == bwgTypeFixedStep)
+    {
+    if (start == 0)
+	errAbort("Missing start= setting line %d of %s\n", lf->lineIx, lf->fileName);
+    if (step == 0)
+	errAbort("Missing step= setting line %d of %s\n", lf->lineIx, lf->fileName);
+    if (span == 0)
+	span = step;
+    parseFixedStepSection(lf, clipDontDie, lm, itemsPerSlot, 
+    	chrom, chromSize, span, start-1, step, pSectionList);
+    }
+else
+    {
+    if (start != 0)
+	errAbort("Extra start= setting line %d of %s\n", lf->lineIx, lf->fileName);
+    if (step != 0)
+	errAbort("Extra step= setting line %d of %s\n", lf->lineIx, lf->fileName);
+    if (span == 0)
+	span = 1;
+    parseVariableStepSection(lf, clipDontDie, lm, itemsPerSlot, 
+    	chrom, chromSize, span, pSectionList);
+    }
+}
+
+struct bedGraphChrom
+/* A chromosome in bed graph format. */
+    {
+    struct bedGraphChrom *next;		/* Next in list. */
+    char *name;			/* Chromosome name - not allocated here. */
+    bits32 size;		/* Chromosome size. */
+    struct bwgBedGraphItem *itemList;	/* List of items. */
+    };
+
+static int bedGraphChromCmpName(const void *va, const void *vb)
+/* Compare to sort based on query start. */
+{
+const struct bedGraphChrom *a = *((struct bedGraphChrom **)va);
+const struct bedGraphChrom *b = *((struct bedGraphChrom **)vb);
+return strcmp(a->name, b->name);
+}
+
+static void parseBedGraphSection(struct lineFile *lf, boolean clipDontDie, 
+	struct hash *chromSizeHash, struct lm *lm, 
+	int itemsPerSlot, struct bwgSection **pSectionList)
+/* Parse out bedGraph section until we get to something that is not in bedGraph format. */
+{
+/* Set up hash and list to store chromosomes. */
+struct hash *chromHash = hashNew(0);
+struct bedGraphChrom *chrom, *chromList = NULL;
+
+/* Collect lines in items on appropriate chromosomes. */
+struct bwgBedGraphItem *item;
+char *line;
+while (lineFileNextReal(lf, &line))
+    {
+    /* Check for end of section. */
+    if (stepTypeLine(line))
+        {
+	lineFileReuse(lf);
+	break;
+	}
+
+    /* Parse out our line and make sure it has exactly 4 columns. */
+    char *words[5];
+    int wordCount = chopLine(line, words);
+    lineFileExpectWords(lf, 4, wordCount);
+
+    /* Get chromosome. */
+    char *chromName = words[0];
+    chrom = hashFindVal(chromHash, chromName);
+    if (chrom == NULL)
+        {
+	lmAllocVar(chromHash->lm, chrom);
+	hashAddSaveName(chromHash, chromName, chrom, &chrom->name);
+	chrom->size = (chromSizeHash ? hashIntVal(chromSizeHash, chromName) : BIGNUM);
+	slAddHead(&chromList, chrom);
+	}
+
+    /* Convert to item and add to chromosome list. */
+    lmAllocVar(lm, item);
+    item->start = lineFileNeedNum(lf, words, 1);
+    item->end = lineFileNeedNum(lf, words, 2);
+    item->val = lineFileNeedDouble(lf, words, 3);
+
+    /* Do sanity checking on coordinates. */
+    if (item->start > item->end)
+        errAbort("bedGraph error: start (%u) after end line (%u) %d of %s.", 
+		item->start, item->end, lf->lineIx, lf->fileName);
+    if (item->end > chrom->size)
+	{
+        warn("bedGraph error line %d of %s: chromosome %s has size %u but item ends at %u",
+	        lf->lineIx, lf->fileName, chrom->name, chrom->size, item->end);
+	if (!clipDontDie)
+	    noWarnAbort();
+	}
+    else
+	{
+	slAddHead(&chrom->itemList, item);
+	}
+    }
+slSort(&chromList, bedGraphChromCmpName);
+
+/* Loop through each chromosome and output the item list, broken into sections
+ * for that chrom. */
+for (chrom = chromList; chrom != NULL; chrom = chrom->next)
+    {
+    slSort(&chrom->itemList, bwgBedGraphItemCmp);
+
+    /* Check to make sure no overlap between items. */
+    struct bwgBedGraphItem *item = chrom->itemList, *nextItem;
+    for (nextItem = item->next; nextItem != NULL; nextItem = nextItem->next)
+        {
+	if (item->end > nextItem->start)
+	    errAbort("Overlap between %s %d %d and %s %d %d.\nPlease remove overlaps and try again",
+	        chrom->name, item->start, item->end, chrom->name, nextItem->start, nextItem->end);
+	item = nextItem;
+	}
+
+    /* Break up into sections of no more than items-per-slot size. */
+    struct bwgBedGraphItem *startItem, *endItem, *nextStartItem = chrom->itemList;
+    for (startItem = chrom->itemList; startItem != NULL; startItem = nextStartItem)
+	{
+	/* Find end item of this section, and start item for next section.
+	 * Terminate list at end item. */
+	int sectionSize = 0;
+	int i;
+	endItem = startItem;
+	for (i=0; i<itemsPerSlot; ++i)
+	    {
+	    if (nextStartItem == NULL)
+		break;
+	    endItem = nextStartItem;
+	    nextStartItem = nextStartItem->next;
+	    ++sectionSize;
+	    }
+	endItem->next = NULL;
+
+	/* Fill in section and add it to section list. */
+	struct bwgSection *section;
+	lmAllocVar(lm, section);
+	section->chrom = cloneString(chrom->name);
+	section->start = startItem->start;
+	section->end = endItem->end;
+	section->type = bwgTypeBedGraph;
+	section->items.bedGraphList = startItem;
+	section->itemCount = sectionSize;
+	slAddHead(pSectionList, section);
+	}
+    }
+
+/* Free up hash, no longer needed. Free's chromList as a side effect since chromList is in 
+ * hash's memory. */
+hashFree(&chromHash);
+chromList = NULL;
+}
+
+void bwgMakeChromInfo(struct bwgSection *sectionList, struct hash *chromSizeHash,
+	int *retChromCount, struct bbiChromInfo **retChromArray,
+	int *retMaxChromNameSize)
+/* Fill in chromId field in sectionList.  Return array of chromosome name/ids. 
+ * The chromSizeHash is keyed by name, and has int values. */
+{
+/* Build up list of unique chromosome names. */
+struct bwgSection *section;
+char *chromName = "";
+int chromCount = 0;
+int maxChromNameSize = 0;
+struct slRef *uniq, *uniqList = NULL;
+for (section = sectionList; section != NULL; section = section->next)
+    {
+    if (!sameString(section->chrom, chromName))
+        {
+	chromName = section->chrom;
+	refAdd(&uniqList, chromName);
+	++chromCount;
+	int len = strlen(chromName);
+	if (len > maxChromNameSize)
+	    maxChromNameSize = len;
+	}
+    section->chromId = chromCount-1;
+    }
+slReverse(&uniqList);
+
+/* Allocate and fill in results array. */
+struct bbiChromInfo *chromArray;
+AllocArray(chromArray, chromCount);
+int i;
+for (i = 0, uniq = uniqList; i < chromCount; ++i, uniq = uniq->next)
+    {
+    chromArray[i].name = uniq->val;
+    chromArray[i].id = i;
+    chromArray[i].size = hashIntVal(chromSizeHash, uniq->val);
+    }
+
+/* Clean up, set return values and go home. */
+slFreeList(&uniqList);
+*retChromCount = chromCount;
+*retChromArray = chromArray;
+*retMaxChromNameSize = maxChromNameSize;
+}
+
+int bwgAverageResolution(struct bwgSection *sectionList)
+/* Return the average resolution seen in sectionList. */
+{
+if (sectionList == NULL)
+    return 1;
+bits64 totalRes = 0;
+bits32 sectionCount = 0;
+struct bwgSection *section;
+int i;
+for (section = sectionList; section != NULL; section = section->next)
+    {
+    int sectionRes = 0;
+    switch (section->type)
+        {
+	case bwgTypeBedGraph:
+	    {
+	    struct bwgBedGraphItem *item;
+	    sectionRes = BIGNUM;
+	    for (item = section->items.bedGraphList; item != NULL; item = item->next)
+		{
+		int size = item->end - item->start;
+		if (sectionRes > size)
+		    sectionRes = size;
+		}
+	    break;
+	    }
+	case bwgTypeVariableStep:
+	    {
+	    struct bwgVariableStepPacked *items = section->items.variableStepPacked, *prev;
+	    bits32 smallestGap = BIGNUM;
+	    for (i=1; i<section->itemCount; ++i)
+	        {
+		prev = items;
+		items += 1;
+		bits32 gap = items->start - prev->start;
+		if (smallestGap > gap)
+		    smallestGap = gap;
+		}
+	    if (smallestGap != BIGNUM)
+	        sectionRes = smallestGap;
+	    else
+	        sectionRes = section->itemSpan;
+	    break;
+	    }
+	case bwgTypeFixedStep:
+	    {
+	    sectionRes = section->itemStep;
+	    break;
+	    }
+	default:
+	    internalErr();
+	    break;
+	}
+    totalRes += sectionRes;
+    ++sectionCount;
+    }
+return (totalRes + sectionCount/2)/sectionCount;
+}
+
+#define bwgSectionHeaderSize 24	/* Size of section header in file. */
+
+static int bwgItemSize(enum bwgSectionType type)
+/* Return size of an item inside a particular section. */
+{
+switch (type)
+    {
+    case bwgTypeBedGraph:
+	return 2*sizeof(bits32) + sizeof(float);
+	break;
+    case bwgTypeVariableStep:
+	return sizeof(bits32) + sizeof(float);
+	break;
+    case bwgTypeFixedStep:
+	return sizeof(float);
+	break;
+    default:
+        internalErr();
+	return 0;
+    }
+}
+
+static int bwgSectionSize(struct bwgSection *section)
+/* Return size (on disk) of section. */
+{
+return bwgSectionHeaderSize + bwgItemSize(section->type) * section->itemCount;
+}
+
+static bits64 bwgTotalSectionSize(struct bwgSection *sectionList)
+/* Return total size of all sections. */
+{
+bits64 total = 0;
+struct bwgSection *section;
+for (section = sectionList; section != NULL; section = section->next)
+    total += bwgSectionSize(section);
+return total;
+}
+
+static void bwgReduceBedGraph(struct bwgSection *section, bits32 chromSize, int reduction, 
+	struct bbiSummary **pOutList)
+/*Reduce a bedGraph section onto outList. */
+{
+struct bwgBedGraphItem *item = section->items.bedGraphList;
+for (item = section->items.bedGraphList; item != NULL; item = item->next)
+    {
+    bbiAddRangeToSummary(section->chromId, chromSize, item->start, item->end, 
+    	item->val, reduction, pOutList);
+    }
+}
+
+static void bwgReduceVariableStep(struct bwgSection *section, bits32 chromSize, int reduction, 
+	struct bbiSummary **pOutList)
+/*Reduce a variableStep section onto outList. */
+{
+struct bwgVariableStepPacked *items = section->items.variableStepPacked;
+int i;
+for (i=0; i<section->itemCount; ++i)
+    {
+    bbiAddRangeToSummary(section->chromId, chromSize, 
+    	items->start, items->start + section->itemSpan, items->val, reduction, pOutList);
+    items += 1;
+    }
+}
+
+static void bwgReduceFixedStep(struct bwgSection *section, bits32 chromSize, int reduction, 
+	struct bbiSummary **pOutList)
+/*Reduce a fixedStep section onto outList. */
+{
+struct bwgFixedStepPacked *items = section->items.fixedStepPacked;
+int start = section->start;
+int i;
+for (i=0; i<section->itemCount; ++i)
+    {
+    bbiAddRangeToSummary(section->chromId, chromSize, start, start + section->itemSpan, items->val, 
+    	reduction, pOutList);
+    start += section->itemStep;
+    items += 1;
+    }
+}
+
+struct bbiSummary *bwgReduceSectionList(struct bwgSection *sectionList, 
+	struct bbiChromInfo *chromInfoArray, int reduction)
+/* Return summary of section list reduced by given amount. */
+{
+struct bbiSummary *outList = NULL;
+struct bwgSection *section = NULL;
+
+/* Loop through input section list reducing into outList. */
+for (section = sectionList; section != NULL; section = section->next)
+    {
+    bits32 chromSize = chromInfoArray[section->chromId].size;
+    switch (section->type)
+        {
+	case bwgTypeBedGraph:
+	    bwgReduceBedGraph(section, chromSize, reduction, &outList);
+	    break;
+	case bwgTypeVariableStep:
+	    bwgReduceVariableStep(section, chromSize, reduction, &outList);
+	    break;
+	case bwgTypeFixedStep:
+	    bwgReduceFixedStep(section, chromSize, reduction, &outList);
+	    break;
+	default:
+	    internalErr();
+	    return 0;
+	}
+    }
+slReverse(&outList);
+return outList;
+}
+
+static void bwgCreate(struct bwgSection *sectionList, struct hash *chromSizeHash, 
+	int blockSize, int itemsPerSlot, boolean doCompress, char *fileName)
+/* Create a bigWig file out of a sorted sectionList. */
+{
+bits64 sectionCount = slCount(sectionList);
+FILE *f = mustOpen(fileName, "wb");
+bits32 sig = bigWigSig;
+bits16 version = bbiCurrentVersion;
+bits16 summaryCount = 0;
+bits16 reserved16 = 0;
+bits32 reserved32 = 0;
+bits64 reserved64 = 0;
+bits64 dataOffset = 0, dataOffsetPos;
+bits64 indexOffset = 0, indexOffsetPos;
+bits64 chromTreeOffset = 0, chromTreeOffsetPos;
+bits64 totalSummaryOffset = 0, totalSummaryOffsetPos;
+bits32 uncompressBufSize = 0;
+bits64 uncompressBufSizePos;
+struct bbiSummary *reduceSummaries[10];
+bits32 reductionAmounts[10];
+bits64 reductionDataOffsetPos[10];
+bits64 reductionDataOffsets[10];
+bits64 reductionIndexOffsets[10];
+int i;
+
+/* Figure out chromosome ID's. */
+struct bbiChromInfo *chromInfoArray;
+int chromCount, maxChromNameSize;
+bwgMakeChromInfo(sectionList, chromSizeHash, &chromCount, &chromInfoArray, &maxChromNameSize);
+
+/* Figure out initial summary level - starting with a summary 10 times the amount
+ * of the smallest item.  See if summarized data is smaller than half input data, if
+ * not bump up reduction by a factor of 2 until it is, or until further summarying
+ * yeilds no size reduction. */
+int  minRes = bwgAverageResolution(sectionList);
+int initialReduction = minRes*10;
+bits64 fullSize = bwgTotalSectionSize(sectionList);
+bits64 maxReducedSize = fullSize/2;
+struct bbiSummary *firstSummaryList = NULL, *summaryList = NULL;
+bits64 lastSummarySize = 0, summarySize;
+for (;;)
+    {
+    summaryList = bwgReduceSectionList(sectionList, chromInfoArray, initialReduction);
+    bits64 summarySize = bbiTotalSummarySize(summaryList);
+    if (doCompress)
+	{
+        summarySize *= 2;	// Compensate for summary not compressing as well as primary data
+	}
+    if (summarySize >= maxReducedSize && summarySize != lastSummarySize)
+        {
+	/* Need to do more reduction.  First scale reduction by amount that it missed
+	 * being small enough last time, with an extra 10% for good measure.  Then
+	 * just to keep from spinning through loop two many times, make sure this is
+	 * at least 2x the previous reduction. */
+	int nextReduction = 1.1 * initialReduction * summarySize / maxReducedSize;
+	if (nextReduction < initialReduction*2)
+	    nextReduction = initialReduction*2;
+	initialReduction = nextReduction;
+	bbiSummaryFreeList(&summaryList);
+	lastSummarySize = summarySize;
+	}
+    else
+        break;
+    }
+summaryCount = 1;
+reduceSummaries[0] = firstSummaryList = summaryList;
+reductionAmounts[0] = initialReduction;
+
+/* Now calculate up to 10 levels of further summary. */
+bits64 reduction = initialReduction;
+for (i=0; i<ArraySize(reduceSummaries)-1; i++)
+    {
+    reduction *= 4;
+    if (reduction > 1000000000)
+        break;
+    summaryList = bbiReduceSummaryList(reduceSummaries[summaryCount-1], chromInfoArray, 
+    	reduction);
+    summarySize = bbiTotalSummarySize(summaryList);
+    if (summarySize != lastSummarySize)
+        {
+ 	reduceSummaries[summaryCount] = summaryList;
+	reductionAmounts[summaryCount] = reduction;
+	++summaryCount;
+	}
+    int summaryItemCount = slCount(summaryList);
+    if (summaryItemCount <= chromCount)
+        break;
+    }
+
+/* Write fixed header. */
+writeOne(f, sig);
+writeOne(f, version);
+writeOne(f, summaryCount);
+chromTreeOffsetPos = ftell(f);
+writeOne(f, chromTreeOffset);
+dataOffsetPos = ftell(f);
+writeOne(f, dataOffset);
+indexOffsetPos = ftell(f);
+writeOne(f, indexOffset);
+writeOne(f, reserved16);  /* fieldCount */
+writeOne(f, reserved16);  /* definedFieldCount */
+writeOne(f, reserved64);  /* autoSqlOffset. */
+totalSummaryOffsetPos = ftell(f);
+writeOne(f, totalSummaryOffset);
+uncompressBufSizePos = ftell(f);
+writeOne(f, uncompressBufSize);
+for (i=0; i<2; ++i)
+    writeOne(f, reserved32);
+
+/* Write summary headers */
+for (i=0; i<summaryCount; ++i)
+    {
+    writeOne(f, reductionAmounts[i]);
+    writeOne(f, reserved32);
+    reductionDataOffsetPos[i] = ftell(f);
+    writeOne(f, reserved64);	// Fill in with data offset later
+    writeOne(f, reserved64);	// Fill in with index offset later
+    }
+
+/* Write dummy summary */
+struct bbiSummaryElement totalSum;
+ZeroVar(&totalSum);
+totalSummaryOffset = ftell(f);
+bbiSummaryElementWrite(f, &totalSum);
+
+/* Write chromosome bPlusTree */
+chromTreeOffset = ftell(f);
+int chromBlockSize = min(blockSize, chromCount);
+bptFileBulkIndexToOpenFile(chromInfoArray, sizeof(chromInfoArray[0]), chromCount, chromBlockSize,
+    bbiChromInfoKey, maxChromNameSize, bbiChromInfoVal, 
+    sizeof(chromInfoArray[0].id) + sizeof(chromInfoArray[0].size), 
+    f);
+
+/* Write out data section count and sections themselves. */
+dataOffset = ftell(f);
+writeOne(f, sectionCount);
+struct bwgSection *section;
+for (section = sectionList; section != NULL; section = section->next)
+    {
+    bits32 uncSizeOne = bwgSectionWrite(section, doCompress, f);
+    if (uncSizeOne > uncompressBufSize)
+         uncompressBufSize = uncSizeOne;
+    }
+
+/* Write out index - creating a temporary array rather than list representation of
+ * sections in the process. */
+indexOffset = ftell(f);
+struct bwgSection **sectionArray;
+AllocArray(sectionArray, sectionCount);
+for (section = sectionList, i=0; section != NULL; section = section->next, ++i)
+    sectionArray[i] = section;
+cirTreeFileBulkIndexToOpenFile(sectionArray, sizeof(sectionArray[0]), sectionCount,
+    blockSize, 1, NULL, bwgSectionFetchKey, bwgSectionFetchOffset, 
+    indexOffset, f);
+freez(&sectionArray);
+
+/* Write out summary sections. */
+verbose(2, "bwgCreate writing %d summaries\n", summaryCount);
+for (i=0; i<summaryCount; ++i)
+    {
+    reductionDataOffsets[i] = ftell(f);
+    reductionIndexOffsets[i] = bbiWriteSummaryAndIndex(reduceSummaries[i], blockSize, itemsPerSlot, doCompress, f);
+    verbose(3, "wrote %d of data, %d of index on level %d\n", (int)(reductionIndexOffsets[i] - reductionDataOffsets[i]), (int)(ftell(f) - reductionIndexOffsets[i]), i);
+    }
+
+/* Calculate summary */
+struct bbiSummary *sum = firstSummaryList;
+if (sum != NULL)
+    {
+    totalSum.validCount = sum->validCount;
+    totalSum.minVal = sum->minVal;
+    totalSum.maxVal = sum->maxVal;
+    totalSum.sumData = sum->sumData;
+    totalSum.sumSquares = sum->sumSquares;
+    for (sum = sum->next; sum != NULL; sum = sum->next)
+	{
+	totalSum.validCount += sum->validCount;
+	if (sum->minVal < totalSum.minVal) totalSum.minVal = sum->minVal;
+	if (sum->maxVal > totalSum.maxVal) totalSum.maxVal = sum->maxVal;
+	totalSum.sumData += sum->sumData;
+	totalSum.sumSquares += sum->sumSquares;
+	}
+    /* Write real summary */
+    fseek(f, totalSummaryOffset, SEEK_SET);
+    bbiSummaryElementWrite(f, &totalSum);
+    }
+else
+    totalSummaryOffset = 0;	/* Edge case, no summary. */
+
+/* Go back and fill in offsets properly in header. */
+fseek(f, dataOffsetPos, SEEK_SET);
+writeOne(f, dataOffset);
+fseek(f, indexOffsetPos, SEEK_SET);
+writeOne(f, indexOffset);
+fseek(f, chromTreeOffsetPos, SEEK_SET);
+writeOne(f, chromTreeOffset);
+fseek(f, totalSummaryOffsetPos, SEEK_SET);
+writeOne(f, totalSummaryOffset);
+
+if (doCompress)
+    {
+    int maxZoomUncompSize = itemsPerSlot * sizeof(struct bbiSummaryOnDisk);
+    if (maxZoomUncompSize > uncompressBufSize)
+	uncompressBufSize = maxZoomUncompSize;
+    fseek(f, uncompressBufSizePos, SEEK_SET);
+    writeOne(f, uncompressBufSize);
+    }
+
+/* Also fill in offsets in zoom headers. */
+for (i=0; i<summaryCount; ++i)
+    {
+    fseek(f, reductionDataOffsetPos[i], SEEK_SET);
+    writeOne(f, reductionDataOffsets[i]);
+    writeOne(f, reductionIndexOffsets[i]);
+    }
+
+/* Write end signature. */
+fseek(f, 0L, SEEK_END);
+writeOne(f, sig);
+
+/* Clean up */
+freez(&chromInfoArray);
+carefulClose(&f);
+}
+
+struct bwgSection *bwgParseWig(
+	char *fileName,       /* Name of ascii wig file. */
+	boolean clipDontDie,  /* Skip items outside chromosome rather than aborting. */
+	struct hash *chromSizeHash,  /* If non-NULL items checked to be inside chromosome. */
+	int maxSectionSize,   /* Biggest size of a section.  100 - 100,000 is usual range. */
+	struct lm *lm)	      /* Memory pool to allocate from. */
+/* Parse out ascii wig file - allocating memory in lm. */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *line;
+struct bwgSection *sectionList = NULL;
+
+/* remove initial browser and track lines */
+lineFileRemoveInitialCustomTrackLines(lf);
+
+while (lineFileNextReal(lf, &line))
+    {
+    verbose(2, "processing %s\n", line);
+    if (stringIn("chrom=", line))
+	parseSteppedSection(lf, clipDontDie, chromSizeHash, line, lm, maxSectionSize, &sectionList);
+    else
+        {
+	/* Check for bed... */
+	char *dupe = cloneString(line);
+	char *words[5];
+	int wordCount = chopLine(dupe, words);
+	if (wordCount != 4)
+	    errAbort("Unrecognized line %d of %s:\n%s\n", lf->lineIx, lf->fileName, line);
+
+	/* Parse out a bed graph line just to check numerical format. */
+	char *chrom = words[0];
+	int start = lineFileNeedNum(lf, words, 1);
+	int end = lineFileNeedNum(lf, words, 2);
+	double val = lineFileNeedDouble(lf, words, 3);
+	verbose(2, "bedGraph %s:%d-%d@%g\n", chrom, start, end, val);
+
+	/* Push back line and call bed parser. */
+	lineFileReuse(lf);
+	parseBedGraphSection(lf, clipDontDie, chromSizeHash, lm, maxSectionSize, &sectionList);
+	}
+    }
+slSort(&sectionList, bwgSectionCmp);
+
+/* Check for overlap at section level. */
+struct bwgSection *section, *nextSection;
+for (section = sectionList; section != NULL; section = nextSection)
+    {
+    nextSection = section->next;
+    if (nextSection != NULL)
+        {
+	if (sameString(section->chrom, nextSection->chrom))
+	    {
+	    if (section->end > nextSection->start)
+	        {
+		errAbort("There's more than one value for %s base %d (in coordinates that start with 1).\n",
+		    section->chrom, nextSection->start+1);
+		}
+	    }
+	}
+    }
+
+return sectionList;
+}
+
+void bigWigFileCreate(
+	char *inName, 		/* Input file in ascii wiggle format. */
+	char *chromSizes, 	/* Two column tab-separated file: <chromosome> <size>. */
+	int blockSize,		/* Number of items to bundle in r-tree.  1024 is good. */
+	int itemsPerSlot,	/* Number of items in lowest level of tree.  512 is good. */
+	boolean clipDontDie,	/* If TRUE then clip items off end of chrom rather than dying. */
+	boolean compress,	/* If TRUE then compress data. */
+	char *outName)
+/* Convert ascii format wig file (in fixedStep, variableStep or bedGraph format) 
+ * to binary big wig format. */
+{
+/* This code needs to agree with code in two other places currently - bigBedFileCreate,
+ * and bbiFileOpen.  I'm thinking of refactoring to share at least between
+ * bigBedFileCreate and bigWigFileCreate.  It'd be great so it could be structured
+ * so that it could send the input in one chromosome at a time, and send in the zoom
+ * stuff only after all the chromosomes are done.  This'd potentially reduce the memory
+ * footprint by a factor of 2 or 4.  Still, for now it works. -JK */
+struct hash *chromSizeHash = bbiChromSizesFromFile(chromSizes);
+struct lm *lm = lmInit(0);
+struct bwgSection *sectionList = bwgParseWig(inName, clipDontDie, chromSizeHash, itemsPerSlot, lm);
+if (sectionList == NULL)
+    errAbort("%s is empty of data", inName);
+bwgCreate(sectionList, chromSizeHash, blockSize, itemsPerSlot, compress, outName);
+lmCleanup(&lm);
+}
+
diff --git a/lib/bwgQuery.c b/lib/bwgQuery.c
new file mode 100644
index 0000000..f8e7582
--- /dev/null
+++ b/lib/bwgQuery.c
@@ -0,0 +1,400 @@
+/* bwgQuery - implements the query side of bigWig.  See bwgInternal.h for definition of file
+ * format. */
+
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "localmem.h"
+#include "options.h"
+#include "sig.h"
+#include "sqlNum.h"
+#include "obscure.h"
+#include "dystring.h"
+#include "bPlusTree.h"
+#include "cirTree.h"
+#include "rangeTree.h"
+#include "udc.h"
+#include "zlibFace.h"
+#include "bbiFile.h"
+#include "bwgInternal.h"
+#include "bigWig.h"
+#include "bigBed.h"
+
+
+struct bbiFile *bigWigFileOpen(char *fileName)
+/* Open up big wig file. */
+{
+return bbiFileOpen(fileName, bigWigSig, "big wig");
+}
+
+boolean bigWigFileCheckSigs(char *fileName)
+/* check file signatures at beginning and end of file */
+{
+return bbiFileCheckSigs(fileName, bigWigSig, "big wig");
+}
+
+#ifdef OLD
+static void bwgSectionHeadRead(struct bbiFile *bwf, struct bwgSectionHead *head)
+/* Read section header. */
+{
+struct udcFile *udc = bwf->udc;
+boolean isSwapped = bwf->isSwapped;
+head->chromId = udcReadBits32(udc, isSwapped);
+head->start = udcReadBits32(udc, isSwapped);
+head->end = udcReadBits32(udc, isSwapped);
+head->itemStep = udcReadBits32(udc, isSwapped);
+head->itemSpan = udcReadBits32(udc, isSwapped);
+head->type = udcGetChar(udc);
+head->reserved = udcGetChar(udc);
+head->itemCount = udcReadBits16(udc, isSwapped);
+}
+#endif /* OLD */
+
+void bwgSectionHeadFromMem(char **pPt, struct bwgSectionHead *head, boolean isSwapped)
+/* Read section header. */
+{
+char *pt = *pPt;
+head->chromId = memReadBits32(&pt, isSwapped);
+head->start = memReadBits32(&pt, isSwapped);
+head->end = memReadBits32(&pt, isSwapped);
+head->itemStep = memReadBits32(&pt, isSwapped);
+head->itemSpan = memReadBits32(&pt, isSwapped);
+head->type = *pt++;
+head->reserved = *pt++;
+head->itemCount = memReadBits16(&pt, isSwapped);
+*pPt = pt;
+}
+
+static int bigWigBlockDumpIntersectingRange(boolean isSwapped, char *blockPt, char *blockEnd, 
+	char *chrom, bits32 rangeStart, bits32 rangeEnd, int maxCount, FILE *out)
+/* Print out info on parts of block that intersect start-end, block starting at current position. */
+{
+struct bwgSectionHead head;
+bwgSectionHeadFromMem(&blockPt, &head, isSwapped);
+bits16 i;
+float val;
+int outCount = 0;
+
+switch (head.type)
+    {
+    case bwgTypeBedGraph:
+	{
+	fprintf(out, "#bedGraph section %s:%u-%u\n",  chrom, head.start, head.end);
+	for (i=0; i<head.itemCount; ++i)
+	    {
+	    bits32 start = memReadBits32(&blockPt, isSwapped);
+	    bits32 end = memReadBits32(&blockPt, isSwapped);
+	    val = memReadFloat(&blockPt, isSwapped);
+	    if (rangeIntersection(rangeStart, rangeEnd, start, end) > 0)
+		{
+		fprintf(out, "%s\t%u\t%u\t%g\n", chrom, start, end, val);
+		++outCount;
+		if (maxCount != 0 && outCount >= maxCount)
+		    break;
+		}
+	    }
+	break;
+	}
+    case bwgTypeVariableStep:
+	{
+	fprintf(out, "variableStep chrom=%s span=%u\n", chrom, head.itemSpan);
+	for (i=0; i<head.itemCount; ++i)
+	    {
+	    bits32 start = memReadBits32(&blockPt, isSwapped);
+	    val = memReadFloat(&blockPt, isSwapped);
+	    if (rangeIntersection(rangeStart, rangeEnd, start, start+head.itemSpan) > 0)
+		{
+		fprintf(out, "%u\t%g\n", start+1, val);
+		++outCount;
+		if (maxCount != 0 && outCount >= maxCount)
+		    break;
+		}
+	    }
+	break;
+	}
+    case bwgTypeFixedStep:
+	{
+	boolean gotStart = FALSE;
+	bits32 start = head.start;
+	for (i=0; i<head.itemCount; ++i)
+	    {
+	    val = memReadFloat(&blockPt, isSwapped);
+	    if (rangeIntersection(rangeStart, rangeEnd, start, start+head.itemSpan) > 0)
+	        {
+		if (!gotStart)
+		    {
+		    fprintf(out, "fixedStep chrom=%s start=%u step=%u span=%u\n", 
+			    chrom, start+1, head.itemStep, head.itemSpan);
+		    gotStart = TRUE;
+		    }
+		fprintf(out, "%g\n", val);
+		++outCount;
+		if (maxCount != 0 && outCount >= maxCount)
+		    break;
+		}
+	    start += head.itemStep;
+	    }
+	break;
+	}
+    default:
+        internalErr();
+	break;
+    }
+assert( (maxCount != 0 && outCount >= maxCount) || (blockPt == blockEnd));
+return outCount;
+}
+
+struct bbiInterval *bigWigIntervalQuery(struct bbiFile *bwf, char *chrom, bits32 start, bits32 end,
+	struct lm *lm)
+/* Get data for interval.  Return list allocated out of lm. */
+{
+if (bwf->typeSig != bigWigSig)
+   errAbort("Trying to do bigWigIntervalQuery on a non big-wig file.");
+bbiAttachUnzoomedCir(bwf);
+struct bbiInterval *el, *list = NULL;
+struct fileOffsetSize *blockList = bbiOverlappingBlocks(bwf, bwf->unzoomedCir, 
+	chrom, start, end, NULL);
+struct fileOffsetSize *block, *beforeGap, *afterGap;
+struct udcFile *udc = bwf->udc;
+boolean isSwapped = bwf->isSwapped;
+float val;
+int i;
+
+/* Set up for uncompression optionally. */
+char *uncompressBuf = NULL;
+if (bwf->uncompressBufSize > 0)
+    uncompressBuf = needLargeMem(bwf->uncompressBufSize);
+
+/* This loop is a little complicated because we merge the read requests for efficiency, but we 
+ * have to then go back through the data one unmerged block at a time. */
+for (block = blockList; block != NULL; )
+    {
+    /* Find contigious blocks and read them into mergedBuf. */
+    fileOffsetSizeFindGap(block, &beforeGap, &afterGap);
+    bits64 mergedOffset = block->offset;
+    bits64 mergedSize = beforeGap->offset + beforeGap->size - mergedOffset;
+    udcSeek(udc, mergedOffset);
+    char *mergedBuf = needLargeMem(mergedSize);
+    udcMustRead(udc, mergedBuf, mergedSize);
+    char *blockBuf = mergedBuf;
+
+    /* Loop through individual blocks within merged section. */
+    for (;block != afterGap; block = block->next)
+        {
+	/* Uncompress if necessary. */
+	char *blockPt, *blockEnd;
+	if (uncompressBuf)
+	    {
+	    blockPt = uncompressBuf;
+	    int uncSize = zUncompress(blockBuf, block->size, uncompressBuf, bwf->uncompressBufSize);
+	    blockEnd = blockPt + uncSize;
+	    }
+	else
+	    {
+	    blockPt = blockBuf;
+	    blockEnd = blockPt + block->size;
+	    }
+
+	/* Deal with insides of block. */
+	struct bwgSectionHead head;
+	bwgSectionHeadFromMem(&blockPt, &head, isSwapped);
+	switch (head.type)
+	    {
+	    case bwgTypeBedGraph:
+		{
+		for (i=0; i<head.itemCount; ++i)
+		    {
+		    bits32 s = memReadBits32(&blockPt, isSwapped);
+		    bits32 e = memReadBits32(&blockPt, isSwapped);
+		    val = memReadFloat(&blockPt, isSwapped);
+		    if (s < start) s = start;
+		    if (e > end) e = end;
+		    if (s < e)
+			{
+			lmAllocVar(lm, el);
+			el->start = s;
+			el->end = e;
+			el->val = val;
+			slAddHead(&list, el);
+			}
+		    }
+		break;
+		}
+	    case bwgTypeVariableStep:
+		{
+		for (i=0; i<head.itemCount; ++i)
+		    {
+		    bits32 s = memReadBits32(&blockPt, isSwapped);
+		    bits32 e = s + head.itemSpan;
+		    val = memReadFloat(&blockPt, isSwapped);
+		    if (s < start) s = start;
+		    if (e > end) e = end;
+		    if (s < e)
+			{
+			lmAllocVar(lm, el);
+			el->start = s;
+			el->end = e;
+			el->val = val;
+			slAddHead(&list, el);
+			}
+		    }
+		break;
+		}
+	    case bwgTypeFixedStep:
+		{
+		bits32 s = head.start;
+		bits32 e = s + head.itemSpan;
+		for (i=0; i<head.itemCount; ++i)
+		    {
+		    val = memReadFloat(&blockPt, isSwapped);
+		    bits32 clippedS = s, clippedE = e;
+		    if (clippedS < start) clippedS = start;
+		    if (clippedE > end) clippedE = end;
+		    if (clippedS < clippedE)
+			{
+			lmAllocVar(lm, el);
+			el->start = clippedS;
+			el->end = clippedE;
+			el->val = val;
+			slAddHead(&list, el);
+			}
+		    s += head.itemStep;
+		    e += head.itemStep;
+		    }
+		break;
+		}
+	    default:
+		internalErr();
+		break;
+	    }
+	assert(blockPt == blockEnd);
+	blockBuf += block->size;
+	}
+    freeMem(mergedBuf);
+    }
+freeMem(uncompressBuf);
+slFreeList(&blockList);
+slReverse(&list);
+return list;
+}
+
+int bigWigIntervalDump(struct bbiFile *bwf, char *chrom, bits32 start, bits32 end, int maxCount,
+	FILE *out)
+/* Print out info on bigWig parts that intersect chrom:start-end.   Set maxCount to 0 if you 
+ * don't care how many are printed.  Returns number printed. */
+{
+if (bwf->typeSig != bigWigSig)
+   errAbort("Trying to do bigWigIntervalDump on a non big-wig file.");
+bbiAttachUnzoomedCir(bwf);
+struct fileOffsetSize *blockList = bbiOverlappingBlocks(bwf, bwf->unzoomedCir, 
+	chrom, start, end, NULL);
+struct fileOffsetSize *block, *beforeGap, *afterGap;
+struct udcFile *udc = bwf->udc;
+int printCount = 0;
+
+/* Set up for uncompression optionally. */
+char *uncompressBuf = NULL;
+if (bwf->uncompressBufSize > 0)
+    uncompressBuf = needLargeMem(bwf->uncompressBufSize);
+
+/* This loop is a little complicated because we merge the read requests for efficiency, but we 
+ * have to then go back through the data one unmerged block at a time. */
+for (block = blockList; block != NULL; )
+    {
+    /* Find contigious blocks and read them into mergedBuf. */
+    fileOffsetSizeFindGap(block, &beforeGap, &afterGap);
+    bits64 mergedOffset = block->offset;
+    bits64 mergedSize = beforeGap->offset + beforeGap->size - mergedOffset;
+    udcSeek(udc, mergedOffset);
+    char *mergedBuf = needLargeMem(mergedSize);
+    udcMustRead(udc, mergedBuf, mergedSize);
+    char *blockBuf = mergedBuf;
+
+    /* Loop through individual blocks within merged section. */
+    for (;block != afterGap; block = block->next)
+        {
+	/* Uncompress if necessary. */
+	char *blockPt, *blockEnd;
+	if (uncompressBuf)
+	    {
+	    blockPt = uncompressBuf;
+	    int uncSize = zUncompress(blockBuf, block->size, uncompressBuf, bwf->uncompressBufSize);
+	    blockEnd = blockPt + uncSize;
+	    }
+	else
+	    {
+	    blockPt = blockBuf;
+	    blockEnd = blockPt + block->size;
+	    }
+
+	/* Do the actual dump. */
+	int oneCount = bigWigBlockDumpIntersectingRange(bwf->isSwapped, blockPt, blockEnd, 
+		chrom, start, end, maxCount, out);
+
+	/* Keep track of how many dumped, not exceeding maximum. */
+	printCount += oneCount;
+	if (maxCount != 0)
+	    {
+	    if (oneCount >= maxCount)
+		{
+		block = NULL;	 // we want to drop out of the outer loop too
+		break;
+		}
+
+	    maxCount -= oneCount;
+	    }
+	blockBuf += block->size;
+	}
+    freeMem(mergedBuf);
+    }
+freeMem(uncompressBuf);
+
+slFreeList(&blockList);
+return printCount;
+}
+
+boolean bigWigSummaryArray(struct bbiFile *bwf, char *chrom, bits32 start, bits32 end,
+	enum bbiSummaryType summaryType, int summarySize, double *summaryValues)
+/* Fill in summaryValues with  data from indicated chromosome range in bigWig file.
+ * Be sure to initialize summaryValues to a default value, which will not be touched
+ * for regions without data in file.  (Generally you want the default value to either
+ * be 0.0 or nan("") depending on the application.)  Returns FALSE if no data
+ * at that position. */
+{
+boolean ret = bbiSummaryArray(bwf, chrom, start, end, bigWigIntervalQuery,
+	summaryType, summarySize, summaryValues);
+return ret;
+}
+
+boolean bigWigSummaryArrayExtended(struct bbiFile *bwf, char *chrom, bits32 start, bits32 end,
+	int summarySize, struct bbiSummaryElement *summary)
+/* Get extended summary information for summarySize evenely spaced elements into
+ * the summary array. */
+{
+boolean ret = bbiSummaryArrayExtended(bwf, chrom, start, end, bigWigIntervalQuery,
+	summarySize, summary);
+return ret;
+}
+
+double bigWigSingleSummary(struct bbiFile *bwf, char *chrom, int start, int end,
+    enum bbiSummaryType summaryType, double defaultVal)
+/* Return the summarized single value for a range. */
+{
+double arrayOfOne = defaultVal;
+bigWigSummaryArray(bwf, chrom, start, end, summaryType, 1, &arrayOfOne);
+return arrayOfOne;
+}
+
+boolean isBigWig(char *fileName)
+/* Peak at a file to see if it's bigWig */
+{
+FILE *f = mustOpen(fileName, "rb");
+bits32 sig;
+mustReadOne(f, sig);
+fclose(f);
+if (sig == bigWigSig)
+    return TRUE;
+sig = byteSwap32(sig);
+return sig == bigWigSig;
+}
+
diff --git a/lib/bwgValsOnChrom.c b/lib/bwgValsOnChrom.c
new file mode 100644
index 0000000..1a96b7a
--- /dev/null
+++ b/lib/bwgValsOnChrom.c
@@ -0,0 +1,214 @@
+/* bwgValsOnChrom - implements the bigWigValsOnChrom access to bigWig. */
+
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "localmem.h"
+#include "bits.h"
+#include "sig.h"
+#include "udc.h"
+#include "zlibFace.h"
+#include "bbiFile.h"
+#include "bwgInternal.h"
+#include "bigWig.h"
+
+struct bigWigValsOnChrom *bigWigValsOnChromNew()
+/* Allocate new empty bigWigValsOnChromStructure. */
+{
+return needMem(sizeof(struct bigWigValsOnChrom));
+}
+
+void bigWigValsOnChromFree(struct bigWigValsOnChrom **pChromVals)
+/* Free up bigWigValsOnChrom */
+{
+struct bigWigValsOnChrom *chromVals = *pChromVals;
+if (chromVals != NULL)
+    {
+    freeMem(chromVals->chrom);
+    freeMem(chromVals->valBuf);
+    freeMem(chromVals->covBuf);
+    freez(pChromVals);
+    }
+}
+
+static void fetchIntoBuf(struct bbiFile *bwf, char *chrom, bits32 start, bits32 end,
+	struct bigWigValsOnChrom *chromVals)
+/* Get data for interval.  Return list allocated out of lm. */
+{
+/* A lot of code duplicated with bigWigIntervalQuery, but here the clipping
+ * is simplified since always working across full chromosome, and the output is
+ * different.  Since both of these are in inner loops and speed critical, it's hard
+ * to factor out without perhaps making it worse than the bit of duplication. */
+if (bwf->typeSig != bigWigSig)
+   errAbort("Trying to do fetchIntoBuf on a non big-wig file.");
+bbiAttachUnzoomedCir(bwf);
+struct fileOffsetSize *blockList = bbiOverlappingBlocks(bwf, bwf->unzoomedCir, 
+	chrom, start, end, NULL);
+struct fileOffsetSize *block, *beforeGap, *afterGap;
+struct udcFile *udc = bwf->udc;
+boolean isSwapped = bwf->isSwapped;
+float val;
+int i;
+Bits *covBuf = chromVals->covBuf;
+double *valBuf = chromVals->valBuf;
+
+/* Set up for uncompression optionally. */
+char *uncompressBuf = NULL;
+if (bwf->uncompressBufSize > 0)
+    uncompressBuf = needLargeMem(bwf->uncompressBufSize);
+
+/* This loop is a little complicated because we merge the read requests for efficiency, but we 
+ * have to then go back through the data one unmerged block at a time. */
+for (block = blockList; block != NULL; )
+    {
+    /* Find contigious blocks and read them into mergedBuf. */
+    fileOffsetSizeFindGap(block, &beforeGap, &afterGap);
+    bits64 mergedOffset = block->offset;
+    bits64 mergedSize = beforeGap->offset + beforeGap->size - mergedOffset;
+    udcSeek(udc, mergedOffset);
+    char *mergedBuf = needLargeMem(mergedSize);
+    udcMustRead(udc, mergedBuf, mergedSize);
+    char *blockBuf = mergedBuf;
+
+    /* Loop through individual blocks within merged section. */
+    for (;block != afterGap; block = block->next)
+        {
+	/* Uncompress if necessary. */
+	char *blockPt, *blockEnd;
+	if (uncompressBuf)
+	    {
+	    blockPt = uncompressBuf;
+	    int uncSize = zUncompress(blockBuf, block->size, uncompressBuf, bwf->uncompressBufSize);
+	    blockEnd = blockPt + uncSize;
+	    }
+	else
+	    {
+	    blockPt = blockBuf;
+	    blockEnd = blockPt + block->size;
+	    }
+
+	/* Deal with insides of block. */
+	struct bwgSectionHead head;
+	bwgSectionHeadFromMem(&blockPt, &head, isSwapped);
+	switch (head.type)
+	    {
+	    case bwgTypeBedGraph:
+		{
+		for (i=0; i<head.itemCount; ++i)
+		    {
+		    bits32 s = memReadBits32(&blockPt, isSwapped);
+		    bits32 e = memReadBits32(&blockPt, isSwapped);
+		    bitSetRange(covBuf, s, e-s);
+		    val = memReadFloat(&blockPt, isSwapped);
+		    bits32 j;
+		    for (j=s; j<e; ++j)
+		        valBuf[j] = val;
+		    }
+		break;
+		}
+	    case bwgTypeVariableStep:
+		{
+		for (i=0; i<head.itemCount; ++i)
+		    {
+		    bits32 s = memReadBits32(&blockPt, isSwapped);
+		    val = memReadFloat(&blockPt, isSwapped);
+		    bitSetRange(covBuf, s, head.itemSpan);
+		    bits32 e = s + head.itemSpan;
+		    bits32 j;
+		    for (j=s; j<e; ++j)
+		        valBuf[j] = val;
+		    }
+		break;
+		}
+	    case bwgTypeFixedStep:
+		{
+		/* Do a little optimization for the most common and worst case - step1/span1 */
+		if (head.itemStep == 1 && head.itemSpan == 1)
+		    {
+		    bits32 s = head.start;
+		    bits32 e = head.end;
+		    bitSetRange(covBuf, s, e-s);
+		    bits32 j;
+		    for (j=s; j<e; ++j)
+		        valBuf[j] = memReadFloat(&blockPt, isSwapped);
+		    }
+		else
+		    {
+		    bits32 s = head.start;
+		    bits32 e = s + head.itemSpan;
+		    for (i=0; i<head.itemCount; ++i)
+			{
+			bitSetRange(covBuf, s, head.itemSpan);
+			val = memReadFloat(&blockPt, isSwapped);
+			bits32 j;
+			for (j=s; j<e; ++j)
+			    valBuf[j] = val;
+			s += head.itemStep;
+			e += head.itemStep;
+			}
+		    }
+		break;
+		}
+	    default:
+		internalErr();
+		break;
+	    }
+	assert(blockPt == blockEnd);
+	blockBuf += block->size;
+	}
+    freeMem(mergedBuf);
+    }
+freeMem(uncompressBuf);
+slFreeList(&blockList);
+}
+
+
+boolean bigWigValsOnChromFetchData(struct bigWigValsOnChrom *chromVals, char *chrom, 
+	struct bbiFile *bigWig)
+/* Fetch data for chromosome from bigWig. Returns FALSE if not data on that chrom. */
+{
+/* Fetch chromosome and size into self. */
+freeMem(chromVals->chrom);
+chromVals->chrom = cloneString(chrom);
+long chromSize = chromVals->chromSize = bbiChromSize(bigWig, chrom);
+
+if (chromSize <= 0)
+    return FALSE;
+
+/* Make sure buffers are big enough. */
+if (chromSize > chromVals->bufSize)
+    {
+    freeMem(chromVals->valBuf);
+    freeMem(chromVals->covBuf);
+    chromVals->valBuf = needHugeMem((sizeof(double))*chromSize);
+    chromVals->covBuf = bitAlloc(chromSize);
+    chromVals->bufSize = chromSize;
+    }
+
+/* Zero out buffers */
+bitClear(chromVals->covBuf, chromSize);
+double *valBuf = chromVals->valBuf;
+int i;
+for (i=0; i<chromSize; ++i)
+    valBuf[i] = 0.0;
+
+fetchIntoBuf(bigWig, chrom, 0, chromSize, chromVals);
+
+#ifdef OLD
+/* Fetch intervals for this chromosome and fold into buffers. */
+struct lm *lm = lmInit(0);
+struct bbiInterval *iv, *ivList = bigWigIntervalQuery(bigWig, chrom, 0, chromSize, lm);
+for (iv = ivList; iv != NULL; iv = iv->next)
+    {
+    double val = iv->val;
+    int end = iv->end;
+    for (i=iv->start; i<end; ++i)
+	valBuf[i] = val;
+    bitSetRange(chromVals->covBuf, iv->start, iv->end - iv->start);
+    }
+lmCleanup(&lm);
+#endif /* OLD */
+return TRUE;
+}
+
+
diff --git a/lib/cda.c b/lib/cda.c
new file mode 100644
index 0000000..88a0a82
--- /dev/null
+++ b/lib/cda.c
@@ -0,0 +1,477 @@
+/* cda.c - cDNA Alignment structure.  This stores all the info except
+ * the bases themselves on an cDNA alignment. 
+ * 
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "dnautil.h"
+#include "memgfx.h"
+#include "sig.h"
+#include "fuzzyFind.h"
+#include "cda.h"
+
+
+char *cdaLoadString(FILE *f)
+/* Load in a string from CDA file. */
+{
+UBYTE size;
+char *s;
+if (!readOne(f, size))
+    return NULL;
+s = needMem(size+1);
+mustRead(f, s, size);
+return s;
+}
+
+static void cdaWriteString(FILE *f, char *s)
+/* Write string out to CDA file. */
+{
+int size;
+UBYTE usize;
+if (s == NULL)
+    s = "";
+size = strlen(s);
+usize = (UBYTE)size;
+assert(size < 256);
+writeOne(f, usize);
+mustWrite(f, s, size);
+}
+
+void cdaReadBlock(FILE *f, struct cdaBlock *block)
+/* Read one block from cda file. */
+{
+mustReadOne(f, block->nStart);
+mustReadOne(f, block->nEnd);
+mustReadOne(f, block->hStart);
+block->hEnd = block->hStart + (block->nEnd - block->nStart);
+mustReadOne(f, block->startGood);
+mustReadOne(f, block->endGood);
+mustReadOne(f, block->midScore);
+}
+
+static void cdaWriteBlock(FILE *f, struct cdaBlock *block)
+/* Write one block to cda file. */
+{
+writeOne(f, block->nStart);
+writeOne(f, block->nEnd);
+writeOne(f, block->hStart);
+writeOne(f, block->startGood);
+writeOne(f, block->endGood);
+writeOne(f, block->midScore);
+}
+
+void cdaFixChromStartEnd(struct cdaAli *cda)
+/* Loop through blocks and figure out and fill in chromStart
+ * and chromEnd. */
+{
+int start = 0x7fffffff;
+int end = -start;
+int count = cda->blockCount;
+struct cdaBlock *block = cda->blocks;
+
+while (--count >= 0)
+    {
+    if (start > block->hStart)
+        start = block->hStart;
+    if (end < block->hEnd)
+        end = block->hEnd;
+    ++block;
+    }
+cda->chromStart = start;
+cda->chromEnd = end;
+}
+
+FILE *cdaOpenVerify(char *fileName)
+/* Call this to open file and verify signature, then call cdaLoadOne
+ * which returns NULL at EOF. */
+{
+FILE *aliFile;
+bits32 sig;
+
+aliFile = mustOpen(fileName, "rb");
+mustReadOne(aliFile, sig);
+if (sig != aliSig)
+    errAbort("Bad signature %x on %s", sig, fileName);
+return aliFile;
+}
+
+static FILE *cdaCreate(char *fileName)
+/* Open file to write and put out signature. */
+{
+bits32 sig = aliSig;
+FILE *f = mustOpen(fileName, "wb");
+writeOne(f, sig);
+return f;
+}
+
+struct cdaAli *cdaLoadOne(FILE *f)
+/* Load one cdaAli from file.  Assumes file pointer is correctly positioned. */
+{
+struct cdaAli *ca;
+struct cdaBlock *blocks;
+int count;
+int i;
+char *name;
+UBYTE chromIx;
+
+if ((name = cdaLoadString(f)) == NULL)
+    return NULL;
+AllocVar(ca);
+ca->name = name;
+mustReadOne(f, ca->isEmbryonic);
+mustReadOne(f, ca->baseCount);
+mustReadOne(f, ca->milliScore);
+mustReadOne(f, chromIx);
+ca->chromIx = chromIx;
+mustReadOne(f, ca->strand);
+mustReadOne(f, ca->direction);
+mustReadOne(f, ca->blockCount);
+count = ca->blockCount;
+ca->blocks = blocks = needMem(count * sizeof(blocks[0]));
+for (i=0; i<count; ++i)
+    cdaReadBlock(f, &blocks[i]);
+cdaFixChromStartEnd(ca);
+return ca;
+}
+
+static void cdaWriteOne(FILE *f, struct cdaAli *ca)
+/* Write one cdaAli to file. */
+{
+int count;
+int i;
+struct cdaBlock *blocks;
+UBYTE chromIx;
+
+cdaWriteString(f, ca->name);
+writeOne(f, ca->isEmbryonic);
+writeOne(f, ca->baseCount);
+writeOne(f, ca->milliScore);
+if (ca->chromIx > 255)
+    errAbort("chromIx too big in cdaWriteOne.");
+chromIx = (UBYTE)ca->chromIx;
+writeOne(f, chromIx);
+writeOne(f, ca->strand);
+writeOne(f, ca->direction);
+writeOne(f, ca->blockCount);
+count = ca->blockCount;
+blocks = ca->blocks;
+for (i=0; i<count; ++i)
+    cdaWriteBlock(f, &blocks[i]);
+}
+
+void cdaWrite(char *fileName, struct cdaAli *cdaList)
+/* Write out a cdaList to a cda file. */
+{
+FILE *f = cdaCreate(fileName);
+struct cdaAli *ca;
+for (ca = cdaList; ca != NULL; ca = ca->next)
+    cdaWriteOne(f, ca);
+fclose(f);
+}
+
+boolean cdaCloneIsReverse(struct cdaAli *cda)
+/* Returns TRUE if clone (.3/.5 pair) aligns on reverse strand. */
+{
+boolean isReverse = (cda->direction == '-');
+if (cda->strand == '-')
+    isReverse = !isReverse;
+return isReverse;
+}
+
+char cdaCloneStrand(struct cdaAli *cda)
+/* Return '+' or '-' depending on the strand that clone (.3/.5 pair) aligns on. */
+{
+return cdaCloneIsReverse(cda) ? '-' : '+';
+}
+
+char cdaDirChar(struct cdaAli *cda, char chromStrand)
+/* Return '>' or '<' or ' ' depending whether cDNA is going same, opposite, or
+ * unknown alignment as the chromosome strand. */
+{
+boolean isReverse = cdaCloneIsReverse(cda);
+if (chromStrand == '-')
+    isReverse = !isReverse;
+return (isReverse ? '<' : '>');    
+}
+
+void cdaRcOne(struct cdaAli *cda, int dnaStart, int baseCount)
+/* Reverse complement one cda. DnaStart is typically display window start. */
+{
+struct cdaBlock *block, *endBlock;
+
+for (block = cda->blocks, endBlock = block+cda->blockCount; block < endBlock; ++block)
+    {
+    int temp;
+    UBYTE uc;
+    temp = reverseOffset(block->hStart-dnaStart, baseCount) + dnaStart + 1;
+    block->hStart = reverseOffset(block->hEnd-dnaStart, baseCount) + dnaStart + 1;
+    block->hEnd = temp;
+    temp = reverseOffset(block->nStart, cda->baseCount);
+    block->nStart = reverseOffset(block->nEnd, cda->baseCount);
+    block->nEnd = temp;
+    uc = block->startGood;
+    block->startGood = block->endGood;
+    block->endGood = uc;
+    }
+block = cda->blocks;
+endBlock -= 1;
+for (;block < endBlock; ++block, --endBlock)
+    {
+    struct cdaBlock temp;
+    temp = *block;
+    *block = *endBlock;
+    *endBlock = temp;
+    }
+}
+
+void cdaRcList(struct cdaAli *cdaList, int dnaStart, int baseCount)
+/* Reverse complement cda list. */
+{
+struct cdaAli *cda;
+for (cda = cdaList; cda != NULL; cda = cda->next)
+    cdaRcOne(cda, dnaStart, baseCount);
+}
+
+
+void cdaFreeAli(struct cdaAli *ca)
+/* Free a single cdaAli. */
+{
+freeMem(ca->blocks);
+freeMem(ca->name);
+freeMem(ca);
+}
+
+void cdaFreeAliList(struct cdaAli **pList)
+/* Free list of cdaAli. */
+{
+struct cdaAli *ca, *next;
+next = *pList;
+while ((ca = next) != NULL)
+    {
+    next = ca->next;
+    cdaFreeAli(ca);
+    }
+*pList = NULL;
+}
+
+
+static void cdaCoalesceOne(struct cdaAli *ca, boolean updateScore)
+/* Coalesce blocks separated by small amounts of noise. */
+{
+struct cdaBlock *left = ca->blocks;
+struct cdaBlock *block = left+1;
+struct cdaBlock *writeBlock = block;
+int readCount = ca->blockCount;
+int i;
+
+/* Implicitly have read and written first one. */
+for (i=1; i<readCount; ++i)
+    {
+    int hGap = intAbs(block->hStart - left->hEnd);
+    int nGap = intAbs(block->nStart - left->nEnd);
+    if (hGap > 2 || nGap > 2)
+        {
+        left = writeBlock;
+        *writeBlock++ = *block;
+        }
+    else
+        {
+        int leftMatch, blockMatch;
+        int totalMatch;
+
+        /* Update score. */
+        if (updateScore)
+            {
+            leftMatch = roundingScale(left->midScore, left->nEnd-left->nStart, 255);
+            blockMatch = roundingScale(block->midScore, block->nEnd-block->nStart, 255);
+            totalMatch = leftMatch + blockMatch - nGap - hGap;
+            left->midScore = roundingScale(totalMatch, 255, block->nEnd-left->nStart);
+            }
+
+        /* Update ends. */
+        left->hEnd = block->hEnd;
+        left->nEnd = block->nEnd;
+        left->endGood = block->endGood;  
+        }
+    ++block;
+    }
+ca->blockCount = writeBlock - ca->blocks;
+}
+
+void cdaCoalesceAll(struct cdaAli *ca, boolean updateScore)
+/* Coalesce blocks separated by small amounts of noise. */
+{
+for (;ca != NULL; ca = ca->next)
+    cdaCoalesceOne(ca, updateScore);
+}
+
+void cdaCoalesceBlocks(struct cdaAli *ca)
+/* Coalesce blocks separated by small amounts of noise. */
+{
+cdaCoalesceAll(ca, TRUE);
+}
+
+void cdaCoalesceFast(struct cdaAli *ca)
+/* Coalesce blocks as above, but don't update the score. */
+{
+cdaCoalesceAll(ca, FALSE);
+}
+
+
+void cdaShowAlignmentTrack(struct memGfx *mg, 
+    int xOff, int yOff, int width, int height,  Color goodColor, Color badColor,
+    int dnaSize, int dnaOffset, struct cdaAli *cda, char repeatChar)
+/* Draw alignment on a horizontal track of picture. */
+{
+struct cdaBlock *block = cda->blocks;
+int count = cda->blockCount;
+int blockIx;
+int scaledHeight = roundingScale(height, dnaSize, width);
+MgFont *font = NULL;
+int repeatCharWidth = 0;
+
+if (repeatChar)
+    {
+    font = mgSmallFont();
+    repeatCharWidth = mgFontCharWidth(font, repeatChar);
+    }
+
+for (blockIx = 0; blockIx < count; ++blockIx)
+    {
+    int x[4];
+    int b[4];
+    Color c[3];
+    int quarterWid;
+    int i;
+    int w;
+
+    b[0] = block->hStart;
+    b[3] = block->hEnd;
+    quarterWid = (b[3]-b[0]+2)>>2;
+    if (quarterWid > scaledHeight)
+        quarterWid = scaledHeight;
+    b[1] = b[0] + quarterWid;
+    b[2] = b[3] - quarterWid;
+
+    c[0] = ((block->startGood >= 4 && (blockIx == 0 || block[-1].nEnd == block[0].nStart)) 
+        ? goodColor : badColor);
+    c[1] = ((block->midScore > 229) ? goodColor : badColor);
+    c[2] = ((block->endGood >= 4 && (blockIx == count-1 || block[0].nEnd == block[1].nStart))
+        ? goodColor : badColor);
+
+    for (i=0; i<4; ++i)
+        x[i] = roundingScale(b[i]-dnaOffset, width, dnaSize) + xOff;
+    for (i=0; i<3; ++i)
+        {
+        if ((w = x[i+1] - x[i]) > 0)
+            mgDrawBox(mg, x[i], yOff, w, height, c[i]);
+        }
+    
+    if (repeatChar)
+        {
+        char buf[256];
+        int charCount;
+        w = x[3] - x[0];
+        charCount = w/repeatCharWidth;
+        if (charCount >= sizeof(buf))
+            charCount = sizeof(buf)-1;
+        memset(buf, repeatChar, charCount);
+        buf[charCount] = 0;
+        mgTextCentered(mg, x[0], yOff, w, height, MG_WHITE, font, buf);
+        }
+    ++block;
+    }
+}
+
+
+static UBYTE leftGood(struct ffAli *ali)
+{
+DNA *n = ali->nStart;
+DNA *h = ali->hStart;
+int size = ali->nEnd - ali->nStart;
+int matchSize = 0;
+
+while (--size >= 0)
+    {
+    if (*n++ != *h++)
+        break;
+    ++matchSize;
+    }
+if (matchSize > 255)
+    matchSize = 255;
+return (UBYTE)matchSize;
+}
+
+static UBYTE rightGood(struct ffAli *ali)
+{
+DNA *n = ali->nEnd;
+DNA *h = ali->hEnd;
+int size = ali->nEnd - ali->nStart;
+int matchSize = 0;
+
+while (--size >= 0)
+    {
+    if (*--n != *--h)
+        break;
+    ++matchSize;
+    }
+if (matchSize > 255)
+    matchSize = 255;
+return (UBYTE)matchSize;
+}
+
+
+static int countAlis(struct ffAli *ali)
+{
+int count = 0;
+while (ali != NULL)
+    {
+    ++count;
+    ali = ali->right;
+    }
+return count;
+}
+
+struct cdaAli *cdaAliFromFfAli(struct ffAli *aliList, 
+    DNA *needle, int needleSize, DNA *hay, int haySize, boolean isRc)
+/* Convert from ffAli to cdaAli format. */
+{
+int count = countAlis(aliList);
+struct cdaAli *cda;
+struct cdaBlock *blocks;
+struct ffAli *fa;
+int score;
+int bases;
+
+if (isRc)
+    reverseComplement(needle, needleSize);
+AllocVar(cda);
+cda->baseCount = needleSize;
+cda->strand = (isRc ? '-' : '+');
+cda->direction = '+';   /* Actually we don't know. */
+cda->orientation = (isRc ? -1 : 1);
+cda->blockCount = count;
+cda->blocks = blocks = needMem(count * sizeof(blocks[0]));
+
+for (fa = aliList; fa != NULL; fa = fa->right)
+    {
+    blocks->nStart = fa->nStart - needle;
+    blocks->nEnd = fa->nEnd - needle;
+    blocks->hStart = fa->hStart - hay;
+    blocks->hEnd  = fa->hEnd - hay;
+    blocks->startGood = leftGood(fa);
+    blocks->endGood = rightGood(fa);
+    bases = fa->nEnd - fa->nStart;
+    score = dnaScoreMatch(fa->nStart, fa->hStart, bases);
+    blocks->midScore = roundingScale(255, score, bases);
+    ++blocks;
+    }
+cdaFixChromStartEnd(cda);
+if (isRc)
+    {
+    reverseComplement(needle, needleSize);
+    }
+return cda;
+}
+
diff --git a/lib/chain.c b/lib/chain.c
new file mode 100644
index 0000000..0a2a1f3
--- /dev/null
+++ b/lib/chain.c
@@ -0,0 +1,644 @@
+/* chain - pairwise alignments that can include gaps in both
+ * sequences at once.  This is similar in many ways to psl,
+ * but more suitable to cross species genomic comparisons. */
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "dnaseq.h"
+#include "dnautil.h"
+#include "chain.h"
+
+
+void chainFree(struct chain **pChain)
+/* Free up a chain. */
+{
+struct chain *chain = *pChain;
+if (chain != NULL)
+    {
+    slFreeList(&chain->blockList);
+    freeMem(chain->qName);
+    freeMem(chain->tName);
+    freez(pChain);
+    }
+}
+
+void chainFreeList(struct chain **pList)
+/* Free a list of dynamically allocated chain's */
+{
+struct chain *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    chainFree(&el);
+    }
+*pList = NULL;
+}
+
+int cBlockCmpQuery(const void *va, const void *vb)
+/* Compare to sort based on query start. */
+{
+const struct cBlock *a = *((struct cBlock **)va);
+const struct cBlock *b = *((struct cBlock **)vb);
+return a->qStart - b->qStart;
+}
+
+int cBlockCmpTarget(const void *va, const void *vb)
+/* Compare to sort based on target start. */
+{
+const struct cBlock *a = *((struct cBlock **)va);
+const struct cBlock *b = *((struct cBlock **)vb);
+return a->tStart - b->tStart;
+}
+
+int cBlockCmpBoth(const void *va, const void *vb)
+/* Compare to sort based on query, then target. */
+{
+const struct cBlock *a = *((struct cBlock **)va);
+const struct cBlock *b = *((struct cBlock **)vb);
+int dif;
+dif = a->qStart - b->qStart;
+if (dif == 0)
+    dif = a->tStart - b->tStart;
+return dif;
+}
+
+int cBlockCmpDiagQuery(const void *va, const void *vb)
+/* Compare to sort based on diagonal, then query. */
+{
+const struct cBlock *a = *((struct cBlock **)va);
+const struct cBlock *b = *((struct cBlock **)vb);
+int dif;
+dif = (a->tStart - a->qStart) - (b->tStart - b->qStart);
+if (dif == 0)
+    dif = a->qStart - b->qStart;
+return dif;
+}
+
+void cBlocksAddOffset(struct cBlock *blockList, int qOff, int tOff)
+/* Add offsets to block list. */
+{
+struct cBlock *block;
+for (block = blockList; block != NULL; block = block->next)
+    {
+    block->tStart += tOff;
+    block->tEnd += tOff;
+    block->qStart += qOff;
+    block->qEnd += qOff;
+    }
+}
+
+struct cBlock *cBlocksFromAliSym(int symCount, char *qSym, char *tSym, 
+        int qPos, int tPos)
+/* Convert alignment from alignment symbol (bases and dashes) format 
+ * to a list of chain blocks.  The qPos and tPos correspond to the start
+ * in the query and target sequences of the first letter in  qSym and tSym. */
+{
+struct cBlock *blockList = NULL, *block = NULL;
+int i;
+for (i=0; i<symCount; ++i)
+    {
+    if (qSym[i] == '-')
+        {
+        block = NULL;
+        ++tPos;
+        }
+    else if (tSym[i] == '-')
+        {
+        block = NULL;
+        ++qPos;
+        }
+    else
+        {
+        if (block == NULL)
+            {
+            AllocVar(block);
+            slAddHead(&blockList, block);
+            block->qStart = qPos;
+            block->tStart = tPos;
+            }
+        block->qEnd = ++qPos;
+        block->tEnd = ++tPos;
+        }
+    }
+slReverse(&blockList);
+return blockList;
+}
+        
+
+int chainCmpScore(const void *va, const void *vb)
+/* Compare to sort based on total score. */
+{
+const struct chain *a = *((struct chain **)va);
+const struct chain *b = *((struct chain **)vb);
+double diff = b->score - a->score;
+if (diff < 0.0) return -1;
+else if (diff > 0.0) return 1;
+else return 0;
+}
+
+int chainCmpScoreDesc(const void *va, const void *vb)
+/* Compare to sort based on total score descending. */
+{
+const struct chain *a = *((struct chain **)va);
+const struct chain *b = *((struct chain **)vb);
+double diff = a->score - b->score;
+if (diff < 0.0) return -1;
+else if (diff > 0.0) return 1;
+else return 0;
+}
+
+int chainCmpTarget(const void *va, const void *vb)
+/* Compare to sort based on target position. */
+{
+const struct chain *a = *((struct chain **)va);
+const struct chain *b = *((struct chain **)vb);
+int dif = strcmp(a->tName, b->tName);
+if (dif == 0)
+    dif = a->tStart - b->tStart;
+return dif;
+}
+
+#define FACTOR 300000000
+
+int chainCmpQuery(const void *va, const void *vb)
+/* Compare to sort based on query chrom and target position. */
+{
+const struct chain *a = *((struct chain **)va);
+const struct chain *b = *((struct chain **)vb);
+int dif;                                                                        
+
+dif = strcmp(a->qName, b->qName);                                               
+if (dif == 0)                                                                   
+    dif = a->qStart - b->qStart;                                                
+return dif;                       
+}
+
+static int nextId = 1;
+
+void chainIdSet(int id)
+/* Set next chain id. */
+{
+nextId = id;
+}
+
+void chainIdReset()
+/* Reset chain id. */
+{
+chainIdSet(1);
+}
+
+void chainIdNext(struct chain *chain)
+/* Add an id to a chain if it doesn't have one already */
+{
+chain->id = nextId++;
+}
+
+void chainWriteHead(struct chain *chain, FILE *f)
+/* Write chain before block/insert list. */
+{
+if (chain->id == 0)
+    chainIdNext(chain);
+fprintf(f, "chain %1.0f %s %d + %d %d %s %d %c %d %d %d\n", chain->score,
+    chain->tName, chain->tSize, chain->tStart, chain->tEnd,
+    chain->qName, chain->qSize, chain->qStrand, chain->qStart, chain->qEnd,
+    chain->id);
+}
+
+void chainWrite(struct chain *chain, FILE *f)
+/* Write out chain to file in usual format*/
+{
+struct cBlock *b, *nextB;
+
+chainWriteHead(chain, f);
+for (b = chain->blockList; b != NULL; b = nextB)
+    {
+    nextB = b->next;
+    fprintf(f, "%d", b->qEnd - b->qStart);
+    if (nextB != NULL)
+	fprintf(f, "\t%d\t%d", 
+		nextB->tStart - b->tEnd, nextB->qStart - b->qEnd);
+    fputc('\n', f);
+    }
+fputc('\n', f);
+}
+
+void chainWriteAll(struct chain *chainList, FILE *f)
+/* Write all chains to file. */
+{
+struct chain *chain;
+for (chain = chainList; chain != NULL; chain = chain->next)
+    chainWrite(chain, f);
+}
+
+void chainWriteLong(struct chain *chain, FILE *f)
+/* Write out chain to file in longer format*/
+{
+struct cBlock *b, *nextB;
+
+chainWriteHead(chain, f);
+for (b = chain->blockList; b != NULL; b = nextB)
+    {
+    nextB = b->next;
+    fprintf(f, "%d\t%d\t", b->tStart, b->qStart);
+    fprintf(f, "%d", b->qEnd - b->qStart);
+    if (nextB != NULL)
+	fprintf(f, "\t%d\t%d", 
+		nextB->tStart - b->tEnd, nextB->qStart - b->qEnd);
+    fputc('\n', f);
+    }
+fputc('\n', f);
+}
+
+struct chain *chainReadChainLine(struct lineFile *lf)
+/* Read line that starts with chain.  Allocate memory
+ * and fill in values.  However don't read link lines. */
+{
+char *row[13];
+int wordCount;
+struct chain *chain;
+
+wordCount = lineFileChop(lf, row);
+if (wordCount == 0)
+    return NULL;
+if (wordCount < 12)
+    errAbort("Expecting at least 12 words line %d of %s", 
+    	lf->lineIx, lf->fileName);
+if (!sameString(row[0], "chain"))
+    errAbort("Expecting 'chain' line %d of %s", lf->lineIx, lf->fileName);
+AllocVar(chain);
+chain->score = atof(row[1]);
+chain->tName = cloneString(row[2]);
+chain->tSize = lineFileNeedNum(lf, row, 3);
+if (wordCount >= 13)
+    chain->id = lineFileNeedNum(lf, row, 12);
+else
+    chainIdNext(chain);
+
+/* skip tStrand for now, always implicitly + */
+chain->tStart = lineFileNeedNum(lf, row, 5);
+chain->tEnd = lineFileNeedNum(lf, row, 6);
+chain->qName = cloneString(row[7]);
+chain->qSize = lineFileNeedNum(lf, row, 8);
+chain->qStrand = row[9][0];
+chain->qStart = lineFileNeedNum(lf, row, 10);
+chain->qEnd = lineFileNeedNum(lf, row, 11);
+if (chain->qStart >= chain->qEnd || chain->tStart >= chain->tEnd)
+    errAbort("End before start line %d of %s", lf->lineIx, lf->fileName);
+if (chain->qStart < 0 || chain->tStart < 0)
+    errAbort("Start before zero line %d of %s", lf->lineIx, lf->fileName);
+if (chain->qEnd > chain->qSize || chain->tEnd > chain->tSize)
+    errAbort("Past end of sequence line %d of %s", lf->lineIx, lf->fileName);
+return chain;
+}
+
+void chainReadBlocks(struct lineFile *lf, struct chain *chain)
+/* Read in chain blocks from file. */
+{
+char *row[3];
+int q,t;
+
+/* Now read in block list. */
+q = chain->qStart;
+t = chain->tStart;
+for (;;)
+    {
+    int wordCount = lineFileChop(lf, row);
+    int size = lineFileNeedNum(lf, row, 0);
+    struct cBlock *b;
+    AllocVar(b);
+    slAddHead(&chain->blockList, b);
+    b->qStart = q;
+    b->tStart = t;
+    q += size;
+    t += size;
+    b->qEnd = q;
+    b->tEnd = t;
+    if (wordCount == 1)
+        break;
+    else if (wordCount < 3)
+        errAbort("Expecting 1 or 3 words line %d of %s\n", 
+		lf->lineIx, lf->fileName);
+    t += lineFileNeedNum(lf, row, 1);
+    q += lineFileNeedNum(lf, row, 2);
+    }
+if (q != chain->qEnd)
+    errAbort("q end mismatch %d vs %d line %d of %s\n", 
+    	q, chain->qEnd, lf->lineIx, lf->fileName);
+if (t != chain->tEnd)
+    errAbort("t end mismatch %d vs %d line %d of %s\n", 
+    	t, chain->tEnd, lf->lineIx, lf->fileName);
+slReverse(&chain->blockList);
+}
+
+struct chain *chainRead(struct lineFile *lf)
+/* Read next chain from file.  Return NULL at EOF. 
+ * Note that chain block scores are not filled in by
+ * this. */
+{
+struct chain *chain = chainReadChainLine(lf);
+if (chain != NULL)
+    chainReadBlocks(lf, chain);
+return chain;
+}
+
+void chainSwap(struct chain *chain)
+/* Swap target and query side of chain. */
+{
+struct chain old = *chain;
+struct cBlock *b;
+
+/* Copy basic stuff swapping t and q. */
+chain->qName = old.tName;
+chain->tName = old.qName;
+chain->qStart = old.tStart;
+chain->qEnd = old.tEnd;
+chain->tStart = old.qStart;
+chain->tEnd = old.qEnd;
+chain->qSize = old.tSize;
+chain->tSize = old.qSize;
+
+/* Swap t and q in blocks. */
+for (b = chain->blockList; b != NULL; b = b->next)
+    {
+    struct cBlock old = *b;
+    b->qStart = old.tStart;
+    b->qEnd = old.tEnd;
+    b->tStart = old.qStart;
+    b->tEnd = old.qEnd;
+    }
+
+/* Cope with the minus strand. */
+if (chain->qStrand == '-')
+    {
+    /* chain's are really set up so that the target is on the
+     * + strand and the query is on the minus strand.
+     * Therefore we need to reverse complement both 
+     * strands while swapping to preserve this. */
+    for (b = chain->blockList; b != NULL; b = b->next)
+        {
+	reverseIntRange(&b->tStart, &b->tEnd, chain->tSize);
+	reverseIntRange(&b->qStart, &b->qEnd, chain->qSize);
+	}
+    reverseIntRange(&chain->tStart, &chain->tEnd, chain->tSize);
+    reverseIntRange(&chain->qStart, &chain->qEnd, chain->qSize);
+    slReverse(&chain->blockList);
+    }
+}
+
+struct hash *chainReadUsedSwapLf(char *fileName, boolean swapQ, Bits *bits, struct lineFile *lf)
+/* Read chains that are marked as used in the 
+ * bits array (which may be NULL) into a hash keyed by id. */
+{
+char nameBuf[16];
+struct hash *hash = hashNew(18);
+struct chain *chain;
+int usedCount = 0, count = 0;
+
+while ((chain = chainRead(lf)) != NULL)
+    {
+    ++count;
+    if (bits != NULL && !bitReadOne(bits, chain->id))
+	{
+	chainFree(&chain);
+        continue;
+	}
+    safef(nameBuf, sizeof(nameBuf), "%x", chain->id);
+    if (hashLookup(hash, nameBuf))
+        errAbort("Duplicate chain %d ending line %d of %s", 
+		chain->id, lf->lineIx, lf->fileName);
+    if (swapQ)
+        chainSwap(chain);
+    hashAdd(hash, nameBuf, chain);
+    ++usedCount;
+    }
+return hash;
+}
+
+struct hash *chainReadUsedSwap(char *fileName, boolean swapQ, Bits *bits)
+/* Read chains that are marked as used in the 
+ * bits array (which may be NULL) into a hash keyed by id. */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+struct hash *hash = chainReadUsedSwapLf(fileName, swapQ, NULL, lf);
+lineFileClose(&lf);
+return hash;
+}
+
+struct hash *chainReadAllSwap(char *fileName, boolean swapQ)
+/* Read chains into a hash keyed by id. */
+{
+return chainReadUsedSwap(fileName, swapQ, NULL);
+}
+
+struct hash *chainReadAll(char *fileName)
+/* Read chains into a hash keyed by id. */
+{
+return chainReadAllSwap(fileName, FALSE);
+}
+
+struct hash *chainReadAllWithMeta(char *fileName, FILE *f)
+/* Read chains into a hash keyed by id. */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+struct hash *hash = NULL;
+lineFileSetMetaDataOutput(lf, f);
+hash = chainReadUsedSwapLf(fileName, FALSE, NULL, lf);
+lineFileClose(&lf);
+return hash;
+}
+
+
+struct chain *chainFind(struct hash *hash, int id)
+/* Find chain in hash, return NULL if not found */
+{
+char nameBuf[16];
+safef(nameBuf, sizeof(nameBuf), "%x", id);
+return hashFindVal(hash, nameBuf);
+}
+
+struct chain *chainLookup(struct hash *hash, int id)
+/* Find chain in hash. */
+{
+char nameBuf[16];
+safef(nameBuf, sizeof(nameBuf), "%x", id);
+return hashMustFindVal(hash, nameBuf);
+}
+
+void chainSubsetOnT(struct chain *chain, int subStart, int subEnd, 
+    struct chain **retSubChain,  struct chain **retChainToFree)
+/* Get subchain of chain bounded by subStart-subEnd on 
+ * target side.  Return result in *retSubChain.  In some
+ * cases this may be the original chain, in which case
+ * *retChainToFree is NULL.  When done call chainFree on
+ * *retChainToFree.  The score and id fields are not really
+ * properly filled in. */
+{
+/* Find first relevant block. */
+struct cBlock *firstBlock;
+for (firstBlock = chain->blockList; firstBlock != NULL; firstBlock = firstBlock->next)
+    {
+    if (firstBlock->tEnd > subStart)
+	break;
+    }
+chainFastSubsetOnT(chain, firstBlock, subStart, subEnd, retSubChain, retChainToFree);
+}
+
+void chainFastSubsetOnT(struct chain *chain, struct cBlock *firstBlock,
+	int subStart, int subEnd, struct chain **retSubChain,  struct chain **retChainToFree)
+/* Get subchain as in chainSubsetOnT. Pass in initial block that may
+ * be known from some index to speed things up. */
+{
+struct chain *sub = NULL;
+struct cBlock *oldB, *b, *bList = NULL;
+int qStart = BIGNUM, qEnd = -BIGNUM;
+int tStart = BIGNUM, tEnd = -BIGNUM;
+
+/* Check for easy case. */
+if (subStart <= chain->tStart && subEnd >= chain->tEnd)
+    {
+    *retSubChain = chain;
+    *retChainToFree = NULL;
+    return;
+    }
+/* Build new block list and calculate bounds. */
+for (oldB = firstBlock; oldB != NULL; oldB = oldB->next)
+    {
+    if (oldB->tStart >= subEnd)
+        break;
+    b = CloneVar(oldB);
+    if (b->tStart < subStart)
+        {
+	b->qStart += subStart - b->tStart;
+	b->tStart = subStart;
+	}
+    if (b->tEnd > subEnd)
+        {
+	b->qEnd -= b->tEnd - subEnd;
+	b->tEnd = subEnd;
+	}
+    slAddHead(&bList, b);
+    if (qStart > b->qStart)
+        qStart = b->qStart;
+    if (qEnd < b->qEnd)
+        qEnd = b->qEnd;
+    if (tStart > b->tStart)
+        tStart = b->tStart;
+    if (tEnd < b->tEnd)
+        tEnd = b->tEnd;
+    }
+slReverse(&bList);
+
+/* Make new chain based on old. */
+if (bList != NULL)
+    {
+    double sizeRatio;
+    AllocVar(sub);
+    sub->blockList = bList;
+    sub->qName = cloneString(chain->qName);
+    sub->qSize = chain->qSize;
+    sub->qStrand = chain->qStrand;
+    sub->qStart = qStart;
+    sub->qEnd = qEnd;
+    sub->tName = cloneString(chain->tName);
+    sub->tSize = chain->tSize;
+    sub->tStart = tStart;
+    sub->tEnd = tEnd;
+    sub->id = chain->id;
+
+    /* Fake new score. */
+    sizeRatio = (sub->tEnd - sub->tStart);
+    sizeRatio /= (chain->tEnd - chain->tStart);
+    sub->score = sizeRatio * chain->score;
+    }
+*retSubChain = *retChainToFree = sub;
+}
+
+void chainSubsetOnQ(struct chain *chain, int subStart, int subEnd, 
+    struct chain **retSubChain,  struct chain **retChainToFree)
+/* Get subchain of chain bounded by subStart-subEnd on 
+ * query side.  Return result in *retSubChain.  In some
+ * cases this may be the original chain, in which case
+ * *retChainToFree is NULL.  When done call chainFree on
+ * *retChainToFree.  The score and id fields are not really
+ * properly filled in. */
+{
+struct chain *sub = NULL;
+struct cBlock *oldB, *b, *bList = NULL;
+int qStart = BIGNUM, qEnd = -BIGNUM;
+int tStart = BIGNUM, tEnd = -BIGNUM;
+
+/* Check for easy case. */
+if (subStart <= chain->qStart && subEnd >= chain->qEnd)
+    {
+    *retSubChain = chain;
+    *retChainToFree = NULL;
+    return;
+    }
+/* Build new block list and calculate bounds. */
+for (oldB = chain->blockList; oldB != NULL; oldB = oldB->next)
+    {
+    if (oldB->qEnd <= subStart)
+        continue;
+    if (oldB->qStart >= subEnd)
+        break;
+    b = CloneVar(oldB);
+    if (b->qStart < subStart)
+        {
+	b->tStart += subStart - b->qStart;
+	b->qStart = subStart;
+	}
+    if (b->qEnd > subEnd)
+        {
+	b->tEnd -= b->qEnd - subEnd;
+	b->qEnd = subEnd;
+	}
+    slAddHead(&bList, b);
+    if (tStart > b->tStart)
+        tStart = b->tStart;
+    if (tEnd < b->tEnd)
+        tEnd = b->tEnd;
+    if (qStart > b->qStart)
+        qStart = b->qStart;
+    if (qEnd < b->qEnd)
+        qEnd = b->qEnd;
+    }
+slReverse(&bList);
+
+/* Make new chain based on old. */
+if (bList != NULL)
+    {
+    AllocVar(sub);
+    sub->blockList = bList;
+    sub->qName = cloneString(chain->qName);
+    sub->qSize = chain->qSize;
+    sub->qStrand = chain->qStrand;
+    sub->qStart = qStart;
+    sub->qEnd = qEnd;
+    sub->tName = cloneString(chain->tName);
+    sub->tSize = chain->tSize;
+    sub->tStart = tStart;
+    sub->tEnd = tEnd;
+    sub->id = chain->id;
+    }
+*retSubChain = *retChainToFree = sub;
+}
+
+void chainRangeQPlusStrand(struct chain *chain, int *retQs, int *retQe)
+/* Return range of bases covered by chain on q side on the plus
+ * strand. */
+{
+if (chain == NULL)
+    errAbort("chain::chainRangeQPlusStrand() - Can't find range in null query chain.");
+if (chain->qStrand == '-')
+    {
+    *retQs = chain->qSize - chain->qEnd;
+    *retQe = chain->qSize - chain->qStart;
+    }
+else
+    {
+    *retQs = chain->qStart;
+    *retQe = chain->qEnd;
+    }
+}
+
diff --git a/lib/chainBlock.c b/lib/chainBlock.c
new file mode 100644
index 0000000..9d28b92
--- /dev/null
+++ b/lib/chainBlock.c
@@ -0,0 +1,450 @@
+/* chainBlock - Chain together scored blocks from an alignment
+ * into scored chains.  Internally this uses a kd-tree and a
+ * varient of an algorithm suggested by Webb Miller and further
+ * developed by Jim Kent. */
+
+#include "common.h"
+#include "localmem.h"
+#include "linefile.h"
+#include "dlist.h"
+#include "chainBlock.h"
+
+
+struct kdBranch
+/* A kd-tree. That is a binary tree which partitions the children
+ * into higher and lower one dimension at a time.  We're just doing
+ * one in two dimensions, so it alternates between q and t dimensions. */
+    {
+    struct kdBranch *lo;      /* Pointer to children with lower coordinates. */
+    struct kdBranch *hi;      /* Pointer to children with higher coordinates. */
+    struct kdLeaf *leaf;      /* Extra info for leaves on tree. */
+    int cutCoord;	      /* Coordinate (in some dimension) to cut on */
+    double maxScore;	      /* Max score of any leaf below us. */
+    int maxQ;		      /* Maximum qEnd of any leaf below us. */
+    int maxT;		      /* Maximum tEnd of any leaf below us. */
+    };
+
+struct kdLeaf
+/* A leaf in our kdTree. */
+    {
+    struct kdLeaf *next;	/* Next in list. */
+    struct cBlock *cb;	        /* Start position and score from user. */
+    struct kdBranch *bestPred;	/* Best predecessor. */
+    double totalScore;		/* Total score of chain up to here. */
+    bool hit;			/* This hit? Used by system internally. */
+    };
+
+struct kdTree
+/* The whole tree.  */
+    {
+    struct kdBranch *root;	/* Pointer to root of kd-tree. */
+    };
+
+
+static int kdLeafCmpQ(const void *va, const void *vb)
+/* Compare to sort based on query start. */
+{
+const struct kdLeaf *a = *((struct kdLeaf **)va);
+const struct kdLeaf *b = *((struct kdLeaf **)vb);
+return a->cb->qStart - b->cb->qStart;
+}
+
+static int kdLeafCmpT(const void *va, const void *vb)
+/* Compare to sort based on target start. */
+{
+const struct kdLeaf *a = *((struct kdLeaf **)va);
+const struct kdLeaf *b = *((struct kdLeaf **)vb);
+return a->cb->tStart - b->cb->tStart;
+}
+
+static int kdLeafCmpTotal(const void *va, const void *vb)
+/* Compare to sort based on total score. */
+{
+const struct kdLeaf *a = *((struct kdLeaf **)va);
+const struct kdLeaf *b = *((struct kdLeaf **)vb);
+double diff = b->totalScore - a->totalScore;
+if (diff < 0) return -1;
+else if (diff > 0) return 1;
+else return 0;
+}
+
+static int medianVal(struct dlList *list, int medianIx, int dim)
+/* Return value of median block in list on given dimension 
+ * Mark blocks up to median as hit. */
+{
+struct dlNode *node = list->head;
+struct kdLeaf *leaf = NULL;
+int i;
+
+for (i=0; i<medianIx; ++i)
+    {
+    leaf = node->val;
+    leaf->hit = TRUE;  
+    node = node->next;
+    }
+return (dim == 0 ? leaf->cb->qStart : leaf->cb->tStart);
+}
+
+static int splitList(struct dlList *oldList, struct dlList *newList)
+/* Peel off members of oldList that are not hit onto new list. */
+{
+struct dlNode *node, *next;
+struct kdLeaf *leaf;
+int newCount = 0;
+dlListInit(newList);
+for (node = oldList->head; !dlEnd(node); node = next)
+    {
+    next = node->next;
+    leaf = node->val;
+    if (!leaf->hit)
+	{
+	dlRemove(node);
+	dlAddTail(newList, node);
+	++newCount;
+	}
+    }
+return newCount;
+}
+
+static void clearHits(struct dlList *list)
+/* Clear hit flags of all blocks on list. */
+{
+struct dlNode *node;
+for (node = list->head; !dlEnd(node); node = node->next)
+    {
+    struct kdLeaf *leaf = node->val;
+    leaf->hit = FALSE;
+    }
+}
+
+
+static struct kdBranch *kdBuild(int nodeCount, struct dlList *lists[2], int dim,
+	struct lm *lm)
+/* Build up kd-tree recursively. */
+{
+struct kdBranch *branch;
+lmAllocVar(lm, branch);
+if (nodeCount == 1)
+    {
+    struct kdLeaf *leaf = lists[0]->head->val;
+    branch->leaf = leaf;
+    branch->maxQ = leaf->cb->qEnd;
+    branch->maxT = leaf->cb->tEnd;
+    }
+else
+    {
+    int newCount;
+    struct dlList *newLists[2];
+    struct dlList newQ, newT;
+    int nextDim = 1-dim;
+
+    /* Subdivide lists along median.  */
+    newLists[0] = &newQ;
+    newLists[1] = &newT;
+    clearHits(lists[0]);
+    branch->cutCoord = medianVal(lists[dim], nodeCount/2, dim);
+    newCount = splitList(lists[0], newLists[0]);
+    splitList(lists[1], newLists[1]);
+
+    /* Recurse on each side. */
+    branch->lo = kdBuild(nodeCount - newCount, lists, nextDim, lm);
+    branch->hi = kdBuild(newCount, newLists, nextDim, lm);
+    branch->maxQ = max(branch->lo->maxQ, branch->hi->maxQ);
+    branch->maxT = max(branch->lo->maxT, branch->hi->maxT);
+    }
+return branch;
+}
+
+static struct kdTree *kdTreeMake(struct kdLeaf *leafList, struct lm *lm)
+/* Make a kd-tree containing leafList. */
+{
+struct kdLeaf *leaf;
+int nodeCount = slCount(leafList);
+struct kdTree *tree;
+struct dlList qList, tList,*lists[2];
+struct dlNode *qNodes, *tNodes;
+int i;
+
+/* Build lists sorted in each dimension. This
+ * will let us quickly find medians while constructing
+ * the kd-tree. */
+dlListInit(&qList);
+dlListInit(&tList);
+AllocArray(qNodes, nodeCount);
+AllocArray(tNodes, nodeCount);
+for (i=0 , leaf=leafList; leaf != NULL; leaf = leaf->next, ++i)
+    {
+    qNodes[i].val = tNodes[i].val = leaf;
+    dlAddTail(&qList, &qNodes[i]);
+    dlAddTail(&tList, &tNodes[i]);
+    }
+/* Just sort qList since tList is sorted because it was
+ * constructed from sorted leafList. */
+dlSort(&qList, kdLeafCmpQ); 
+lists[0] = &qList;
+lists[1] = &tList;
+
+/* Allocate master data structure and call recursive builder. */
+lmAllocVar(lm, tree);
+tree->root = kdBuild(nodeCount, lists, 0, lm);
+
+/* Clean up and go home. */
+freeMem(qNodes);
+freeMem(tNodes);
+return tree;
+}
+
+struct predScore
+/* Predecessor and score we get merging with it. */
+    {
+    struct kdBranch *pred;	/* Predecessor. */
+    double score;		/* Score of us plus predecessor. */
+    };
+
+static struct predScore bestPredecessor(
+	struct kdLeaf *lonely,	    /* We're finding this leaf's predecessor */
+	ConnectCost connectCost,    /* Cost to connect two leafs. */
+	GapCost gapCost,	    /* Lower bound on gap cost. */
+	void *gapData,		    /* Data to pass to Gap/Connect cost */
+	int dim,		    /* Dimension level of tree splits on. */
+	struct kdBranch *branch,    /* Subtree to explore */
+	struct predScore bestSoFar) /* Best predecessor so far. */
+/* Find the highest scoring predecessor to this leaf, and
+ * thus iteratively the highest scoring subchain that ends
+ * in this leaf. */
+{
+struct kdLeaf *leaf;
+double maxScore = branch->maxScore + lonely->cb->score;
+
+/* If best score in this branch of tree wouldn't be enough
+ * don't bother exploring it. First try without calculating
+ * gap score in case gap score is a little expensive to calculate. */
+if (maxScore < bestSoFar.score)
+    return bestSoFar;
+maxScore -= gapCost(lonely->cb->qStart - branch->maxQ, 
+	lonely->cb->tStart - branch->maxT, gapData);
+if (maxScore < bestSoFar.score)
+    return bestSoFar;
+
+
+/* If it's a terminal branch, then calculate score to connect
+ * with it. */
+else if ((leaf = branch->leaf) != NULL)
+    {
+    if (leaf->cb->qStart < lonely->cb->qStart 
+     && leaf->cb->tStart < lonely->cb->tStart)
+	{
+	double score = leaf->totalScore + lonely->cb->score - 
+		connectCost(leaf->cb, lonely->cb, gapData);
+	if (score > bestSoFar.score)
+	   {
+	   bestSoFar.score = score;
+	   bestSoFar.pred = branch;
+	   }
+	}
+    return bestSoFar;
+    }
+
+/* Otherwise explore sub-trees that could harbor predecessors. */
+else
+    {
+    int newDim = 1-dim;
+    int dimCoord = (dim == 0 ? lonely->cb->qStart : lonely->cb->tStart);
+    
+    /* Explore hi branch first as it is more likely to have high
+     * scores.  However only explore it if it can have things starting
+     * before us. */
+    if (dimCoord > branch->cutCoord)
+         bestSoFar = bestPredecessor(lonely, connectCost, gapCost, gapData,
+	 	newDim, branch->hi, bestSoFar);
+    bestSoFar = bestPredecessor(lonely, connectCost, gapCost, gapData,
+    	newDim, branch->lo, bestSoFar);
+    return bestSoFar;
+    }
+}
+
+static void updateScoresOnWay(struct kdBranch *branch, 
+	int dim, struct kdLeaf *leaf)
+/* Traverse kd-tree to find leaf.  Update all maxScores on the way
+ * to reflect leaf->totalScore. */
+{
+int newDim = 1-dim;
+int dimCoord = (dim == 0 ? leaf->cb->qStart : leaf->cb->tStart);
+if (branch->maxScore < leaf->totalScore) branch->maxScore = leaf->totalScore;
+if (branch->leaf == NULL)
+    {
+    if (dimCoord <= branch->cutCoord)
+	updateScoresOnWay(branch->lo, newDim, leaf);
+    if (dimCoord >= branch->cutCoord)
+	updateScoresOnWay(branch->hi, newDim, leaf);
+    }
+}
+
+static void findBestPredecessors(struct kdTree *tree, struct kdLeaf *leafList, 
+	ConnectCost connectCost, GapCost gapCost, void *gapData)
+/* Find best predecessor for each leaf. */
+{
+static struct predScore noBest;
+struct kdLeaf *leaf;
+double bestScore = 0;
+
+for (leaf = leafList; leaf != NULL; leaf = leaf->next)
+    {
+    struct predScore best;
+    best = bestPredecessor(leaf, connectCost, gapCost, gapData, 0, tree->root, noBest);
+    if (best.score > leaf->totalScore)
+        {
+	leaf->totalScore = best.score;
+	leaf->bestPred = best.pred;
+	}
+    updateScoresOnWay(tree->root, 0, leaf);
+    if (bestScore < leaf->totalScore)
+        {
+	bestScore = leaf->totalScore;
+	}
+    }
+}
+
+static double scoreBlocks(struct cBlock *blockList, ConnectCost connectCost,
+	void *gapData)
+/* Score list of blocks including gaps between blocks. */
+{
+struct cBlock *block, *lastBlock = NULL;
+double score = 0;
+for (block = blockList; block != NULL; block = block->next)
+    {
+    score += block->score;
+    if (lastBlock != NULL)
+	score -= connectCost(lastBlock, block, gapData);
+    lastBlock = block;
+    }
+return score;
+}
+
+static struct chain *peelChains(char *qName, int qSize, char qStrand,
+	char *tName, int tSize, struct kdLeaf *leafList, FILE *details)
+/* Peel off all chains from tree implied by
+ * best predecessors. */
+{
+struct kdLeaf *leaf;
+struct chain *chainList = NULL, *chain;
+for (leaf = leafList; leaf != NULL; leaf = leaf->next)
+    leaf->hit = FALSE;
+for (leaf = leafList; leaf != NULL; leaf = leaf->next)
+    {
+    if (!leaf->hit)
+        {
+	struct kdLeaf *lf;
+	AllocVar(chain);
+	chain->qName = cloneString(qName);
+	chain->qSize = qSize;
+	chain->qStrand = qStrand;
+	chain->tName = cloneString(tName);
+	chain->tSize = tSize;
+	chain->qEnd = leaf->cb->qEnd;
+	chain->tEnd = leaf->cb->tEnd;
+	if (details)
+	    {
+	    chain->score = leaf->totalScore;
+	    chain->id = -1;
+	    chainWriteHead(chain, details);
+	    chain->score = 0;
+	    chain->id = 0;
+	    }
+	slAddHead(&chainList, chain);
+	for (lf = leaf; ; )
+	    {
+	    lf->hit = TRUE;
+	    slAddHead(&chain->blockList, lf->cb);
+	    chain->qStart = lf->cb->qStart;
+	    chain->tStart = lf->cb->tStart;
+	    if (details)
+	        {
+		struct cBlock *b = lf->cb;
+		fprintf(details, "%d\t%f\t%d\t%d\t%d\n", b->score, lf->totalScore,
+			b->tStart, b->qStart, b->qEnd - b->qStart);
+		}
+	    if (lf->bestPred == NULL)
+	         break;
+	    else
+	        {
+		if (details)
+		    {
+		    struct cBlock *b = lf->cb;
+		    struct cBlock *a = lf->bestPred->leaf->cb;
+		    fprintf(details, " gap %d\t%d\n", 
+			b->tStart - a->tEnd, b->qStart - a->qEnd);
+		    }
+		}
+	    lf = lf->bestPred->leaf;
+	    if (lf->hit)
+	        break;
+	    }
+	}
+    }
+slReverse(&chainList);
+return chainList;
+}
+
+struct chain *chainBlocks(
+	char *qName, int qSize, char qStrand,	/* Info on query sequence */
+	char *tName, int tSize, 		/* Info on target. */
+	struct cBlock **pBlockList, 		/* Unordered ungapped alignments. */
+	ConnectCost connectCost, 		/* Calculate cost to connect nodes. */
+	GapCost gapCost, 			/* Cost for non-overlapping nodes. */
+	void *gapData, 				/* Passed through to connect/gapCosts */
+	FILE *details)				/* NULL except for debugging */
+/* Create list of chains from list of blocks.  The blockList will get
+ * eaten up as the blocks are moved from the list to the chain. 
+ * The list of chains returned is sorted by score. 
+ *
+ * The details FILE may be NULL, and is where additional information
+ * about the chaining is put.
+ *
+ * Note that the connectCost needs to adjust for possibly partially 
+ * overlapping blocks, and that these need to be taken out of the
+ * resulting chains in general.  This can get fairly complex.  Also
+ * the chains will need some cleanup at the end.  Use the chainConnect
+ * module to help with this.  See hg/mouseStuff/axtChain for example usage. */
+{
+struct kdTree *tree;
+struct kdLeaf *leafList = NULL, *leaf;
+struct cBlock *block;
+struct chain *chainList = NULL, *chain;
+struct lm *lm;
+
+/* Empty lists will be problematic later, so deal with them here. */
+if (*pBlockList == NULL)
+   return NULL;
+
+/* Make a leaf for each block. */
+lm = lmInit(0);  /* Memory for tree, branches and leaves. */
+for (block = *pBlockList; block != NULL; block = block->next)
+    {
+    /* Watch out for 0-length blocks in input: */
+    if (block->tStart == block->tEnd)
+	continue;
+    lmAllocVar(lm, leaf);
+    leaf->cb = block;
+    leaf->totalScore = block->score;
+    slAddHead(&leafList, leaf);
+    }
+
+/* Figure out chains. */
+slSort(&leafList, kdLeafCmpT);
+tree = kdTreeMake(leafList, lm);
+findBestPredecessors(tree, leafList, connectCost, gapCost, gapData);
+slSort(&leafList, kdLeafCmpTotal);
+chainList = peelChains(qName, qSize, qStrand, tName, tSize, leafList, details);
+
+/* Rescore chains (since some truncated) */
+for (chain = chainList; chain != NULL; chain = chain->next)
+    chain->score = scoreBlocks(chain->blockList, connectCost, gapData);
+slSort(&chainList,  chainCmpScore);
+
+/* Clean up and go home. */
+lmCleanup(&lm);
+*pBlockList = NULL;
+return chainList;
+}
+
diff --git a/lib/chainConnect.c b/lib/chainConnect.c
new file mode 100644
index 0000000..3e513dc
--- /dev/null
+++ b/lib/chainConnect.c
@@ -0,0 +1,366 @@
+/* chainConnect - Stuff to cope with connect costs and overlaps when 
+ * making chains. This works closely with the chainBlock module. */
+
+#include "common.h"
+#include "chain.h"
+#include "axt.h"
+#include "gapCalc.h"
+#include "chainConnect.h"
+
+
+double chainScoreBlock(char *q, char *t, int size, int matrix[256][256])
+/* Score block through matrix. */
+{
+double score = 0;
+int i;
+for (i=0; i<size; ++i)
+    score += matrix[(int)q[i]][(int)t[i]];
+return score;
+}
+
+double chainCalcScore(struct chain *chain, struct axtScoreScheme *ss, 
+	struct gapCalc *gapCalc, struct dnaSeq *query, struct dnaSeq *target)
+/* Calculate chain score freshly. */
+{
+struct cBlock *b1, *b2;
+double score = 0;
+for (b1 = chain->blockList; b1 != NULL; b1 = b2)
+    {
+    score += chainScoreBlock(query->dna + b1->qStart, 
+    	target->dna + b1->tStart, b1->tEnd - b1->tStart, ss->matrix);
+    b2 = b1->next;
+    if (b2 != NULL)
+        score -=  gapCalcCost(gapCalc, b2->qStart - b1->qEnd, 
+		              b2->tStart - b1->tEnd);
+    }
+return score;
+}
+
+double chainCalcScoreSubChain(struct chain *chain, struct axtScoreScheme *ss, 
+	struct gapCalc *gapCalc, struct dnaSeq *query, struct dnaSeq *target)
+/* Calculate chain score assuming query and target 
+   span the chained region rather than entire chrom. */
+{
+struct cBlock *b1, *b2;
+double score = 0;
+for (b1 = chain->blockList; b1 != NULL; b1 = b2)
+    {
+    score += chainScoreBlock(query->dna + (b1->qStart) - chain->qStart, 
+    	target->dna + (b1->tStart) - chain->tStart, b1->tEnd - b1->tStart, ss->matrix);
+    b2 = b1->next;
+    if (b2 != NULL)
+        score -=  gapCalcCost(gapCalc, b2->qStart - b1->qEnd, 
+		              b2->tStart - b1->tEnd);
+    }
+return score;
+}
+
+void cBlockFindCrossover(struct cBlock *left, struct cBlock *right,
+	struct dnaSeq *qSeq, struct dnaSeq *tSeq,  
+	int overlap, int matrix[256][256], int *retPos, int *retScoreAdjustment)
+/* Find ideal crossover point of overlapping blocks.  That is
+ * the point where we should start using the right block rather
+ * than the left block.  This point is an offset from the start
+ * of the overlapping region (which is the same as the start of the
+ * right block). */
+{
+int bestPos = 0;
+char *rqStart = qSeq->dna + right->qStart;
+char *lqStart = qSeq->dna + left->qEnd - overlap;
+char *rtStart = tSeq->dna + right->tStart;
+char *ltStart = tSeq->dna + left->tEnd - overlap;
+int i;
+double score, bestScore, rScore, lScore;
+
+/* Make sure overlap is not larger than either block size: */
+if (overlap > (left->tEnd - left->tStart) ||
+    overlap > (right->tEnd - right->tStart))
+    errAbort("overlap is %d -- too large for one of these:\n"
+	     "qSize=%d  tSize=%d\n"
+	     "left: qStart=%d qEnd=%d (%d) tStart=%d tEnd=%d (%d)\n"
+	     "right: qStart=%d qEnd=%d (%d) tStart=%d tEnd=%d (%d)\n",
+	     overlap, qSeq->size, tSeq->size,
+	     left->qStart, left->qEnd, left->qEnd - left->qStart,
+	     left->tStart, left->tEnd, left->tEnd - left->tStart,
+	     right->qStart, right->qEnd, right->qEnd - right->qStart, 
+	     right->tStart, right->tEnd, right->tEnd - right->tStart);
+
+score = bestScore = rScore = chainScoreBlock(rqStart, rtStart, overlap, matrix);
+lScore = chainScoreBlock(lqStart, ltStart, overlap, matrix);
+for (i=0; i<overlap; ++i)
+    {
+    score += matrix[(int)lqStart[i]][(int)ltStart[i]];
+    score -= matrix[(int)rqStart[i]][(int)rtStart[i]];
+    if (score > bestScore)
+	{
+	bestScore = score;
+	bestPos = i+1;
+	}
+    }
+*retPos = bestPos;
+*retScoreAdjustment = rScore + lScore - bestScore;
+}
+
+
+int chainConnectGapCost(int dq, int dt, struct chainConnect *cc)
+/* Calculate cost of non-overlapping gap. */
+{
+return gapCalcCost(cc->gapCalc, dq, dt);
+}
+
+int chainConnectCost(struct cBlock *a, struct cBlock *b, 
+	struct chainConnect *cc)
+/* Calculate connection cost - including gap score
+ * and overlap adjustments if any. */
+{
+int dq = b->qStart - a->qEnd;
+int dt = b->tStart - a->tEnd;
+int overlapAdjustment = 0;
+
+if (a->qStart >= b->qStart || a->tStart >= b->tStart)
+    {
+    errAbort("a (%d %d) not strictly before b (%d %d)",
+    	a->qStart, a->tStart, b->qStart, b->tStart);
+    }
+if (dq < 0 || dt < 0)
+   {
+   int bSize = b->qEnd - b->qStart;
+   int aSize = a->qEnd - a->qStart;
+   int overlap = -min(dq, dt);
+   int crossover;
+   if (overlap >= bSize || overlap >= aSize) 
+       {
+       /* One of the blocks is enclosed completely on one dimension
+        * or other by the other.  Discourage this overlap. */
+       overlapAdjustment = 100000000;
+       }
+   else
+       {
+       cBlockFindCrossover(a, b, cc->query, cc->target, overlap, 
+       		cc->ss->matrix, &crossover, &overlapAdjustment);
+       dq += overlap;
+       dt += overlap;
+       }
+   }
+return overlapAdjustment + gapCalcCost(cc->gapCalc, dq, dt);
+}
+
+static void checkStartBeforeEnd(struct chain *chain, char *message)
+/* Check qStart < qEnd, tStart < tEnd for each block. */
+{
+struct cBlock *b;
+for (b = chain->blockList; b != NULL; b = b->next)
+    {
+    if (b->qStart >= b->qEnd || b->tStart >= b->tEnd)
+	errAbort("Start after end in (%d %d) to (%d %d) %s",
+	    b->qStart, b->tStart, b->qEnd, b->tEnd, message);
+    }
+}
+
+static void checkChainGaps(struct chain *chain, char *message)
+/* Check that gaps between blocks are non-negative. */
+{
+struct cBlock *a, *b;
+a = chain->blockList;
+if (a == NULL)
+    return;
+for (b = a->next; b != NULL; b = b->next)
+    {
+    if (a->qEnd > b->qStart || a->tEnd > b->tStart)
+	{
+	errAbort("Negative gap between (%d %d - %d %d) and (%d %d - %d %d) %s",
+	    a->qStart, a->tStart, a->qEnd, a->tEnd, 
+	    b->qStart, b->tStart, b->qEnd, b->tEnd, message);
+	}
+    a = b;
+    }
+}
+
+static void checkChainIncreases(struct chain *chain, char *message)
+/* Check that qStart and tStart both strictly increase
+ * in chain->blockList. */
+{
+struct cBlock *a, *b;
+a = chain->blockList;
+if (a == NULL)
+    return;
+for (b = a->next; b != NULL; b = b->next)
+    {
+    if (a->qStart >= b->qStart || a->tStart >= b->tStart)
+	{
+	errAbort("a (%d %d) not before b (%d %d) %s",
+	    a->qStart, a->tStart, b->qStart, b->tStart, message);
+	}
+    a = b;
+    }
+}
+
+void chainCalcBounds(struct chain *chain)
+/* Recalculate chain boundaries - setting qStart/qEnd/tStart/tEnd from
+ * a scan of blockList. */
+{
+struct cBlock *b = chain->blockList;
+if (chain->blockList == NULL)
+    return;
+chain->qStart = b->qStart;
+chain->tStart = b->tStart;
+b = slLastEl(chain->blockList);
+chain->qEnd = b->qEnd;
+chain->tEnd = b->tEnd;
+}
+
+static boolean removeNegativeBlocks(struct chain *chain)
+/* Removing the partial overlaps occassional results
+ * in all of a block being removed.  This routine
+ * removes the dried up husks of these blocks 
+ * and returns TRUE if it finds any. */
+{
+struct cBlock *newList = NULL, *b, *next;
+boolean gotNeg = FALSE;
+for (b = chain->blockList; b != NULL; b = next)
+    {
+    next = b->next;
+    if (b->qStart >= b->qEnd || b->tStart >= b->tEnd)
+	{
+        gotNeg = TRUE;
+	freeMem(b);
+	}
+    else
+        {
+	slAddHead(&newList, b);
+	}
+    }
+slReverse(&newList);
+chain->blockList = newList;
+if (gotNeg)
+    chainCalcBounds(chain);
+return gotNeg;
+}
+
+void setChainBounds(struct chain *chain)
+/* Set chain overall bounds to fit blocks. */
+{
+struct cBlock *b = chain->blockList;
+chain->qStart = b->qStart;
+chain->tStart = b->tStart;
+while (b->next != NULL)
+     b = b->next;
+chain->qEnd = b->qEnd;
+chain->tEnd = b->tEnd;
+}
+
+void chainRemovePartialOverlaps(struct chain *chain, 
+	struct dnaSeq *qSeq, struct dnaSeq *tSeq, int matrix[256][256])
+/* If adjacent blocks overlap then find crossover points between them. */
+{
+struct cBlock *a, *b;
+boolean totalTrimA, totalTrimB;
+
+assert(chain->blockList != NULL);
+
+/* Do an internal sanity check to make sure that things
+ * really are sorted by both qStart and tStart. */
+checkChainIncreases(chain, "before removePartialOverlaps");
+
+/* Remove overlapping portion of blocks.  In some
+ * tricky repeating regions this can result in 
+ * complete blocks being removed.  This complicates
+ * the loop below in some cases, forcing us to essentially
+ * start over when the first of the two blocks we
+ * are examining gets trimmed out completely. */
+for (;;)
+    {
+    totalTrimA = totalTrimB = FALSE;
+    a = chain->blockList;
+    b = a->next;
+    for (;;)
+        {
+	int dq, dt;
+	if (b == NULL)
+	    break;
+	dq = b->qStart - a->qEnd;
+	dt = b->tStart - a->tEnd;
+	if (dq < 0 || dt < 0)
+	   {
+	   int overlap = -min(dq, dt);
+	   int aSize = a->qEnd - a->qStart;
+	   int bSize = b->qEnd - b->qStart;
+	   int crossover, invCross, overlapAdjustment;
+	   if (overlap >= aSize || overlap >= bSize)
+	       {
+	       totalTrimB = TRUE;
+	       }
+	   else
+	       {
+	       cBlockFindCrossover(a, b, qSeq, tSeq, overlap, matrix, 
+	                     &crossover, &overlapAdjustment);
+	       b->qStart += crossover;
+	       b->tStart += crossover;
+	       invCross = overlap - crossover;
+	       a->qEnd -= invCross;
+	       a->tEnd -= invCross;
+	       if (b->qEnd <= b->qStart)
+		   {
+		   totalTrimB = TRUE;
+		   }
+	       else if (a->qEnd <= a->qStart)
+		   {
+		   totalTrimA = TRUE;
+		   }
+	       }
+	   }
+	if (totalTrimA == TRUE)
+	    {
+	    removeNegativeBlocks(chain);
+	    break;
+	    }
+	else if (totalTrimB == TRUE)
+	    {
+	    b = b->next;
+	    freez(&a->next);
+	    a->next = b;
+	    totalTrimB = FALSE;
+	    }
+	else
+	    {
+	    a = b;
+	    b = b->next;
+	    }
+	}
+    if (!totalTrimA)
+        break;
+    }
+
+/* Reset chain bounds - may have clipped them in this
+ * process. */
+setChainBounds(chain);
+
+/* Do internal sanity checks. */
+checkChainGaps(chain, "after removePartialOverlaps");
+checkStartBeforeEnd(chain, "after removePartialOverlaps");
+}
+
+void chainMergeAbutting(struct chain *chain)
+/* Merge together blocks in a chain that abut each
+ * other exactly. */
+{
+struct cBlock *newList = NULL, *b, *last = NULL, *next;
+for (b = chain->blockList; b != NULL; b = next)
+    {
+    next = b->next;
+    if (last == NULL || last->qEnd != b->qStart || last->tEnd != b->tStart)
+	{
+	slAddHead(&newList, b);
+	last = b;
+	}
+    else
+        {
+	last->qEnd = b->qEnd;
+	last->tEnd = b->tEnd;
+	freeMem(b);
+	}
+    }
+slReverse(&newList);
+chain->blockList = newList;
+}
+
diff --git a/lib/chainToAxt.c b/lib/chainToAxt.c
new file mode 100644
index 0000000..66d18ad
--- /dev/null
+++ b/lib/chainToAxt.c
@@ -0,0 +1,121 @@
+/* chainToAxt - convert from chain to axt format. */
+
+#include "common.h"
+#include "chain.h"
+#include "dnautil.h"
+#include "dnaseq.h"
+#include "axt.h"
+#include "chainToAxt.h"
+
+
+static struct axt *axtFromBlocks(
+	struct chain *chain,
+	struct cBlock *startB, struct cBlock *endB,
+	struct dnaSeq *qSeq, int qOffset,
+	struct dnaSeq *tSeq, int tOffset)
+/* Convert a list of blocks (guaranteed not to have inserts in both
+ * strands between them) to an axt. */
+{
+int symCount = 0;
+int dq, dt, blockSize = 0, symIx = 0;
+struct cBlock *b, *a = NULL;
+struct axt *axt;
+char *qSym, *tSym;
+
+/* Make a pass through figuring out how big output will be. */
+for (b = startB; b != endB; b = b->next)
+    {
+    if (a != NULL)
+        {
+	dq = b->qStart - a->qEnd;
+	dt = b->tStart - a->tEnd;
+	symCount += dq + dt;
+	}
+    blockSize = b->qEnd - b->qStart;
+    symCount += blockSize;
+    a = b;
+    }
+
+/* Allocate axt and fill in most fields. */
+AllocVar(axt);
+axt->qName = cloneString(chain->qName);
+axt->qStart = startB->qStart;
+axt->qEnd = a->qEnd;
+axt->qStrand = chain->qStrand;
+axt->tName = cloneString(chain->tName);
+axt->tStart = startB->tStart;
+axt->tEnd = a->tEnd;
+axt->tStrand = '+';
+axt->symCount = symCount;
+axt->qSym = qSym = needLargeMem(symCount+1);
+qSym[symCount] = 0;
+axt->tSym = tSym = needLargeMem(symCount+1);
+tSym[symCount] = 0;
+
+/* Fill in symbols. */
+a = NULL;
+for (b = startB; b != endB; b = b->next)
+    {
+    if (a != NULL)
+        {
+	dq = b->qStart - a->qEnd;
+	dt = b->tStart - a->tEnd;
+	if (dq == 0)
+	    {
+	    memset(qSym+symIx, '-', dt);
+	    memcpy(tSym+symIx, tSeq->dna + a->tEnd - tOffset, dt);
+	    symIx += dt;
+	    }
+	else
+	    {
+	    assert(dt == 0);
+	    memset(tSym+symIx, '-', dq);
+	    memcpy(qSym+symIx, qSeq->dna + a->qEnd - qOffset, dq);
+	    symIx += dq;
+	    }
+	}
+    blockSize = b->qEnd - b->qStart;
+    memcpy(qSym+symIx, qSeq->dna + b->qStart - qOffset, blockSize);
+    memcpy(tSym+symIx, tSeq->dna + b->tStart - tOffset, blockSize);
+    symIx += blockSize;
+    a = b;
+    }
+assert(symIx == symCount);
+
+/* Fill in score and return. */
+axt->score = axtScoreDnaDefault(axt);
+return axt;
+}
+
+struct axt *chainToAxt(struct chain *chain, 
+	struct dnaSeq *qSeq, int qOffset,
+	struct dnaSeq *tSeq, int tOffset, int maxGap, int maxChain)
+/* Convert a chain to a list of axt's.  This will break
+ * where there is a double-sided gap in chain, or 
+ * where there is a single-sided gap greater than maxGap, or 
+ * where there is a chain longer than maxChain.
+ */
+{
+struct cBlock *startB = chain->blockList, *a = NULL, *b;
+struct axt *axtList = NULL, *axt;
+
+for (b = chain->blockList; b != NULL; b = b->next)
+    {
+    if (a != NULL)
+        {
+	int dq = b->qStart - a->qEnd;
+	int dt = b->tStart - a->tEnd;
+	if ((dq > 0 && dt > 0) || dt > maxGap || dq > maxGap || (b->tEnd - startB->tStart) > maxChain)
+	    {
+	    axt = axtFromBlocks(chain, startB, b, qSeq, qOffset, tSeq, tOffset);
+	    slAddHead(&axtList, axt);
+	    startB = b;
+	    }
+	}
+    a = b;
+    }
+axt = axtFromBlocks(chain, startB, NULL, qSeq, qOffset, tSeq, tOffset);
+slAddHead(&axtList, axt);
+slReverse(&axtList);
+return axtList;
+}
diff --git a/lib/chainToPsl.c b/lib/chainToPsl.c
new file mode 100644
index 0000000..d6c92d3
--- /dev/null
+++ b/lib/chainToPsl.c
@@ -0,0 +1,122 @@
+/* chainToPsl - convert between chains and psl.  Both of these
+ * are alignment formats that can handle gaps in both strands
+ * and do not include the sequence itself. */
+
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "psl.h"
+#include "chain.h"
+
+
+
+struct psl *chainToPsl(struct chain *chain)
+/* chainToPsl - convert chain to psl.  This does not fill in
+ * the match, repMatch, mismatch, and N fields since it needs
+ * the sequence for that.  It does fill in the rest though. */
+{
+struct psl *psl;
+int blockCount, i;
+struct cBlock *b, *nextB;
+
+blockCount = slCount(chain->blockList);
+AllocVar(psl);
+AllocArray(psl->blockSizes, blockCount);
+AllocArray(psl->qStarts, blockCount);
+AllocArray(psl->tStarts, blockCount);
+psl->strand[0] = chain->qStrand;
+psl->qName = cloneString(chain->qName);
+psl->qSize = chain->qSize;
+if (chain->qStrand == '-')
+    {
+    psl->qStart = chain->qSize - chain->qEnd;
+    psl->qEnd = chain->qSize - chain->qStart;
+    }
+else
+    {
+    psl->qStart = chain->qStart;
+    psl->qEnd = chain->qEnd;
+    }
+psl->tName = cloneString(chain->tName);
+psl->tSize = chain->tSize;
+psl->tStart = chain->tStart;
+psl->tEnd = chain->tEnd;
+psl->blockCount = blockCount;
+for (i=0, b=chain->blockList; i < blockCount; ++i, b = nextB)
+    {
+    nextB = b->next;
+    psl->tStarts[i] = b->tStart;
+    psl->qStarts[i] = b->qStart;
+    psl->blockSizes[i] = b->qEnd - b->qStart;
+    if (nextB != NULL)
+        {
+	int qGap = nextB->qStart - b->qEnd;
+	int tGap = nextB->tStart - b->tEnd;
+	if (qGap != 0)
+	    {
+	    psl->qBaseInsert += qGap;
+	    psl->qNumInsert += 1;
+	    }
+	if (tGap != 0)
+	    {
+	    psl->tBaseInsert += tGap;
+	    psl->tNumInsert += 1;
+	    }
+	}
+    }
+return psl;
+}
+
+static void fillInMatchEtc(struct chain *chain, 
+	struct dnaSeq *query, struct dnaSeq *target, struct psl *psl)
+/* Fill in psl->match,mismatch,repMatch, and nCount fields.
+ * Assumes that query and target are on correct strands already. */
+{
+struct cBlock *block;
+unsigned match = 0, misMatch=0, repMatch=0, nCount=0;
+for (block = chain->blockList; block != NULL; block = block->next)
+    {
+    DNA *qDna = query->dna + block->qStart;
+    DNA *tDna = target->dna + block->tStart;
+    int i, size = block->qEnd - block->qStart;
+    for (i=0; i<size; ++i)
+        {
+	DNA q,t;
+	int qv, tv;
+	q = qDna[i];
+	t = tDna[i];
+	qv = ntVal[(int)q];
+	tv = ntVal[(int)t];
+	if (qv < 0 || tv < 0)
+	    ++nCount;
+	else if (qv == tv)
+	    {
+	    if (isupper(q) && isupper(t))
+	        ++match;
+	    else
+	        ++repMatch;
+	    }
+	else 
+	    ++misMatch;
+        }
+    }
+psl->match = match;
+psl->misMatch = misMatch;
+psl->repMatch = repMatch;
+psl->nCount = nCount;
+}
+
+struct psl *chainToFullPsl(struct chain *chain, 
+	struct dnaSeq *query,   /* Forward query sequence. */
+	struct dnaSeq *rQuery,	/* Reverse complemented query sequence. */
+	struct dnaSeq *target)
+/* Convert chainList to pslList, filling in matches, N's etc. */
+{
+struct psl *psl = chainToPsl(chain);
+struct dnaSeq *qSeq = (chain->qStrand == '-' ? rQuery : query);
+fillInMatchEtc(chain, qSeq, target, psl);
+return psl;
+}
+
+
+
diff --git a/lib/cheapcgi.c b/lib/cheapcgi.c
new file mode 100644
index 0000000..a9f0927
--- /dev/null
+++ b/lib/cheapcgi.c
@@ -0,0 +1,2110 @@
+/* Routines for getting variables passed in from web page
+ * forms via CGI.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "hash.h"
+#include "cheapcgi.h"
+#include "portable.h"
+#include "linefile.h"
+#include "errabort.h"
+#ifndef GBROWSE
+#include "mime.h"
+#endif /* GBROWSE */
+#include <signal.h>
+
+
+/* These three variables hold the parsed version of cgi variables. */
+static char *inputString = NULL;
+static unsigned long inputSize;
+static struct hash *inputHash = NULL;
+static struct cgiVar *inputList = NULL;
+
+static boolean haveCookiesHash = FALSE;
+static struct hash *cookieHash = NULL;
+static struct cgiVar *cookieList = NULL;
+
+/* should cheapcgi use temp files to store uploaded files */
+static boolean doUseTempFile = FALSE;
+
+void dumpCookieList()
+/* Print out the cookie list. */
+{
+struct cgiVar *v;
+for (v=cookieList; v != NULL; v = v->next)
+    printf("%s=%s (%d)\n", v->name, v->val, v->saved);
+}
+
+void useTempFile()
+/* tell cheapcgi to use temp files */
+{
+doUseTempFile = TRUE;
+}
+
+boolean cgiIsOnWeb()
+/* Return TRUE if looks like we're being run as a CGI. */
+{
+return getenv("REQUEST_METHOD") != NULL;
+}
+
+char *cgiRequestMethod()
+/* Return CGI REQUEST_METHOD (such as 'GET/POST/PUT/DELETE/HEAD') */
+{
+return getenv("REQUEST_METHOD");
+}
+
+char *cgiRequestUri()
+/* Return CGI REQUEST_URI */
+{
+return getenv("REQUEST_URI");
+}
+
+char *cgiRequestContentLength()
+/* Return HTTP REQUEST CONTENT_LENGTH if available*/
+{
+return getenv("CONTENT_LENGTH");
+}
+
+char *cgiScriptName()
+/* Return name of script so libs can do context-sensitive stuff. */
+{
+return getenv("SCRIPT_NAME");
+}
+
+char *cgiServerName()
+/* Return name of server, better to use cgiServerNamePort() for
+   actual URL construction */
+{
+return getenv("SERVER_NAME");
+}
+
+char *cgiServerPort()
+/* Return port number of server, default 80 if not found */
+{
+char *port = getenv("SERVER_PORT");
+if (port)
+    return port;
+else
+    return "80";
+}
+
+char *cgiServerNamePort()
+/* Return name of server with port if different than 80 */
+{
+char *port = cgiServerPort();
+char *namePort = cgiServerName();
+struct dyString *result = newDyString(256);
+if (namePort)
+    {
+    dyStringPrintf(result,"%s",namePort);
+    if (differentString(port, "80"))
+	dyStringPrintf(result,":%s",port);
+    return dyStringCannibalize(&result);
+    }
+else
+    return NULL;
+}
+
+char *cgiRemoteAddr()
+/* Return IP address of client (or "unknown"). */
+{
+static char *dunno = "unknown";
+char *remoteAddr = getenv("REMOTE_ADDR");
+if (remoteAddr == NULL)
+    remoteAddr = dunno;
+return remoteAddr;
+}
+
+char *cgiUserAgent()
+/* Return remote user agent (HTTP_USER_AGENT) or NULL if remote user agent is not known */
+{
+return getenv("HTTP_USER_AGENT");
+}
+
+enum browserType cgiClientBrowser(char **browserQualifier, enum osType *clientOs,
+                                  char **clientOsQualifier)
+/* Return client browser type determined from (HTTP_USER_AGENT)
+   Optionally requuest the additional info about the client */
+{
+// WARNING: The specifics of the HTTP_USER_AGENT vary widely.
+//          This has only been tested on a few cases.
+static enum browserType clientBrowser = btUnknown;
+static enum browserType clientOsType  = osUnknown;
+static char *clientBrowserExtra       = NULL;
+static char *clientOsExtra            = NULL;
+
+if (clientBrowser == btUnknown)
+    {
+    char *userAgent = cgiUserAgent();
+    if (userAgent != NULL)
+        {
+        //warn(userAgent);  // Use this to investigate other cases
+        char *ptr=NULL;
+
+        // Determine the browser
+        if ((ptr = stringIn("Opera",userAgent)) != NULL) // Must be before IE
+            {
+            clientBrowser = btOpera;
+            }
+        else if ((ptr = stringIn("MSIE ",userAgent)) != NULL)
+            {
+            clientBrowser = btIE;
+            ptr += strlen("MSIE ");
+            clientBrowserExtra = cloneFirstWordByDelimiter(ptr,';');
+            }
+        else if ((ptr = stringIn("Firefox",userAgent)) != NULL)
+            {
+            clientBrowser = btFF;
+            ptr += strlen("(Firefox/");
+            clientBrowserExtra = cloneFirstWordByDelimiter(ptr,' ');
+            }
+        else if ((ptr = stringIn("Chrome",userAgent)) != NULL)  // Must be before Safari
+            {
+            clientBrowser = btChrome;
+            ptr += strlen("Chrome/");
+            clientBrowserExtra = cloneFirstWordByDelimiter(ptr,' ');
+            }
+        else if ((ptr = stringIn("Safari",userAgent)) != NULL)
+            {
+            clientBrowser = btSafari;
+            ptr += strlen("Safari/");
+            clientBrowserExtra = cloneFirstWordByDelimiter(ptr,' ');
+            }
+        else
+            {
+            clientBrowser = btOther;
+            }
+
+        // Determine the OS
+        if ((ptr = stringIn("Windows",userAgent)) != NULL)
+            {
+            clientOsType = osWindows;
+            ptr += strlen("Windows ");
+            clientOsExtra = cloneFirstWordByDelimiter(ptr,';');
+            }
+        else if ((ptr = stringIn("Linux",userAgent)) != NULL)
+            {
+            clientOsType = osLinux;
+            ptr += strlen("Linux ");
+            clientOsExtra = cloneFirstWordByDelimiter(ptr,';');
+            }
+        else if ((ptr = stringIn("Mac ",userAgent)) != NULL)
+            {
+            clientOsType = osMac;
+            ptr += strlen("Mac ");
+            clientOsExtra = cloneFirstWordByDelimiter(ptr,';');
+            }
+        else
+            {
+            clientOsType = osOther;
+            }
+        }
+    }
+if (browserQualifier != NULL)
+    {
+    if (clientBrowserExtra != NULL)
+        *browserQualifier = cloneString(clientBrowserExtra);
+    else
+        *browserQualifier = NULL;
+    }
+if (clientOs != NULL)
+    *clientOs = clientOsType;
+if (clientOsQualifier != NULL)
+    {
+    if (clientOsExtra != NULL)
+        *clientOsQualifier = cloneString(clientOsExtra);
+    else
+        *clientOsQualifier = NULL;
+    }
+
+return clientBrowser;
+}
+
+char *_cgiRawInput()
+/* For debugging get the unprocessed input. */
+{
+return inputString;
+}
+
+static void getQueryInputExt(boolean abortOnErr)
+/* Get query string from environment if they've used GET method. */
+{
+inputString = getenv("QUERY_STRING");
+if (inputString == NULL)
+    {
+    if (abortOnErr)
+	errAbort("No QUERY_STRING in environment.");
+    inputString = cloneString("");
+    return;
+    }
+inputString = cloneString(inputString);
+}
+
+static void getQueryInput()
+/* Get query string from environment if they've used GET method. */
+{
+getQueryInputExt(TRUE);
+}
+
+static void getPostInput()
+/* Get input from file if they've used POST method.
+ * Grab any GET QUERY_STRING input first. */
+{
+char *s;
+long i;
+int r;
+
+getQueryInputExt(FALSE);
+int getSize = strlen(inputString);
+
+s = getenv("CONTENT_LENGTH");
+if (s == NULL)
+    errAbort("No CONTENT_LENGTH in environment.");
+if (sscanf(s, "%lu", &inputSize) != 1)
+    errAbort("CONTENT_LENGTH isn't a number.");
+s = getenv("CONTENT_TYPE");
+if (s != NULL && startsWith("multipart/form-data", s))
+    {
+    /* use MIME parse on input stream instead, can handle large uploads */
+    /* inputString must not be NULL so it knows it was set */
+    return;
+    }
+int len = getSize + inputSize;
+if (getSize > 0)
+    ++len;
+char *temp = needMem((size_t)len+1);
+for (i=0; i<inputSize; ++i)
+    {
+    r = getc(stdin);
+    if (r == EOF)
+	errAbort("Short POST input.");
+    temp[i] = r;
+    }
+if (getSize > 0)
+  temp[i++] = '&';
+strncpy(temp+i, inputString, getSize);
+temp[len] = 0;
+freeMem(inputString);
+inputString = temp;
+}
+
+#define memmem(hay, haySize, needle, needleSize) \
+    memMatch(needle, needleSize, hay, haySize)
+
+#ifndef GBROWSE
+static void cgiParseMultipart(struct hash **retHash, struct cgiVar **retList)
+/* process a multipart form */
+{
+char h[1024];  /* hold mime header line */
+char *s = NULL, *ct = NULL;
+struct dyString *dy = newDyString(256);
+struct mimeBuf *mb = NULL;
+struct mimePart *mp = NULL;
+char **env = NULL;
+struct hash *hash = newHash(6);
+struct cgiVar *list = NULL, *el;
+extern char **environ;
+
+
+//debug
+//fprintf(stderr,"GALT: top of cgiParseMultipart()\n");
+//fflush(stderr);
+
+/* find the CONTENT_ environment strings, use to make Alternate Header string for MIME */
+for(env=environ; *env; env++)
+    if (startsWith("CONTENT_",*env))
+	{
+	//debug
+        //fprintf(stderr,"%s\n",*env);  //debug
+	safef(h,sizeof(h),"%s",*env);
+	s = strchr(h,'_');    /* change env syntax to MIME style header, from _= to -: */
+	if (!s)
+	    errAbort("expecting '_' parsing env var %s for MIME alt header", *env);
+	*s = '-';
+	s = strchr(h,'=');
+	if (!s)
+	    errAbort("expecting '=' parsing env var %s for MIME alt header", *env);
+	*s = ':';
+	dyStringPrintf(dy,"%s\r\n",h);
+	}
+dyStringAppend(dy,"\r\n");  /* blank line at end means end of headers */
+
+//debug
+//fprintf(stderr,"Alternate Header Text:\n%s",dy->string);
+//fflush(stderr);
+mb = initMimeBuf(STDIN_FILENO);
+//debug
+//fprintf(stderr,"got past initMimeBuf(STDIN_FILENO)\n");
+//fflush(stderr);
+mp = parseMultiParts(mb, cloneString(dy->string)); /* The Alternate Header will get freed */
+freeDyString(&dy);
+if(!mp->multi) /* expecting multipart child parts */
+    errAbort("Malformatted multipart-form.");
+
+//debug
+//fprintf(stderr,"GALT: Wow got past parse of MIME!\n");
+//fflush(stderr);
+
+ct = hashFindVal(mp->hdr,"content-type");
+//debug
+//fprintf(stderr,"GALT: main content-type: %s\n",ct);
+//fflush(stderr);
+if (!startsWith("multipart/form-data",ct))
+    errAbort("main content-type expected starts with [multipart/form-data], found [%s]",ct);
+
+for(mp=mp->multi;mp;mp=mp->next)
+    {
+    char *cd = NULL, *cdMain = NULL, *cdName = NULL, *cdFileName = NULL, *ct = NULL;
+    cd = hashFindVal(mp->hdr,"content-disposition");
+    ct = hashFindVal(mp->hdr,"content-type");
+    //debug
+    //fprintf(stderr,"GALT: content-disposition: %s\n",cd);
+    //fprintf(stderr,"GALT: content-type: %s\n",ct);
+    //fflush(stderr);
+    cdMain=getMimeHeaderMainVal(cd);
+    cdName=getMimeHeaderFieldVal(cd,"name");
+    cdFileName=getMimeHeaderFieldVal(cd,"filename");
+    //debug
+    //fprintf(stderr,"cgiParseMultipart: main:[%s], name:[%s], filename:[%s]\n",cdMain,cdName,cdFileName);
+    //fflush(stderr);
+    if (!sameString(cdMain,"form-data"))
+	errAbort("main content-type expected [form-data], found [%s]",cdMain);
+
+    //debug
+    //fprintf(stderr,"GALT: mp->size[%llu], mp->binary=[%d], mp->fileName=[%s], mp=>data:[%s]\n",
+        //(unsigned long long) mp->size, mp->binary, mp->fileName,
+        //mp->binary && mp->data ? "<binary data not safe to print>" : mp->data);
+    //fflush(stderr);
+
+    /* filename if there is one */
+    /* Internet Explorer on Windows is sending full path names, strip
+     * directory name from those.  Using \ and / and : as potential
+     * path separator characters, e.g.:
+     *	 C:\Documents and Settings\tmp\file.txt.gz
+     */
+    if (cdFileName)
+	{
+	char *lastPathSep = strrchr(cdFileName, (int) '\\');
+	if (!lastPathSep)
+		lastPathSep = strrchr(cdFileName, (int) '/');
+	if (!lastPathSep)
+		lastPathSep = strrchr(cdFileName, (int) ':');
+	char varNameFilename[256];
+	safef(varNameFilename, sizeof(varNameFilename), "%s__filename", cdName);
+	AllocVar(el);
+	if (lastPathSep)
+	    el->val = cloneString(lastPathSep+1);
+	else
+	    el->val = cloneString(cdFileName);
+        slAddHead(&list, el);
+        hashAddSaveName(hash, varNameFilename, el, &el->name);
+        }
+
+    if (mp->data)
+        {
+        if (mp->binary)
+	    {
+	    char varNameBinary[256];
+	    char addrSizeBuf[40];
+	    safef(varNameBinary,sizeof(varNameBinary),"%s__binary",cdName);
+            safef(addrSizeBuf,sizeof(addrSizeBuf),"%lu %llu",
+		(unsigned long)mp->data,
+		(unsigned long long)mp->size);
+	    AllocVar(el);
+	    el->val = cloneString(addrSizeBuf);
+	    slAddHead(&list, el);
+	    hashAddSaveName(hash, varNameBinary, el, &el->name);
+	    }
+	else  /* normal variable, not too big, does not contain zeros */
+	    {
+	    AllocVar(el);
+	    el->val = mp->data;
+	    slAddHead(&list, el);
+	    hashAddSaveName(hash, cdName, el, &el->name);
+	    }
+        }
+    else if (mp->fileName)
+	{
+	char varNameData[256];
+	safef(varNameData, sizeof(varNameData), "%s__data", cdName);
+	AllocVar(el);
+        el->val = mp->fileName;
+        slAddHead(&list, el);
+        hashAddSaveName(hash, varNameData, el, &el->name);
+        //debug
+        //fprintf(stderr,"GALT special: saved varNameData:[%s], mp=>fileName:[%s]\n",el->name,el->val);
+        //fflush(stderr);
+        }
+    else if (mp->multi)
+	{
+	warn("unexpected nested MIME structures");
+	}
+    else
+	{
+	errAbort("mp-> type not data,fileName, or multi - unexpected MIME structure");
+	}
+
+    freez(&cdMain);
+    freez(&cdName);
+    freez(&cdFileName);
+    }
+
+slReverse(&list);
+*retList = list;
+*retHash = hash;
+}
+#endif /* GBROWSE */
+
+
+
+static void parseCookies(struct hash **retHash, struct cgiVar **retList)
+/* parses any cookies and puts them into the given hash and list */
+{
+char* str;
+char *namePt, *dataPt, *nextNamePt;
+struct hash *hash;
+struct cgiVar *list = NULL, *el;
+
+/* don't build the hash table again */
+if(haveCookiesHash == TRUE)
+	return;
+
+str = cloneString(getenv("HTTP_COOKIE"));
+if(str == NULL) /* don't have a cookie */
+	return;
+
+hash = newHash(6);
+
+namePt = str;
+while (isNotEmpty(namePt))
+    {
+    dataPt = strchr(namePt, '=');
+    if (dataPt == NULL)
+	errAbort("Mangled Cookie input string: no = in '%s' (offset %d in complete cookie string: '%s')",
+		 namePt, (int)(namePt - str), getenv("HTTP_COOKIE"));
+    *dataPt++ = 0;
+    nextNamePt = strchr(dataPt, ';');
+    if (nextNamePt != NULL)
+	{
+         *nextNamePt++ = 0;
+	 if (*nextNamePt == ' ')
+	     nextNamePt++;
+	}
+    cgiDecode(dataPt,dataPt,strlen(dataPt));
+    AllocVar(el);
+    el->val = dataPt;
+    slAddHead(&list, el);
+    hashAddSaveName(hash, namePt, el, &el->name);
+    namePt = nextNamePt;
+    }
+
+haveCookiesHash = TRUE;
+
+slReverse(&list);
+*retList = list;
+*retHash = hash;
+}
+
+char *findCookieData(char *varName)
+/* Get the string associated with varName from the cookie string. */
+{
+struct hashEl *hel;
+char *firstResult;
+
+/* make sure that the cookie hash table has been created */
+parseCookies(&cookieHash, &cookieList);
+if (cookieHash == NULL)
+    return NULL;
+/* Watch out for multiple cookies with the same name (hel is a list) --
+ * warn if we find them. */
+hel = hashLookup(cookieHash, varName);
+if (hel == NULL)
+    return NULL;
+else
+    firstResult = ((struct cgiVar *)hel->val)->val;
+hel = hel->next;
+while (hel != NULL)
+    {
+    char *val = ((struct cgiVar *)(hel->val))->val;
+    if (sameString(varName, hel->name) && !sameString(firstResult, val))
+	{
+	/* This is too early to call warn -- it will mess up html output. */
+	fprintf(stderr,
+		"findCookieData: Duplicate cookie value from IP=%s: "
+		"%s has both %s and %s\n",
+		cgiRemoteAddr(),
+		varName, firstResult, val);
+	}
+    hel = hel->next;
+    }
+return firstResult;
+}
+
+static char *cgiInputSource(char *s)
+/* For NULL sources make a guess as to real source. */
+{
+char *qs;
+if (s != NULL)
+    return s;
+qs = getenv("QUERY_STRING");
+if (qs == NULL)
+    return "POST";
+char *cl = getenv("CONTENT_LENGTH");
+if (cl != NULL && atoi(cl) > 0)
+    return "POST";
+return "QUERY";
+}
+
+static void _cgiFindInput(char *method)
+/* Get raw CGI input into inputString.  Method can be "POST", "QUERY", "GET" or NULL
+ * for unknown. */
+{
+if (inputString == NULL)
+    {
+    method = cgiInputSource(method);
+    if (sameWord(method, "POST"))
+        getPostInput();
+    else if (sameWord(method, "QUERY") || sameWord(method, "GET"))
+        getQueryInput();
+    else
+        errAbort("Unknown form method");
+    }
+}
+
+static void cgiParseInputAbort(char *input, struct hash **retHash,
+        struct cgiVar **retList)
+/* Parse cgi-style input into a hash table and list.  This will alter
+ * the input data.  The hash table will contain references back
+ * into input, so please don't free input until you're done with
+ * the hash. Prints message aborts if there's an error.*/
+{
+char *namePt, *dataPt, *nextNamePt;
+struct hash *hash = *retHash;
+struct cgiVar *list = *retList, *el;
+
+if (!hash)
+  hash = newHash(6);
+slReverse(&list);
+
+namePt = input;
+while (namePt != NULL && namePt[0] != 0)
+    {
+    dataPt = strchr(namePt, '=');
+    if (dataPt == NULL)
+	{
+	errAbort("Mangled CGI input string %s", namePt);
+	}
+    *dataPt++ = 0;
+    nextNamePt = strchr(dataPt, '&');
+    if (nextNamePt == NULL)
+	nextNamePt = strchr(dataPt, ';');	/* Accomodate DAS. */
+    if (nextNamePt != NULL)
+         *nextNamePt++ = 0;
+    cgiDecode(namePt,namePt,strlen(namePt));	/* for unusual ct names */
+    cgiDecode(dataPt,dataPt,strlen(dataPt));
+    AllocVar(el);
+    el->val = dataPt;
+    slAddHead(&list, el);
+    hashAddSaveName(hash, namePt, el, &el->name);
+    namePt = nextNamePt;
+    }
+slReverse(&list);
+*retList = list;
+*retHash = hash;
+}
+
+static jmp_buf cgiParseRecover;
+
+static void cgiParseAbort()
+/* Abort cgi parsing. */
+{
+longjmp(cgiParseRecover, -1);
+}
+
+boolean cgiParseInput(char *input, struct hash **retHash,
+        struct cgiVar **retList)
+/* Parse cgi-style input into a hash table and list.  This will alter
+ * the input data.  The hash table will contain references back
+ * into input, so please don't free input until you're done with
+ * the hash. Prints message and returns FALSE if there's an error.*/
+{
+boolean ok = TRUE;
+int status = setjmp(cgiParseRecover);
+if (status == 0)    /* Always true except after long jump. */
+    {
+    pushAbortHandler(cgiParseAbort);
+    cgiParseInputAbort(input, retHash, retList);
+    }
+else    /* They long jumped here because of an error. */
+    {
+    ok = FALSE;
+    }
+popAbortHandler();
+return ok;
+}
+
+
+static boolean dumpStackOnSignal = FALSE;  // should a stack dump be generated?
+
+static void catchSignal(int sigNum)
+/* handler for various terminal signals for logging purposes */
+{
+char *sig = NULL;
+switch (sigNum)
+    {
+    case SIGABRT:
+      sig = "SIGABRT";
+      break;
+    case SIGSEGV:
+      sig = "SIGSEGV";
+      break;
+    case SIGFPE:
+      sig = "SIGFPE";
+      break;
+    case SIGBUS:
+      sig = "SIGBUS";
+      break;
+    }
+    logCgiToStderr();
+    fprintf(stderr, "Received signal %s\n", sig);
+    if (dumpStackOnSignal)
+        dumpStack("Stack for signal %s\n", sig);
+raise(SIGKILL);
+}
+
+void initSigHandlers(boolean dumpStack)
+/* set handler for various terminal signals for logging purposes.
+ * if dumpStack is TRUE, attempt to dump the stack. */
+{
+if (cgiIsOnWeb())
+    {
+    signal(SIGABRT, catchSignal);
+    signal(SIGSEGV, catchSignal);
+    signal(SIGFPE, catchSignal);
+    signal(SIGBUS, catchSignal);
+    dumpStackOnSignal = dumpStack;
+    }
+}
+
+
+static void initCgiInput()
+/* Initialize CGI input stuff.  After this CGI vars are
+ * stored in an internal hash/list regardless of how they
+ * were passed to the program. */
+{
+char* s;
+
+if (inputString != NULL)
+    return;
+
+_cgiFindInput(NULL);
+
+#ifndef GBROWSE
+/* check to see if the input is a multipart form */
+s = getenv("CONTENT_TYPE");
+if (s != NULL && startsWith("multipart/form-data", s))
+    {
+    cgiParseMultipart(&inputHash, &inputList);
+    }
+#endif /* GBROWSE */
+
+cgiParseInputAbort(inputString, &inputHash, &inputList);
+
+/* now parse the cookies */
+parseCookies(&cookieHash, &cookieList);
+
+/* Set enviroment variables CGIs to enable sql tracing and/or profiling */
+s = cgiOptionalString("JKSQL_TRACE");
+if (s != NULL)
+    envUpdate("JKSQL_TRACE", s);
+s = cgiOptionalString("JKSQL_PROF");
+if (s != NULL)
+    envUpdate("JKSQL_PROF", s);
+
+}
+
+struct cgiVar *cgiVarList()
+/* return the list of cgiVar's */
+{
+initCgiInput();
+return inputList;
+}
+
+static char *findVarData(char *varName)
+/* Get the string associated with varName from the query string. */
+{
+struct cgiVar *var;
+
+initCgiInput();
+if ((var = hashFindVal(inputHash, varName)) == NULL)
+    return NULL;
+return var->val;
+}
+
+void cgiBadVar(char *varName)
+/* Complain about a variable that's not there. */
+{
+if (varName == NULL) varName = "";
+errAbort("Sorry, didn't find CGI input variable '%s'", varName);
+}
+
+static char *mustFindVarData(char *varName)
+/* Find variable and associated data or die trying. */
+{
+char *res = findVarData(varName);
+if (res == NULL)
+    cgiBadVar(varName);
+return res;
+}
+
+char *javaScriptLiteralEncode(char *inString)
+/* Use backslash escaping on newline
+ * and quote chars, backslash and others.
+ * Intended that the encoded string will be
+ * put between quotes at a higher level and
+ * then interpreted by Javascript. */
+{
+char c;
+int outSize = 0;
+char *outString, *out, *in;
+
+if (inString == NULL)
+    return(cloneString(""));
+
+/* Count up how long it will be */
+in = inString;
+while ((c = *in++) != 0)
+    {
+    if (c == '\''
+     || c == '\"'
+     || c == '&'
+     || c == '\\'
+     || c == '\n'
+     || c == '\r'
+     || c == '\t'
+     || c == '\b'
+     || c == '\f'
+	)
+        outSize += 2;
+    else
+        outSize += 1;
+    }
+outString = needMem(outSize+1);
+
+/* Encode string */
+in = inString;
+out = outString;
+while ((c = *in++) != 0)
+    {
+    if (c == '\''
+     || c == '\"'
+     || c == '&'
+     || c == '\\'
+     || c == '\n'
+     || c == '\r'
+     || c == '\t'
+     || c == '\b'
+     || c == '\f'
+	)
+        *out++ = '\\';
+    *out++ = c;
+    }
+*out++ = 0;
+return outString;
+
+}
+
+
+void cgiDecode(char *in, char *out, int inLength)
+/* Decode from cgi pluses-for-spaces format to normal.
+ * Out will be a little shorter than in typically, and
+ * can be the same buffer. */
+{
+char c;
+int i;
+for (i=0; i<inLength;++i)
+    {
+    c = *in++;
+    if (c == '+')
+	*out++ = ' ';
+    else if (c == '%')
+	{
+	int code;
+        if (sscanf(in, "%2x", &code) != 1)
+	    code = '?';
+	in += 2;
+	i += 2;
+	*out++ = code;
+	}
+    else
+	*out++ = c;
+    }
+*out++ = 0;
+}
+
+char *cgiEncode(char *inString)
+/* Return a cgi-encoded version of inString.
+ * Alphanumerics kept as is, space translated to plus,
+ * and all other characters translated to %hexVal. */
+{
+char c;
+int outSize = 0;
+char *outString, *out, *in;
+
+if (inString == NULL)
+    return(cloneString(""));
+
+/* Count up how long it will be */
+in = inString;
+while ((c = *in++) != 0)
+    {
+    if (isalnum(c) || c == ' ' || c == '.' || c == '_')
+        outSize += 1;
+    else
+        outSize += 3;
+    }
+outString = needMem(outSize+1);
+
+/* Encode string */
+in = inString;
+out = outString;
+while ((c = *in++) != 0)
+    {
+    if (isalnum(c) || c == '.' || c == '_')
+        *out++ = c;
+    else if (c == ' ')
+        *out++ = '+';
+    else
+        {
+        unsigned char uc = c;
+        char buf[4];
+        *out++ = '%';
+        safef(buf, sizeof(buf), "%02X", uc);
+        *out++ = buf[0];
+        *out++ = buf[1];
+        }
+    }
+*out++ = 0;
+return outString;
+}
+
+char *cgiEncodeFull(char *inString)
+/* Return a cgi-encoded version of inString (no + for space!).
+ * Alphanumerics/./_ kept as is and all other characters translated to
+ * %hexVal. */
+{
+char c;
+int outSize = 0;
+char *outString, *out, *in;
+
+if (inString == NULL)
+    return(cloneString(""));
+
+/* Count up how long it will be */
+in = inString;
+while ((c = *in++) != 0)
+    {
+    if (isalnum(c) || c == '.' || c == '_')
+        outSize += 1;
+    else
+        outSize += 3;
+    }
+outString = needMem(outSize+1);
+
+/* Encode string */
+in = inString;
+out = outString;
+while ((c = *in++) != 0)
+    {
+    if (isalnum(c) || c == '.' || c == '_')
+        *out++ = c;
+    else
+        {
+        unsigned char uc = c;
+        char buf[4];
+        *out++ = '%';
+        safef(buf, sizeof(buf), "%02X", uc);
+        *out++ = buf[0];
+        *out++ = buf[1];
+        }
+    }
+*out++ = 0;
+return outString;
+}
+
+char *cgiOptionalString(char *varName)
+/* Return value of string if it exists in cgi environment, else NULL */
+{
+return findVarData(varName);
+}
+
+
+char *cgiString(char *varName)
+/* Return string value of cgi variable. */
+{
+return mustFindVarData(varName);
+}
+
+char *cgiUsualString(char *varName, char *usual)
+/* Return value of string if it exists in cgi environment.
+ * Otherwise return 'usual' */
+{
+char *pt;
+pt = findVarData(varName);
+if (pt == NULL)
+    pt = usual;
+return pt;
+}
+
+struct slName *cgiStringList(char *varName)
+/* Find list of cgi variables with given name.  This
+ * may be empty.  Free result with slFreeList(). */
+{
+struct hashEl *hel;
+struct slName *stringList = NULL, *string;
+
+initCgiInput();
+for (hel = hashLookup(inputHash, varName); hel != NULL; hel = hel->next)
+    {
+    if (sameString(hel->name, varName))
+        {
+	struct cgiVar *var = hel->val;
+	string = newSlName(var->val);
+	slAddHead(&stringList, string);
+	}
+    }
+return stringList;
+}
+
+
+int cgiInt(char *varName)
+/* Return int value of cgi variable. */
+{
+char *data;
+char c;
+
+data = mustFindVarData(varName);
+data = skipLeadingSpaces(data);
+c = data[0];
+if (!(isdigit(c) || (c == '-' && isdigit(data[1]))))
+     errAbort("Expecting number in %s, got \"%s\"\n", varName, data);
+return atoi(data);
+}
+
+int cgiIntExp(char *varName)
+/* Evaluate an integer expression in varName and
+ * return value. */
+{
+return intExp(cgiString(varName));
+}
+
+int cgiOptionalInt(char *varName, int defaultVal)
+/* This returns integer value of varName if it exists in cgi environment
+ * and it's not just the empty string otherwise it returns defaultVal. */
+{
+char *s = cgiOptionalString(varName);
+s = skipLeadingSpaces(s);
+if (isEmpty(s))
+    return defaultVal;
+return cgiInt(varName);
+}
+
+double cgiDouble(char *varName)
+/* Returns double value. */
+{
+char *data;
+double x;
+
+data = mustFindVarData(varName);
+if (sscanf(data, "%lf", &x)<1)
+     errAbort("Expecting real number in %s, got \"%s\"\n", varName, data);
+return x;
+}
+
+double cgiOptionalDouble(char *varName, double defaultVal)
+/* Returns double value. */
+{
+if (!cgiVarExists(varName))
+    return defaultVal;
+return cgiDouble(varName);
+}
+
+boolean cgiVarExists(char *varName)
+/* Returns TRUE if the variable was passed in. */
+{
+initCgiInput();
+return hashLookup(inputHash, varName) != NULL;
+}
+
+boolean cgiBoolean(char *varName)
+{
+return cgiVarExists(varName);
+}
+
+int cgiOneChoice(char *varName, struct cgiChoice *choices, int choiceSize)
+/* Returns value associated with string variable in choice table. */
+{
+char *key = cgiString(varName);
+int i;
+int val = -1;
+
+for (i=0; i<choiceSize; ++i)
+    {
+    if (sameWord(choices[i].name, key))
+        {
+        val =  choices[i].value;
+        return val;
+        }
+    }
+errAbort("Unknown key %s for variable %s\n", key, varName);
+return val;
+}
+
+void cgiMakeSubmitButton()
+/* Make 'submit' type button. */
+{
+cgiMakeButton("Submit", "Submit");
+}
+
+void cgiMakeResetButton()
+/* Make 'reset' type button. */
+{
+printf("<INPUT TYPE=RESET NAME=\"Reset\" VALUE=\" Reset \">");
+}
+
+void cgiMakeClearButton(char *form, char *field)
+/* Make button to clear a text field. */
+{
+char javascript[1024];
+
+safef(javascript, sizeof(javascript),
+    "document.%s.%s.value = ''; document.%s.submit();", form, field, form);
+cgiMakeOnClickButton(javascript, " Clear  ");
+}
+
+void cgiMakeButtonWithMsg(char *name, char *value, char *msg)
+/* Make 'submit' type button. Display msg on mouseover, if present*/
+{
+printf("<INPUT TYPE=SUBMIT NAME=\"%s\" VALUE=\"%s\" %s%s%s>",
+        name, value,
+        (msg ? " TITLE=\"" : ""), (msg ? msg : ""), (msg ? "\"" : "" ));
+}
+
+void cgiMakeButtonWithOnClick(char *name, char *value, char *msg, char *onClick)
+/* Make 'submit' type button, with onclick javascript */
+{
+printf("<input type=\"submit\" name=\"%s\" value=\"%s\" onclick=\"%s\" %s%s%s>",
+        name, value, onClick,
+        (msg ? " TITLE=\"" : ""), (msg ? msg : ""), (msg ? "\"" : "" ));
+}
+
+void cgiMakeButton(char *name, char *value)
+/* Make 'submit' type button */
+{
+cgiMakeButtonWithMsg(name, value, NULL);
+}
+
+void cgiMakeOnClickButton(char *command, char *value)
+/* Make 'push' type button with client side onClick (java)script. */
+{
+printf("<INPUT TYPE=\"button\" VALUE=\"%s\" onClick=\"%s\">", value, command);
+}
+
+void cgiMakeOnClickSubmitButton(char *command, char *name, char *value)
+/* Make submit button with both variable name and value with client side
+ * onClick (java)script. */
+{
+printf("<INPUT TYPE=SUBMIT NAME=\"%s\" VALUE=\"%s\" onClick=\"%s\">",
+       name, value, command);
+}
+
+void cgiMakeOptionalButton(char *name, char *value, boolean disabled)
+/* Make 'submit' type button that can be disabled. */
+{
+printf("<INPUT TYPE=SUBMIT NAME=\"%s\" VALUE=\"%s\"", name, value);
+if (disabled)
+    printf(" DISABLED");
+printf(">");
+}
+
+void cgiMakeFileEntry(char *name)
+/* Make file entry box/browser */
+{
+    printf("<INPUT TYPE=FILE NAME=\"%s\">", name);
+}
+
+void cgiSimpleTableStart()
+/* start HTML table  -- no customization. Leaves room
+ * for a fancier implementation */
+{
+printf("<TABLE>\n");
+}
+
+void cgiTableEnd()
+/* end HTML table */
+{
+printf("</TABLE>\n");
+}
+
+void cgiSimpleTableRowStart()
+/* Start table row */
+{
+printf("<TR>\n");
+}
+
+void cgiTableRowEnd()
+/* End table row */
+{
+printf("</TR>\n");
+}
+
+void cgiSimpleTableFieldStart()
+/* Start table field */
+{
+printf("<TD>");
+}
+
+void cgiTableFieldStartAlignRight()
+/* Start table field and align right*/
+{
+printf("<TD ALIGN = RIGHT>");
+}
+
+void cgiTableFieldEnd()
+/* End table field */
+{
+printf("</TD>\n");
+}
+
+void cgiTableField(char *text)
+/* Make table field entry */
+{
+printf("<TD> %s </TD>\n", text);
+}
+
+void cgiTableFieldWithMsg(char *text, char *msg)
+/* Make table field entry with mouseover */
+{
+printf("<TD %s%s%s> %s </TD>\n",
+        (msg ? " TITLE=\"" : ""), (msg ? msg : ""), (msg ? "\"" : "" ),
+        text);
+}
+
+void cgiParagraph(char *text)
+/* Make text paragraph */
+{
+printf("<P> %s\n", text);
+}
+
+void cgiMakeRadioButton(char *name, char *value, boolean checked)
+/* Make radio type button.  A group of radio buttons should have the
+ * same name but different values.   The default selection should be
+ * sent with checked on. */
+{
+printf("<INPUT TYPE=RADIO NAME=\"%s\" VALUE=\"%s\" %s>", name, value,
+   (checked ? "CHECKED" : ""));
+}
+
+void cgiMakeOnClickRadioButton(char *name, char *value, boolean checked,
+                                        char *command)
+/* Make radio type button with onClick command.
+ *  A group of radio buttons should have the
+ * same name but different values.   The default selection should be
+ * sent with checked on. */
+{
+printf("<INPUT TYPE=RADIO NAME=\"%s\" VALUE=\"%s\" %s %s>",
+        name, value, command, (checked ? "CHECKED" : ""));
+}
+
+char *cgiBooleanShadowPrefix()
+/* Prefix for shadow variable set with boolean variables. */
+{
+return "boolshad.";
+}
+#define BOOLSHAD_EXTRA "class='cbShadow'"
+
+boolean cgiBooleanDefined(char *name)
+/* Return TRUE if boolean variable is defined (by
+ * checking for shadow. */
+{
+char buf[256];
+safef(buf, sizeof(buf), "%s%s", cgiBooleanShadowPrefix(), name);
+return cgiVarExists(buf);
+}
+
+static void cgiMakeCheckBox2Bool(char *name, boolean checked, boolean enabled,
+                                 char *id, char *moreHtml)
+/* Make check box - designed to be called by the variously overloaded
+ * cgiMakeCheckBox functions, and should NOT be called directly.
+ * moreHtml: optional additional html like javascript call or mouseover msg (may be NULL)
+ * id: button id (may be NULL)
+ * Also make a shadow hidden variable and support 2 boolean states:
+ *    checked/unchecked and enabled/disabled. */
+{
+char buf[256], idBuf[256];
+
+if(id)
+    safef(idBuf, sizeof(idBuf), " id=\"%s\"", id);
+else
+    idBuf[0] = 0;
+
+printf("<INPUT TYPE=CHECKBOX NAME=\"%s\"%s VALUE=on %s%s%s>", name, idBuf,
+        (moreHtml ? moreHtml : ""),
+        (checked ? " CHECKED" : ""),
+        (enabled ? "" : " DISABLED"));
+safef(buf, sizeof(buf), "%s%s", cgiBooleanShadowPrefix(), name);
+cgiMakeHiddenVarWithExtra(buf, ( enabled ? "0" : (checked ? "-1" : "-2")),BOOLSHAD_EXTRA);
+}
+
+void cgiMakeCheckBoxUtil(char *name, boolean checked, char *msg, char *id)
+/* Make check box - can be called directly, though it was originally meant
+ * as the common code for all lower level checkbox routines.
+ * However, it's util functionality has been taken over by
+ * cgiMakeCheckBoxWithIdAndOptionalHtml() */
+{
+char buf[256];
+
+if (msg)
+    safef(buf, sizeof(buf), "TITLE=\"%s\"", msg);
+else
+    buf[0] = 0;
+
+cgiMakeCheckBox2Bool(name, checked, TRUE, id, buf);
+}
+
+void cgiMakeCheckBoxWithMsg(char *name, boolean checked, char *msg)
+{
+char buf[512];
+safef(buf, sizeof(buf), "title='%s'", msg);
+cgiMakeCheckBox2Bool(name, checked, TRUE, NULL, buf);
+}
+
+void cgiMakeCheckBoxWithId(char *name, boolean checked, char *id)
+/* Make check box, which includes an ID. */
+{
+cgiMakeCheckBox2Bool(name, checked, TRUE, id, NULL);
+}
+
+void cgiMakeCheckBox(char *name, boolean checked)
+/* Make check box. */
+{
+cgiMakeCheckBox2Bool(name, checked, TRUE, NULL, NULL);
+}
+
+void cgiMakeCheckBoxJS(char *name, boolean checked, char *javascript)
+/* Make check box with javascript. */
+{
+cgiMakeCheckBox2Bool(name,checked,TRUE,NULL,javascript);
+}
+
+void cgiMakeCheckBoxIdAndJS(char *name, boolean checked, char *id, char *javascript)
+/* Make check box with ID and javascript. */
+{
+cgiMakeCheckBox2Bool(name,checked,TRUE,id,javascript);
+}
+
+void cgiMakeCheckBoxFourWay(char *name, boolean checked, boolean enabled, char *id,
+                            char *classes, char *moreHtml)
+/* Make check box - with fourWay functionality (checked/unchecked by enabled/disabled)
+ * Also makes a shadow hidden variable that supports the 2 boolean states. */
+{
+char shadName[256];
+
+printf("<INPUT TYPE=CHECKBOX NAME='%s'", name);
+if (id)
+    printf(" id='%s'", id);
+if (checked)
+    printf(" CHECKED");
+if (!enabled)
+    {
+    if (findWordByDelimiter("disabled",' ', classes) == NULL) // fauxDisabled ?
+        printf(" DISABLED");
+    }
+if (classes)
+    printf(" class='%s'",classes);
+if (moreHtml)
+    printf(" %s",moreHtml);
+printf(">");
+
+// The hidden var needs to hold the 4way state
+safef(shadName, sizeof(shadName), "%s%s", cgiBooleanShadowPrefix(), name);
+cgiMakeHiddenVarWithExtra(shadName, ( enabled ? "0" : (checked ? "-1" : "-2")),BOOLSHAD_EXTRA);
+}
+
+
+void cgiMakeHiddenBoolean(char *name, boolean on)
+/* Make hidden boolean variable. Also make a shadow hidden variable so we
+ * can distinguish between variable not present and
+ * variable set to false. */
+{
+char buf[256];
+cgiMakeHiddenVar(name, on ? "on" : "off");
+safef(buf, sizeof(buf), "%s%s", cgiBooleanShadowPrefix(), name);
+cgiMakeHiddenVarWithExtra(buf, "1",BOOLSHAD_EXTRA);
+}
+
+void cgiMakeTextArea(char *varName, char *initialVal, int rowCount, int columnCount)
+/* Make a text area with area rowCount X columnCount and with text: intialVal */
+{
+cgiMakeTextAreaDisableable(varName, initialVal, rowCount, columnCount, FALSE);
+}
+
+void cgiMakeTextAreaDisableable(char *varName, char *initialVal, int rowCount, int columnCount, boolean disabled)
+/* Make a text area that can be disabled. The rea has rowCount X
+ * columnCount and with text: intialVal */
+{
+printf("<TEXTAREA NAME=\"%s\" ROWS=%d COLS=%d %s>%s</TEXTAREA>", varName,
+       rowCount, columnCount, disabled ? "DISABLED" : "",
+       (initialVal != NULL ? initialVal : ""));
+}
+
+void cgiMakeOnKeypressTextVar(char *varName, char *initialVal, int charSize,
+			      char *script)
+/* Make a text control filled with initial value, with a (java)script
+ * to execute every time a key is pressed.  If charSize is zero it's
+ * calculated from initialVal size. */
+{
+if (initialVal == NULL)
+    initialVal = "";
+if (charSize == 0) charSize = strlen(initialVal);
+if (charSize == 0) charSize = 8;
+
+printf("<INPUT TYPE=TEXT NAME=\"%s\" SIZE=%d VALUE=\"%s\"", varName,
+        charSize, initialVal);
+if (isNotEmpty(script))
+    printf(" onkeypress=\"%s\"", script);
+printf(">\n");
+}
+
+void cgiMakeTextVar(char *varName, char *initialVal, int charSize)
+/* Make a text control filled with initial value.  If charSize
+ * is zero it's calculated from initialVal size. */
+{
+cgiMakeOnKeypressTextVar(varName, initialVal, charSize, NULL);
+}
+
+void cgiMakeTextVarWithExtraHtml(char *varName, char *initialVal, int width, char *extra)
+/* Make a text control filled with initial value. */
+{
+if (initialVal == NULL)
+    initialVal = "";
+if (width==0)
+    width=strlen(initialVal)*10;
+if (width==0)
+    width = 100;
+
+printf("<INPUT TYPE=TEXT class='inputBox' NAME=\"%s\" style='width: %dpx' VALUE=\"%s\"",
+       varName,width, initialVal);
+if (isNotEmpty(extra))
+    printf(" %s",extra);
+printf(">\n");
+}
+
+void cgiMakeIntVar(char *varName, int initialVal, int maxDigits)
+/* Make a text control filled with initial value.  */
+{
+if (maxDigits == 0) maxDigits = 4;
+
+printf("<INPUT TYPE=TEXT NAME=\"%s\" SIZE=%d VALUE=%d>", varName,
+        maxDigits, initialVal);
+}
+
+void cgiMakeIntVarInRange(char *varName, int initialVal, char *title, int width,
+                          char *min, char *max)
+/* Make a integer control filled with initial value.
+   If min and/or max are non-NULL will enforce range
+   Requires utils.js jQuery.js and inputBox class */
+{
+if (width==0)
+    {
+    if (max)
+        width=strlen(max)*10;
+    else
+        {
+        int sz=initialVal+1000;
+        if (min)
+            sz=atoi(min) + 1000;
+        width = 10;
+        while (sz/=10)
+            width+=10;
+        }
+    }
+if (width < 65)
+    width = 65;
+
+printf("<INPUT TYPE=TEXT class='inputBox' name=\"%s\" style='width: %dpx' value=%d",
+       varName,width,initialVal);
+printf(" onChange='return validateInt(this,%s,%s);'",
+       (min ? min : "\"null\""),(max ? max : "\"null\""));
+if (title)
+    printf(" title='%s'",title);
+printf(">\n");
+}
+
+void cgiMakeIntVarWithLimits(char *varName, int initialVal, char *title, int width,
+                             int min, int max)
+{
+char minLimit[20];
+char maxLimit[20];
+char *minStr=NULL;
+char *maxStr=NULL;
+if (min != NO_VALUE)
+    {
+    safef(minLimit,sizeof(minLimit),"%d",min);
+    minStr = minLimit;
+    }
+if (max != NO_VALUE)
+    {
+    safef(maxLimit,sizeof(maxLimit),"%d",max);
+    maxStr = maxLimit;
+    }
+cgiMakeIntVarInRange(varName,initialVal,title,width,minStr,maxStr);
+}
+
+void cgiMakeIntVarWithMin(char *varName, int initialVal, char *title, int width, int min)
+{
+char minLimit[20];
+char *minStr=NULL;
+if (min != NO_VALUE)
+    {
+    safef(minLimit,sizeof(minLimit),"%d",min);
+    minStr = minLimit;
+    }
+cgiMakeIntVarInRange(varName,initialVal,title,width,minStr,NULL);
+}
+
+void cgiMakeIntVarWithMax(char *varName, int initialVal, char *title, int width, int max)
+{
+char maxLimit[20];
+char *maxStr=NULL;
+if (max != NO_VALUE)
+    {
+    safef(maxLimit,sizeof(maxLimit),"%d",max);
+    maxStr = maxLimit;
+    }
+cgiMakeIntVarInRange(varName,initialVal,title,width,NULL,maxStr);
+}
+
+void cgiMakeDoubleVar(char *varName, double initialVal, int maxDigits)
+/* Make a text control filled with initial floating-point value.  */
+{
+if (maxDigits == 0) maxDigits = 4;
+
+printf("<INPUT TYPE=TEXT NAME=\"%s\" SIZE=%d VALUE=%g>", varName,
+        maxDigits, initialVal);
+}
+
+void cgiMakeDoubleVarInRange(char *varName, double initialVal, char *title, int width,
+                             char *min, char *max)
+/* Make a floating point control filled with initial value.
+   If min and/or max are non-NULL will enforce range
+   Requires utils.js jQuery.js and inputBox class */
+{
+if (width==0)
+    {
+    if (max)
+        width=strlen(max)*10;
+    }
+if (width < 65)
+    width = 65;
+
+printf("<INPUT TYPE=TEXT class='inputBox' name=\"%s\" style='width: %dpx' value=%g",
+       varName,width,initialVal);
+printf(" onChange='return validateFloat(this,%s,%s);'",
+       (min ? min : "\"null\""),(max ? max : "\"null\""));
+if (title)
+    printf(" title='%s'",title);
+printf(">\n");
+}
+
+void cgiMakeDoubleVarWithLimits(char *varName, double initialVal, char *title, int width,
+                                double min, double max)
+{
+char minLimit[20];
+char maxLimit[20];
+char *minStr=NULL;
+char *maxStr=NULL;
+if ((int)min != NO_VALUE)
+    {
+    safef(minLimit,sizeof(minLimit),"%g",min);
+    minStr = minLimit;
+    }
+if ((int)max != NO_VALUE)
+    {
+    safef(maxLimit,sizeof(maxLimit),"%g",max);
+    maxStr = maxLimit;
+    }
+cgiMakeDoubleVarInRange(varName,initialVal,title,width,minStr,maxStr);
+}
+
+void cgiMakeDoubleVarWithMin(char *varName, double initialVal, char *title, int width, double min)
+{
+char minLimit[20];
+char *minStr=NULL;
+if ((int)min != NO_VALUE)
+    {
+    safef(minLimit,sizeof(minLimit),"%g",min);
+    minStr = minLimit;
+    }
+cgiMakeDoubleVarInRange(varName,initialVal,title,width,minStr,NULL);
+}
+
+void cgiMakeDoubleVarWithMax(char *varName, double initialVal, char *title, int width, double max)
+{
+char maxLimit[20];
+char *maxStr=NULL;
+if ((int)max != NO_VALUE)
+    {
+    safef(maxLimit,sizeof(maxLimit),"%g",max);
+    maxStr = maxLimit;
+    }
+cgiMakeDoubleVarInRange(varName,initialVal,title,width,NULL,maxStr);
+}
+
+void cgiMakeDropListClassWithStyleAndJavascript(char *name, char *menu[],
+        int menuSize, char *checked, char *class, char *style,char *javascript)
+/* Make a drop-down list with names, text class, style and javascript. */
+{
+int i;
+char *selString;
+if (checked == NULL) checked = menu[0];
+printf("<SELECT");
+if (name)
+    printf(" NAME='%s'", name);
+if (class)
+    printf(" class='%s'", class);
+if (style)
+    printf(" style='%s'", style);
+if (javascript)
+    printf(" %s", javascript);
+printf(">\n");
+for (i=0; i<menuSize; ++i)
+    {
+    if (sameWord(menu[i], checked))
+        selString = " SELECTED";
+    else
+        selString = "";
+    printf("<OPTION%s>%s</OPTION>\n", selString, menu[i]);
+    }
+printf("</SELECT>\n");
+}
+
+void cgiMakeDropListClassWithStyle(char *name, char *menu[],
+                                   int menuSize, char *checked, char *class, char *style)
+/* Make a drop-down list with names, text class and style. */
+{
+cgiMakeDropListClassWithStyleAndJavascript(name,menu,menuSize,checked,class,style,"");
+}
+
+void cgiMakeDropListClass(char *name, char *menu[],
+                          int menuSize, char *checked, char *class)
+/* Make a drop-down list with names. */
+{
+cgiMakeDropListClassWithStyle(name, menu, menuSize, checked, class, NULL);
+}
+
+void cgiMakeDropList(char *name, char *menu[], int menuSize, char *checked)
+/* Make a drop-down list with names.
+ * uses style "normalText" */
+{
+    cgiMakeDropListClass(name, menu, menuSize, checked, "normalText");
+}
+
+char *cgiMultListShadowPrefix()
+/* Prefix for shadow variable set with multi-select inputs. */
+{
+return "multishad.";
+}
+
+void cgiMakeMultList(char *name, char *menu[], int menuSize, struct slName *checked, int length)
+/* Make a list of names with window height equalt to length,
+ * which can have multiple selections. Same as drop-down list
+ * except "multiple" is added to select tag. */
+{
+int i;
+char *selString;
+if (checked == NULL) checked = slNameNew(menu[0]);
+printf("<SELECT MULTIPLE SIZE=%d ALIGN=CENTER NAME=\"%s\">\n", length, name);
+for (i=0; i<menuSize; ++i)
+    {
+    if (slNameInList(checked, menu[i]))
+        selString = " SELECTED";
+    else
+        selString = "";
+    printf("<OPTION%s>%s</OPTION>\n", selString, menu[i]);
+    }
+printf("</SELECT>\n");
+char buf[512];
+safef(buf, sizeof(buf), "%s%s", cgiMultListShadowPrefix(), name);
+cgiMakeHiddenVar(buf, "1");
+}
+
+void cgiMakeCheckboxGroupWithVals(char *name, char *menu[], char *values[], int menuSize,
+				  struct slName *checked, int tableColumns)
+/* Make a table of checkboxes that have the same variable name but different
+ * values (same behavior as a multi-select input), with nice labels in menu[]. */
+{
+int i;
+if (values == NULL) values = menu;
+if (menu == NULL) menu = values;
+puts("<TABLE BORDERWIDTH=0><TR>");
+for (i = 0;  i < menuSize;  i++)
+    {
+    if (i > 0 && (i % tableColumns) == 0)
+	printf("</TR><TR>");
+    printf("<TD><INPUT TYPE=CHECKBOX NAME=\"%s\" VALUE=\"%s\" %s> %s</TD>\n", name, values[i],
+	   (slNameInList(checked, values[i]) ? "CHECKED" : ""), menu[i]);
+    }
+if ((i % tableColumns) != 0)
+    while ((i++ % tableColumns) != 0)
+	printf("<TD></TD>");
+puts("</TR></TABLE>");
+char buf[512];
+safef(buf, sizeof(buf), "%s%s", cgiMultListShadowPrefix(), name);
+cgiMakeHiddenVar(buf, "0");
+}
+
+void cgiMakeCheckboxGroup(char *name, char *menu[], int menuSize, struct slName *checked,
+			  int tableColumns)
+/* Make a table of checkboxes that have the same variable name but different
+ * values (same behavior as a multi-select input). */
+{
+cgiMakeCheckboxGroupWithVals(name, menu, NULL, menuSize, checked, tableColumns);
+}
+
+void cgiMakeDropListFull(char *name, char *menu[], char *values[],
+                         int menuSize, char *checked, char *extraAttribs)
+/* Make a drop-down list with names and values. */
+{
+int i;
+char *selString;
+if (checked == NULL) checked = menu[0];
+
+if (NULL != extraAttribs)
+    {
+    printf("<SELECT NAME=\"%s\" %s>\n", name, extraAttribs);
+    }
+else
+    {
+    printf("<SELECT NAME=\"%s\">\n", name);
+    }
+
+for (i=0; i<menuSize; ++i)
+    {
+    if (sameWord(values[i], checked))
+        selString = " SELECTED";
+    else
+        selString = "";
+    printf("<OPTION%s VALUE=\"%s\">%s</OPTION>\n", selString, values[i], menu[i]);
+    }
+printf("</SELECT>\n");
+}
+
+char *cgiMakeSelectDropList(boolean multiple, char *name, struct slPair *valsAndLabels,
+                            char *selected, char *anyAll,char *extraClasses, char *extraHtml)
+// Returns allocated string of HTML defining a drop-down select
+// (if multiple, REQUIRES ui-dropdownchecklist.js)
+// valsAndLabels: val (pair->name) must be filled in but label (pair->val) may be NULL.
+// selected: if not NULL is a val found in the valsAndLabels (multiple then comma delimited list).
+//           If null and anyAll not NULL, that will be selected
+// anyAll: if not NULL is the string for an initial option. It can contain val and label,
+//         delimited by a comma
+// extraHtml: if not NULL contains id, javascript calls and style.
+//            It does NOT contain class definitions
+{
+struct dyString *output = dyStringNew(1024);
+boolean checked = FALSE;
+
+dyStringPrintf(output,"<SELECT name='%s'",name);
+if (multiple)
+    dyStringAppend(output," MULTIPLE");
+if (extraClasses != NULL)
+    dyStringPrintf(output," class='%s%s'",extraClasses,(multiple ? " filterBy" : ""));
+else if (multiple)
+    dyStringAppend(output," class='filterBy'");
+
+if (extraHtml != NULL)
+    dyStringPrintf(output," %s",extraHtml);
+dyStringAppend(output,">\n");
+
+// Handle initial option "Any" or "All"
+if (anyAll != NULL)
+    {
+    char *val = anyAll;  // Could contain a label after the value
+    char *label = strchr(val,',');  // Could contain a label after the value
+    if (label != NULL)
+        {
+        val = cloneString(anyAll);
+        label = strchr(val,',');  // again because this is new mem
+        *label = '\0';
+        label = label+1;
+        }
+    else
+        label = val;
+    checked = TRUE; // The default case
+    if (selected != NULL)
+        {
+        if (multiple)
+            checked = (findWordByDelimiter(val,',', selected) != NULL);
+        else
+            checked = sameString(val,selected);
+        }
+    dyStringPrintf(output, "<OPTION%s VALUE='%s'>%s</OPTION>\n",(checked ? " SELECTED" : ""),
+                   val, javaScriptLiteralEncode(label));
+    if (label != val)
+        freeMem(val);
+    }
+
+// All other options
+struct slPair *valPair = valsAndLabels;
+for (; valPair != NULL; valPair = valPair->next)
+    {
+    checked = FALSE;
+    if (selected != NULL)
+        {
+        if (multiple)
+            checked = (findWordByDelimiter(valPair->name,',', selected) != NULL);
+        else
+            checked = sameString(valPair->name,selected);
+        }
+    char *label = valPair->name;
+    if (valPair->val != NULL)
+        label = valPair->val;
+    dyStringPrintf(output, "<OPTION%s VALUE='%s'>%s</OPTION>\n",(checked ? " SELECTED" : ""),
+                   (char *)valPair->name, javaScriptLiteralEncode(label));
+    }
+
+dyStringPrintf(output,"</SELECT>\n");
+
+return dyStringCannibalize(&output);
+}
+
+void cgiMakeDropListWithVals(char *name, char *menu[], char *values[],
+                         int menuSize, char *checked)
+/* Make a drop-down list with names and values. In this case checked
+ * corresponds to a value, not a menu. */
+{
+int i;
+char *selString;
+if (checked == NULL) checked = values[0];
+
+printf("<SELECT NAME=\"%s\">\n", name);
+for (i=0; i<menuSize; ++i)
+    {
+    if (sameWord(values[i], checked))
+        selString = " SELECTED";
+    else
+        selString = "";
+    printf("<OPTION%s VALUE=\"%s\">%s</OPTION>\n", selString, values[i], menu[i]);
+    }
+printf("</SELECT>\n");
+}
+
+void cgiDropDownWithTextValsAndExtra(char *name, char *text[], char *values[],
+                                     int count, char *selected, char *extra)
+/* Make a drop-down list with both text and values. */
+{
+int i;
+char *selString;
+assert(values != NULL && text != NULL);
+if (selected == NULL)
+    selected = values[0];
+printf("<SELECT");
+if (name)
+    printf(" NAME='%s'", name);
+if (extra)
+    printf("%s", extra);
+printf(">\n");
+for (i=0; i<count; ++i)
+    {
+    if (sameWord(values[i], selected))
+        selString = " SELECTED";
+    else
+        selString = "";
+    printf("<OPTION%s value='%s'>%s</OPTION>\n", selString, values[i], text[i]);
+    }
+printf("</SELECT>\n");
+}
+
+void cgiMakeHiddenVarWithExtra(char *varName, char *string,char *extra)
+/* Store string in hidden input for next time around. */
+{
+printf("<INPUT TYPE=HIDDEN NAME='%s' VALUE='%s'", varName, string);
+if (extra)
+    printf(" %s>\n",extra);
+else
+    puts(">");
+}
+
+void cgiContinueHiddenVar(char *varName)
+/* Write CGI var back to hidden input for next time around. */
+{
+if (cgiVarExists(varName))
+    cgiMakeHiddenVar(varName, cgiString(varName));
+}
+
+void cgiVarExclude(char *varName)
+/* If varName exists, remove it. */
+{
+if (cgiVarExists(varName))
+    {
+    struct cgiVar *cv = hashRemove(inputHash, varName);
+    slRemoveEl(&inputList, cv);
+    }
+}
+
+void cgiVarExcludeExcept(char **varNames)
+/* Exclude all variables except for those in NULL
+ * terminated array varNames.  varNames may be NULL
+ * in which case nothing is excluded. */
+{
+struct hashEl *list, *el;
+struct hash *exclude = newHash(8);
+char *s;
+
+/* Build up hash of things to exclude */
+if (varNames != NULL)
+   {
+   while ((s = *varNames++) != NULL)
+       hashAdd(exclude, s, NULL);
+   }
+
+/* Step through variable list and remove them if not
+ * excluded. */
+initCgiInput();
+list = hashElListHash(inputHash);
+for (el = list; el != NULL; el = el->next)
+    {
+    if (!hashLookup(exclude, el->name))
+        cgiVarExclude(el->name);
+    }
+hashElFreeList(&list);
+freeHash(&exclude);
+}
+
+void cgiVarSet(char *varName, char *val)
+/* Set a cgi variable to a particular value. */
+{
+struct cgiVar *var;
+initCgiInput();
+AllocVar(var);
+var->val = cloneString(val);
+hashAddSaveName(inputHash, varName, var, &var->name);
+}
+
+struct dyString *cgiUrlString()
+/* Get URL-formatted that expresses current CGI variable state. */
+{
+struct dyString *dy = newDyString(0);
+struct cgiVar *cv;
+char *e;
+
+
+for (cv = inputList; cv != NULL; cv = cv->next)
+    {
+    if (cv != inputList)
+       dyStringAppend(dy, "&");
+    e = cgiEncode(cv->val);
+    dyStringPrintf(dy, "%s=", cv->name);
+    dyStringAppend(dy, e);
+    freez(&e);
+    }
+return dy;
+}
+
+void cgiContinueAllVars()
+/* Write back all CGI vars as hidden input for next time around. */
+{
+struct cgiVar *cv;
+for (cv = inputList; cv != NULL; cv = cv->next)
+    cgiMakeHiddenVar(cv->name, cv->val);
+}
+
+
+boolean cgiFromCommandLine(int *pArgc, char *argv[], boolean preferWeb)
+/* Use the command line to set up things as if we were a CGI program.
+ * User types in command line (assuming your program called cgiScript)
+ * like:
+ *        cgiScript nonCgiArg1 var1=value1 var2=value2 var3=value3 nonCgiArg2
+ * or like
+ *        cgiScript nonCgiArg1 var1=value1&var2=value2&var3=value3 nonCgiArg2
+ * or even like
+ *        cgiScript nonCgiArg1 -x -y=bogus z=really
+ * (The non-cgi arguments can occur anywhere.  The cgi arguments (all containing
+ * the character '=' or starting with '-') are erased from argc/argv.  Normally
+ * you call this cgiSpoof(&argc, argv);
+ */
+{
+int argc = *pArgc;
+int i;
+int argcLeft = argc;
+char *name;
+static char queryString[16384];
+char *q = queryString;
+boolean needAnd = TRUE;
+boolean gotAny = FALSE;
+boolean startDash;
+boolean gotEq;
+static char hostLine[512];
+
+if (preferWeb && cgiIsOnWeb())
+    return TRUE;	/* No spoofing required! */
+q += safef(q, queryString + sizeof(queryString) - q,
+	   "%s", "QUERY_STRING=cgiSpoof=on");
+for (i=0; i<argcLeft; )
+    {
+    name = argv[i];
+    if ((startDash = (name[0] == '-')))
+       ++name;
+    gotEq = (strchr(name, '=') != NULL);
+    if (gotEq || startDash)
+        {
+        if (needAnd)
+            *q++ = '&';
+        q += safef(q, queryString + sizeof(queryString) - q, "%s", name);
+        if (!gotEq || strchr(name, '&') == NULL)
+            needAnd = TRUE;
+	if (!gotEq)
+	    q += safef(q, queryString + sizeof(queryString) - q, "=on");
+        memcpy(&argv[i], &argv[i+1], sizeof(argv[i]) * (argcLeft-i-1));
+        argcLeft -= 1;
+        gotAny = TRUE;
+        }
+    else
+        i++;
+    }
+if (gotAny)
+    {
+    *pArgc = argcLeft;
+    }
+putenv("REQUEST_METHOD=GET");
+putenv(queryString);
+char *host = getenv("HOST");
+if (host == NULL)
+    host = "unknown";
+safef(hostLine, sizeof(hostLine), "SERVER_NAME=%s", host);
+putenv(hostLine);
+initCgiInput();
+return gotAny;
+}
+
+boolean cgiSpoof(int *pArgc, char *argv[])
+/* If run from web line set up input
+ * variables from web line, otherwise
+ * set up from command line. */
+{
+return cgiFromCommandLine(pArgc, argv, TRUE);
+}
+
+boolean cgiFromFile(char *fileName)
+/* Set up a cgi environment using parameters stored in a file.
+ * Takes file with arguments in the form:
+ *       argument1=someVal
+ *       # This is a comment
+ *       argument2=someOtherVal
+ *       ...
+ * and puts them into the cgi environment so that the usual
+ * cgiGetVar() commands can be used. Useful when a program
+ * has a lot of possible parameters.
+ */
+{
+char **argv = NULL;
+int argc = 0;
+int maxArgc = 10;
+int i;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *line;
+boolean spoof= FALSE;
+AllocArray(argv, maxArgc);
+/* Remember that first arg is program name.
+   Put filename there instead. */
+argc = 1;
+argv[0] = cloneString(fileName);
+for(;;)
+    {
+    /* If we are at the end we're done. */
+    if(!lineFileNext(lf, &line, NULL))
+	break;
+    /* If it is a comment or blank line skip it. */
+    if (line[0] == '#' || sameString(line, ""))
+        continue;
+    /* If our argv array is full expand it. */
+    if((argc+1) >= maxArgc)
+	{
+	ExpandArray(argv, maxArgc, 2*maxArgc);
+	maxArgc *= 2;
+	}
+    /* Fill in another argument to our psuedo arguments. */
+    argv[argc++] = cloneString(line);
+    }
+spoof = cgiSpoof(&argc, argv);
+/* Cleanup. */
+lineFileClose(&lf);
+for(i=0; i<argc; i++)
+    freez(&argv[i]);
+freez(&argv);
+return spoof;
+}
+
+void logCgiToStderr()
+/* Log useful CGI info to stderr */
+{
+char *ip = getenv("REMOTE_ADDR");
+char *cgiBinary = getenv("SCRIPT_FILENAME");
+char *requestUri = getenv("REQUEST_URI");
+char *hgsid = cgiOptionalString("hgsid");
+char *cgiFileName = NULL;
+time_t nowTime = time(NULL);
+struct tm *tm;
+tm = localtime(&nowTime);
+char *ascTime = asctime(tm);
+size_t len = strlen(ascTime);
+if (cgiBinary)
+    cgiFileName = basename(cgiBinary);
+else
+    cgiFileName = "cgi-bin";
+if (len > 3) ascTime[len-2] = '\0';
+if (!ip)
+    ip = "unknown";
+if (!hgsid)
+    hgsid = "unknown";
+if (!requestUri)
+    requestUri = "unknown";
+fprintf(stderr, "[%s] [%s] [client %s] [hgsid=%.24s] [%.1024s] ", ascTime, cgiFileName, ip,
+	hgsid, requestUri);
+}
+
+void cgiResetState()
+/* This is for reloading CGI settings multiple times in the same program
+ * execution.  No effect if state has not yet been initialized. */
+{
+freez(&inputString);
+inputString = NULL;
+if (inputHash != NULL)
+    hashFree(&inputHash);
+inputHash = NULL;
+inputList = NULL;
+
+haveCookiesHash = FALSE;
+if (cookieHash != NULL)
+    hashFree(&cookieHash);
+cookieHash = NULL;
+cookieList = NULL;
+}
+
+void cgiDown(float lines)
+// Drop down a certain number of lines (may be fractional)
+{
+printf("<div style='height:%fem;'></div>\n",lines);
+}
+
+char *commonCssStyles()
+/* Returns a string of common CSS styles */
+{
+// Contents currently is OBSOLETE as these have been moved to HGStyle.css
+// TODO: remove all traces (from web.c, hgTracks, hgTables) as this funtion does nothing.
+return "";
+}
+
diff --git a/lib/cirTree.c b/lib/cirTree.c
new file mode 100644
index 0000000..9c04984
--- /dev/null
+++ b/lib/cirTree.c
@@ -0,0 +1,558 @@
+/* cirTree chromosome id r tree.  Part of a system to index chromosome ranges - things of
+ * form chrN:start-end.  Generally you'll be using the crTree module - which
+ * makes use of this module and the bPlusTree module - rather than this module directly.
+ * This module works with chromosomes mapped to small integers rather than chromosomes
+ * as strings, saving space and speeding things up in the process, but requiring the
+ * separate bPlusTree to map the names to IDs. 
+ *   This module implements a one dimensional R-tree index treating the chromosome ID
+ * as the most significant part of a two-part key, and the base position as the least 
+ * significant part of the key. */
+
+#include "common.h"
+#include "localmem.h"
+#include "sig.h"
+#include "udc.h"
+#include "cirTree.h"
+
+struct rTree
+/* Recursive range structure. */
+    {
+    struct rTree *next;	/* Next on same level. */
+    struct rTree *children;	/* Child list. */
+    struct rTree *parent;	/* Our parent if any. */
+    bits32 startChromIx;	/* Starting chromosome. */
+    bits32 startBase;		/* Starting base position. */
+    bits32 endChromIx;		/* Ending chromosome. */
+    bits32 endBase;		/* Ending base. */
+    bits64 startFileOffset;	/* Start offset in file for leaves. */
+    bits64 endFileOffset;	/* End file offset for leaves. */
+    };
+
+#define fileHeaderSize (48)	/* Size of file header. */
+#define indexSlotSize (24)	/* Size of startChrom,startBase,endChrom,endBase,offset */
+#define leafSlotSize (32)       /* Size of startChrom,startBase,endChrom,endBase,offset,size */
+#define nodeHeaderSize (4)	/* Size of rTree node header. isLeaf,reserved,childCount. */
+
+int indexNodeSize(int blockSize)
+/* Return size of an index node. */
+{
+return nodeHeaderSize + indexSlotSize * blockSize;
+}
+
+int leafNodeSize(int blockSize)
+/* Return size of a leaf node. */
+{
+return nodeHeaderSize + leafSlotSize * blockSize;
+}
+
+
+static bits64 rWriteIndexLevel(bits16 blockSize, int childNodeSize,
+	struct rTree *tree, int curLevel, int destLevel,
+	bits64 offsetOfFirstChild, FILE *f)
+/* Recursively write an index level, skipping levels below destLevel,
+ * writing out destLevel. */
+{
+struct rTree *el;
+bits64 offset = offsetOfFirstChild;
+if (curLevel == destLevel)
+    {
+    /* We've reached the right level, write out a node header */
+    UBYTE reserved = 0;
+    UBYTE isLeaf = FALSE;
+    bits16 countOne = slCount(tree->children);
+    writeOne(f, isLeaf);
+    writeOne(f, reserved);
+    writeOne(f, countOne);
+
+    /* Write out elements of this node. */
+    for (el = tree->children; el != NULL; el = el->next)
+	{
+	writeOne(f, el->startChromIx);
+	writeOne(f, el->startBase);
+	writeOne(f, el->endChromIx);
+	writeOne(f, el->endBase);
+	writeOne(f, offset);
+	offset += childNodeSize;
+	}
+
+    /* Write out zeroes for empty slots in node. */
+    int i;
+    for (i=countOne; i<blockSize; ++i)
+	repeatCharOut(f, 0, indexSlotSize);
+    }
+else 
+    {
+    /* Otherwise recurse on children. */
+    for (el = tree->children; el != NULL; el = el->next)
+	offset = rWriteIndexLevel(blockSize, childNodeSize, el, curLevel+1, destLevel,
+		offset, f);
+    }
+return offset;
+}
+
+static void writeIndexLevel(int blockSize, int childNodeSize, 
+	struct rTree *tree, bits64 offsetOfFirstChild, int level, FILE *f)
+/* Write out a non-leaf level nodes at given level. */
+{
+rWriteIndexLevel(blockSize, childNodeSize, tree, 0, level, offsetOfFirstChild, f);
+}
+
+static void rWriteLeaves(int itemsPerSlot, int lNodeSize, struct rTree *tree, int curLevel,
+	int leafLevel, FILE *f)
+/* Write out leaf-level nodes. */
+{
+if (curLevel == leafLevel)
+    {
+    /* We've reached the right level, write out a node header. */
+    UBYTE reserved = 0;
+    UBYTE isLeaf = TRUE;
+    bits16 countOne = slCount(tree->children);
+    writeOne(f, isLeaf);
+    writeOne(f, reserved);
+    writeOne(f, countOne);
+
+    /* Write out elements of this node. */
+    struct rTree *el;
+    for (el = tree->children; el != NULL; el = el->next)
+	{
+	writeOne(f, el->startChromIx);
+	writeOne(f, el->startBase);
+	writeOne(f, el->endChromIx);
+	writeOne(f, el->endBase);
+	writeOne(f, el->startFileOffset);
+	bits64 size = el->endFileOffset - el->startFileOffset;
+	writeOne(f, size);
+	}
+
+    /* Write out zeroes for empty slots in node. */
+    int i;
+    for (i=countOne; i<itemsPerSlot; ++i)
+	repeatCharOut(f, 0, indexSlotSize);
+    }
+else
+    {
+    /* Otherwise recurse on children. */
+    struct rTree *el;
+    for (el = tree->children; el != NULL; el = el->next)
+	rWriteLeaves(itemsPerSlot, lNodeSize, el, curLevel+1, leafLevel, f);
+    }
+}
+
+static void writeLeaves(int itemsPerSlot, int lNodeSize, struct rTree *tree, int leafLevel, FILE *f)
+/* Write out leaf-level nodes. */
+{
+rWriteLeaves(itemsPerSlot, lNodeSize, tree, 0, leafLevel, f);
+}
+
+void calcLevelSizes(struct rTree *tree, int *levelSizes, int level, int maxLevel)
+/* Recursively count sizes of levels and add to appropriate slots of levelSizes */
+{
+struct rTree *el;
+for (el = tree; el != NULL; el = el->next)
+    {
+    levelSizes[level] += 1;
+    if (level < maxLevel)
+        calcLevelSizes(el->children, levelSizes, level+1, maxLevel);
+    }
+}
+
+static struct rTree *rTreeFromChromRangeArray( struct lm *lm, int blockSize, int itemsPerSlot,
+	void *itemArray, int itemSize, bits64 itemCount,  void *context,
+	struct cirTreeRange (*fetchKey)(const void *va, void *context),
+	bits64 (*fetchOffset)(const void *va, void *context), bits64 endFileOffset,
+	int *retLevelCount)
+{
+char *items = itemArray;
+struct rTree *el, *list=NULL, *tree = NULL;
+
+/* Make first level above leaf. */
+bits64 i;
+bits64 nextOffset = (*fetchOffset)(items, context);
+for (i=0; i<itemCount; i += itemsPerSlot)
+    {
+    /* Figure out if we are on final iteration through loop, and the
+     * count of items in this iteration. */
+    boolean finalIteration = FALSE;
+    int oneSize = itemCount-i;
+    if (oneSize > itemsPerSlot)
+        oneSize = itemsPerSlot;
+    else
+        finalIteration = TRUE;
+
+    /* Allocate element and put on list. */
+    lmAllocVar(lm, el);
+    slAddHead(&list, el);
+
+    /* Fill out most of element from first item in element. */
+    char *startItem = items + itemSize * i;
+    struct cirTreeRange key = (*fetchKey)(startItem, context);
+    el->startChromIx = el->endChromIx = key.chromIx;
+    el->startBase = key.start;
+    el->endBase = key.end;
+    el->startFileOffset = nextOffset;
+
+    /* Figure out end of element from offset of next element (or file size
+     * for final element.) */
+    if (finalIteration)
+	nextOffset = endFileOffset;
+    else
+        {
+	char *endItem = startItem + itemSize*oneSize;
+        nextOffset = (*fetchOffset)(endItem, context);
+	}
+    el->endFileOffset = nextOffset;
+
+    /* Expand area spanned to include all items in block. */
+    int j;
+    for (j=1; j<oneSize; ++j)
+        {
+	void *item = items + itemSize*(i+j);
+	key = (*fetchKey)(item, context);
+	if (key.chromIx < el->startChromIx)
+	    {
+	    el->startChromIx = key.chromIx;
+	    el->startBase = key.start;
+	    }
+	else if (key.chromIx == el->startChromIx)
+	    {
+	    if (key.start < el->startBase)
+	        el->startBase = key.start;
+	    }
+	if (key.chromIx > el->endChromIx)
+	    {
+	    el->endChromIx = key.chromIx;
+	    el->endBase = key.end;
+	    }
+	else if (key.chromIx == el->endChromIx)
+	    {
+	    if (key.end > el->endBase)
+	        el->endBase = key.end;
+	    }
+	}
+    }
+slReverse(&list);
+verbose(2, "Made %d primary index nodes out of %llu items\n", slCount(list), itemCount);
+
+/* Now iterate through making more and more condensed versions until have just one. */
+int levelCount = 1;
+tree = list;
+while (tree->next != NULL || levelCount < 2)
+    {
+    list = NULL;
+    int slotsUsed = blockSize;
+    struct rTree *parent = NULL, *next;
+    for (el = tree; el != NULL; el = next)
+        {
+	next = el->next;
+	if (slotsUsed >= blockSize)
+	    {
+	    slotsUsed = 1;
+	    lmAllocVar(lm, parent);
+	    parent = lmCloneMem(lm, el, sizeof(*el));
+	    parent->children = el;
+	    el->parent = parent;
+	    el->next = NULL;
+	    slAddHead(&list, parent);
+	    }
+	else
+	    {
+	    ++slotsUsed;
+	    slAddHead(&parent->children, el);
+	    el->parent = parent;
+	    if (el->startChromIx < parent->startChromIx)
+		{
+	        parent->startChromIx = el->startChromIx;
+		parent->startBase = el->startBase;
+		}
+	    else if (el->startChromIx == parent->startChromIx)
+	        {
+		if (el->startBase < parent->startBase)
+		    parent->startBase = el->startBase;
+		}
+	    if (el->endChromIx > parent->endChromIx)
+		{
+	        parent->endChromIx = el->endChromIx;
+		parent->endBase = el->endBase;
+		}
+	    else if (el->endChromIx == parent->endChromIx)
+	        {
+		if (el->endBase > parent->endBase)
+		    parent->endBase = el->endBase;
+		}
+	    }
+	}
+
+    slReverse(&list);
+    for (el = list; el != NULL; el = el->next)
+        slReverse(&el->children);
+    tree = list;
+    levelCount += 1;
+    }
+*retLevelCount = levelCount;
+return tree;
+}
+
+static void writeTreeToOpenFile(struct rTree *tree, int blockSize, int levelCount, FILE *f)
+/* Write out tree to a file that is open already - writing out index nodes from 
+ * highest to lowest level, and then leaf nodes. */
+{
+/* Calculate sizes of each level. */
+int i;
+int levelSizes[levelCount];
+for (i=0; i<levelCount; ++i)
+    levelSizes[i] = 0;
+calcLevelSizes(tree, levelSizes, 0, levelCount-1);
+
+/* Calc offsets of each level. */
+bits64 levelOffsets[levelCount];
+bits64 offset = ftell(f);
+bits64 iNodeSize = indexNodeSize(blockSize);
+bits64 lNodeSize = leafNodeSize(blockSize);
+for (i=0; i<levelCount; ++i)
+    {
+    levelOffsets[i] = offset;
+    offset += levelSizes[i] * iNodeSize;
+    verbose(2, "level %d: size %d, offset %llu\n", i, levelSizes[i], levelOffsets[i]);
+    }
+
+verbose(2, "%d levels.  Level sizes are", levelCount);
+for (i=0; i<levelCount; ++i) verbose(2, " %d", levelSizes[i]);
+verbose(2, "\n");
+
+/* Write out index levels. */
+int finalLevel = levelCount-3;
+for (i=0; i<=finalLevel; ++i)
+    {
+    bits64 childNodeSize = (i==finalLevel ? lNodeSize : iNodeSize);
+    writeIndexLevel(blockSize, childNodeSize, tree,
+    	levelOffsets[i+1], i, f);
+    if (ftell(f) != levelOffsets[i+1])
+        errAbort("Internal error: offset mismatch (%llu vs %llu) line %d of %s\n", (bits64)ftell(f), levelOffsets[i+1], __LINE__, __FILE__);
+    }
+
+/* Write out leaf level. */
+int leafLevel = levelCount - 2;
+writeLeaves(blockSize, leafNodeSize(blockSize), tree, leafLevel, f);
+}
+
+void cirTreeFileBulkIndexToOpenFile(
+	void *itemArray, int itemSize, bits64 itemCount, 
+	bits32 blockSize, bits32 itemsPerSlot,
+	void *context,
+	struct cirTreeRange (*fetchKey)(const void *va, void *context),
+	bits64 (*fetchOffset)(const void *va, void *context), 
+	bits64 endFileOffset, FILE *f)
+/* Create a r tree index from a sorted array, writing output starting at current position
+ * of an already open file.  See rTreeFileCreate for explanation of parameters. */
+{
+int levelCount;
+struct lm *lm = lmInit(0);
+struct rTree *tree = rTreeFromChromRangeArray(lm, blockSize, itemsPerSlot,
+	itemArray, itemSize, itemCount, context, fetchKey, fetchOffset, endFileOffset,
+	&levelCount);
+bits32 magic = cirTreeSig;
+bits32 reserved = 0;
+writeOne(f, magic);
+writeOne(f, blockSize);
+writeOne(f, itemCount);
+writeOne(f, tree->startChromIx);
+writeOne(f, tree->startBase);
+writeOne(f, tree->endChromIx);
+writeOne(f, tree->endBase);
+writeOne(f, endFileOffset);
+writeOne(f, itemsPerSlot);
+writeOne(f, reserved);
+writeTreeToOpenFile(tree, blockSize, levelCount, f);
+lmCleanup(&lm);
+}
+
+void cirTreeFileCreate(
+	void *itemArray, 	/* Sorted array of things to index. */
+	int itemSize, 		/* Size of each element in array. */
+	bits64 itemCount, 	/* Number of elements in array. */
+	bits32 blockSize,	/* R tree block size - # of children for each node. */
+	bits32 itemsPerSlot,	/* Number of items to put in each index slot at lowest level. */
+	void *context,		/* Context pointer for use by fetch call-back functions. */
+	struct cirTreeRange (*fetchKey)(const void *va, void *context),/* Given item, return key. */
+	bits64 (*fetchOffset)(const void *va, void *context), /* Given item, return file offset */
+	bits64 endFileOffset,				 /* Last position in file we index. */
+	char *fileName)                                  /* Name of output file. */
+/* Create a r tree index file from a sorted array. */
+{
+FILE *f = mustOpen(fileName, "wb");
+cirTreeFileBulkIndexToOpenFile(itemArray, itemSize, itemCount, blockSize, itemsPerSlot,
+	context, fetchKey, fetchOffset, endFileOffset, f);
+carefulClose(&f);
+}
+
+struct cirTreeFile *cirTreeFileAttach(char *fileName, struct udcFile *udc)
+/* Open up r-tree index file on previously open file, with cirTree
+ * header at current file position. */
+{
+/* Open file and allocate structure to hold info from header etc. */
+struct cirTreeFile *crt = needMem(sizeof(*crt));
+crt->fileName = fileName;
+crt->udc = udc;
+
+/* Read magic number at head of file and use it to see if we are proper file type, and
+ * see if we are byte-swapped. */
+bits32 magic;
+boolean isSwapped = FALSE;
+udcMustReadOne(udc, magic);
+if (magic != cirTreeSig)
+    {
+    magic = byteSwap32(magic);
+    isSwapped = crt->isSwapped = TRUE;
+    if (magic != cirTreeSig)
+       errAbort("%s is not a chromosome id r-tree index file", fileName);
+    }
+
+/* Read rest of defined bits of header, byte swapping as needed. */
+crt->blockSize = udcReadBits32(udc, isSwapped);
+crt->itemCount = udcReadBits64(udc, isSwapped);
+crt->startChromIx = udcReadBits32(udc, isSwapped);
+crt->startBase = udcReadBits32(udc, isSwapped);
+crt->endChromIx = udcReadBits32(udc, isSwapped);
+crt->endBase = udcReadBits32(udc, isSwapped);
+crt->fileSize = udcReadBits64(udc, isSwapped);
+crt->itemsPerSlot = udcReadBits32(udc, isSwapped);
+
+/* Skip over reserved bits of header. */
+bits32 reserved32;
+udcMustReadOne(udc, reserved32);
+
+/* Save position of root block of r tree. */
+crt->rootOffset = udcTell(udc);
+
+return crt;
+}
+
+struct cirTreeFile *cirTreeFileOpen(char *fileName)
+/* Open up r-tree index file - reading header and verifying things. */
+{
+return cirTreeFileAttach(cloneString(fileName), udcFileOpen(fileName, udcDefaultDir()));
+}
+
+void cirTreeFileDetach(struct cirTreeFile **pCrt)
+/* Detatch and free up cirTree file opened with cirTreeFileAttach. */
+{
+freez(pCrt);
+}
+
+void cirTreeFileClose(struct cirTreeFile **pCrt)
+/* Close and free up cirTree file opened with cirTreeFileAttach. */
+{
+struct cirTreeFile *crt = *pCrt;
+if (crt != NULL)
+    {
+    freez(&crt->fileName);
+    udcFileClose(&crt->udc);
+    cirTreeFileDetach(pCrt);
+    }
+}
+
+inline int cmpTwoBits32(bits32 aHi, bits32 aLo, bits32 bHi, bits32 bLo)
+/* Return - if b is less than a , 0 if equal, else +*/
+{
+if (aHi < bHi)
+    return 1;
+else if (aHi > bHi)
+    return -1;
+else
+    {
+    if (aLo < bLo)
+       return 1;
+    else if (aLo > bLo)
+       return -1;
+    else
+       return 0;
+    }
+}
+
+static inline boolean cirTreeOverlaps(int qChrom, int qStart, int qEnd, 
+	int rStartChrom, int rStartBase, int rEndChrom, int rEndBase)
+{
+return cmpTwoBits32(qChrom, qStart, rEndChrom, rEndBase) > 0 &&
+       cmpTwoBits32(qChrom, qEnd, rStartChrom, rStartBase) < 0;
+}
+
+static void rFindOverlappingBlocks(struct cirTreeFile *crt, int level, bits64 indexFileOffset,
+	bits32 chromIx, bits32 start, bits32 end, struct fileOffsetSize **retList)
+/* Recursively find blocks with data. */
+{
+struct udcFile *udc = crt->udc;
+
+/* Seek to start of block. */
+udcSeek(udc, indexFileOffset);
+
+/* Read block header. */
+UBYTE isLeaf;
+UBYTE reserved;
+bits16 i, childCount;
+udcMustReadOne(udc, isLeaf);
+udcMustReadOne(udc, reserved);
+boolean isSwapped = crt->isSwapped;
+childCount = udcReadBits16(udc, isSwapped);
+
+verbose(3, "rFindOverlappingBlocks %llu %u:%u-%u.  childCount %d. isLeaf %d\n", indexFileOffset, chromIx, start, end, (int)childCount, (int)isLeaf);
+
+if (isLeaf)
+    {
+    /* Loop through node adding overlapping leaves to block list. */
+    for (i=0; i<childCount; ++i)
+        {
+	bits32 startChromIx = udcReadBits32(udc, isSwapped);
+	bits32 startBase = udcReadBits32(udc, isSwapped);
+	bits32 endChromIx = udcReadBits32(udc, isSwapped);
+	bits32 endBase = udcReadBits32(udc, isSwapped);
+	bits64 offset = udcReadBits64(udc, isSwapped);
+	bits64 size = udcReadBits64(udc, isSwapped);
+	if (cirTreeOverlaps(chromIx, start, end, startChromIx, startBase, endChromIx, endBase))
+	    {
+	    struct fileOffsetSize *block;
+	    AllocVar(block);
+	    block->offset = offset;
+	    block->size = size;
+	    slAddHead(retList, block);
+	    }
+	}
+    }
+else
+    {
+    /* Read node into arrays. */
+    bits32 startChromIx[childCount], startBase[childCount];
+    bits32 endChromIx[childCount], endBase[childCount];
+    bits64 offset[childCount];
+    for (i=0; i<childCount; ++i)
+        {
+	startChromIx[i] = udcReadBits32(udc, isSwapped);
+	startBase[i] = udcReadBits32(udc, isSwapped);
+	endChromIx[i] = udcReadBits32(udc, isSwapped);
+	endBase[i] = udcReadBits32(udc, isSwapped);
+	offset[i] = udcReadBits64(udc, isSwapped);
+	}
+
+    /* Recurse into child nodes that we overlap. */
+    for (i=0; i<childCount; ++i)
+	{
+	if (cirTreeOverlaps(chromIx, start, end, startChromIx[i], startBase[i], 
+		endChromIx[i], endBase[i]))
+	    {
+	    rFindOverlappingBlocks(crt, level+1, offset[i], chromIx, start, end, retList);
+	    }
+	}
+    }
+}
+
+struct fileOffsetSize *cirTreeFindOverlappingBlocks(struct cirTreeFile *crt, 
+	bits32 chromIx, bits32 start, bits32 end)
+/* Return list of file blocks that between them contain all items that overlap
+ * start/end on chromIx.  Also there will be likely some non-overlapping items
+ * in these blocks too. When done, use slListFree to dispose of the result. */
+{
+struct fileOffsetSize *blockList = NULL;
+rFindOverlappingBlocks(crt, 0, crt->rootOffset, chromIx, start, end, &blockList);
+slReverse(&blockList);
+return blockList;
+}
+
diff --git a/lib/codebias.c b/lib/codebias.c
new file mode 100644
index 0000000..9de37b4
--- /dev/null
+++ b/lib/codebias.c
@@ -0,0 +1,147 @@
+/* codebias.c - stuff for managing codons and codon bias. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "dnautil.h"
+#include "hmmstats.h"
+#include "codebias.h"
+
+
+
+struct codonBias *codonLoadBias(char *fileName)
+/* Create scaled log codon bias tables based on .cod file.  
+ * You can freeMem it when you're done. */
+{
+struct codonBias *cb;
+char line[1024];
+int lineCount = 0;
+char *words[128];
+int wordCount;
+int i = 0, j = 0;
+int skip = 0;
+boolean getMark0 = FALSE;
+boolean getMark1 = FALSE;
+FILE *f = mustOpen(fileName, "r");
+int val;
+
+AllocVar(cb);
+while (fgets(line, sizeof(line), f) )
+    {
+    ++lineCount;
+    if (skip)
+        {
+        skip -= 1;
+        continue;
+        }
+    if (getMark1)
+        {
+        wordCount = chopLine(line, words);
+        if (wordCount != 65)
+            errAbort("Bad line %d of %s\n", lineCount, fileName);
+        for (j=0; j<64; ++j)
+            {
+            val = atoi(words[j+1]);
+            if (val == 0)
+                cb->mark1[i][j] = scaledLog(1.0E-20);
+            else
+                cb->mark1[i][j] = scaledLog(0.001*val);
+            }
+        if ((i += 1) == 64)
+            getMark1 = FALSE;
+        }
+    else if (getMark0)
+        {
+        wordCount = chopLine(line, words);
+        if (wordCount != 64)
+            errAbort("Bad line %d of %s\n", lineCount, fileName);
+        for (j=0; j<64; ++j)
+            {
+            val = atoi(words[j]);
+            if (val == 0)
+                cb->mark0[j] = scaledLog(1.0E-20);
+            else
+                cb->mark0[j] = scaledLog(0.001*val);
+            }
+        getMark0 = FALSE;
+        }
+    else if (startsWith("Markov", line))
+        {
+        wordCount = chopLine(line, words);
+        if (wordCount != 2)
+            errAbort("Bad line %d of %s\n", lineCount, fileName);
+        if (sameString(words[1], "0"))
+            getMark0 = TRUE;
+        else if (sameString(words[1], "1"))
+            getMark1 = TRUE;
+        else
+            errAbort("Bad line %d of %s\n", lineCount, fileName);
+        skip = 3;
+        }
+    }
+fclose(f);
+return cb;
+}
+   
+static void unN(DNA *dna, int dnaSize)
+/* Turn N's into T's. */
+{
+int i;
+int val;
+for (i=0; i<dnaSize; ++i)
+    {
+    if ((val = ntVal[(int)dna[i]]) < 0)
+        dna[i] = 't';
+    }
+}
+
+int codonFindFrame(DNA *dna, int dnaSize, struct codonBias *forBias)
+/* Assuming a stretch of DNA is an exon, find most likely frame that it's in. 
+ * Beware this routine will replace N's with T's in the input dna.*/
+{
+double logOneFourth = log(0.25);
+double logProbs[3];
+int frame;
+int dnaIx;
+double logP;
+double bestLogP = -0x6fffffff;
+int bestFrame = -1;
+int lastDnaStart = dnaSize-3;
+DNA *d;
+int codon = 0, lastCodon; 
+
+unN(dna, dnaSize);
+for (frame=0; frame<3; ++frame)
+    {
+    /* Partial first codon just gets even background score. */
+    logP = frame*logOneFourth;
+    /* 1st order model on first full codon. */
+    if (frame <= lastDnaStart)
+        {
+        d = dna+frame;
+        codon = (ntVal[(int)d[0]]<<4) + (ntVal[(int)d[1]]<<2) + ntVal[(int)d[2]];
+        logP += forBias->mark0[codon];
+        }
+    /* 2nd order model on subsequent full codons. */
+    for (dnaIx = frame+3; dnaIx <= lastDnaStart; dnaIx += 3)
+        {
+        lastCodon = codon;
+        d = dna+dnaIx;
+        codon = (ntVal[(int)d[0]]<<4) + (ntVal[(int)d[1]]<<2) + ntVal[(int)d[2]];
+        logP += forBias->mark1[lastCodon][codon];
+        }
+    /* Partial last codon gets even background score. */
+    logP += (dnaSize-dnaIx)*logOneFourth;
+    logProbs[frame] = logP;
+    if (logP > bestLogP)
+        {
+        bestLogP = logP;
+        bestFrame = frame;
+        }
+    }
+return bestFrame;
+}
+
+
+
diff --git a/lib/colHash.c b/lib/colHash.c
new file mode 100644
index 0000000..49d1537
--- /dev/null
+++ b/lib/colHash.c
@@ -0,0 +1,48 @@
+/* colHash - stuff for fast lookup of index given an
+ * rgb value. */
+
+#include "common.h"
+#include "memgfx.h"
+#include "colHash.h"
+
+
+struct colHash *colHashNew()
+/* Get a new color hash. */
+{
+struct colHash *cHash;
+AllocVar(cHash);
+cHash->freeEl = cHash->elBuf;
+return cHash;
+}
+
+void colHashFree(struct colHash **pEl)
+/* Free up color hash. */
+{
+freez(pEl);
+}
+
+struct colHashEl *colHashAdd(struct colHash *cHash, 
+	unsigned r, unsigned g, unsigned b, int ix)
+/* Add new element to color hash. */
+{
+struct colHashEl *che = cHash->freeEl++, **pCel;
+che->col.r = r;
+che->col.g = g;
+che->col.b = b;
+che->ix = ix;
+pCel = &cHash->lists[colHashFunc(r,g,b)];
+slAddHead(pCel, che);
+return che;
+}
+
+struct colHashEl *colHashLookup(struct colHash *cHash, 
+	unsigned r, unsigned g, unsigned b)
+/* Lookup value in hash. */
+{
+struct colHashEl *che;
+for (che = cHash->lists[colHashFunc(r,g,b)]; che != NULL; che = che->next)
+    if (che->col.r == r && che->col.g == g && che->col.b == b)
+	return che;
+return NULL;
+}
+
diff --git a/lib/colHash.h b/lib/colHash.h
new file mode 100644
index 0000000..5fb90ed
--- /dev/null
+++ b/lib/colHash.h
@@ -0,0 +1,38 @@
+/* colHash - stuff for fast lookup of index given an
+ * rgb value. */
+#ifndef COLHASH_H
+#define COLHASH_H
+
+#define colHashFunc(r,g,b) (r+g+g+b)
+
+struct colHashEl
+/* An element in a color hash. */
+    {
+    struct colHashEl *next;	/* Next in list. */
+    struct rgbColor col;	/* Color RGB. */
+    int ix;			/* Color Index. */
+    };
+
+struct colHash
+/* A hash on RGB colors. */
+    {
+    struct colHashEl *lists[4*256];	/* Hash chains. */
+    struct colHashEl elBuf[256];	/* Buffer of elements. */
+    struct colHashEl *freeEl;		/* Pointer to next free element. */
+    };
+
+struct colHash *colHashNew();
+/* Get a new color hash. */
+
+void colHashFree(struct colHash **pEl);
+/* Free up color hash. */
+
+struct colHashEl *colHashAdd(struct colHash *cHash, 
+	unsigned r, unsigned g, unsigned b, int ix);
+/* Add new element to color hash. */
+
+struct colHashEl *colHashLookup(struct colHash *cHash, 
+	unsigned r, unsigned g, unsigned b);
+/* Lookup value in hash. */
+
+#endif /* COLHASH_H */
diff --git a/lib/common.c b/lib/common.c
new file mode 100644
index 0000000..b253d92
--- /dev/null
+++ b/lib/common.c
@@ -0,0 +1,3449 @@
+/* Commonly used routines in a wide range of applications.
+ * Strings, singly-linked lists, and a little file i/o.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "errabort.h"
+#include "portable.h"
+#include "linefile.h"
+#include "hash.h"
+
+
+void *cloneMem(void *pt, size_t size)
+/* Allocate a new buffer of given size, and copy pt to it. */
+{
+void *newPt = needLargeMem(size);
+memcpy(newPt, pt, size);
+return newPt;
+}
+
+static char *cloneStringZExt(const char *s, int size, int copySize)
+/* Make a zero terminated copy of string in memory */
+{
+char *d = needMem(copySize+1);
+copySize = min(size,copySize);
+memcpy(d, s, copySize);
+d[copySize] = 0;
+return d;
+}
+
+char *cloneStringZ(const char *s, int size)
+/* Make a zero terminated copy of string in memory */
+{
+return cloneStringZExt(s, strlen(s), size);
+}
+
+char *cloneString(const char *s)
+/* Make copy of string in dynamic memory */
+{
+int size = 0;
+if (s == NULL)
+    return NULL;
+size = strlen(s);
+return cloneStringZExt(s, size, size);
+}
+
+char *cloneLongString(char *s)
+/* Make clone of long string. */
+{
+size_t size = strlen(s);
+return cloneMem(s, size+1);
+}
+
+char *catTwoStrings(char *a, char *b)
+/* Allocate new string that is a concatenation of two strings. */
+{
+int aLen = strlen(a), bLen = strlen(b);
+int len = aLen + bLen;
+char *newBuf = needLargeMem(len+1);
+memcpy(newBuf, a, aLen);
+memcpy(newBuf+aLen, b, bLen);
+newBuf[len] = 0;
+return newBuf;
+}
+
+/* Reverse the order of the bytes. */
+void reverseBytes(char *bytes, long length)
+{
+long halfLen = (length>>1);
+char *end = bytes+length;
+char c;
+while (--halfLen >= 0)
+    {
+    c = *bytes;
+    *bytes++ = *--end;
+    *end = c;
+    }
+}
+
+void reverseInts(int *a, int length)
+/* Reverse the order of the integer array. */
+{
+int halfLen = (length>>1);
+int *end = a+length;
+int c;
+while (--halfLen >= 0)
+    {
+    c = *a;
+    *a++ = *--end;
+    *end = c;
+    }
+}
+
+void reverseUnsigned(unsigned *a, int length)
+/* Reverse the order of the unsigned array. */
+{
+int halfLen = (length>>1);
+unsigned *end = a+length;
+unsigned c;
+while (--halfLen >= 0)
+    {
+    c = *a;
+    *a++ = *--end;
+    *end = c;
+    }
+}
+
+void reverseDoubles(double *a, int length)
+/* Reverse the order of the double array. */
+{
+int halfLen = (length>>1);
+double *end = a+length;
+double c;
+while (--halfLen >= 0)
+    {
+    c = *a;
+    *a++ = *--end;
+    *end = c;
+    }
+}
+
+void reverseStrings(char **a, int length)
+/* Reverse the order of the char* array. */
+{
+int halfLen = (length>>1);
+char **end = a+length;
+char *c;
+while (--halfLen >= 0)
+    {
+    c = *a;
+    *a++ = *--end;
+    *end = c;
+    }
+}
+
+/* Swap buffers a and b. */
+void swapBytes(char *a, char *b, int length)
+{
+char c;
+int i;
+
+for (i=0; i<length; ++i)
+    {
+    c = a[i];
+    a[i] = b[i];
+    b[i] = c;
+    }
+}
+
+
+/** List managing routines. */
+
+/* Count up elements in list. */
+int slCount(const void *list)
+{
+struct slList *pt = (struct slList *)list;
+int len = 0;
+
+while (pt != NULL)
+    {
+    len += 1;
+    pt = pt->next;
+    }
+return len;
+}
+
+void *slElementFromIx(void *list, int ix)
+/* Return the ix'th element in list.  Returns NULL
+ * if no such element. */
+{
+struct slList *pt = (struct slList *)list;
+int i;
+for (i=0;i<ix;i++)
+    {
+    if (pt == NULL) return NULL;
+    pt = pt->next;
+    }
+return pt;
+}
+
+int slIxFromElement(void *list, void *el)
+/* Return index of el in list.  Returns -1 if not on list. */
+{
+struct slList *pt;
+int ix = 0;
+
+for (pt = list, ix=0; pt != NULL; pt = pt->next, ++ix)
+    if (el == (void*)pt)
+	return ix;
+return -1;
+}
+
+void *slLastEl(void *list)
+/* Returns last element in list or NULL if none. */
+{
+struct slList *next, *el;
+if ((el = list) == NULL)
+    return NULL;
+while ((next = el->next) != NULL)
+    el = next;
+return el;
+}
+
+/* Add new node to tail of list.
+ * Usage:
+ *    slAddTail(&list, node);
+ * where list and nodes are both pointers to structure
+ * that begin with a next pointer.
+ */
+void slAddTail(void *listPt, void *node)
+{
+struct slList **ppt = (struct slList **)listPt;
+struct slList *n = (struct slList *)node;
+
+while (*ppt != NULL)
+    {
+    ppt = &((*ppt)->next);
+    }
+n->next = NULL;
+*ppt = n;
+}
+
+void *slPopHead(void *vListPt)
+/* Return head of list and remove it from list. (Fast) */
+{
+struct slList **listPt = (struct slList **)vListPt;
+struct slList *el = *listPt;
+if (el != NULL)
+    {
+    *listPt = el->next;
+    el->next = NULL;
+    }
+return el;
+}
+
+void *slPopTail(void *vListPt)
+/* Return tail of list and remove it from list. (Not so fast) */
+{
+struct slList **listPt = (struct slList **)vListPt;
+struct slList *el = *listPt;
+if (el != NULL)
+    {
+    for (;;)
+        {
+        if (el->next == NULL)
+            {
+            *listPt = NULL;
+            break;
+            }
+        listPt = &el->next;
+        el = el->next;
+        }
+    }
+return el;
+}
+
+
+
+void *slCat(void *va, void *vb)
+/* Return concatenation of lists a and b.
+ * Example Usage:
+ *   struct slName *a = getNames("a");
+ *   struct slName *b = getNames("b");
+ *   struct slName *ab = slCat(a,b)
+ */
+{
+struct slList *a = va;
+struct slList *b = vb;
+struct slList *end;
+if (a == NULL)
+    return b;
+for (end = a; end->next != NULL; end = end->next)
+    ;
+end->next = b;
+return a;
+}
+
+void slReverse(void *listPt)
+/* Reverse order of a list.
+ * Usage:
+ *    slReverse(&list);
+ */
+{
+struct slList **ppt = (struct slList **)listPt;
+struct slList *newList = NULL;
+struct slList *el, *next;
+
+next = *ppt;
+while (next != NULL)
+    {
+    el = next;
+    next = el->next;
+    el->next = newList;
+    newList = el;
+    }
+*ppt = newList;
+}
+
+void slFreeList(void *listPt)
+/* Free list */
+{
+struct slList **ppt = (struct slList**)listPt;
+struct slList *next = *ppt;
+struct slList *el;
+
+while (next != NULL)
+    {
+    el = next;
+    next = el->next;
+    freeMem((char*)el);
+    }
+*ppt = NULL;
+}
+
+void slSort(void *pList, int (*compare )(const void *elem1,  const void *elem2))
+/* Sort a singly linked list with Qsort and a temporary array. */
+{
+struct slList **pL = (struct slList **)pList;
+struct slList *list = *pL;
+int count;
+count = slCount(list);
+if (count > 1)
+    {
+    struct slList *el;
+    struct slList **array;
+    int i;
+    array = needLargeMem(count * sizeof(*array));
+    for (el = list, i=0; el != NULL; el = el->next, i++)
+        array[i] = el;
+    qsort(array, count, sizeof(array[0]), compare);
+    list = NULL;
+    for (i=0; i<count; ++i)
+        {
+        array[i]->next = list;
+        list = array[i];
+        }
+    freeMem(array);
+    slReverse(&list);
+    *pL = list;
+    }
+}
+
+void slUniqify(void *pList, int (*compare )(const void *elem1,  const void *elem2), void (*free)())
+/* Return sorted list with duplicates removed.
+ * Compare should be same type of function as slSort's compare (taking
+ * pointers to pointers to elements.  Free should take a simple
+ * pointer to dispose of duplicate element, and can be NULL. */
+{
+struct slList **pSlList = (struct slList **)pList;
+struct slList *oldList = *pSlList;
+struct slList *newList = NULL, *el;
+
+slSort(&oldList, compare);
+while ((el = slPopHead(&oldList)) != NULL)
+    {
+    if ((newList == NULL) || (compare(&newList, &el) != 0))
+        slAddHead(&newList, el);
+    else if (free != NULL)
+        free(el);
+    }
+slReverse(&newList);
+*pSlList = newList;
+}
+
+boolean slRemoveEl(void *vpList, void *vToRemove)
+/* Remove element from doubly linked list.  Usage:
+ *    slRemove(&list, el);
+ * Returns TRUE if element in list.  */
+{
+struct slList **pList = vpList;
+struct slList *toRemove = vToRemove;
+struct slList *el, *next, *newList = NULL;
+boolean didRemove = FALSE;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    if (el != toRemove)
+	{
+	slAddHead(&newList, el);
+	}
+    else
+        didRemove = TRUE;
+    }
+slReverse(&newList);
+*pList = newList;
+return didRemove;
+}
+
+struct slInt *slIntNew(int x)
+/* Return a new int. */
+{
+struct slInt *a;
+AllocVar(a);
+a->val = x;
+return a;
+}
+
+int slIntCmp(const void *va, const void *vb)
+/* Compare two slInts. */
+{
+const struct slInt *a = *((struct slInt **)va);
+const struct slInt *b = *((struct slInt **)vb);
+return a->val - b->val;
+}
+
+int slIntCmpRev(const void *va, const void *vb)
+/* Compare two slInts in reverse direction. */
+{
+const struct slInt *a = *((struct slInt **)va);
+const struct slInt *b = *((struct slInt **)vb);
+return b->val - a->val;
+}
+
+struct slInt * slIntFind(struct slInt *list, int target)
+/* Find target in slInt list or return NULL */
+{
+struct slInt *i;
+for (i=list;i;i=i->next)
+    if (i->val == target)
+	return i;
+return NULL;
+}
+
+static int doubleCmp(const void *va, const void *vb)
+/* Compare function to sort array of doubles. */
+{
+const double *a = va;
+const double *b = vb;
+double diff = *a - *b;
+if (diff < 0)
+    return -1;
+else if (diff > 0)
+    return 1;
+else
+    return 0;
+}
+
+void doubleSort(int count, double *array)
+/* Sort an array of doubles. */
+{
+if (count > 1)
+qsort(array, count, sizeof(array[0]), doubleCmp);
+}
+
+double doubleMedian(int count, double *array)
+/* Return median value in array.  This will sort
+ * the array as a side effect. */
+{
+double median;
+doubleSort(count, array);
+if ((count&1) == 1)
+    median = array[count>>1];
+else
+    {
+    count >>= 1;
+    median = (array[count] + array[count-1]) * 0.5;
+    }
+return median;
+}
+
+void doubleBoxWhiskerCalc(int count, double *array, double *retMin,
+                          double *retQ1, double *retMedian, double *retQ3, double *retMax)
+/* Calculate what you need to draw a box and whiskers plot from an array of doubles. */
+{
+doubleSort(count, array);
+*retMin = array[0];
+*retQ1 = array[(count+2)/4];
+int halfCount = count>>1;
+if ((count&1) == 1)
+    *retMedian = array[halfCount];
+else
+    {
+    *retMedian = (array[halfCount] + array[halfCount-1]) * 0.5;
+    }
+*retQ3 = array[(3*count+2)/4];
+*retMax = array[count-1];
+}
+
+struct slDouble *slDoubleNew(double x)
+/* Return a new double. */
+{
+struct slDouble *a;
+AllocVar(a);
+a->val = x;
+return a;
+}
+
+int slDoubleCmp(const void *va, const void *vb)
+/* Compare two slDoubles. */
+{
+const struct slDouble *a = *((struct slDouble **)va);
+const struct slDouble *b = *((struct slDouble **)vb);
+double diff = a->val - b->val;
+if (diff < 0)
+    return -1;
+else if (diff > 0)
+    return 1;
+else
+    return 0;
+}
+
+double slDoubleMedian(struct slDouble *list)
+/* Return median value on list. */
+{
+int i,count = slCount(list);
+struct slDouble *el;
+double *array, median;
+if (count == 0)
+    errAbort("Can't take median of empty list");
+AllocArray(array,count);
+for (i=0, el=list; i<count; ++i, el=el->next)
+    array[i] = el->val;
+median = doubleMedian(count, array);
+freeMem(array);
+return median;
+}
+
+void slDoubleBoxWhiskerCalc(struct slDouble *list, double *retMin,
+                            double *retQ1, double *retMedian, double *retQ3, double *retMax)
+/* Calculate what you need to draw a box and whiskers plot from a list of slDoubles. */
+{
+int i,count = slCount(list);
+struct slDouble *el;
+double *array;
+if (count == 0)
+    errAbort("Can't take do slDoubleBoxWhiskerCalc of empty list");
+AllocArray(array,count);
+for (i=0, el=list; i<count; ++i, el=el->next)
+    array[i] = el->val;
+doubleBoxWhiskerCalc(count, array, retMin, retQ1, retMedian, retQ3, retMax);
+freeMem(array);
+}
+
+static int intCmp(const void *va, const void *vb)
+/* Compare function to sort array of ints. */
+{
+const int *a = va;
+const int *b = vb;
+int diff = *a - *b;
+if (diff < 0)
+    return -1;
+else if (diff > 0)
+    return 1;
+else
+    return 0;
+}
+
+void intSort(int count, int *array)
+/* Sort an array of ints. */
+{
+if (count > 1)
+qsort(array, count, sizeof(array[0]), intCmp);
+}
+
+int intMedian(int count, int *array)
+/* Return median value in array.  This will sort
+ * the array as a side effect. */
+{
+int median;
+intSort(count, array);
+if ((count&1) == 1)
+    median = array[count>>1];
+else
+    {
+    count >>= 1;
+    median = (array[count] + array[count-1]) * 0.5;
+    }
+return median;
+}
+
+
+struct slName *newSlName(char *name)
+/* Return a new name. */
+{
+struct slName *sn;
+if (name != NULL)
+    {
+    int len = strlen(name);
+    sn = needMem(sizeof(*sn)+len);
+    strcpy(sn->name, name);
+    return sn;
+    }
+else
+    {
+    AllocVar(sn);
+    }
+return sn;
+}
+
+struct slName *slNameNewN(char *name, int size)
+/* Return new slName of given size. */
+{
+struct slName *sn = needMem(sizeof(*sn) + size);
+memcpy(sn->name, name, size);
+return sn;
+}
+
+int slNameCmpCase(const void *va, const void *vb)
+/* Compare two slNames, ignore case. */
+{
+const struct slName *a = *((struct slName **)va);
+const struct slName *b = *((struct slName **)vb);
+return strcasecmp(a->name, b->name);
+}
+
+void slNameSortCase(struct slName **pList)
+/* Sort slName list, ignore case. */
+{
+slSort(pList, slNameCmpCase);
+}
+
+int slNameCmp(const void *va, const void *vb)
+/* Compare two slNames. */
+{
+const struct slName *a = *((struct slName **)va);
+const struct slName *b = *((struct slName **)vb);
+return strcmp(a->name, b->name);
+}
+
+int slNameCmpStringsWithEmbeddedNumbers(const void *va, const void *vb)
+/* Compare strings such as gene names that may have embedded numbers,
+ * so that bmp4a comes before bmp14a */
+{
+const struct slName *a = *((struct slName **)va);
+const struct slName *b = *((struct slName **)vb);
+return cmpStringsWithEmbeddedNumbers(a->name, b->name);
+}
+
+
+
+void slNameSort(struct slName **pList)
+/* Sort slName list. */
+{
+slSort(pList, slNameCmp);
+}
+
+boolean slNameInList(struct slName *list, char *string)
+/* Return true if string is in name list -- case insensitive. */
+{
+struct slName *el;
+for (el = list; el != NULL; el = el->next)
+    if (sameWord(string, el->name))
+        return TRUE;
+return FALSE;
+}
+
+boolean slNameInListUseCase(struct slName *list, char *string)
+/* Return true if string is in name list -- case sensitive. */
+{
+struct slName *el;
+for (el = list; el != NULL; el = el->next)
+    if (string != NULL && !strcmp(string, el->name))
+        return TRUE;
+return FALSE;
+}
+
+void *slNameFind(void *list, char *string)
+/* Return first element of slName list (or any other list starting
+ * with next/name fields) that matches string. */
+{
+struct slName *el;
+for (el = list; el != NULL; el = el->next)
+    if (sameWord(string, el->name))
+        return el;
+return NULL;
+}
+
+int slNameFindIx(struct slName *list, char *string)
+/* Return index of first element of slName list (or any other
+ * list starting with next/name fields) that matches string.
+ * Return -1 if not found. */
+{
+struct slName *el;
+int ix = 0;
+for (el = list; el != NULL; el = el->next, ix++)
+    if (sameString(string, el->name))
+        return ix;
+return -1;
+}
+
+char *slNameStore(struct slName **pList, char *string)
+/* Put string into list if it's not there already.
+ * Return the version of string stored in list. */
+{
+struct slName *el;
+for (el = *pList; el != NULL; el = el->next)
+    {
+    if (sameString(string, el->name))
+	return el->name;
+    }
+el = newSlName(string);
+slAddHead(pList, el);
+return el->name;
+}
+
+struct slName *slNameAddHead(struct slName **pList, char *name)
+/* Add name to start of list and return it. */
+{
+struct slName *el = slNameNew(name);
+slAddHead(pList, el);
+return el;
+}
+
+struct slName *slNameAddTail(struct slName **pList, char *name)
+/* Add name to end of list (not efficient for long lists),
+ * and return it. */
+{
+struct slName *el = slNameNew(name);
+slAddTail(pList, el);
+return el;
+}
+
+struct slName *slNameCloneList(struct slName *list)
+/* Return clone of list. */
+{
+struct slName *el, *newEl, *newList = NULL;
+for (el = list; el != NULL; el = el->next)
+    {
+    newEl = slNameNew(el->name);
+    slAddHead(&newList, newEl);
+    }
+slReverse(&newList);
+return newList;
+}
+
+
+struct slName *slNameListFromString(char *s, char delimiter)
+/* Return list of slNames gotten from parsing delimited string.
+ * The final delimiter is optional. a,b,c  and a,b,c, are equivalent
+ * for comma-delimited lists. */
+{
+char *e;
+struct slName *list = NULL, *el;
+while (s != NULL && s[0] != 0)
+    {
+    e = strchr(s, delimiter);
+    if (e == NULL)
+	el = slNameNew(s);
+    else
+	{
+        el = slNameNewN(s, e-s);
+	e += 1;
+	}
+    slAddHead(&list, el);
+    s = e;
+    }
+slReverse(&list);
+return list;
+}
+
+struct slName *slNameListOfUniqueWords(char *text,boolean respectQuotes)
+// Return list of unique words found by parsing string delimited by whitespace.
+// If respectQuotes then ["Lucy and Ricky" 'Fred and Ethyl'] will yield 2 slNames no quotes
+{
+struct slName *list = NULL;
+char *word = NULL;
+while (text != NULL)
+    {
+    if (respectQuotes)
+        {
+        word = nextWordRespectingQuotes(&text);
+        if (word != NULL)
+            {
+            if (word[0] == '"')
+                stripChar(word, '"');
+            else if (word[0] == '\'')
+                stripChar(word, '\'');
+            }
+        }
+    else
+        word = nextWord(&text);
+    if (word)
+        slNameStore(&list, word);
+    else
+        break;
+    }
+
+slReverse(&list);
+return list;
+}
+
+struct slName *slNameListFromStringArray(char *stringArray[], int arraySize)
+/* Return list of slNames from an array of strings of length arraySize.
+ * If a string in the array is NULL, the array will be treated as
+ * NULL-terminated (shorter than arraySize). */
+{
+char *s;
+struct slName *list = NULL, *el;
+int i;
+if (stringArray == NULL)
+    return NULL;
+for (i = 0;  i < arraySize;  i++)
+    {
+    s = stringArray[i];
+    if (s == NULL)
+	break;
+    el = slNameNew(s);
+    slAddHead(&list, el);
+    }
+slReverse(&list);
+return list;
+}
+
+char *slNameListToString(struct slName *list, char delimiter)
+/* Return string created by joining all names with the delimiter. */
+{
+struct slName *el;
+int elCount = 0;
+int len = 0;
+char del[2];
+char *s;
+
+del[0] = delimiter;
+del[1] = '\0';
+
+for (el = list; el != NULL; el = el->next, elCount++)
+	len += strlen(el->name);
+len += elCount;
+
+AllocArray(s, len);
+
+for (el = list; el != NULL; el = el->next)
+	{
+	strcat(s, el->name);
+	if (el->next != NULL)
+		strcat(s, del);
+	}
+return s;
+}
+
+struct slName *slNameLoadReal(char *fileName)
+/* load file lines that are not blank or start with a '#' into a slName
+ * list */
+{
+struct slName *lines = NULL;
+char *line;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+while (lineFileNextReal(lf, &line))
+    slSafeAddHead(&lines, slNameNew(line));
+lineFileClose(&lf);
+slReverse(&lines);
+return lines;
+}
+
+struct slName *slNameIntersection(struct slName *a, struct slName *b)
+/* return intersection of two slName lists.  */
+{
+struct hash *hashA = newHash(0);
+struct slName *el, *retval = NULL;
+
+for (el = a; el != NULL; el = el->next)
+    hashAddInt(hashA, el->name, 1);
+for (el = b; el != NULL; el = el->next)
+    if(hashLookup(hashA, el->name) != NULL)
+        slNameAddHead(&retval, el->name);
+hashFree(&hashA);
+return retval;
+}
+
+struct slRef *refOnList(struct slRef *refList, void *val)
+/* Return ref if val is already on list, otherwise NULL. */
+{
+struct slRef *ref;
+for (ref = refList; ref != NULL; ref = ref->next)
+    if (ref->val == val)
+        return ref;
+return NULL;
+}
+
+struct slRef *slRefNew(void *val)
+/* Create new slRef element. */
+{
+struct slRef *ref;
+AllocVar(ref);
+ref->val = val;
+return ref;
+}
+
+void refAdd(struct slRef **pRefList, void *val)
+/* Add reference to list. */
+{
+struct slRef *ref;
+AllocVar(ref);
+ref->val = val;
+slAddHead(pRefList, ref);
+}
+
+void refAddUnique(struct slRef **pRefList, void *val)
+/* Add reference to list if not already on list. */
+{
+if (refOnList(*pRefList, val) == NULL)
+    {
+    refAdd(pRefList, val);
+    }
+}
+
+struct slRef *refListFromSlList(void *list)
+/* Make a reference list that mirrors a singly-linked list. */
+{
+struct slList *el;
+struct slRef *refList = NULL, *ref;
+for (el= list; el != NULL; el = el->next)
+    {
+    ref = slRefNew(el);
+    slAddHead(&refList, ref);
+    }
+slReverse(&refList);
+return refList;
+}
+
+
+struct slPair *slPairNew(char *name, void *val)
+/* Allocate new name/value pair. */
+{
+struct slPair *el;
+AllocVar(el);
+el->name = cloneString(name);
+el->val = val;
+return el;
+}
+
+void slPairAdd(struct slPair **pList, char *name, void *val)
+/* Add new slPair to head of list. */
+{
+struct slPair *el = slPairNew(name, val);
+slAddHead(pList, el);
+}
+
+void slPairFree(struct slPair **pEl)
+/* Free up struct and name.  (Don't free up values.) */
+{
+struct slPair *el = *pEl;
+if (el != NULL)
+    {
+    freeMem(el->name);
+    freez(pEl);
+    }
+}
+
+void slPairFreeList(struct slPair **pList)
+/* Free up list.  (Don't free up values.) */
+{
+struct slPair *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    slPairFree(&el);
+    }
+*pList = NULL;
+}
+
+void slPairFreeVals(struct slPair *list)
+/* Free up all values on list. */
+{
+struct slPair *el;
+for (el = list; el != NULL; el = el->next)
+    freez(&el->val);
+}
+
+void slPairFreeValsAndList(struct slPair **pList)
+/* Free up all values on list and list itself */
+{
+slPairFreeVals(*pList);
+slPairFreeList(pList);
+}
+
+struct slPair *slPairFind(struct slPair *list, char *name)
+/* Return list element of given name, or NULL if not found. */
+{
+struct slPair *el;
+for (el = list; el != NULL; el = el->next)
+    if (sameString(name, el->name))
+        break;
+return el;
+}
+
+void *slPairFindVal(struct slPair *list, char *name)
+/* Return value associated with name in list, or NULL if not found. */
+{
+struct slPair *el = slPairFind(list, name);
+if (el == NULL)
+    return NULL;
+return el->val;
+}
+
+struct slPair *slPairListFromString(char *str,boolean respectQuotes)
+// Return slPair list parsed from list in string like:  [name1=val1 name2=val2 ...]
+// if respectQuotes then string can have double quotes: [name1="val 1" "name 2"=val2 ...]
+//    resulting pair strips quotes: {name1}={val 1},{name 2}={val2}
+// Returns NULL if parse error.  Free this up with slPairFreeValsAndList.
+{
+char *s = skipLeadingSpaces(str);  // Would like to remove this and tighten up the standard someday.
+if (isEmpty(s))
+    return NULL;
+
+struct slPair *list = NULL;
+char name[1024];
+char val[1024];
+char buf[1024];
+bool inQuote = FALSE;
+char *b = buf;
+char sep = '=';
+char c = ' ';
+int mode = 0;
+while(1)
+    {
+    c = *s++;
+    if (mode == 0 || mode == 2) // reading name or val
+	{
+	boolean term = FALSE;
+	if (respectQuotes && b == buf && !inQuote && c == '"')
+	    inQuote = TRUE;
+	else if (inQuote && c == '"')
+	    term = TRUE;
+	else if ((c == sep || c == 0) && !inQuote)
+	    {
+	    term = TRUE;
+	    --s;  // rewind
+	    }
+	else if (c == ' ' && !inQuote)
+	    {
+	    warn("slPairListFromString: Unexpected whitespace in %s", str);
+	    return NULL;
+	    }
+	else if (c == 0 && inQuote)
+	    {
+	    warn("slPairListFromString: Unterminated quote in %s", str);
+	    return NULL;
+	    }
+	else
+	    {
+	    *b++ = c;
+	    if ((b - buf) > sizeof buf)
+		{
+		warn("slPairListFromString: pair name or value too long in %s", str);
+		return NULL;
+		}
+	    }
+	if (term)
+	    {
+	    inQuote = FALSE;
+	    *b = 0;
+	    if (mode == 0)
+		{
+		safecpy(name, sizeof name, buf);
+		if (strlen(name)<1)
+		    {
+		    warn("slPairListFromString: Pair name cannot be empty in %s", str);
+		    return NULL;
+		    }
+		// Shall we check for name being alphanumeric, at least for the respectQuotes=FALSE case?
+		}
+	    else // mode == 2
+                {
+		safecpy(val, sizeof val, buf);
+		if (!respectQuotes && (hasWhiteSpace(name) || hasWhiteSpace(val))) // should never happen
+		    {
+		    warn("slPairListFromString() Unexpected white space in name=value pair: [%s]=[%s] in string=[%s]\n", name, val, str);
+		    break;
+		    }
+		slPairAdd(&list, name, cloneString(val));
+		}
+	    ++mode;
+	    }
+	}
+    else if (mode == 1) // read required "=" sign
+	{
+	if (c != '=')
+	    {
+	    warn("slPairListFromString: Expected character = after name in %s", str);
+	    return NULL;
+            }
+	++mode;
+	sep = ' ';
+	b = buf;
+	}
+    else // (mode == 3) reading optional separating space
+	{
+	if (c == 0)
+	    break;
+	if (c != ' ')
+	    {
+	    mode = 0;
+	    --s;
+	    b = buf;
+	    sep = '=';
+	    }
+	}
+    }
+slReverse(&list);
+return list;
+}
+
+char *slPairListToString(struct slPair *list,boolean quoteIfSpaces)
+// Returns an allocated string of pairs in form of [name1=val1 name2=val2 ...]
+// If requested, will wrap name or val in quotes if contain spaces: [name1="val 1" "name 2"=val2]
+{
+// Don't rely on dyString.  We should do the accounting ourselves and not create extra dependencies.
+int count = 0;
+struct slPair *pair = list;
+for (;pair != NULL; pair = pair->next)
+    {
+    assert(pair->name != NULL && pair->val != NULL); // Better assert and get this over with,
+                                                     // complete with stack
+    count += strlen(pair->name);
+    count += strlen((char *)(pair->val));
+    count += 2; // = and ' ' delimit
+    if (quoteIfSpaces)
+        {
+        if (hasWhiteSpace(pair->name))
+            count += 2; // " and "
+        if (hasWhiteSpace((char *)(pair->val)))
+            count += 2; // " and "
+        }
+    }
+if (count == 0)
+    return NULL;
+
+char *str = needMem(count+5); // A bit of slop
+
+char *strPtr = str;
+for (pair = list; pair != NULL; pair = pair->next, strPtr += strlen(strPtr))
+    {
+    if (pair != list) // Not first cycle
+        *strPtr++ = ' ';
+    if (hasWhiteSpace(pair->name))
+        {
+        if (quoteIfSpaces)
+            sprintf(strPtr,"\"%s\"=",pair->name);
+        else
+            {
+            warn("slPairListToString() Unexpected white space in name: [%s]\n", pair->name);
+            sprintf(strPtr,"%s=",pair->name); // warn but still make string
+            }
+        }
+    else
+        sprintf(strPtr,"%s=",pair->name);
+    strPtr += strlen(strPtr);
+    if (hasWhiteSpace((char *)(pair->val)))
+        {
+        if (quoteIfSpaces)
+            sprintf(strPtr,"\"%s\"",(char *)(pair->val));
+        else
+            {
+            warn("slPairListToString() Unexpected white space in val: [%s]\n", (char *)(pair->val));
+            sprintf(strPtr,"%s",(char *)(pair->val)); // warn but still make string
+            }
+        }
+    else
+        sprintf(strPtr,"%s",(char *)(pair->val));
+    }
+return str;
+}
+
+char *slPairNameToString(struct slPair *list, char delimiter,boolean quoteIfSpaces)
+// Return string created by joining all names (ignoring vals) with the delimiter.
+// If requested, will wrap name in quotes if contain spaces: [name1,"name 2" ...]
+{
+int elCount = 0;
+int count = 0;
+struct slPair *pair = list;
+for (; pair != NULL; pair = pair->next, elCount++)
+    {
+    assert(pair->name != NULL);
+    count += strlen(pair->name);
+    if (quoteIfSpaces && hasWhiteSpace(pair->name))
+        count += 2;
+    }
+count += elCount;
+if (count == 0)
+    return NULL;
+
+char *str = needMem(count+5); // A bit of slop
+
+char *strPtr = str;
+for (pair = list; pair != NULL; pair = pair->next, strPtr += strlen(strPtr))
+    {
+    if (pair != list)
+        *strPtr++ = delimiter;
+    if (hasWhiteSpace(pair->name))
+        {
+        if (quoteIfSpaces)
+            sprintf(strPtr,"\"%s\"",pair->name);
+        else
+            {
+            if (delimiter == ' ')  // if delimied by commas, this is entirely okay!
+                warn("slPairListToString() Unexpected white space in name delimied by space: "
+                     "[%s]\n", pair->name);
+            sprintf(strPtr,"%s",pair->name); // warn but still make string
+            }
+        }
+    else
+        sprintf(strPtr,"%s",pair->name);
+    }
+return str;
+}
+
+int slPairCmpCase(const void *va, const void *vb)
+/* Compare two slPairs, ignore case. */
+{
+const struct slPair *a = *((struct slPair **)va);
+const struct slPair *b = *((struct slPair **)vb);
+return strcasecmp(a->name, b->name);
+}
+
+void slPairSortCase(struct slPair **pList)
+/* Sort slPair list, ignore case. */
+{
+slSort(pList, slPairCmpCase);
+}
+
+int slPairCmp(const void *va, const void *vb)
+/* Compare two slPairs. */
+{
+const struct slPair *a = *((struct slPair **)va);
+const struct slPair *b = *((struct slPair **)vb);
+return strcmp(a->name, b->name);
+}
+
+int slPairValCmpCase(const void *va, const void *vb)
+/* Case insensitive compare two slPairs on their values (must be string). */
+{
+const struct slPair *a = *((struct slPair **)va);
+const struct slPair *b = *((struct slPair **)vb);
+return strcasecmp((char *)(a->val), (char *)(b->val));
+}
+
+int slPairValCmp(const void *va, const void *vb)
+/* Compare two slPairs on their values (must be string). */
+{
+const struct slPair *a = *((struct slPair **)va);
+const struct slPair *b = *((struct slPair **)vb);
+return strcmp((char *)(a->val), (char *)(b->val));
+}
+
+void slPairValSortCase(struct slPair **pList)
+/* Sort slPair list on values (must be string), ignore case. */
+{
+slSort(pList, slPairValCmpCase);
+}
+
+void slPairValSort(struct slPair **pList)
+/* Sort slPair list on values (must be string). */
+{
+slSort(pList, slPairValCmp);
+}
+
+int slPairIntCmp(const void *va, const void *vb)
+// Compare two slPairs on their integer values.
+{
+const struct slPair *a = *((struct slPair **)va);
+const struct slPair *b = *((struct slPair **)vb);
+return ((char *)(a->val) - (char *)(b->val)); // cast works and val is 0 vased integer
+}
+
+void slPairIntSort(struct slPair **pList)
+// Sort slPair list on integer values.
+{
+slSort(pList, slPairIntCmp);
+}
+
+int slPairAtoiCmp(const void *va, const void *vb)
+// Compare two slPairs on their strings interpreted as integer values.
+{
+const struct slPair *a = *((struct slPair **)va);
+const struct slPair *b = *((struct slPair **)vb);
+return (atoi((char *)(a->val)) - atoi((char *)(b->val)));
+}
+
+void slPairValAtoiSort(struct slPair **pList)
+// Sort slPair list on string values interpreted as integers.
+{
+slSort(pList, slPairAtoiCmp);
+}
+
+void gentleFree(void *pt)
+{
+if (pt != NULL) freeMem((char*)pt);
+}
+
+int differentWord(char *s1, char *s2)
+/* strcmp ignoring case - returns zero if strings are
+ * the same (ignoring case) otherwise returns difference
+ * between first non-matching characters. */
+{
+char c1, c2;
+for (;;)
+    {
+    c1 = toupper(*s1++);
+    c2 = toupper(*s2++);
+    if (c1 != c2) /* Takes care of end of string in one but not the other too */
+	return c2-c1;
+    if (c1 == 0)  /* Take care of end of string in both. */
+	return 0;
+    }
+}
+
+int differentStringNullOk(char *a, char *b)
+/* Returns 0 if two strings (either of which may be NULL)
+ * are the same.  Otherwise it returns a positive or negative
+ * number depending on the alphabetical order of the two
+ * strings.
+ * This is basically a strcmp that can handle NULLs in
+ * the input.  If used in a sort the NULLs will end
+ * up before any of the cases with data.   */
+{
+if (a == b)
+    return FALSE;
+else if (a == NULL)
+    return -1;
+else if (b == NULL)
+    return 1;
+else
+    return strcmp(a,b) != 0;
+}
+
+boolean startsWith(const char *start, const char *string)
+/* Returns TRUE if string begins with start. */
+{
+char c;
+int i;
+
+for (i=0; ;i += 1)
+    {
+    if ((c = start[i]) == 0)
+        return TRUE;
+    if (string[i] != c)
+        return FALSE;
+    }
+}
+
+boolean startsWithWord(char *firstWord, char *line)
+/* Return TRUE if first white-space-delimited word in line
+ * is same as firstWord.  Comparison is case sensitive. */
+{
+int len = strlen(firstWord);
+int i;
+for (i=0; i<len; ++i)
+   if (firstWord[i] != line[i])
+       return FALSE;
+char c = line[len];
+return c == 0 || isspace(c);
+}
+
+boolean startsWithWordByDelimiter(char *firstWord,char delimit, char *line)
+/* Return TRUE if first word in line is same as firstWord as delimited by delimit.
+   Comparison is case sensitive. Delimit of ' ' uses isspace() */
+{
+if (delimit == ' ')
+    return startsWithWord(firstWord,line);
+if (!startsWith(firstWord,line))
+    return FALSE;
+char c = line[strlen(firstWord)];
+return (c == '\0' || c == delimit);
+}
+
+char * findWordByDelimiter(char *word,char delimit, char *line)
+/* Return pointer to first occurance of word in line broken by 'delimit' char
+   Comparison is case sensitive. Delimit of ' ' uses isspace() */
+{
+int ix;
+char *p=line;
+while (p!=NULL && *p!='\0')
+    {
+    for (ix = 0;
+         word[ix] != '\0' && word[ix] == *p;
+         ix++,p++) ; // advance as long as they match
+    if (ix == strlen(word))
+        {
+        if (*p=='\0'
+        || *p==delimit
+        || (delimit == ' ' && isspace(*p)))
+            return p - ix; // matched and delimited
+        }
+    for (;   *p!='\0' && *p!=delimit && (delimit != ' ' || !isspace(*p)); p++)
+        ;  // advance to next delimit
+    if (*p!='\0')
+        {
+        p++;
+        continue;  // delimited so start again after delimit
+        }
+    }
+return NULL;
+}
+
+char *rStringIn(char *needle, char *haystack)
+/* Return last position of needle in haystack, or NULL if it's not there. */
+{
+int nSize = strlen(needle);
+char *pos;
+for (pos = haystack + strlen(haystack) - nSize; pos >= haystack; pos -= 1)
+    {
+    if (memcmp(needle, pos, nSize) == 0)
+        return pos;
+    }
+return NULL;
+}
+
+char *stringBetween(char *start, char *end, char *haystack)
+/* Return string between start and end strings, or NULL if
+ * none found.  The first such instance is returned.
+ * String must be freed by caller. */
+{
+char *pos, *p;
+int len;
+if ((p = stringIn(start, haystack)) != NULL)
+    {
+    pos = p + strlen(start);
+    if ((p = stringIn(end, pos)) != NULL)
+        {
+        len = p - pos;
+        pos = cloneMem(pos, len + 1);
+        pos[len] = 0;
+        return pos;
+        }
+    }
+return NULL;
+}
+
+boolean endsWith(char *string, char *end)
+/* Returns TRUE if string ends with end. */
+{
+int sLen, eLen, offset;
+sLen = strlen(string);
+eLen = strlen(end);
+offset = sLen - eLen;
+if (offset < 0)
+    return FALSE;
+return sameString(string+offset, end);
+}
+
+char lastChar(char *s)
+/* Return last character in string. */
+{
+if (s == NULL || s[0] == 0)
+    return 0;
+return s[strlen(s)-1];
+}
+
+void trimLastChar(char *s)
+/* Erase last character in string. */
+{
+int len = strlen(s);
+if (len > 0)
+   s[len-1] = 0;
+}
+
+char *lastNonwhitespaceChar(char *s)
+// Return pointer to last character in string that is not whitespace.
+{
+if (s == NULL || s[0] == 0)
+    return NULL;
+
+char *sPos = s + (strlen(s) - 1);
+for (;sPos >= s;sPos--)
+    {
+    if (!isspace(*sPos))
+        return sPos;
+    }
+return NULL;
+}
+
+char *matchingCharBeforeInLimits(char *limit, char *s, char c)
+/* Look for character c sometime before s, but going no further than limit.
+ * Return NULL if not found. */
+{
+while (--s >= limit)
+    if (*s == c)
+        return s;
+return NULL;
+}
+
+char *memMatch(char *needle, int nLen, char *haystack, int hLen)
+/* Returns first place where needle (of nLen chars) matches
+ * haystack (of hLen chars) */
+{
+char c = *needle++;
+nLen -= 1;
+hLen -= nLen;
+while (--hLen >= 0)
+    {
+    if (*haystack++ == c && memcmp(needle, haystack, nLen) == 0)
+        {
+        return haystack-1;
+        }
+    }
+return NULL;
+}
+
+void toUpperN(char *s, int n)
+/* Convert a section of memory to upper case. */
+{
+int i;
+for (i=0; i<n; ++i)
+    s[i] = toupper(s[i]);
+}
+
+void toLowerN(char *s, int n)
+/* Convert a section of memory to lower case. */
+{
+int i;
+for (i=0; i<n; ++i)
+    s[i] = tolower(s[i]);
+}
+
+void toggleCase(char *s, int size)
+/* toggle upper and lower case chars in string. */
+{
+char c;
+int i;
+for (i=0; i<size; ++i)
+    {
+    c = s[i];
+    if (isupper(c))
+        c = tolower(c);
+    else if (islower(c))
+        c = toupper(c);
+    s[i] = c;
+    }
+}
+
+
+char *strUpper(char *s)
+/* Convert entire string to upper case. */
+{
+char c;
+char *ss=s;
+for (;;)
+    {
+    if ((c = *ss) == 0) break;
+    *ss++ = toupper(c);
+    }
+return s;
+}
+
+char *replaceChars(char *string, char *old, char *new)
+/*
+  Replaces the old with the new. The old and new string need not be of equal size
+ Can take any length string.
+ Return value needs to be freeMem'd.
+*/
+{
+int numTimes = 0;
+int oldLen = strlen(old);
+int newLen = strlen(new);
+int strLen = 0;
+char *result = NULL;
+char *ptr = strstr(string, old);
+char *resultPtr = NULL;
+
+while(NULL != ptr)
+    {
+    numTimes++;
+    ptr += oldLen;
+    ptr = strstr(ptr, old);
+    }
+strLen = max(strlen(string) + (numTimes * (newLen - oldLen)), strlen(string));
+result = needMem(strLen + 1);
+
+ptr = strstr(string, old);
+resultPtr = result;
+while(NULL != ptr)
+    {
+    strLen = ptr - string;
+    strcpy(resultPtr, string);
+    string = ptr + oldLen;
+
+    resultPtr += strLen;
+    strcpy(resultPtr, new);
+    resultPtr += newLen;
+    ptr = strstr(string, old);
+    }
+
+strcpy(resultPtr, string);
+return result;
+}
+
+int strSwapStrs(char *string, int sz,char *oldStr, char *newStr)
+/* Swaps all occurrences of the old with the new in string. Need not be same size
+   Swaps in place but restricted by sz.  Returns count of swaps or -1 for sz failure. */
+{
+// WARNING: called at low level, so no errors allowed.
+int count = 0;
+char *p=NULL;
+for(p=strstr(string,oldStr);p!=NULL;p=strstr(p+strlen(oldStr),oldStr))
+    count++;
+if (count == 0)
+    return 0;
+if((strlen(string)+(count*(strlen(newStr) - strlen(oldStr))))>=sz)
+    return -1;
+for(p=strstr(string,oldStr);p!=NULL;p=strstr(p+strlen(newStr),oldStr))
+    {
+    memmove(p+strlen(newStr),p+strlen(oldStr),strlen(p+strlen(oldStr))+1); // NULL at end is also moved!
+    memcpy(p,newStr,strlen(newStr));
+    }
+return count;
+}
+
+char *strLower(char *s)
+/* Convert entire string to lower case */
+{
+char c;
+char *ss=s;
+for (;;)
+    {
+    if ((c = *ss) == 0) break;
+    *ss++ = tolower(c);
+    }
+return s;
+}
+
+char * memSwapChar(char *s, int len, char oldChar, char newChar)
+/* Substitute newChar for oldChar throughout memory of given length. */
+{
+int ix=0;
+for (;ix<len;ix++)
+    {
+    if (s[ix] == oldChar)
+        s[ix] =  newChar;
+    }
+return s;
+}
+
+void stripChar(char *s, char c)
+/* Remove all occurences of c from s. */
+{
+char *in = s, *out = s;
+char b;
+
+for (;;)
+    {
+    b = *out = *in++;
+    if (b == 0)
+       break;
+    if (b != c)
+       ++out;
+    }
+}
+
+char *stripEnclosingChar(char *inout,char encloser)
+// Removes enclosing char if found at both beg and end, preserving pointer
+// Note: handles brackets '(','{' and '[' by complement at end
+{
+if (inout == NULL || strlen(inout) < 2 || *inout != encloser)
+    return inout;
+
+char *end = inout + (strlen(inout) - 1);
+char closer = encloser;
+switch (closer)
+    {
+    case '(': closer = ')'; break;
+    case '{': closer = '}'; break;
+    case '[': closer = ']'; break;
+    default: break;
+    }
+if (*end  != closer)
+    return inout;
+*end = '\0';
+return memmove(inout,inout+1,strlen(inout));  // use memmove to safely copy in place
+}
+
+void stripString(char *s, char *strip)
+/* Remove all occurences of strip from s. */
+{
+char c, *in = s, *out = s;
+int stripSize = strlen(strip);
+char stripFirst = strip[0];
+
+while ((c = *in) != 0)
+    {
+    c = *in;
+    if (c == stripFirst)
+        {
+	if (startsWith(strip, in))
+	    {
+	    in += stripSize;
+	    continue;
+	    }
+	}
+    *out = c;
+    ++out;
+    ++in;
+    }
+*out = 0;
+}
+
+int countCase(char *s,boolean upper)
+// Count letters with case (upper or lower)
+{
+char a;
+int count = 0;
+while ((a = *s++) != 0)
+    if (( upper && isupper(a))
+    ||  (!upper && islower(a)))
+        ++count;
+return count;
+}
+
+int countChars(char *s, char c)
+/* Return number of characters c in string s. */
+{
+char a;
+int count = 0;
+while ((a = *s++) != 0)
+    if (a == c)
+        ++count;
+return count;
+}
+
+int countCharsN(char *s, char c, int size)
+/* Return number of characters c in string s of given size. */
+{
+int i;
+int count = 0;
+for (i=0; i<size; ++i)
+    if (s[i] == c)
+        ++count;
+return count;
+}
+
+int countLeadingChars(char *s, char c)
+/* Count number of characters c at start of string. */
+{
+int count = 0;
+while (*s++ == c)
+   ++count;
+return count;
+}
+
+int countLeadingDigits(const char *s)
+/* Return number of leading digits in s */
+{
+int count = 0;
+while (isdigit(*s))
+   {
+   ++count;
+   ++s;
+   }
+return count;
+}
+
+int countLeadingNondigits(const char *s)
+/* Count number of leading non-digit characters in s. */
+{
+int count = 0;
+char c;
+while ((c = *s++) != 0)
+   {
+   if (isdigit(c))
+       break;
+   ++count;
+   }
+return count;
+}
+
+int countSeparatedItems(char *string, char separator)
+/* Count number of items in string you would parse out with given
+ * separator,  assuming final separator is optional. */
+{
+int count = 0;
+char c, lastC = 0;
+while ((c = *string++) != 0)
+    {   
+    if (c == separator)
+       ++count;
+    lastC = c;
+    }
+if (lastC != separator && lastC != 0)
+    ++count;
+return count;
+}
+
+int cmpStringsWithEmbeddedNumbers(const char *a, const char *b)
+/* Compare strings such as gene names that may have embedded numbers,
+ * so that bmp4a comes before bmp14a */
+{
+for (;;)
+   {
+   /* Figure out number of digits at start, and do numerical comparison if there
+    * are any.  If numbers agree step over numerical part, otherwise return difference. */
+   int aNum = countLeadingDigits(a);
+   int bNum = countLeadingDigits(b);
+   if (aNum >= 0 && bNum >= 0)
+       {
+       int diff = atoi(a) - atoi(b);
+       if (diff != 0)
+           return diff;
+       a += aNum;
+       b += bNum;
+       }
+
+   /* Count number of non-digits at start. */
+   int aNonNum = countLeadingNondigits(a);
+   int bNonNum = countLeadingNondigits(b);
+
+   // If different sizes of non-numerical part, then don't match, let strcmp sort out how
+   if (aNonNum != bNonNum)
+        return strcmp(a,b);
+   // If no characters left then they are the same!
+   else if (aNonNum == 0)
+       return 0;
+   // Non-numerical part is the same length and non-zero.  See if it is identical.  Return if not.
+   else
+       {
+        int diff = memcmp(a,b,aNonNum);
+       if (diff != 0)
+            return diff;
+       a += aNonNum;
+       b += bNonNum;
+       }
+   }
+}
+
+int cmpWordsWithEmbeddedNumbers(const char *a, const char *b)
+/* Case insensitive version of cmpStringsWithEmbeddedNumbers. */
+{
+char *A = cloneString(a);
+char *B = cloneString(b);
+int diff = cmpStringsWithEmbeddedNumbers(strUpper(A), strUpper(B));
+freeMem(A);
+freeMem(B);
+return diff;
+}
+
+int countSame(char *a, char *b)
+/* Count number of characters that from start in a,b that are same. */
+{
+char c;
+int i;
+int count = 0;
+for (i=0; ; ++i)
+   {
+   c = a[i];
+   if (b[i] != c)
+       break;
+   if (c == 0)
+       break;
+   ++count;
+   }
+return count;
+}
+
+
+/* int chopString(in, sep, outArray, outSize); */
+/* This chops up the input string (cannabilizing it)
+ * into an array of zero terminated strings in
+ * outArray.  It returns the number of strings.
+ * If you pass in NULL for outArray, it will just
+ * return the number of strings that it *would*
+ * chop. 
+ * GOTCHA: since multiple separators are skipped
+ * and treated as one, it is impossible to parse 
+ * a list with an empty string. 
+ * e.g. cat\t\tdog returns only cat and dog but no empty string */
+int chopString(char *in, char *sep, char *outArray[], int outSize)
+{
+int recordCount = 0;
+
+for (;;)
+    {
+    if (outArray != NULL && recordCount >= outSize)
+	break;
+    /* Skip initial separators. */
+    in += strspn(in, sep);
+    if (*in == 0)
+	break;
+    if (outArray != NULL)
+	outArray[recordCount] = in;
+    recordCount += 1;
+    in += strcspn(in, sep);
+    if (*in == 0)
+	break;
+    if (outArray != NULL)
+	*in = 0;
+    in += 1;
+    }
+return recordCount;
+}
+
+int chopByWhite(char *in, char *outArray[], int outSize)
+/* Like chopString, but specialized for white space separators. 
+ * See the GOTCHA in chopString */
+{
+int recordCount = 0;
+char c;
+for (;;)
+    {
+    if (outArray != NULL && recordCount >= outSize)
+	break;
+
+    /* Skip initial separators. */
+    while (isspace(*in)) ++in;
+    if (*in == 0)
+        break;
+
+    /* Store start of word and look for end of word. */
+    if (outArray != NULL)
+        outArray[recordCount] = in;
+    recordCount += 1;
+    for (;;)
+        {
+        if ((c = *in) == 0)
+            break;
+        if (isspace(c))
+            break;
+        ++in;
+        }
+    if (*in == 0)
+	break;
+
+    /* Tag end of word with zero. */
+    if (outArray != NULL)
+	*in = 0;
+    /* And skip over the zero. */
+    in += 1;
+    }
+return recordCount;
+}
+
+int chopByWhiteRespectDoubleQuotes(char *in, char *outArray[], int outSize)
+/* Like chopString, but specialized for white space separators.
+ * Further, any doubleQuotes (") are respected.
+ * If doubleQuote is encloses whole string, then they are removed:
+ *   "Fred and Ethyl" results in word [Fred and Ethyl]
+ * If doubleQuotes exist inside string they are retained:
+ *   Fred" and Ethyl" results in word [Fred" and Ethyl"]
+ * Special note "" is a valid, though empty word. */
+{
+int recordCount = 0;
+char c;
+char *quoteBegins = NULL;
+boolean quoting = FALSE;
+for (;;)
+    {
+    if (outArray != NULL && recordCount >= outSize)
+        break;
+
+    /* Skip initial separators. */
+    while (isspace(*in)) ++in;
+    if (*in == 0)
+        break;
+
+    /* Store start of word and look for end of word. */
+    if (outArray != NULL)
+        {
+        outArray[recordCount] = in;
+        if ((*in == '"'))
+            quoteBegins = (in+1);
+        else
+            quoteBegins = NULL;
+        }
+    recordCount += 1;
+    quoting = FALSE;
+    for (;;)
+        {
+        if ((c = *in) == 0)
+            break;
+        if (quoting)
+            {
+            if (c == '"')
+                {
+                quoting = FALSE;
+                if (quoteBegins != NULL) // implies out array
+                    {
+                    if ((c = *(in+1) == 0 )|| isspace(c)) // whole word is quoted.
+                        {
+                        outArray[recordCount-1] = quoteBegins; // Fix beginning of word
+                        quoteBegins = NULL;
+                        break;
+                        }
+                    }
+                }
+            }
+        else
+            {
+            quoting = (c == '"');
+            if (isspace(c))
+                break;
+            }
+        ++in;
+        }
+    if (*in == 0)
+        break;
+
+    /* Tag end of word with zero. */
+    if (outArray != NULL)
+        *in = 0;
+    /* And skip over the zero. */
+    in += 1;
+    }
+return recordCount;
+}
+
+int chopByChar(char *in, char chopper, char *outArray[], int outSize)
+/* Chop based on a single character. */
+{
+int i;
+char c;
+if (*in == 0)
+    return 0;
+for (i=0; (i<outSize) || (outArray==NULL); ++i)
+    {
+    if (outArray != NULL)
+        outArray[i] = in;
+    for (;;)
+	{
+	if ((c = *in++) == 0)
+	    return i+1;
+	else if (c == chopper)
+	    {
+            if (outArray != NULL)
+                in[-1] = 0;
+	    break;
+	    }
+	}
+    }
+return i;
+}
+
+char crLfChopper[] = "\n\r";
+char whiteSpaceChopper[] = " \t\n\r";
+
+
+char *skipBeyondDelimit(char *s,char delimit)
+/* Returns NULL or pointer to first char beyond one (or more contiguous) delimit char.
+   If delimit is ' ' then skips beyond first patch of whitespace. */
+{
+if (s != NULL)
+    {
+    char *beyond = NULL;
+    if (delimit == ' ')
+        return skipLeadingSpaces(skipToSpaces(s));
+    else
+        beyond = strchr(s,delimit);
+    if (beyond != NULL)
+        {
+        for (beyond++;*beyond == delimit;beyond++) ;
+        if (*beyond != '\0')
+            return beyond;
+        }
+    }
+return NULL;
+}
+
+char *skipLeadingSpaces(char *s)
+/* Return first non-white space. */
+{
+char c;
+if (s == NULL) return NULL;
+for (;;)
+    {
+    c = *s;
+    if (!isspace(c))
+	return s;
+    ++s;
+    }
+}
+
+char *skipToSpaces(char *s)
+/* Return first white space or NULL if none.. */
+{
+char c;
+if (s == NULL)
+    return NULL;
+for (;;)
+    {
+    c = *s;
+    if (c == 0)
+        return NULL;
+    if (isspace(c))
+	return s;
+    ++s;
+    }
+}
+
+
+
+void eraseTrailingSpaces(char *s)
+/* Replace trailing white space with zeroes. */
+{
+int len = strlen(s);
+int i;
+char c;
+
+for (i=len-1; i>=0; --i)
+    {
+    c = s[i];
+    if (isspace(c))
+	s[i] = 0;
+    else
+	break;
+    }
+}
+
+/* Remove white space from a string */
+void eraseWhiteSpace(char *s)
+{
+char *in, *out;
+char c;
+
+in = out = s;
+for (;;)
+    {
+    c = *in++;
+    if (c == 0)
+	break;
+    if (!isspace(c))
+	*out++ = c;
+    }
+*out++ = 0;
+}
+
+/* Remove non-alphanumeric chars from string */
+void eraseNonAlphaNum(char *s)
+{
+char *in, *out;
+char c;
+
+in = out = s;
+for (;;)
+    {
+    c = *in++;
+    if (c == 0)
+        break;
+    if (isalnum(c))
+        *out++ = c;
+    }
+*out = 0;
+}
+
+char *trimSpaces(char *s)
+/* Remove leading and trailing white space. */
+{
+if (s != NULL)
+    {
+    s = skipLeadingSpaces(s);
+    eraseTrailingSpaces(s);
+    }
+return s;
+}
+
+void repeatCharOut(FILE *f, char c, int count)
+/* Write character to file repeatedly. */
+{
+while (--count >= 0)
+    fputc(c, f);
+}
+
+void spaceOut(FILE *f, int count)
+/* Put out some spaces to file. */
+{
+repeatCharOut(f, ' ', count);
+}
+
+void starOut(FILE *f, int count)
+/* Put out some asterisks to file. */
+{
+repeatCharOut(f, '*', count);
+}
+
+boolean hasWhiteSpace(char *s)
+/* Return TRUE if there is white space in string. */
+{
+char c;
+while ((c = *s++) != 0)
+    if (isspace(c))
+        return TRUE;
+return FALSE;
+}
+
+char *firstWordInLine(char *line)
+/* Returns first word in line if any (white space separated).
+ * Puts 0 in place of white space after word. */
+{
+char *e;
+line = skipLeadingSpaces(line);
+if ((e = skipToSpaces(line)) != NULL)
+    *e = 0;
+return line;
+}
+
+char *cloneFirstWord(char *line)
+/* Clone first word in line */
+{
+char *startFirstWord = skipLeadingSpaces(line);
+if (startFirstWord == NULL)
+    return NULL;
+char *endFirstWord = skipToSpaces(startFirstWord);
+if (endFirstWord == NULL)
+    return cloneString(startFirstWord);
+else
+    return cloneStringZ(startFirstWord, endFirstWord - startFirstWord);
+}
+
+char *lastWordInLine(char *line)
+/* Returns last word in line if any (white space separated).
+ * Returns NULL if string is empty.  Removes any terminating white space
+ * from line. */
+{
+char *s = line;
+char *word = NULL, *wordEnd = NULL;
+for (;;)
+    {
+    s = skipLeadingSpaces(s);
+    if (s == NULL || s[0] == 0)
+	break;
+    word = s;
+    s = wordEnd = skipToSpaces(s);
+    if (s == NULL)
+        break;
+    }
+if (wordEnd != NULL)
+    *wordEnd = 0;
+return word;
+}
+
+char *nextWord(char **pLine)
+/* Return next word in *pLine and advance *pLine to next
+ * word. */
+{
+char *s = *pLine, *e;
+if (s == NULL || s[0] == 0)
+    return NULL;
+s = skipLeadingSpaces(s);
+if (s[0] == 0)
+    return NULL;
+e = skipToSpaces(s);
+if (e != NULL)
+    *e++ = 0;
+*pLine = e;
+return s;
+}
+
+char *nextWordRespectingQuotes(char **pLine)
+// return next word but respects single or double quotes surrounding sets of words.
+{
+char *s = *pLine, *e;
+if (s == NULL || s[0] == 0)
+    return NULL;
+s = skipLeadingSpaces(s);
+if (s[0] == 0)
+    return NULL;
+if (s[0] == '"')
+    {
+    e = skipBeyondDelimit(s+1,'"');
+    if (e != NULL && !isspace(e[0]))
+        e = skipToSpaces(s);
+    }
+else if (s[0] == '\'')
+    {
+    e = skipBeyondDelimit(s+1,'\'');
+    if (e != NULL && !isspace(e[0]))
+        e = skipToSpaces(s);
+    }
+else
+    e = skipToSpaces(s);
+if (e != NULL)
+    *e++ = 0;
+*pLine = e;
+return s;
+}
+
+char *nextTabWord(char **pLine)
+/* Return next tab-separated word. */
+{
+char *s = *pLine;
+char *e;
+if (s == NULL || *s == '\n' || *s == 0)
+    {
+    *pLine = NULL;
+    return NULL;
+    }
+e = strchr(s, '\t');
+if (e == NULL)
+    {
+    e = strchr(s, '\n');
+    if (e != NULL)
+        *e = 0;
+    *pLine = NULL;
+    }
+else
+    {
+    *e++ = 0;
+    *pLine = e;
+    }
+return s;
+}
+
+char *cloneFirstWordByDelimiter(char *line,char delimit)
+/* Returns a cloned first word, not harming the memory passed in */
+{
+if (line == NULL || *line == 0)
+    return NULL;
+line = skipLeadingSpaces(line);
+if (*line == 0)
+    return NULL;
+int size=0;
+char *e;
+for (e=line;*e!=0;e++)
+    {
+    if (*e==delimit)
+        break;
+    else if (delimit == ' ' && isspace(*e))
+        break;
+    size++;
+    }
+if (size == 0)
+    return NULL;
+char *new = needMem(size + 2); // Null terminated by 2
+memcpy(new, line, size);
+return new;
+}
+
+char *cloneNextWordByDelimiter(char **line,char delimit)
+/* Returns a cloned first word, advancing the line pointer but not harming memory passed in */
+{
+char *new = cloneFirstWordByDelimiter(*line,delimit);
+if (new != NULL)
+    {
+    *line = skipLeadingSpaces(*line);
+    *line += strlen(new);
+    if ( **line != 0)
+        (*line)++;
+    }
+return new;
+}
+
+char *nextStringInList(char **pStrings)
+/* returns pointer to the first string and advances pointer to next in
+   list of strings dilimited by 1 null and terminated by 2 nulls. */
+{
+if (pStrings == NULL || *pStrings == NULL || **pStrings == 0)
+    return NULL;
+char *p=*pStrings;
+*pStrings += strlen(p)+1;
+return p;
+}
+
+int cntStringsInList(char *pStrings)
+/* returns count of strings in a
+   list of strings dilimited by 1 null and terminated by 2 nulls. */
+{
+int cnt=0;
+char *p = pStrings;
+while (nextStringInList(&p) != NULL)
+    cnt++;
+return cnt;
+}
+
+int stringArrayIx(char *string, char *array[], int arraySize)
+
+/* Return index of string in array or -1 if not there. */
+{
+int i;
+for (i=0; i<arraySize; ++i)
+    if (!differentWord(array[i], string))
+        return i;
+return -1;
+}
+
+int ptArrayIx(void *pt, void *array, int arraySize)
+/* Return index of pt in array or -1 if not there. */
+{
+int i;
+void **a = array;
+for (i=0; i<arraySize; ++i)
+    {
+    if (pt == a[i])
+        return i;
+    }
+return -1;
+}
+
+
+
+FILE *mustOpen(char *fileName, char *mode)
+/* Open a file - or squawk and die. */
+{
+FILE *f;
+
+if (sameString(fileName, "stdin"))
+    return stdin;
+if (sameString(fileName, "stdout"))
+    return stdout;
+if ((f = fopen(fileName, mode)) == NULL)
+    {
+    char *modeName = "";
+    if (mode)
+        {
+        if (mode[0] == 'r')
+            modeName = " to read";
+        else if (mode[0] == 'w')
+            modeName = " to write";
+        else if (mode[0] == 'a')
+            modeName = " to append";
+        }
+    errAbort("Can't open %s%s: %s", fileName, modeName, strerror(errno));
+    }
+return f;
+}
+
+void mustWrite(FILE *file, void *buf, size_t size)
+/* Write to a file or squawk and die. */
+{
+if (size != 0 && fwrite(buf, size, 1, file) != 1)
+    {
+    errAbort("Error writing %lld bytes: %s\n", (long long)size, strerror(ferror(file)));
+    }
+}
+
+
+void mustRead(FILE *file, void *buf, size_t size)
+/* Read size bytes from a file or squawk and die. */
+{
+if (size != 0 && fread(buf, size, 1, file) != 1)
+    {
+    if (ferror(file))
+	errAbort("Error reading %lld bytes: %s", (long long)size, strerror(ferror(file)));
+    else
+	errAbort("End of file reading %lld bytes", (long long)size);
+    }
+}
+
+void writeString(FILE *f, char *s)
+/* Write a 255 or less character string to a file.
+ * This will write the length of the string in the first
+ * byte then the string itself. */
+{
+UBYTE bLen;
+int len = strlen(s);
+
+if (len > 255)
+    {
+    warn("String too long in writeString (%d chars):\n%s", len, s);
+    len = 255;
+    }
+bLen = len;
+writeOne(f, bLen);
+mustWrite(f, s, len);
+}
+
+char *readString(FILE *f)
+/* Read a string (written with writeString) into
+ * memory.  freeMem the result when done. */
+{
+UBYTE bLen;
+int len;
+char *s;
+
+if (!readOne(f, bLen))
+    return NULL;
+len = bLen;
+s = needMem(len+1);
+if (len > 0)
+    mustRead(f, s, len);
+return s;
+}
+
+char *mustReadString(FILE *f)
+/* Read a string.  Squawk and die at EOF or if any problem. */
+{
+char *s = readString(f);
+if (s == NULL)
+    errAbort("Couldn't read string");
+return s;
+}
+
+
+boolean fastReadString(FILE *f, char buf[256])
+/* Read a string into buffer, which must be long enough
+ * to hold it.  String is in 'writeString' format. */
+{
+UBYTE bLen;
+int len;
+if (!readOne(f, bLen))
+    return FALSE;
+if ((len = bLen)> 0)
+    mustRead(f, buf, len);
+buf[len] = 0;
+return TRUE;
+}
+
+void msbFirstWriteBits64(FILE *f, bits64 x)
+/* Write out 64 bit number in manner that is portable across architectures */
+{
+int i;
+UBYTE buf[8];
+for (i=7; i>=0; --i)
+    {
+    buf[i] = (UBYTE)(x&0xff);
+    x >>= 8;
+    }
+mustWrite(f, buf, 8);
+}
+
+bits64 msbFirstReadBits64(FILE *f)
+/* Write out 64 bit number in manner that is portable across architectures */
+{
+int i;
+UBYTE buf[8];
+bits64 x = 0;
+mustRead(f, buf, 8);
+for (i=0; i<8; ++i)
+    {
+    x <<= 8;
+    x |= buf[i];
+    }
+return x;
+}
+
+void mustGetLine(FILE *file, char *buf, int charCount)
+/* Read at most charCount-1 bytes from file, but stop after newline if one is
+ * encountered.  The string in buf is '\0'-terminated.  (See man 3 fgets.)
+ * Die if there is an error. */
+{
+char *success = fgets(buf, charCount, file);
+if (success == NULL && charCount > 0)
+    buf[0] = '\0';
+if (ferror(file))
+    errAbort("mustGetLine: fgets failed: %s", strerror(ferror(file)));
+}
+
+int mustOpenFd(char *fileName, int flags)
+/* Open a file descriptor (see man 2 open) or squawk and die. */
+{
+if (sameString(fileName, "stdin"))
+    return STDIN_FILENO;
+if (sameString(fileName, "stdout"))
+    return STDOUT_FILENO;
+// mode is necessary when O_CREAT is given, ignored otherwise
+int mode = 00664;
+int fd = open(fileName, flags, mode);
+if (fd < 0)
+    {
+    char *modeName = "";
+    if ((flags & (O_WRONLY | O_CREAT | O_TRUNC)) == (O_WRONLY | O_CREAT | O_TRUNC))
+	modeName = " to create and truncate";
+    else if ((flags & (O_WRONLY | O_CREAT)) == (O_WRONLY | O_CREAT))
+	modeName = " to create";
+    else if ((flags & O_WRONLY) == O_WRONLY)
+	modeName = " to write";
+    else if ((flags & O_RDWR) == O_RDWR)
+	modeName = " to append";
+    else
+	modeName = " to read";
+    errnoAbort("Can't open %s%s", fileName, modeName);
+    }
+return fd;
+}
+
+void mustReadFd(int fd, void *buf, size_t size)
+/* Read size bytes from a file or squawk and die. */
+{
+ssize_t actualSize;
+char *cbuf = buf;
+// using a loop because linux was not returning all data in a single request when request size exceeded 2GB.
+while (size > 0)
+    {
+    actualSize = read(fd, cbuf, size);
+    if (actualSize < 0)
+	errnoAbort("Error reading %lld bytes", (long long)size);
+    if (actualSize == 0)
+	errAbort("End of file reading %llu bytes (got %lld)", (unsigned long long)size, (long long)actualSize);
+    cbuf += actualSize;
+    size -= actualSize;
+    }
+}
+
+void mustWriteFd(int fd, void *buf, size_t size)
+/* Write size bytes to file descriptor fd or die.  (See man 2 write.) */
+{
+ssize_t result = write(fd, buf, size);
+if (result < size)
+    errAbort("mustWriteFd: write failed: %s", strerror(errno));
+}
+
+off_t mustLseek(int fd, off_t offset, int whence)
+/* Seek to given offset, relative to whence (see man lseek) in file descriptor fd or errAbort.
+ * Return final offset (e.g. if this is just an (fd, 0, SEEK_CUR) query for current position). */
+{
+off_t ret = lseek(fd, offset, whence);
+if (ret < 0)
+    errnoAbort("lseek(%d, %lld, %s (%d)) failed", fd, (long long)offset,
+	       ((whence == SEEK_SET) ? "SEEK_SET" : (whence == SEEK_CUR) ? "SEEK_CUR" :
+		(whence == SEEK_END) ? "SEEK_END" : "invalid 'whence' value"), whence);
+return ret;
+}
+
+void mustCloseFd(int *pFd)
+/* Close file descriptor *pFd if >= 0, abort if there's an error, set *pFd = -1. */
+{
+if (pFd != NULL && *pFd >= 0)
+    {
+    if (close(*pFd) < 0)
+	errnoAbort("close failed");
+    *pFd = -1;
+    }
+}
+
+char *addSuffix(char *head, char *suffix)
+/* Return a needMem'd string containing "headsuffix". Should be free'd
+ when finished. */
+{
+char *ret = NULL;
+int size = strlen(head) + strlen(suffix) +1;
+ret = needMem(sizeof(char)*size);
+snprintf(ret, size, "%s%s", head, suffix);
+return ret;
+}
+
+void chopSuffix(char *s)
+/* Remove suffix (last . in string and beyond) if any. */
+{
+char *e = strrchr(s, '.');
+if (e != NULL)
+    *e = 0;
+}
+
+void chopSuffixAt(char *s, char c)
+/* Remove end of string from first occurrence of char c.
+ * chopSuffixAt(s, '.') is equivalent to regular chopSuffix. */
+{
+char *e = strrchr(s, c);
+if (e != NULL)
+    *e = 0;
+}
+
+char *chopPrefixAt(char *s, char c)
+/* Like chopPrefix, but can chop on any character, not just '.' */
+{
+char *e = strchr(s, c);
+if (e == NULL) return s;
+*e++ = 0;
+return e;
+}
+
+char *chopPrefix(char *s)
+/* This will replace the first '.' in a string with
+ * 0, and return the character after this.  If there
+ * is no '.' in the string this will just return the
+ * unchanged s passed in. */
+{
+return chopPrefixAt(s, '.');
+}
+
+
+
+boolean carefulCloseWarn(FILE **pFile)
+/* Close file if open and null out handle to it.
+ * Return FALSE and print a warning message if there
+ * is a problem.*/
+{
+FILE *f;
+boolean ok = TRUE;
+if ((pFile != NULL) && ((f = *pFile) != NULL))
+    {
+    if (f != stdin && f != stdout)
+        {
+        if (fclose(f) != 0)
+	    {
+            errnoWarn("fclose failed");
+	    ok = FALSE;
+	    }
+        }
+    *pFile = NULL;
+    }
+return ok;
+}
+
+void carefulClose(FILE **pFile)
+/* Close file if open and null out handle to it.
+ * Warn and abort if there's a problem. */
+{
+if (!carefulCloseWarn(pFile))
+    noWarnAbort();
+}
+
+char *firstWordInFile(char *fileName, char *wordBuf, int wordBufSize)
+/* Read the first word in file into wordBuf. */
+{
+FILE *f = mustOpen(fileName, "r");
+mustGetLine(f, wordBuf, wordBufSize);
+fclose(f);
+return trimSpaces(wordBuf);
+}
+
+int fileOffsetSizeCmp(const void *va, const void *vb)
+/* Help sort fileOffsetSize by offset. */
+{
+const struct fileOffsetSize *a = *((struct fileOffsetSize **)va);
+const struct fileOffsetSize *b = *((struct fileOffsetSize **)vb);
+if (a->offset > b->offset)
+    return 1;
+else if (a->offset == b->offset)
+    return 0;
+else
+    return -1;
+}
+
+struct fileOffsetSize *fileOffsetSizeMerge(struct fileOffsetSize *inList)
+/* Returns a new list which is inList transformed to have adjacent blocks
+ * merged.  Best to use this with a sorted list. */
+{
+struct fileOffsetSize *newList = NULL, *newEl = NULL, *oldEl, *nextOld;
+
+for (oldEl = inList; oldEl != NULL; oldEl = nextOld)
+    {
+    nextOld = oldEl->next;
+    if (nextOld != NULL && nextOld->offset < oldEl->offset)
+        errAbort("Unsorted inList in fileOffsetSizeMerge %llu %llu", oldEl->offset, nextOld->offset);
+    if (newEl == NULL || newEl->offset + newEl->size < oldEl->offset)
+        {
+	newEl = CloneVar(oldEl);
+	slAddHead(&newList, newEl);
+	}
+    else
+        {
+	newEl->size = oldEl->offset + oldEl->size - newEl->offset;
+	}
+    }
+slReverse(&newList);
+return newList;
+}
+
+void fileOffsetSizeFindGap(struct fileOffsetSize *list,
+                           struct fileOffsetSize **pBeforeGap, struct fileOffsetSize **pAfterGap)
+/* Starting at list, find all items that don't have a gap between them and the previous item.
+ * Return at gap, or at end of list, returning pointers to the items before and after the gap. */
+{
+struct fileOffsetSize *pt, *next;
+for (pt = list; ; pt = next)
+    {
+    next = pt->next;
+    if (next == NULL || next->offset != pt->offset + pt->size)
+	{
+	*pBeforeGap = pt;
+	*pAfterGap = next;
+	return;
+	}
+    }
+}
+
+
+void mustSystem(char *cmd)
+/* Execute cmd using "sh -c" or die.  (See man 3 system.) fail on errors */
+{
+if (cmd == NULL) // don't allow (system() supports testing for shell this way)
+    errAbort("mustSystem: called with NULL command.");
+int status = system(cmd);
+if (status == -1)
+    errnoAbort("error starting command: %s", cmd);
+else if (WIFSIGNALED(status))
+    errAbort("command terminated by signal %d: %s", WTERMSIG(status), cmd);
+else if (WIFEXITED(status))
+    {
+    if (WEXITSTATUS(status) != 0)
+        errAbort("command exited with %d: %s", WEXITSTATUS(status), cmd);
+    }
+else
+    errAbort("bug: invalid exit status for command: %s", cmd);
+}
+
+int roundingScale(int a, int p, int q)
+/* returns rounded a*p/q */
+{
+if (a > 100000 || p > 100000)
+    {
+    double x = a;
+    x *= p;
+    x /= q;
+    return round(x);
+    }
+else
+    return (a*p + q/2)/q;
+}
+
+int intAbs(int a)
+/* Return integer absolute value */
+{
+return (a >= 0 ? a : -a);
+}
+
+int  rangeIntersection(int start1, int end1, int start2, int end2)
+/* Return amount of bases two ranges intersect over, 0 or negative if no
+ * intersection. */
+{
+int s = max(start1,start2);
+int e = min(end1,end2);
+return e-s;
+}
+
+int positiveRangeIntersection(int start1, int end1, int start2, int end2)
+/* Return number of bases in intersection of two ranges, or
+ * zero if they don't intersect. */
+{
+int ret = rangeIntersection(start1,end1,start2,end2);
+if (ret < 0)
+    ret = 0;
+return ret;
+}
+
+bits64 byteSwap64(bits64 a)
+/* Return byte-swapped version of a */
+{
+union {bits64 whole; UBYTE bytes[4];} u,v;
+u.whole = a;
+v.bytes[0] = u.bytes[7];
+v.bytes[1] = u.bytes[6];
+v.bytes[2] = u.bytes[5];
+v.bytes[3] = u.bytes[4];
+v.bytes[4] = u.bytes[3];
+v.bytes[5] = u.bytes[2];
+v.bytes[6] = u.bytes[1];
+v.bytes[7] = u.bytes[0];
+return v.whole;
+}
+
+bits64 readBits64(FILE *f, boolean isSwapped)
+/* Read and optionally byte-swap 64 bit entity. */
+{
+bits64 val;
+mustReadOne(f, val);
+if (isSwapped)
+    val = byteSwap64(val);
+return val;
+}
+
+bits64 fdReadBits64(int fd, boolean isSwapped)
+/* Read and optionally byte-swap 64 bit entity. */
+{
+bits64 val;
+mustReadOneFd(fd, val);
+if (isSwapped)
+    val = byteSwap64(val);
+return val;
+}
+
+bits64 memReadBits64(char **pPt, boolean isSwapped)
+/* Read and optionally byte-swap 64 bit entity from memory buffer pointed to by
+ * *pPt, and advance *pPt past read area. */
+{
+bits64 val;
+memcpy(&val, *pPt, sizeof(val));
+if (isSwapped)
+    val = byteSwap64(val);
+*pPt += sizeof(val);
+return val;
+}
+
+bits32 byteSwap32(bits32 a)
+/* Return byte-swapped version of a */
+{
+union {bits32 whole; UBYTE bytes[4];} u,v;
+u.whole = a;
+v.bytes[0] = u.bytes[3];
+v.bytes[1] = u.bytes[2];
+v.bytes[2] = u.bytes[1];
+v.bytes[3] = u.bytes[0];
+return v.whole;
+}
+
+bits32 readBits32(FILE *f, boolean isSwapped)
+/* Read and optionally byte-swap 32 bit entity. */
+{
+bits32 val;
+mustReadOne(f, val);
+if (isSwapped)
+    val = byteSwap32(val);
+return val;
+}
+
+bits32 fdReadBits32(int fd, boolean isSwapped)
+/* Read and optionally byte-swap 32 bit entity. */
+{
+bits32 val;
+mustReadOneFd(fd, val);
+if (isSwapped)
+    val = byteSwap32(val);
+return val;
+}
+
+bits32 memReadBits32(char **pPt, boolean isSwapped)
+/* Read and optionally byte-swap 32 bit entity from memory buffer pointed to by
+ * *pPt, and advance *pPt past read area. */
+{
+bits32 val;
+memcpy(&val, *pPt, sizeof(val));
+if (isSwapped)
+    val = byteSwap32(val);
+*pPt += sizeof(val);
+return val;
+}
+
+bits16 byteSwap16(bits16 a)
+/* Return byte-swapped version of a */
+{
+union {bits16 whole; UBYTE bytes[2];} u,v;
+u.whole = a;
+v.bytes[0] = u.bytes[1];
+v.bytes[1] = u.bytes[0];
+return v.whole;
+}
+
+bits16 readBits16(FILE *f, boolean isSwapped)
+/* Read and optionally byte-swap 16 bit entity. */
+{
+bits16 val;
+mustReadOne(f, val);
+if (isSwapped)
+    val = byteSwap16(val);
+return val;
+}
+
+bits16 fdReadBits16(int fd, boolean isSwapped)
+/* Read and optionally byte-swap 16 bit entity. */
+{
+bits16 val;
+mustReadOneFd(fd, val);
+if (isSwapped)
+    val = byteSwap16(val);
+return val;
+}
+
+bits16 memReadBits16(char **pPt, boolean isSwapped)
+/* Read and optionally byte-swap 16 bit entity from memory buffer pointed to by
+ * *pPt, and advance *pPt past read area. */
+{
+bits16 val;
+memcpy(&val, *pPt, sizeof(val));
+if (isSwapped)
+    val = byteSwap16(val);
+*pPt += sizeof(val);
+return val;
+}
+
+double byteSwapDouble(double a)
+/* Return byte-swapped version of a */
+{
+union {double whole; UBYTE bytes[4];} u,v;
+u.whole = a;
+v.bytes[0] = u.bytes[7];
+v.bytes[1] = u.bytes[6];
+v.bytes[2] = u.bytes[5];
+v.bytes[3] = u.bytes[4];
+v.bytes[4] = u.bytes[3];
+v.bytes[5] = u.bytes[2];
+v.bytes[6] = u.bytes[1];
+v.bytes[7] = u.bytes[0];
+return v.whole;
+}
+
+
+double readDouble(FILE *f, boolean isSwapped)
+/* Read and optionally byte-swap double-precision floating point entity. */
+{
+double val;
+mustReadOne(f, val);
+if (isSwapped)
+    val = byteSwapDouble(val);
+return val;
+}
+
+double memReadDouble(char **pPt, boolean isSwapped)
+/* Read and optionally byte-swap double-precision floating point entity
+ * from memory buffer pointed to by *pPt, and advance *pPt past read area. */
+{
+double val;
+memcpy(&val, *pPt, sizeof(val));
+if (isSwapped)
+    val = byteSwapDouble(val);
+*pPt += sizeof(val);
+return val;
+}
+
+float byteSwapFloat(float a)
+/* Return byte-swapped version of a */
+{
+union {float whole; UBYTE bytes[4];} u,v;
+u.whole = a;
+v.bytes[0] = u.bytes[3];
+v.bytes[1] = u.bytes[2];
+v.bytes[2] = u.bytes[1];
+v.bytes[3] = u.bytes[0];
+return v.whole;
+}
+
+
+float readFloat(FILE *f, boolean isSwapped)
+/* Read and optionally byte-swap single-precision floating point entity. */
+{
+float val;
+mustReadOne(f, val);
+if (isSwapped)
+    val = byteSwapFloat(val);
+return val;
+}
+
+float memReadFloat(char **pPt, boolean isSwapped)
+/* Read and optionally byte-swap single-precision floating point entity
+ * from memory buffer pointed to by *pPt, and advance *pPt past read area. */
+{
+float val;
+memcpy(&val, *pPt, sizeof(val));
+if (isSwapped)
+    val = byteSwapFloat(val);
+*pPt += sizeof(val);
+return val;
+}
+
+
+void removeReturns(char *dest, char *src)
+/* Removes the '\r' character from a string.
+ * The source and destination strings can be the same, if there are
+ * no other threads */
+{
+int i = 0;
+int j = 0;
+
+/* until the end of the string */
+for (;;)
+    {
+    /* skip the returns */
+    while(src[j] == '\r')
+	j++;
+
+    /* copy the characters */
+    dest[i] = src[j];
+
+    /* check to see if done */
+    if(src[j] == '\0')
+	break;
+
+    /* advance the counters */
+    i++;
+    j++;
+    }
+}
+
+char* readLine(FILE* fh)
+/* Read a line of any size into dynamic memory, return null on EOF */
+{
+int bufCapacity = 256;
+int bufSize = 0;
+char* buf = needMem(bufCapacity);
+int ch;
+
+/* loop until EOF of EOLN */
+while (((ch = getc(fh)) != EOF) && (ch != '\n'))
+    {
+    /* expand if almost full, always keep one extra char for
+     * zero termination */
+    if (bufSize >= bufCapacity-2)
+        {
+        bufCapacity *= 2;
+        buf = realloc(buf, bufCapacity);
+        if (buf == NULL)
+            {
+            errAbort("Out of memory in readline - request size %d bytes", bufCapacity);
+            }
+        }
+    buf[bufSize++] = ch;
+    }
+
+/* only return EOF if no data was read */
+if ((ch == EOF) && (bufSize == 0))
+    {
+    freeMem(buf);
+    return NULL;
+    }
+buf[bufSize] = '\0';
+return buf;
+}
+
+boolean fileExists(char *fileName)
+/* Return TRUE if file exists (may replace this with non-
+ * portable faster way some day). */
+{
+/* To make piping easier stdin and stdout always exist. */
+if (sameString(fileName, "stdin")) return TRUE;
+if (sameString(fileName, "stdout")) return TRUE;
+
+return fileSize(fileName) != -1;
+}
+
+/*
+ Friendly name for strstrNoCase
+*/
+char *containsStringNoCase(char *haystack, char *needle)
+{
+return strstrNoCase(haystack, needle);
+}
+
+char *strstrNoCase(char *haystack, char *needle)
+/*
+  A case-insensitive strstr function
+Will also robustly handle null strings
+param haystack - The string to be searched
+param needle - The string to look for in the haystack string
+
+return - The position of the first occurence of the desired substring
+or -1 if it is not found
+ */
+{
+char *haystackCopy = NULL;
+char *needleCopy = NULL;
+int index = 0;
+int haystackLen = 0;
+int needleLen = 0;
+char *p, *q;
+
+if (NULL == haystack || NULL == needle)
+    {
+    return NULL;
+    }
+
+haystackLen = strlen(haystack);
+needleLen = strlen(needle);
+
+haystackCopy = (char*) needMem(haystackLen + 1);
+needleCopy = (char*) needMem(needleLen + 1);
+
+for(index = 0; index < haystackLen;  index++)
+    {
+    haystackCopy[index] = tolower(haystack[index]);
+    }
+haystackCopy[haystackLen] = 0; /* Null terminate */
+
+for(index = 0; index < needleLen;  index++)
+    {
+    needleCopy[index] = tolower(needle[index]);
+    }
+needleCopy[needleLen] = 0; /* Null terminate */
+
+p=strstr(haystackCopy, needleCopy);
+q=haystackCopy;
+
+freeMem(haystackCopy);
+freeMem(needleCopy);
+
+if(p==NULL) return NULL;
+
+return p-q+haystack;
+}
+
+int vasafef(char* buffer, int bufSize, char *format, va_list args)
+/* Format string to buffer, vsprintf style, only with buffer overflow
+ * checking.  The resulting string is always terminated with zero byte. */
+{
+int sz = vsnprintf(buffer, bufSize, format, args);
+/* note that some version return -1 if too small */
+if ((sz < 0) || (sz >= bufSize))
+    {
+    buffer[bufSize-1] = (char) 0;
+    errAbort("buffer overflow, size %d, format: %s, buffer: '%s'", bufSize, format, buffer);
+    }
+return sz;
+}
+
+int safef(char* buffer, int bufSize, char *format, ...)
+/* Format string to buffer, vsprintf style, only with buffer overflow
+ * checking.  The resulting string is always terminated with zero byte. */
+{
+int sz;
+va_list args;
+va_start(args, format);
+sz = vasafef(buffer, bufSize, format, args);
+va_end(args);
+return sz;
+}
+
+void safecpy(char *buf, size_t bufSize, const char *src)
+/* copy a string to a buffer, with bounds checking.*/
+{
+size_t slen = strlen(src);
+if (slen > bufSize-1)
+    errAbort("buffer overflow, size %lld, string size: %lld", (long long)bufSize, (long long)slen);
+strcpy(buf, src);
+}
+
+void safencpy(char *buf, size_t bufSize, const char *src, size_t n)
+/* copy n characters from a string to a buffer, with bounds checking.
+ * Unlike strncpy, always null terminates the result */
+{
+if (n > bufSize-1)
+    errAbort("buffer overflow, size %lld, substring size: %lld", (long long)bufSize, (long long)n);
+// strlen(src) can take a long time when src is for example a pointer into a chromosome sequence.
+// Instead of setting slen to max(strlen(src), n), just stop counting length at n.
+size_t slen = 0;
+while (src[slen] != '\0' && slen < n)
+    slen++;
+strncpy(buf, src, n);
+buf[slen] = '\0';
+}
+
+void safecat(char *buf, size_t bufSize, const char *src)
+/* Append  a string to a buffer, with bounds checking.*/
+{
+size_t blen = strlen(buf);
+size_t slen = strlen(src);
+if (blen+slen > bufSize-1)
+    errAbort("buffer overflow, size %lld, new string size: %lld", (long long)bufSize, (long long)(blen+slen));
+strcat(buf, src);
+}
+
+void safencat(char *buf, size_t bufSize, const char *src, size_t n)
+/* append n characters from a string to a buffer, with bounds checking. */
+{
+size_t blen = strlen(buf);
+if (blen+n > bufSize-1)
+    errAbort("buffer overflow, size %lld, new string size: %lld", (long long)bufSize, (long long)(blen+n));
+size_t slen = strlen(src);
+if (slen > n)
+    slen = n;
+strncat(buf, src, n);
+buf[blen+slen] = '\0';
+}
+
+
+static char *naStr = "n/a";
+static char *emptyStr = "";
+
+char *naForNull(char *s)
+/* Return 'n/a' if s is NULL, otherwise s. */
+{
+if (s == NULL)
+   s = naStr;
+return s;
+}
+
+char *naForEmpty(char *s)
+/* Return n/a if s is "" or NULL, otherwise s. */
+{
+if (s == NULL || s[0] == 0)
+    s = naStr;
+return s;
+}
+
+char *emptyForNull(char *s)
+/* Return "" if s is NULL, otherwise s. */
+{
+if (s == NULL)
+   s = emptyStr;
+return s;
+}
+
+char *nullIfAllSpace(char *s)
+/* Return NULL if s is all spaces, otherwise s. */
+{
+s = skipLeadingSpaces(s);
+if (s != NULL)
+    if (s[0] == 0)
+        s = NULL;
+return s;
+}
+
+char *trueFalseString(boolean b)
+/* Return "true" or "false" */
+{
+return (b ? "true" : "false");
+}
+
+void uglyTime(char *label, ...)
+/* Print label and how long it's been since last call.  Call with
+ * a NULL label to initialize. */
+{
+static long lastTime = 0;
+long time = clock1000();
+va_list args;
+va_start(args, label);
+if (label != NULL)
+    {
+    fprintf(stdout, "<span class='timing'>");
+    vfprintf(stdout, label, args);
+    fprintf(stdout, ": %ld millis<BR></span>\n", time - lastTime);
+    }
+lastTime = time;
+va_end(args);
+}
+
+void makeDirs(char* path)
+/* make a directory, including parent directories */
+{
+char pathBuf[PATH_LEN];
+char* next = pathBuf;
+
+strcpy(pathBuf, path);
+if (*next == '/')
+    next++;
+
+while((*next != '\0')
+      && (next = strchr(next, '/')) != NULL)
+    {
+    *next = '\0';
+    makeDir(pathBuf);
+    *next = '/';
+    next++;
+    }
+makeDir(pathBuf);
+}
+
+char *skipNumeric(char *s)
+/* Return first char of s that's not a digit */
+{
+while (isdigit(*s))
+   ++s;
+return s;
+}
+
+char *skipToNumeric(char *s)
+/* skip up to where numeric digits appear */
+{
+while (*s != 0 && !isdigit(*s))
+    ++s;
+return s;
+}
+
+char *splitOffNonNumeric(char *s)
+/* Split off non-numeric part, e.g. mm of mm8. Result should be freed when done */
+{
+return cloneStringZ(s,skipToNumeric(s)-s);
+}
+
+char *splitOffNumber(char *db)
+/* Split off number part, e.g. 8 of mm8. Result should be freed when done */
+{
+return cloneString(skipToNumeric(db));
+}
+
+time_t mktimeFromUtc (struct tm *t)
+/* Return time_t for tm in UTC (GMT)
+ * Useful for stuff like converting to time_t the
+ * last-modified HTTP response header
+ * which is always GMT. Returns -1 on failure of mktime */
+{
+    time_t time;
+    char *tz;
+    char save_tz[100];
+    tz=getenv("TZ");
+    if (tz)
+        safecpy(save_tz, sizeof(save_tz), tz);
+    setenv("TZ", "GMT0", 1);
+    tzset();
+    t->tm_isdst = 0;
+    time=mktime(t);
+    if (tz)
+        setenv("TZ", save_tz, 1);
+    else
+        unsetenv("TZ");
+    tzset();
+    return (time);
+}
+
+
+time_t dateToSeconds(const char *date,const char*format)
+// Convert a string date to time_t
+{
+struct tm storage={0,0,0,0,0,0,0,0,0};
+if (strptime(date,format,&storage)==NULL)
+    return 0;
+else
+    return mktime(&storage);
+}
+
+boolean dateIsOld(const char *date,const char*format)
+// Is this string date older than now?
+{
+time_t test = dateToSeconds(date,format);
+time_t now = clock1();
+return (test < now);
+}
+
+static int daysOfMonth(struct tm *tp)
+/* Returns the days of the month given the year */
+{
+int days=0;
+switch(tp->tm_mon)
+    {
+    case 3:
+    case 5:
+    case 8:
+    case 10:    days = 30;
+                break;
+    case 1:     days = 28;
+                if ( (tp->tm_year % 4) == 0
+                &&  ((tp->tm_year % 20) != 0 || (tp->tm_year % 100) == 0) )
+                    days = 29;
+                break;
+    default:    days = 31;
+                break;
+    }
+return days;
+}
+
+static void dateAdd(struct tm *tp,int addYears,int addMonths,int addDays)
+/* Add years,months,days to a date */
+{
+tp->tm_mday  += addDays;
+tp->tm_mon   += addMonths;
+tp->tm_year  += addYears;
+int dom=28;
+while ( (tp->tm_mon >11  || tp->tm_mon <0)
+    || (tp->tm_mday>dom || tp->tm_mday<1) )
+    {
+    if (tp->tm_mon>11)   // First month: tm.tm_mon is 0-11 range
+        {
+        tp->tm_year += (tp->tm_mon / 12);
+        tp->tm_mon  = (tp->tm_mon % 12);
+        }
+    else if (tp->tm_mon<0)
+        {
+        tp->tm_year += (tp->tm_mon / 12) - 1;
+        tp->tm_mon  =  (tp->tm_mon % 12) + 12;
+        }
+    else
+        {
+        dom = daysOfMonth(tp);
+        if (tp->tm_mday>dom)
+            {
+            tp->tm_mday -= dom;
+            tp->tm_mon  += 1;
+            dom = daysOfMonth(tp);
+            }
+        else if (tp->tm_mday < 1)
+            {
+            tp->tm_mon  -= 1;
+            dom = daysOfMonth(tp);
+            tp->tm_mday += dom;
+            }
+        }
+    }
+}
+
+char *dateAddTo(char *date,char *format,int addYears,int addMonths,int addDays)
+/* Add years,months,days to a formatted date and returns the new date as a cloned string
+*  format is a strptime/strftime format: %F = yyyy-mm-dd */
+{
+char *newDate = needMem(12);
+struct tm tp;
+if (strptime(date,format, &tp))
+    {
+    dateAdd(&tp,addYears,addMonths,addDays); // tp.tm_year only contains years since 1900
+    strftime(newDate,12,format,&tp);
+    }
+return cloneString(newDate);  // newDate is never freed!
+}
+
diff --git a/lib/common.ps b/lib/common.ps
new file mode 100644
index 0000000..b4a65c6
--- /dev/null
+++ b/lib/common.ps
@@ -0,0 +1,97 @@
+%% Common postScript header.
+
+/boxHere {
+% Draw a box at current position.
+% Usage width height boxAt
+dup 0 exch   %stack width height 0 height
+rlineto      %stack width height
+exch dup 0   %stack height width width 0
+rlineto      %stack height width
+exch         %stack width height
+0 exch       %stack width 0 height
+neg          %stack width 0 -height
+rlineto      %stack width
+neg 0        %stack -width 0
+rlineto
+} def
+
+/boxAt {
+% Draw a box at a position.  Usage:
+% width height x y boxAt
+moveto
+boxHere
+} def
+
+/fillBox {
+% Draw filled box at a position. Usage:
+% width height x y fillBox
+newpath
+boxAt
+fill
+} def
+
+/strokeBox {
+% Draw stroked box at a position. Usage:
+% width height x y strokeBox
+newpath
+boxAt
+stroke
+} def
+
+/smallFont {
+/Times-Roman findfont
+10 scalefont
+setfont
+} def
+
+/showBefore {
+% Draw text immediately before rather
+% than immediately after current position.
+% Usage (some text) showBefore
+dup
+stringwidth
+neg
+exch
+neg
+exch
+rmoveto
+show
+} def
+
+/showMiddle {
+% Draw text centered at current position.
+% Usage (some text) showMiddle
+dup stringwidth
+2 div neg
+exch
+2 div neg
+exch
+rmoveto
+show
+} def
+
+/ellipse {
+/endangle exch def
+/startangle exch def
+/yrad exch def
+/xrad exch def
+/y exch def
+/x exch def
+/savematrix matrix currentmatrix def
+x y translate
+xrad yrad scale
+0 0 1 startangle endangle arc
+savematrix setmatrix
+} def
+
+/fillTextBox {
+true charpath pathbbox
+/y2 exch def /x2 exch def
+/y1 exch def /x1 exch def
+/w x2 x1 sub def
+/h y2 y1 sub def
+w h x1 y1 fillBox
+} def
+
+smallFont
+
diff --git a/lib/common.pss b/lib/common.pss
new file mode 100644
index 0000000..955f63a
--- /dev/null
+++ b/lib/common.pss
@@ -0,0 +1,96 @@
+"%% Common postScript header.\n"
+"\n"
+"/boxHere {\n"
+"% Draw a box at current position.\n"
+"% Usage width height boxAt\n"
+"dup 0 exch   %stack width height 0 height\n"
+"rlineto      %stack width height\n"
+"exch dup 0   %stack height width width 0\n"
+"rlineto      %stack height width\n"
+"exch         %stack width height\n"
+"0 exch       %stack width 0 height\n"
+"neg          %stack width 0 -height\n"
+"rlineto      %stack width\n"
+"neg 0        %stack -width 0\n"
+"rlineto\n"
+"} def\n"
+"\n"
+"/boxAt {\n"
+"% Draw a box at a position.  Usage:\n"
+"% width height x y boxAt\n"
+"moveto\n"
+"boxHere\n"
+"} def\n"
+"\n"
+"/fillBox {\n"
+"% Draw filled box at a position. Usage:\n"
+"% width height x y fillBox\n"
+"newpath\n"
+"boxAt\n"
+"fill\n"
+"} def\n"
+"\n"
+"/strokeBox {\n"
+"% Draw stroked box at a position. Usage:\n"
+"% width height x y strokeBox\n"
+"newpath\n"
+"boxAt\n"
+"stroke\n"
+"} def\n"
+"\n"
+"/smallFont {\n"
+"/Times-Roman findfont\n"
+"10 scalefont\n"
+"setfont\n"
+"} def\n"
+"\n"
+"/showBefore {\n"
+"% Draw text immediately before rather\n"
+"% than immediately after current position.\n"
+"% Usage (some text) showBefore\n"
+"dup\n"
+"stringwidth\n"
+"neg\n"
+"exch\n"
+"neg\n"
+"exch\n"
+"rmoveto\n"
+"show\n"
+"} def\n"
+"\n"
+"/showMiddle {\n"
+"% Draw text centered at current position.\n"
+"% Usage (some text) showMiddle\n"
+"dup stringwidth\n"
+"2 div neg\n"
+"exch\n"
+"2 div neg\n"
+"exch\n"
+"rmoveto\n"
+"show\n"
+"} def\n"
+"\n"
+"/ellipse {\n"
+"/endangle exch def\n"
+"/startangle exch def\n"
+"/yrad exch def\n"
+"/xrad exch def\n"
+"/y exch def\n"
+"/x exch def\n"
+"/savematrix matrix currentmatrix def\n"
+"x y translate\n"
+"xrad yrad scale\n"
+"0 0 1 startangle endangle arc\n"
+"savematrix setmatrix\n"
+"} def\n"
+"/fillTextBox {\n"
+"true charpath pathbbox\n"
+"/y2 exch def /x2 exch def\n"
+"/y1 exch def /x1 exch def\n"
+"/w x2 x1 sub def\n"
+"/h y2 y1 sub def\n"
+"w h x1 y1 fillBox\n"
+"} def\n"
+"\n"
+"smallFont\n"
+"\n"
diff --git a/lib/correlate.c b/lib/correlate.c
new file mode 100644
index 0000000..246d5c3
--- /dev/null
+++ b/lib/correlate.c
@@ -0,0 +1,77 @@
+/* correlate - calculate r, also known as Pearson's correlation
+ * coefficient.  r*r has the nice property that it explains
+ * how much of one variable's variation can be explained as
+ * a linear function of the other variable's variation.  Beware
+ * the weight of extreme outliers though! */
+
+#include "common.h"
+#include "correlate.h"
+
+
+struct correlate *correlateNew()
+/* Return new correlation handler. */
+{
+struct correlate *c;
+return AllocVar(c);
+}
+
+void correlateFree(struct correlate **pC)
+/* Free up correlator. */
+{
+freez(pC);
+}
+
+void correlateNext(struct correlate *c, double x, double y)
+/* Add next sample to correlation. */
+{
+c->sumX += x;
+c->sumXX += x*x;
+c->sumXY += x*y;
+c->sumY += y;
+c->sumYY += y*y;
+c->n += 1; 
+}
+
+void correlateNextMulti(struct correlate *c, double x, double y, int count)
+/* Do same thing as calling correlateNext with x and y count times. */
+{
+double ct = count;	/* Do type conversion once. */
+double cx = ct*x;
+double cy = ct*y;
+c->sumX += cx;
+c->sumXX += cx*x;
+c->sumXY += cx*y;
+c->sumY += cy;
+c->sumYY += cy*y;
+c->n += count;
+}
+
+double correlateResult(struct correlate *c)
+/* Returns correlation (aka R) */
+{
+double r = 0;
+if (c->n > 0)
+    {
+    double sp = c->sumXY - c->sumX*c->sumY/c->n;
+    double ssx = c->sumXX - c->sumX*c->sumX/c->n;
+    double ssy = c->sumYY - c->sumY*c->sumY/c->n;
+    double q = ssx*ssy;
+    if (q != 0)
+        r = sp/sqrt(q);
+    }
+return r;
+}
+
+double correlateArrays(double *x, double *y, int size)
+/* Return correlation of two arrays of doubles. */
+{
+struct correlate *c = correlateNew();
+double r;
+int i;
+for (i=0; i<size; ++i)
+     correlateNext(c, x[i], y[i]);
+r = correlateResult(c);
+correlateFree(&c);
+return r;
+}
+
diff --git a/lib/crTree.c b/lib/crTree.c
new file mode 100644
index 0000000..54e82a7
--- /dev/null
+++ b/lib/crTree.c
@@ -0,0 +1,398 @@
+/* crTree chromosome r tree. This module creates and uses a disk-based index that can find items
+ * that overlap with a chromosome range - something of the form chrN:start-end - with a
+ * minimum of disk access.  It is implemented with a combination of bPlusTrees and r-trees. 
+ * The items being indexed can overlap with each other.  
+ * 
+ * There's two main sides to using this module - creating an index, and using it.
+ *
+ * The first step of index creation is actually to insure that the file being indexed
+ * is ordered by chromosome,start,end.  For a .bed file you can insure this
+ * with the command:
+ *     sort -k1,1 -k2,2n -k3,3n unsorted.bed > sorted.bed
+ * Note that the the chromosome field is sorted alphabetically and the start and end
+ * fields are sorted numerically.
+ *
+ * Once this is done then the index creation program scans the input file, and
+ * makes a list of crTreeItems, one for each item in the file, and passed this
+ * to the function crTreeFileCreate. A crTreeItem just contains the chromosome
+ * range and file offset for an item.
+ *
+ * Using an index is done in two steps.  First you open the index with crTreeFileOpen,
+ * and then you use crTreeFindOverlappingBlocks to find parts of the file the overlap
+ * with your query range.  The result of a crTreeFindOverlappingBlocks call is a list
+ * of regions in the file.  These regions typically include some non-overlapping items
+ * as well.  It is up to the caller to parse through the resulting region list to
+ * convert it from just bytes on disk into the memory data structure.  During this
+ * parsing you should ignore items that don't overlap your range of interest.
+ *
+ * The programs crTreeIndexBed and crTreeSearchBed create and search a crTree index
+ * for a bed file, and are useful examples to view for other programs that want to
+ * use the crTree system. */
+
+
+#include "common.h"
+#include "hash.h"
+#include "udc.h"
+#include "sig.h"
+#include "bPlusTree.h"
+#include "cirTree.h"
+#include "crTree.h"
+
+#define chromOffsetPos 8	// Where in file chromosome b-tree lives
+#define cirOffsetPos 16		// Where in file interval r-tree lives
+#define crHeaderSize 64		// Size of file header 
+
+struct name32
+/* Pair of a name and a 32-bit integer. Used to assign IDs to chromosomes. */
+    {
+    struct name32 *next;
+    char *name;
+    bits32 val;
+    };
+
+static int name32Cmp(const void *va, const void *vb)
+/* Compare to sort on name. */
+{
+const struct name32 *a = ((struct name32 *)va);
+const struct name32 *b = ((struct name32 *)vb);
+return strcmp(a->name, b->name);
+}
+
+static void name32Key(const void *va, char *keyBuf)
+/* Get key field. */
+{
+const struct name32 *a = ((struct name32 *)va);
+strcpy(keyBuf, a->name);
+}
+
+static void *name32Val(const void *va)
+/* Get key field. */
+{
+const struct name32 *a = ((struct name32 *)va);
+return (void*)(&a->val);
+}
+
+struct crTreeRange
+/* A chromosome id and an interval inside it. */
+    {
+    char *chrom;	/* Chromosome id. String memory owned in hash. */
+    bits32 start;	/* Start position in chromosome. */
+    bits32 end;		/* One past last base in interval in chromosome. */
+    };
+
+struct ciContext 
+/* A structure that carries around context for the fetchKey and fetchOffset callbacks. */
+    {
+    struct crTreeRange (*fetchKey)(const void *va);   /* Given item, return key. */
+    bits64 (*fetchOffset)(const void *va); 		 /* Given item, return file offset */
+    };
+
+struct ciItem
+/* Small wrapper around crItem. Contains the key values precomputed, and the chromosome index
+ * for each key. */
+     {
+     void *item;			/* Underlying cr item. */
+     struct crTreeRange key;		/* The key for this item. */
+     bits32 chromIx;			/* Associated chromosome index. */
+     };
+
+static struct cirTreeRange ciItemFetchKey(const void *va, void *context)
+/* Given item, return key. */
+{
+const struct ciItem *a = ((struct ciItem *)va);
+struct cirTreeRange ret;
+ret.chromIx = a->chromIx;
+ret.start = a->key.start;
+ret.end = a->key.end;
+return ret;
+}
+
+static bits64 ciItemFetchOffset(const void *va, void *context)
+/* Given item, return file offset */
+{
+const struct ciItem *a = ((struct ciItem *)va);
+const struct ciContext *c = context;
+return (c->fetchOffset)(a->item);
+}
+
+static bits32 mustFindChromIx(char *chrom, struct name32 *array, bits32 chromCount)
+/* Do a binary search on array to find the index associated with chrom.  Print
+ * error message and abort if not found. */
+{
+struct name32 key;
+key.name = chrom;
+struct name32 *el = bsearch(&key, array, chromCount, sizeof(array[0]), name32Cmp);
+if (el == NULL)
+    errAbort("%s not found in mustFindChromIx\n", chrom);
+return el->val;
+}
+
+static void crTreeFileCreateLow(
+	char **chromNames,	/* All chromosome (or contig) names */
+	int chromCount,		/* Number of chromosomes. */
+	void *itemArray, 	/* Sorted array of things to index. */
+	int itemSize, 		/* Size of each element in array. */
+	bits64 itemCount, 	/* Number of elements in array. */
+	bits32 blockSize,	/* R tree block size - # of children for each node. */
+	bits32 itemsPerSlot,	/* Number of items to put in each index slot at lowest level. */
+	struct crTreeRange (*fetchKey)(const void *va),   /* Given item, return key. */
+	bits64 (*fetchOffset)(const void *va), 		 /* Given item, return file offset */
+	bits64 initialDataOffset,			 /* Offset of 1st piece of data in file. */
+	bits64 totalDataSize,				 /* Total size of data we are indexing. */
+	char *fileName)                                 /* Name of output file. */
+/* Create a r tree index file from an array of chromosomes and an array of items with
+ * basic bed (chromosome,start,end) and file offset information. */
+{
+// uglyf("crTreeFileCreate %s itemCount=%llu, chromCount=%d\n", fileName, itemCount, chromCount);
+/* Open file and write header. */
+FILE *f = mustOpen(fileName, "wb");
+bits32 magic = crTreeSig;
+bits32 reserved32 = 0;
+bits64 chromOffset = crHeaderSize;
+bits64 cirOffset = 0;
+bits64 reserved64 = 0;
+writeOne(f, magic);
+writeOne(f, reserved32);
+writeOne(f, chromOffset);
+writeOne(f, cirOffset);	       /* Will fill this back in later */
+writeOne(f, reserved64);
+writeOne(f, reserved64);
+writeOne(f, reserved64);
+writeOne(f, reserved64);
+writeOne(f, reserved64);
+
+/* Convert array of chromosomes to a sorted array of name32s.  Also
+ * figure out maximum chromosome name size. */
+struct name32 *name32Array;
+AllocArray(name32Array, chromCount);
+bits32 chromIx;
+int maxChromNameSize = 0;
+for (chromIx=0; chromIx<chromCount; ++chromIx)
+    {
+    struct name32 *name32 = &name32Array[chromIx];
+    char *name = chromNames[chromIx];
+    name32->name = name;
+    int nameSize = strlen(name);
+    if (nameSize > maxChromNameSize)
+        maxChromNameSize = nameSize;
+    }
+qsort(name32Array, chromCount, sizeof(name32Array[0]), name32Cmp);
+for (chromIx=0; chromIx<chromCount; ++chromIx)
+    {
+    struct name32 *name32 = &name32Array[chromIx];
+    name32->val = chromIx;
+    }
+
+/* Write out bPlusTree index of chromosome IDs. */
+int chromBlockSize = min(blockSize, chromCount);
+bptFileBulkIndexToOpenFile(name32Array, sizeof(name32Array[0]), chromCount, chromBlockSize,
+    name32Key, maxChromNameSize, name32Val, sizeof(name32Array[0].val), f);
+	
+/* Convert itemArray to ciItemArray.  This is mainly to avoid having to do the chromosome to
+ * chromosome index conversion for each item.  The cost is some memory though.... */
+struct ciItem *ciItemArray;
+AllocArray(ciItemArray, itemCount);
+bits64 itemIx;
+char *itemPos = itemArray;
+char *lastChrom = "";
+bits32 lastChromIx = 0;
+for (itemIx=0; itemIx < itemCount; ++itemIx)
+    {
+    struct ciItem *ciItem = &ciItemArray[itemIx];
+    ciItem->item = itemPos;
+    ciItem->key = (*fetchKey)(itemPos);
+    if (!sameString(lastChrom, ciItem->key.chrom))
+        {
+	lastChrom = ciItem->key.chrom;
+	lastChromIx = mustFindChromIx(lastChrom, name32Array, chromCount);
+	}
+    ciItem->chromIx = lastChromIx;
+    itemPos += itemSize;
+    }
+
+/* Record starting position of r tree and write it out. */
+cirOffset = ftell(f);
+struct ciContext context;
+ZeroVar(&context);
+context.fetchKey = fetchKey;
+context.fetchOffset = fetchOffset;
+cirTreeFileBulkIndexToOpenFile(ciItemArray, sizeof(ciItemArray[0]), itemCount, blockSize, 
+	itemsPerSlot, &context, ciItemFetchKey, ciItemFetchOffset, totalDataSize, f);
+
+/* Seek back and write offset to r tree. */
+fseek(f, cirOffsetPos, SEEK_SET);
+writeOne(f, cirOffset);
+
+
+/* Clean up */
+freez(&name32Array);
+carefulClose(&f);
+}
+
+int crTreeItemCmp(const void *va, const void *vb)
+/* Compare to sort based on chrom,start,end. */
+{
+const struct crTreeItem *a = ((struct crTreeItem *)va);
+const struct crTreeItem *b = ((struct crTreeItem *)vb);
+int dif;
+dif = strcmp(a->chrom, b->chrom);
+if (dif == 0)
+    dif = a->start - b->start;
+if (dif == 0)
+    dif = a->end - b->end;
+return dif;
+}
+
+struct crTreeRange crTreeItemKey(const void *va)
+/* Get key fields. */
+{
+const struct crTreeItem *a = *((struct crTreeItem **)va);
+struct crTreeRange ret;
+ret.chrom = a->chrom;
+ret.start = a->start;
+ret.end = a->end;
+return ret;
+}
+
+bits64 crTreeItemOffset(const void *va)
+/* Get offset of item in file. */
+{
+const struct crTreeItem *a = *((struct crTreeItem **)va);
+return a->fileOffset;
+}
+
+void crTreeFileCreateInputCheck(struct crTreeItem *itemList, struct hash *chromHash, 
+	bits32 blockSize, bits32 itemsPerSlot, bits64 endPosition, char *fileName)
+/* Do sanity checking on itemList and chromHash and endPosition.  Make sure that itemList is
+ * sorted properly mostly. */
+{
+struct crTreeItem *item, *next;
+for (item = itemList; item != NULL; item = next)
+    {
+    next = item->next;
+    if (next != NULL)
+	{
+        if (crTreeItemCmp(item, next) > 0)
+	    errAbort("Out of order itemList in crTreeFileCreateInputCheck");
+	if (item->fileOffset > next->fileOffset)
+	    errAbort("Out of sequence itemList in crTreeFileCreateInputCheck");
+	}
+    }
+}
+
+
+void crTreeFileCreate(
+	struct crTreeItem *itemList,  /* List of all items - sorted here and in underlying file. */
+	struct hash *chromHash,	      /* Hash of all chromosome names. */
+	bits32 blockSize,	/* R tree block size - # of children for each node. 1024 is good. */
+	bits32 itemsPerSlot,	/* Number of items to put in each index slot at lowest level.
+				 * Typically either blockSize/2 or 1. */
+	bits64 endPosition,	/* File offset after have read all items in file. */
+	char *fileName)        /* Name of output file. */
+/* Create a cr tree index of file. The itemList contains the position of each item in the
+ * chromosome and in the file being indexed.  Both the file and the itemList must be sorted
+ * by chromosome (alphabetic), start (numerical), end (numerical). 
+ *    We recommend you run crTreeFileCreateInputCheck on the input parameters right before
+ * calling this if you have problems. */
+{
+/* We can't handle empty input... */
+if (itemList == NULL)
+    errAbort("crTreeFileCreate can't handle empty itemList.");
+
+/* Make array of pointers out of linked list. */
+struct crTreeItem **itemArray;
+bits32 itemCount = slCount(itemList);
+AllocArray(itemArray, itemCount);
+struct crTreeItem *item;
+int itemIx;
+for (itemIx=0, item=itemList; itemIx<itemCount; ++itemIx, item=item->next)
+    itemArray[itemIx] = item;
+
+/* Make up chromosome array. */
+int chromCount = chromHash->elCount;
+char **chromArray;
+AllocArray(chromArray, chromCount);
+struct hashEl *el, *list = hashElListHash(chromHash);
+bits32 chromIx;
+for (el = list, chromIx=0; el != NULL; el = el->next, ++chromIx)
+    chromArray[chromIx] = el->name;
+slFreeList(&list);
+
+/* Call function to make index file. */
+crTreeFileCreateLow(chromArray, chromCount, itemArray, sizeof(itemArray[0]), itemCount,
+	blockSize, itemsPerSlot, crTreeItemKey, crTreeItemOffset, itemList->fileOffset, 
+	endPosition, fileName);
+}
+
+/****** Start of reading and searching (as opposed to file creation) code *******/
+
+struct crTreeFile *crTreeFileOpen(char *fileName)
+/* Open up r-tree index file - reading headers and verifying things. */
+{
+/* Open file and allocate structure to hold info from header etc. */
+struct udcFile *udc = udcFileOpen(fileName, udcDefaultDir());
+struct crTreeFile *crt = needMem(sizeof(*crt));
+fileName = crt->fileName = cloneString(fileName);
+crt->udc = udc;
+
+/* Read magic number at head of file and use it to see if we are proper file type, and
+ * see if we are byte-swapped. */
+bits32 magic;
+boolean isSwapped = FALSE;
+udcMustReadOne(udc, magic);
+if (magic != crTreeSig)
+    {
+    magic = byteSwap32(magic);
+    isSwapped = crt->isSwapped = TRUE;
+    if (magic != crTreeSig)
+       errAbort("%s is not a chromosome r-tree index file", fileName);
+    }
+
+/* Read rest of high level header including notably the offsets to the
+ * chromosome and range indexes. */
+bits32 reserved32;
+udcMustReadOne(udc, reserved32);
+crt->chromOffset = udcReadBits64(udc, isSwapped);
+crt->cirOffset = udcReadBits64(udc, isSwapped);
+
+/* Read in the chromosome index header. */
+udcSeek(udc, crt->chromOffset);
+crt->chromBpt = bptFileAttach(fileName, udc);
+
+/* Read in range index header. */
+udcSeek(udc, crt->cirOffset);
+crt->cir = cirTreeFileAttach(fileName, udc);
+
+return crt;
+}
+
+void crTreeFileClose(struct crTreeFile **pCrt)
+/* Close and free up crTree file opened with crTreeFileAttach. */
+{
+struct crTreeFile *crt = *pCrt;
+if (crt != NULL)
+    {
+    cirTreeFileDetach(&crt->cir);
+    bptFileDetach(&crt->chromBpt);
+    udcFileClose(&crt->udc);
+    freez(&crt->fileName);
+    freez(pCrt);
+    }
+}
+
+
+struct fileOffsetSize *crTreeFindOverlappingBlocks(struct crTreeFile *crt, 
+	char *chrom, bits32 start, bits32 end)
+/* Return list of file blocks that between them contain all items that overlap
+ * start/end on chromIx.  Also there will be likely some non-overlapping items
+ * in these blocks too. When done, use slListFree to dispose of the result. */
+{
+/* Find chromosome index.  Return NULL if no such chromosome*/
+bits32 chromIx;
+if (!bptFileFind(crt->chromBpt, chrom, strlen(chrom), &chromIx, sizeof(chromIx)))
+    return NULL;
+
+return cirTreeFindOverlappingBlocks(crt->cir, chromIx, start, end);
+}
+
+
diff --git a/lib/dgRange.c b/lib/dgRange.c
new file mode 100644
index 0000000..0c4c6e7
--- /dev/null
+++ b/lib/dgRange.c
@@ -0,0 +1,219 @@
+/* dgRange - stuff to tell if a graph which has a range
+ * of values associated with each edge is internally consistent.  
+ * See comment under bfGraphFromRangeGraph for details. */
+
+#include "common.h"
+#include "diGraph.h"
+
+
+struct bfEdge
+/* An edge in a (lightweight) Belman Ford graph. */
+   {
+   struct bfEdge *next;    /* Pointer to next element. */
+   int distance;           /* Distance - may be negative. */
+   struct bfVertex *in;    /* Connecting node. */
+   struct bfVertex *out;   /* Connecting node. */
+   };
+
+struct bfVertex
+/* A node in a (lightweight) Belman Ford graph. */
+   {
+   int position;               /* Currently assigned position. */
+   struct bfEdge *waysOut;     /* Ways out. */
+   };
+
+struct bfGraph
+/* A lightweight, but fixed sized graph for Belman Ford algorithm. */
+    {
+    int vertexCount;	         /* Number of vertices */
+    struct bfVertex *vertices;   /* Array of vertices. */
+    int edgeCount;               /* Number of edges. */
+    struct bfEdge *edges;        /* Array of edges. */
+    };
+
+struct bfRange 
+/* Min and max distances allowed for an edge. */
+   {
+   int minDist, maxDist;
+   };
+
+static void bfGraphFree(struct bfGraph **pGraph)
+/* Free up Belman-Ford graph. */
+{
+struct bfGraph *graph = *pGraph;
+if (graph != NULL)
+    {
+    freeMem(graph->vertices);
+    freeMem(graph->edges);
+    freez(pGraph);
+    }
+}
+
+static struct bfGraph *bfGraphFromRangeGraph(struct diGraph *rangeGraph, 
+   boolean (*findEdgeRange)(struct dgEdge *edge, int *retMin, int *retMax),
+   struct dgNode *a, struct dgNode *b, int abMin, int abMax)
+/* Construct a directed graph with two edges for each
+ * edge of the range graph.  Where the range graph
+ * has the following info:
+ *     sourceNode destNode minDistance maxDistance
+ *    -------------------------------------------
+ *         A         B         2          5
+ * The bfGraph would have:
+ *     sourceNode destNode   edgeVal  meaning
+ *    --------------------------------------------
+ *         A         B         5     D(A) - D(B) <= 5 
+ *         B         A        -2     D(B) - D(A) <= -2
+ * Furthermore the bfGraph introduces a new node,
+ * "zero", which has a zero-valued connection to
+ * all other nodes.
+ *
+ * This graph can then be processed via the Bellman-
+ * Ford algorithm (see p. 532 of Cormen,Leiserson and
+ * Rivest's Introduction to Algorithms, MIT Press 1990)
+ * to see if the bfGraph, and by extension the range
+ * graph, is consistent.
+ */
+{
+struct bfGraph *bfGraph;
+struct bfVertex *vertices, *freeVertex, *newSource, *newDest, *zeroVertex;
+struct bfEdge *edges, *newEdge, *freeEdge;
+struct dgNode *oldSource, *oldDest, *oldNode;
+int oldEdgeCount = dlCount(rangeGraph->edgeList);
+int oldVertexCount = 0;
+
+/* Coopt topoOrder field to store unique ID for each
+ * node, starting at 1.  (We'll reserve 0 for the
+ * node we insert - the Belman Ford "zero" node.)*/
+for (oldNode = rangeGraph->nodeList; oldNode != NULL; oldNode = oldNode->next)
+    oldNode->topoOrder = ++oldVertexCount;
+
+/* Allocate space for new graph. */
+AllocVar(bfGraph);
+bfGraph->vertexCount = oldVertexCount + 1;
+bfGraph->vertices = freeVertex = AllocArray(vertices, bfGraph->vertexCount);
+bfGraph->edgeCount = 2*oldEdgeCount + oldVertexCount;
+if (a != NULL)
+  bfGraph->edgeCount += 2;
+bfGraph->edges = freeEdge = AllocArray(edges, bfGraph->edgeCount);
+
+/* Get zero vertex. */
+zeroVertex = freeVertex++;
+
+/* Scan through old graph and add vertices to new graph. */
+for (oldSource = rangeGraph->nodeList; oldSource != NULL; 
+    oldSource = oldSource->next)
+    {
+    struct dgConnection *dgConn;
+    int rangeMin, rangeMax;
+
+    /* Allocate new source vertex. */
+    newSource = freeVertex++;
+
+    /* Make connection from zero vertex to this one. */
+    newEdge = freeEdge++;
+    newEdge->distance = 0;
+    newEdge->in = zeroVertex;
+    newEdge->out = newSource;
+    slAddHead(&zeroVertex->waysOut, newEdge);
+
+    /* Loop through all ways out of source. */
+    for (dgConn = oldSource->nextList; dgConn != NULL; dgConn = dgConn->next)
+        {
+	/* Find destination vertex and size range of edge. */
+	if ((*findEdgeRange)(dgConn->edgeOnList->val, &rangeMin, &rangeMax))
+	    {
+	    oldDest = dgConn->node;
+	    newDest = &vertices[oldDest->topoOrder];
+
+	    /* Make two new edges corresponding to old edge. */
+	    newEdge = freeEdge++;
+	    newEdge->distance = rangeMax;
+	    newEdge->in = newSource;
+	    newEdge->out = newDest;
+	    slAddHead(&newSource->waysOut, newEdge);
+	    newEdge = freeEdge++;
+	    newEdge->distance = -rangeMin;
+	    newEdge->in = newDest;
+	    newEdge->out = newSource;
+	    slAddHead(&newDest->waysOut, newEdge);
+	    }
+	}
+    }
+/* Add additional pair of edges for extra range if applicable. */
+if (a != NULL)
+    {
+    newSource = &vertices[a->topoOrder];
+    newDest = &vertices[b->topoOrder];
+    newEdge = freeEdge++;
+    newEdge->distance = abMax;
+    newEdge->in = newSource;
+    newEdge->out = newDest;
+    slAddHead(&newSource->waysOut, newEdge);
+    newEdge = freeEdge++;
+    newEdge->distance = -abMin;
+    newEdge->in = newDest;
+    newEdge->out = newSource;
+    slAddHead(&newDest->waysOut, newEdge);
+    }
+bfGraph->edgeCount = freeEdge - bfGraph->edges;
+return bfGraph;
+}
+
+static boolean bfCheckGraph(struct bfGraph *graph)
+/* Run Belman-Ford algorithm to check graph for consistency. */
+{
+struct bfVertex *vertices = graph->vertices, *in, *out;
+int vertexCount = graph->vertexCount;
+int edgeCount = graph->edgeCount;
+struct bfEdge *edges = graph->edges, *edge;
+int i, edgeIx;
+int maxIterations = vertexCount - 1;
+boolean anyChange = FALSE;
+int newPos;
+
+for (i=0; i<vertexCount; ++i)
+    vertices[i].position = 0x3fffffff;    /* Mighty big number. */
+for (i=0; i<maxIterations; ++i)
+    {
+    anyChange = FALSE;
+    for (edgeIx = 0, edge = edges; edgeIx < edgeCount; ++edgeIx, ++edge)
+        {
+	in = edge->in;
+	out = edge->out;
+	newPos = in->position + edge->distance;
+	if (newPos < out->position)
+	    {
+	    out->position = newPos;
+	    anyChange = TRUE;
+	    }
+	}
+    if (!anyChange)
+        break;
+    }
+return !anyChange;
+}
+
+boolean dgAddedRangeConsistent(struct diGraph *rangeGraph,
+   struct dgNode *a, struct dgNode *b, int abMin, int abMax,
+   boolean (*findEdgeRange)(struct dgEdge *edge, int *retMin, int *retMax) )
+/* Return TRUE if graph with a range of allowable distances associated
+ * with each edge would be internally consistent if add edge from a to b
+ * with given min/max values. */
+{
+struct bfGraph *bfGraph;
+boolean ok; 
+
+bfGraph = bfGraphFromRangeGraph(rangeGraph, findEdgeRange, a, b, abMin, abMax);
+ok = bfCheckGraph(bfGraph);
+bfGraphFree(&bfGraph);
+return ok;
+}
+
+boolean dgRangesConsistent(struct diGraph *rangeGraph,
+   boolean (*findEdgeRange)(struct dgEdge *edge, int *retMin, int *retMax) )
+/* Return TRUE if graph with a range of allowable distances associated
+ * with each edge is internally consistent. */
+{
+return dgAddedRangeConsistent(rangeGraph, NULL, NULL, 0, 0, findEdgeRange);
+}
+
diff --git a/lib/diGraph.c b/lib/diGraph.c
new file mode 100644
index 0000000..4d80e9c
--- /dev/null
+++ b/lib/diGraph.c
@@ -0,0 +1,738 @@
+/* diGraph - Directed graph routines. */
+#include "common.h"
+#include "hash.h"
+#include "dlist.h"
+#include "diGraph.h"
+
+
+struct diGraph *dgNew()
+/* Return a new directed graph object. */
+{
+struct diGraph *dg;
+AllocVar(dg);
+dg->nodeHash = newHash(0);
+dg->edgeList = newDlList();
+return dg;
+}
+
+static void dgNodeFree(struct dgNode **pNode)
+/* Free a diGraph node. */
+{
+struct dgNode *node = *pNode;
+if (node == NULL)
+    return;
+slFreeList(&node->nextList);
+slFreeList(&node->prevList);
+freez(pNode);
+}
+
+static void dgNodeFreeList(struct dgNode **pList)
+/* Free list of diGraph nodes. */
+{
+struct dgNode *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    dgNodeFree(&el);
+    }
+*pList = NULL;
+}
+
+void dgFree(struct diGraph **pGraph)
+/* Free a directed graph. */
+{
+struct diGraph *dg = *pGraph;
+if (dg == NULL)
+    return;
+freeHash(&dg->nodeHash);
+dgNodeFreeList(&dg->nodeList);
+freeDlListAndVals(&dg->edgeList);
+freez(pGraph);
+}
+
+
+struct dgNode *dgAddNode(struct diGraph *dg, char *name, void *val)
+/* Create new node in graph. It's legal (but not efficient) to add
+ * a node with the same name and value twice.  It's not legal to
+ * add a node with the same name and a different value.  
+ * You can pass in NULL for the name in which case the 
+ * hexadecimal representation of val will become the name. */
+{
+struct dgNode *node;
+struct hashEl *hel;
+struct hash *hash = dg->nodeHash;
+char nbuf[17];
+
+if (name == NULL)
+    {
+    sprintf(nbuf, "%p", val);
+    name = nbuf;
+    }
+hel = hashLookup(hash, name);
+if (hel != NULL)
+    {
+    node = hel->val;
+    if (node->val != val)
+	{
+	errAbort("Trying to add node %s with a new value (old 0x%llx new 0x%llx)",
+	    name, ptrToLL(node->val), ptrToLL(val));
+	}
+    return node;
+    }
+AllocVar(node);
+hel = hashAdd(hash, name, node);
+node->name = hel->name;
+node->val = val;
+slAddHead(&dg->nodeList, node);
+return node;
+}
+
+struct dgNode *dgAddNumberedNode(struct diGraph *dg, int id, void *val)
+/* Create new node with a number instead of a name. */
+{
+char buf[16];
+sprintf(buf, "%d", id);
+return dgAddNode(dg, buf, val);
+}
+
+struct dgNode *dgFindNode(struct diGraph *dg, char *name)
+/* Find existing node in graph. Return NULL if not in graph. */
+{
+struct hashEl *hel;
+if ((hel = hashLookup(dg->nodeHash, name)) == NULL)
+    return NULL;
+return hel->val;
+}
+
+struct dgNode *dgFindNumberedNode(struct diGraph *dg, int id)
+/* Find node given number. */
+{
+char buf[16];
+sprintf(buf, "%d", id);
+return dgFindNode(dg, buf);
+}
+
+
+void *dgNodeVal(struct dgNode *node)
+/* Return value associated with node. */
+{
+return node->val;
+}
+
+void *dgNodeName(struct dgNode *node)
+/* Return name associated with node. */
+{
+return node->name;
+}
+
+int dgNodeNumber(struct dgNode *node)
+/* Return number of node.  (Will likely return 0 if node
+ * was added with a name rather than a number). */
+{
+return atoi(node->name);
+}
+
+struct dgNodeRef *dgFindNodeInRefList(struct dgNodeRef *refList, struct dgNode *node)
+/* Return reference to node if in list, or NULL if not. */
+{
+struct dgNodeRef *ref;
+for (ref = refList; ref != NULL; ref = ref->next)
+    if (ref->node == node)
+	return ref;
+return NULL;
+}
+
+struct dgConnection *dgFindNodeInConList(struct dgConnection *conList, struct dgNode *node)
+/* Return connection to node if in list, or NULL if not. */
+{
+struct dgConnection *con;
+for (con = conList; con != NULL; con = con->next)
+    if (con->node == node)
+	return con;
+return NULL;
+}
+
+
+struct dgEdge *dgConnect(struct diGraph *dg, struct dgNode *a, struct dgNode *b)
+/* Connect node a to node b.  Returns connecting edge. 
+ * Not an error to reconnect.  However all connects can 
+ * be broken with a single disconnect. */
+{
+return dgConnectWithVal(dg, a, b, NULL);
+}
+
+struct dgEdge *dgConnectWithVal(struct diGraph *dg, struct dgNode *a, 
+     struct dgNode *b, void *val)
+/* Connect node a to node b and put val on edge.  An error to
+ * reconnect with a different val. */
+{
+struct dgConnection *con;
+struct dgEdge *edge;
+struct dlNode *edgeOnList;
+
+/* Check to see if it's already there. */
+if ((con = dgFindNodeInConList(a->nextList, b)) != NULL)
+    {
+    edge =  con->edgeOnList->val;
+    if (val != edge->val)
+        warn("Trying to add new value to edge between %s and %s, ignoring",
+	   a->name, b->name);
+    return edge;
+    }
+/* Allocate edge and put on list. */
+AllocVar(edge);
+edge->a = a;
+edge->b = b;
+edge->val = val;
+edgeOnList = dlAddValTail(dg->edgeList, edge);
+
+/* Connect nodes to each other. */
+AllocVar(con);
+con->node = b;
+con->edgeOnList = edgeOnList;
+slAddHead(&a->nextList, con);
+AllocVar(con);
+con->node = a;
+con->edgeOnList = edgeOnList;
+slAddHead(&b->prevList, con);
+
+return edge;
+}
+
+static struct dlNode *dgRemoveFromConList(struct dgConnection **pConList, 
+	struct dgNode *node, struct dgConnection **retCon)
+/* Remove reference to node from list. */
+{
+struct dgConnection *newList = NULL;
+struct dgConnection *con, *next;
+struct dlNode *edgeOnList = NULL;
+
+for (con = *pConList; con != NULL; con = next)
+    {
+    next = con->next;
+    if (con->node == node)
+	{
+	edgeOnList = con->edgeOnList;
+	if (retCon != NULL)
+	    *retCon = con;
+	else
+	    freeMem(con);
+	}
+    else
+	{
+	slAddHead(&newList, con);
+	}
+    }
+slReverse(&newList);
+*pConList = newList;
+return edgeOnList;
+}
+
+void dgDisconnect(struct diGraph *dg, struct dgNode *a, struct dgNode *b)
+/* Disconnect nodes a and b. */
+{
+struct dlNode *edgeInList;
+struct dgEdge *edge;
+
+dgRemoveFromConList(&a->nextList, b, NULL);
+edgeInList = dgRemoveFromConList(&b->prevList, a, NULL);
+if (edgeInList != NULL)
+    {
+    edge = edgeInList->val;
+    dlRemove(edgeInList);
+    freeMem(edgeInList);
+    freeMem(edge);
+    }
+}
+
+
+void dgClearVisitFlags(struct diGraph *dg)
+/* Clear out visit flags. */
+{
+struct dgNode *node;
+for (node = dg->nodeList; node != NULL; node = node->next)
+    node->visited = FALSE;
+}
+
+void dgClearConnFlags(struct diGraph *dg)
+/* Clear out connect flags. */
+{
+struct dgNode *node;
+for (node = dg->nodeList; node != NULL; node = node->next)
+    node->conn = FALSE;
+}
+
+static struct dgNode *rTarget;
+
+static boolean rPathExists(struct dgNode *a)
+/* Recursively find if path from a to b exists. */
+{
+struct dgConnection *ref;
+if (a == rTarget)
+    return TRUE;
+a->visited = TRUE;
+
+for (ref = a->nextList; ref != NULL; ref = ref->next)
+    {
+    if (!ref->node->visited && rPathExists(ref->node))
+	return TRUE;
+    }
+return FALSE;
+}
+
+boolean dgPathExists(struct diGraph *dg, struct dgNode *a, struct dgNode *b)
+/* Return TRUE if there's a path from a to b. */
+{
+rTarget = b;
+dgClearVisitFlags(dg);
+return rPathExists(a);
+}
+
+static int topoIx;
+
+static void rTopoSort(struct dgNode *node)
+{
+struct dgConnection *ref;
+node->visited = TRUE;
+for (ref = node->nextList; ref != NULL; ref = ref->next)
+    {
+    if (!ref->node->visited)
+	rTopoSort(ref->node);
+    }
+node->topoOrder = ++topoIx;
+}
+
+void dgTopoSort(struct diGraph *dg)
+/* Fill in topological order of nodes. */
+{
+struct dgNode *node;
+
+topoIx = 0;
+dgClearVisitFlags(dg);
+for (node = dg->nodeList; node != NULL; node = node->next)
+    {
+    if (!node->visited)
+	rTopoSort(node);
+    }
+}
+
+static boolean  rHasCycles(struct dgNode *node)
+/* Recursively see if has cycles by looking for
+ * backwards topoOrder. */
+{
+struct dgConnection *ref;
+struct dgNode *child;
+
+node->visited = TRUE;
+for (ref = node->nextList; ref != NULL; ref = ref->next)
+    {
+    child = ref->node;
+    if (child->topoOrder > node->topoOrder)
+	return TRUE;
+    if (!child->visited)
+	if (rHasCycles(child))
+	    return TRUE;
+    }
+return FALSE;
+}
+
+boolean dgHasCycles(struct diGraph *dg)
+/* Return TRUE if directed graph has cycles. */
+{
+struct dgNode *node;
+
+dgTopoSort(dg);
+dgClearVisitFlags(dg);
+for (node = dg->nodeList; node != NULL; node = node->next)
+    {
+    if (!node->visited)
+	if (rHasCycles(node))
+	    return TRUE;
+    }
+return FALSE;
+}
+
+struct dgNodeRef *rRefList;
+bool rMustHaveVal;			/* Set to TRUE if rFindConnected only to
+                                         * consider nodes with values in connections. */
+
+static void rFindConnected(struct dgNode *a)
+/* Find all things connected to a directly or not that haven't
+ * already been visited and put them on rRefList. */
+{
+if (!a->conn && (!rMustHaveVal || a->val))
+    {
+    struct dgNodeRef *ref;
+    struct dgConnection *con;
+    AllocVar(ref);
+    ref->node = a;
+    slAddHead(&rRefList, ref);
+    a->conn = TRUE;
+    for (con = a->nextList; con != NULL; con = con->next)
+	rFindConnected(con->node);
+    for (con = a->prevList; con != NULL; con = con->next)
+	rFindConnected(con->node);
+    }
+}
+
+struct dgNodeRef *dgFindNextConnected(struct diGraph *dg)
+/* Return list of nodes that make up next connected component,
+ * or NULL if no more components.  slFreeList this when
+ * done.  Call "dgClearConnFlags" before first call to this.
+ * Do not call dgFindConnectedToNode between dgFindFirstConnected 
+ * and this as they use the same flag variables to keep track of
+ * what vertices are used. */
+{
+struct dgNode *a;
+
+for (a=dg->nodeList; a != NULL; a = a->next)
+    {
+    if (!a->conn)
+	break;
+    }
+if (a == NULL)
+    return NULL;
+rRefList = NULL;
+rMustHaveVal = FALSE;
+rFindConnected(a);
+return rRefList;
+}
+
+struct dgNodeRef *dgFindNextConnectedWithVals(struct diGraph *dg)
+/* Like dgFindConnected, but only considers graph nodes that
+ * have a val attached. */
+{
+struct dgNode *a;
+
+for (a=dg->nodeList; a != NULL; a = a->next)
+    {
+    if (!a->conn && a->val != NULL)
+	break;
+    }
+if (a == NULL)
+    return NULL;
+rRefList = NULL;
+rMustHaveVal = TRUE;
+rFindConnected(a);
+return rRefList;
+}
+
+
+static int connectedComponents(struct diGraph *dg)
+/* Count number of connected components and set component field
+ * of each node to reflect which component it is in. */
+{
+struct dgNodeRef *ref;
+int conCount = 0;
+struct dgNode *a = dg->nodeList;
+
+dgClearConnFlags(dg);
+for (;;)
+    {
+    for (; a != NULL; a = a->next)
+	{
+	if (!a->conn && (!rMustHaveVal || a->val))
+	    break;
+	}
+    if (a == NULL)
+	break;
+    rRefList = NULL;
+    rFindConnected(a);
+    ++conCount;
+    for (ref = rRefList; ref != NULL; ref = ref->next)
+	{
+	ref->node->component = conCount;
+	}
+    slFreeList(&rRefList);
+    }
+return conCount;
+}
+
+int dgConnectedComponents(struct diGraph *dg)
+/* Count number of connected components and set component field
+ * of each node to reflect which component it is in. */
+{
+rMustHaveVal = FALSE;
+return connectedComponents(dg);
+}
+
+int dgConnectedComponentsWithVals(struct diGraph *dg)
+/* Count number of connected components and set component field
+ * of each node to reflect which component it is in. Only
+ * consider components with values. */
+{
+rMustHaveVal = TRUE;
+return connectedComponents(dg);
+}
+
+struct dgNodeRef *dgFindNewConnected(struct diGraph *dg, struct dgNode *a)
+/* Find a connected component guaranteed not to be covered before 
+ * including a. */
+{
+rRefList = NULL;
+rMustHaveVal = FALSE;
+rFindConnected(a);
+return rRefList;
+}
+
+struct dgNodeRef *dgFindNewConnectedWithVals(struct diGraph *dg, struct dgNode *a)
+/* Find a connected component guaranteed not to be covered before 
+ * that includes a.  Connected components must have values*/
+{
+rRefList = NULL;
+rMustHaveVal = TRUE;
+rFindConnected(a);
+return rRefList;
+}
+
+
+struct dgNodeRef *dgFindConnectedToNode(struct diGraph *dg, struct dgNode *a)
+/* Return reference list of all nodes connected to a, including a.
+ * slFreeList this list when done. */
+{
+dgClearConnFlags(dg);
+return dgFindNewConnected(dg, a);
+}
+
+struct dgEdge *dgDirectlyFollows(struct diGraph *dg, struct dgNode *a, struct dgNode *b)
+/* Return TRUE if b directly follows a. */
+{
+struct dgConnection *con = dgFindNodeInConList(a->nextList, b);
+if (con == NULL)
+    return NULL;
+return con->edgeOnList->val;
+}
+
+struct dgNodeRef *dgFindPath(struct diGraph *dg, struct dgNode *a, struct dgNode *b)
+/* Find shortest path from a to b.  Return NULL if can't be found. */
+{
+struct dgNodeRef *refList  = NULL, *ref;
+struct dgConnection *con;
+struct dgNode *node, *nNode;
+struct dlList *fifo;
+struct dlNode *ffNode;
+struct dgNode endNode;
+int fifoSize = 1;
+
+/* Do some quick and easy tests first to return if have no way out
+ * of node A, or if B directly follows A. */
+if (a->nextList == NULL)
+    return NULL;
+if (a == b)
+    {
+    AllocVar(ref);
+    ref->node = a;
+    return ref;
+    }
+if ((con = dgFindNodeInConList(a->nextList, b)) != NULL)
+    {
+    AllocVar(refList);
+    refList->node = a;
+    node = con->node;
+    AllocVar(ref);
+    ref->node = node;
+    slAddTail(&refList, ref);
+    return refList;
+    }
+
+/* Set up for breadth first traversal.  Will use a doubly linked
+ * list as a fifo. */
+for (node = dg->nodeList; node != NULL; node = node->next)
+    node->tempEntry = NULL;
+fifo = newDlList();
+dlAddValTail(fifo, a);
+a->tempEntry = &endNode;
+
+while ((ffNode = dlPopHead(fifo)) != NULL)
+    {
+    --fifoSize;
+    node = ffNode->val;
+    freeMem(ffNode);
+    for (con = node->nextList; con != NULL; con = con->next)
+	{
+	nNode = con->node;
+	if (nNode->tempEntry == NULL)
+	    {
+	    nNode->tempEntry = node;
+	    if (nNode == b)
+		{
+		while (nNode != &endNode && nNode != NULL)
+		    {
+		    AllocVar(ref);
+		    ref->node = nNode;
+		    slAddHead(&refList, ref);
+		    nNode = nNode->tempEntry;
+		    }
+		break;
+		}
+	    else
+		{
+		dlAddValTail(fifo, nNode);
+		++fifoSize;
+		if (fifoSize > 100000)
+		    errAbort("Internal error in dgFindPath");
+		}
+	    }
+	}
+    }
+freeDlList(&fifo);
+return refList;
+}
+
+static int cmpPriority(const void *va, const void *vb)
+/* Sort smallest offset into needle first. */
+{
+const struct dgNode *a = *((struct dgNode **)va);
+const struct dgNode *b = *((struct dgNode **)vb);
+return (a->priority - b->priority);
+}
+
+boolean dgParentsAllVisited(struct dgNode *node)
+/* Return TRUE if all parents of node have  been visited. */
+{
+struct dgConnection *con;
+for (con = node->prevList; con != NULL; con = con->next)
+    {
+    if (con->node->visited == FALSE)
+	return FALSE;
+    }
+return TRUE;
+}
+
+struct dgNodeRef *dgConstrainedPriorityOrder(struct diGraph *dg)
+/* Return traversal of graph in priority order subject to
+ * constraint that all parents must be output before
+ * their children regardless of node priority. 
+ * Graph must be cycle free. */
+{
+struct dlList *sortedList = newDlList();
+struct dgNode *graphNode;
+struct dlNode *listNode;
+struct dgNodeRef *refList = NULL, *ref;
+
+if (dgHasCycles(dg))
+    errAbort("Call to dgConstrainedPriorityOrder on graph with cycles.");
+
+/* Make up list sorted by priority. */
+for (graphNode = dg->nodeList; graphNode != NULL; graphNode = graphNode->next)
+    {
+    dlAddValTail(sortedList, graphNode);
+    graphNode->visited = FALSE;
+    }
+dlSort(sortedList, cmpPriority);
+
+/* Loop taking first member of list with no untraversed parents. */
+while (!dlEmpty(sortedList))
+    {
+    for (listNode = sortedList->head; listNode->next != NULL; listNode = listNode->next)
+	{
+	graphNode = listNode->val;
+	if (dgParentsAllVisited(graphNode))
+	    {
+	    dlRemove(listNode);
+	    freeMem(listNode);
+	    AllocVar(ref);
+	    ref->node = graphNode;
+	    slAddHead(&refList, ref);
+	    graphNode->visited = TRUE;
+	    break;
+	    }
+	}
+    }
+freeDlList(&sortedList);
+slReverse(&refList);
+return refList;
+}
+
+struct dgEdgeRef *dgFindSubEdges(struct diGraph *dg, struct dgNodeRef *subGraph)
+/* Return list of edges in graph that connected together nodes in subGraph. */
+{
+struct hash *hash = newHash(0);
+struct dgNodeRef *nr;
+struct dgConnection *con;
+struct dgEdgeRef *erList = NULL, *er;
+struct dgNode *node;
+
+/* Build up hash of nodes in subGraph. */
+for (nr = subGraph; nr != NULL; nr = nr->next)
+    {
+    node = nr->node;
+    hashAdd(hash, node->name, node);
+    }
+
+for (nr = subGraph; nr != NULL; nr = nr->next)
+    {
+    node = nr->node;
+    for (con = node->nextList; con != NULL; con = con->next)
+	{
+	if (hashLookup(hash, con->node->name))
+	    {
+	    AllocVar(er);
+	    er->edge = con->edgeOnList->val;
+	    slAddHead(&erList, er);
+	    }
+	}
+    }
+freeHash(&hash);
+return erList;
+}
+
+void dgSwapEdges(struct diGraph *dg, struct dgEdgeRef *erList)
+/* Swap polarity of all edges in erList.  (Assumes you don't have
+ * edges going both directions in graph.) */
+{
+struct dgEdgeRef *er;
+struct dgEdge *edge;
+struct dgNode *a, *b;
+struct dgConnection *con1, *con2;
+
+/* Remove edges from next and previous list of all
+ * involved nodes and swap nodes in edge itself. */
+for (er = erList; er != NULL; er = er->next)
+    {
+    edge = er->edge;
+    a = edge->a;
+    b = edge->b;
+    dgRemoveFromConList(&a->nextList, b, &con1);
+    dgRemoveFromConList(&b->prevList, a, &con2);
+    edge->a = b;
+    edge->b = a;
+    con1->node = a;
+    slAddHead(&b->nextList, con1);
+    con2->node = b;
+    slAddHead(&a->prevList, con2);
+    }
+}
+
+
+struct dgConnection *dgNextList(struct dgNode *node)
+/* Return list of nodes that follow node. */
+{
+return node->nextList;
+}
+
+struct dgConnection *dgPrevList(struct dgNode *node)
+/* Return list of nodes that precede node. */
+{
+return node->prevList;
+}
+
+void dgDumpGraph(struct diGraph *dg, FILE *out, boolean hideIsolated)
+/* Dump info on graph to output. */
+{
+struct dgNode *node;
+struct dgConnection *con;
+
+for (node = dg->nodeList; node != NULL; node = node->next)
+    {
+    if (hideIsolated  && node->nextList == NULL)
+	continue;
+    fprintf(out, "%s:", node->name);
+    for (con = node->nextList; con != NULL; con = con->next)
+	fprintf(out, " %s", con->node->name);
+    fprintf(out, "\n");
+    }
+}
+
+
diff --git a/lib/diGraph.c.97 b/lib/diGraph.c.97
new file mode 100644
index 0000000..d0bd076
--- /dev/null
+++ b/lib/diGraph.c.97
@@ -0,0 +1,764 @@
+/* diGraph - Directed graph routines. */
+#include "common.h"
+#include "hash.h"
+#include "dlist.h"
+#include "diGraph.h"
+
+struct diGraph *dgNew()
+/* Return a new directed graph object. */
+{
+struct diGraph *dg;
+AllocVar(dg);
+dg->nodeHash = newHash(0);
+dg->edgeList = newDlList();
+return dg;
+}
+
+static void dgNodeFree(struct dgNode **pNode)
+/* Free a diGraph node. */
+{
+struct dgNode *node = *pNode;
+if (node == NULL)
+    return;
+slFreeList(&node->nextList);
+slFreeList(&node->prevList);
+freez(pNode);
+}
+
+static void dgNodeFreeList(struct dgNode **pList)
+/* Free list of diGraph nodes. */
+{
+struct dgNode *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    dgNodeFree(&el);
+    }
+*pList = NULL;
+}
+
+void dgFree(struct diGraph **pGraph)
+/* Free a directed graph. */
+{
+struct diGraph *dg = *pGraph;
+if (dg == NULL)
+    return;
+freeHash(&dg->nodeHash);
+dgNodeFreeList(&dg->nodeList);
+freeDlListAndVals(&dg->edgeList);
+freez(pGraph);
+}
+
+
+struct dgNode *dgAddNode(struct diGraph *dg, char *name, void *val)
+/* Create new node in graph. It's legal (but not efficient) to add
+ * a node with the same name and value twice.  It's not legal to
+ * add a node with the same name and a different value.  
+ * You can pass in NULL for the name in which case the 
+ * hexadecimal representation of val will become the name. */
+{
+struct dgNode *node;
+struct hashEl *hel;
+struct hash *hash = dg->nodeHash;
+char nbuf[17];
+static int nameIx = 0;
+
+if (name == NULL)
+    {
+    sprintf(nbuf, "%p", val);
+    name = nbuf;
+    }
+hel = hashLookup(hash, name);
+if (hel != NULL)
+    {
+    node = hel->val;
+    if (node->val != val)
+	{
+	errAbort("Trying to add node %s with a new value (old %x new %x)",
+	    name, node->val, val);
+	}
+    return node;
+    }
+AllocVar(node);
+hel = hashAdd(hash, name, node);
+node->name = hel->name;
+node->val = val;
+slAddHead(&dg->nodeList, node);
+return node;
+}
+
+struct dgNode *dgAddNumberedNode(struct diGraph *dg, int id, void *val)
+/* Create new node with a number instead of a name. */
+{
+char buf[16];
+sprintf(buf, "%d", id);
+return dgAddNode(dg, buf, val);
+}
+
+struct dgNode *dgFindNode(struct diGraph *dg, char *name)
+/* Find existing node in graph. Return NULL if not in graph. */
+{
+struct hashEl *hel;
+if ((hel = hashLookup(dg->nodeHash, name)) == NULL)
+    return NULL;
+return hel->val;
+}
+
+struct dgNode *dgFindNumberedNode(struct diGraph *dg, int id)
+/* Find node given number. */
+{
+char buf[16];
+sprintf(buf, "%d", id);
+return dgFindNode(dg, buf);
+}
+
+
+void *dgNodeVal(struct dgNode *node)
+/* Return value associated with node. */
+{
+return node->val;
+}
+
+void *dgNodeName(struct dgNode *node)
+/* Return name associated with node. */
+{
+return node->name;
+}
+
+int dgNodeNumber(struct dgNode *node)
+/* Return number of node.  (Will likely return 0 if node
+ * was added with a name rather than a number). */
+{
+return atoi(node->name);
+}
+
+struct dgNodeRef *dgFindNodeInRefList(struct dgNodeRef *refList, struct dgNode *node)
+/* Return reference to node if in list, or NULL if not. */
+{
+struct dgNodeRef *ref;
+for (ref = refList; ref != NULL; ref = ref->next)
+    if (ref->node == node)
+	return ref;
+return NULL;
+}
+
+struct dgConnection *dgFindNodeInConList(struct dgConnection *conList, struct dgNode *node)
+/* Return connection to node if in list, or NULL if not. */
+{
+struct dgConnection *con;
+for (con = conList; con != NULL; con = con->next)
+    if (con->node == node)
+	return con;
+return NULL;
+}
+
+struct dgEdge *dgConnect(struct diGraph *dg, struct dgNode *a, struct dgNode *b)
+/* Connect node a to node b.  Returns connecting edge. 
+ * Not an error to reconnect.  However all connects can 
+ * be broken with a single disconnect. */
+{
+dgConnectWithVal(dg, a, b, NULL);
+}
+
+struct dgEdge *dgConnectWithVal(struct diGraph *dg, struct dgNode *a, 
+     struct dgNode *b, void *val)
+/* Connect node a to node b and put val on edge.  An error to
+ * reconnect with a different val. */
+{
+struct dgConnection *con;
+struct dgEdge *edge;
+struct dlNode *edgeOnList;
+
+/* Check to see if it's already there. */
+if ((con = dgFindNodeInConList(a->nextList, b)) != NULL)
+    {
+    edge =  con->edgeOnList->val;
+    if (val != edge->val)
+        warn("Trying to add new value to edge between %s and %s, ignoring",
+	   a->name, b->name);
+    return edge;
+    }
+/* Allocate edge and put on list. */
+AllocVar(edge);
+edge->a = a;
+edge->b = b;
+edge->val = val;
+edgeOnList = dlAddValTail(dg->edgeList, edge);
+
+/* Connect nodes to each other. */
+AllocVar(con);
+con->node = b;
+con->edgeOnList = edgeOnList;
+slAddHead(&a->nextList, con);
+AllocVar(con);
+con->node = a;
+con->edgeOnList = edgeOnList;
+slAddHead(&b->prevList, con);
+
+return edge;
+}
+
+struct dgEdge *dgConnectUnflippable(struct diGraph *dg, struct dgNode *a, struct dgNode *b,
+    void *val)
+/* Connect a to b with an edge than can't be flipped. */
+{
+struct dgEdge *edge = dgConnectWithVal(dg, a, b, val);
+edge->unflippable = TRUE;
+return edge;
+}
+
+static struct dlNode *dgRemoveFromConList(struct dgConnection **pConList, 
+	struct dgNode *node, struct dgConnection **retCon)
+/* Remove reference to node from list. */
+{
+struct dgConnection *newList = NULL;
+struct dgConnection *con, *next;
+struct dlNode *edgeOnList = NULL;
+
+for (con = *pConList; con != NULL; con = next)
+    {
+    next = con->next;
+    if (con->node == node)
+	{
+	edgeOnList = con->edgeOnList;
+	if (retCon != NULL)
+	    *retCon = con;
+	else
+	    freeMem(con);
+	}
+    else
+	{
+	slAddHead(&newList, con);
+	}
+    }
+slReverse(&newList);
+*pConList = newList;
+return edgeOnList;
+}
+
+void dgDisconnect(struct diGraph *dg, struct dgNode *a, struct dgNode *b)
+/* Disconnect nodes a and b. */
+{
+struct dlNode *edgeInList;
+struct dgEdge *edge;
+
+dgRemoveFromConList(&a->nextList, b, NULL);
+edgeInList = dgRemoveFromConList(&b->prevList, a, NULL);
+if (edgeInList != NULL)
+    {
+    edge = edgeInList->val;
+    dlRemove(edgeInList);
+    freeMem(edgeInList);
+    freeMem(edge);
+    }
+}
+
+
+void dgClearVisitFlags(struct diGraph *dg)
+/* Clear out visit flags. */
+{
+struct dgNode *node;
+for (node = dg->nodeList; node != NULL; node = node->next)
+    node->visited = FALSE;
+}
+
+void dgClearConnFlags(struct diGraph *dg)
+/* Clear out connect flags. */
+{
+struct dgNode *node;
+for (node = dg->nodeList; node != NULL; node = node->next)
+    node->conn = FALSE;
+}
+
+static struct dgNode *rTarget;
+
+static boolean rPathExists(struct dgNode *a)
+/* Recursively find if path from a to b exists. */
+{
+struct dgConnection *ref;
+if (a == rTarget)
+    return TRUE;
+a->visited = TRUE;
+
+for (ref = a->nextList; ref != NULL; ref = ref->next)
+    {
+    if (!ref->node->visited && rPathExists(ref->node))
+	return TRUE;
+    }
+return FALSE;
+}
+
+boolean dgPathExists(struct diGraph *dg, struct dgNode *a, struct dgNode *b)
+/* Return TRUE if there's a path from a to b. */
+{
+rTarget = b;
+dgClearVisitFlags(dg);
+return rPathExists(a);
+}
+
+static int topoIx;
+
+static void rTopoSort(struct dgNode *node)
+{
+struct dgConnection *ref;
+node->visited = TRUE;
+for (ref = node->nextList; ref != NULL; ref = ref->next)
+    {
+    if (!ref->node->visited)
+	rTopoSort(ref->node);
+    }
+node->topoOrder = ++topoIx;
+}
+
+void dgTopoSort(struct diGraph *dg)
+/* Fill in topological order of nodes. */
+{
+struct dgNode *node;
+
+topoIx = 0;
+dgClearVisitFlags(dg);
+for (node = dg->nodeList; node != NULL; node = node->next)
+    {
+    if (!node->visited)
+	rTopoSort(node);
+    }
+}
+
+static boolean  rHasCycles(struct dgNode *node)
+/* Recursively see if has cycles by looking for
+ * backwards topoOrder. */
+{
+struct dgConnection *ref;
+struct dgNode *child;
+
+node->visited = TRUE;
+for (ref = node->nextList; ref != NULL; ref = ref->next)
+    {
+    child = ref->node;
+    if (child->topoOrder > node->topoOrder)
+	return TRUE;
+    if (!child->visited)
+	if (rHasCycles(child))
+	    return TRUE;
+    }
+return FALSE;
+}
+
+boolean dgHasCycles(struct diGraph *dg)
+/* Return TRUE if directed graph has cycles. */
+{
+struct dgNode *node;
+
+dgTopoSort(dg);
+dgClearVisitFlags(dg);
+for (node = dg->nodeList; node != NULL; node = node->next)
+    {
+    if (!node->visited)
+	if (rHasCycles(node))
+	    return TRUE;
+    }
+return FALSE;
+}
+
+struct dgNodeRef *rRefList;
+bool rRespectFlipper;			/* Set to TRUE if rFindConnected only to
+                                         * consider nodes with values in connections. */
+
+static void rFindConnected(struct dgNode *a)
+/* Find all things connected to a directly or not that haven't
+ * already been visited and put them on rRefList. */
+{
+if (!a->conn)
+    {
+    struct dgNodeRef *ref;
+    struct dgConnection *con;
+    struct dgEdge *edge;
+
+    AllocVar(ref);
+    ref->node = a;
+    slAddHead(&rRefList, ref);
+    a->conn = TRUE;
+    for (con = a->nextList; con != NULL; con = con->next)
+	{
+	edge = con->edgeOnList->val;
+	if (!rRespectFlipper || !edge->unflippable)
+	    rFindConnected(con->node);
+	}
+    for (con = a->prevList; con != NULL; con = con->next)
+	{
+	edge = con->edgeOnList->val;
+	if (!rRespectFlipper || !edge->unflippable)
+	    rFindConnected(con->node);
+	}
+    }
+}
+
+struct dgNodeRef *dgFindNextConnected(struct diGraph *dg)
+/* Return list of nodes that make up next connected component,
+ * or NULL if no more components.  slFreeList this when
+ * done.  Call "dgClearConnFlags" before first call to this.
+ * Do not call dgFindConnectedToNode between dgFindFirstConnected 
+ * and this as they use the same flag variables to keep track of
+ * what vertices are used. */
+{
+struct dgNode *a;
+
+for (a=dg->nodeList; a != NULL; a = a->next)
+    {
+    if (!a->conn)
+	break;
+    }
+if (a == NULL)
+    return NULL;
+rRefList = NULL;
+rRespectFlipper = FALSE;
+rFindConnected(a);
+return rRefList;
+}
+
+struct dgNodeRef *dgFindNextFlippableConnected(struct diGraph *dg)
+/* Like dgFindConnected, but only considers graph nodes that
+ * are conencted by a flippable edge. */
+{
+struct dgNode *a;
+
+for (a=dg->nodeList; a != NULL; a = a->next)
+    {
+    if (!a->conn)
+	break;
+    }
+if (a == NULL)
+    return NULL;
+rRefList = NULL;
+rRespectFlipper = TRUE;
+rFindConnected(a);
+return rRefList;
+}
+
+
+static int connectedComponents(struct diGraph *dg)
+/* Count number of connected components and set component field
+ * of each node to reflect which component it is in. */
+{
+struct dgNodeRef *ref;
+int conCount = 0;
+struct dgNode *a = dg->nodeList;
+
+dgClearConnFlags(dg);
+for (;;)
+    {
+    for (; a != NULL; a = a->next)
+	{
+	if (!a->conn)
+	    break;
+	}
+    if (a == NULL)
+	break;
+    rRefList = NULL;
+    rFindConnected(a);
+    ++conCount;
+    for (ref = rRefList; ref != NULL; ref = ref->next)
+	{
+	ref->node->component = conCount;
+	}
+    slFreeList(&rRefList);
+    }
+return conCount;
+}
+
+int dgConnectedComponents(struct diGraph *dg)
+/* Count number of connected components and set component field
+ * of each node to reflect which component it is in. */
+{
+rRespectFlipper = FALSE;
+connectedComponents(dg);
+}
+
+int dgConnectedFlippableComponents(struct diGraph *dg)
+/* Count number of connected components and set component field
+ * of each node to reflect which component it is in. Only
+ * consider components connected by flippable edges. */
+{
+rRespectFlipper = TRUE;
+connectedComponents(dg);
+}
+
+struct dgNodeRef *dgFindNewConnected(struct diGraph *dg, struct dgNode *a)
+/* Find a connected component guaranteed not to be covered before 
+ * including a. */
+{
+rRefList = NULL;
+rRespectFlipper = FALSE;
+rFindConnected(a);
+return rRefList;
+}
+
+struct dgNodeRef *dgFindNewFlippableConnected(struct diGraph *dg, struct dgNode *a)
+/* Find a connected component guaranteed not to be covered before 
+ * that includes a.  Connected components must be connected by flippable
+ * edges. */
+{
+rRefList = NULL;
+rRespectFlipper = TRUE;
+rFindConnected(a);
+return rRefList;
+}
+
+
+struct dgNodeRef *dgFindConnectedToNode(struct diGraph *dg, struct dgNode *a)
+/* Return reference list of all nodes connected to a, including a.
+ * slFreeList this list when done. */
+{
+dgClearConnFlags(dg);
+return dgFindNewConnected(dg, a);
+}
+
+struct dgEdge *dgDirectlyFollows(struct diGraph *dg, struct dgNode *a, struct dgNode *b)
+/* Return TRUE if b directly follows a. */
+{
+struct dgConnection *con = dgFindNodeInConList(a->nextList, b);
+if (con == NULL)
+    return NULL;
+return con->edgeOnList->val;
+}
+
+struct dgNodeRef *dgFindPath(struct diGraph *dg, struct dgNode *a, struct dgNode *b)
+/* Find shortest path from a to b.  Return NULL if can't be found. */
+{
+struct dgNodeRef *refList  = NULL, *ref;
+struct dgConnection *con;
+struct dgNode *node, *nNode;
+struct dlList *fifo;
+struct dlNode *ffNode;
+struct dgNode endNode;
+int fifoSize = 1;
+
+/* Do some quick and easy tests first to return if have no way out
+ * of node A, or if B directly follows A. */
+if (a->nextList == NULL)
+    return NULL;
+if (a == b)
+    {
+    AllocVar(ref);
+    ref->node = a;
+    return ref;
+    }
+if ((con = dgFindNodeInConList(a->nextList, b)) != NULL)
+    {
+    AllocVar(refList);
+    refList->node = a;
+    node = con->node;
+    AllocVar(ref);
+    ref->node = node;
+    slAddTail(&refList, ref);
+    return refList;
+    }
+
+/* Set up for breadth first traversal.  Will use a doubly linked
+ * list as a fifo. */
+for (node = dg->nodeList; node != NULL; node = node->next)
+    node->tempEntry = NULL;
+fifo = newDlList();
+dlAddValTail(fifo, a);
+a->tempEntry = &endNode;
+
+while ((ffNode = dlPopHead(fifo)) != NULL)
+    {
+    --fifoSize;
+    node = ffNode->val;
+    freeMem(ffNode);
+    for (con = node->nextList; con != NULL; con = con->next)
+	{
+	nNode = con->node;
+	if (nNode->tempEntry == NULL)
+	    {
+	    nNode->tempEntry = node;
+	    if (nNode == b)
+		{
+		while (nNode != &endNode && nNode != NULL)
+		    {
+		    AllocVar(ref);
+		    ref->node = nNode;
+		    slAddHead(&refList, ref);
+		    nNode = nNode->tempEntry;
+		    }
+		break;
+		}
+	    else
+		{
+		dlAddValTail(fifo, nNode);
+		++fifoSize;
+		if (fifoSize > 100000)
+		    errAbort("Internal error in dgFindPath");
+		}
+	    }
+	}
+    }
+freeDlList(&fifo);
+return refList;
+}
+
+static int cmpPriority(const void *va, const void *vb)
+/* Sort smallest offset into needle first. */
+{
+const struct dgNode *a = *((struct dgNode **)va);
+const struct dgNode *b = *((struct dgNode **)vb);
+return (a->priority - b->priority);
+}
+
+boolean dgParentsAllVisited(struct dgNode *node)
+/* Return TRUE if all parents of node have  been visited. */
+{
+struct dgConnection *con;
+for (con = node->prevList; con != NULL; con = con->next)
+    {
+    if (con->node->visited == FALSE)
+	return FALSE;
+    }
+return TRUE;
+}
+
+struct dgNodeRef *dgConstrainedPriorityOrder(struct diGraph *dg)
+/* Return traversal of graph in priority order subject to
+ * constraint that all parents must be output before
+ * their children regardless of node priority. 
+ * Graph must be cycle free. */
+{
+struct dlList *sortedList = newDlList();
+struct dgNode *graphNode;
+struct dlNode *listNode;
+struct dgNodeRef *refList = NULL, *ref;
+
+if (dgHasCycles(dg))
+    errAbort("Call to dgConstrainedPriorityOrder on graph with cycles.");
+
+/* Make up list sorted by priority. */
+for (graphNode = dg->nodeList; graphNode != NULL; graphNode = graphNode->next)
+    {
+    dlAddValTail(sortedList, graphNode);
+    graphNode->visited = FALSE;
+    }
+dlSort(sortedList, cmpPriority);
+
+/* Loop taking first member of list with no untraversed parents. */
+while (!dlEmpty(sortedList))
+    {
+    for (listNode = sortedList->head; listNode->next != NULL; listNode = listNode->next)
+	{
+	graphNode = listNode->val;
+	if (dgParentsAllVisited(graphNode))
+	    {
+	    dlRemove(listNode);
+	    freeMem(listNode);
+	    AllocVar(ref);
+	    ref->node = graphNode;
+	    slAddHead(&refList, ref);
+	    graphNode->visited = TRUE;
+	    break;
+	    }
+	}
+    }
+freeDlList(&sortedList);
+slReverse(&refList);
+return refList;
+}
+
+struct dgEdgeRef *dgFindSubEdges(struct diGraph *dg, struct dgNodeRef *subGraph,
+	boolean onlyFlippable)
+/* Return list of edges in graph that connected together nodes in subGraph. 
+ * Optionally return only flippable edges. */
+{
+struct hash *hash = newHash(0);
+struct dgNodeRef *nr;
+struct dgConnection *con;
+struct dgEdgeRef *erList = NULL, *er;
+struct dgEdge *edge;
+struct dgNode *node;
+
+/* Build up hash of nodes in subGraph. */
+for (nr = subGraph; nr != NULL; nr = nr->next)
+    {
+    node = nr->node;
+    hashAdd(hash, node->name, node);
+    }
+
+for (nr = subGraph; nr != NULL; nr = nr->next)
+    {
+    node = nr->node;
+    for (con = node->nextList; con != NULL; con = con->next)
+	{
+	if (hashLookup(hash, con->node->name))
+	    {
+	    edge = con->edgeOnList->val;
+	    if (!onlyFlippable || !edge->unflippable)
+		{
+		AllocVar(er);
+		er->edge = con->edgeOnList->val;
+		slAddHead(&erList, er);
+		}
+	    }
+	}
+    }
+freeHash(&hash);
+return erList;
+}
+
+void dgSwapEdges(struct diGraph *dg, struct dgEdgeRef *erList)
+/* Swap polarity of all edges in erList.  (Assumes you don't have
+ * edges going both directions in graph.) */
+{
+struct dgEdgeRef *er;
+struct dgEdge *edge;
+struct dgNode *a, *b;
+struct dgConnection *con1, *con2;
+
+/* Remove edges from next and previous list of all
+ * involved nodes and swap nodes in edge itself. */
+for (er = erList; er != NULL; er = er->next)
+    {
+    edge = er->edge;
+    a = edge->a;
+    b = edge->b;
+    dgRemoveFromConList(&a->nextList, b, &con1);
+    dgRemoveFromConList(&b->prevList, a, &con2);
+    edge->a = b;
+    edge->b = a;
+    con1->node = a;
+    slAddHead(&b->nextList, con1);
+    con2->node = b;
+    slAddHead(&a->prevList, con2);
+    }
+}
+
+
+struct dgConnection *dgNextList(struct dgNode *node)
+/* Return list of nodes that follow node. */
+{
+return node->nextList;
+}
+
+struct dgConnection *dgPrevList(struct dgNode *node)
+/* Return list of nodes that precede node. */
+{
+return node->prevList;
+}
+
+void dgDumpGraph(struct diGraph *dg, FILE *out, boolean hideIsolated)
+/* Dump info on graph to output. */
+{
+struct dgNode *node;
+struct dgConnection *con;
+
+for (node = dg->nodeList; node != NULL; node = node->next)
+    {
+    if (hideIsolated  && node->nextList == NULL)
+	continue;
+    fprintf(out, "%s:", node->name);
+    for (con = node->nextList; con != NULL; con = con->next)
+	fprintf(out, " %s", con->node->name);
+    fprintf(out, "\n");
+    }
+}
+
+
diff --git a/lib/diff b/lib/diff
new file mode 100644
index 0000000..e69de29
diff --git a/lib/diffs b/lib/diffs
new file mode 100644
index 0000000..5b8bb76
--- /dev/null
+++ b/lib/diffs
@@ -0,0 +1,599 @@
+diff --git a/src/hg/encode/encodeMergeReplicates/encodeMergeReplicates.c b/src/hg/encode/encodeMergeReplicates/encodeMergeReplicates.c
+index b68a4ef..14333df 100644
+--- a/src/hg/encode/encodeMergeReplicates/encodeMergeReplicates.c
++++ b/src/hg/encode/encodeMergeReplicates/encodeMergeReplicates.c
+@@ -3,6 +3,7 @@
+ #include "linefile.h"
+ #include "hash.h"
+ #include "options.h"
++#include "narrowPeak.h"
+ 
+ static char const rcsid[] = "$Id: newProg.c,v 1.30 2010/03/24 21:18:33 hiram Exp $";
+ 
+@@ -10,9 +11,10 @@ void usage()
+ /* Explain usage and exit. */
+ {
+ errAbort(
+-  "encodeMergeReplicates - Merge together replicates for a pooled output.  Only works on narrowPeak files currently.\n"
++  "encodeMergeReplicates - Merge together replicates for a pooled output.  \n"
++  "Only works on narrowPeak files currently.\n"
+   "usage:\n"
+-  "   encodeMergeReplicates XXX\n"
++  "   encodeMergeReplicates in1 in2 in3 ... output\n"
+   "options:\n"
+   "   -xxx=XXX\n"
+   );
+@@ -22,8 +24,9 @@ static struct optionSpec options[] = {
+    {NULL, 0},
+ };
+ 
+-void encodeMergeReplicates(char *XXX)
+-/* encodeMergeReplicates - Merge together replicates for a pooled output.  Only works on narrowPeak files currently.. */
++void encodeMergeReplicates(int inCount, char *inNames[], char *outName)
++/* encodeMergeReplicates - Merge together replicates for a pooled output.  
++ * Only works on narrowPeak files currently. */
+ {
+ }
+ 
+@@ -31,8 +34,8 @@ int main(int argc, char *argv[])
+ /* Process command line. */
+ {
+ optionInit(&argc, argv, options);
+-if (argc != 2)
++if (argc < 4)
+     usage();
+-encodeMergeReplicates(argv[1]);
++encodeMergeReplicates(argv+1, argc-2, argv[argc-1]);
+ return 0;
+ }
+diff --git a/src/hg/makeDb/trackDb/human/hg18/trackDb.wgEncode.ra b/src/hg/makeDb/trackDb/human/hg18/trackDb.wgEncode.ra
+index cdcd9c0..04342b6 100644
+--- a/src/hg/makeDb/trackDb/human/hg18/trackDb.wgEncode.ra
++++ b/src/hg/makeDb/trackDb/human/hg18/trackDb.wgEncode.ra
+@@ -1683,14 +1683,14 @@ group regulation
+ 	type wig 0.00 4417.02
+ 	color 191,128,255
+ 
+-    track wgEncodeRegMarkEnhancer
++    track wgEncodeRegMarkEnhH3k4me1
+     # compositeTrack on
+     container multiWig
+     noInherit on
+     type wig 0 10000
+     superTrack wgEncodeReg full
+     shortLabel Enhancer H3K4Me1
+-    longLabel Enhancer histone mark (H3K4Me1) on 8 cell lines from ENCODE
++    longLabel H3K4Me1 - an Enhancer and Promoter Histone Mark on 8 Cell Lines from ENCODE
+     release alpha
+     configurable on
+     visibility full
+@@ -1700,74 +1700,74 @@ group regulation
+     showSubtrackColorOnUi on
+     priority 2
+ 
+-	track wgEncodeRegMarkEnhancerGm12878
++	track wgEncodeRegMarkEnhH3k4me1Gm12878
+ 	shortLabel	Gm12878
+-	longLabel Enhancer mark (H3K4Me1) on Gm12878 cells from ENCODE
++	longLabel H3K4Me1 - an Enhancer and Promoter Histone Mark on Gm12878 cells from ENCODE
+         release alpha
+-	parent wgEncodeRegMarkEnhancer
++	parent wgEncodeRegMarkEnhH3k4me1
+ 	type wig 0.00 9323.50
+ 	color 255,128,128
+ 	table wgEncodeBroadChipSeqSignalGm12878H3k4me1
+ 
+-	track wgEncodeRegMarkEnhancerH1hesc
++	track wgEncodeRegMarkEnhH3k4me1H1hesc
+ 	shortLabel	H1 ES
+-	longLabel Enhancer mark (H3K4Me1) on H1 ES cells from ENCODE
++	longLabel H3K4Me1 - an Enhancer and Promoter Histone Mark on H1 ES cells from ENCODE
+         release alpha
+-	parent wgEncodeRegMarkEnhancer
++	parent wgEncodeRegMarkEnhH3k4me1
+ 	color 255,223,128
+ 	table wgEncodeBroadChipSeqSignalH1hescH3k4me1
+ 	type wig 0.00 12286.00
+ 
+-	track wgEncodeRegMarkEnhancerHmec
++	track wgEncodeRegMarkEnhH3k4me1Hmec
+ 	shortLabel	HMEC
+-	longLabel Enhancer mark (H3K4Me1) on HMEC cells from ENCODE 
++	longLabel H3K4Me1 - an Enhancer and Promoter Histone Mark on HMEC cells from ENCODE 
+         release alpha
+-	parent wgEncodeRegMarkEnhancer
++	parent wgEncodeRegMarkEnhH3k4me1
+ 	color 191,255,128
+ 	table wgEncodeBroadChipSeqSignalHmecH3k4me1
+ 	type wig 0.00 13574.00
+ 
+-	track wgEncodeRegMarkEnhancerHsmm
++	track wgEncodeRegMarkEnhH3k4me1Hsmm
+ 	shortLabel	HSMM
+-	longLabel Enhancer mark (H3K4Me1) on HSMM cells from ENCODE 
++	longLabel H3K4Me1 - an Enhancer and Promoter Histone Mark on HSMM cells from ENCODE 
+         release alpha
+-	parent wgEncodeRegMarkEnhancer
++	parent wgEncodeRegMarkEnhH3k4me1
+ 	color 128,255,159
+ 	table wgEncodeBroadChipSeqSignalHsmmH3k4me1
+ 	type wig 0.00 10412.00
+ 
+-	track wgEncodeRegMarkEnhancerHuvec
++	track wgEncodeRegMarkEnhH3k4me1Huvec
+ 	shortLabel	HUVEC
+-	longLabel Enhancer mark (H3K4Me1) on HUVEC cells from ENCODE 
++	longLabel H3K4Me1 - an Enhancer and Promoter Histone Mark on HUVEC cells from ENCODE 
+         release alpha
+-	parent wgEncodeRegMarkEnhancer
++	parent wgEncodeRegMarkEnhH3k4me1
+ 	color 128,255,255
+ 	table wgEncodeBroadChipSeqSignalHuvecH3k4me1
+ 	type wig 0.00 5259.25
+ 
+-	track wgEncodeRegMarkEnhancerK562
++	track wgEncodeRegMarkEnhH3k4me1K562
+ 	shortLabel	K562
+-	longLabel Enhancer mark (H3K4Me1) on K562 cells from ENCODE 
++	longLabel H3K4Me1 - an Enhancer and Promoter Histone Mark on K562 cells from ENCODE 
+         release alpha
+-	parent wgEncodeRegMarkEnhancer
++	parent wgEncodeRegMarkEnhH3k4me1
+ 	color 128,159,255
+ 	table wgEncodeBroadChipSeqSignalK562H3k4me1
+ 	type wig 0.00 8682.25
+ 
+-	track wgEncodeRegMarkEnhancerNhek
++	track wgEncodeRegMarkEnhH3k4me1Nhek
+ 	shortLabel	NHEK
+-	longLabel Enhancer mark (H3K4Me1) on NHEK cells from ENCODE 
++	longLabel H3K4Me1 - an Enhancer and Promoter Histone Mark on NHEK cells from ENCODE 
+         release alpha
+-	parent wgEncodeRegMarkEnhancer
++	parent wgEncodeRegMarkEnhH3k4me1
+ 	color 191,128,255
+ 	table wgEncodeBroadChipSeqSignalNhekH3k4me1
+ 	type wig 0.00 4240.50
+ 
+-	track wgEncodeRegMarkEnhancerNhlf
++	track wgEncodeRegMarkEnhH3k4me1Nhlf
+ 	shortLabel	NHLF
+-	longLabel Enhancer mark (H3K4Me1) on NHLF cells from ENCODE 
++	longLabel H3K4Me1 - an Enhancer and Promoter Histone Mark on NHLF cells from ENCODE 
+         release alpha
+-	parent wgEncodeRegMarkEnhancer
++	parent wgEncodeRegMarkEnhH3k4me1
+ 	color 255,128,223
+ 	table wgEncodeBroadChipSeqSignalNhlfH3k4me1
+ 	type wig 0.00 14639.00
+@@ -1779,7 +1779,7 @@ group regulation
+     type wig 0 10000
+     superTrack wgEncodeReg full
+     shortLabel Enhancer H3K27Ac
+-    longLabel Enhancer histone mark (H3K27Ac) on 8 cell lines from ENCODE
++    longLabel H3K27Ac - An Enhancer and Promoter Histone Mark on 8 Cell Lines from ENCODE
+     release alpha
+     configurable on
+     visibility full
+@@ -1791,7 +1791,7 @@ group regulation
+ 
+ 	track wgEncodeRegMarkEnhH3k27acGm12878
+ 	shortLabel	Gm12878
+-	longLabel Enhancer mark (H3K27Ac) on Gm12878 cells from ENCODE
++	longLabel H3K27Ac - An enhancer and promoter mark on Gm12878 cells from ENCODE
+         release alpha
+ 	parent wgEncodeRegMarkEnhH3k27ac
+ 	type wig 0.00 9323.50
+@@ -1800,7 +1800,7 @@ group regulation
+ 
+ 	track wgEncodeRegMarkEnhH3k27acH1hesc
+ 	shortLabel	H1 ES
+-	longLabel Enhancer mark (H3K27Ac) on H1 ES cells from ENCODE
++	longLabel H3K27Ac - An enhancer and promoter mark on H1 ES cells from ENCODE
+         release alpha
+ 	parent wgEncodeRegMarkEnhH3k27ac
+ 	color 255,223,128
+@@ -1809,7 +1809,7 @@ group regulation
+ 
+ 	track wgEncodeRegMarkEnhH3k27acHmec
+ 	shortLabel	HMEC
+-	longLabel Enhancer mark (H3K27Ac) on HMEC cells from ENCODE 
++	longLabel H3K27Ac - An enhancer and promoter mark on HMEC cells from ENCODE 
+         release alpha
+ 	parent wgEncodeRegMarkEnhH3k27ac
+ 	color 191,255,128
+@@ -1818,7 +1818,7 @@ group regulation
+ 
+ 	track wgEncodeRegMarkEnhH3k27acHsmm
+ 	shortLabel	HSMM
+-	longLabel Enhancer mark (H3K27Ac) on HSMM cells from ENCODE 
++	longLabel H3K27Ac - An enhancer and promoter mark on HSMM cells from ENCODE 
+         release alpha
+ 	parent wgEncodeRegMarkEnhH3k27ac
+ 	color 128,255,159
+@@ -1827,7 +1827,7 @@ group regulation
+ 
+ 	track wgEncodeRegMarkEnhH3k27acHuvec
+ 	shortLabel	HUVEC
+-	longLabel Enhancer mark (H3K27Ac) on HUVEC cells from ENCODE 
++	longLabel H3K27Ac - An enhancer and promoter mark on HUVEC cells from ENCODE 
+         release alpha
+ 	parent wgEncodeRegMarkEnhH3k27ac
+ 	color 128,255,255
+@@ -1836,7 +1836,7 @@ group regulation
+ 
+ 	track wgEncodeRegMarkEnhH3k27acK562
+ 	shortLabel	K562
+-	longLabel Enhancer mark (H3K27Ac) on K562 cells from ENCODE 
++	longLabel H3K27Ac - An enhancer and promoter mark on K562 cells from ENCODE 
+         release alpha
+ 	parent wgEncodeRegMarkEnhH3k27ac
+ 	color 128,159,255
+@@ -1845,7 +1845,7 @@ group regulation
+ 
+ 	track wgEncodeRegMarkEnhH3k27acNhek
+ 	shortLabel	NHEK
+-	longLabel Enhancer mark (H3K27Ac) on NHEK cells from ENCODE 
++	longLabel H3K27Ac - An enhancer and promoter mark on NHEK cells from ENCODE 
+         release alpha
+ 	parent wgEncodeRegMarkEnhH3k27ac
+ 	color 191,128,255
+@@ -1854,7 +1854,7 @@ group regulation
+ 
+ 	track wgEncodeRegMarkEnhH3k27acNhlf
+ 	shortLabel	NHLF
+-	longLabel Enhancer mark (H3K27Ac) on NHLF cells from ENCODE 
++	longLabel H3K27Ac - An enhancer and promoter mark on NHLF cells from ENCODE 
+         release alpha
+ 	parent wgEncodeRegMarkEnhH3k27ac
+ 	color 255,128,223
+@@ -1971,7 +1971,7 @@ group regulation
+     type factorSource
+     superTrack wgEncodeReg dense
+     sourceTable wgEncodeRegTfbsCells
+-    inputTracks wgEncodeYaleChIPseq
++    inputTracks wgEncodeYaleChIPseq wgEncodeHudsonalphaChipSeq
+     inputTracksSubgroupSelect view=Peaks
+     inputTracksSubgroupDisplay cellType factor
+     visibility dense
+diff --git a/src/hg/regulate/regCluster/makefile b/src/hg/regulate/regCluster/makefile
+index b4de7cb..d1c0e73 100644
+--- a/src/hg/regulate/regCluster/makefile
++++ b/src/hg/regulate/regCluster/makefile
+@@ -5,7 +5,7 @@ MYLIBDIR = ../../../lib/${MACHTYPE}
+ MYLIBS =  ${MYLIBDIR}/jkweb.a
+ 
+ A = regCluster
+-O = regCluster.o
++O = regCluster.o 
+ 
+ regCluster: ${O} ${MYLIBS}
+ 	${CC} ${COPT} -o ${DESTDIR}${BINDIR}/${A}${EXE} $O ${MYLIBS} $L
+diff --git a/src/hg/regulate/regCluster/regCluster.c b/src/hg/regulate/regCluster/regCluster.c
+index 7d8245c..0c3691c 100644
+--- a/src/hg/regulate/regCluster/regCluster.c
++++ b/src/hg/regulate/regCluster/regCluster.c
+@@ -3,10 +3,9 @@
+ #include "linefile.h"
+ #include "hash.h"
+ #include "options.h"
+-#include "sqlNum.h"
+-#include "obscure.h"
+ #include "localmem.h"
+ #include "rangeTree.h"
++#include "peakCluster.h"
+ 
+ static char const rcsid[] = "$Id: regCluster.c,v 1.4 2010/05/16 21:41:42 kent Exp $";
+ 
+@@ -51,247 +50,6 @@ static struct optionSpec options[] = {
+    {NULL, 0},
+ };
+ 
+-struct regDim
+-/* A regulatory dimension */
+-    {
+-    int colIx;		/* Column index in table. */
+-    char *label;	/* Label */
+-    };
+-
+-struct regSource 
+-/* A source of regulatory information */
+-    {
+-    struct regSource *next;
+-    char *dataSource;		/* File (or table) */
+-    int chromColIx;		/* Chromosome column index. */
+-    int startColIx;		/* Start coordinate column index. */
+-    int endColIx;		/* End ccoordinate column ix. */
+-    int scoreColIx;		/* Index for score column. */
+-    double normFactor;		/* Multiply this to get browser score. */
+-    char **labels;		/* Label for each dimension */
+-    int minColCount;		/* Minimum number of columns. */
+-    };
+-
+-struct regItem
+-/* An item in a regulatory track */
+-    {
+-    struct regItem *next;
+-    char *chrom;		/* Chromosome. Not allocated here. */
+-    int chromStart,chromEnd;	/* Half open coordinates. */
+-    double score;		/* Ideally something like -log(p). */
+-    struct regSource *source;   /* Source track/file for item. */
+-    };
+-
+-struct regCluster
+-/* A cluster of items. */
+-    {
+-    struct regCluster *next;
+-    char *chrom;		/* Chromosome.  Not allocated here. */
+-    int chromStart, chromEnd;	/* Half open coordinates. */
+-    double score;		/* Sum of component scores. */
+-    double maxSubScore;		/* Max of component scores. */
+-    struct slRef *itemRefList;	/* List of references to component items. */
+-    };
+-
+-struct regSource *regSourceLoadAll(char *fileName, int dimCount)
+-/* Read file, parse it line by line and return list of regSources. */
+-{
+-struct lineFile *lf = lineFileOpen(fileName, TRUE);
+-int rowSize = dimCount + 6;
+-char *row[rowSize];
+-struct regSource *sourceList = NULL, *source;
+-while (lineFileNextRow(lf, row, rowSize))
+-    {
+-    /* Allocate struct and read in fixed fields. */
+-    AllocVar(source);
+-    source->dataSource = cloneString(row[0]);
+-    source->chromColIx = sqlUnsigned(row[1]);
+-    source->startColIx = sqlUnsigned(row[2]);
+-    source->endColIx = sqlUnsigned(row[3]);
+-    source->scoreColIx = sqlUnsigned(row[4]);
+-    source->normFactor = sqlDouble(row[5]);
+-
+-    /* Read in dimension labels. */
+-    AllocArray(source->labels, dimCount);
+-    int i;
+-    for (i=0; i<dimCount; ++i)
+-        source->labels[i] = cloneString(row[i+6]);
+-
+-    /* Calculate required columns. */
+-    int minColCount = max(source->chromColIx, source->startColIx);
+-    minColCount = max(minColCount, source->endColIx);
+-    minColCount = max(minColCount, source->scoreColIx);
+-    source->minColCount = minColCount + 1;
+-    slAddHead(&sourceList, source);
+-    }
+-lineFileClose(&lf);
+-slReverse(&sourceList);
+-return sourceList;
+-}
+-
+-void clusterSource(struct regSource *source, struct hash *chromHash, 
+-	struct rbTreeNode *stack[128])
+-/* Read through data source and add items to it to rangeTrees in hash */
+-{
+-struct lineFile *lf = lineFileOpen(source->dataSource, TRUE);
+-struct lm *lm = chromHash->lm;	/* Local memory pool - share with hash */
+-char *row[source->minColCount];
+-struct regItem *item;
+-while (lineFileNextRow(lf, row, source->minColCount))
+-    {
+-    char *chrom = row[source->chromColIx];
+-    struct hashEl *hel = hashLookup(chromHash, chrom);
+-    if (hel == NULL)
+-        {
+-	struct rbTree *tree = rangeTreeNewDetailed(lm, stack);
+-	hel = hashAdd(chromHash, chrom, tree);
+-	}
+-    struct rbTree *tree = hel->val;
+-    lmAllocVar(lm, item);
+-    item->chrom = hel->name;
+-    item->chromStart = sqlUnsigned(row[source->startColIx]);
+-    item->chromEnd = sqlUnsigned(row[source->endColIx]);
+-    item->score = sqlDouble(row[source->scoreColIx]) * source->normFactor;
+-    if (item->score > 1000) item->score = 1000;
+-    item->source = source;
+-    rangeTreeAddValList(tree, item->chromStart, item->chromEnd, item);
+-    }
+-
+-lineFileClose(&lf);
+-}
+-
+-int cmpChromEls(const void *va, const void *vb)
+-/* Compare to sort based on query start. */
+-{
+-const struct hashEl *a = *((struct hashEl **)va);
+-const struct hashEl *b = *((struct hashEl **)vb);
+-return cmpWordsWithEmbeddedNumbers(a->name, b->name);
+-}
+-
+-void addCluster(struct lm *lm, struct regItem *itemList, int start, int end,
+-	struct regCluster **pList)
+-/* Make cluster of all items that overlap start/end, and put it on list. */
+-{
+-struct regCluster *cluster;
+-lmAllocVar(lm, cluster);
+-double score = 0.0;
+-double maxSubScore = 0.0;
+-struct slRef  *refList = NULL, *ref;
+-struct regItem *item;
+-for (item = itemList; item != NULL; item = item->next)
+-    {
+-    if (rangeIntersection(start, end, item->chromStart, item->chromEnd) > 0)
+-	{
+-	lmAllocVar(lm, ref);
+-	ref->val = item;
+-	slAddHead(&refList, ref);
+-	score += item->score;
+-	if (item->score > maxSubScore) maxSubScore = item->score;
+-	}
+-    }
+-slReverse(&refList);
+-cluster->chrom = itemList->chrom;
+-cluster->chromStart = start;
+-cluster->chromEnd = end;
+-cluster->itemRefList = refList;
+-cluster->score = score;
+-cluster->maxSubScore = maxSubScore;
+-slAddHead(pList, cluster);
+-}
+-
+-struct regCluster *clusterItems(struct lm *lm, struct regItem *itemList, 
+-	double forceJoinScore, double weakLevel)
+-/* Convert a list of items to a list of clusters of items.  This may break up clusters that
+- * have weakly linked parts. 
+-      [                ]
+-      AAAAAAAAAAAAAAAAAA 
+-       BBBBBB   DDDDDD
+-        CCCC     EEEE
+-   gets tranformed into
+-       [    ]   [    ]
+-      AAAAAAAAAAAAAAAAAA 
+-       BBBBBB   DDDDDD
+-        CCCC     EEEE
+-   The strategy is to build a rangeTree of coverage, which might look something like so:
+-      123333211123333211 
+-   then define cluster ends that exceed the minimum limit, which is either 10% of the highest
+-   or forceJoinScore if 10% of the highest is more than forceJoinScore.  This will go to
+-   something like so:
+-        [---]   [----]   
+-   Finally the items that are overlapping a cluster are assigned to it.  Note that this
+-   may mean that an item may be in multiple clusters.
+-        [ABC]   [ ADE]
+- */
+-{
+-int easyMax = round(1.0/weakLevel);
+-int itemCount = slCount(itemList);
+-struct regCluster *clusterList = NULL;
+-if (itemCount < easyMax)
+-    {
+-    struct regItem *item = itemList;
+-    int chromStart = item->chromStart;
+-    int chromEnd = item->chromEnd;
+-    for (item = item->next; item != NULL; item = item->next)
+-        {
+-	if (item->chromStart < chromStart) chromStart = item->chromStart;
+-	if (item->chromEnd > chromEnd) chromEnd = item->chromEnd;
+-	}
+-    addCluster(lm, itemList, chromStart, chromEnd, &clusterList);
+-    }
+-else
+-    {
+-    /* Make up coverage tree. */
+-    struct rbTree *covTree = rangeTreeNew();
+-    struct regItem *item;
+-    for (item = itemList; item != NULL; item = item->next)
+-	rangeTreeAddToCoverageDepth(covTree, item->chromStart, item->chromEnd);
+-    struct range *range, *rangeList = rangeTreeList(covTree);
+-
+-    /* Figure out maximum coverage. */
+-    int maxCov = 0;
+-    for (range = rangeList; range != NULL; range = range->next)
+-        {
+-	int cov = ptToInt(range->val);
+-	if (cov > maxCov) maxCov = cov;
+-	}
+-
+-    /* Figure coverage threshold. */
+-    int threshold = round(maxCov * weakLevel);
+-    if (threshold > forceJoinScore-1) threshold = forceJoinScore-1;
+-
+-    /* Loop through emitting sections over threshold as clusters */
+-    boolean inRange = FALSE;
+-    boolean start = 0, end = 0;
+-    for (range = rangeList; range != NULL; range = range->next)
+-        {
+-	int cov = ptToInt(range->val);
+-	if (cov > threshold)
+-	    {
+-	    if (inRange)
+-	       end = range->end;
+-	    else
+-	       {
+-	       inRange = TRUE;
+-	       start = range->start;
+-	       end = range->end;
+-	       }
+-	    }
+-	else
+-	    {
+-	    if (inRange)
+-		{
+-		addCluster(lm, itemList, start, end, &clusterList);
+-		inRange = FALSE;
+-		}
+-	    }
+-	}
+-    if (inRange)
+-        addCluster(lm, itemList, start, end, &clusterList);
+-    }
+-slReverse(&clusterList);
+-return clusterList;
+-}
+-
+ static int clusterIx = 0;
+ 
+ void outputClustersForChrom(char *chrom, struct rbTree *tree, FILE *fCluster, FILE *fBed)
+@@ -302,13 +60,13 @@ verbose(2, "Got %d ranges on %s\n", slCount(rangeList), chrom);
+ struct lm *lm = lmInit(0);
+ for (range = rangeList; range != NULL; range = range->next)
+     {
+-    struct regCluster *cluster, *clusterList = clusterItems(lm, range->val, 
++    struct peakCluster *cluster, *clusterList = peakClusterItems(lm, range->val, 
+     	clForceJoinScore, clWeakLevel);
+     for (cluster = clusterList; cluster != NULL; cluster = cluster->next)
+         {
+ 	struct slRef *ref, *refList=cluster->itemRefList;
+ 	++clusterIx;
+-	struct regItem *item = refList->val;
++	struct peakItem *item = refList->val;
+ 	struct hash *uniqHash = hashNew(0);
+ 	for (ref = refList; ref != NULL; ref = ref->next)
+ 	    {
+@@ -335,20 +93,17 @@ lmCleanup(&lm);
+ void regCluster(char *tableOfTables, char *outCluster, char *outBed)
+ /* regCluster - Cluster regulator regions. */
+ {
+-struct regSource *source, *sourceList = regSourceLoadAll(tableOfTables, clDims);
++struct peakSource *source, *sourceList = peakSourceLoadAll(tableOfTables, clDims);
+ verbose(1, "Read %d sources from %s\n", slCount(sourceList), tableOfTables);
+-struct hash *chromHash = hashNew(0);
+-struct rbTreeNode *stack[128];
++struct peakClusterMaker *maker = peakClusterMakerNew();
+ for (source = sourceList; source != NULL; source = source->next)
+-    {
+-    clusterSource(source, chromHash, stack);
+-    }
++    peakClusterMakerAddFromSource(maker, source);
+ 
+ /* Get out list of chromosomes and process one at a time. */
+ FILE *fCluster = mustOpen(outCluster, "w");
+ FILE *fBed = mustOpen(outBed, "w");
+-struct hashEl *chrom, *chromList = hashElListHash(chromHash);
+-slSort(&chromList, cmpChromEls);
++struct hashEl *chrom;
++struct hashEl *chromList = peakClusterMakerChromList(maker);
+ int totalClusters = 0;
+ for (chrom = chromList; chrom != NULL; chrom = chrom->next)
+     {
+@@ -357,10 +112,10 @@ for (chrom = chromList; chrom != NULL; chrom = chrom->next)
+     outputClustersForChrom(chrom->name, tree, fCluster, fBed);
+     }
+ verbose(1, "%d singly-linked clusters, %d clusters in %d chromosomes\n", 
+-	totalClusters, clusterIx, chromHash->elCount);
++	totalClusters, clusterIx, maker->chromHash->elCount);
+ carefulClose(&fCluster);
+ carefulClose(&fBed);
+-
++peakClusterMakerFree(&maker);
+ }
+ 
+ int main(int argc, char *argv[])
+diff --git a/src/hg/utils/automation/Encode.pm b/src/hg/utils/automation/Encode.pm
+old mode 100644
+new mode 100755
+diff --git a/src/hg/utils/automation/EnsGeneAutomate.pm b/src/hg/utils/automation/EnsGeneAutomate.pm
+old mode 100644
+new mode 100755
+diff --git a/src/hg/utils/automation/HgDb.pm b/src/hg/utils/automation/HgDb.pm
+old mode 100644
+new mode 100755
diff --git a/lib/dlist.c b/lib/dlist.c
new file mode 100644
index 0000000..3d1f22d
--- /dev/null
+++ b/lib/dlist.c
@@ -0,0 +1,300 @@
+/* dlist.c - Doubly-linked list routines. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+#include "common.h"
+#include "dlist.h"
+
+
+void dlListInit(struct dlList *dl)
+/* Initialize list to be empty */
+{
+dl->head = (struct dlNode *)(&dl->nullMiddle);
+dl->nullMiddle = NULL;
+dl->tail = (struct dlNode *)(&dl->head);
+}
+
+struct dlList *newDlList()
+/* Return a new doubly linked list. */
+{
+struct dlList *dl;
+AllocVar(dl);
+dl->head = (struct dlNode *)(&dl->nullMiddle);
+dl->tail = (struct dlNode *)(&dl->head);
+return dl;
+}
+
+void dlListReset(struct dlList *dl)
+/* Reset a list to the empty state (does not free values)  */
+{
+struct dlNode *node, *next;
+for (node = dl->head; node->next != NULL; node = next)
+    {
+    next = node->next;
+    freeMem(node);
+    }
+dl->head = (struct dlNode *)(&dl->nullMiddle);
+dl->nullMiddle = NULL;
+dl->tail = (struct dlNode *)(&dl->head);
+}
+
+void freeDlList(struct dlList **pList)
+/* Free up a doubly linked list and it's nodes (but not the node values). */
+{
+struct dlList *list = *pList;
+if (list != NULL)
+    {
+    dlListReset(list);
+    freez(pList);
+    }
+}
+
+void freeDlListAndVals(struct dlList **pList)
+/* Free all values in doubly linked list and the list itself.  (Just calls
+ * freeMem on all values. */
+{
+struct dlList *list = *pList;
+if (list != NULL)
+    {
+    struct dlNode *node;
+    for (node = list->head; node->next != NULL; node = node->next)
+        freeMem(node->val);
+    freeDlList(pList);
+    }
+}
+
+
+void dlInsertBetween(struct dlNode *before, struct dlNode *after, struct dlNode *newNode)
+{
+before->next = newNode; 
+newNode->prev = before; 
+newNode->next = after;  
+after->prev = newNode; 
+}
+
+void dlAddBefore(struct dlNode *anchor, struct dlNode *newNode)
+/* Add a node to list before anchor member. */
+{
+dlInsertBetween(anchor->prev, anchor, newNode);
+}
+
+void dlAddAfter(struct dlNode *anchor, struct dlNode *newNode)
+/* Add a node to list after anchor member. */
+{
+dlInsertBetween(anchor, anchor->next, newNode);
+}
+
+void dlAddHead(struct dlList *list, struct dlNode *newNode)
+/* Add a node to head of list. */
+{
+struct dlNode *head = list->head;
+dlInsertBetween(head->prev, head, newNode);
+}
+
+void dlAddTail(struct dlList *list, struct dlNode *newNode)
+/* Add a node to tail of list. */
+{
+struct dlNode *tail = list->tail;
+dlInsertBetween(tail, tail->next, newNode);
+}
+
+struct dlNode *dlAddValBefore(struct dlNode *anchor, void *val)
+/* Create a node containing val and add to list before anchor member. */
+{
+struct dlNode *node = AllocA(struct dlNode);
+node->val = val;
+dlAddBefore(anchor, node);
+return node;
+}
+
+struct dlNode *dlAddValAfter(struct dlNode *anchor, void *val)
+/* Create a node containing val and add to list after anchor member. */
+{
+struct dlNode *node = AllocA(struct dlNode);
+node->val = val;
+dlAddAfter(anchor, node);
+return node;
+}
+
+struct dlNode *dlAddValHead(struct dlList *list, void *val)
+/* Create a node containing val and add to head of list. */
+{
+struct dlNode *node = AllocA(struct dlNode);
+node->val = val;
+dlAddHead(list, node);
+return node;
+}
+
+struct dlNode *dlAddValTail(struct dlList *list, void *val)
+/* Create a node containing val and add to tail of list. */
+{
+struct dlNode *node = AllocA(struct dlNode);
+node->val = val;
+dlAddTail(list, node);
+return node;
+}
+
+void dlRemove(struct dlNode *node)
+/* Removes a node from list. Node is not freed. */
+{
+struct dlNode *before = node->prev;
+struct dlNode *after = node->next;
+before->next = after;
+after->prev = before;
+node->prev = NULL;
+node->next = NULL;
+}
+
+void dlRemoveHead(struct dlList *list)
+/* Removes head from list. Node is not freed. */
+{
+dlRemove(list->head);
+}
+
+void dlRemoveTail(struct dlList *list)
+/* Remove tail from list. Node is not freed. */
+{
+dlRemove(list->tail);
+}
+
+struct dlNode *dlPopHead(struct dlList *list)
+/* Remove first node from list and return it. */
+{
+struct dlNode *node = list->head;
+if (node->next == NULL)
+    return NULL;
+dlRemove(node);
+return node;
+}
+
+struct dlNode *dlPopTail(struct dlList *list)
+/* Remove last node from list and return it. */
+{
+struct dlNode *node = list->tail;
+if (node->prev == NULL)
+    return NULL;
+dlRemove(node);
+return node;
+}
+
+void dlDelete(struct dlNode **nodePtr)
+/* Removes a node from list and frees it. */
+{
+struct dlNode *node = *nodePtr;
+if (node != NULL)
+    {
+    dlRemove(node);
+    freeMem(node);
+    }
+}
+
+int dlCount(struct dlList *list)
+/* Return length of list. */
+{
+return slCount(list->head) - 1;
+}
+
+
+struct dlSorter 
+/* Helper structure for sorting dlNodes preserving order */
+    {
+    struct dlNode *node;
+    };
+
+static int (*compareFunc)(const void *elem1, const void *elem2);
+/* Node comparison pointer, just used by dlSortNodes and helpers. */
+
+static int dlNodeCmp(const void *elem1, const void *elem2)
+/* Compare two dlSorters indirectly, by calling compareFunc. */
+{
+struct dlSorter *a = (struct dlSorter *)elem1;
+struct dlSorter *b = (struct dlSorter *)elem2;
+return compareFunc(&a->node->val, &b->node->val);
+}
+    
+void dlSort(struct dlList *list, 
+	int (*compare )(const void *elem1,  const void *elem2))
+/* Sort a singly linked list with Qsort and a temporary array. 
+ * The arguments to the compare function in real, non-void, life
+ * are pointers to pointers of the type that is in the val field of 
+ * the nodes of the list. */
+{
+int len = dlCount(list);
+
+if (len > 1)
+    {
+    /* Move val's onto an array, sort, and then put back into list. */
+    struct dlSorter *sorter = needLargeMem(len * sizeof(sorter[0])), *s;
+    struct dlNode *node;
+    int i;
+
+    for (i=0, node = list->head; i<len; ++i, node = node->next)
+	{
+	s = &sorter[i];
+	s->node = node;
+	}
+    compareFunc = compare;
+    qsort(sorter, len, sizeof(sorter[0]), dlNodeCmp);
+    dlListInit(list);
+    for (i=0; i<len; ++i)
+	dlAddTail(list, sorter[i].node);
+    freeMem(sorter);
+    }
+}
+
+
+boolean dlEmpty(struct dlList *list)
+/* Return TRUE if list is empty. */
+{
+return dlIsEmpty(list);
+}
+
+struct dlNode *dlGetBeforeHead(struct dlList *list)
+/* Get the node before the head of the list */
+{
+if (dlEmpty(list))
+    return list->head;
+else
+    return list->head->prev;
+}
+
+struct dlNode *dlGetAfterTail(struct dlList *list)
+/* Get the node after the tail of the list */
+{
+if (dlEmpty(list))
+    return list->tail;
+else
+    return list->tail->next;
+}
+
+void *dlListToSlList(struct dlList *dList)
+/* Return slList from dlList. */
+{
+struct slList *list = NULL, *el;
+struct dlNode *node;
+
+for (node = dList->tail; node->prev != NULL; node = node->prev)
+    {
+    el = node->val;
+    slAddHead(&list, el);
+    }
+return list;
+}
+
+void dlCat(struct dlList *a, struct dlList *b)
+/* Move items from b to end of a. */
+{
+struct dlNode *node;
+while ((node = dlPopHead(b)) != NULL)
+    dlAddTail(a, node);
+}
+
+struct dlNode *dlValInList(struct dlList *list, void *val)
+/* Return node on list if any that has associated val. */
+{
+struct dlNode *node;
+for (node = list->head; !dlEnd(node); node = node->next)
+    if (node->val == val)
+        return node;
+return NULL;
+}
diff --git a/lib/dnaLoad.c b/lib/dnaLoad.c
new file mode 100644
index 0000000..f3a24d8
--- /dev/null
+++ b/lib/dnaLoad.c
@@ -0,0 +1,300 @@
+/* dnaLoad - Load dna from a variaty of file formats. */
+
+#include "common.h"
+#include "dnaseq.h"
+#include "fa.h"
+#include "twoBit.h"
+#include "nib.h"
+#include "dnaLoad.h"
+
+
+struct dnaLoadStack
+/* Keep track of a single DNA containing file. */
+    {
+    struct dnaLoadStack *next;	/* Next in list. */
+    struct twoBitFile *twoBit; /* Two bit file if any. */
+    struct twoBitIndex *tbi;	 /* Next twoBit sequence. */
+    struct lineFile *textFile;	/* Text file if any. */
+    boolean textIsFa;		/* True if text is in fasta format. */
+    };
+
+struct dnaLoad
+/* A structure to help us load DNA from files - mixed case
+ * from either .fa, .nib, or .2bit files */
+    {
+    struct dnaLoad *next;	/* Next loader in list. */
+    char *topFileName;		/* Highest level file name. */
+    boolean finished;		/* Set to TRUE at end. */
+    struct dnaLoadStack *stack;	/* Stack of files we're working on. */
+    int curStart;		/* Start offset within current parent sequence. */
+    int curEnd;			/* End offset  within current parent sequence. */
+    int curSize;		/* Size of current parent sequence. */
+    };
+
+struct dnaLoadStack *dnaLoadStackNew(char *fileName)
+/* Create new dnaLoadStack on composite file. */
+{
+struct dnaLoadStack *dls;
+AllocVar(dls);
+if (twoBitIsFile(fileName))
+    {
+    dls->twoBit = twoBitOpen(fileName);
+    dls->tbi = dls->twoBit->indexList;
+    }
+else
+    {
+    char *line;
+    dls->textFile = lineFileOpen(fileName, TRUE);
+    if (lineFileNextReal(dls->textFile, &line))
+        {
+	line = trimSpaces(line);
+	if (line[0] == '>')
+	    dls->textIsFa = TRUE;
+	lineFileReuse(dls->textFile);
+	}
+    }
+return dls;
+}
+
+void dnaLoadStackFree(struct dnaLoadStack **pDls)
+/* free up resources associated with dnaLoadStack. */
+{
+struct dnaLoadStack *dls = *pDls;
+if (dls != NULL)
+    {
+    lineFileClose(&dls->textFile);
+    twoBitClose(&dls->twoBit);
+    freez(pDls);
+    }
+}
+
+void dnaLoadStackFreeList(struct dnaLoadStack **pList)
+/* Free a list of dynamically allocated dnaLoadStack's */
+{
+struct dnaLoadStack *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    dnaLoadStackFree(&el);
+    }
+*pList = NULL;
+}
+
+void dnaLoadClose(struct dnaLoad **pDl)
+/* Free up resources associated with dnaLoad. */
+{
+struct dnaLoad *dl = *pDl;
+if (dl != NULL)
+    {
+    dnaLoadStackFreeList(&dl->stack);
+    freeMem(dl->topFileName);
+    freez(pDl);
+    }
+}
+
+struct dnaLoad *dnaLoadOpen(char *fileName)
+/* Return new DNA loader.  Call dnaLoadNext() on this until
+ * you get a NULL return, then dnaLoadClose(). */
+{
+struct dnaLoad *dl;
+AllocVar(dl);
+dl->topFileName = cloneString(fileName);
+return dl;
+}
+
+struct dnaSeq *dnaLoadSingle(char *fileName, int *retStart, int *retEnd, int *retParentSize)
+/* Return sequence if it's a nib file or 2bit part, NULL otherwise. */
+{
+struct dnaSeq *seq = NULL;
+unsigned start = 0, end = 0;
+int parentSize = 0;
+if (nibIsFile(fileName))
+    {
+    /* Save offset out of fileName for auto-lifting */
+    char filePath[PATH_LEN];
+    char name[PATH_LEN];
+    nibParseName(0, fileName, filePath, name, &start, &end);
+
+    if (end != 0)	/* It's just a range. */
+        {
+	FILE *f;
+	int size;
+	nibOpenVerify(filePath, &f, &size);
+	parentSize = size;
+	}
+    seq =  nibLoadAllMasked(NIB_MASK_MIXED, fileName);
+    if (end == 0)
+         parentSize = end = seq->size;
+    freez(&seq->name);
+    seq->name = cloneString(name);
+    }
+else if (twoBitIsRange(fileName))
+    {
+    /* Save offset out of fileName for auto-lifting */
+    char *rangeSpec = cloneString(fileName);
+    int start, end;
+    char *file, *seqName;
+    twoBitParseRange(rangeSpec, &file, &seqName, &start, &end);
+
+    /* Load sequence. */
+        {
+	struct twoBitFile *tbf = twoBitOpen(file);
+	parentSize = twoBitSeqSize(tbf, seqName);
+	seq = twoBitReadSeqFrag(tbf, seqName, start, end);
+	twoBitClose(&tbf);
+	}
+    if (end == 0)
+        end = seq->size;
+    freez(&rangeSpec);
+    }
+if (retStart != NULL)
+    *retStart = start;
+if (retEnd != NULL)
+    *retEnd = end;
+if (retParentSize != NULL)
+    *retParentSize = parentSize;
+return seq;
+}
+
+static struct dnaSeq *dnaLoadNextFromStack(struct dnaLoad *dl)
+/* Load next piece of DNA from stack of files.  Return NULL
+ * when stack is empty. */
+{
+struct dnaLoadStack *dls;
+struct dnaSeq *seq = NULL;
+while ((dls = dl->stack) != NULL)
+    {
+    if (dls->twoBit)
+        {
+	if (dls->tbi != NULL)
+	    {
+	    seq = twoBitReadSeqFrag(dls->twoBit, dls->tbi->name, 0, 0);
+	    dls->tbi = dls->tbi->next;
+	    return seq;
+	    }
+	else
+	    {
+	    dl->stack = dls->next;
+	    dnaLoadStackFree(&dls);
+	    }
+	}
+    else if (dls->textIsFa)
+        {
+	DNA *dna;
+	char *name;
+	int size;
+	if (faMixedSpeedReadNext(dls->textFile, &dna, &size, &name))
+	    {
+	    AllocVar(seq);
+	    seq->dna = needLargeMem(size+1);
+	    memcpy((void *)seq->dna, (void *)dna, size);
+	    seq->dna[size] = 0;
+	    seq->size = size;
+	    seq->name = cloneString(name);
+	    dl->curStart = 0;
+	    dl->curEnd = size;
+	    dl->curSize = size;
+	    return seq;
+	    }
+	else
+	    {
+	    dl->stack = dls->next;
+	    dnaLoadStackFree(&dls);
+	    }
+	}
+    else	/* It's a file full of file names. */
+        {
+	char *line;
+	if (lineFileNextReal(dls->textFile, &line))
+	    {
+	    line  = trimSpaces(line);
+	    if ((seq = dnaLoadSingle(line, &dl->curStart, &dl->curEnd, &dl->curSize)) != NULL)
+	         return seq;
+	    else
+	         {
+		 struct dnaLoadStack *newDls;
+		 newDls = dnaLoadStackNew(line);
+		 slAddHead(&dl->stack, newDls);
+		 }
+	    }
+	else
+	    {
+	    dl->stack = dls->next;
+	    dnaLoadStackFree(&dls);
+	    }
+	}
+    }
+dl->finished = TRUE;
+return NULL;
+}
+
+static struct dnaSeq *dnaLoadStackOrSingle(struct dnaLoad *dl)
+/* Return next dna sequence. */
+{
+struct dnaSeq *seq = NULL;
+if (dl->finished)
+    return NULL;
+if (dl->stack == NULL)
+    {
+    if ((seq = dnaLoadSingle(dl->topFileName, &dl->curStart, &dl->curEnd, &dl->curSize)) != NULL)
+	{
+	dl->finished = TRUE;
+	return seq;
+	}
+    dl->stack = dnaLoadStackNew(dl->topFileName);
+    }
+return dnaLoadNextFromStack(dl);
+}
+
+struct dnaSeq *dnaLoadNext(struct dnaLoad *dl)
+/* Return next dna sequence. */
+{
+struct dnaSeq *seq;
+dl->curSize = dl->curStart = dl->curEnd = 0;
+seq = dnaLoadStackOrSingle(dl);
+return seq;
+}
+
+struct dnaSeq *dnaLoadAll(char *fileName)
+/* Return list of all DNA referenced in file.  File
+ * can be either a single fasta file, a single .2bit
+ * file, a .nib file, or a text file containing
+ * a list of the above files. DNA is mixed case. */
+{
+struct dnaLoad *dl = dnaLoadOpen(fileName);
+struct dnaSeq *seqList = NULL, *seq;
+while ((seq = dnaLoadNext(dl)) != NULL)
+    {
+    slAddHead(&seqList, seq);
+    }
+dnaLoadClose(&dl);
+slReverse(&seqList);
+return seqList;
+}
+
+int dnaLoadCurStart(struct dnaLoad *dl)
+/* Returns the start offset of current sequence within a larger
+ * sequence.  Useful for programs that want to auto-lift
+ * nib and 2bit fragments.  Please call only after a
+ * sucessful dnaLoadNext. */
+{
+return dl->curStart;
+}
+
+int dnaLoadCurEnd(struct dnaLoad *dl)
+/* Returns the end offset of current sequence within a larger
+ * sequence.  Useful for programs that want to auto-lift
+ * nib and 2bit fragments.  Please call only after a
+ * sucessful dnaLoadNext. */
+{
+return dl->curEnd;
+}
+
+int dnaLoadCurSize(struct dnaLoad *dl)
+/* Returns the size of the parent sequence.  Useful for
+ * auto-lift programs.  Please call only after dnaLoadNext. */
+{
+return dl->curSize;
+}
+
diff --git a/lib/dnaMarkov.c b/lib/dnaMarkov.c
new file mode 100644
index 0000000..5d8d6d2
--- /dev/null
+++ b/lib/dnaMarkov.c
@@ -0,0 +1,239 @@
+/* dnaMarkov - stuff to build 1st, 2nd, 3rd, and coding
+ * 3rd degree Markov models for DNA. */
+
+#include "common.h"
+#include "dnautil.h"
+#include "dnaseq.h"
+#include "slog.h"
+#include "dnaMarkov.h"
+
+
+void dnaMark0(struct dnaSeq *seqList, double mark0[5], int slogMark0[5])
+/* Figure out frequency of bases in input.  Results go into
+ * mark0 and optionally in scaled log form into slogMark0.
+ * Order is N, T, C, A, G.  (TCAG is our normal order) */
+{
+struct dnaSeq *seq;
+int histo[4];
+int oneHisto[4];
+double total;
+int i;
+double *freq = mark0+1;
+
+zeroBytes(histo, sizeof(histo));
+for (seq = seqList; seq != NULL; seq = seq->next)
+    {
+    dnaBaseHistogram(seq->dna, seq->size, oneHisto);
+    for (i=0; i<4; ++i)
+        histo[i] += oneHisto[i];
+    }
+total = histo[0] + histo[1] + histo[2] + histo[3];
+freq[-1] = 1.0;
+for (i=0; i<4; ++i)
+    freq[i] = (double)histo[i] / total;
+if (slogMark0 != NULL)
+    {
+    int *slogFreq = slogMark0 + 1;
+    slogFreq[-1] = 0;
+    for (i=0; i<4; ++i)
+	slogFreq[i] = slog(freq[i]);
+    }
+}
+
+
+void dnaMark1(struct dnaSeq *seqList, double mark0[5], int slogMark0[5], 
+	double mark1[5][5], int slogMark1[5][5])
+/* Make up 1st order Markov model - probability that one nucleotide
+ * will follow another. Input is sequence and 0th order Markov models.
+ * Output is first order Markov model. slogMark1 can be NULL. */
+{
+struct dnaSeq *seq;
+DNA *dna, *endDna;
+int i,j;
+int histo[5][5];
+int hist1[5];
+
+zeroBytes(histo, sizeof(histo));
+zeroBytes(hist1, sizeof(hist1));
+for (seq = seqList; seq != NULL; seq = seq->next)
+    {
+    dna = seq->dna;
+    endDna = dna + seq->size-1;
+    for (;dna < endDna; ++dna)
+        {
+        i = ntVal[(int)dna[0]];
+        j = ntVal[(int)dna[1]];
+        hist1[i+1] += 1;
+        histo[i+1][j+1] += 1;
+        }
+    }
+for (i=0; i<5; ++i)
+    {
+    for (j=0; j<5; ++j)
+        {
+        double mark1Val;
+        int matVal = histo[i][j] + 1;
+        mark1Val = ((double)matVal)/(hist1[i]+5);
+        mark1[i][j] = mark1Val;
+	if (slogMark1 != NULL)
+	    slogMark1[i][j] = slog(mark1Val);
+        }
+    }
+for (i=0; i<5; ++i)
+    {
+    mark1[i][0] = 1;
+    mark1[0][i] = mark0[i];
+    if (slogMark1 != NULL)
+	{
+	slogMark1[i][0] = 0;
+	slogMark1[0][i] = slogMark0[i];
+	}
+    }
+}
+
+void dnaMarkTriple(struct dnaSeq *seqList, 
+    double mark0[5], int slogMark0[5],
+    double mark1[5][5], int slogMark1[5][5],
+    double mark2[5][5][5], int slogMark2[5][5][5],
+    int offset, int advance, int earlyEnd)
+/* Make up a table of how the probability of a nucleotide depends on the previous two.
+ * Depending on offset and advance parameters this could either be a straight 2nd order
+ * Markov model, or a model for a particular coding frame. */
+{
+struct dnaSeq *seq;
+DNA *dna, *endDna;
+int i,j,k;
+int histo[5][5][5];
+int hist2[5][5];
+int total = 0;
+zeroBytes(histo, sizeof(histo));
+zeroBytes(hist2, sizeof(hist2));
+for (seq = seqList; seq != NULL; seq = seq->next)
+    {
+    dna = seq->dna;
+    endDna = dna + seq->size - earlyEnd - 2;
+    dna += offset;
+    for (;dna < endDna; dna += advance)
+        {
+        i = ntVal[(int)dna[0]];
+        j = ntVal[(int)dna[1]];
+        k = ntVal[(int)dna[2]];
+        hist2[i+1][j+1] += 1;
+        histo[i+1][j+1][k+1] += 1;
+        total += 1;
+        }
+    }
+for (i=0; i<5; ++i)
+    {
+    for (j=0; j<5; ++j)
+        {
+        for (k=0; k<5; ++k)
+            {
+            double markVal;
+            int matVal = histo[i][j][k]+1;
+            if (i == 0 || j == 0 || k == 0)
+                {
+                if (k == 0)
+                    {
+                    mark2[i][j][k] = 1;
+		    if (slogMark2 != NULL)
+			slogMark2[i][j][k] = 0;
+                    }
+                else if (j == 0)
+                    {
+                    mark2[i][j][k] = mark0[k];
+		    if (slogMark2 != NULL)
+			slogMark2[i][j][k] = slogMark0[k];
+                    }
+                else if (i == 0)
+                    {
+                    mark2[i][j][k] = mark1[j][k];
+		    if (slogMark2 != NULL)
+			slogMark2[i][j][k] = slogMark1[j][k];
+                    }
+                }
+            else
+                {
+                markVal = ((double)matVal)/(hist2[i][j]+5);
+                mark2[i][j][k] = markVal;
+		if (slogMark2 != NULL)
+		    slogMark2[i][j][k] = slog(markVal);
+                }
+            }
+        }
+    }
+}
+
+void dnaMark2(struct dnaSeq *seqList, double mark0[5], int slogMark0[5],
+	double mark1[5][5], int slogMark1[5][5],
+	double mark2[5][5][5], int slogMark2[5][5][5])
+/* Make up 1st order Markov model - probability that one nucleotide
+ * will follow the previous two. */
+{
+dnaMarkTriple(seqList, mark0, slogMark0, mark1, slogMark1, 
+	mark2, slogMark2, 0, 1, 0);
+}
+
+#define SIG 10
+
+char *dnaMark2Serialize(double mark2[5][5][5])
+// serialize a 2nd order markov model
+{
+int i, j, k;
+int offset = 0;
+char *buf = NULL;
+int bufLen = 5*5*5 * (SIG + 3) + 1;
+buf = needMem(bufLen);
+for(i = 0; i < 5; i++)
+    for(j = 0; j < 5; j++)
+        for(k = 0; k < 5; k++)
+            {
+            if(offset)
+                {
+                sprintf(buf + offset, ";%1.*f", SIG, mark2[i][j][k]);
+                offset += (SIG + 3);
+                }
+            else
+                {
+                sprintf(buf + offset, "%1.*f", SIG, mark2[i][j][k]);
+                offset += (SIG + 2);
+                }
+            }
+buf[offset] = 0;
+return buf;
+}
+
+void dnaMark2Deserialize(char *buf, double mark2[5][5][5])
+// deserialize a 2nd order markov model
+{
+int i, j, k;
+int offset = 0;
+for(i = 0; i < 5; i++)
+    for(j = 0; j < 5; j++)
+        for(k = 0; k < 5; k++)
+            {
+            float f;
+            if(offset)
+                {
+                sscanf(buf + offset, ";%f", &f);
+                mark2[i][j][k] = f;
+                offset += (SIG + 3);
+                }
+            else
+                {
+                sscanf(buf + offset, "%f", &f);
+                mark2[i][j][k] = f;
+                offset += (SIG + 2);
+                }
+            }
+}
+
+void dnaMarkMakeLog2(double mark2[5][5][5])
+// convert a 2nd-order markov array to log2
+{
+int i, j, k;
+for(i = 0; i < 5; i++)
+    for(j = 0; j < 5; j++)
+        for(k = 0; k < 5; k++)
+            mark2[i][j][k] = logBase2(mark2[i][j][k]);
+}
diff --git a/lib/dnaMotif.c b/lib/dnaMotif.c
new file mode 100644
index 0000000..042e7b9
--- /dev/null
+++ b/lib/dnaMotif.c
@@ -0,0 +1,628 @@
+/* dnaMotif.c was originally generated by the autoSql program, which also 
+ * generated dnaMotif.h and dnaMotif.sql.  This module links the database and
+ * the RAM representation of objects. */
+
+#include "common.h"
+#include "linefile.h"
+#include "sqlList.h"
+#include "dystring.h"
+#include "dnaMotif.h"
+#include "portable.h"
+
+
+struct dnaMotif *dnaMotifCommaIn(char **pS, struct dnaMotif *ret)
+/* Create a dnaMotif out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new dnaMotif */
+{
+char *s = *pS;
+int i;
+
+if (ret == NULL)
+    AllocVar(ret);
+ret->name = sqlStringComma(&s);
+ret->columnCount = sqlSignedComma(&s);
+s = sqlEatChar(s, '{');
+AllocArray(ret->aProb, ret->columnCount);
+for (i=0; i<ret->columnCount; ++i)
+    {
+    ret->aProb[i] = sqlSignedComma(&s);
+    }
+s = sqlEatChar(s, '}');
+s = sqlEatChar(s, ',');
+s = sqlEatChar(s, '{');
+AllocArray(ret->cProb, ret->columnCount);
+for (i=0; i<ret->columnCount; ++i)
+    {
+    ret->cProb[i] = sqlSignedComma(&s);
+    }
+s = sqlEatChar(s, '}');
+s = sqlEatChar(s, ',');
+s = sqlEatChar(s, '{');
+AllocArray(ret->gProb, ret->columnCount);
+for (i=0; i<ret->columnCount; ++i)
+    {
+    ret->gProb[i] = sqlSignedComma(&s);
+    }
+s = sqlEatChar(s, '}');
+s = sqlEatChar(s, ',');
+s = sqlEatChar(s, '{');
+AllocArray(ret->tProb, ret->columnCount);
+for (i=0; i<ret->columnCount; ++i)
+    {
+    ret->tProb[i] = sqlSignedComma(&s);
+    }
+s = sqlEatChar(s, '}');
+s = sqlEatChar(s, ',');
+*pS = s;
+return ret;
+}
+
+void dnaMotifFree(struct dnaMotif **pEl)
+/* Free a single dynamically allocated dnaMotif such as created
+ * with dnaMotifLoad(). */
+{
+struct dnaMotif *el;
+
+if ((el = *pEl) == NULL) return;
+freeMem(el->name);
+freeMem(el->aProb);
+freeMem(el->cProb);
+freeMem(el->gProb);
+freeMem(el->tProb);
+freez(pEl);
+}
+
+void dnaMotifFreeList(struct dnaMotif **pList)
+/* Free a list of dynamically allocated dnaMotif's */
+{
+struct dnaMotif *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    dnaMotifFree(&el);
+    }
+*pList = NULL;
+}
+
+void dnaMotifOutput(struct dnaMotif *el, FILE *f, char sep, char lastSep) 
+/* Print out dnaMotif.  Separate fields with sep. Follow last field with lastSep. */
+{
+int i;
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->name);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%d", el->columnCount);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->columnCount; ++i)
+    {
+    fprintf(f, "%f", el->aProb[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->columnCount; ++i)
+    {
+    fprintf(f, "%f", el->cProb[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->columnCount; ++i)
+    {
+    fprintf(f, "%f", el->gProb[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->columnCount; ++i)
+    {
+    fprintf(f, "%f", el->tProb[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+fputc(lastSep,f);
+}
+
+float dnaMotifSequenceProb(struct dnaMotif *motif, DNA *dna)
+/* Return probability of dna according to motif.  Make sure
+ * motif is probabalistic (with call to dnaMotifMakeProbabalistic
+ * if you're not sure) before calling this. */
+{
+float p = 1.0;
+int i;
+for (i=0; i<motif->columnCount; ++i)
+    {
+    switch (dna[i])
+        {
+	case 'a':
+	case 'A':
+	    p *= motif->aProb[i];
+	    break;
+	case 'c':
+	case 'C':
+	    p *= motif->cProb[i];
+	    break;
+	case 'g':
+	case 'G':
+	    p *= motif->gProb[i];
+	    break;
+	case 't':
+	case 'T':
+	    p *= motif->tProb[i];
+	    break;
+	case 0:
+	    warn("dna shorter than motif");
+	    internalErr();
+	    break;
+	default:
+	    p *= 0.25;
+	    break;
+	}
+    }
+return p;
+}
+
+static float dnaMotifSequenceProbWithMark0(struct dnaMotif *motif, DNA *dna, double mark0[5])
+{
+float p = 1.0;
+int i;
+for (i=0; i<motif->columnCount; ++i)
+    {
+    int val = ntVal[(int) dna[i]] + 1;
+    p *= (mark0[val]/mark0[0]);
+    }
+return p;
+}
+
+static float dnaMotifSequenceProbLog(struct dnaMotif *motif, DNA *dna)
+{
+float p = 0;
+int i;
+for (i=0; i<motif->columnCount; ++i)
+    {
+    switch (dna[i])
+        {
+	case 'a':
+	case 'A':
+	    p += motif->aProb[i];
+	    break;
+	case 'c':
+	case 'C':
+	    p += motif->cProb[i];
+	    break;
+	case 'g':
+	case 'G':
+	    p += motif->gProb[i];
+	    break;
+	case 't':
+	case 'T':
+	    p += motif->tProb[i];
+	    break;
+	case 0:
+	    warn("dna shorter than motif");
+	    internalErr();
+	    break;
+	default:
+	    p += logBase2(0.25);
+	    break;
+	}
+    }
+return p;
+}
+
+char dnaMotifBestStrand(struct dnaMotif *motif, DNA *dna)
+/* Figure out which strand of DNA is better for probabalistic motif. */
+{
+float fScore, rScore;
+fScore = dnaMotifSequenceProb(motif, dna);
+reverseComplement(dna, motif->columnCount);
+rScore = dnaMotifSequenceProb(motif, dna);
+reverseComplement(dna, motif->columnCount);
+if (fScore >= rScore)
+    return '+';
+else
+    return '-';
+}
+
+double dnaMotifBitScore(struct dnaMotif *motif, DNA *dna)
+/* Return logBase2-odds score of dna given a probabalistic motif. */
+{
+double p = dnaMotifSequenceProb(motif, dna);
+double q = pow(0.25, motif->columnCount);
+double odds = p/q;
+return logBase2(odds);
+}
+
+double dnaMotifBitScoreWithMark0Bg(struct dnaMotif *motif, DNA *dna, double mark0[5])
+/* Return logBase2-odds score of dna given a probabalistic motif and using a 0-order markov model for the background. */
+{
+double p = dnaMotifSequenceProb(motif, dna);
+double q = dnaMotifSequenceProbWithMark0(motif, dna, mark0);
+double odds = p/q;
+return logBase2(odds);
+}
+
+double dnaMotifBitScoreWithMarkovBg(struct dnaMotif *motif, DNA *dna, double mark2[5][5][5])
+/* Return logBase2-odds score of dna given a probabalistic motif using a 2nd-order markov model for the background.
+   motif and markd2 must be in log2 format.
+   Seq must contain an extra two bases at the front (i.e. we start scoring from dna + 2). */
+{
+double p = dnaMotifSequenceProbLog(motif, dna + 2);
+double q = 0;
+int i, index;
+// XXXX assert somehow that length(dna) == motif->columnCount + 2?
+dnaUtilOpen();
+for(i = 0, index = 2; i < motif->columnCount; i++, index++)
+    {
+    double tmp = mark2[ntVal5[(int) dna[index - 2]] + 1][ntVal5[(int) dna[index - 1]] + 1][ntVal5[(int) dna[index]] + 1];
+#if 0
+    char buf[4];
+    safencpy(buf, sizeof(buf), dna + index - 2, 3);
+    fprintf(stderr, "%s: tmp: %.6f\n", buf, tmp);
+#endif
+    q += tmp;
+    }
+return p - q;
+}
+
+
+void dnaMotifMakeLog2(struct dnaMotif *motif)
+{
+int i;
+for (i = 0; i < motif->columnCount; i++)
+    {
+    motif->aProb[i] = logBase2(motif->aProb[i]);
+    motif->cProb[i] = logBase2(motif->cProb[i]);
+    motif->gProb[i] = logBase2(motif->gProb[i]);
+    motif->tProb[i] = logBase2(motif->tProb[i]);
+    }
+}
+
+void dnaMotifNormalize(struct dnaMotif *motif)
+/* Make all columns of motif sum to one. */
+{
+int i;
+for (i=0; i<motif->columnCount; ++i)
+    {
+    float sum = motif->aProb[i] + motif->cProb[i] + motif->gProb[i] + motif->tProb[i];
+    if (sum < 0)
+        errAbort("%s has negative numbers, perhaps it's score not probability based", 
+		motif->name);
+    if (sum == 0)
+         motif->aProb[i] = motif->cProb[i] = motif->gProb[i] = motif->tProb[i] = 0.25;
+    motif->aProb[i] /= sum;
+    motif->cProb[i] /= sum;
+    motif->gProb[i] /= sum;
+    motif->tProb[i] /= sum;
+    }
+}
+
+boolean dnaMotifIsScoreBased(struct dnaMotif *motif)
+/* Return TRUE if dnaMotif is score-based (which we decide by
+ * the presense of negative values. */
+{
+int i;
+for (i=0; i<motif->columnCount; ++i)
+    {
+    if (motif->aProb[i] < 0) return TRUE;
+    if (motif->cProb[i] < 0) return TRUE;
+    if (motif->gProb[i] < 0) return TRUE;
+    if (motif->tProb[i] < 0) return TRUE;
+    }
+return FALSE;
+}
+
+void dnaMotifScoreToProb(struct dnaMotif *motif)
+/* Convert motif that is log-odds score based to motif
+ * that is probability based.  This assumes that the
+ * background distribution is simple: 25% for each base */
+{
+int i;
+for (i=0; i<motif->columnCount; ++i)
+    {
+    motif->aProb[i] = exp(motif->aProb[i]);
+    motif->cProb[i] = exp(motif->cProb[i]);
+    motif->gProb[i] = exp(motif->gProb[i]);
+    motif->tProb[i] = exp(motif->tProb[i]);
+    }
+dnaMotifNormalize(motif);
+}
+
+void dnaMotifMakeProbabalistic(struct dnaMotif *motif)
+/* Change motif, which may be score or count based, to 
+ * probabalistic one, where each column adds to 1.0 */
+{
+if (dnaMotifIsScoreBased(motif))
+    dnaMotifScoreToProb(motif);
+else
+    dnaMotifNormalize(motif);
+}
+
+static void printProbRow(FILE *f, char *label, float *p, int pCount)
+/* Print one row of a probability profile. */
+{
+int i;
+fprintf(f, "%s ", label);
+for (i=0; i < pCount; ++i)
+    fprintf(f, "%5.2f ", p[i]);
+printf("\n");
+}
+
+void dnaMotifPrintProb(struct dnaMotif *motif, FILE *f)
+/* Print DNA motif probabilities. */
+{
+printProbRow(f, "A", motif->aProb, motif->columnCount);
+printProbRow(f, "C", motif->cProb, motif->columnCount);
+printProbRow(f, "G", motif->gProb, motif->columnCount);
+printProbRow(f, "T", motif->tProb, motif->columnCount);
+}
+
+
+static double u1(double prob)
+/* Calculate partial uncertainty for one base. */
+{
+if (prob == 0)
+    return 0;
+return prob * logBase2(prob);
+}
+
+static double uncertainty(struct dnaMotif *motif, int pos)
+/* Return the uncertainty at pos of motif.  This corresponds
+ * to the H function in logo.pm */
+{
+return -( u1(motif->aProb[pos]) + u1(motif->cProb[pos])
+	+ u1(motif->gProb[pos]) +u1(motif->tProb[pos]) );
+}
+
+double dnaMotifBitsOfInfo(struct dnaMotif *motif, int pos)
+/* Return bits of information at position. */
+{
+if (pos > motif->columnCount || pos < 0)
+    internalErr();
+return 2 - uncertainty(motif, pos);
+}
+
+struct letterProb
+/* A letter tied to a probability. */
+    {
+    struct letterProb *next;
+    double prob;	/* Probability for this letter. */
+    char letter;	/* The letter (upper case) */
+    };
+
+static struct letterProb *letterProbNew(char letter, double prob)
+/* Make a new letterProb. */
+{
+struct letterProb *lp;
+AllocVar(lp);
+lp->letter = letter;
+lp->prob = prob;
+return lp;
+}
+
+static int letterProbCmp(const void *va, const void *vb)
+/* Compare to sort highest probability first. */
+{
+const struct letterProb *a = *((struct letterProb **)va);
+const struct letterProb *b = *((struct letterProb **)vb);
+double dif = a->prob - b->prob;
+if (dif < 0)
+   return -1;
+else if (dif > 0)
+   return 1;
+else
+   return 0;
+}
+
+static void addBaseProb(struct letterProb **pList, char letter, double prob)
+/* If prob > 0 add letterProb to list. */
+{
+if (prob > 0)
+    {
+    struct letterProb *lp = letterProbNew(letter, prob);
+    slAddHead(pList, lp);
+    }
+}
+
+static struct letterProb *letterProbFromMotifColumn(struct dnaMotif *motif, int pos)
+/* Return letterProb list corresponding to column of motif. */
+{
+struct letterProb *lpList = NULL;
+addBaseProb(&lpList, 'A', motif->aProb[pos]);
+addBaseProb(&lpList, 'C', motif->cProb[pos]);
+addBaseProb(&lpList, 'G', motif->gProb[pos]);
+addBaseProb(&lpList, 'T', motif->tProb[pos]);
+slSort(&lpList, letterProbCmp);
+return lpList;
+}
+
+static void psOneColumn(struct dnaMotif *motif, int pos,
+    double xStart, double yStart, double width, double totalHeight,
+    FILE *f)
+/* Write one column of logo to postScript. */
+{
+struct letterProb *lp, *lpList = letterProbFromMotifColumn(motif, pos);
+double x = xStart, y = yStart, w = width, h;
+for (lp = lpList; lp != NULL; lp = lp->next)
+    {
+    h = totalHeight * lp->prob;
+    if (h >= 1.0)
+	{
+	fprintf(f, "%cColor ", tolower(lp->letter));
+	fprintf(f, "%3.2f ", x);
+	fprintf(f, "%3.2f ", y);
+	fprintf(f, "%3.2f ", x + w);
+	fprintf(f, "%3.2f ", y + h);
+	fprintf(f, "(%c) textInBox\n", lp->letter);
+	}
+    y += h;
+    }
+fprintf(f, "\n");
+slFreeList(&lpList);
+}
+
+static void dnaMotifDims(struct dnaMotif *motif, double widthPerBase, double height, 
+	int *retWidth, int *retHeight)
+/* Calculate dimensions of motif when rendered. */
+{
+static int widthFudgeFactor = 2, heightFudgeFactor = 2;
+*retWidth = ceil(widthPerBase * motif->columnCount) + widthFudgeFactor;
+*retHeight = ceil(height) + heightFudgeFactor;
+}
+
+void dnaMotifToLogoPs2(struct dnaMotif *motif, double widthPerBase, double height, 
+                       double minHeight, char *fileName)
+/* Write logo corresponding to motif to postScript file, with extended options. minHeight
+ * is the minimum height that is excluded from information content scaling.  This allows
+ * something to show up in columns with very little information content.  Setting this
+ * to be the same as height creates an frequency-based logo.
+ */
+{
+FILE *f = mustOpen(fileName, "w");
+int i;
+int xStart = 0;
+int w, h;
+char *s = 
+#include "dnaMotif.pss"
+;
+
+dnaMotifDims(motif, widthPerBase, height, &w, &h);
+fprintf(f, "%%!PS-Adobe-3.1 EPSF-3.0\n");
+fprintf(f, "%%%%BoundingBox: 0 0 %d %d\n\n", w, h);
+fprintf(f, "%s", s);
+
+fprintf(f, "%s", "% Start of code for this specific logo\n");
+
+for (i=0; i<motif->columnCount; ++i)
+    {
+    double infoScale = dnaMotifBitsOfInfo(motif, i)/2.0;
+    // only scale part beyond minHeight
+    double useHeight = minHeight + (infoScale * (height - minHeight));
+    if (useHeight > height)
+        useHeight = height;
+    psOneColumn(motif, i, xStart, 0, widthPerBase, useHeight, f);
+    xStart += widthPerBase;
+    }
+fprintf(f, "showpage\n");
+carefulClose(&f);
+}
+
+void dnaMotifToLogoPs(struct dnaMotif *motif, double widthPerBase, double height, char *fileName)
+/* Write logo corresponding to motif to postScript file. */
+{
+dnaMotifToLogoPs2(motif, widthPerBase, height, 0.0, fileName);
+}
+
+void dnaMotifToLogoPng(
+	struct dnaMotif *motif,	/* Motif to draw. */
+	double widthPerBase, 	/* Width of each base. */
+	double height, 		/* Max height. */
+	char *gsExe, 		/* ghostscript executable, NULL for default */
+	char *tempDir,          /* temp dir , NULL for default */
+	char *fileName)		/* output png file name. */
+/* Write logo corresponding to motif to png file. */
+{
+char *psName = rTempName(tempDir, "dnaMotif", ".ps");
+struct dyString *dy = dyStringNew(0);
+int w, h;
+int sysRet;
+
+if (gsExe == NULL) gsExe = "gs";
+if (tempDir == NULL) tempDir = "/tmp";
+dnaMotifToLogoPs(motif, widthPerBase, height, psName);
+dnaMotifDims(motif, widthPerBase, height, &w, &h);
+dyStringAppend(dy, gsExe);
+dyStringAppend(dy, " -sDEVICE=png16m -sOutputFile=");
+dyStringAppend(dy, fileName);
+dyStringAppend(dy, " -dBATCH -dNOPAUSE -q ");
+dyStringPrintf(dy, "-g%dx%d ", w, h);
+dyStringAppend(dy, psName);
+sysRet = system(dy->string);
+if (sysRet != 0)
+    errAbort("System call returned %d for:\n  %s", sysRet, dy->string);
+
+/* Clean up. */
+dyStringFree(&dy);
+
+/* change permisssions so the webserver can access the file */
+dy = newDyString(0);
+dyStringPrintf(dy, "chmod 666 %s ", fileName);
+sysRet = system(dy->string);
+
+remove(psName);
+}
+
+void dnaMotifToLogoPsW(struct dnaMotif *motif, double widthPerBase, double width, double height, char *fileName)
+/* Write logo corresponding to motif to postScript file. */
+{
+FILE *f = mustOpen(fileName, "w");
+int i;
+int xStart = 0;
+int w, h;
+char *s = 
+#include "dnaMotif.pss"
+;
+
+dnaMotifDims(motif, widthPerBase, height, &w, &h);
+fprintf(f, "%%!PS-Adobe-3.1 EPSF-3.0\n");
+fprintf(f, "%%%%BoundingBox: 0 0 %d %d\n\n", w, h);
+fprintf(f, "%s", s);
+
+fprintf(f, "%s", "% Start of code for this specific logo\n");
+
+for (i=0; i<motif->columnCount; ++i)
+    {
+    double infoScale = 0.9 ; 
+    xStart = i * width / motif->columnCount;
+    psOneColumn(motif, i, xStart, 0, widthPerBase, infoScale * height, f);
+    }
+fprintf(f, "showpage\n");
+carefulClose(&f);
+}
+
+void dnaMotifToLogoPGM(
+	struct dnaMotif *motif,	/* Motif to draw. */
+	double widthPerBase, 	/* Width of each base. */
+	double width, 		/* Max width. */
+	double height, 		/* Max height. */
+	char *gsExe, 		/* ghostscript executable, NULL for default */
+	char *tempDir,          /* temp dir , NULL for default */
+	char *fileName)		/* output png file name. */
+/* Write logo corresponding to motif to pgm file. */
+{
+char *psName = rTempName(tempDir, "dnaMotif", ".ps");
+struct dyString *dy = dyStringNew(0);
+int w, h;
+int sysRet;
+
+if (gsExe == NULL) gsExe = "gs";
+if (tempDir == NULL) tempDir = "/tmp";
+dnaMotifToLogoPsW(motif, widthPerBase, width, height, psName);
+dnaMotifDims(motif, widthPerBase, height, &w, &h);
+dyStringAppend(dy, gsExe);
+dyStringAppend(dy, " -sDEVICE=pgmraw -sOutputFile=");
+dyStringAppend(dy, fileName);
+dyStringAppend(dy, " -dBATCH -dNOPAUSE -q ");
+dyStringPrintf(dy, "-g%dx%d ", (int) ceil(width), h);
+dyStringAppend(dy, psName);
+sysRet = system(dy->string);
+if (sysRet != 0)
+    errAbort("System call returned %d for:\n  %s", sysRet, dy->string);
+
+/* Clean up. */
+dyStringFree(&dy);
+
+/* change permisssions so the webserver can access the file */
+dy = newDyString(0);
+dyStringPrintf(dy, "chmod 666 %s ", fileName);
+sysRet = system(dy->string);
+
+remove(psName);
+}
diff --git a/lib/dnaMotif.pss b/lib/dnaMotif.pss
new file mode 100644
index 0000000..b2b5fb6
--- /dev/null
+++ b/lib/dnaMotif.pss
@@ -0,0 +1,61 @@
+"/logoFont {\n"
+"/Helvetica findfont\n"
+"10 scalefont\n"
+"setfont\n"
+"} def\n"
+"\n"
+"\n"
+"/textBounds {\n"
+"% Figure out bounding box of string in current font.  Usage:\n"
+"% call: text letterSize \n"
+"% sets: tbX1 tbY1 tbX2 tbY2 tbW tbH\n"
+"% The bounds are relative to the current position\n"
+"gsave\n"
+"newpath\n"
+"0 0 moveto\n"
+"true charpath\n"
+"flattenpath\n"
+"pathbbox\n"
+"grestore\n"
+"/tbY2 exch def\n"
+"/tbX2 exch def\n"
+"/tbY1 exch def\n"
+"/tbX1 exch def\n"
+"/tbW tbX2 tbX1 sub def\n"
+"/tbH tbY2 tbY1 sub def\n"
+"} def\n"
+"\n"
+"/textInBox {\n"
+"% Draw text so that it fits inside of box.  Usage:\n"
+"%   x1 y1 x2 y2 text textInBox\n"
+"\n"
+"% Copy parameters from variables to stack and save context\n"
+"/tibText exch def\n"
+"/tibY2 exch def\n"
+"/tibX2 exch def\n"
+"/tibY1 exch def\n"
+"/tibX1 exch def\n"
+"gsave\n"
+"\n"
+"% move to x1/y1 adjusted for text offset\n"
+"tibText textBounds\n"
+"tibX1 tbX1 sub tibY1 tbY1 sub moveto\n"
+"\n"
+"% Set scaling\n"
+"/tibW tibX2 tibX1 sub def\n"
+"/tibH tibY2 tibY1 sub def\n"
+"tibW tbW div tibH tbH div scale\n"
+"\n"
+"% draw and return\n"
+"tibText show\n"
+"grestore\n"
+"} def\n"
+"\n"
+"/aColor { 0 0.7 0 setrgbcolor } def\n"
+"/cColor { 0 0.5 0.7 setrgbcolor } def\n"
+"/gColor { 0.8 0.5 0 setrgbcolor } def\n"
+"/tColor { 0.9 0 0 setrgbcolor } def\n"
+"\n"
+"logoFont\n"
+"\n"
+"\n"
diff --git a/lib/dnaseq.c b/lib/dnaseq.c
new file mode 100644
index 0000000..11a007c
--- /dev/null
+++ b/lib/dnaseq.c
@@ -0,0 +1,181 @@
+/* dnaSeq.c - stuff to manage DNA sequences. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "dnaseq.h"
+#include "bits.h"
+#include "hash.h"
+#include "obscure.h"
+
+
+
+struct dnaSeq *newDnaSeq(DNA *dna, int size, char *name)
+/* Create a new DNA seq. */
+{
+struct dnaSeq *seq;
+
+seq = needMem(sizeof(*seq));
+if (name != NULL)
+    seq->name = cloneString(name);
+seq->dna = dna;
+seq->size = size;
+seq->mask = NULL;
+return seq;
+}
+
+struct dnaSeq *cloneDnaSeq(struct dnaSeq *orig)
+/* Duplicate dna sequence in RAM. */
+{
+struct dnaSeq *seq = CloneVar(orig);
+seq->name = cloneString(seq->name);
+seq->dna = needHugeMem(seq->size+1);
+memcpy(seq->dna, orig->dna, seq->size+1);
+seq->mask = NULL;
+if (orig->mask != NULL)
+    {
+    seq->mask = bitClone(orig->mask, seq->size);
+    }
+return seq;
+}
+
+void freeDnaSeq(struct dnaSeq **pSeq)
+/* Free up DNA seq. (And unlink underlying resource node.) */
+{
+struct dnaSeq *seq = *pSeq;
+if (seq == NULL)
+    return;
+freeMem(seq->name);
+freeMem(seq->dna);
+bitFree(&seq->mask);
+freez(pSeq);
+}
+
+void freeDnaSeqList(struct dnaSeq **pSeqList)
+/* Free up list of DNA sequences. */
+{
+struct dnaSeq *seq, *next;
+
+for (seq = *pSeqList; seq != NULL; seq = next)
+    {
+    next = seq->next;
+    freeDnaSeq(&seq);
+    }
+*pSeqList = NULL;
+}
+
+boolean seqIsLower(bioSeq *seq)
+/* Return TRUE if sequence is all lower case. */
+{
+int size = seq->size, i;
+char *poly = seq->dna;
+for (i=0; i<size; ++i)
+    if (!islower(poly[i]))
+        return FALSE;
+return TRUE;
+}
+
+boolean seqIsDna(bioSeq *seq)
+/* Make educated guess whether sequence is DNA or protein. */
+{
+return isDna(seq->dna, seq->size);
+}
+
+
+aaSeq *translateSeqN(struct dnaSeq *inSeq, unsigned offset, unsigned inSize, boolean stop)
+/* Return a translated sequence.  Offset is position of first base to
+ * translate. If size is 0 then use length of inSeq. */
+{
+aaSeq *seq;
+DNA *dna = inSeq->dna;
+AA *pep, aa;
+int i, lastCodon;
+int actualSize = 0;
+
+assert(offset <= inSeq->size);
+if ((inSize == 0) || (inSize > (inSeq->size - offset)))
+    inSize = inSeq->size - offset;
+lastCodon = offset + inSize - 3;
+
+AllocVar(seq);
+seq->dna = pep = needLargeMem(inSize/3+1);
+for (i=offset; i <= lastCodon; i += 3)
+    {
+    aa = lookupCodon(dna+i);
+    if (aa == 0)
+	{
+        if (stop)
+	    break;
+	else
+	    aa = 'Z';
+	}
+    *pep++ = aa;
+    ++actualSize;
+    }
+*pep = 0;
+assert(actualSize <= inSize/3+1);
+seq->size = actualSize;
+seq->name = cloneString(inSeq->name);
+return seq;
+}
+
+aaSeq *translateSeq(struct dnaSeq *inSeq, unsigned offset, boolean stop)
+/* Return a translated sequence.  Offset is position of first base to
+ * translate. If stop is TRUE then stop at first stop codon.  (Otherwise 
+ * represent stop codons as 'Z'). */
+{
+return translateSeqN(inSeq, offset, 0, stop);
+}
+
+bioSeq *whichSeqIn(bioSeq **seqs, int seqCount, char *letters)
+/* Figure out which if any sequence letters is in. */
+{
+aaSeq *seq;
+int i;
+
+for (i=0; i<seqCount; ++i)
+    {
+    seq = seqs[i];
+    if (seq->dna <= letters && letters < seq->dna + seq->size)
+        return seq;
+    }
+internalErr();
+return NULL;
+}
+
+Bits *maskFromUpperCaseSeq(bioSeq *seq)
+/* Allocate a mask for sequence and fill it in based on
+ * sequence case. */
+{
+int size = seq->size, i;
+char *poly = seq->dna;
+Bits *b = bitAlloc(size);
+for (i=0; i<size; ++i)
+    {
+    if (isupper(poly[i]))
+        bitSetOne(b, i);
+    }
+return b;
+}
+
+struct hash *dnaSeqHash(struct dnaSeq *seqList)
+/* Return hash of sequences keyed by name. */
+{
+int size = slCount(seqList)+1;
+int sizeLog2 = digitsBaseTwo(size);
+struct hash *hash = hashNew(sizeLog2);
+struct dnaSeq *seq;
+for (seq = seqList; seq != NULL; seq = seq->next)
+    hashAddUnique(hash, seq->name, seq);
+return hash;
+}
+
+int dnaSeqCmpName(const void *va, const void *vb)
+/* Compare to sort based on sequence name. */
+{
+const struct dnaSeq *a = *((struct dnaSeq **)va);
+const struct dnaSeq *b = *((struct dnaSeq **)vb);
+return strcmp(a->name, b->name);
+}
+
diff --git a/lib/dnautil.c b/lib/dnautil.c
new file mode 100644
index 0000000..61ac692
--- /dev/null
+++ b/lib/dnautil.c
@@ -0,0 +1,1124 @@
+/* Some stuff that you'll likely need in any program that works with
+ * DNA.  Includes stuff for amino acids as well. 
+ *
+ * Assumes that DNA is stored as a character.
+ * The DNA it generates will include the bases 
+ * as lowercase tcag.  It will generally accept
+ * uppercase as well, and also 'n' or 'N' or '-'
+ * for unknown bases. 
+ *
+ * Amino acids are stored as single character upper case. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "dnautil.h"
+
+
+struct codonTable
+/* The dread codon table. */
+    {
+    DNA *codon;		/* Lower case. */
+    AA protCode;	/* Upper case. The "Standard" code */
+    AA mitoCode;	/* Upper case. Vertebrate Mitochondrial translations */
+    };
+
+struct codonTable codonTable[] = 
+/* The master codon/protein table. */
+{
+    {"ttt", 'F', 'F',},
+    {"ttc", 'F', 'F',},
+    {"tta", 'L', 'L',},
+    {"ttg", 'L', 'L',},
+
+    {"tct", 'S', 'S',},
+    {"tcc", 'S', 'S',},
+    {"tca", 'S', 'S',},
+    {"tcg", 'S', 'S',},
+
+    {"tat", 'Y', 'Y',},
+    {"tac", 'Y', 'Y',},
+    {"taa", 0, 0,},
+    {"tag", 0, 0,},
+
+    {"tgt", 'C', 'C',},
+    {"tgc", 'C', 'C',},
+    {"tga", 0, 'W',},
+    {"tgg", 'W', 'W',},
+
+
+    {"ctt", 'L', 'L',},
+    {"ctc", 'L', 'L',},
+    {"cta", 'L', 'L',},
+    {"ctg", 'L', 'L',},
+
+    {"cct", 'P', 'P',},
+    {"ccc", 'P', 'P',},
+    {"cca", 'P', 'P',},
+    {"ccg", 'P', 'P',},
+
+    {"cat", 'H', 'H',},
+    {"cac", 'H', 'H',},
+    {"caa", 'Q', 'Q',},
+    {"cag", 'Q', 'Q',},
+
+    {"cgt", 'R', 'R',},
+    {"cgc", 'R', 'R',},
+    {"cga", 'R', 'R',},
+    {"cgg", 'R', 'R',},
+
+
+    {"att", 'I', 'I',},
+    {"atc", 'I', 'I',},
+    {"ata", 'I', 'M',},
+    {"atg", 'M', 'M',},
+
+    {"act", 'T', 'T',},
+    {"acc", 'T', 'T',},
+    {"aca", 'T', 'T',},
+    {"acg", 'T', 'T',},
+
+    {"aat", 'N', 'N',},
+    {"aac", 'N', 'N',},
+    {"aaa", 'K', 'K',},
+    {"aag", 'K', 'K',},
+
+    {"agt", 'S', 'S',},
+    {"agc", 'S', 'S',},
+    {"aga", 'R', 0,},
+    {"agg", 'R', 0,},
+
+
+    {"gtt", 'V', 'V',},
+    {"gtc", 'V', 'V',},
+    {"gta", 'V', 'V',},
+    {"gtg", 'V', 'V',},
+
+    {"gct", 'A', 'A',},
+    {"gcc", 'A', 'A',},
+    {"gca", 'A', 'A',},
+    {"gcg", 'A', 'A',},
+
+    {"gat", 'D', 'D',},
+    {"gac", 'D', 'D',},
+    {"gaa", 'E', 'E',},
+    {"gag", 'E', 'E',},
+
+    {"ggt", 'G', 'G',},
+    {"ggc", 'G', 'G',},
+    {"gga", 'G', 'G',},
+    {"ggg", 'G', 'G',},
+};
+
+/* A table that gives values 0 for t
+			     1 for c
+			     2 for a
+			     3 for g
+ * (which is order aa's are in biochemistry codon tables)
+ * and gives -1 for all others. */
+int ntVal[256];
+int ntValLower[256];	/* NT values only for lower case. */
+int ntValUpper[256];	/* NT values only for upper case. */
+int ntVal5[256];
+int ntValNoN[256]; /* Like ntVal, but with T_BASE_VAL in place of -1 for nonexistent ones. */
+DNA valToNt[(N_BASE_VAL|MASKED_BASE_BIT)+1];
+
+/* convert tables for bit-4 indicating masked */
+int ntValMasked[256];
+DNA valToNtMasked[256];
+
+static boolean inittedNtVal = FALSE;
+
+static void initNtVal()
+{
+if (!inittedNtVal)
+    {
+    int i;
+    for (i=0; i<ArraySize(ntVal); i++)
+        {
+	ntValUpper[i] = ntValLower[i] = ntVal[i] = -1;
+        ntValNoN[i] = T_BASE_VAL;
+	if (isspace(i) || isdigit(i))
+	    ntVal5[i] = ntValMasked[i] = -1;
+	else
+            {
+	    ntVal5[i] = N_BASE_VAL;
+	    ntValMasked[i] = (islower(i) ? (N_BASE_VAL|MASKED_BASE_BIT) : N_BASE_VAL);
+            }
+        }
+    ntVal5['t'] = ntVal5['T'] = ntValNoN['t'] = ntValNoN['T'] = ntVal['t'] = ntVal['T'] = 
+    	ntValLower['t'] = ntValUpper['T'] = T_BASE_VAL;
+    ntVal5['u'] = ntVal5['U'] = ntValNoN['u'] = ntValNoN['U'] = ntVal['u'] = ntVal['U'] = 
+    	ntValLower['u'] = ntValUpper['U'] = U_BASE_VAL;
+    ntVal5['c'] = ntVal5['C'] = ntValNoN['c'] = ntValNoN['C'] = ntVal['c'] = ntVal['C'] = 
+    	ntValLower['c'] = ntValUpper['C'] = C_BASE_VAL;
+    ntVal5['a'] = ntVal5['A'] = ntValNoN['a'] = ntValNoN['A'] = ntVal['a'] = ntVal['A'] = 
+    	ntValLower['a'] = ntValUpper['A'] = A_BASE_VAL;
+    ntVal5['g'] = ntVal5['G'] = ntValNoN['g'] = ntValNoN['G'] = ntVal['g'] = ntVal['G'] = 
+    	ntValLower['g'] = ntValUpper['G'] = G_BASE_VAL;
+
+    valToNt[T_BASE_VAL] = valToNt[T_BASE_VAL|MASKED_BASE_BIT] = 't';
+    valToNt[C_BASE_VAL] = valToNt[C_BASE_VAL|MASKED_BASE_BIT] = 'c';
+    valToNt[A_BASE_VAL] = valToNt[A_BASE_VAL|MASKED_BASE_BIT] = 'a';
+    valToNt[G_BASE_VAL] = valToNt[G_BASE_VAL|MASKED_BASE_BIT] = 'g';
+    valToNt[N_BASE_VAL] = valToNt[N_BASE_VAL|MASKED_BASE_BIT] = 'n';
+
+    /* masked values */
+    ntValMasked['T'] = T_BASE_VAL;
+    ntValMasked['U'] = U_BASE_VAL;
+    ntValMasked['C'] = C_BASE_VAL;
+    ntValMasked['A'] = A_BASE_VAL;
+    ntValMasked['G'] = G_BASE_VAL;
+
+    ntValMasked['t'] = T_BASE_VAL|MASKED_BASE_BIT;
+    ntValMasked['u'] = U_BASE_VAL|MASKED_BASE_BIT;
+    ntValMasked['c'] = C_BASE_VAL|MASKED_BASE_BIT;
+    ntValMasked['a'] = A_BASE_VAL|MASKED_BASE_BIT;
+    ntValMasked['g'] = G_BASE_VAL|MASKED_BASE_BIT;
+
+    valToNtMasked[T_BASE_VAL] = 'T';
+    valToNtMasked[C_BASE_VAL] = 'C';
+    valToNtMasked[A_BASE_VAL] = 'A';
+    valToNtMasked[G_BASE_VAL] = 'G';
+    valToNtMasked[N_BASE_VAL] = 'N';
+
+    valToNtMasked[T_BASE_VAL|MASKED_BASE_BIT] = 't';
+    valToNtMasked[C_BASE_VAL|MASKED_BASE_BIT] = 'c';
+    valToNtMasked[A_BASE_VAL|MASKED_BASE_BIT] = 'a';
+    valToNtMasked[G_BASE_VAL|MASKED_BASE_BIT] = 'g';
+    valToNtMasked[N_BASE_VAL|MASKED_BASE_BIT] = 'n';
+
+    inittedNtVal = TRUE;
+    }
+}
+
+/* Returns one letter code for protein, 
+ * 0 for stop codon or X for bad input,
+ * The "Standard" Code */
+AA lookupCodon(DNA *dna)
+{
+int ix;
+int i;
+char c;
+
+if (!inittedNtVal)
+    initNtVal();
+ix = 0;
+for (i=0; i<3; ++i)
+    {
+    int bv = ntVal[(int)dna[i]];
+    if (bv<0)
+	return 'X';
+    ix = (ix<<2) + bv;
+    }
+c = codonTable[ix].protCode;
+return c;
+}
+
+boolean isStopCodon(DNA *dna)
+/* Return TRUE if it's a stop codon. */
+{
+return lookupCodon(dna) == 0;
+}
+
+boolean isKozak(char *dna, int dnaSize, int pos)
+/* Return TRUE if it's a Kozak compatible start. */
+{
+if (lookupCodon(dna+pos) != 'M')
+   {
+   return FALSE;
+   }
+if (pos + 3 < dnaSize)
+    {
+    if (ntVal[(int)dna[pos+3]] == G_BASE_VAL)
+        return TRUE;
+    }
+if (pos >= 3)
+    {
+    int c = ntVal[(int)dna[pos-3]];
+    if (c == A_BASE_VAL || c == G_BASE_VAL)
+        return TRUE;
+    }
+return FALSE;
+}
+
+
+boolean isReallyStopCodon(char *dna, boolean selenocysteine)
+/* Return TRUE if it's really a stop codon, even considering
+ * possibilility of selenocysteine. */
+{
+if (selenocysteine)
+    {
+    /* Luckily the mitochondria *also* replaces TGA with 
+     * something else, even though it isn't selenocysteine */
+    return lookupMitoCodon(dna) == 0;
+    }
+else
+    {
+    return lookupCodon(dna) == 0;
+    }
+}
+
+
+/* Returns one letter code for protein, 
+ * 0 for stop codon or X for bad input,
+ * Vertebrate Mitochondrial Code */
+AA lookupMitoCodon(DNA *dna)
+{
+int ix;
+int i;
+char c;
+
+if (!inittedNtVal)
+    initNtVal();
+ix = 0;
+for (i=0; i<3; ++i)
+    {
+    int bv = ntVal[(int)dna[i]];
+    if (bv<0)
+	return 'X';
+    ix = (ix<<2) + bv;
+    }
+c = codonTable[ix].mitoCode;
+c = toupper(c);
+return c;
+}
+
+Codon codonVal(DNA *start)
+/* Return value from 0-63 of codon starting at start. 
+ * Returns -1 if not a codon. */
+{
+int v1,v2,v3;
+
+if ((v1 = ntVal[(int)start[0]]) < 0)
+    return -1;
+if ((v2 = ntVal[(int)start[1]]) < 0)
+    return -1;
+if ((v3 = ntVal[(int)start[2]]) < 0)
+    return -1;
+return ((v1<<4) + (v2<<2) + v3);
+}
+
+DNA *valToCodon(int val)
+/* Return  codon corresponding to val (0-63) */
+{
+assert(val >= 0 && val < 64);
+return codonTable[val].codon;
+}
+
+void dnaTranslateSome(DNA *dna, char *out, int outSize)
+/* Translate DNA upto a stop codon or until outSize-1 amino acids, 
+ * whichever comes first. Output will be zero terminated. */
+{
+int i;
+int dnaSize;
+int protSize = 0;
+
+outSize -= 1;  /* Room for terminal zero */
+dnaSize = strlen(dna);
+for (i=0; i<dnaSize-2; i+=3)
+    {
+    if (protSize >= outSize)
+        break;
+    if ((out[protSize++] = lookupCodon(dna+i)) == 0)
+        break;
+    }
+out[protSize] = 0;
+}
+
+/* A little array to help us decide if a character is a 
+ * nucleotide, and if so convert it to lower case. */
+char ntChars[256];
+
+static void initNtChars()
+{
+static boolean initted = FALSE;
+
+if (!initted)
+    {
+    zeroBytes(ntChars, sizeof(ntChars));
+    ntChars['a'] = ntChars['A'] = 'a';
+    ntChars['c'] = ntChars['C'] = 'c';
+    ntChars['g'] = ntChars['G'] = 'g';
+    ntChars['t'] = ntChars['T'] = 't';
+    ntChars['n'] = ntChars['N'] = 'n';
+    ntChars['u'] = ntChars['U'] = 'u';
+    ntChars['-'] = 'n';
+    initted = TRUE;
+    }
+}
+
+char ntMixedCaseChars[256];
+
+static void initNtMixedCaseChars()
+{
+static boolean initted = FALSE;
+
+if (!initted)
+    {
+    zeroBytes(ntMixedCaseChars, sizeof(ntMixedCaseChars));
+    ntMixedCaseChars['a'] = 'a';
+    ntMixedCaseChars['A'] = 'A';
+    ntMixedCaseChars['c'] = 'c';
+    ntMixedCaseChars['C'] = 'C';
+    ntMixedCaseChars['g'] = 'g';
+    ntMixedCaseChars['G'] = 'G';
+    ntMixedCaseChars['t'] = 't';
+    ntMixedCaseChars['T'] = 'T';
+    ntMixedCaseChars['n'] = 'n';
+    ntMixedCaseChars['N'] = 'N';
+    ntMixedCaseChars['u'] = 'u';
+    ntMixedCaseChars['U'] = 'U';
+    ntMixedCaseChars['-'] = 'n';
+    initted = TRUE;
+    }
+}
+
+/* Another array to help us do complement of DNA */
+DNA ntCompTable[256];
+static boolean inittedCompTable = FALSE;
+
+static void initNtCompTable()
+{
+zeroBytes(ntCompTable, sizeof(ntCompTable));
+ntCompTable[' '] = ' ';
+ntCompTable['-'] = '-';
+ntCompTable['='] = '=';
+ntCompTable['a'] = 't';
+ntCompTable['c'] = 'g';
+ntCompTable['g'] = 'c';
+ntCompTable['t'] = 'a';
+ntCompTable['u'] = 'a';
+ntCompTable['n'] = 'n';
+ntCompTable['-'] = '-';
+ntCompTable['.'] = '.';
+ntCompTable['A'] = 'T';
+ntCompTable['C'] = 'G';
+ntCompTable['G'] = 'C';
+ntCompTable['T'] = 'A';
+ntCompTable['U'] = 'A';
+ntCompTable['N'] = 'N';
+ntCompTable['R'] = 'Y';
+ntCompTable['Y'] = 'R';
+ntCompTable['M'] = 'K';
+ntCompTable['K'] = 'M';
+ntCompTable['S'] = 'S';
+ntCompTable['W'] = 'W';
+ntCompTable['V'] = 'B';
+ntCompTable['H'] = 'D';
+ntCompTable['D'] = 'H';
+ntCompTable['B'] = 'V';
+ntCompTable['X'] = 'N';
+ntCompTable['r'] = 'y';
+ntCompTable['y'] = 'r';
+ntCompTable['s'] = 's';
+ntCompTable['w'] = 'w';
+ntCompTable['m'] = 'k';
+ntCompTable['k'] = 'm';
+ntCompTable['v'] = 'b';
+ntCompTable['h'] = 'd';
+ntCompTable['d'] = 'h';
+ntCompTable['b'] = 'v';
+ntCompTable['x'] = 'n';
+ntCompTable['('] = ')';
+ntCompTable[')'] = '(';
+inittedCompTable = TRUE;
+}
+
+/* Complement DNA (not reverse). */
+void complement(DNA *dna, long length)
+{
+int i;
+
+if (!inittedCompTable) initNtCompTable();
+for (i=0; i<length; ++i)
+    {
+    *dna = ntCompTable[(int)*dna];
+    ++dna;
+    }
+}
+
+
+/* Reverse complement DNA. */
+void reverseComplement(DNA *dna, long length)
+{
+reverseBytes(dna, length);
+complement(dna, length);
+}
+
+/* Reverse offset - return what will be offset (0 based) to
+ * same member of array after array is reversed. */
+long reverseOffset(long offset, long arraySize)
+{
+return arraySize-1 - offset;
+}
+
+/* Switch start/end (zero based half open) coordinates
+ * to opposite strand. */
+void reverseIntRange(int *pStart, int *pEnd, int size)
+{
+int temp;
+temp = *pStart;
+*pStart = size - *pEnd;
+*pEnd = size - temp;
+}
+
+/* Switch start/end (zero based half open) coordinates
+ * to opposite strand. */
+void reverseUnsignedRange(unsigned *pStart, unsigned *pEnd, int size)
+{
+unsigned temp;
+temp = *pStart;
+*pStart = size - *pEnd;
+*pEnd = size - temp;
+}
+
+int cmpDnaStrings(DNA *a, DNA *b)
+/* Compare using screwy non-alphabetical DNA order TCGA */
+{
+for (;;)
+    {
+    DNA aa = *a++;
+    DNA bb = *b++;
+    if (aa != bb)
+        return ntVal[(int)aa] - ntVal[(int)bb];
+    if (aa == 0)
+	break;
+    }
+return 0;
+}
+
+
+/* Convert T's to U's */
+void toRna(DNA *dna)
+{
+DNA c;
+for (;;)
+    {
+    c = *dna;
+    if (c == 't')
+	*dna = 'u';
+    else if (c == 'T')
+	*dna = 'U';
+    else if (c == 0)
+	break;
+    ++dna;
+    }
+}
+
+char *skipIgnoringDash(char *a, int size, bool skipTrailingDash)
+/* Count size number of characters, and any 
+ * dash characters. */
+{
+while (size > 0)
+    {
+    if (*a++ != '-')
+        --size;
+    }
+if (skipTrailingDash)
+    while (*a == '-')
+       ++a;
+return a;
+}
+
+int countNonDash(char *a, int size)
+/* Count number of non-dash characters. */
+{
+int count = 0;
+int i;
+for (i=0; i<size; ++i)
+    if (a[i] != '-') 
+        ++count;
+return count;
+}
+
+int nextPowerOfFour(long x)
+/* Return next power of four that would be greater or equal to x.
+ * For instance if x < 4, return 1, if x < 16 return 2.... 
+ * (From biological point of view how many bases are needed to
+ * code this number.) */
+{
+int count = 1;
+while (x > 4)
+    {
+    count += 1;
+    x >>= 2;
+    }
+return count;
+}
+
+long dnaOrAaFilteredSize(char *raw, char filter[256])
+/* Return how long DNA will be after non-DNA is filtered out. */
+{
+char c;
+long count = 0;
+dnaUtilOpen();
+while ((c = *raw++) != 0)
+    {
+    if (filter[(int)c]) ++count;
+    }
+return count;
+}
+
+void dnaOrAaFilter(char *in, char *out, char filter[256])
+/* Run chars through filter. */
+{
+char c;
+dnaUtilOpen();
+while ((c = *in++) != 0)
+    {
+    if ((c = filter[(int)c]) != 0) *out++ = c;
+    }
+*out++ = 0;
+}
+
+long dnaFilteredSize(char *rawDna)
+/* Return how long DNA will be after non-DNA is filtered out. */
+{
+return dnaOrAaFilteredSize(rawDna, ntChars);
+}
+
+void dnaFilter(char *in, DNA *out)
+/* Filter out non-DNA characters and change to lower case. */
+{
+dnaOrAaFilter(in, out, ntChars);
+}
+
+void dnaFilterToN(char *in, DNA *out)
+/* Change all non-DNA characters to N. */
+{
+DNA c;
+initNtChars();
+while ((c = *in++) != 0)
+    {
+    if ((c = ntChars[(int)c]) != 0) *out++ = c;
+    else *out++ = 'n';
+    }
+*out++ = 0;
+}
+
+void dnaMixedCaseFilter(char *in, DNA *out)
+/* Filter out non-DNA characters but leave case intact. */
+{
+dnaOrAaFilter(in, out, ntMixedCaseChars);
+}
+
+long aaFilteredSize(char *raw)
+/* Return how long aa will be after non-aa chars is filtered out. */
+{
+return dnaOrAaFilteredSize(raw, aaChars);
+}
+
+void aaFilter(char *in, DNA *out)
+/* Filter out non-aa characters and change to upper case. */
+{
+dnaOrAaFilter(in, out, aaChars);
+}
+
+void upperToN(char *s, int size)
+/* Turn upper case letters to N's. */
+{
+char c;
+int i;
+for (i=0; i<size; ++i)
+    {
+    c = s[i];
+    if (isupper(c))
+        s[i] = 'n';
+    }
+}
+
+void lowerToN(char *s, int size)
+/* Turn lower case letters to N's. */
+{
+char c;
+int i;
+for (i=0; i<size; ++i)
+    {
+    c = s[i];
+    if (islower(c))
+        s[i] = 'N';
+    }
+}
+
+
+void dnaBaseHistogram(DNA *dna, int dnaSize, int histogram[4])
+/* Count up frequency of occurance of each base and store 
+ * results in histogram. */
+{
+int val;
+zeroBytes(histogram, 4*sizeof(int));
+while (--dnaSize >= 0)
+    {
+    if ((val = ntVal[(int)*dna++]) >= 0)
+        ++histogram[val];
+    }
+}
+
+bits64 basesToBits64(char *dna, int size)
+/* Convert dna of given size (up to 32) to binary representation */
+{
+if (size > 32)
+    errAbort("basesToBits64 called on %d bases, can only go up to 32", size);
+bits64 result = 0;
+int i;
+for (i=0; i<size; ++i)
+    {
+    result <<= 2;
+    result += ntValNoN[(int)dna[i]];
+    }
+return result;
+}
+
+bits32 packDna16(DNA *in)
+/* pack 16 bases into a word */
+{
+bits32 out = 0;
+int count = 16;
+int bVal;
+while (--count >= 0)
+    {
+    bVal = ntValNoN[(int)*in++];
+    out <<= 2;
+    out += bVal;
+    }
+return out;
+}
+
+bits16 packDna8(DNA *in)
+/* Pack 8 bases into a short word */
+{
+bits16 out = 0;
+int count = 8;
+int bVal;
+while (--count >= 0)
+    {
+    bVal = ntValNoN[(int)*in++];
+    out <<= 2;
+    out += bVal;
+    }
+return out;
+}
+
+UBYTE packDna4(DNA *in)
+/* Pack 4 bases into a UBYTE */
+{
+UBYTE out = 0;
+int count = 4;
+int bVal;
+while (--count >= 0)
+    {
+    bVal = ntValNoN[(int)*in++];
+    out <<= 2;
+    out += bVal;
+    }
+return out;
+}
+
+void unpackDna(bits32 *tiles, int tileCount, DNA *out)
+/* Unpack DNA. Expands to 16x tileCount in output. */
+{
+int i, j;
+bits32 tile;
+
+for (i=0; i<tileCount; ++i)
+    {
+    tile = tiles[i];
+    for (j=15; j>=0; --j)
+        {
+        out[j] = valToNt[tile & 0x3];
+        tile >>= 2;
+        }
+    out += 16;
+    }
+}
+
+void unpackDna4(UBYTE *tiles, int byteCount, DNA *out)
+/* Unpack DNA. Expands to 4x byteCount in output. */
+{
+int i, j;
+UBYTE tile;
+
+for (i=0; i<byteCount; ++i)
+    {
+    tile = tiles[i];
+    for (j=3; j>=0; --j)
+        {
+        out[j] = valToNt[tile & 0x3];
+        tile >>= 2;
+        }
+    out += 4;
+    }
+}
+
+
+
+
+static void checkSizeTypes()
+/* Make sure that some of our predefined types are the right size. */
+{
+assert(sizeof(UBYTE) == 1);
+assert(sizeof(WORD) == 2);
+assert(sizeof(bits32) == 4);
+assert(sizeof(bits16) == 2);
+}
+
+int intronOrientationMinSize(DNA *iStart, DNA *iEnd, int minIntronSize)
+/* Given a gap in genome from iStart to iEnd, return 
+ * Return 1 for GT/AG intron between left and right, -1 for CT/AC, 0 for no
+ * intron.  Assumes DNA is lower cased. */
+{
+if (iEnd - iStart < minIntronSize)
+    return 0;
+if (iStart[0] == 'g' && iStart[1] == 't' && iEnd[-2] == 'a' && iEnd[-1] == 'g')
+    {
+    return 1;
+    }
+else if (iStart[0] == 'c' && iStart[1] == 't' && iEnd[-2] == 'a' && iEnd[-1] == 'c')
+    {
+    return -1;
+    }
+else
+    return 0;
+}
+
+int intronOrientation(DNA *iStart, DNA *iEnd)
+/* Given a gap in genome from iStart to iEnd, return 
+ * Return 1 for GT/AG intron between left and right, -1 for CT/AC, 0 for no
+ * intron.  Assumes DNA is lower cased. */
+{
+return intronOrientationMinSize(iStart, iEnd, 32);
+}
+
+int dnaScore2(DNA a, DNA b)
+/* Score match between two bases (relatively crudely). */
+{
+if (a == 'n' || b == 'n') return 0;
+if (a == b) return 1;
+else return -1;
+}
+
+int  dnaOrAaScoreMatch(char *a, char *b, int size, int matchScore, int mismatchScore, 
+	char ignore)
+/* Compare two sequences (without inserts or deletions) and score. */
+{
+int i;
+int score = 0;
+for (i=0; i<size; ++i)
+    {
+    char aa = a[i];
+    char bb = b[i];
+    if (aa == ignore || bb == ignore)
+        continue;
+    if (aa == bb)
+        score += matchScore;
+    else
+        score += mismatchScore;
+    }
+return score;
+}
+
+int dnaScoreMatch(DNA *a, DNA *b, int size)
+/* Compare two pieces of DNA base by base. Total mismatches are
+ * subtracted from total matches and returned as score. 'N's 
+ * neither hurt nor help score. */
+{
+return dnaOrAaScoreMatch(a, b, size, 1, -1, 'n');
+}
+
+int aaScore2(AA a, AA b)
+/* Score match between two amino acids (relatively crudely). */
+{
+if (a == 'X' || b == 'X') return 0;
+if (a == b) return 2;
+else return -1;
+}
+
+int aaScoreMatch(AA *a, AA *b, int size)
+/* Compare two peptides aa by aa. */
+{
+return dnaOrAaScoreMatch(a, b, size, 2, -1, 'X');
+}
+
+void writeSeqWithBreaks(FILE *f, char *letters, int letterCount, int maxPerLine)
+/* Write out letters with newlines every maxLine. */
+{
+int lettersLeft = letterCount;
+int lineSize;
+while (lettersLeft > 0)
+    {
+    lineSize = lettersLeft;
+    if (lineSize > maxPerLine)
+        lineSize = maxPerLine;
+    mustWrite(f, letters, lineSize);
+    fputc('\n', f);
+    letters += lineSize;
+    lettersLeft -= lineSize;
+    }
+}
+
+static int findTailPolyAMaybeMask(DNA *dna, int size, boolean doMask,
+				  boolean loose)
+/* Identify PolyA at end; mask to 'n' if specified.  This allows a few 
+ * non-A's as noise to be trimmed too.  Returns number of bases trimmed.  
+ * Leaves first two bases of PolyA in case there's a taa stop codon. */
+{
+int i;
+int score = 10;
+int bestScore = 10;
+int bestPos = -1;
+int trimSize = 0;
+
+for (i=size-1; i>=0; --i)
+    {
+    DNA b = dna[i];
+    if (b == 'n' || b == 'N')
+        continue;
+    if (score > 20) score = 20;
+    if (b == 'a' || b == 'A')
+	{
+        score += 1;
+	if (score >= bestScore)
+	    {
+	    bestScore = score;
+	    bestPos = i;
+	    }
+	else if (loose && score >= (bestScore - 8))
+	    {
+	    /* If loose, keep extending even if score isn't back up to best. */
+	    bestPos = i;
+	    }
+	}
+    else
+	{
+        score -= 10;
+	}
+    if (score < 0)
+	{
+        break;
+	}
+    }
+if (bestPos >= 0)
+    {
+    trimSize = size - bestPos - 2;	// Leave two for aa in taa stop codon
+    if (trimSize > 0)
+        {
+	if (doMask)
+	    for (i=size - trimSize; i<size; ++i)
+		dna[i] = 'n';
+	}
+    else
+        trimSize = 0;
+    }
+return trimSize;
+}
+
+int tailPolyASizeLoose(DNA *dna, int size)
+/* Return size of PolyA at end (if present).  This allows a few non-A's as 
+ * noise to be trimmed too, but skips first two aa for taa stop codon.  
+ * It is less conservative in extending the polyA region than maskTailPolyA. */
+{
+return findTailPolyAMaybeMask(dna, size, FALSE, TRUE);
+}
+
+int maskTailPolyA(DNA *dna, int size)
+/* Convert PolyA at end to n.  This allows a few non-A's as noise to be 
+ * trimmed too.  Returns number of bases trimmed.  Leaves very last a. */
+{
+return findTailPolyAMaybeMask(dna, size, TRUE, FALSE);
+}
+
+static int findHeadPolyTMaybeMask(DNA *dna, int size, boolean doMask,
+				  boolean loose)
+/* Return size of PolyT at start (if present); mask to 'n' if specified.  
+ * This allows a few non-T's as noise to be trimmed too, but skips last
+ * two tt for revcomp'd taa stop codon. */
+{
+int i;
+int score = 10;
+int bestScore = 10;
+int bestPos = -1;
+int pastPoly = 0;
+int trimSize = 0;
+
+for (i=0; i<size; ++i)
+    {
+    DNA b = dna[i];
+    if (b == 'n' || b == 'N')
+        continue;
+    if (score > 20) score = 20;
+    if (b == 't' || b == 'T')
+	{
+        score += 1;
+	if (score >= bestScore)
+	    {
+	    bestScore = score;
+	    bestPos = i;
+	    }
+	else if (loose && score >= (bestScore - 8))
+	    {
+	    /* If loose, keep extending even if score isn't back up to best. */
+	    bestPos = i;
+	    }
+	}
+    else
+	{
+        score -= 10;
+	}
+    if (score < 0)
+	{
+	pastPoly = i;
+        break;
+	}
+    }
+if (bestPos >= 0)
+    {
+    trimSize = bestPos+1 - 2;	// Leave two for aa in taa stop codon
+    if (trimSize > 0)
+	{
+	if (doMask)
+	    memset(dna, 'n', trimSize);
+	}
+    else
+        trimSize = 0;
+    }
+return trimSize;
+}
+
+int headPolyTSizeLoose(DNA *dna, int size)
+/* Return size of PolyT at start (if present).  This allows a few non-T's as 
+ * noise to be trimmed too, but skips last two tt for revcomp'd taa stop 
+ * codon.  
+ * It is less conservative in extending the polyA region than maskHeadPolyT. */
+{
+return findHeadPolyTMaybeMask(dna, size, FALSE, TRUE);
+}
+
+int maskHeadPolyT(DNA *dna, int size)
+/* Convert PolyT at start.  This allows a few non-T's as noise to be 
+ * trimmed too.  Returns number of bases trimmed.  */
+{
+return findHeadPolyTMaybeMask(dna, size, TRUE, FALSE);
+}
+
+boolean isDna(char *poly, int size)
+/* Return TRUE if letters in poly are at least 90% ACGTU */
+{
+int i;
+int dnaCount = 0;
+
+dnaUtilOpen();
+for (i=0; i<size; ++i)
+    {
+    if (ntChars[(int)poly[i]]) 
+	dnaCount += 1;
+    }
+return (dnaCount >= round(0.9 * size));
+}
+
+boolean isAllDna(char *poly, int size)
+/* Return TRUE if letters in poly are 100% ACGTU */
+{
+int i;
+
+if (size <= 1)
+    return FALSE;
+dnaUtilOpen();
+for (i=0; i<size-1; ++i)
+    {
+    if (ntChars[(int)poly[i]] == 0) 
+	return FALSE;
+    }
+return TRUE;
+}
+
+
+
+/* Tables to convert from 0-20 to ascii single letter representation
+ * of proteins. */
+int aaVal[256];
+AA valToAa[21];
+
+AA aaChars[256];	/* 0 except for value aa characters.  Converts to upper case rest. */
+
+struct aminoAcidTable
+/* A little info about each amino acid. */
+    {
+    int ix;
+    char letter;
+    char abbreviation[3];
+    char *name;
+    };
+
+struct aminoAcidTable aminoAcidTable[] = 
+{
+    {0, 'A', "ala", "alanine"},
+    {1, 'C', "cys", "cysteine"},
+    {2, 'D', "asp",  "aspartic acid"},
+    {3, 'E', "glu",  "glutamic acid"},
+    {4, 'F', "phe",  "phenylalanine"},
+    {5, 'G', "gly",  "glycine"},
+    {6, 'H', "his",  "histidine"},
+    {7, 'I', "ile",  "isoleucine"},
+    {8, 'K', "lys",  "lysine"},
+    {9, 'L', "leu",  "leucine"},
+    {10, 'M',  "met", "methionine"},
+    {11, 'N',  "asn", "asparagine"},
+    {12, 'P',  "pro", "proline"},
+    {13, 'Q',  "gln", "glutamine"},
+    {14, 'R',  "arg", "arginine"},
+    {15, 'S',  "ser", "serine"},
+    {16, 'T',  "thr", "threonine"},
+    {17, 'V',  "val", "valine"},
+    {18, 'W',  "trp", "tryptophan"},
+    {19, 'Y',  "tyr", "tyrosine"},
+    {20, 'X',  "ter", "termination"},
+};
+
+char *aaAbbr(int i)
+/* return pointer to AA abbrevation */
+{
+return(aminoAcidTable[i].abbreviation);
+}
+
+char aaLetter(int i)
+/* return AA letter */
+{
+return(aminoAcidTable[i].letter);
+}
+
+static void initAaVal()
+/* Initialize aaVal and valToAa tables. */
+{
+int i;
+char c, lowc;
+
+for (i=0; i<ArraySize(aaVal); ++i)
+    aaVal[i] = -1;
+for (i=0; i<ArraySize(aminoAcidTable); ++i)
+    {
+    c = aminoAcidTable[i].letter;
+    lowc = tolower(c);
+    aaVal[(int)c] = aaVal[(int)lowc] = i;
+    aaChars[(int)c] = aaChars[(int)lowc] = c;
+    valToAa[i] = c;
+    }
+aaChars['x'] = aaChars['X'] = 'X';
+}
+
+void dnaUtilOpen()
+/* Initialize stuff herein. */
+{
+static boolean opened = FALSE;
+if (!opened)
+    {
+    checkSizeTypes();
+    initNtVal();
+    initAaVal();
+    initNtChars();
+    initNtMixedCaseChars();
+    initNtCompTable();
+    opened = TRUE;
+    }
+}
diff --git a/lib/dsPrint.c b/lib/dsPrint.c
new file mode 100644
index 0000000..fd25fb3
--- /dev/null
+++ b/lib/dsPrint.c
@@ -0,0 +1,330 @@
+// dsPrint - Dynamic string Stack based Printing.
+//
+// This module relies upon a dyString based stack of buffers which accumulate output
+// for later printing.  As a stack, only the top buffer can be filled and flushed out
+// (dsPrintFlush).  When flushing, the top buffer's content is appended to the next
+// lower buffer, unless explicitly requested otherwise (dsPrintDirectly).
+// If the stack is empty, dsPrintf will be equivalent to printf.
+//
+// Output goes to STDOUT unless a single alternative out file is registered.
+
+#include "common.h"
+#include "dsPrint.h"
+
+// The stack of dyString buffers is only accessible locally
+static struct dyString *dsStack = NULL;
+// It is desirable to return a unique token but NOT give access to the dyString it is based on
+#define dsPointerToToken(pointer) (int)((long)(pointer) & 0xffffffff)
+#define dsAssertToken(token) assert(dsPointerToToken(dsStack) == token)
+
+// This module defaults to STDOUT but an alternative can be registered
+static FILE *dsOut = NULL;
+#define dsInitializeOut() {if (dsOut == NULL) dsOut = stdout;}
+#define dsAssertUnregisteredOut() assert(dsOut == stdout || dsOut == NULL)
+#define dsAssertRegisteredOut(out) assert(dsOut == out)
+
+
+int dsPrintOpen(int initialBufSize)
+// Allocate dynamic string and puts at top of stack
+// returns token to be used for later stack accounting asserts
+{
+if (initialBufSize <= 0)
+    initialBufSize = 2048; // presume large
+struct dyString *ds = dyStringNew(initialBufSize);
+slAddHead(&dsStack,ds);
+return dsPointerToToken(ds);
+}
+
+
+int dsPrintf(char *format, ...)
+// Prints into end of the top ds buffer, and return resulting string length
+// If there is no current buffer, this acts like a simple printf and returns -1
+{
+int len = -1; // caller could assert returned length > 0 to ensure dsPrint is open!
+va_list args;
+va_start(args, format);
+if (dsStack != NULL)
+    {
+    dyStringVaPrintf(dsStack, format, args);
+    len = dyStringLen(dsStack);
+    }
+else
+    {
+    dsInitializeOut()
+    vfprintf(dsOut,format, args);
+    }
+va_end(args);
+return len;
+}
+
+
+int dsPrintDirectly(int token,FILE *file)
+// Prints the contents of the top buffer directly to a file.
+// Will leave the filled buffer at top of stack
+// Returns the length printed.
+{
+dsAssertToken(token);
+
+int len = dyStringLen(dsStack);
+if (len != 0)
+    fprintf(file,"%s",dyStringContents(dsStack));
+    fflush(file);
+return len;
+}
+
+
+int dsPrintFlush(int token)
+// Flushes the top buffer to the next lower one and empties top buffer.
+// If there is no lower buffer then the content is printed to STDOUT (or registered out).
+// Returns the length flushed.
+{
+dsAssertToken(token);
+
+int len = dyStringLen(dsStack);
+if (len != 0)
+    {
+    if (dsStack->next == NULL)
+        {
+        dsInitializeOut();
+        fprintf(dsOut,"%s",dyStringContents(dsStack));
+        fflush(dsOut);
+        }
+    else
+        dyStringAppend(dsStack->next,dyStringContents(dsStack));
+    dyStringClear(dsStack);
+    }
+return len;
+}
+
+
+int dsPrintClose(int token)
+// Abandons the top buffer and its content, freeing memory.
+// Returns the length abandoned.
+{
+dsAssertToken(token);
+int len = dyStringLen(dsStack);
+struct dyString *ds = slPopHead(&dsStack);
+dyStringFree(&ds);
+return len;
+}
+
+int dsPrintFlushAndClose(int token)
+// Flushes the top buffer to the next lower one and frees the top buffer.
+// If there is no lower buffer then the content is printed to STDOUT (or registered out).
+// Returns the length flushed.
+{
+int len = dsPrintFlush(token);
+dsPrintClose(token);
+return len;
+}
+
+
+char * dsPrintContent(int token)
+// returns the content of the current buffer as a string, but does not flush or free it
+// NOTE: returned pointer is not cloned memory and will be changed by successive dsPrint calls
+{
+dsAssertToken(token);
+return dyStringContents(dsStack);
+}
+
+
+int dsPrintEmpty(int token)
+// Empties the top buffer in stack (abandoning content), but leave buffer in place
+// Returns the length abandoned.
+{
+dsAssertToken(token);
+int len = dyStringLen(dsStack);
+dyStringClear(dsStack);
+return len;
+}
+
+
+static int dsPrintStackIxFromToken(int token)
+// Return the stack member corresponding to the token.
+// This ix can be used to walk up the stack from a given point
+{
+struct dyString *ds = dsStack; 
+int ix = 0;
+
+for (; ds != NULL; ds = ds->next, ++ix)
+    {
+    if (dsPointerToToken(ds) == token)
+        return ix;
+    }
+return -1;
+}
+
+
+static struct dyString *dsPrintStackMemberFromIx(int ix)
+// Return the stack member corresponding to the ix.
+// By walking stack ix's, you can walk up or down the stack
+{
+if (ix < 0)
+    return NULL;
+return slElementFromIx(dsStack,ix);
+}
+
+
+int dsPrintSize(int token)
+// Returns the curent length of the buffer starting at the level corresponding to token.
+// Unlike other cases, the token does not have to correspond to the top of the stack!
+{
+//dsAssertToken(token);
+//return dyStringLen(dsStack);
+int ix = dsPrintStackIxFromToken(token);
+assert(ix >= 0);
+
+int len = 0;
+struct dyString *ds = NULL;
+for (;ix>0;ix--)
+    {
+    ds = dsPrintStackMemberFromIx(ix);
+    assert(ds != NULL);
+    len += dyStringLen(ds);
+    }
+len += dyStringLen(dsStack);
+return len;
+}
+
+
+int dsPrintStackDepth()
+// Returns the current dsPrint buffer stack depth
+{
+return slCount(dsStack);
+}
+
+
+void dsPrintRegisterOut(FILE *out)
+// Registers an alternative to STDOUT.  After registering, all dsPrint out goes to this file.
+// NOTE: There is no stack. Register/Unregister serially.
+{
+dsAssertUnregisteredOut();
+dsOut = out;
+}
+
+
+void dsPrintUnregisterOut(FILE *out)
+// Unregisters the alternative to STDOUT.  After unregistering all dsPrint out goes to STDOUT.
+// NOTE: There is no stack. Register/Unregister serially.
+{
+dsAssertRegisteredOut(out);
+dsOut = stdout;
+}
+
+
+int dsPrintSizeAll()
+// returns combined current size of all buffers
+{
+int len = 0;
+if (dsStack != NULL)
+    {
+    struct dyString *ds = dsStack;
+    for (;ds != NULL; ds = ds->next)
+        len += dyStringLen(ds);
+    }
+return len;
+}
+
+
+int dsPrintFlushAndCloseAll()
+// flushes, frees and closes all stacked buffers
+// returns length flushed
+{
+int len = 0;
+if (dsStack != NULL)
+    {
+    while (dsStack != NULL)
+        {
+        int token = dsPointerToToken(dsStack);
+        len = dsPrintFlushAndClose(token); // Only the last length is needed!
+        }
+    }
+return len;
+}
+
+
+char *dsPrintCannibalizeAndClose(int token)
+// Closes the top stack buffer returning content.  Returned string should be freed.
+{
+dsAssertToken(token);
+struct dyString *ds = slPopHead(&dsStack);
+return dyStringCannibalize(&ds);
+}
+
+
+char *dsPrintCannibalizeAndCloseAll()
+// Closes all stack buffers and returns a single string that is the full content.  
+// Returned string should be freed.
+{
+while (dsStack != NULL && dsStack->next != NULL)
+    {
+    int token = dsPointerToToken(dsStack);
+    dsPrintFlushAndClose(token); // Flushes each to the next lower buffer
+    }
+if (dsStack == NULL)
+    return NULL;
+else
+    return dyStringCannibalize(&dsStack);
+}
+
+/*
+void dsPrintTest()
+// Tests of dsPrint functions
+{
+printf("Plain printf\n");
+dsPrintf("1 dsPrintf unopened\n");
+
+int token1 = dsPrintOpen(0);
+dsPrintf("2 dsOpen:1\n");
+dsPrintFlush(token1);
+dsPrintf("3^10   1:%d after flush\n",dsPrintStackDepth());
+int token2 = dsPrintOpen(256);
+dsPrintf("4 dsOpen:2 len1:%d  len2:%d  lenAll:%d\n",
+         dsPrintSize(token1),dsPrintSize(token2),dsPrintSizeAll());
+dsPrintRegisterOut(stderr);
+dsPrintFlush(token2);
+dsPrintUnregisterOut(stderr);
+dsPrintf("5      2:%d After flush  len1:%d  len2:%d  lenAll:%d\n",
+         dsPrintStackDepth(),dsPrintSize(token1),dsPrintSize(token2),dsPrintSizeAll());
+dsPrintFlushAndClose(token2);
+dsPrintf("6      1:%d After flushAndClose:2  len1:%d\n",dsPrintStackDepth(),dsPrintSize(token1));
+token2 = dsPrintOpen(256);
+dsPrintf("7 dsOpen:2 reopen:2  WILL ABANDON CONTENT\n");
+char *content = cloneString(dsPrintContent(token2));
+dsPrintAbandonContent(token2);
+dsPrintf("8x7    2:%d len1:%d len2:%d lenAll:%d isEmpty2:%s\n",
+         dsPrintStackDepth(),dsPrintSize(token1),dsPrintSize(token2),dsPrintSizeAll(),
+         (dsPrintIsEmpty(token2) ? "EMPTY":"NOT_EMPTY"));
+strSwapChar(content,'\n','~');  // Replace newline before printing.
+dsPrintf("9      2:%d No flush yet   len1:%d  len2:%d  lenAll:%d  prev7:[%s]\n",
+         dsPrintStackDepth(),dsPrintSize(token1),dsPrintSize(token2),dsPrintSizeAll(),content);
+freez(&content);
+int token3 = dsPrintOpen(256);
+dsPuts("10  Open:3 Line doubled and out of turn due to dsPrintDirectly()");
+dsPrintDirectly(token3,stdout);
+dsPrintf("11     3:%d Just prior to closing all.  len1:%d  len2:%d  len3:%d  lenAll:%d",
+         dsPrintStackDepth(),
+         dsPrintSize(token1),dsPrintSize(token2),dsPrintSize(token3),dsPrintSizeAll());
+int token4 = dsPrintOpen(256);
+dsPrintf("12  Open:4 Opened  stack:%d  WILL ABANDON\n",dsPrintStackDepth());
+dsPrintAbandon(token4);
+dsPutc('\n');
+dsPuts("13  Puts:  Added last '\\n' with dsPutc(), this with dsPuts().");
+dsPrintf("14     3:%d Last line!  Expect 7 & 12 missing, 10 dupped.  lenAll:%d  Bye.\n",
+         dsPrintStackDepth(),dsPrintSizeAll());
+dsPrintFlushAndCloseAll();
+assert(dsStack == NULL);
+int ix = 0;
+for (;ix<20;ix++) // tested to 1000
+    {
+    dsPrintOpen(32); // Don't even care about tokens!
+    if (ix == 0)
+        dsPrintf("CannibalizeAndCloseAll():");
+    dsPrintf(" %d",dsPrintStackDepth());
+    }
+content = dsPrintCannibalizeAndCloseAll();
+printf("\n[%s]\n",content);
+freez(&content);
+}
+*/
+
diff --git a/lib/dtdParse.c b/lib/dtdParse.c
new file mode 100644
index 0000000..dd86acf
--- /dev/null
+++ b/lib/dtdParse.c
@@ -0,0 +1,466 @@
+/* dtdParse - parse an XML DTD file.  Actually this only
+ * parses a relatively simple subset of DTD's.  It's still
+ * useful for autoXml and xmlToSql. */
+
+#include "common.h"
+#include "hash.h"
+#include "linefile.h"
+#include "dystring.h"
+#include "obscure.h"
+#include "dtdParse.h"
+
+
+static void syntaxError(struct lineFile *lf)
+/* Report syntax error and exit. */
+{
+errAbort("Syntax error line %d of %s", lf->lineIx, lf->fileName);
+}
+
+static char *needNextWord(char **pLine, struct lineFile *lf)
+/* Get next word in line.  Squawk and die if can't find it. */
+{
+char *word = nextWord(pLine);
+if (word == NULL)
+    errAbort("Missing data line %d of %s", lf->lineIx, lf->fileName);
+return word;
+}
+
+void needQuotedString( char *in, char *out, struct lineFile *lf, char **retNext)
+/* Grab quoted string starting at in and put it into out.  Advance retNext
+ * to just past quoted string.  In and out may point to same buffer. */
+{
+if (!parseQuotedString(in, out, retNext))
+    errAbort("Missing closing quote line %d of %s", lf->lineIx, lf->fileName);
+}
+
+static boolean isAllUpper(char *s)
+/* Return true if all alphabetical letters in string
+ * are upper case. */
+{
+char c;
+while ((c = *s++) != 0)
+    {
+    if (isalpha(c) && !isupper(c))
+        return FALSE;
+    }
+return TRUE;
+}
+
+static boolean isAllLower(char *s)
+/* Return true if all alphabetical letters in string
+ * are upper case. */
+{
+char c;
+while ((c = *s++) != 0)
+    {
+    if (isalpha(c) && !islower(c))
+        return FALSE;
+    }
+return TRUE;
+}
+
+
+static char *mixedCaseName(char *prefix, char *orig)
+/* Convert var_like_this or VAR_LIKE_THIS or even
+ * var-like-this to varLikeThis. */
+{
+char *mixed;
+char *d, *s = orig;
+char c;
+int prefixLen = strlen(prefix), len;
+boolean nextUpper;
+boolean allUpper = isAllUpper(orig); 
+boolean allLower = isAllLower(orig);
+boolean initiallyMixed = (!allUpper && !allLower);
+
+/* Allocate string big enough for prefix and all. */
+len = strlen(orig) + prefixLen;
+mixed = d = needMem(len+1);
+strcpy(d, prefix);
+d += prefixLen;
+nextUpper = (prefixLen > 0);
+
+for (;;)
+   {
+   c = *s++;
+   if (c == '_' || c == '-' || c == ':')
+       nextUpper = TRUE;
+   else
+       {
+       if (nextUpper)
+           c = toupper(c);
+       else if (!initiallyMixed)
+           c = tolower(c);
+       nextUpper = FALSE;
+       *d++ = c;
+       if (c == 0)
+	   break;
+       }
+   }
+return mixed;
+}
+
+static struct hash *initialEntityHash()
+/* Make an initial entity hash - one that is just made up
+ * of our built-ins. */
+{
+struct hash *hash = hashNew(0);
+hashAdd(hash, "INTEGER", cloneString("#INT"));
+hashAdd(hash, "REAL", cloneString("#FLOAT"));
+hashAdd(hash, "INT", cloneString("INT"));
+hashAdd(hash, "FLOAT", cloneString("FLOAT"));
+return hash;
+}
+
+static struct dtdElement *parseElement(
+	char *prefix, char *textField, char *line, 
+	struct hash *elHash, struct lineFile *lf)
+/* Parse out <!ELEMENT line after <!ELEMENT. */
+{
+char *word, *s, *e;
+char *words[256];
+int wordCount, i;
+struct dtdElChild *ec;
+struct dtdElement *el;
+boolean isOr;
+char orCopyCode = '?';
+
+word = needNextWord(&line, lf);
+s = word + strlen(word)-1;
+if (s[0] == '>')
+   *s = 0;
+if ((el = hashFindVal(elHash, word)) != NULL)
+    errAbort("Duplicate element %s line %d and %d of %s", word, el->lineIx, lf->lineIx, lf->fileName);
+AllocVar(el);
+el->lineIx = lf->lineIx;
+hashAddSaveName(elHash, word, el, &el->name);
+el->mixedCaseName = mixedCaseName(prefix, el->name);
+if (line != NULL && (s = strchr(line, '(')) != NULL)
+    {
+    s += 1;
+    if ((e = strchr(line, ')')) == NULL)
+        errAbort("Missing ')' line %d of %s", lf->lineIx, lf->fileName);
+    *e = 0;
+    isOr = (strchr(s, '|') != NULL);
+    if (isOr)
+      {
+	orCopyCode = *(e+1);
+	if ((orCopyCode != '+') && (orCopyCode != '*'))
+	  orCopyCode = '?';
+      }
+    wordCount = chopString(s, "| ,\t", words, ArraySize(words));
+    if (wordCount == ArraySize(words))
+	errAbort("Too many children in list line %d of %s", lf->lineIx, lf->fileName);
+    for (i=0; i<wordCount; ++i)
+	{
+	char *name = words[i];
+	int len = strlen(name);
+	char lastC = name[len-1];
+	if (name[0] == '#')
+	    {
+	    if (isOr)
+	        errAbort("# character in enumeration not allowed line %d of %s",
+		   lf->lineIx, lf->fileName);
+	    if (el->textType != NULL)
+		errAbort("Multiple types for text between tags line %d of %s", 
+			lf->lineIx, lf->fileName);
+	    el->textType = cloneString(name);
+	    }
+	else
+	    {
+	    AllocVar(ec);
+	    slAddHead(&el->children, ec);
+	    ec->isOr = isOr;
+	    if (isOr)
+	       ec->copyCode = orCopyCode;
+	    else
+		{
+		if (lastC == '+' || lastC == '?' || lastC == '*')
+		    {
+		    ec->copyCode = lastC;
+		    name[len-1] = 0;
+		    }
+		else
+		    ec->copyCode = '1';
+		}
+	    if (sameString(name, textField))
+		errAbort("Name conflict with default text field name line %d of %s", lf->lineIx, lf->fileName);
+	    ec->name = cloneString(name);
+	    }
+	}
+    slReverse(&el->children);
+    }
+return el;
+}
+
+static void parseAttribute(char *line, char *textField,
+	struct hash *elHash, struct lineFile *lf)
+/* Parse out <!ATTLIST line after <!ATTLIST. */
+{
+char *word;
+struct dtdAttribute *att;
+struct dtdElement *el;
+char *e;
+
+/* Get rid of trailing '>' */
+e = strrchr(line, '>');
+if (e == NULL)
+    errAbort("Missing '>' line %d of %s", lf->lineIx, lf->fileName);
+*e = 0;
+
+word = needNextWord(&line, lf);
+if ((el = hashFindVal(elHash, word)) == NULL)
+    errAbort("Undefined %s line %d of %s", word, lf->lineIx, lf->fileName);
+word = needNextWord(&line, lf);
+if (sameString(word, textField))
+    errAbort("Name conflict with text field name line %d of %s", lf->lineIx, lf->fileName);
+AllocVar(att);
+att->name = cloneString(word);
+att->mixedCaseName = mixedCaseName("", att->name);
+word = needNextWord(&line, lf);
+att->type = cloneString(word);
+line = skipLeadingSpaces(line);
+if (line[0] == '#')
+    {
+    word = needNextWord(&line, lf);
+    if (sameWord("#REQUIRED", word))
+        att->required = TRUE;
+    else if (sameWord("#IMPLIED", word))
+        att->usual = NULL;
+    else
+        errAbort("Unknown directive %s line %d of %s", word, lf->lineIx, lf->fileName);
+    }
+else if (line[0] == '\'' || line[0] == '"')
+    {
+    word = line;
+    needQuotedString(word, word, lf, &line);
+    att->usual = cloneString(word);
+    }
+else
+    {
+    word = needNextWord(&line, lf);
+    att->usual = cloneString(word);
+    }
+slAddTail(&el->attributes, att);
+}
+
+
+void parseEntity(struct hash *entityHash, struct hash *predefEntityHash,
+	char *line, struct lineFile *lf)
+/* Parse out an entity and add it to hash.  We'll dodge our predefined entities. */
+{
+char *percent = needNextWord(&line, lf);
+char *name = needNextWord(&line, lf);
+char *value = skipLeadingSpaces(line);
+if (value[0] != '"')
+    errAbort("Expecting quoted string at end of ENTITY tag line %d of %s",
+    	lf->lineIx, lf->fileName);
+needQuotedString(value, value, lf, &line);
+if (!sameString(percent, "%"))
+    errAbort("Expecting %% after ENTITY tag line %d of %s", lf->lineIx, lf->fileName);
+if (hashLookup(predefEntityHash, name) == NULL)
+/* We don't want to overwrite the predefined entities.  These are all
+ * defined to be #PCDATA or CDATA for the benefit of non-UCSC XML tools.
+ * Internally we map them to #INT/#FLOAT etc. so we can have numbers
+ * as well as strings in our C structures and relational database tables. */
+    {
+    char *oldVal = hashFindVal(entityHash, name);
+    if (oldVal != NULL)
+        {
+	if (!sameString(oldVal, value))
+	    errAbort("Entity %s redefined line %d of %s", name, lf->lineIx, lf->fileName);
+	}
+    else
+        {
+	hashAdd(entityHash, name, cloneString(value));
+	}
+    }
+}
+
+
+static void fixupChildRefs(struct dtdElement *elList, struct hash *elHash, char *fileName)
+/* Go through all of elements children and make sure that the corresponding
+ * elements are defined. */
+{
+struct dtdElement *el, *child;
+struct dtdElChild *ec;
+for (el = elList; el != NULL; el = el->next)
+    {
+    for (ec = el->children; ec != NULL; ec = ec->next)
+        {
+	if ((child = hashFindVal(elHash, ec->name)) == NULL)
+	    errAbort("%s's child %s undefined line %d of %s", el->name, ec->name, el->lineIx, fileName);
+	ec->el = child;
+	}
+    }
+}
+
+static char *eatComment(struct lineFile *lf, char *line)
+/* Eat possibly multi-line comment.  Return line past end of comment */
+{
+char *s;
+for (;;)
+    {
+    if ((s = stringIn("-->", line)) != NULL)
+        {
+	line = skipLeadingSpaces(s+3);
+	if (line[0] == 0)
+	    line = NULL;
+	return line;
+	}
+    if (!lineFileNext(lf, &line, NULL))
+        return NULL;
+    }
+}
+
+static void expandEntities(char *s, struct hash *entityHash, struct lineFile *lf,
+	struct dyString *dest)
+/* Copy s into dest, expanding any entity (something in format %name;) 
+ * by looking it up in entity hash. */
+{
+char c;
+while ((c = *s++) != 0)
+    {
+    if (c == '%' && !isspace(s[0]))
+        {
+	char *name = s;
+	char *end = strchr(s, ';');
+	char *value;
+	if (end == NULL)
+	    errAbort("Can't find ; after %% to close entity line %d of %s",
+	    	lf->lineIx, lf->fileName);
+	*end++ = 0;
+	s = end;
+	value = hashFindVal(entityHash, name);
+	if (value == NULL)
+	    errAbort("Entity %%%s; is not defined line %d of %s",
+	    	name, lf->lineIx, lf->fileName);
+	dyStringAppend(dest, value);
+	}
+    else
+        dyStringAppendC(dest, c);
+    }
+}
+
+static char *dtdxTag(struct lineFile *lf, struct hash *entityHash,
+	struct dyString *buf)
+/* Return next tag. */
+{
+char *line;
+
+/* Skip until get a line that starts with '<' */
+if (!lineFileNextReal(lf,  &line))
+    return NULL;
+line = trimSpaces(line);
+if (line[0] != '<')
+    errAbort("Text outside of a tag line %d of %s", lf->lineIx, lf->fileName);
+dyStringClear(buf);
+for (;;)
+    {
+    expandEntities(line, entityHash, lf, buf);
+    if (buf->string[buf->stringSize-1] == '>')
+         break;
+    dyStringAppendC(buf, ' ');
+    if (!lineFileNext(lf, &line, NULL))
+        errAbort("End of file %s inside of a tag.", lf->fileName);
+    line = trimSpaces(line);
+    }
+return buf->string;
+}
+
+void dtdParse(char *fileName, char *prefix, char *textField,
+	struct dtdElement **retList, struct hash **retHash)
+/* Parse out a dtd file into elements that are returned in retList,
+ * and for your convenience also in retHash (which is keyed by the
+ * name of the element.  Note that XML element names can include the '-'
+ * character.  For this and other reasons in addition to the element
+ * name as it appears in the XML tag, the element has a mixedCaseName
+ * that strips '-' and '_' chars, and tries to convert the name to
+ * a mixed-case convention style name.  The prefix if any will be
+ * prepended to mixed-case names.  The textField is what to name
+ * the field that contains the letters between tags.  By default
+ * (if NULL) it is "text." */
+{
+struct hash *elHash = newHash(8);
+struct hash *entityHash = initialEntityHash();
+struct hash *predefEntityHash = initialEntityHash();
+struct dtdElement *elList = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *line, *word;
+struct dyString *buf = dyStringNew(0);
+
+if (prefix == NULL)
+    prefix = "";
+if (textField == NULL)
+    textField = "text";
+while ((line = dtdxTag(lf, entityHash, buf)) != NULL)
+    {
+    line = trimSpaces(line);
+    if (line == NULL || line[0] == 0 || line[0] == '#')
+        continue;
+    if (startsWith("<!--", line))
+	{
+        line = eatComment(lf, line);
+	if (line == NULL)
+	    continue;
+	}
+    if (!startsWith("<!", line))
+        syntaxError(lf);
+    line += 2;
+    word = needNextWord(&line, lf);
+    if (sameWord("ELEMENT", word))
+        {
+	el = parseElement(prefix, textField, line, elHash, lf);
+	slAddHead(&elList, el);
+	}
+    else if (sameWord("ATTLIST", word))
+        {
+	parseAttribute(line, textField, elHash, lf);
+	}
+    else if (sameWord("ENTITY", word))
+        {
+	parseEntity(entityHash, predefEntityHash, line, lf);
+	}
+    else
+        {
+	errAbort("Don't understand %s line %d of %s", word, lf->lineIx, lf->fileName);
+	}
+    }
+lineFileClose(&lf);
+dyStringFree(&buf);
+slReverse(&elList);
+fixupChildRefs(elList, elHash, fileName);
+freeHashAndVals(&entityHash);
+freeHashAndVals(&predefEntityHash);
+*retHash = elHash;
+*retList = elList;
+}
+
+void dtdElementDump(struct dtdElement *el, FILE *f)
+/* Dump info on element. */
+{
+struct dtdElChild *ec;
+struct dtdAttribute *att;
+fprintf(f, "%s %s (", el->name, el->mixedCaseName);
+for (ec = el->children; ec != NULL; ec = ec->next)
+    {
+    fprintf(f, "%s", ec->name);
+    if (ec->copyCode != '1')
+        fprintf(f, "%c", ec->copyCode);
+    if (ec->isOr)
+        fprintf(f, " (isOr)");
+    if (ec->next != NULL)
+        fprintf(f, ", ");
+    }
+fprintf(f, ")");
+if (el->textType != NULL)
+    fprintf(f, " (%s)", el->textType);
+fprintf(f, "\n");
+for (att = el->attributes; att != NULL; att = att->next)
+    {
+    fprintf(f, "  %s %s %s %s\n",
+        att->name, att->type, (att->usual ? att->usual : "n/a"),  
+	(att->required ? "required" : "optional"));
+    }
+}
+
diff --git a/lib/dystring.c b/lib/dystring.c
new file mode 100644
index 0000000..1fa6c22
--- /dev/null
+++ b/lib/dystring.c
@@ -0,0 +1,250 @@
+/* dystring - dynamically resizing string.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "dystring.h"
+
+
+struct dyString *newDyString(int initialBufSize)
+/* Allocate dynamic string with initial buffer size.  (Pass zero for default) */
+{
+struct dyString *ds;
+AllocVar(ds);
+if (initialBufSize == 0)
+    initialBufSize = 512;
+ds->string = needMem(initialBufSize+1);
+ds->bufSize = initialBufSize;
+return ds;
+}
+
+void freeDyString(struct dyString **pDs)
+/* Free up dynamic string. */
+{
+struct dyString *ds;
+if ((ds = *pDs) != NULL)
+    {
+    freeMem(ds->string);
+    freez(pDs);
+    }
+}
+
+char *dyStringCannibalize(struct dyString **pDy)
+/* Kill dyString, but return the string it is wrapping
+ * (formerly dy->string).  This should be free'd at your
+ * convenience. */
+{
+char *s;
+struct dyString *ds = *pDy;
+assert(ds != NULL);
+s = ds->string;
+freez(pDy);
+return s;
+}
+
+void freeDyStringList(struct dyString **pDs)
+/* free up a list of dyStrings */
+{
+struct dyString *ds, *next;
+for(ds = *pDs; ds != NULL; ds = next)
+    {
+    next = ds->next;
+    freeDyString(&ds);
+    }
+*pDs = NULL;
+}
+
+static void dyStringExpandBuf(struct dyString *ds, int newSize)
+/* Expand buffer to new size. */
+{
+ds->string = needMoreMem(ds->string, ds->stringSize+1, newSize+1);
+ds->bufSize = newSize;
+}
+
+void dyStringBumpBufSize(struct dyString *ds, int size)
+/* Force dyString buffer to be at least given size. */
+{
+if (ds->bufSize < size)
+    dyStringExpandBuf(ds, size);
+}
+
+void dyStringAppendN(struct dyString *ds, char *string, int stringSize)
+/* Append string of given size to end of string. */
+{
+int oldSize = ds->stringSize;
+int newSize = oldSize + stringSize;
+char *buf;
+if (newSize > ds->bufSize)
+    {
+    int newAllocSize = newSize + oldSize;
+    int oldSizeTimesOneAndAHalf = oldSize * 1.5;
+    if (newAllocSize < oldSizeTimesOneAndAHalf)
+        newAllocSize = oldSizeTimesOneAndAHalf;
+    dyStringExpandBuf(ds,newAllocSize);
+    }
+buf = ds->string;
+memcpy(buf+oldSize, string, stringSize);
+ds->stringSize = newSize;
+buf[newSize] = 0;
+}
+
+char dyStringAppendC(struct dyString *ds, char c)
+/* Append char to end of string. */
+{
+char *s;
+if (ds->stringSize >= ds->bufSize)
+     dyStringExpandBuf(ds, ds->bufSize+256);
+s = ds->string + ds->stringSize++;
+*s++ = c;
+*s = 0;
+return c;
+}
+
+void dyStringAppendMultiC(struct dyString *ds, char c, int n)
+/* Append N copies of char to end of string. */
+{
+int oldSize = ds->stringSize;
+int newSize = oldSize + n;
+int newAllocSize = newSize + oldSize;
+char *buf;
+if (newSize > ds->bufSize)
+    dyStringExpandBuf(ds,newAllocSize);
+buf = ds->string;
+memset(buf+oldSize, c, n);
+ds->stringSize = newSize;
+buf[newSize] = 0;
+}
+
+void dyStringAppend(struct dyString *ds, char *string)
+/* Append zero terminated string to end of dyString. */
+{
+dyStringAppendN(ds, string, strlen(string));
+}
+
+void dyStringAppendEscapeQuotes(struct dyString *dy, char *string,
+	char quot, char esc)
+/* Append escaped-for-quotation version of string to dy. */
+{
+char c;
+char *s = string;
+while ((c = *s++) != 0)
+     {
+     if (c == quot)
+         dyStringAppendC(dy, esc);
+     dyStringAppendC(dy, c);
+     }
+}
+
+void dyStringVaPrintf(struct dyString *ds, char *format, va_list args)
+/* VarArgs Printf to end of dyString. */
+{
+/* attempt to format the string in the current space.  If there
+ * is not enough room, increase the buffer size and try again */
+int avail, sz;
+while (TRUE)
+    {
+    va_list argscp;
+    va_copy(argscp, args);
+    avail = ds->bufSize - ds->stringSize;
+    if (avail <= 0)
+        {
+	/* Don't pass zero sized buffers to vsnprintf, because who knows
+	 * if the library function will handle it. */
+        dyStringExpandBuf(ds, ds->bufSize+ds->bufSize);
+	avail = ds->bufSize - ds->stringSize;
+	}
+    sz = vsnprintf(ds->string + ds->stringSize, avail, format, argscp);
+    va_end(argscp);
+
+    /* note that some version return -1 if too small */
+    if ((sz < 0) || (sz >= avail))
+        dyStringExpandBuf(ds, ds->bufSize+ds->bufSize);
+    else
+        {
+        ds->stringSize += sz;
+        break;
+        }
+    }
+}
+
+void dyStringPrintf(struct dyString *ds, char *format, ...)
+/*  Printf to end of dyString. */
+{
+va_list args;
+va_start(args, format);
+dyStringVaPrintf(ds, format, args);
+va_end(args);
+}
+
+struct dyString *dyStringCreate(char *format, ...)
+/*  Create a dyString with a printf style initial content */
+{
+int len = strlen(format) * 3;
+struct dyString *ds = newDyString(len);
+va_list args;
+va_start(args, format);
+dyStringVaPrintf(ds, format, args);
+va_end(args);
+return ds;
+}
+
+struct dyString * dyStringSub(char *orig, char *in, char *out)
+/* Make up a duplicate of orig with all occurences of in substituted
+ * with out. */
+{
+int inLen = strlen(in), outLen = strlen(out), origLen = strlen(orig);
+struct dyString *dy = newDyString(origLen + 2*outLen);
+char *s, *e;
+
+if (orig == NULL) return NULL;
+for (s = orig; ;)
+    {
+    e = stringIn(in, s);
+    if (e == NULL)
+	{
+        e = orig + origLen;
+	dyStringAppendN(dy, s, e - s);
+	break;
+	}
+    else
+        {
+	dyStringAppendN(dy, s, e - s);
+	dyStringAppendN(dy, out, outLen);
+	s = e + inLen;
+	}
+    }
+return dy;
+}
+
+void dyStringResize(struct dyString *ds, int newSize)
+/* resize a string, if the string expands, blanks are appended */
+{
+int oldSize = ds->stringSize;
+if (newSize > oldSize)
+    {
+    /* grow */
+    if (newSize > ds->bufSize)
+        dyStringExpandBuf(ds, newSize + ds->stringSize);
+    memset(ds->string+newSize, ' ', newSize);
+    }
+ds->string[newSize] = '\0';
+ds->stringSize = newSize;
+}
+
+void dyStringQuoteString(struct dyString *dy, char quotChar, char *text)
+/* Append quotChar-quoted text (with any internal occurrences of quotChar
+ * \-escaped) onto end of dy. */
+{
+char c;
+
+dyStringAppendC(dy, quotChar);
+while ((c = *text++) != 0)
+    {
+    if (c == quotChar)
+        dyStringAppendC(dy, '\\');
+    dyStringAppendC(dy, c);
+    }
+dyStringAppendC(dy, quotChar);
+}
+
diff --git a/lib/emblParse.c b/lib/emblParse.c
new file mode 100644
index 0000000..5061010
--- /dev/null
+++ b/lib/emblParse.c
@@ -0,0 +1,156 @@
+/* Parse EMBL formatted files. EMBL files are basically line
+ * oriented.  Each line begins with a short (usually two letter)
+ * type word.  Adjacent lines with the same type are generally
+ * considered logical extensions of each other.  In many cases
+ * lines can be considered fields in an EMBL database.  Records
+ * are separated by lines starting with '//'  Generally lines
+ * starting with XX are empty and used to make the records more
+ * human readable.   Here is an example record:
+ 
+ C  M00001
+ XX
+ ID  V$MYOD_01
+ XX
+ NA  MyoD
+ XX
+ DT  EWI (created); 19.10.92.
+ DT  ewi (updated); 22.06.95.
+ XX
+ PO     A     C     G     T
+ 01     0     0     0     0
+ 02     0     0     0     0
+ 03     1     2     2     0
+ 04     2     1     2     0
+ 05     3     0     1     1
+ 06     0     5     0     0
+ 07     5     0     0     0
+ 08     0     0     4     1
+ 09     0     1     4     0
+ 10     0     0     0     5
+ 11     0     0     5     0
+ 12     0     1     2     2
+ 13     0     2     0     3
+ 14     1     0     3     1
+ 15     0     0     0     0
+ 16     0     0     0     0
+ 17     0     0     0     0
+ XX
+ BF  T00526; MyoD                         ; mouse
+ XX
+ BA  5 functional elements in 3 genes
+ XX
+ XX
+ //
+ 
+ */
+
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "emblParse.h"
+
+
+boolean emblLineGroup(struct lineFile *lf, char type[16], struct dyString *val)
+/* Read next line of embl file.  Read line after that too if it
+ * starts with the same type field. Return FALSE at EOF. */
+{
+char *line, *word;
+int typeLen = 0;
+
+dyStringClear(val);
+while (lineFileNext(lf, &line, NULL))
+    {
+    line = skipLeadingSpaces(line);
+
+    /* Parse out first word into type. */
+    if (isspace(line[0]))
+        errAbort("embl line that doesn't start with type line %d of %s", 
+		lf->lineIx, lf->fileName);
+    if (typeLen == 0)
+        {
+	word = nextWord(&line);
+	typeLen = strlen(word);
+	if (typeLen >= 16)
+	    errAbort("Type word at start of line too long for embl file line %d of %s",
+	    	lf->lineIx, lf->fileName);
+	strcpy(type, word);
+	}
+    else if (!startsWith(type, line) || !isspace(line[typeLen]))
+        {
+	lineFileReuse(lf);
+	break;
+	}
+    else
+        {
+	dyStringAppendC(val, '\n');
+	word = nextWord(&line);
+	}
+
+    if (line != NULL)
+	{
+	/* Usually have two spaces after type. */
+	if (isspace(line[0]))
+	   ++line;
+	if (isspace(line[0]))
+	   ++line;
+
+	/* Append what's rest of line to return value. */
+	dyStringAppend(val, line);
+	}
+    }
+return typeLen > 0;
+}
+
+struct hash *emblRecord(struct lineFile *lf)
+/* Read next record and return it in hash.   (Free this
+ * hash with freeHashAndVals.)   Hash is keyed by type
+ * and has string values. */
+{
+struct hash *hash = NULL;
+char type[16];
+struct dyString *val = newDyString(256);
+boolean gotEnd = FALSE;
+
+while (emblLineGroup(lf, type, val))
+    {
+    if (hash == NULL)
+        hash = newHash(7);
+    if (sameString(type, "//"))
+        {
+	gotEnd = TRUE;
+	break;
+	}
+    hashAdd(hash, type, cloneString(val->string));
+    }
+if (hash != NULL && !gotEnd)
+    warn("Incomplete last record of embl file %s\n", lf->fileName);
+return hash;
+}
+
+static void notEmbl(char *fileName)
+/* Complain it's not really an EMBL file. */
+{
+errAbort("%s is not an emblFile", fileName);
+}
+
+struct lineFile *emblOpen(char *fileName, char type[256])
+/* Open up embl file, verify format and optionally  return 
+ * type (VV line).  Close this with lineFileClose(). */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+struct hash *hash = emblRecord(lf);
+char *vv;
+
+if (hash == NULL)
+    notEmbl(fileName);
+if ((vv = hashFindVal(hash, "VV")) == NULL)
+    notEmbl(fileName);
+if (type != NULL)
+    {
+    if (strlen(vv) >= 256)
+	notEmbl(fileName);
+    strcpy(type, vv);
+    }
+freeHashAndVals(&hash);
+return lf;
+}
diff --git a/lib/errCatch.c b/lib/errCatch.c
new file mode 100644
index 0000000..2f25025
--- /dev/null
+++ b/lib/errCatch.c
@@ -0,0 +1,123 @@
+/* errCatch - help catch errors so that errAborts aren't
+ * fatal, and warn's don't necessarily get printed immediately. 
+ * Note that error conditions caught this way will tend to
+ * leak resources unless there are additional wrappers. 
+ *
+ * Typical usage is
+ * errCatch = errCatchNew();
+ * if (errCatchStart(errCatch))
+ *     doFlakyStuff();
+ * errCatchEnd(errCatch);
+ * if (errCatch->gotError)
+ *     warn("%s", errCatch->message->string);
+ * errCatchFree(&errCatch); 
+ * cleanupFlakyStuff();
+ */
+
+#include "common.h"
+#include "errabort.h"
+#include "dystring.h"
+#include "hash.h"
+#include <pthread.h>
+#include "errCatch.h"
+
+
+
+struct errCatch *errCatchNew()
+/* Return new error catching structure. */
+{
+struct errCatch *errCatch;
+AllocVar(errCatch);
+errCatch->message = dyStringNew(0);
+return errCatch;
+}
+
+void errCatchFree(struct errCatch **pErrCatch)
+/* Free up resources associated with errCatch */
+{
+struct errCatch *errCatch = *pErrCatch;
+if (errCatch != NULL)
+    {
+    dyStringFree(&errCatch->message);
+    freez(pErrCatch);
+    }
+}
+
+static struct errCatch **getStack()
+/* Return a pointer to the errCatch object stack for the current pthread. */
+{
+static pthread_mutex_t getStackMutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_lock( &getStackMutex );
+static struct hash *perThreadStacks = NULL;
+pthread_t pid = pthread_self(); //  can be a pointer or a number
+// A true integer has function would be nicer, but this will do.  
+// Don't safef, theoretically that could abort.
+char key[64];
+snprintf(key, sizeof(key), "%lld",  ptrToLL(pid));
+key[ArraySize(key)-1] = '\0';
+if (perThreadStacks == NULL)
+    perThreadStacks = hashNew(0);
+struct hashEl *hel = hashLookup(perThreadStacks, key);
+if (hel == NULL)
+    hel = hashAdd(perThreadStacks, key, NULL);
+pthread_mutex_unlock( &getStackMutex );
+return (struct errCatch **)(&hel->val);
+}
+
+static void errCatchAbortHandler()
+/* semiAbort */
+{
+struct errCatch **pErrCatchStack = getStack(), *errCatchStack = *pErrCatchStack;
+errCatchStack->gotError = TRUE;
+longjmp(errCatchStack->jmpBuf, -1);
+}
+
+static void errCatchWarnHandler(char *format, va_list args)
+/* Write an error to top of errCatchStack. */
+{
+struct errCatch **pErrCatchStack = getStack(), *errCatchStack = *pErrCatchStack;
+dyStringVaPrintf(errCatchStack->message, format, args);
+dyStringAppendC(errCatchStack->message, '\n');
+}
+
+boolean errCatchPushHandlers(struct errCatch *errCatch)
+/* Push error handlers.  Not usually called directly. */
+{
+pushAbortHandler(errCatchAbortHandler);
+pushWarnHandler(errCatchWarnHandler);
+struct errCatch **pErrCatchStack = getStack();
+slAddHead(pErrCatchStack, errCatch);
+return TRUE;
+}
+
+void errCatchEnd(struct errCatch *errCatch)
+/* Restore error handlers and pop self off of catching stack. */
+{
+popWarnHandler();
+popAbortHandler();
+struct errCatch **pErrCatchStack = getStack(), *errCatchStack = *pErrCatchStack;
+if (errCatch != errCatchStack)
+   errAbort("Mismatch between errCatch and errCatchStack");
+*pErrCatchStack = errCatch->next;
+}
+
+boolean errCatchFinish(struct errCatch **pErrCatch)
+/* Finish up error catching.  Report error if there is a
+ * problem and return FALSE.  If no problem return TRUE.
+ * This handles errCatchEnd and errCatchFree. */
+{
+struct errCatch *errCatch = *pErrCatch;
+boolean ok = TRUE;
+if (errCatch != NULL)
+    {
+    errCatchEnd(errCatch);
+    if (errCatch->gotError)
+	{
+	ok = FALSE;
+	warn("%s", errCatch->message->string);
+	}
+    errCatchFree(pErrCatch);
+    }
+return ok;
+}
+
diff --git a/lib/errabort.c b/lib/errabort.c
new file mode 100644
index 0000000..e3f8a7d
--- /dev/null
+++ b/lib/errabort.c
@@ -0,0 +1,326 @@
+/* ErrAbort.c - our error handler.
+ *
+ * This maintains two stacks - a warning message printer
+ * stack, and a "abort handler" stack.
+ *
+ * By default the warnings will go to stderr, and
+ * aborts will exit the program.  You can push a
+ * function on to the appropriate stack to change
+ * this behavior.  The top function on the stack
+ * gets called.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+// developer: this include is for an occasionally useful means of getting stack info without
+// crashing
+// however, it is not supported on cygwin.  Conditionally compile this in when desired.
+//#define BACKTRACE_EXISTS
+#ifdef BACKTRACE_EXISTS
+#include <execinfo.h>
+#endif///def BACKTRACE_EXISTS
+#include <pthread.h>
+#include "common.h"
+#include "hash.h"
+#include "dystring.h"
+#include "errabort.h"
+
+
+
+#define maxWarnHandlers 20
+#define maxAbortHandlers 12
+struct perThreadAbortVars
+/* per thread variables for abort and warn */
+    {
+    boolean debugPushPopErr;        // generate stack dump on push/pop error
+    boolean errAbortInProgress;     /* Flag to indicate that an error abort is in progress.
+                                      * Needed so that a warn handler can tell if it's really
+                                      * being called because of a warning or an error. */
+    WarnHandler warnArray[maxWarnHandlers];
+    int warnIx;
+    AbortHandler abortArray[maxAbortHandlers];
+    int abortIx;
+    };
+
+static struct perThreadAbortVars *getThreadVars();  // forward declaration
+
+static void defaultVaWarn(char *format, va_list args)
+/* Default error message handler. */
+{
+if (format != NULL) {
+    fflush(stdout);
+    vfprintf(stderr, format, args);
+    fprintf(stderr, "\n");
+    }
+}
+
+static void silentVaWarn(char *format, va_list args)
+/* Warning handler that just hides it.  Useful sometimes when high level code
+ * expects low level code may fail (as in finding a file on the net) but doesn't
+ * want user to be bothered about it. */
+{
+}
+
+
+void vaWarn(char *format, va_list args)
+/* Call top of warning stack to issue warning. */
+{
+struct perThreadAbortVars *ptav = getThreadVars();
+ptav->warnArray[ptav->warnIx](format, args);
+}
+
+void warn(char *format, ...)
+/* Issue a warning message. */
+{
+va_list args;
+va_start(args, format);
+vaWarn(format, args);
+va_end(args);
+}
+
+void warnWithBackTrace(char *format, ...)
+/* Issue a warning message and append backtrace. */
+{
+va_list args;
+va_start(args, format);
+struct dyString *dy = newDyString(255);
+dyStringAppend(dy, format);
+
+#define STACK_LIMIT 20
+char **strings = NULL;
+int count = 0;
+
+// developer: this is an occasionally useful means of getting stack info without crashing
+// however, it is not supported on cygwin.  Conditionally compile this in when desired.
+// The define is at top to include execinfo.h
+#ifdef BACKTRACE_EXISTS
+void *buffer[STACK_LIMIT];
+count = backtrace(buffer, STACK_LIMIT);
+strings = backtrace_symbols(buffer, count);
+#endif///def BACKTRACE_EXISTS
+
+if (strings == NULL)
+    dyStringAppend(dy,"\nno backtrace_symbols available in errabort::warnWithBackTrace().");
+else
+    {
+    int ix = 1;
+    dyStringAppend(dy,"\nBACKTRACE (use on cmdLine):");
+    if (strings[1] != NULL)
+        {
+        strSwapChar(strings[1],' ','\0');
+        dyStringPrintf(dy,"\naddr2line -Cfise %s",strings[1]);
+        strings[1] += strlen(strings[1]) + 1;
+        }
+    for (; ix < count && strings[ix] != NULL; ix++)
+        {
+        strings[ix] = skipBeyondDelimit(strings[ix],'[');
+        strSwapChar(strings[ix],']','\0');
+        dyStringPrintf(dy," %s",strings[ix]);
+        }
+
+    free(strings);
+    }
+vaWarn(dyStringCannibalize(&dy), args);
+va_end(args);
+}
+
+
+void errnoWarn(char *format, ...)
+/* Prints error message from UNIX errno first, then does rest of warning. */
+{
+char fbuf[512];
+va_list args;
+va_start(args, format);
+sprintf(fbuf, "%s\n%s", strerror(errno), format);
+vaWarn(fbuf, args);
+va_end(args);
+}
+
+
+void pushWarnHandler(WarnHandler handler)
+/* Set abort handler */
+{
+struct perThreadAbortVars *ptav = getThreadVars();
+if (ptav->warnIx >= maxWarnHandlers-1)
+    {
+    if (ptav->debugPushPopErr)
+        dumpStack("pushWarnHandler overflow");
+    errAbort("Too many pushWarnHandlers, can only handle %d\n", maxWarnHandlers-1);
+    }
+ptav->warnArray[++ptav->warnIx] = handler;
+}
+
+void popWarnHandler()
+/* Revert to old warn handler. */
+{
+struct perThreadAbortVars *ptav = getThreadVars();
+if (ptav->warnIx <= 0)
+    {
+    if (ptav->debugPushPopErr)
+        dumpStack("popWarnHandler underflow");
+    errAbort("Too few popWarnHandlers");
+    }
+--ptav->warnIx;
+}
+
+static void defaultAbort()
+/* Default error handler exits program. */
+{
+if ((getenv("ERRASSERT") != NULL) || (getenv("ERRABORT") != NULL))
+    abort();
+else
+    exit(-1);
+}
+
+
+void noWarnAbort()
+/* Abort without message. */
+{
+struct perThreadAbortVars *ptav = getThreadVars();
+ptav->abortArray[ptav->abortIx]();
+exit(-1);               /* This is just to make compiler happy.
+                         * We have already exited or longjmped by now. */
+}
+
+void vaErrAbort(char *format, va_list args)
+/* Abort function, with optional (vprintf formatted) error message. */
+{
+/* flag is needed because both errAbort and warn generate message
+ * using the warn handler, however sometimes one needed to know
+ * (like when logging), if it's an error or a warning.  This is far from
+ * perfect, as this isn't cleared if the error handler continues,
+ * as with an exception mechanism. */
+struct perThreadAbortVars *ptav = getThreadVars();
+ptav->errAbortInProgress = TRUE;
+vaWarn(format, args);
+noWarnAbort();
+}
+
+void errAbort(char *format, ...)
+/* Abort function, with optional (printf formatted) error message. */
+{
+va_list args;
+va_start(args, format);
+vaErrAbort(format, args);
+va_end(args);
+}
+
+void errnoAbort(char *format, ...)
+/* Prints error message from UNIX errno first, then does errAbort. */
+{
+char fbuf[512];
+va_list args;
+va_start(args, format);
+sprintf(fbuf, "%s\n%s", strerror(errno), format);
+vaErrAbort(fbuf, args);
+va_end(args);
+}
+
+void pushAbortHandler(AbortHandler handler)
+/* Set abort handler */
+{
+struct perThreadAbortVars *ptav = getThreadVars();
+if (ptav->abortIx >= maxAbortHandlers-1)
+    {
+    if (ptav->debugPushPopErr)
+        dumpStack("pushAbortHandler overflow");
+    errAbort("Too many pushAbortHandlers, can only handle %d", maxAbortHandlers-1);
+    }
+ptav->abortArray[++ptav->abortIx] = handler;
+}
+
+void popAbortHandler()
+/* Revert to old abort handler. */
+{
+struct perThreadAbortVars *ptav = getThreadVars();
+if (ptav->abortIx <= 0)
+    {
+    if (ptav->debugPushPopErr)
+        dumpStack("popAbortHandler underflow");
+    errAbort("Too many popAbortHandlers\n");
+    }
+--ptav->abortIx;
+}
+
+static void debugAbort()
+/* Call the debugger. */
+{
+fflush(stdout);
+assert(FALSE);
+defaultAbort();
+}
+
+void pushDebugAbort()
+/* Push abort handler that will invoke debugger. */
+{
+pushAbortHandler(debugAbort);
+}
+
+static void warnAbortHandler(char *format, va_list args)
+/* warn handler that also aborts. */
+{
+defaultVaWarn(format, args);
+noWarnAbort();
+}
+
+void pushWarnAbort()
+/* Push handler that will abort on warnings. */
+{
+pushWarnHandler(warnAbortHandler);
+}
+
+void pushSilentWarnHandler()
+/* Set warning handler to be quiet.  Do a popWarnHandler to restore. */
+{
+pushWarnHandler(silentVaWarn);
+}
+
+void errAbortDebugnPushPopErr()
+/*  generate stack dump if there is a error in the push/pop functions */
+{
+struct perThreadAbortVars *ptav = getThreadVars();
+ptav->debugPushPopErr = TRUE;
+}
+
+boolean isErrAbortInProgress() 
+/* Flag to indicate that an error abort is in progress.
+ * Needed so that a warn handler can tell if it's really
+ * being called because of a warning or an error. */
+{
+struct perThreadAbortVars *ptav = getThreadVars();
+return ptav->errAbortInProgress;
+}
+
+
+static struct perThreadAbortVars *getThreadVars()
+/* Return a pointer to the perThreadAbortVars for the current pthread. */
+{
+static pthread_mutex_t ptavMutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_lock( &ptavMutex );
+static struct hash *perThreadVars = NULL;
+pthread_t pid = pthread_self(); //  can be a pointer or a number
+// A true integer has function would be nicer, but this will do.  
+// Don't safef, theoretically that could abort.
+char key[64];
+snprintf(key, sizeof(key), "%lld",  ptrToLL(pid));
+key[ArraySize(key)-1] = '\0';
+if (perThreadVars == NULL)
+    perThreadVars = hashNew(0);
+struct hashEl *hel = hashLookup(perThreadVars, key);
+if (hel == NULL)
+    {
+    // if it is the first time, initialization the perThreadAbortVars
+    struct perThreadAbortVars *ptav;
+    AllocVar(ptav);
+    ptav->debugPushPopErr = FALSE;
+    ptav->errAbortInProgress = FALSE;
+    ptav->warnIx = 0;
+    ptav->warnArray[0] = defaultVaWarn;
+    ptav->abortIx = 0;
+    ptav->abortArray[0] = defaultAbort;
+    hel = hashAdd(perThreadVars, key, ptav);
+    }
+pthread_mutex_unlock( &ptavMutex );
+return (struct perThreadAbortVars *)(hel->val);
+}
+
diff --git a/lib/fa.c b/lib/fa.c
new file mode 100644
index 0000000..930ff9a
--- /dev/null
+++ b/lib/fa.c
@@ -0,0 +1,648 @@
+/* Routines for reading and writing fasta format sequence files.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "errabort.h"
+#include "hash.h"
+#include "portable.h"
+#include "dnautil.h"
+#include "dnaseq.h"
+#include "fa.h"
+#include "linefile.h"
+
+
+boolean faReadNext(FILE *f, char *defaultName, boolean mustStartWithComment,
+                         char **retCommentLine, struct dnaSeq **retSeq) 
+/* Read next sequence from .fa file. Return sequence in retSeq.  
+ * If retCommentLine is non-null
+ * return the '>' line in retCommentLine.   
+ * The whole thing returns FALSE at end of file.  
+ * DNA chars are mapped to lower case.*/
+{
+    return faReadMixedNext(f, 0, defaultName, mustStartWithComment,
+                                        retCommentLine, retSeq);
+}
+
+boolean faReadMixedNext(FILE *f, boolean preserveCase, char *defaultName, 
+    boolean mustStartWithComment, char **retCommentLine, struct dnaSeq **retSeq)
+/* Read next sequence from .fa file. Return sequence in retSeq.  
+ * If retCommentLine is non-null return the '>' line in retCommentLine.
+ * The whole thing returns FALSE at end of file. 
+ * Contains parameter to preserve mixed case. */
+{
+char lineBuf[1024];
+int lineSize;
+char *words[1];
+int c;
+off_t offset = ftello(f);
+size_t dnaSize = 0;
+DNA *dna, *sequence;
+char *name = defaultName;
+
+if (name == NULL)
+    name = "";
+dnaUtilOpen();
+if (retCommentLine != NULL)
+    *retCommentLine = NULL;
+*retSeq = NULL;
+
+/* Skip first lines until it starts with '>' */
+for (;;)
+    {
+    if(fgets(lineBuf, sizeof(lineBuf), f) == NULL)
+        {
+        if (ferror(f))
+            errnoAbort("read of fasta file failed");
+        return FALSE;
+        }
+    lineSize = strlen(lineBuf);
+    if (lineBuf[0] == '>')
+        {
+	if (retCommentLine != NULL)
+            *retCommentLine = cloneString(lineBuf);
+        offset = ftello(f);
+        chopByWhite(lineBuf, words, ArraySize(words));
+        name = words[0]+1;
+        break;
+        }
+    else if (!mustStartWithComment)
+        {
+        if (fseeko(f, offset, SEEK_SET) < 0)
+            errnoAbort("fseek on fasta file failed");
+        break;
+        }
+    else
+        offset += lineSize;
+    }
+/* Count up DNA. */
+for (;;)
+    {
+    c = fgetc(f);
+    if (c == EOF || c == '>')
+        break;
+    if (isalpha(c))
+        {
+        ++dnaSize;
+        }
+    }
+
+if (dnaSize == 0)
+    {
+    warn("Invalid fasta format: sequence size == 0 for element %s",name);
+    }
+
+/* Allocate DNA and fill it up from file. */
+dna = sequence = needHugeMem(dnaSize+1);
+if (fseeko(f, offset, SEEK_SET) < 0)
+    errnoAbort("fseek on fasta file failed");
+for (;;)
+    {
+    c = fgetc(f);
+    if (c == EOF || c == '>')
+        break;
+    if (isalpha(c))
+        {
+        /* check for non-DNA char */
+        if (ntChars[c] == 0)
+            {
+            *dna++ = preserveCase ? 'N' : 'n';
+            }
+        else
+            {
+            *dna++ = preserveCase ? c : ntChars[c];
+            }
+        }
+    }
+if (c == '>')
+    ungetc(c, f);
+*dna = 0;
+
+*retSeq = newDnaSeq(sequence, dnaSize, name);
+if (ferror(f))
+    errnoAbort("read of fasta file failed");    
+return TRUE;
+}
+
+
+struct dnaSeq *faReadOneDnaSeq(FILE *f, char *defaultName, boolean mustStartWithComment)
+/* Read sequence from FA file. Assumes positioned at or before
+ * the '>' at start of sequence. */  
+{
+struct dnaSeq *seq;
+if (!faReadNext(f, defaultName, mustStartWithComment, NULL, &seq))
+    return NULL;
+else
+    return seq;
+}
+
+static bioSeq *nextSeqFromMem(char **pText, boolean isDna, boolean doFilter)
+/* Convert fa in memory to bioSeq.  Update *pText to point to next
+ * record.  Returns NULL when no more sequences left. */
+{
+char *name = "";
+char *s, *d;
+struct dnaSeq *seq;
+int size = 0;
+char c;
+char *filter = (isDna ? ntChars : aaChars);
+char *text = *pText;
+char *p = skipLeadingSpaces(text);
+if (p == NULL)
+    return NULL;
+dnaUtilOpen();
+if (*p == '>')
+    {
+    char *end;
+    s = strchr(p, '\n');
+    if (s != NULL) ++s;
+    name = skipLeadingSpaces(p+1);
+    end = skipToSpaces(name);
+    if (end >= s || name >= s)
+        errAbort("No name in line starting with '>'");
+    if (end != NULL)
+        *end = 0;
+    }
+else
+    {
+    s = p; 
+    if (s == NULL || s[0] == 0)
+        return NULL;
+    }
+name = cloneString(name);
+    
+d = text;
+if (s != NULL)
+    {
+    for (;;)
+	{
+	c = *s;
+	if (c == 0 || c == '>')
+	    break;
+	++s;
+	if (!isalpha(c))
+	    continue;
+	if (doFilter)
+	    {
+	    if ((c = filter[(int)c]) == 0) 
+		{
+		if (isDna)
+		    c = 'n';
+		else
+		    c = 'X';
+		}
+	    }
+	d[size++] = c;
+	}
+    }
+d[size] = 0;
+
+/* Put sequence into our little sequence structure. */
+AllocVar(seq);
+seq->name = name;
+seq->dna = text;
+seq->size = size;
+*pText = s;
+return seq;
+}
+
+bioSeq *faNextSeqFromMemText(char **pText, boolean isDna)
+/* Convert fa in memory to bioSeq.  Update *pText to point to next
+ * record.  Returns NULL when no more sequences left. */
+{
+return nextSeqFromMem(pText, isDna, TRUE);
+}
+
+bioSeq *faNextSeqFromMemTextRaw(char **pText)
+/* Same as faNextSeqFromMemText, but will leave in 
+ * letters even if they aren't in DNA or protein alphabed. */
+{
+return nextSeqFromMem(pText, TRUE, FALSE);
+}
+
+bioSeq *faSeqListFromMemText(char *text, boolean isDna)
+/* Convert fa's in memory into list of dnaSeqs. */
+{
+bioSeq *seqList = NULL, *seq;
+while ((seq = faNextSeqFromMemText(&text, isDna)) != NULL)
+    {
+    slAddHead(&seqList, seq);
+    }
+slReverse(&seqList);
+return seqList;
+}
+
+bioSeq *faSeqListFromMemTextRaw(char *text)
+/* Convert fa's in memory into list of dnaSeqs without
+ * converting chars to N's. */
+{
+bioSeq *seqList = NULL, *seq;
+while ((seq = faNextSeqFromMemTextRaw(&text)) != NULL)
+    {
+    slAddHead(&seqList, seq);
+    }
+slReverse(&seqList);
+return seqList;
+}
+
+
+bioSeq *faSeqFromMemText(char *text, boolean isDna)
+/* Convert fa in memory to bioSeq. */
+{
+return faNextSeqFromMemText(&text, isDna);
+}
+
+struct dnaSeq *faFromMemText(char *text)
+/* Return a sequence from a .fa file that's been read into
+ * a string in memory. This cannabalizes text, which should
+ * be allocated with needMem.  This buffer becomes part of
+ * the returned dnaSeq, which may be freed normally with
+ * freeDnaSeq. */
+{
+return faNextSeqFromMemText(&text, TRUE);
+}
+
+struct dnaSeq *faReadSeq(char *fileName, boolean isDna)
+/* Open fa file and read a single sequence from it. */
+{
+int maxSize = fileSize(fileName);
+int fd;
+DNA *s;
+
+if (maxSize < 0)
+    errAbort("can't open %s", fileName);
+s = needHugeMem(maxSize+1);
+fd = open(fileName, O_RDONLY);
+if (read(fd, s, maxSize) < 0)
+    errAbort("faReadSeq: read failed: %s", strerror(errno));
+close(fd);
+s[maxSize] = 0;
+return faSeqFromMemText(s, isDna);
+}
+
+struct dnaSeq *faReadDna(char *fileName)
+/* Open fa file and read a single nucleotide sequence from it. */
+{
+return faReadSeq(fileName, TRUE);
+}
+
+struct dnaSeq *faReadAa(char *fileName)
+/* Open fa file and read a peptide single sequence from it. */
+{
+return faReadSeq(fileName, FALSE);
+}
+
+static unsigned faFastBufSize = 0;
+static DNA *faFastBuf;
+
+static void expandFaFastBuf(int bufPos, int minExp)
+/* Make faFastBuf bigger. */
+{
+if (faFastBufSize == 0)
+    {
+    faFastBufSize = 64 * 1024;
+    while (minExp > faFastBufSize)
+        faFastBufSize <<= 1;
+    faFastBuf = needHugeMem(faFastBufSize);
+    }
+else
+    {
+    DNA *newBuf;
+    unsigned newBufSize = faFastBufSize + faFastBufSize;
+    while (newBufSize < minExp)
+	{
+        newBufSize <<= 1;
+	if (newBufSize <= 0)
+	    errAbort("expandFaFastBuf: integer overflow when trying to "
+		     "increase buffer size from %u to a min of %u.",
+		     faFastBufSize, minExp);
+	}
+    newBuf = needHugeMem(newBufSize);
+    memcpy(newBuf, faFastBuf, bufPos);
+    freeMem(faFastBuf);
+    faFastBuf = newBuf;
+    faFastBufSize = newBufSize;
+    }
+}
+
+void faFreeFastBuf()
+/* Free up buffers used in fa fast and speedreading. */
+{
+freez(&faFastBuf);
+faFastBufSize = 0;
+}
+
+boolean faFastReadNext(FILE *f, DNA **retDna, int *retSize, char **retName)
+/* Read in next FA entry as fast as we can. Return FALSE at EOF. 
+ * The returned DNA and name will be overwritten by the next call
+ * to this function. */
+{
+int c;
+int bufIx = 0;
+static char name[256];
+int nameIx = 0;
+boolean gotSpace = FALSE;
+
+/* Seek to next '\n' and save first word as name. */
+dnaUtilOpen();
+name[0] = 0;
+for (;;)
+    {
+    if ((c = fgetc(f)) == EOF)
+        {
+        *retDna = NULL;
+        *retSize = 0;
+        *retName = NULL;
+        return FALSE;
+        }
+    if (!gotSpace && nameIx < ArraySize(name)-1)
+        {
+        if (isspace(c))
+            gotSpace = TRUE;
+        else if (c != '>')
+            {
+            name[nameIx++] = c;
+            }
+        }
+    if (c == '\n')
+        break;
+    }
+name[nameIx] = 0;
+/* Read until next '>' */
+for (;;)
+    {
+    c = fgetc(f);
+    if (c == EOF || c == '>')
+        c = 0;
+    else if (!isalpha(c))
+        continue;
+    else
+	{
+	c = ntChars[c];
+	if (c == 0) c = 'n';
+	}
+    if (bufIx >= faFastBufSize)
+	expandFaFastBuf(bufIx, 0);
+    faFastBuf[bufIx++] = c;
+    if (c == 0)
+        {
+        *retDna = faFastBuf;
+        *retSize = bufIx-1;
+        *retName = name;
+        return TRUE;
+        }
+    }
+}
+
+
+void faWriteNext(FILE *f, char *startLine, DNA *dna, int dnaSize)
+/* Write next sequence to fa file. */
+{
+if (dnaSize == 0)
+    return;
+if (startLine != NULL)
+    fprintf(f, ">%s\n", startLine);
+writeSeqWithBreaks(f, dna, dnaSize, 50);
+}
+
+void faWrite(char *fileName, char *startLine, DNA *dna, int dnaSize)
+/* Write out FA file or die trying. */
+{
+FILE *f = mustOpen(fileName, "w");
+faWriteNext(f, startLine, dna, dnaSize);
+if (fclose(f) != 0)
+    errnoAbort("fclose failed");
+}
+
+void faWriteAll(char *fileName, bioSeq *seqList)
+/* Write out all sequences in list to file. */
+{
+FILE *f = mustOpen(fileName, "w");
+bioSeq *seq;
+
+for (seq=seqList; seq != NULL; seq = seq->next)
+    faWriteNext(f, seq->name, seq->dna, seq->size);
+if (fclose(f) != 0)
+    errnoAbort("fclose failed");
+}
+
+boolean faMixedSpeedReadNext(struct lineFile *lf, DNA **retDna, int *retSize, char **retName)
+/* Read in DNA or Peptide FA record in mixed case.   Allow any upper or lower case
+ * letter, or the dash character in. */
+{
+char c;
+int bufIx = 0;
+static char name[512];
+int lineSize, i;
+char *line;
+
+dnaUtilOpen();
+
+/* Read first line, make sure it starts with '>', and read first word
+ * as name of sequence. */
+name[0] = 0;
+if (!lineFileNext(lf, &line, &lineSize))
+    {
+    *retDna = NULL;
+    *retSize = 0;
+    return FALSE;
+    }
+if (line[0] == '>')
+    {
+    line = firstWordInLine(skipLeadingSpaces(line+1));
+    if (line == NULL)
+        errAbort("Expecting sequence name after '>' line %d of %s", lf->lineIx, lf->fileName);
+    strncpy(name, line, sizeof(name));
+    name[sizeof(name)-1] = '\0'; /* Just to make sure name is NULL terminated. */
+    }
+else
+    {
+    errAbort("Expecting '>' line %d of %s", lf->lineIx, lf->fileName);
+    }
+/* Read until next '>' */
+for (;;)
+    {
+    if (!lineFileNext(lf, &line, &lineSize))
+        break;
+    if (line[0] == '>')
+        {
+	lineFileReuse(lf);
+	break;
+	}
+    if (bufIx + lineSize >= faFastBufSize)
+	expandFaFastBuf(bufIx, lineSize);
+    for (i=0; i<lineSize; ++i)
+        {
+	c = line[i];
+	if (isalpha(c) || c == '-')
+	    faFastBuf[bufIx++] = c;
+	}
+    }
+if (bufIx >= faFastBufSize)
+    expandFaFastBuf(bufIx, 0);
+faFastBuf[bufIx] = 0;
+*retDna = faFastBuf;
+*retSize = bufIx;
+*retName = name;
+if (bufIx == 0)
+    {
+    warn("Invalid fasta format: sequence size == 0 for element %s",name);
+    }
+
+return TRUE;
+}
+
+void faToProtein(char *poly, int size)
+/* Convert possibly mixed-case protein to upper case.  Also
+ * convert any strange characters to 'X'.  Does not change size.
+ * of sequence. */
+{
+int i;
+char c;
+dnaUtilOpen();
+for (i=0; i<size; ++i)
+    {
+    if ((c = aaChars[(int)poly[i]]) == 0)
+	c = 'X';
+    poly[i] = c;
+    }
+}
+
+void faToDna(char *poly, int size)
+/* Convert possibly mixed-case DNA to lower case.  Also turn
+ * any strange characters to 'n'.  Does not change size.
+ * of sequence. */
+{
+int i;
+char c;
+dnaUtilOpen();
+for (i=0; i<size; ++i)
+    {
+    if ((c = ntChars[(int)poly[i]]) == 0)
+	c = 'n';
+    poly[i] = c;
+    }
+}
+
+boolean faSomeSpeedReadNext(struct lineFile *lf, DNA **retDna, int *retSize, char **retName, boolean isDna)
+/* Read in DNA or Peptide FA record. */
+{
+char *poly;
+int size;
+
+if (!faMixedSpeedReadNext(lf, retDna, retSize, retName))
+    return FALSE;
+size = *retSize;
+poly = *retDna;
+if (isDna)
+    faToDna(poly, size);
+else
+    faToProtein(poly, size);
+return TRUE;
+}
+
+boolean faPepSpeedReadNext(struct lineFile *lf, DNA **retDna, int *retSize, char **retName)
+/* Read in next peptide FA entry as fast as we can.  */
+{
+return faSomeSpeedReadNext(lf, retDna, retSize, retName, FALSE);
+}
+
+boolean faSpeedReadNext(struct lineFile *lf, DNA **retDna, int *retSize, char **retName)
+/* Read in next FA entry as fast as we can. Faster than that old,
+ * pokey faFastReadNext. Return FALSE at EOF. 
+ * The returned DNA and name will be overwritten by the next call
+ * to this function. */
+{
+return faSomeSpeedReadNext(lf, retDna, retSize, retName, TRUE);
+}
+
+static struct dnaSeq *faReadAllMixableInLf(struct lineFile *lf, 
+	boolean isDna, boolean mixed)
+/* Return list of all sequences from open fa file. 
+ * Mixed case parameter overrides isDna.  If mixed is false then
+ * will return DNA in lower case and non-DNA in upper case. */
+{
+struct dnaSeq *seqList = NULL, *seq;
+DNA *dna;
+char *name;
+int size;
+boolean ok;
+
+for (;;)
+    {
+    if (mixed)
+        ok = faMixedSpeedReadNext(lf, &dna, &size, &name);
+    else
+        ok = faSomeSpeedReadNext(lf, &dna, &size, &name, isDna);
+    if (!ok)
+        break;
+    AllocVar(seq);
+    seq->name = cloneString(name);
+    seq->size = size;
+    seq->dna = cloneMem(dna, size+1);
+    slAddHead(&seqList, seq);
+    }
+slReverse(&seqList);
+faFreeFastBuf();
+return seqList;
+}
+
+static struct dnaSeq *faReadAllSeqMixable(char *fileName, boolean isDna, boolean mixed)
+/* Return list of all sequences in FA file. 
+ * Mixed case parameter overrides isDna.  If mixed is false then
+ * will return DNA in lower case and non-DNA in upper case. */
+{
+struct lineFile *lf = lineFileOpen(fileName, FALSE);
+struct dnaSeq *seqList = faReadAllMixableInLf(lf, isDna, mixed);
+lineFileClose(&lf);
+return seqList;
+}
+
+struct hash *faReadAllIntoHash(char *fileName, enum dnaCase dnaCase)
+/* Return hash of all sequences in FA file.  */
+{
+boolean isDna = (dnaCase == dnaLower);
+boolean isMixed = (dnaCase == dnaMixed);
+struct dnaSeq *seqList = faReadAllSeqMixable(fileName, isDna, isMixed);
+struct hash *hash = hashNew(18);
+struct dnaSeq *seq;
+for (seq = seqList; seq != NULL; seq = seq->next)
+    {
+    if (hashLookup(hash, seq->name))
+        errAbort("%s duplicated in %s", seq->name, fileName);
+    hashAdd(hash, seq->name, seq);
+    }
+return hash;
+}
+
+
+struct dnaSeq *faReadAllSeq(char *fileName, boolean isDna)
+/* Return list of all sequences in FA file. */
+{
+return faReadAllSeqMixable(fileName, isDna, FALSE);
+}
+
+struct dnaSeq *faReadAllDna(char *fileName)
+/* Return list of all DNA sequences in FA file. */
+{
+return faReadAllSeq(fileName, TRUE);
+}
+
+struct dnaSeq *faReadAllPep(char *fileName)
+/* Return list of all peptide sequences in FA file. */
+{
+return faReadAllSeq(fileName, FALSE);
+}
+
+struct dnaSeq *faReadAllMixed(char *fileName)
+/* Read in mixed case fasta file, preserving case. */
+{
+return faReadAllSeqMixable(fileName, FALSE, TRUE);
+}
+
+struct dnaSeq *faReadAllMixedInLf(struct lineFile *lf)
+/* Read in mixed case sequence from open fasta file. */
+{
+return faReadAllMixableInLf(lf, FALSE, TRUE);
+}
diff --git a/lib/ffAli.c b/lib/ffAli.c
new file mode 100644
index 0000000..122e1d6
--- /dev/null
+++ b/lib/ffAli.c
@@ -0,0 +1,185 @@
+/* Some relatively small utility functions that act on ffAlis.
+ * (Separated from fuzzyFinder.c so people can do light ffAli 
+ * work without including 100k of fuzzyFinder object code.) 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "dnautil.h"
+#include "fuzzyFind.h"
+
+
+void ffFreeAli(struct ffAli **pAli)
+/* Dispose of memory gotten from fuzzyFind(). */
+{
+struct ffAli *ali = *pAli;
+if (ali != NULL)
+    {
+    while (ali->right)
+        ali = ali->right;
+    slFreeList(&ali);
+    }
+*pAli = NULL;
+}
+
+int ffOneIntronOrientation(struct ffAli *left, struct ffAli *right)
+/* Return 1 for GT/AG intron between left and right, -1 for CT/AC, 0 for no
+ * intron. */
+{
+if (left->nEnd != right->nStart)
+    return 0;
+return intronOrientation(left->hEnd, right->hStart);
+}
+
+int ffIntronOrientation(struct ffAli *ali)
+/* Return + for positive orientation overall, - for negative,
+ * 0 if can't tell. */
+{
+struct ffAli *left = ali, *right;
+int orient = 0;
+
+if (left != NULL)
+    {
+    while((right = left->right) != NULL)
+	{
+	orient += intronOrientation(left->hEnd, right->hStart);
+	left = right;
+	}
+    }
+return orient;
+}
+
+struct ffAli *ffRightmost(struct ffAli *ff)
+/* Return rightmost block of alignment. */
+{
+while (ff->right != NULL)
+    ff = ff->right;
+return ff;
+}
+
+struct ffAli *ffMakeRightLinks(struct ffAli *rightMost)
+/* Given a pointer to the rightmost block in an alignment
+ * which has all of the left pointers filled in, fill in
+ * the right pointers and return the leftmost block. */
+{
+struct ffAli *ff, *last = NULL;
+
+for (ff = rightMost; ff != NULL; ff = ff->left)
+    {
+    ff->right = last;
+    last = ff;
+    }
+return last;
+}
+
+
+static int countGoodStart(struct ffAli *ali)
+/* Return number of perfect matchers at start. */
+{
+DNA *n = ali->nStart;
+DNA *h = ali->hStart;
+int count = ali->nEnd - ali->nStart;
+int i;
+for (i=0; i<count; ++i)
+    {
+    if (*n++ != *h++)
+        break;
+    }
+return i;
+}
+
+static int countGoodEnd(struct ffAli *ali)
+/* Return number of perfect matchers at start. */
+{
+DNA *n = ali->nEnd;
+DNA *h = ali->hEnd;
+int count = ali->nEnd - ali->nStart;
+int i;
+for (i=0; i<count; ++i)
+    {
+    if (*--n != *--h)
+        break;
+    }
+return i;
+}
+
+void ffCountGoodEnds(struct ffAli *aliList)
+/* Fill in the goodEnd and badEnd scores. */
+{
+struct ffAli *ali;
+for (ali = aliList; ali != NULL; ali = ali->right)
+    {
+    ali->startGood = countGoodStart(ali);
+    ali->endGood = countGoodEnd(ali);
+    }
+}
+
+int ffAliCount(struct ffAli *d)
+/* How many blocks in alignment? */
+{
+int acc = 0;
+while (d != NULL)
+    {
+    ++acc;
+    d = d->right;
+    }
+return acc;
+}
+
+struct ffAli *ffAliFromSym(int symCount, char *nSym, char *hSym,
+	struct lm *lm, char *nStart, char *hStart)
+/* Convert symbol representation of alignments (letters plus '-')
+ * to ffAli representation.  If lm is nonNULL, ffAli result 
+ * will be lmAlloced, else it will be needMemed. This routine
+ * depends on nSym/hSym being zero terminated. */
+{
+struct ffAli *ffList = NULL, *ff = NULL;
+char n, h;
+int i;
+
+for (i=0; i<=symCount; ++i)
+    {
+    boolean isGap;
+    n = nSym[i];
+    h = hSym[i];
+    isGap = (n == '-' || n == 0 || h == '-' || h == 0);
+    if (isGap)
+	{
+	if (ff != NULL)
+	    {
+	    ff->nEnd = nStart;
+	    ff->hEnd = hStart;
+	    ff->left = ffList;
+	    ffList = ff;
+	    ff = NULL;
+	    }
+	}
+    else
+	{
+	if (ff == NULL)
+	    {
+	    if (lm != NULL)
+		{
+		lmAllocVar(lm, ff);
+		}
+	    else
+		{
+		AllocVar(ff);
+		}
+	    ff->nStart = nStart;
+	    ff->hStart = hStart;
+	    }
+	}
+    if (n != '-')
+	{
+	++nStart;
+	}
+    if (h != '-')
+	{
+	++hStart;
+	}
+    }
+ffList = ffMakeRightLinks(ffList);
+return ffList;
+}
diff --git a/lib/ffScore.c b/lib/ffScore.c
new file mode 100644
index 0000000..8eb6983
--- /dev/null
+++ b/lib/ffScore.c
@@ -0,0 +1,212 @@
+/* ffScore - stuff to score ffAli alignments. */
+
+#include "common.h"
+#include "dnautil.h"
+#include "obscure.h"
+#include "fuzzyFind.h"
+
+
+int ffIntronMax = ffIntronMaxDefault;
+
+void setFfIntronMax(int value)
+{
+ffIntronMax = value;
+}
+
+int ffScoreMatch(DNA *a, DNA *b, int size)
+/* Compare two pieces of DNA base by base. Total mismatches are
+ * subtracted from total matches and returned as score. 'N's 
+ * neither hurt nor help score. */
+{
+int i;
+int score = 0;
+for (i=0; i<size; ++i)
+    {
+    DNA aa = a[i];
+    DNA bb = b[i];
+    if (aa == 'n' || bb == 'n')
+        continue;
+    if (aa == bb)
+        ++score;
+    else
+        score -= 1;
+    }
+return score;
+}
+
+int ffCalcCdnaGapPenalty(int hGap, int nGap)
+/* Return gap penalty for given h and n gaps. */
+{
+int acc = 2;
+if (hGap > 400000)	/* Discourage really long introns. */
+    {
+    acc += (hGap - 400000)/3000;
+    if (hGap > ffIntronMax)
+        acc += (hGap - ffIntronMax)/2000;
+    }
+if (hGap < 0)   /* Discourage jumping back in haystack. */
+    {
+    hGap = -8*hGap;
+    if (hGap > 48)
+        hGap = (hGap*hGap);
+    }
+if (nGap < 0)   /* Jumping back in needle gets rid of previous alignment. */
+    {
+    acc += -nGap;
+    nGap = 0;
+    }
+acc += digitsBaseTwo(hGap)/2;
+if (nGap != 0)
+    {
+    acc += digitsBaseTwo(nGap);
+    }
+else
+    {
+    if (hGap > 30)
+	acc -= 1;
+    }
+return acc;
+}
+
+static int calcTightGap(int hGap, int nGap)
+/* Figure out gap penalty using tight model (gaps bad!) */
+{
+if (hGap == 0 && nGap == 0)
+    return 0;
+else
+    {
+    int overlap = min(hGap, nGap);
+    int penalty = 8;
+    if (overlap < 0)
+	overlap = 0;
+
+    if (hGap < 0)
+	hGap = -8*hGap;
+    if (nGap < 0)
+	nGap = -2*nGap;
+    penalty += (hGap-overlap + nGap-overlap) + overlap;
+    return penalty;
+    }
+}
+
+static int calcLooseGap(int hGap, int nGap)
+/* Figure out gap penalty using loose model (gaps not so bad) */
+{
+if (hGap == 0 && nGap == 0)
+    return 0;
+else
+    {
+    int overlap = min(hGap, nGap);
+    int penalty = 8;
+    if (overlap < 0)
+	overlap = 0;
+
+    if (hGap < 0)
+	hGap = -8*hGap;
+    if (nGap < 0)
+	nGap = -2*nGap;
+    penalty += log(hGap-overlap+1) + log(nGap-overlap+1);
+    return penalty;
+    }
+}
+
+
+int ffCalcGapPenalty(int hGap, int nGap, enum ffStringency stringency)
+/* Return gap penalty for given h and n gaps. */
+{
+switch (stringency)
+    {
+    case ffCdna:
+	return ffCalcCdnaGapPenalty(hGap, nGap);
+    case ffTight:
+	return calcTightGap(hGap,nGap);
+    case ffLoose:
+	return calcLooseGap(hGap,nGap);
+    default:
+        errAbort("Unknown stringency type %d", stringency);
+	return 0;
+    }
+}
+
+
+int ffCdnaGapPenalty(struct ffAli *left, struct ffAli *right)
+/* What is penalty for gap between two. */
+{
+int hGap = right->hStart - left->hEnd;
+int nGap = right->nStart - left->nEnd;
+return ffCalcCdnaGapPenalty(hGap, nGap);
+}
+
+int ffGapPenalty(struct ffAli *left, struct ffAli *right, enum ffStringency stringency)
+/* What is penalty for gap between two given stringency? */
+{
+int hGap = right->hStart - left->hEnd;
+int nGap = right->nStart - left->nEnd;
+return ffCalcGapPenalty(hGap, nGap, stringency);
+}
+
+int ffScoreSomeAlis(struct ffAli *ali, int count, enum ffStringency stringency)
+/* Figure out score of count alis. */
+{
+int score = 0;
+int oneScore;
+
+while (--count >= 0)
+    {
+    int len = ali->hEnd - ali->hStart;
+    struct ffAli *right = ali->right;
+    oneScore = dnaScoreMatch(ali->hStart, ali->nStart, len);
+    score += oneScore;
+    if (count > 0)  /* Calculate gap penalty */
+        score -= ffGapPenalty(ali, right,stringency);
+    ali = right;
+    }
+return score;
+}
+
+int ffScoreSomething(struct ffAli *ali, enum ffStringency stringency,
+   boolean isProt)
+/* Score alignment. */
+{
+int score = 0;
+int oneScore;
+int (*scoreMatch)(char *a, char *b, int size);
+
+if (ali == NULL)
+    return -0x7FFFFFFF;
+scoreMatch = (isProt ? aaScoreMatch : dnaScoreMatch );
+while (ali->left != NULL) ali = ali->left;
+while (ali != NULL)
+    {
+    int len = ali->hEnd - ali->hStart;
+    struct ffAli *right = ali->right;
+    oneScore = scoreMatch(ali->hStart, ali->nStart, len);
+    score += oneScore;
+    if (right)  /* Calculate gap penalty */
+        {
+        score -= ffGapPenalty(ali, right, stringency);
+        }
+    ali = right;
+    }
+return score;
+}
+
+int ffScore(struct ffAli *ali, enum ffStringency stringency)
+/* Score alignment. */
+{
+return ffScoreSomething(ali, stringency, FALSE);
+}
+
+int ffScoreCdna(struct ffAli *ali)
+/* Figure out overall score of this alignment. 
+ * Perfect match is number of bases in needle. */
+{
+return ffScore(ali, ffCdna);
+}
+
+int ffScoreProtein(struct ffAli *ali, enum ffStringency stringency)
+/* Figure out overall score of protein alignment. */
+{
+return ffScoreSomething(ali, stringency, TRUE);
+}
+
diff --git a/lib/filePath.c b/lib/filePath.c
new file mode 100644
index 0000000..9207b1a
--- /dev/null
+++ b/lib/filePath.c
@@ -0,0 +1,130 @@
+/* filePath - stuff to handle file name parsing. */
+#include "common.h"
+#include "filePath.h"
+
+
+void undosPath(char *path)
+/* Convert '\' to '/' in path. */
+{
+subChar(path, '\\', '/');
+}
+
+void splitPath(char *path, char dir[PATH_LEN], char name[FILENAME_LEN],
+	       char extension[FILEEXT_LEN])
+/* Split a full path into components.  The dir component will include the
+ * trailing / if any.  The extension component will include the starting
+ * . if any.   Pass in NULL for dir, name, or extension if you don't care about
+ * that part. */
+{
+char *dirStart, *nameStart, *extStart, *extEnd;
+int dirSize, nameSize, extSize;
+
+undosPath(path);
+dirStart = path;
+nameStart = strrchr(path,'/');
+if (nameStart == NULL)
+    nameStart = path;
+else
+    nameStart += 1;
+extStart = strrchr(nameStart, '.');
+if (extStart == NULL)
+    extStart = nameStart + strlen(nameStart);
+extEnd = extStart + strlen(extStart);
+if ((dirSize = (nameStart - dirStart)) >= PATH_LEN)
+    errAbort("Directory too long in %s", path);
+if ((nameSize = (extStart - nameStart)) >= FILENAME_LEN)
+    errAbort("Name too long in %s", path);
+if ((extSize = (extEnd - extStart)) >= FILEEXT_LEN)
+    errAbort("Extension too long in %s", path);
+if (dir != NULL)
+    {
+    memcpy(dir, dirStart, dirSize);
+    dir[dirSize] = 0;
+    }
+if (name != NULL)
+    {
+    memcpy(name, nameStart, nameSize);
+    name[nameSize] = 0;
+    }
+if (extension != NULL)
+    {
+    memcpy(extension, extStart, extSize);
+    extension[extSize] = 0;
+    }
+}
+
+static char *findSlashBefore(char *start, char *e)
+/* Return first slash before s (but not before start) */
+{
+while (--e >= start)
+    {
+    if (*e == '/')
+         return e;
+    }
+return start;
+}
+
+char *expandRelativePath(char *baseDir, char *relPath)
+/* Expand relative path to more absolute one. */
+{
+if (relPath[0] == '/')
+   // hey, it's absolute actually... 
+   return cloneString(relPath);
+
+char *e = baseDir + strlen(baseDir);
+int slashCount;
+char *rel = relPath;
+char *result;
+int size, baseSize;
+undosPath(baseDir);
+undosPath(relPath);
+slashCount = countChars(baseDir, '/');
+if (baseDir[0] == 0)
+    slashCount = -1;
+while (startsWith("../", rel))
+    {
+    if (slashCount < 0)
+        {
+	warn("More ..'s in \"%s\" than directories in \"%s\"", relPath, baseDir);
+	return NULL;
+	}
+    else if (slashCount == 0)
+        e = baseDir;
+    else
+        e = findSlashBefore(baseDir, e);
+    slashCount -= 1;
+    rel += 3;
+    }
+baseSize = e - baseDir;
+size = strlen(rel) + 1;
+if (baseSize > 0)
+    size += baseSize + 1;
+if (baseSize > 0)
+    {
+    result = needMem(size);
+    memcpy(result, baseDir, baseSize);
+    result[baseSize] = '/';
+    strcpy(result + baseSize + 1, rel);
+    }
+else
+    result = cloneString(rel);
+return result;
+}
+
+char *pathRelativeToFile(char *baseFile, char *relPath)
+/* Given a base file name and a path relative to that, return
+ * relative path interpreted as if it were seen from the
+ * same directory holding the baseFile.  
+ *   An example of using this would be in processing include
+ * files.  In this case the baseFile would be the current
+ * source file, and the relPath would be from the include
+ * statement.  The returned result could then be used to
+ * open the include file. */
+{
+char dir[PATH_LEN];
+splitPath(baseFile, dir, NULL, NULL);
+int dirLen = strlen(dir);
+if (dirLen > 0 && dir[dirLen-1] == '/')
+     dir[dirLen-1] = 0;
+return expandRelativePath(dir, relPath);
+}
diff --git a/lib/fixColor.c b/lib/fixColor.c
new file mode 100644
index 0000000..3ec71b1
--- /dev/null
+++ b/lib/fixColor.c
@@ -0,0 +1,20 @@
+/* Fixed colors - always in color map. */
+#include "common.h"
+#include "memgfx.h"
+
+
+struct rgbColor mgFixedColors[9] = {
+/* These correspond to MG_WHITE, MG_BLACK, etc. */
+    { 255, 255, 255},
+    { 0, 0, 0},
+    { 255, 0, 0},
+    { 0, 255, 0},
+    { 0, 0, 255},
+    { 0, 255, 255},
+    { 255, 0, 255},
+    { 255, 255, 0},
+    { 140, 140, 140},
+};
+
+
+
diff --git a/lib/flydna.c b/lib/flydna.c
new file mode 100644
index 0000000..d2423d9
--- /dev/null
+++ b/lib/flydna.c
@@ -0,0 +1,111 @@
+/* flydna.c - routines for accessing fly genome and cDNA sequences. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+#include "common.h"
+#include "snof.h"
+#include "dnautil.h"
+#include "dnaseq.h"
+#include "fa.h"
+#include "nt4.h"
+#include "cda.h"
+#include "wormdna.h"
+#include "flydna.h"
+
+
+static char *chromNames[] = {"adh"};
+static char *ntFileNames[] = {"c:/biodata/fly/chrom/adh.nt"};
+
+void flyLoadNt4Genome(struct nt4Seq ***retNt4Seq, int *retNt4Count)
+/* Load up entire packed fly genome into memory. */
+{
+struct nt4Seq **pSeq;
+int i;
+
+pSeq = needMem(ArraySize(ntFileNames) * sizeof(pSeq[0]) );
+for (i=0; i<ArraySize(ntFileNames); ++i)
+	{
+	pSeq[i] = loadNt4(ntFileNames[i], chromNames[i]);
+	}
+*retNt4Seq = pSeq;
+*retNt4Count = ArraySize(ntFileNames);
+}
+
+void flyFreeNt4Genome(struct nt4Seq ***pNt4Seq)
+/* Free up packed fly genome. */
+{
+struct nt4Seq **pSeq;
+int i;
+
+if ((pSeq = *pNt4Seq) == NULL)
+	return;
+for (i=0; i<ArraySize(ntFileNames); ++i)
+	freeNt4(&pSeq[i]);
+freez(pNt4Seq);
+}
+
+void flyChromNames(char ***retNames, int *retNameCount)
+/* Get list of fly chromosome names. */
+{
+*retNames = chromNames;
+*retNameCount = ArraySize(chromNames);
+}
+
+void flyFaCommentIntoInfo(char *faComment, struct wormCdnaInfo *retInfo)
+/* Process line from .fa file containing information about cDNA into binary
+ * structure. */
+{
+if (retInfo)
+    {
+    char *s;
+    zeroBytes(retInfo, sizeof(*retInfo));
+    /* Separate out first word and use it as name. */
+    s = strchr(faComment, ' ');
+    if (s != NULL)
+	    *s++ = 0;
+    retInfo->name = faComment+1;
+    retInfo->motherString = faComment;
+	s = strrchr(retInfo->name, '.');
+	retInfo->orientation = '+';
+	if (s != NULL)
+		retInfo->orientation = (s[1] == '3' ? '-' : '+');
+    }
+}
+
+
+boolean flyCdnaSeq(char *name, struct dnaSeq **retDna, struct wormCdnaInfo *retInfo)
+/* Get a single fly cDNA sequence. Optionally (if retInfo is non-null) get additional
+ * info about the sequence. */
+{
+long offset;
+char *faComment;
+char **pFaComment = (retInfo == NULL ? NULL : &faComment);
+static struct snof *cdnaSnof = NULL;
+static FILE *cdnaFa;
+
+if (cdnaSnof == NULL)
+	cdnaSnof = snofMustOpen("c:/biodata/fly/cDna/allcdna");
+if (cdnaFa == NULL)
+	cdnaFa = mustOpen("c:/biodata/fly/cDna/allcdna.fa", "rb");
+if (!snofFindOffset(cdnaSnof, name, &offset))
+    return FALSE;
+fseek(cdnaFa, offset, SEEK_SET);
+if (!faReadNext(cdnaFa, name, TRUE, pFaComment, retDna))
+    return FALSE;
+flyFaCommentIntoInfo(faComment, retInfo);
+return TRUE;
+}
+
+
+char *flyFeaturesDir()
+/* Return the features directory. (Includes trailing slash.) */
+{
+return "C:/biodata/fly/features/";
+}
+
+FILE *flyOpenGoodAli()
+/* Opens good alignment file and reads signature. 
+ * (You can then cdaLoadOne() it.) */
+{
+return cdaOpenVerify("C:/biodata/fly/cDNA/good.ali");
+}
diff --git a/lib/fof.c b/lib/fof.c
new file mode 100644
index 0000000..d6e5479
--- /dev/null
+++ b/lib/fof.c
@@ -0,0 +1,580 @@
+/* fofFa - create a fof index for a list of FA files. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+#include "common.h"
+#include "localmem.h"
+#include "sig.h"
+#include "fof.h"
+
+
+struct fofRecord
+/* This holds a record of an index file. */
+    {
+    bits32 offset;  /* Start offset within file. Must be first element.*/
+    bits32 size;    /* Sizer within file. */
+    UBYTE fileIx;   /* Which file it's in. */
+    char name[1];   /* Dynamically allocated to fit actual size. */
+    };
+
+struct fof
+/* Manage a file offset file - an index which includes the file,
+ * the offset, and the size of each item. */
+    {
+    char *name;                  /* Name of fof given to fofOpen. */
+    char *relDir;                /* Directory to apply to index files. */
+    char **fileNames;            /* Names of files being indexed. */
+    FILE **files;                /* Possibly null file handles of files being indexed. */
+    FILE *f;                     /* Index file handle. */
+    int fileCount;               /* The number of files being indexed. */
+    int endIx;                   /* Last index. */
+    int maxNameSize;             /* Size allocated for index field in index. */
+    int itemSize;                /* Size of index record. */
+    long headSize;               /* Offset to first index record. */
+    struct fofRecord *rec;       /* Buffer space for one index record. */
+    struct fofRecord *first;     /* First record. */
+    struct fofRecord *last;      /* Last record. */
+    };
+
+
+static void readStringZ(FILE *f, char *s, int maxLen)
+/* Read in a zero terminated string from file. */
+{
+int c;
+int ix;
+maxLen -= 1;    /* room for zero tag. */
+
+for (ix = 0; ix <maxLen; ++ix)
+    {
+    if ((c = fgetc(f)) == EOF)
+        errAbort("Unexpected EOF in readStringZ");
+    if (c == 0)
+        break;
+    s[ix] = c;
+    }
+if (ix == maxLen)
+    errAbort("String too long in readStringZ");
+s[ix] = 0;
+}
+
+
+struct fof *fofOpen(char *fofName, char *fofDir)
+/* Open up the named fof. fofDir may be NULL.  It should include 
+ * trailing '/' if non-null. */
+{
+bits32 sig, elCount;
+bits16 fileCount, maxNameSize;
+FILE *f;
+char nameBuf[512];
+char pathBuf[512];
+struct fof *fof;
+int i;
+
+/* Handle directory either being something or NULL, and
+ * either ending with a slash or not. */
+if (fofDir == NULL)
+    {
+    fofDir = "";
+    }
+
+/* Open file, verify signature. */
+safef(pathBuf, sizeof(pathBuf), "%s%s", fofDir, fofName);
+f = mustOpen(pathBuf, "rb");
+mustReadOne(f, sig);
+if (sig != fofSig)
+    errAbort("Bad signature on %s", pathBuf);
+mustReadOne(f, elCount);
+
+/* Read size info and allocate basic fof structure. */
+mustReadOne(f, fileCount);
+if (fileCount > 12)
+    warn("%d files indexed in fof %s!?", fileCount, fofName);
+mustReadOne(f, maxNameSize);
+if (maxNameSize > 40)
+    warn("%d maxName size in fof %s!?", maxNameSize, fofName);
+AllocVar(fof);
+fof->name = cloneString(fofName);
+fof->relDir = cloneString(fofDir);
+fof->fileNames = needMem(fileCount * sizeof(fof->fileNames[0]));
+fof->files = needMem(fileCount * sizeof(fof->files[0]));
+fof->f = f;
+fof->fileCount = fileCount;
+fof->endIx = elCount-1;
+fof->maxNameSize = maxNameSize;
+fof->itemSize = sizeof(bits32) +sizeof(bits32) + sizeof(UBYTE) + maxNameSize;
+fof->rec = needMem(sizeof(*fof->rec) + maxNameSize);
+fof->first = needMem(sizeof(*fof->rec) + maxNameSize);
+fof->last = needMem(sizeof(*fof->rec) + maxNameSize);
+
+/* Read in names of files being indexed and figure header size. */
+for (i=0; i<fileCount; ++i)
+    {
+    readStringZ(f, nameBuf, sizeof(nameBuf));
+    safef(pathBuf, sizeof(pathBuf), "%s%s", fofDir, nameBuf);
+    fof->fileNames[i] = cloneString(pathBuf);
+    }
+fof->headSize = ftell(f);
+
+/* Read in first and last records. */
+mustRead(f, fof->first, fof->itemSize);
+fseek(f, fof->headSize + fof->endIx*fof->itemSize, SEEK_SET);
+mustRead(f, fof->last, fof->itemSize);
+
+/* All done (files will be opened as needed, not here). */
+return fof;
+}
+
+
+void fofClose(struct fof **pFof)
+/* Close down the named fof. */
+{
+struct fof *fof = *pFof;
+if (fof != NULL)
+    {
+    int fileCount = fof->fileCount;
+    int i;
+
+    for (i=0; i<fileCount; ++i)
+        {
+        freeMem(fof->fileNames[i]);
+        carefulClose(&fof->files[i]);
+        }
+    freeMem(fof->name);
+    freeMem(fof->fileNames);
+    freeMem(fof->files);
+    freeMem(fof->rec);
+    freeMem(fof->first);
+    freeMem(fof->last);
+    carefulClose(&fof->f);
+    freez(pFof);
+    }
+}
+
+int fofElementCount(struct fof *fof)
+/* How many names are in fof file? */
+{
+return fof->endIx + 1;
+}
+
+static void fofRecToPos(struct fof *fof, int ix, struct fofRecord *rec, struct fofPos *pos)
+/* Convert from record to position, opening file for entry if necessary. */
+{
+int fileIx = rec->fileIx;
+FILE *f;
+
+pos->indexIx = ix;
+pos->offset = rec->offset;
+pos->size = rec->size;
+pos->fileName = fof->fileNames[fileIx];
+if ((f = fof->files[fileIx]) != NULL)
+    {
+    pos->f = f;
+    }
+else
+    {
+    pos->f = fof->files[fileIx] = mustOpen(fof->fileNames[fileIx], "rb");
+    }
+return;
+}
+
+
+static int fofCmp(char *prefix, char *name, int maxSize, boolean isPrefix)
+/* Compare either prefix of whole string to name. */
+{
+if (isPrefix)
+    return memcmp(prefix, name, maxSize);
+else
+    return strcmp(prefix, name);
+}
+
+static boolean fofSearch(struct fof *fof, char *name, int nameSize, 
+    boolean isPrefix, struct fofPos *retPos)
+/* Find index of name by binary search.
+ * Returns FALSE if no such name in the index file. */
+ {
+struct fofRecord *rec = fof->rec;
+int startIx, endIx, midIx;
+int cmp;
+int itemSize = fof->itemSize;
+FILE *f = fof->f;
+int headSize = fof->headSize;
+
+/* Truncate name size if necessary. */
+if (nameSize > fof->maxNameSize)
+    nameSize = fof->maxNameSize;
+
+/* Set up endpoints of binary search */
+startIx = 0;
+endIx = fof->endIx;
+
+/* Check for degenerate initial case */
+if (fofCmp(name, fof->first->name, nameSize, isPrefix) == 0)
+    {
+    fofRecToPos(fof, startIx, fof->first, retPos);
+    return TRUE;
+    }
+if (fofCmp(name, fof->last->name, nameSize, isPrefix) == 0)
+    {
+    fofRecToPos(fof, endIx, fof->last, retPos);
+    return TRUE;
+    }
+
+/* Do binary search. */
+for (;;)
+    {
+    midIx = (startIx + endIx ) / 2;
+    if (midIx == startIx || midIx == endIx)
+        return FALSE;
+    fseek(f, headSize + midIx*itemSize, SEEK_SET);
+    mustRead(f, rec, itemSize);
+    cmp = fofCmp(name, rec->name, nameSize, isPrefix);
+    if (cmp == 0)
+        {
+        fofRecToPos(fof, midIx, rec, retPos);
+        return TRUE;
+        }
+    else if (cmp > 0)
+	{
+	startIx = midIx;
+	}
+    else
+	{
+	endIx = midIx;
+	}
+    }
+}
+
+boolean fofFindFirst(struct fof *fof, char *prefix, 
+    int prefixSize, struct fofPos *retPos)
+/* Find first element with key starting with prefix. */
+{
+int ix;
+struct fofRecord *rec = fof->rec;
+FILE *f = fof->f;
+int itemSize = fof->itemSize;
+int headSize = fof->headSize;
+
+/* Find some record that starts with prefix. */
+if (!fofSearch(fof, prefix, prefixSize, TRUE, retPos))
+    return FALSE;
+
+/* Backtrack until find one that doesn't start with prefix. */
+ix = retPos->indexIx;
+while (--ix >= 0)
+    {
+    fseek(f, headSize + ix*itemSize, SEEK_SET);
+    mustRead(f, rec, itemSize);
+    if (memcmp(prefix, rec->name, prefixSize) != 0)
+        break;
+    }
+
+/* Return the first record that does start with prefix. */
+++ix;
+fseek(f, headSize + ix*itemSize, SEEK_SET);
+mustRead(f, rec, itemSize);
+fofRecToPos(fof, ix, rec, retPos);
+return TRUE;
+}
+
+
+boolean fofFind(struct fof *fof, char *name, struct fofPos *retPos)
+/* Find element corresponding with name.  Returns FALSE if no such name
+ * in the index file. */
+{
+return fofSearch(fof, name, strlen(name), FALSE, retPos);
+}
+
+void *fofFetch(struct fof *fof, char *name, int *retSize)
+/* Lookup element in index, allocate memory for it, and read
+ * it.  Returns buffer with element in it, which should be
+ * freeMem'd when done. Aborts if element isn't there. */
+{
+struct fofPos pos;
+void *s;
+
+if (!fofFind(fof, name, &pos))
+    errAbort("Couldn't find %s in %s", name, fof->name);
+s = needLargeMem(pos.size);
+fseek(pos.f, pos.offset, SEEK_SET);
+mustRead(pos.f, s, pos.size);
+*retSize = pos.size;
+return s;
+}
+
+char *fofFetchString(struct fof *fof, char *name, int *retSize)
+/* Lookup element in index, allocate memory for it, read it.
+ * Returns zero terminated string with element in it, which 
+ * should be freeMem'd when done. Aborts if element isn't there. */
+{
+struct fofPos pos;
+char *s;
+
+if (!fofFind(fof, name, &pos))
+    errAbort("Couldn't find %s in %s", name, fof->name);
+s = needLargeMem(pos.size+1);
+fseek(pos.f, pos.offset, SEEK_SET);
+mustRead(pos.f, s, pos.size);
+s[pos.size] = 0;
+*retSize = pos.size;
+return s;
+}
+
+/* ------------------- Batch read ------------------------*/
+static int cmpOnKey(const void *va, const void *vb)
+/* Comparison function for qsort on an array of offset pointers.
+ * Sorts on key. */
+{
+const struct fofBatch *a = *((struct fofBatch **)va);
+const struct fofBatch *b = *((struct fofBatch **)vb);
+return strcmp(a->key, b->key);
+}
+
+static int cmpOnFilePos(const void *va, const void *vb)
+/* Comparison function for qsort on an array of offset pointers.
+ * Sorts on file then file offset. */
+{
+const struct fofBatch *a = *((struct fofBatch **)va);
+const struct fofBatch *b = *((struct fofBatch **)vb);
+int dif = a->f - b->f;
+if (dif == 0)
+    dif = a->offset - b->offset;
+return dif;
+}
+
+static void elFromRec(struct fof *fof, struct fofRecord *rec, struct fofBatch *el)
+/* Fill in a batch element from record. */
+{
+FILE *ff;
+int fileIx = rec->fileIx;
+if ((ff = fof->files[fileIx]) != NULL)
+    {
+    el->f = ff;
+    }
+else
+    {
+    el->f = fof->files[fileIx] = mustOpen(fof->fileNames[fileIx], "rb");
+    }
+el->offset = rec->offset;
+el->size = rec->size;
+}
+
+struct fofBatch *fofBatchFind(struct fof *fof, struct fofBatch *list)
+/* Look up all of members on list. */
+{
+struct fofBatch *el;
+FILE *f = fof->f;
+struct fofRecord *rec = fof->rec;
+int itemSize = fof->itemSize;
+char *lastKey = "";
+
+slSort(&list, cmpOnKey);
+fseek(f, fof->headSize, SEEK_SET);
+for (el = list; el != NULL; el = el->next)
+    {
+    char *key = el->key;
+    if (sameString(key, lastKey))
+        {
+        elFromRec(fof, rec, el);
+        }
+    else
+        {
+        for (;;)
+            {
+            mustRead(f, rec, itemSize);
+            if (sameString(key, rec->name))
+                {
+                elFromRec(fof, rec, el);
+                lastKey = key;
+                break;
+                }
+            }
+        }
+    }
+slSort(&list, cmpOnFilePos);
+return list;
+}
+
+
+/* ------------------- Write Side ------------------------*/
+
+struct lm *localMem;    /* Local (fast) memory pool. */
+
+struct fofRecList
+/* This holds a list of records for an index file. */
+    {
+    struct fofRecList *next;
+    struct fofRecord rec;
+    };
+
+static int cmpRecList(const void *va, const void *vb)
+/* Comparison function for qsort on an array of offset pointers.
+ * Sorts first on name, then on fileIx, then on offset. */
+{
+const struct fofRecList *a = *((struct fofRecList **)va);
+const struct fofRecList *b = *((struct fofRecList **)vb);
+int dif;
+dif = strcmp(a->rec.name, b->rec.name);
+if (dif == 0)
+    {
+    UBYTE ao = a->rec.fileIx;
+    UBYTE bo = b->rec.fileIx;
+    if (ao < bo)
+        dif =  -1;
+    else if (ao > bo)
+        dif = 1;
+    else
+        {
+        bits32 ao = a->rec.offset;
+        bits32 bo = b->rec.offset;
+        if (ao < bo)
+            dif =  -1;
+        else if (ao == bo)
+            dif = 0;
+        else
+            dif = 1;
+        }
+    }
+return dif;
+}
+
+static bits16 maxNameSize;      /* Maximum size we've seen. */
+
+struct fofRecList *newFofRecEl(int fileIx, long offset, long size, char *name, int nameLen)
+/* Create a new offset list element. */
+{
+struct fofRecList *fr;
+
+if (maxNameSize < nameLen)
+    maxNameSize = nameLen;
+fr = lmAlloc(localMem, sizeof(*fr) + nameLen);
+fr->rec.offset = offset;
+fr->rec.size = size;
+fr->rec.fileIx = fileIx;
+memcpy(fr->rec.name, name, nameLen);
+return fr;
+}
+
+void fofMake(char *inFiles[], int inCount, char *outName, 
+    boolean (*readHeader)(FILE *inFile, void *data),
+    boolean (*nextRecord)(FILE *inFile, void *data, char **rName, int *rNameLen), 
+    void *data, boolean dupeOk)
+/* Make an index file
+ * Inputs:
+ *     inFiles - List of files that you're indexing with header read and verified.
+ *     inCount - Size of file list.
+ *     outName - name of index file to create
+ *     readHeader - function that sets up file to read first record.  May be NULL.
+ *     nextRecord - function that reads next record in file you're indexing
+ *                  and returns the name of that record.  Returns FALSE at
+ *                  end of file.  Can set *rNameLen to zero you want indexer
+ *                  to ignore the record. 
+ *     data - void pointer passed through to nextRecord.
+ *     dupeOk - set to TRUE if you want dupes to not cause squawking
+ */
+{
+FILE *out;
+bits32 sig = fofSig;
+bits32 elCount = 0;
+bits16 fileCount = inCount;
+struct fofRecList *recList = NULL, *rl;
+int i, fileIx, itemSize;
+char *lastName = "";
+int maxMod = 10000;
+
+/* Initialize. */
+localMem = lmInit(0);
+maxNameSize = 0;
+
+/* Read in all records and sort by name. */
+for (fileIx = 0; fileIx<inCount; ++fileIx)
+    {
+    char *inName = inFiles[fileIx];
+    FILE *in = mustOpen(inName, "rb");
+    bits32 start, end;
+    char *name;
+    int nameLen;
+    int mod = maxMod;
+
+    printf("Processing %s\n", inName);
+    if (readHeader)
+        readHeader(in, data);
+    start = ftell(in);
+    while (nextRecord(in, data, &name, &nameLen))
+        {
+	if (--mod == 0)
+	    {
+	    putc('.', stdout);
+	    fflush(stdout);
+	    mod = maxMod;
+	    }
+        end = ftell(in);
+        if (nameLen > 0)
+            {
+            rl = newFofRecEl(fileIx, start, end-start, name, nameLen);
+            slAddHead(&recList, rl);
+            }
+        start = end;
+        }
+    fclose(in);
+    printf("\n");
+    }
+
+printf("sorting\n");
+slSort(&recList, cmpRecList);
+
+/* Count up names. */
+if (dupeOk)
+    elCount = slCount(recList);
+else
+    {
+    lastName = "";
+    for (rl = recList; rl != NULL; rl = rl->next)
+        {
+        char *name = rl->rec.name;
+        if (!sameString(name, lastName))
+            {
+            ++elCount;
+            lastName = name;
+            }
+        }
+    }
+
+/* Write out index file. */
+printf("Writing %s\n", outName);
+out = mustOpen(outName, "wb");
+writeOne(out, sig);
+writeOne(out, elCount);
+writeOne(out, fileCount);
+writeOne(out, maxNameSize);
+itemSize = sizeof(bits32) +sizeof(bits32) + sizeof(UBYTE) + maxNameSize;
+for (i=0; i<inCount; ++i)
+    {
+    char *name = inFiles[i];
+    int len = strlen(name)+1;
+    mustWrite(out, name, len);
+    }
+lastName = "";
+for (rl = recList; rl != NULL; rl = rl->next)
+    {
+    if (!dupeOk)
+        {
+        char *name = rl->rec.name;
+        if (sameString(name, lastName))
+            {
+            warn("Duplicate %s only saving first.", name);
+            continue;
+            }
+        else
+            lastName = name;
+        }
+    writeOne(out, rl->rec.offset);
+    writeOne(out, rl->rec.size);
+    writeOne(out, rl->rec.fileIx);
+    mustWrite(out, rl->rec.name, maxNameSize);
+    }
+if (fclose(out) != 0)
+    errnoAbort("fclose failed");
+/* Clean up. */
+lmCleanup(&localMem);
+}
+
diff --git a/lib/font/README b/lib/font/README
new file mode 100644
index 0000000..157c5b6
--- /dev/null
+++ b/lib/font/README
@@ -0,0 +1,23 @@
+Most of these files were created from fonts in the xfree package.  These were downloaded from the
+CVS archive at  http://www.xfree86.org/cvs/  in the xc/fonts/bdf/100dpi  and xc/fonts/bdf/75dpi
+modules using the bdfToGem format Hiram Clawson wrote.  The commands in particular are:
+
+bdfToGem 75dpi/courR12.bdf mgCourier12.c -name=Courier12
+bdfToGem 75dpi/courR18.bdf mgCourier18.c -name=Courier18
+bdfToGem 75dpi/courR24.bdf mgCourier24.c -name=Courier24
+bdfToGem 75dpi/helvR08.bdf mgHelvetica8.c -name=Helvetica8
+bdfToGem 75dpi/helvR12.bdf mgHelvetica12.c -name=Helvetica12
+bdfToGem 75dpi/helvR14.bdf mgHelvetica14.c -name=Helvetica14
+bdfToGem 75dpi/helvR18.bdf mgHelvetica18.c -name=Helvetica18
+bdfToGem 75dpi/helvR24.bdf mgHelvetica24.c -name=Helvetica24
+bdfToGem 75dpi/timR08.bdf mgTimes8.c -name=Times8
+bdfToGem 75dpi/timR12.bdf mgTimes12.c -name=Times12
+bdfToGem 75dpi/timR14.bdf mgTimes14.c -name=Times14
+bdfToGem 75dpi/timR18.bdf mgTimes18.c -name=Times18
+bdfToGem 75dpi/timR24.bdf mgTimes24.c -name=Times24
+bdfToGem 100dpi/courR24.bdf mgCourier34.c -name=Courier34
+bdfToGem 100dpi/helvR24.bdf mgHelvetica34.c -name=Helvetica34
+bdfToGem 100dpi/helvB24.bdf mgHelveticaBold34.c -name=HelveticaBold34
+bdfToGem 100dpi/timR24.bdf mgTimes34.c -name=Times34
+
+Two additional fonts - sail and sixhi - were from other sources now lost in the midsts of time.
diff --git a/lib/font/mgCourier10.c b/lib/font/mgCourier10.c
new file mode 100644
index 0000000..972787b
--- /dev/null
+++ b/lib/font/mgCourier10.c
@@ -0,0 +1,299 @@
+
+/* Courier10.c - compiled data for font -Adobe-Courier-M-R-N--10-100-75 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/courR10.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Courier10_data[2376] = {
+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,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,
+0x4,0x4,0x21,0x40,0x8,0,0x4,0x8,0x40,0x8,
+0x8,0x40,0,0x14,0x40,0x46,0x14,0,0,0x10,
+0x21,0x80,0x8,0,0,0,0,0,0x10,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,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,0x40,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,0x10,0,0,
+0,0,0,0xc1,0x83,0x80,0x2,0x8,0x52,0x85,
+0x14,0,0x2,0x10,0xa2,0x84,0x10,0xa2,0x80,0x28,
+0x20,0x89,0x28,0x90,0,0x8,0x42,0x49,0x10,0,
+0x8,0x8,0x42,0x80,0x28,0,0x4,0x8,0x60,0x8,
+0x8,0x40,0xd,0x14,0x40,0x86,0x14,0,0,0x10,
+0x21,0x80,0x8,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,0x85,0xa,0x10,0,0x8,0x9,0x2,
+0,0,0,0x2,0x30,0x43,0xc,0x11,0xe3,0x9e,
+0x30,0xc0,0,0,0,0,0x30,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xc,0x40,0xc2,0,
+0x20,0xc,0,0x18,0x1,0x80,0xc0,0x41,0x30,0x30,
+0,0,0,0,0,0x20,0,0,0,0,
+0x2,0x21,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,0x1,
+0xe,0x2,0x22,0,0x50,0xc0,0,0,0x3,0x1e,
+0x30,0x3,0x1c,0x20,0,0,0x1,0x80,0,0x42,
+0x85,0x8,0,0,0,0,0x8,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x1,0x84,0x10,0xa5,0xa,
+0x10,0,0x2,0x10,0x92,0x44,0x10,0xa2,0x86,0x28,
+0x21,0x9,0x28,0x90,0,0x8,0x42,0x49,0x11,0x82,
+0x40,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,0x85,
+0xa,0x39,0x83,0x8,0x10,0x8d,0x88,0,0,0x4,
+0x49,0xc4,0x92,0x31,0x4,0x12,0x49,0x20,0,0x10,
+0x2,0xc,0x49,0xcf,0xc,0xf3,0xef,0x8c,0xcf,0xe7,
+0xb6,0xe2,0x2d,0x8c,0xf0,0xcf,0xe,0xfb,0x3d,0xf7,
+0xdb,0x67,0x88,0x20,0x45,0,0,0x4,0,0x8,
+0x2,0,0x40,0,0x10,0x10,0,0,0,0,
+0,0x20,0,0,0,0,0x4,0x20,0x80,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,0x1,0x10,0x89,0x42,0xe,
+0x1,0x27,0,0,0x4,0x80,0x48,0x85,0x8,0,
+0x7,0xc0,0,0x83,0,0x44,0x88,0x90,0xe,0x38,
+0xe3,0x8e,0x38,0xf9,0x9f,0x7d,0xf7,0xdf,0x7d,0xf7,
+0xde,0x6c,0x61,0x86,0x18,0x64,0x46,0xe7,0x9e,0x79,
+0xed,0x82,0x40,0,0,0,0,0,0,0,
+0,0,0,0,0xa,0,0,0,0,0x1,
+0,0,0,0,0,0x80,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,0x85,0x1f,0x42,0xa4,0x8,
+0x10,0x82,0x8,0,0,0x4,0x48,0x40,0x82,0x51,
+0x4,0x2,0x49,0x20,0,0x21,0xe1,0x12,0x98,0xa4,
+0x92,0x49,0x24,0x92,0x48,0x81,0x14,0x43,0x64,0x92,
+0x49,0x24,0x90,0xa9,0x28,0xa2,0x52,0x24,0x88,0x20,
+0x48,0x80,0,0xc7,0xc,0x38,0xc7,0x8d,0x70,0xc7,
+0x16,0x13,0x4b,0xc,0xb0,0xd5,0xce,0x7b,0x6c,0xeb,
+0xdb,0x67,0x84,0x20,0x82,0x80,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,0x43,0xbe,0x73,0xe2,0x10,0x2,0xd0,0x80,0xf8,
+0xb,0xc0,0x33,0xe2,0x4,0x3,0x6a,0x80,0,0x84,
+0x80,0xe9,0xd3,0x20,0x5,0x14,0x51,0x45,0x14,0x62,
+0x49,0x24,0x92,0x44,0x10,0x41,0x9,0x24,0x92,0x49,
+0x24,0x92,0x89,0x24,0x92,0x49,0x44,0xe2,0x4c,0x30,
+0xc3,0xc,0x30,0xd9,0x86,0x18,0x61,0x8c,0x30,0xc3,
+0x7,0x58,0x61,0x86,0x18,0x60,0x6,0xed,0xb6,0xdb,
+0x6c,0xe6,0xc0,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,0x80,0xa,0x33,0x46,0,0x20,0x45,0x3e,0x1,
+0xe0,0x8,0x48,0x41,0xc,0x91,0xc7,0x4,0x30,0xe2,
+0x8,0x40,0,0x84,0xa9,0x27,0x10,0x49,0xc7,0x10,
+0x78,0x81,0x18,0x42,0xa6,0x92,0x49,0x24,0x8c,0x21,
+0x25,0x2a,0x21,0x41,0x8,0x10,0x40,0,0,0x24,
+0x92,0x49,0x22,0x12,0x48,0x41,0x14,0x12,0xa4,0x92,
+0x49,0x22,0x10,0x21,0x24,0x6a,0x51,0x21,0x4,0x20,
+0x85,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,0x4,0x8,0x50,
+0x80,0xc,0x2,0x96,0x92,0x9,0xeb,0x40,0,0x87,
+0x18,0x1,0x2a,0x88,0x1,0xc3,0x12,0x10,0x20,0x40,
+0x89,0x24,0x92,0x49,0x24,0xba,0xe,0x38,0xe3,0x84,
+0x10,0x41,0x1d,0x34,0x92,0x49,0x24,0x91,0xb,0x24,
+0x92,0x49,0x28,0x92,0xc2,0x8,0x20,0x82,0x9,0x2a,
+0x49,0x24,0x92,0x44,0x10,0x41,0x9,0x24,0x92,0x49,
+0x24,0x97,0xc9,0x24,0x92,0x49,0x24,0x92,0x40,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,0x80,0x3f,0x8,
+0xb9,0x40,0x20,0x40,0x8,0,0,0x8,0x48,0x42,
+0x2,0xf8,0x24,0x84,0x48,0x20,0,0x21,0xe1,0x8,
+0xa9,0xe4,0x90,0x49,0x5,0x16,0x48,0x89,0x14,0x42,
+0xa5,0x92,0x71,0x27,0x2,0x21,0x25,0x2a,0x20,0x82,
+0x8,0x10,0x40,0,0,0xe4,0x90,0x49,0xc2,0x12,
+0x48,0x41,0x18,0x12,0xa4,0x92,0x49,0x22,0xc,0x21,
+0x22,0xaa,0x21,0x22,0x8,0x20,0x40,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,0x44,0x8,0x73,0xe0,0x12,0x2,0xd0,
+0x24,0x8,0xa,0xc0,0,0,0,0x1,0x26,0x80,
+0,0,0x9,0x24,0x58,0x90,0xf,0x3c,0xf3,0xcf,
+0x3c,0xe2,0x8,0x20,0x82,0x4,0x10,0x41,0x9,0x2c,
+0x92,0x49,0x24,0x92,0x8d,0x24,0x92,0x49,0x10,0xe2,
+0x2e,0x38,0xe3,0x8e,0x38,0xfa,0xf,0x3c,0xf3,0xc4,
+0x10,0x41,0x9,0x24,0x92,0x49,0x24,0x90,0x9,0x24,
+0x92,0x49,0x24,0x92,0x40,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,0x14,0x49,0x58,0x80,0x20,0x40,
+0x8,0,0,0x10,0x48,0x44,0x12,0x10,0x24,0x88,
+0x48,0x20,0,0x10,0x2,0,0x9d,0x24,0x92,0x49,
+0x24,0x12,0x48,0x89,0x12,0x4a,0x24,0x92,0x41,0x24,
+0x92,0x21,0x25,0x14,0x50,0x84,0x88,0x8,0x40,0,
+0x1,0x24,0x92,0x49,0x2,0x12,0x48,0x41,0x14,0x12,
+0xa4,0x92,0x49,0x22,0x2,0x25,0x22,0x94,0x51,0x24,
+0x84,0x20,0x80,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,0x43,
+0x91,0x88,0x82,0xc,0x1,0x27,0x92,0,0x4,0x80,
+0x3,0xe0,0,0x1,0x22,0x80,0,0x7,0x92,0x4c,
+0xa9,0x30,0x89,0x24,0x92,0x49,0x25,0x22,0x49,0x24,
+0x92,0x44,0x10,0x41,0x9,0x24,0x92,0x49,0x24,0x94,
+0x49,0x24,0x92,0x49,0x10,0x82,0x32,0x49,0x24,0x92,
+0x49,0x22,0x48,0x20,0x82,0x4,0x10,0x41,0x9,0x24,
+0x92,0x49,0x24,0x91,0x9,0x24,0x92,0x49,0x24,0x92,
+0x40,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,0x80,
+0x14,0x30,0x67,0x40,0x10,0x80,0,0x20,0x2,0x10,
+0x31,0xe7,0x8c,0x11,0xc3,0x8,0x31,0xc2,0x8,0,
+0,0x8,0x83,0x3f,0xc,0xf3,0xee,0xc,0xcf,0xe6,
+0x39,0xfb,0x6c,0x8c,0xe0,0xce,0x5c,0x70,0xc2,0x14,
+0xd9,0xc7,0x88,0x8,0x40,0,0,0xdf,0xc,0x34,
+0xe7,0x8e,0xed,0xf1,0x36,0x7e,0xbe,0xcc,0x70,0xe7,
+0x9c,0x18,0xd1,0x14,0xd8,0xc7,0x84,0x20,0x80,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,0x41,0x3f,0x1,0xc2,0x2,
+0,0xc0,0,0,0x3,0,0,0,0,0x1,
+0xd2,0x80,0x20,0,0,0x9f,0x12,0x79,0x19,0xe7,
+0x9e,0x79,0xe7,0x39,0x9f,0x7d,0xf7,0xdf,0x7d,0xf7,
+0xde,0x64,0x61,0x86,0x18,0x60,0x16,0x18,0x61,0x86,
+0x39,0xc6,0xcd,0x34,0xd3,0x4d,0x35,0xd9,0x87,0x1c,
+0x71,0xdf,0x7d,0xf7,0xc6,0x76,0x61,0x86,0x18,0x60,
+0x16,0x1a,0x69,0xa6,0x98,0xe1,0x80,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,0x10,0,0,
+0x10,0x80,0,0x20,0,0x20,0,0,0,0,
+0,0,0,0,0x8,0,0,0,0x78,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x20,0,0,0,0,0,0,0x8,0x4,
+0x40,0,0,0,0,0,0,0x2,0,0x1,
+0,0,0,0,0x40,0x20,0,0,0,0,
+0,0x80,0x4,0x20,0x80,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,0x41,0,0,0x2,0x1c,0,0,0,0,
+0,0,0,0,0,0x1,0x6,0xc0,0x10,0,
+0,0x4,0x38,0x12,0x40,0,0,0,0,0,
+0x80,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x80,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x10,0x81,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,0x9,0,0,0x40,
+0,0,0,0,0,0,0,0,0,0,
+0x10,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xc,0,0xc0,0x3f,0,0,
+0,0,0,0x1c,0,0x6,0,0,0,0,
+0xe0,0x70,0,0,0,0,0x3,0,0x2,0x21,
+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,0x40,0,0,
+0x2,0,0,0,0,0,0,0,0,0,
+0,0x1,0,0,0x60,0,0,0,0,0x1,
+0x80,0,0,0,0,0x3,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x61,0xc6,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,
+};
+
+static WORD Courier10_ch_ofst[225] = {
+0,6,12,18,24,30,36,42,48,54,
+60,66,72,78,84,90,96,102,108,114,
+120,126,132,138,144,150,156,162,168,174,
+180,186,192,198,204,210,216,222,228,234,
+240,246,252,258,264,270,276,282,288,294,
+300,306,312,318,324,330,336,342,348,354,
+360,366,372,378,384,390,396,402,408,414,
+420,426,432,438,444,450,456,462,468,474,
+480,486,492,498,504,510,516,522,528,534,
+540,546,552,558,564,570,576,582,588,594,
+600,606,612,618,624,630,636,642,648,654,
+660,666,672,678,684,690,696,702,708,714,
+720,726,732,738,744,750,756,762,768,774,
+780,786,792,798,804,810,816,822,828,834,
+840,846,852,858,864,870,876,882,888,894,
+900,906,912,918,924,930,936,943,950,957,
+963,969,975,981,987,993,999,1005,1011,1017,
+1023,1029,1035,1041,1047,1053,1059,1065,1071,1077,
+1083,1089,1095,1101,1107,1113,1119,1125,1131,1137,
+1143,1149,1155,1161,1167,1173,1179,1185,1191,1197,
+1203,1209,1215,1221,1227,1233,1239,1245,1251,1257,
+1263,1269,1275,1281,1287,1293,1299,1305,1311,1317,
+1323,1329,1335,1341,1347,
+};
+
+static struct font_hdr Courier10_font = {
+STPROP, 10, "-Adobe-Courier-M-R-N--10-100-75", 32, 255,
+11, 9, 5, 2, 2,
+8, 6, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Courier10_ch_ofst, Courier10_data,
+216, 11,
+NULL,
+0, 0,   /* x/y offset */
+11,        /* lineHeight */
+9,	   /* psHeight */
+};
+
+MgFont *mgCourier10Font()
+{
+return &Courier10_font;
+}
+
+MgFont *mgSmallFixedFont()
+{
+return &Courier10_font;
+}
diff --git a/lib/font/mgCourier12.c b/lib/font/mgCourier12.c
new file mode 100644
index 0000000..1fbe27f
--- /dev/null
+++ b/lib/font/mgCourier12.c
@@ -0,0 +1,364 @@
+
+/* Courier12.c - compiled data for font -Adobe-Courier-M-R-N--12-120-75 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/courR12.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Courier12_data[3080] = {
+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,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,
+0x4,0x2,0x8,0x28,0,0x40,0,0x4,0x2,0x8,
+0,0x40,0x20,0x80,0,0x5,0x10,0x8,0x20,0x50,
+0,0,0x8,0x4,0x10,0,0x20,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,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,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,
+0x2,0x4,0x14,0x50,0x50,0xa0,0,0x2,0x4,0x14,
+0x28,0x20,0x41,0x42,0x80,0xa,0x8,0x10,0x50,0xa1,
+0x40,0,0x4,0x8,0x28,0x50,0x40,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0xc,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,0x20,0,0x1,0,0,0,0x4,0x80,0,
+0,0,0,0x1,0x38,0x20,0xe1,0xc0,0x8f,0x87,
+0x3e,0x38,0x70,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,0xc4,0x6,0,0,0x40,0x3,0,0,
+0xc0,0x7,0,0xc0,0x20,0x26,0x7,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,0x1e,0,
+0,0,0,0,0,0,0,0,0,0,
+0x80,0x1f,0,0,0,0,0x4,0x4,0x6,0,
+0,0,0,0,0,0x40,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x80,0,0,0,0,0x3,0x4,0x2,
+0x8,0x14,0,0x40,0,0x4,0x2,0x8,0,0x40,
+0x20,0x80,0x3,0x8a,0x10,0x10,0x20,0xa0,0,0,
+0x8,0x8,0x10,0,0x26,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,0x20,0xa0,0xa3,0x86,0xe,0x8,0x8,0x40,0x40,
+0,0,0,0x2,0x44,0xe1,0x12,0x21,0x88,0x8,
+0x22,0x44,0x88,0,0,0,0,0x1c,0x38,0xe3,
+0xe1,0xcf,0x9f,0xbf,0x1c,0xee,0xf8,0xf7,0x6e,0x18,
+0xf3,0x9c,0xf8,0x73,0xe1,0xef,0xfd,0xfb,0xf7,0xef,
+0xdd,0xf0,0x82,0x2,0x4,0,0x20,0x1,0,0,
+0x40,0x8,0,0x40,0,0x2,0x1,0,0,0,
+0,0,0,0x2,0,0,0,0,0,0,
+0x41,0x4,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,0x40,0xc0,0x1d,0xc4,0x12,0x28,
+0x70,0xc0,0,0,0xe,0x3e,0x30,0,0xc1,0x81,
+0,0x2a,0,0,0x20,0xc0,0xc,0x1c,0x19,0x10,
+0xe,0x1c,0x38,0x70,0xe1,0xc3,0xe3,0x9f,0xbf,0x7e,
+0xfc,0xf9,0xf3,0xe7,0xdf,0x3b,0x9c,0x38,0x70,0xe1,
+0xc0,0x7,0x3b,0xf7,0xef,0xdf,0xbf,0x4,0x82,0x4,
+0x14,0x28,0x50,0xa0,0,0x2,0x4,0x14,0x28,0x20,
+0x41,0x42,0x86,0x14,0x8,0x20,0x51,0x41,0x40,0,
+0x4,0x10,0x28,0x50,0x42,0x2,0x80,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x20,0xa0,0xa4,0x49,0x12,0x8,0x8,0x40,0x40,
+0,0,0,0x2,0x44,0x21,0x10,0x22,0x88,0x10,
+0x4,0x44,0x88,0,0,0x80,0x8,0x22,0x44,0x21,
+0x12,0x24,0x48,0x91,0x22,0x44,0x20,0x22,0x44,0xd,
+0x99,0x22,0x4c,0x89,0x12,0x29,0x28,0x91,0x22,0x44,
+0x89,0x10,0x82,0x2,0xa,0,0,0x1,0,0,
+0x40,0x8,0,0x40,0,0x2,0x1,0,0,0,
+0,0,0,0x2,0,0,0,0,0,0,
+0x81,0x2,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,0x41,0x28,0x48,0x84,0x18,0,
+0x88,0x20,0,0,0x11,0,0x48,0x1,0x22,0x40,
+0,0x2a,0,0,0x61,0x20,0x4,0x24,0x22,0x20,
+0x2,0x4,0x8,0x10,0x20,0x41,0x84,0x48,0x91,0x22,
+0x44,0x20,0x40,0x81,0x8,0x99,0x22,0x44,0x89,0x12,
+0x20,0x9,0x91,0x22,0x44,0x89,0x12,0x4,0x80,0,
+0,0,0,0x40,0,0,0,0,0,0,
+0,0,0x9,0,0,0,0,0,0,0,
+0x80,0,0,0,0x2,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,0x20,0xa3,0xf4,0x6,0x50,0x8,0x10,0x21,0xf0,
+0x80,0,0,0x4,0x44,0x21,0x10,0x22,0x88,0x10,
+0x4,0x44,0x88,0,0x1,0,0x4,0x2,0x4c,0x51,
+0x12,0x24,0x4a,0x15,0x22,0x44,0x20,0x22,0x84,0xd,
+0x99,0x22,0x44,0x89,0x12,0x9,0x28,0x91,0x2a,0x28,
+0x51,0x20,0x81,0x2,0x11,0,0,0xf1,0xe1,0xc3,
+0xc7,0x1f,0x1d,0x58,0xe1,0xe2,0x61,0x1d,0x2e,0x1c,
+0xb8,0x75,0x71,0xc7,0xd9,0xbb,0xf7,0xef,0xdd,0xf0,
+0x81,0x2,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,0x20,0xe1,0x7,0x85,0x4,0x24,0x1,
+0x34,0xe1,0x20,0,0x2e,0x80,0x48,0x20,0x40,0x80,
+0x19,0xaa,0,0,0x21,0x22,0x44,0x44,0x49,0x41,
+0x5,0xa,0x14,0x28,0x50,0xa2,0x84,0x49,0x12,0x24,
+0x48,0x20,0x40,0x81,0x8,0x95,0x22,0x44,0x89,0x12,
+0x24,0x4a,0x91,0x22,0x44,0x88,0xa3,0xc4,0x8f,0x1e,
+0x3c,0x78,0xf1,0xe3,0x63,0x87,0xe,0x1c,0x38,0xe1,
+0xc3,0x87,0x7,0xae,0x1c,0x38,0x70,0xe1,0xc1,0x7,
+0x33,0x66,0xcd,0x9b,0xbb,0xce,0xe0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x20,0x1,0x43,0x1,0x88,0x80,0x10,0x20,0x40,
+0x80,0,0,0x4,0x44,0x20,0x20,0xc4,0x8f,0x1e,
+0x4,0x38,0x88,0x40,0x82,0xf,0x82,0x4,0x54,0x51,
+0xe2,0x4,0x4e,0x1c,0x20,0x7c,0x20,0x23,0x4,0xa,
+0x95,0x22,0x4c,0x89,0xe3,0x81,0x8,0x9b,0x2a,0x10,
+0x50,0x40,0x81,0x2,0,0,0,0x9,0x12,0x24,
+0x48,0x88,0x22,0x64,0x20,0x22,0x81,0xa,0x99,0x22,
+0x44,0x88,0x82,0x22,0x8,0x91,0x22,0x28,0x89,0x20,
+0x81,0x2,0x9,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,0x1,0x53,0xe4,0x8f,0x84,0x22,0x1,
+0x44,0xa2,0x47,0xc0,0x2a,0x80,0x30,0xf8,0x82,0x40,
+0x8,0x9a,0,0,0x20,0xc1,0x2e,0x8e,0x86,0x80,
+0x5,0xa,0x14,0x28,0x50,0xa2,0xe4,0xf,0x1e,0x3c,
+0x78,0x20,0x40,0x81,0x1c,0x95,0x22,0x44,0x89,0x12,
+0x22,0x8a,0x91,0x22,0x44,0x88,0x42,0x25,0,0x81,
+0x2,0x4,0x8,0x10,0x94,0x48,0x91,0x22,0x44,0x20,
+0x40,0x81,0x8,0x99,0x22,0x44,0x89,0x12,0x20,0x9,
+0x91,0x22,0x44,0x89,0x12,0x24,0x40,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x20,0x1,0x41,0x86,0x1d,0,0x10,0x20,0xa3,
+0xe0,0xf,0x80,0x8,0x44,0x20,0x40,0x28,0x80,0x91,
+0x4,0x44,0x78,0,0x4,0,0x1,0x8,0x54,0xf9,
+0x12,0x4,0x4a,0x14,0x26,0x44,0x20,0x23,0x84,0xa,
+0x95,0x22,0x78,0x89,0x20,0xe1,0x8,0x8a,0x2a,0x28,
+0x20,0x40,0x80,0x82,0,0,0,0x79,0x12,0x4,
+0x4f,0x88,0x22,0x44,0x20,0x23,0x1,0xa,0x91,0x22,
+0x44,0x88,0x81,0xc2,0x8,0x91,0x2a,0x10,0x88,0x41,
+0x1,0x1,0x15,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,0x1,0x40,0x84,0x82,0,0x12,0x1,
+0x44,0x4,0x80,0x4f,0xac,0x80,0,0x21,0xe1,0x80,
+0x8,0x8a,0x8,0,0x70,0,0x91,0x21,0x61,0x21,
+0xf,0x9f,0x3e,0x7c,0xf9,0xf2,0x84,0x9,0x12,0x24,
+0x48,0x20,0x40,0x81,0x8,0x93,0x22,0x44,0x89,0x12,
+0x21,0xa,0x91,0x22,0x44,0x88,0x42,0x24,0x87,0x8f,
+0x1e,0x3c,0x78,0xf3,0xf4,0xf,0x9f,0x3e,0x7c,0x20,
+0x40,0x81,0x8,0x91,0x22,0x44,0x89,0x12,0x27,0xca,
+0x91,0x22,0x44,0x89,0x12,0x24,0x40,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x20,0x7,0xe4,0x49,0xa2,0,0x10,0x20,0,
+0x80,0,0,0x8,0x44,0x20,0x80,0x2f,0xc0,0x91,
+0x8,0x44,0x8,0,0x2,0xf,0x82,0x8,0x4e,0x89,
+0x12,0x24,0x48,0x10,0x22,0x44,0x21,0x22,0x44,0x4a,
+0x93,0x22,0x40,0x89,0x10,0x21,0x8,0x8a,0x36,0x28,
+0x20,0x90,0x80,0x82,0,0,0,0x89,0x12,0x4,
+0x48,0x8,0x22,0x44,0x20,0x22,0x81,0xa,0x91,0x22,
+0x44,0x88,0x80,0x22,0x8,0x8a,0x2a,0x28,0x50,0x80,
+0x81,0x2,0x12,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,0x21,0x50,0x87,0x8f,0x80,0xc,0x1,
+0x35,0xe2,0x40,0x40,0x2a,0x80,0,0,0,0,
+0x8,0x8a,0,0,0x1,0xe1,0x22,0x62,0x92,0x61,
+0x8,0x91,0x22,0x44,0x89,0x17,0x84,0x48,0x91,0x22,
+0x44,0x20,0x40,0x81,0x8,0x93,0x22,0x44,0x89,0x12,
+0x22,0x8a,0x91,0x22,0x44,0x88,0x43,0xc4,0x48,0x91,
+0x22,0x44,0x89,0x14,0x84,0x8,0x10,0x20,0x40,0x20,
+0x40,0x81,0x8,0x91,0x22,0x44,0x89,0x12,0x20,0xa,
+0x91,0x22,0x44,0x88,0xa2,0x22,0x80,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,0x2,0x84,0x42,0x63,0,0x10,0x20,0,
+0x82,0,0,0x10,0x44,0x21,0x12,0x20,0x90,0x91,
+0x8,0x44,0x10,0,0x81,0,0x4,0,0x40,0x89,
+0x12,0x24,0x48,0x90,0x22,0x44,0x21,0x22,0x24,0x48,
+0x93,0x22,0x40,0x89,0x12,0x21,0xd,0x8e,0x14,0x44,
+0x21,0x10,0x80,0x42,0,0,0,0x89,0x12,0x24,
+0x48,0x88,0x22,0x44,0x20,0x22,0x41,0xa,0x91,0x22,
+0x44,0x88,0x82,0x22,0x28,0x8e,0x14,0x44,0x71,0x10,
+0x81,0x2,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,0x20,0xe1,0x18,0x42,0x4,0x24,0,
+0x88,0x1,0x20,0,0x11,0,0,0xf8,0,0,
+0x8,0x8a,0,0,0,0x2,0x44,0xa4,0x24,0xa2,
+0x8,0x91,0x22,0x44,0x89,0x14,0x84,0x48,0x91,0x22,
+0x44,0x20,0x40,0x81,0x8,0x91,0x22,0x44,0x89,0x12,
+0x24,0x4c,0x9b,0x36,0x6c,0xd8,0x42,0x5,0x48,0x91,
+0x22,0x44,0x89,0x14,0x94,0x48,0x91,0x22,0x44,0x20,
+0x40,0x81,0x8,0x91,0x22,0x44,0x89,0x12,0x21,0xc,
+0x91,0x22,0x44,0x88,0xe2,0x23,0x80,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x20,0x2,0x83,0x81,0x9c,0x80,0x8,0x40,0,
+0x2,0,0x8,0x10,0x38,0xf9,0xf1,0xc1,0xcf,0xe,
+0x8,0x38,0xe0,0x40,0x80,0x80,0x8,0x8,0x39,0xdf,
+0xe1,0xcf,0x9f,0xbc,0x1c,0xee,0xf8,0xc7,0x3f,0xdd,
+0xf9,0x1c,0xf0,0x73,0x9b,0xc7,0xc7,0x4,0x14,0xee,
+0x71,0xf0,0x80,0x42,0,0,0,0x76,0xe1,0xc3,
+0xa7,0x1e,0x1e,0xee,0xf8,0x26,0x37,0xfa,0xf9,0x9c,
+0x78,0x79,0xe1,0xc1,0xc7,0x44,0x14,0xc6,0x21,0xf0,
+0x81,0x2,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,0x20,0x43,0xe0,0x7,0x4,0x24,0,
+0x70,0,0,0,0xe,0,0,0,0,0,
+0xf,0x4a,0,0,0,0,0x8,0xf8,0x48,0xf4,
+0x1d,0xfb,0xf7,0xef,0xdf,0xbc,0xe3,0x9f,0xbf,0x7e,
+0xfc,0xf9,0xf3,0xe7,0xdf,0x39,0x1c,0x38,0x70,0xe1,
+0xc0,0x7,0xe,0x1c,0x38,0x70,0xe7,0xd,0x87,0x4e,
+0x9d,0x3a,0x74,0xeb,0x63,0x87,0xe,0x1c,0x38,0xf9,
+0xf3,0xe7,0xc7,0x39,0x9c,0x38,0x70,0xe1,0xc0,0x7,
+0xe,0x9d,0x3a,0x74,0x43,0xc1,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,0x1,0,0,0,0x8,0x40,0,
+0x4,0,0,0x20,0,0,0,0,0,0,
+0,0,0,0x1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x18,0,0,0,0,0,0,
+0,0,0x80,0x22,0,0,0,0,0,0,
+0,0,0x2,0,0,0x20,0,0,0,0,
+0x40,0x8,0,0,0,0,0,0,0x20,0,
+0x81,0x2,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,0x20,0x40,0,0,0x4,0x3c,0,
+0,0,0,0,0,0,0,0,0,0,
+0x8,0x1b,0,0x10,0,0,0,0x20,0xf0,0x24,
+0x40,0,0,0,0,0,0x1,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x8,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x8,
+0,0,0,0,0x42,0x1,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,0x4,0x80,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,0xc0,0x6,0,0,0,0,0,0,
+0,0,0x2,0,0,0x20,0,0,0,0,
+0x40,0x8,0,0,0,0,0,0,0x20,0,
+0x41,0x4,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,0x20,0,0,0,0x4,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x8,0,0,0x8,0,0,0,0,0,0x3,
+0x80,0,0,0,0,0,0,0x80,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,0x80,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x42,0x1,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,0,0,
+0,0,0,0,0,0x7f,0,0,0,0,
+0,0,0x1c,0,0x1,0xc0,0,0,0,0,
+0xe0,0x1c,0,0,0,0,0,0,0xc0,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,0x20,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x8,0,0,0x30,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,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,0x3,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x1,0x87,0x6,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+};
+
+static WORD Courier12_ch_ofst[225] = {
+0,7,14,21,28,35,42,49,56,63,
+70,77,84,91,98,105,112,119,126,133,
+140,147,154,161,168,175,182,189,196,203,
+210,217,224,231,238,245,252,259,266,273,
+280,287,294,301,308,315,322,329,336,343,
+350,357,364,371,378,385,392,399,406,413,
+420,427,434,441,448,455,462,469,476,483,
+490,497,504,511,518,525,532,539,546,553,
+560,567,574,581,588,595,602,609,616,623,
+630,637,644,651,658,665,672,679,686,693,
+700,707,714,721,728,735,742,749,756,763,
+770,777,784,791,798,805,812,819,826,833,
+840,847,854,861,868,875,882,889,896,903,
+910,917,924,931,938,945,952,959,966,973,
+980,987,994,1001,1008,1015,1022,1029,1036,1043,
+1050,1057,1064,1071,1078,1085,1092,1100,1108,1116,
+1123,1130,1137,1144,1151,1158,1165,1172,1179,1186,
+1193,1200,1207,1214,1221,1228,1235,1242,1249,1256,
+1263,1270,1277,1284,1291,1298,1305,1312,1319,1326,
+1333,1340,1347,1354,1361,1368,1375,1382,1389,1396,
+1403,1410,1417,1424,1431,1438,1445,1452,1459,1466,
+1473,1480,1487,1494,1501,1508,1515,1522,1529,1536,
+1543,1550,1557,1564,1571,
+};
+
+static struct font_hdr Courier12_font = {
+STPROP, 12, "-Adobe-Courier-M-R-N--12-120-75", 32, 255,
+14, 11, 7, 3, 3,
+8, 7, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Courier12_ch_ofst, Courier12_data,
+220, 14,
+NULL,
+0, 0,   /* x/y offset */
+15,        /* lineHeight */
+11,	   /* psHeight */
+};
+
+MgFont *mgCourier12Font()
+{
+return &Courier12_font;
+}
diff --git a/lib/font/mgCourier14.c b/lib/font/mgCourier14.c
new file mode 100644
index 0000000..ab17196
--- /dev/null
+++ b/lib/font/mgCourier14.c
@@ -0,0 +1,734 @@
+
+/* Courier14.c - compiled data for font -Adobe-Courier-M-R-N--14-140-75 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/courR14.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Courier14_data[6720] = {
+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,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,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,0xc0,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,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,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,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,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,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,
+0x60,0x3,0x2,0x3,0x40,0x1,0x20,0,0,0x30,
+0x1,0x82,0,0x3,0,0x30,0x20,0,0,0xd,
+0x18,0,0xc1,0x80,0xd0,0,0,0,0x30,0x1,
+0x83,0,0,0x30,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,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,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,0x80,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,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,
+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,
+0x18,0xc,0x5,0x5,0x83,0x60,0xc0,0,0,0xc,
+0x6,0x5,0x6,0xc0,0xc0,0xc0,0x50,0x6c,0,0x16,
+0x6,0x3,0x2,0x41,0x60,0xd8,0,0,0xc,0x6,
+0x4,0x86,0x60,0xc0,0,0,0,0,0,0,
+0,0,0xc0,0,0,0,0,0,0,0,
+0,0,0,0,0x66,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,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,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,0x8,0,0,0,0x81,0x80,0,0,0x4,
+0x10,0,0,0,0,0,0,0x4,0x3c,0x8,
+0xf,0x7,0x80,0xc1,0xf0,0x70,0xfc,0x3c,0x1c,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,0x3,0x84,0x1,0xc0,
+0,0,0x30,0,0x30,0,0,0x60,0,0x3c,
+0,0xc0,0x4,0x2,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x80,0x1,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,0x18,0,0x6,0x7,0,0xc0,0,0,
+0,0,0x4,0,0,0x8,0x4,0x7,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,0x38,0x30,0x6,0x2,0x3,
+0x40,0x1,0x20,0,0,0x30,0x3,0x2,0,0x3,
+0,0x60,0x20,0,0x18,0xd,0xc,0x1,0x81,0,
+0xd0,0,0,0,0x18,0x3,0x2,0,0,0x30,
+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,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,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,0x8,0x9,0x2,0x81,0xe2,0x40,0,0x20,0x8,
+0x8,0x4,0,0,0,0,0,0x8,0x42,0x18,
+0x10,0x88,0x41,0x41,0,0x80,0x84,0x42,0x22,0,
+0,0,0,0,0,0x70,0x1c,0x1c,0x1f,0x83,
+0xaf,0xc3,0xf9,0xfc,0x74,0xe7,0x1f,0x7,0xdd,0xcf,
+0x87,0x1f,0x9c,0x78,0x7e,0x1e,0x3f,0x7,0x47,0xf7,
+0x3b,0x8f,0xc7,0xe7,0x3b,0x9f,0x82,0x2,0,0x40,
+0x20,0,0xc,0,0x10,0,0,0x20,0,0x40,
+0,0x40,0x4,0x2,0xc,0x3,0x80,0,0,0,
+0,0,0,0,0x2,0,0,0,0,0,
+0,0,0x1,0,0x80,0x80,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,0x2,0x1,0x80,0x3,
+0xb8,0x20,0x3c,0x36,0x1e,0xc,0,0,0,0,
+0xf0,0,0x24,0,0x9,0,0x83,0,0,0xfc,
+0,0,0xc,0x6,0,0x18,0x2c,0x10,0x84,0,
+0x38,0x1c,0xe,0x7,0x3,0x81,0xc0,0xfc,0x3a,0x7f,
+0x3f,0x9f,0xcf,0xe3,0xe1,0xf0,0xf8,0x7c,0xfc,0x73,
+0x8f,0x7,0x83,0xc1,0xe0,0xf0,0,0x3d,0x73,0xb9,
+0xdc,0xee,0x73,0xb9,0xc0,0x44,0xc,0x18,0x5,0x5,
+0x83,0x60,0xc0,0,0,0xc,0xc,0x5,0x6,0xc0,
+0xc1,0x80,0x50,0x6c,0x68,0x16,0x3,0x6,0x2,0x81,
+0x61,0x98,0,0,0x6,0xc,0x5,0x6,0xc0,0xc3,
+0,0x6c,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,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,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,0x8,0x9,0x2,0x82,0x22,0x40,0x70,0x20,0x8,
+0x8,0x4,0x1,0,0,0,0,0x8,0x42,0x28,
+0x10,0x80,0x41,0x41,0x1,0,0x4,0x42,0x21,0,
+0,0,0x30,0x1,0x80,0x88,0x22,0x4,0x8,0x44,
+0x64,0x21,0x8,0x84,0x8c,0x42,0x4,0x1,0x8,0x82,
+0x3,0x19,0x88,0x84,0x21,0x21,0x10,0x88,0xc4,0x92,
+0x11,0x4,0x82,0x42,0x11,0x10,0x82,0x2,0,0x40,
+0x50,0,0,0,0x10,0,0,0x20,0,0x40,
+0,0x40,0,0,0x4,0,0x80,0,0,0,
+0,0,0,0,0x2,0,0,0,0,0,
+0,0,0x1,0,0x80,0x80,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,0x2,0x2,0x40,0x1,
+0x10,0x20,0x44,0,0x21,0x2,0,0,0,0x1,
+0x8,0x78,0x24,0x4,0x1,0x3,0,0,0x1,0x28,
+0,0,0x4,0x9,0,0x8,0x44,0x23,0x8,0,
+0x8,0x4,0x2,0x1,0,0x80,0x40,0x64,0x46,0x21,
+0x10,0x88,0x44,0x20,0x80,0x40,0x20,0x10,0x42,0x31,
+0x10,0x88,0x44,0x22,0x11,0x8,0x82,0x42,0x21,0x10,
+0x88,0x44,0x21,0x10,0x80,0x44,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x4,0,0,0,0,0,
+0,0,0x30,0,0,0,0,0,0,0x1,
+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,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,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,0x8,0x9,0x2,0x82,0x1,0x98,0x90,0x20,0x10,
+0x4,0x1f,0x1,0,0,0,0,0x10,0x42,0x8,
+0,0x80,0x42,0x41,0x1,0,0x8,0x42,0x21,0x6,
+0x3,0,0xc0,0,0x60,0x88,0x42,0xa,0x8,0x48,
+0x24,0x11,0x8,0x85,0x4,0x42,0x4,0x1,0x9,0x2,
+0x2,0xb9,0x49,0x2,0x21,0x40,0x90,0x88,0x44,0x92,
+0x11,0x4,0x92,0x24,0x11,0x11,0x2,0x1,0,0x40,
+0x50,0,0,0x1e,0x17,0x3,0xa3,0xa0,0xe1,0xf8,
+0x76,0x5c,0x1c,0x1f,0x4,0xe0,0x86,0xdb,0x70,0x78,
+0xdc,0x1d,0x99,0x87,0xc7,0xc6,0x33,0x9d,0xc7,0x77,
+0x73,0x9f,0x1,0,0x80,0x80,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,0x4,0x7,0x82,0x5,0xa1,
+0x10,0x20,0x40,0,0x4c,0x8e,0x2,0x20,0,0x2,
+0xe4,0,0x18,0x4,0x2,0,0x80,0x6,0x31,0x28,
+0,0,0x4,0x9,0x11,0x8,0x84,0x40,0x90,0x10,
+0x14,0xa,0x5,0x2,0x81,0x40,0xa0,0xa0,0x82,0x24,
+0x12,0x9,0x4,0x80,0x80,0x40,0x20,0x10,0x41,0x29,
+0x20,0x50,0x28,0x14,0xa,0x4,0x44,0x85,0x21,0x10,
+0x88,0x44,0x21,0x10,0xf8,0x44,0x3c,0x1e,0xf,0x7,
+0x83,0xc1,0xe1,0xd8,0x3a,0x1c,0xe,0x7,0x3,0x83,
+0x81,0xc0,0xe0,0x70,0x3e,0x6e,0xf,0x7,0x83,0xc1,
+0xe0,0xf0,0x30,0x3d,0x63,0x31,0x98,0xcc,0x67,0x39,
+0x71,0xce,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,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,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,0x8,0x9,0x7,0xc3,0,0x60,0x80,0x20,0x10,
+0x4,0x4,0x1,0,0,0,0,0x10,0x42,0x8,
+0x1,0x3,0x82,0x41,0xe1,0x70,0x8,0x3c,0x23,0x6,
+0x3,0x3,0x3,0xf8,0x18,0x8,0x4e,0xa,0x8,0x48,
+0x4,0x11,0x20,0x91,0,0x42,0x4,0x1,0xa,0x2,
+0x2,0xa9,0x49,0x2,0x21,0x40,0x90,0x88,0,0x82,
+0x10,0x88,0x92,0x24,0xa,0x2,0x2,0x1,0,0x40,
+0x88,0,0,0x21,0x18,0x84,0x64,0x61,0x10,0x40,
+0x8c,0x62,0x4,0x1,0x4,0x80,0x83,0x69,0x88,0x84,
+0x62,0x23,0xa,0x48,0x42,0x2,0x11,0x8,0x82,0x22,
+0x21,0x11,0x1,0,0x80,0x80,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,0x8,0x82,0x2,0x40,
+0xa0,0x20,0xf0,0,0x52,0x8b,0x4,0x47,0xf0,0x2,
+0x94,0,0,0x3f,0x84,0x4,0x80,0x2,0x11,0x28,
+0,0,0x4,0x6,0x8,0x88,0x84,0x44,0x90,0,
+0x14,0xa,0x5,0x2,0x81,0x40,0xa0,0xa4,0x80,0x24,
+0x12,0x9,0x4,0x80,0x80,0x40,0x20,0x10,0x41,0x29,
+0x20,0x50,0x28,0x14,0xa,0x4,0x28,0x89,0x21,0x10,
+0x88,0x44,0x20,0xa0,0x84,0x58,0x42,0x21,0x10,0x88,
+0x44,0x22,0x12,0x64,0x46,0x22,0x11,0x8,0x84,0x40,
+0x80,0x40,0x20,0x10,0x42,0x31,0x10,0x88,0x44,0x22,
+0x11,0x8,0,0x46,0x21,0x10,0x88,0x44,0x22,0x11,
+0x88,0x84,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,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,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,0x8,0,0x2,0x80,0xc0,0xc0,0x80,0,0x10,
+0x4,0xa,0xf,0xe0,0x3,0xf0,0,0x20,0x42,0x8,
+0x2,0,0x44,0x40,0x11,0x88,0x8,0x42,0x1d,0,
+0,0x4,0,0,0x4,0x10,0x52,0x11,0xf,0x88,
+0x4,0x11,0xe0,0xf1,0,0x7e,0x4,0x1,0xe,0x2,
+0x2,0x49,0x29,0x2,0x21,0x40,0x91,0x7,0x80,0x82,
+0x10,0x88,0xaa,0x18,0xa,0x4,0x2,0,0x80,0x40,
+0x88,0,0,0x1,0x10,0x48,0x28,0x22,0x8,0x41,
+0x4,0x42,0x4,0x1,0x5,0,0x82,0x49,0x9,0x2,
+0x41,0x41,0xc,0x8,0x2,0x2,0x11,0x8,0x92,0x14,
+0x21,0x2,0x2,0,0x80,0x40,0xc8,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,0x8,0x7,0x84,0x21,
+0xf0,0x20,0x88,0,0x50,0x80,0x8,0x80,0x13,0xf2,
+0xe4,0,0,0x4,0xf,0x3,0,0x2,0x10,0xe8,
+0x30,0,0xe,0,0x4,0x5d,0x1e,0x9b,0x24,0,
+0x22,0x11,0x8,0x84,0x42,0x21,0x11,0x3c,0x80,0x3c,
+0x1e,0xf,0x7,0x80,0x80,0x40,0x20,0x10,0xf1,0x25,
+0x20,0x50,0x28,0x14,0xa,0x4,0x10,0x91,0x21,0x10,
+0x88,0x44,0x20,0xa0,0x84,0x44,0x2,0x1,0,0x80,
+0x40,0x20,0x10,0x44,0x82,0x41,0x20,0x90,0x48,0x20,
+0x80,0x40,0x20,0x10,0x81,0x21,0x20,0x50,0x28,0x14,
+0xa,0x5,0xfe,0x89,0x21,0x10,0x88,0x44,0x22,0x11,
+0x4,0x84,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,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,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,0x8,0,0x7,0xc0,0x23,0x31,0x50,0,0x10,
+0x4,0x11,0x1,0,0,0,0,0x20,0x42,0x8,
+0x4,0,0x44,0x40,0x11,0x8,0x10,0x42,0x1,0,
+0,0x3,0x3,0xf8,0x18,0x20,0x52,0x1f,0x8,0x48,
+0x4,0x11,0x20,0x91,0x1e,0x42,0x4,0x11,0x9,0x2,
+0x12,0x49,0x29,0x2,0x3e,0x40,0x9e,0,0x40,0x82,
+0x10,0x50,0xaa,0x24,0x4,0x4,0x2,0,0x80,0x40,
+0,0,0,0x1f,0x10,0x48,0x8,0x23,0xf8,0x41,
+0x4,0x42,0x4,0x1,0x6,0,0x82,0x49,0x9,0x2,
+0x41,0x41,0x8,0x7,0x82,0x2,0x10,0x90,0x92,0x8,
+0x12,0x4,0x1,0,0x80,0x81,0x30,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,0x4,0x8,0x82,0x4,0x20,
+0x40,0,0x44,0,0x52,0x8f,0x19,0x80,0x10,0x2,
+0xa4,0,0,0x4,0,0,0,0x2,0x10,0x28,
+0x30,0,0,0xf,0x6,0x62,0x31,0x20,0x4c,0x10,
+0x3e,0x1f,0xf,0x87,0xc3,0xe1,0xf1,0xe4,0x80,0x24,
+0x12,0x9,0x4,0x80,0x80,0x40,0x20,0x10,0x41,0x25,
+0x20,0x50,0x28,0x14,0xa,0x4,0x28,0xa1,0x21,0x10,
+0x88,0x44,0x20,0x40,0x84,0x42,0x3e,0x1f,0xf,0x87,
+0xc3,0xe1,0xf1,0xfc,0x80,0x7f,0x3f,0x9f,0xcf,0xe0,
+0x80,0x40,0x20,0x10,0x81,0x21,0x20,0x50,0x28,0x14,
+0xa,0x4,0,0x91,0x21,0x10,0x88,0x44,0x21,0x21,
+0x4,0x48,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,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,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,0x2,0x82,0x20,0x49,0x20,0,0x10,
+0x4,0,0x1,0,0,0,0,0x40,0x42,0x8,
+0x8,0,0x47,0xe0,0x11,0x8,0x10,0x42,0x1,0,
+0,0,0xc0,0,0x60,0x20,0x4f,0x20,0x88,0x48,
+0x4,0x11,0x8,0x81,0x4,0x42,0x4,0x11,0x8,0x82,
+0x12,0x9,0x19,0x2,0x20,0x40,0x91,0x8,0x40,0x82,
+0x10,0x50,0x44,0x24,0x4,0x8,0x82,0,0x40,0x40,
+0,0,0,0x21,0x10,0x48,0x8,0x22,0,0x41,
+0x4,0x42,0x4,0x1,0x5,0,0x82,0x49,0x9,0x2,
+0x41,0x41,0x8,0,0x42,0x2,0x10,0x90,0x54,0x14,
+0x12,0x8,0x1,0,0x80,0x80,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,0x4,0x7,0x2,0x2,0x41,
+0xf0,0x20,0x3c,0,0x4c,0x80,0x8,0x80,0,0x2,
+0x94,0,0,0,0,0,0,0x2,0x10,0x28,
+0,0,0,0,0x4,0x42,0x51,0,0x54,0x30,
+0x41,0x20,0x90,0x48,0x24,0x12,0xa,0x20,0x80,0x21,
+0x10,0x88,0x44,0x20,0x80,0x40,0x20,0x10,0x41,0x23,
+0x20,0x50,0x28,0x14,0xa,0x4,0x44,0xc1,0x21,0x10,
+0x88,0x44,0x20,0x40,0xf8,0x42,0x42,0x21,0x10,0x88,
+0x44,0x22,0x12,0x20,0x80,0x40,0x20,0x10,0x8,0,
+0x80,0x40,0x20,0x10,0x81,0x21,0x20,0x50,0x28,0x14,
+0xa,0x4,0x30,0xa1,0x21,0x10,0x88,0x44,0x21,0x21,
+0x4,0x48,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,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,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,0x2,0x83,0xc0,0x49,0x30,0,0x10,
+0x4,0,0x1,0x1,0x80,0,0x60,0x40,0x42,0x8,
+0x10,0x88,0x40,0x42,0x10,0x88,0x10,0x42,0x2,0x6,
+0x3,0,0x30,0x1,0x80,0,0x40,0x20,0x88,0x44,
+0x24,0x21,0x8,0x80,0x84,0x42,0x4,0x11,0x8,0x82,
+0x12,0x9,0x18,0x84,0x20,0x21,0x10,0x8c,0x40,0x82,
+0x10,0x20,0x44,0x42,0x4,0x10,0x82,0,0x40,0x40,
+0,0,0,0x23,0x18,0x84,0x24,0x61,0x8,0x40,
+0x8c,0x42,0x4,0x1,0x4,0x80,0x82,0x49,0x8,0x84,
+0x62,0x23,0x8,0x8,0x42,0x22,0x30,0x60,0x6c,0x22,
+0xc,0x11,0x1,0,0x80,0x80,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,0x4,0x2,0x4,0x25,0xa0,
+0x40,0x20,0x8,0,0x21,0,0x4,0x40,0,0x1,
+0x8,0,0,0x3f,0x80,0,0,0x2,0x30,0x28,
+0,0,0,0,0x8,0x84,0x92,0x8,0xa4,0x40,
+0x41,0x20,0x90,0x48,0x24,0x12,0xa,0x24,0x42,0x21,
+0x10,0x88,0x44,0x20,0x80,0x40,0x20,0x10,0x42,0x23,
+0x10,0x88,0x44,0x22,0x11,0x8,0x82,0xc2,0x21,0x10,
+0x88,0x44,0x20,0x40,0x80,0x52,0x46,0x23,0x11,0x88,
+0xc4,0x62,0x32,0x64,0x42,0x21,0x10,0x88,0x44,0x20,
+0x80,0x40,0x20,0x10,0x42,0x21,0x10,0x88,0x44,0x22,
+0x11,0x8,0x30,0x42,0x23,0x11,0x88,0xc4,0x60,0xc1,
+0x88,0x30,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,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,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,0x8,0,0x2,0x80,0x80,0x30,0xc8,0,0x8,
+0x8,0,0,0x1,0x80,0,0x60,0x80,0x3c,0x3e,
+0x1f,0x87,0x80,0xe1,0xe0,0x70,0x10,0x3c,0x1c,0x6,
+0x3,0,0,0,0,0x20,0x20,0x7b,0xdf,0x83,
+0xcf,0xc3,0xf9,0xe0,0x78,0xe7,0x1f,0xe,0x1c,0x6f,
+0xf7,0x1f,0x88,0x78,0x78,0x1e,0x38,0x4b,0x83,0xe1,
+0xe0,0x20,0x44,0xe7,0x1f,0x1f,0x82,0,0x20,0x40,
+0,0,0,0x1d,0xb7,0x3,0xc3,0xb0,0xf1,0xf0,
+0x74,0xe7,0x1f,0x1,0xc,0xe3,0xe7,0x6f,0x9c,0x78,
+0x5c,0x1d,0x1e,0xf,0x81,0xc1,0xd8,0x60,0x6c,0x77,
+0x4,0x1f,0x1,0,0x80,0x80,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,0x4,0x2,0xf,0xc0,0,
+0xe0,0x20,0x88,0,0x1e,0,0x2,0x20,0,0,
+0xf0,0,0,0,0,0,0,0x3,0xd8,0x28,
+0,0,0,0,0x11,0x8,0xf4,0x11,0x3e,0x40,
+0xf7,0xfb,0xfd,0xfe,0xff,0x7f,0xbf,0x7c,0x3c,0x7f,
+0x3f,0x9f,0xcf,0xe3,0xe1,0xf0,0xf8,0x7c,0xfc,0x71,
+0xf,0x7,0x83,0xc1,0xe0,0xf0,0x1,0x3c,0x1e,0xf,
+0x7,0x83,0xc1,0xf1,0xc0,0xcc,0x3b,0x1d,0x8e,0xc7,
+0x63,0xb1,0xd9,0xb8,0x3c,0x1e,0xf,0x7,0x83,0xc3,
+0xe1,0xf0,0xf8,0x7c,0x3c,0x73,0x8f,0x7,0x83,0xc1,
+0xe0,0xf0,0,0xbc,0x1d,0x8e,0xc7,0x63,0xb0,0x41,
+0x70,0x10,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,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,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,0x80,0,0,0,0x8,
+0x8,0,0,0x3,0,0,0,0x80,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x6,0,0,0,0,0,0x1c,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x18,0x80,0,0,0,
+0,0,0,0,0,0,0x2,0,0x20,0x40,
+0,0,0,0,0,0,0,0,0,0,
+0x4,0,0,0x1,0,0,0,0,0,0,
+0x40,0x1,0,0,0,0,0,0,0,0,
+0x8,0,0x1,0,0x80,0x80,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,0x4,0,0,0,0,
+0,0x20,0xf0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x2,0,0x6c,
+0,0x10,0,0,0,0,0x10,0x38,0x4,0x44,
+0,0,0,0,0,0,0,0,0x10,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,0x10,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x81,
+0,0x20,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,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,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,0x80,0,0,0,0x4,
+0x10,0,0,0x2,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x2f,0,0,0,0,
+0,0,0,0,0,0,0x3,0x80,0x1,0xc0,
+0,0,0,0,0,0,0,0,0,0,
+0x8,0,0,0x2,0,0,0,0,0,0,
+0x40,0x1,0,0,0,0,0,0,0,0,
+0x8,0,0,0x80,0x81,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,0x4,0,0,0,0,
+0,0x20,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x2,0,0,
+0,0x8,0,0,0,0,0,0,0,0x38,
+0,0,0,0,0,0,0,0,0x8,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,0x8,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x81,
+0,0x20,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,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,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x1,0xff,0,0,0,0,0,0,0,0,
+0xf0,0,0,0x1c,0,0,0,0,0,0,
+0xf0,0x7,0x80,0,0,0,0,0,0,0,
+0x3c,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,0x2,0,0,
+0,0x38,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x38,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,0x38,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x3,0xc3,
+0xc0,0xf0,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,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,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+};
+
+static WORD Courier14_ch_ofst[225] = {
+0,9,18,27,36,45,54,63,72,81,
+90,99,108,117,126,135,144,153,162,171,
+180,189,198,207,216,225,234,243,252,261,
+270,279,288,297,306,315,324,333,342,351,
+360,369,378,387,396,405,414,423,432,441,
+450,459,468,477,486,495,504,513,522,531,
+540,549,558,567,576,585,594,603,612,621,
+630,639,648,657,666,675,684,693,702,711,
+720,729,738,747,756,765,774,783,792,801,
+810,819,828,837,846,855,864,873,882,891,
+900,909,918,927,936,945,954,963,972,981,
+990,999,1008,1017,1026,1035,1044,1053,1062,1071,
+1080,1089,1098,1107,1116,1125,1134,1143,1152,1161,
+1170,1179,1188,1197,1206,1215,1224,1233,1242,1251,
+1260,1269,1278,1287,1296,1305,1314,1323,1332,1341,
+1350,1359,1368,1377,1386,1395,1404,1413,1422,1431,
+1440,1449,1458,1467,1476,1485,1494,1503,1512,1521,
+1530,1539,1548,1557,1566,1575,1584,1593,1602,1611,
+1620,1629,1638,1647,1656,1665,1674,1683,1692,1701,
+1710,1719,1728,1737,1746,1755,1764,1773,1782,1791,
+1800,1809,1818,1827,1836,1845,1854,1863,1872,1881,
+1890,1899,1908,1917,1926,1935,1944,1953,1962,1971,
+1980,1989,1998,2007,2016,
+};
+
+static struct font_hdr Courier14_font = {
+STPROP, 14, "-Adobe-Courier-M-R-N--14-140-75", 32, 255,
+16, 13, 8, 3, 3,
+10, 9, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Courier14_ch_ofst, Courier14_data,
+420, 16,
+NULL,
+0, 0,   /* x/y offset */
+19,        /* lineHeight */
+13,	   /* psHeight */
+};
+
+MgFont *mgCourier14Font()
+{
+return &Courier14_font;
+}
+
+MgFont *mgMediumFixedFont()
+{
+return &Courier14_font;
+}
+
diff --git a/lib/font/mgCourier18.c b/lib/font/mgCourier18.c
new file mode 100644
index 0000000..b625799
--- /dev/null
+++ b/lib/font/mgCourier18.c
@@ -0,0 +1,875 @@
+
+/* Courier18.c - compiled data for font -Adobe-Courier-M-R-N--18-180-75 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/courR18.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Courier18_data[8132] = {
+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,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,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,0,0,0,0,
+0x10,0,0x40,0x10,0,0,0,0x18,0,0,
+0,0x10,0,0x40,0x30,0,0,0x80,0x4,0x1,
+0,0,0,0,0,0x20,0x1,0,0x40,0,
+0,0,0,0,0x2,0,0x8,0x6,0,0,
+0x2,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,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,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,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,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,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,0x8,0,
+0x80,0x28,0xc,0x81,0xb0,0x24,0,0,0,0x8,
+0,0x80,0x48,0x19,0x80,0x40,0x8,0x2,0x80,0xd8,
+0,0x1,0x90,0x10,0x2,0,0xa0,0x19,0x6,0xc0,
+0,0,0x1,0,0x10,0x9,0x3,0x30,0x4,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,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,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,
+0x4,0x80,0x40,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x4,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,0x2,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,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,
+0x2,0,0x40,0x1c,0,0,0x4,0x1,0,0x44,
+0x13,0,0,0x24,0,0,0,0x4,0x1,0,
+0x84,0,0,0x20,0x10,0x4,0x40,0,0,0x2,
+0x60,0x8,0x4,0x1,0x10,0x26,0,0,0,0,
+0,0x80,0x20,0x10,0x80,0,0x8,0,0,0,
+0,0,0,0,0,0,0,0x18,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,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x1,0x80,0x6c,0x4,0x80,
+0x40,0x70,0,0,0x60,0x1,0x2,0,0x10,0,
+0,0,0,0,0,0x4,0xe,0x1,0x80,0x38,
+0xf,0,0x30,0x7e,0x1,0xe1,0xfe,0xe,0x1,0xc0,
+0,0,0,0,0,0,0,0,0xf,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,0x3,0x82,0,0x38,0x1,
+0,0,0x8,0,0x1,0x80,0,0,0x18,0,
+0,0xf0,0,0x60,0,0,0,0x30,0x3,0xc0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x1,
+0x80,0x40,0x30,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,0x10,0,0,0,0,0x1,0,
+0x7c,0,0,0,0,0,0,0,0,0,
+0,0,0xe,0,0,0x38,0x7,0,0x20,0,
+0x7,0xe0,0,0,0,0x80,0,0,0xe,0x1,
+0xc0,0x22,0,0,0,0,0,0,0,0,
+0,0x18,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,0x70,0x10,0,
+0x40,0x30,0,0,0,0x24,0,0,0,0x10,
+0,0x40,0x30,0,0x1,0,0x4,0x1,0,0,
+0x39,0x80,0,0x40,0,0x80,0xc0,0,0,0,
+0,0,0x1,0,0x8,0x2,0,0,0x2,0x18,
+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,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,0x1,0x80,0x6c,0x4,0x81,0xe8,0x88,
+0,0,0x60,0x2,0x1,0,0x10,0,0,0,
+0,0,0,0x8,0x11,0x6,0x80,0x44,0x10,0x80,
+0x50,0x40,0x2,0x1,0x2,0x11,0x2,0x20,0,0,
+0,0,0,0,0,0xf8,0x10,0x87,0x81,0xfc,
+0x7,0xa7,0xe0,0xff,0x1f,0xe0,0x7a,0x71,0xc7,0xf0,
+0x3f,0x79,0xe7,0xc1,0xc1,0xdc,0xf0,0x70,0x7f,0x1,
+0xc1,0xfc,0x7,0x47,0xfd,0xe7,0xbc,0x7f,0x8f,0x71,
+0xce,0x38,0xfe,0x2,0x1,0,0x8,0x2,0x80,0,
+0x4,0,0,0x80,0,0,0x8,0,0x1,0,
+0,0x20,0,0x80,0x8,0x10,0,0x40,0,0,
+0,0,0,0,0,0,0,0,0x80,0,
+0,0,0,0,0,0,0,0x2,0,0x40,
+0x8,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,0x10,0x7,0,0,0xe3,0x81,0,0x84,0x1b,
+0x3,0xc0,0x70,0,0,0,0,0x7,0xc0,0,
+0x11,0,0,0x44,0x8,0x80,0x40,0,0x9,0x40,
+0,0,0x3,0x80,0x78,0,0x2,0x4,0x40,0x82,
+0x10,0,0x3c,0x7,0x80,0xf0,0x1e,0x3,0xc0,0xf8,
+0xf,0xf0,0x7a,0x7f,0x8f,0xf1,0xfe,0x3f,0xc3,0xf8,
+0x7f,0xf,0xe1,0xfc,0x7e,0xe,0x78,0x38,0x7,0,
+0xe0,0x1c,0x3,0x80,0,0xe,0x3e,0x7b,0xcf,0x79,
+0xef,0x3c,0xe3,0x9c,0,0x88,0x8,0,0x80,0x48,
+0xc,0x81,0xb0,0x24,0,0,0,0x8,0,0x80,
+0x48,0x19,0x80,0x80,0x8,0x2,0x80,0xd8,0x46,0x1,
+0x90,0x20,0x1,0x1,0x20,0x32,0xc,0xc0,0,0,
+0,0x80,0x10,0x5,0x1,0xb0,0x4,0x8,0,0xd8,
+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,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,0x1,0x80,0x6c,0x4,0x82,0x18,0x88,0x3,0x80,
+0x60,0x2,0x1,0,0x10,0x2,0,0,0,0,
+0,0x8,0x20,0x80,0x80,0x82,0,0x40,0x50,0x40,
+0x4,0,0x4,0x20,0x84,0x10,0,0,0,0xc,
+0,0x30,0x1,0xc,0x20,0x80,0x80,0x82,0x18,0x62,
+0x10,0x41,0x8,0x21,0x86,0x20,0x80,0x80,0x4,0x20,
+0x81,0,0xc1,0x8c,0x21,0x8c,0x20,0x86,0x30,0x82,
+0x8,0xc4,0x44,0x81,0x10,0x12,0x2,0x20,0x84,0x10,
+0x82,0x2,0x1,0,0x8,0x4,0x40,0,0x2,0,
+0,0x80,0,0,0x8,0,0x2,0,0,0x20,
+0,0x80,0x8,0x10,0,0x40,0,0,0,0,
+0,0,0,0,0,0,0x80,0,0,0,
+0,0,0,0,0,0x2,0,0x40,0x8,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,0x10,
+0x8,0x80,0,0x41,0x1,0,0x84,0,0xc,0x30,
+0x8,0,0,0,0,0x18,0x30,0xf8,0x11,0,
+0x80,0x4,0,0x80,0x80,0,0x11,0x40,0,0,
+0,0x80,0x84,0,0x2,0x8,0x41,0xc,0x20,0,
+0x4,0,0x80,0x10,0x2,0,0x40,0x8,0x3,0x11,
+0x86,0x20,0x84,0x10,0x82,0x10,0x40,0x40,0x8,0x1,
+0,0x20,0x21,0x6,0x10,0xc6,0x18,0xc3,0x18,0x63,
+0xc,0x62,0x2,0x31,0x48,0x11,0x2,0x20,0x44,0x8,
+0x41,0x8,0x1,0x8,0x4,0x1,0,0x84,0x13,0,
+0,0x18,0,0,0,0x4,0x1,0,0x84,0,
+0,0x40,0x10,0x4,0x40,0,0x1a,0x2,0x60,0x10,
+0x2,0x2,0x10,0x4c,0,0,0x60,0,0,0x40,
+0x20,0x8,0x80,0,0x8,0x8,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,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,0x1,
+0x80,0x48,0x4,0x82,0x8,0x88,0x4,0x40,0x20,0x4,
+0,0x80,0xfe,0x2,0,0,0,0,0,0x10,
+0x20,0x80,0x80,0x82,0,0x40,0x90,0x40,0x4,0,
+0x4,0x20,0x84,0x10,0,0,0,0x30,0,0xc,
+0x1,0x4,0x20,0x81,0x40,0x82,0x10,0x22,0x8,0x41,
+0x8,0x21,0x2,0x20,0x80,0x80,0x4,0x21,0x1,0,
+0xa2,0x8a,0x21,0x4,0x20,0x44,0x10,0x82,0x10,0x44,
+0x44,0x81,0x10,0x12,0x22,0x11,0x2,0x20,0x84,0x2,
+0,0x80,0x8,0x8,0x20,0,0,0,0,0x80,
+0,0,0x8,0,0x2,0,0,0x20,0,0,
+0,0x10,0,0x40,0,0,0,0,0,0,
+0,0,0,0,0x80,0,0,0,0,0,
+0,0,0,0x2,0,0x40,0x8,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,0x1,0x80,0x3c,0x8,0x2,
+0x10,0x22,0x1,0,0x80,0,0x9,0xd0,0x78,0,
+0,0,0,0x17,0x90,0,0x11,0,0x80,0x8,
+0x3,0,0,0,0x11,0x40,0,0,0,0x80,
+0x84,0,0x2,0x10,0x42,0x2,0x40,0x30,0xa,0x1,
+0x40,0x28,0x5,0,0xa0,0x14,0x5,0x11,0x2,0x20,
+0x84,0x10,0x82,0x10,0x40,0x40,0x8,0x1,0,0x20,
+0x20,0x85,0x10,0x82,0x10,0x42,0x8,0x41,0x8,0x21,
+0x4,0x20,0x88,0x11,0x2,0x20,0x44,0x8,0x22,0xf,
+0xc1,0x8,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x21,0,0,0,0,0,
+0,0,0,0,0x60,0,0,0,0,0,
+0,0,0,0x8,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,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,0x1,0x80,0x48,
+0x3f,0xe2,0,0x71,0x84,0,0x20,0x4,0,0x80,
+0x38,0x2,0,0,0,0,0,0x10,0x20,0x80,
+0x80,0x2,0,0x80,0x90,0x5c,0x8,0,0x8,0x11,
+0x4,0x10,0x18,0x3,0,0xc0,0,0x3,0,0x4,
+0x23,0x81,0x40,0x82,0x20,0x2,0x8,0x41,0x8,0x22,
+0,0x20,0x80,0x80,0x4,0x22,0x1,0,0xa2,0x8a,
+0x22,0x2,0x20,0x48,0x8,0x82,0x10,0x4,0x44,0x81,
+0x8,0x22,0x22,0x11,0x2,0x20,0x8,0x2,0,0x80,
+0x8,0,0,0,0,0x3,0xc0,0xbc,0xf,0x41,
+0xe8,0x3c,0xf,0xe0,0xf6,0x2f,0x3,0x80,0xfc,0x13,
+0xc0,0x41,0xb3,0x1b,0xc0,0xf0,0x6f,0x3,0xd9,0xdc,
+0xf,0x43,0xf8,0xc3,0x1c,0x73,0x8e,0x73,0x8e,0x38,
+0xfe,0x2,0,0x40,0x8,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,0x1,0x80,0x44,0x8,0x1,0xe0,0x22,
+0x1,0,0xe0,0,0x12,0x48,0x88,0x2,0x20,0,
+0,0x24,0x48,0,0xe,0,0x80,0x10,0,0x80,
+0,0xc3,0x11,0x40,0,0,0,0x80,0x84,0x22,
+0x2,0x10,0x42,0x22,0x40,0x30,0xa,0x1,0x40,0x28,
+0x5,0,0xa0,0x14,0x5,0x2,0,0x20,0x84,0x10,
+0x82,0x10,0x40,0x40,0x8,0x1,0,0x20,0x20,0x85,
+0x11,0x1,0x20,0x24,0x4,0x80,0x90,0x10,0x88,0x41,
+0x48,0x11,0x2,0x20,0x44,0x8,0x22,0x8,0x21,0x10,
+0x1e,0x3,0xc0,0x78,0xf,0x1,0xe0,0x3c,0x1c,0x60,
+0xf4,0x1e,0x3,0xc0,0x78,0xf,0x1,0xc0,0x38,0x7,
+0,0xe0,0x1,0xd,0xe0,0x78,0xf,0x1,0xe0,0x3c,
+0x7,0x80,0,0x1e,0x8c,0x31,0x86,0x30,0xc6,0x18,
+0xe3,0x8b,0xc3,0x8e,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,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,0x1,0x80,0,0x9,0x1,
+0xc0,0xe,0x4,0,0,0x4,0,0x80,0x28,0x2,
+0,0,0,0,0,0x20,0x20,0x80,0x80,0x4,
+0x7,0x1,0x10,0x62,0xb,0x80,0x8,0xe,0x2,0x30,
+0x18,0x3,0x3,0,0xff,0x80,0xc0,0x8,0x24,0x82,
+0x20,0x84,0x20,0x2,0x8,0x48,0x9,0x2,0,0x20,
+0x80,0x80,0x4,0x24,0x1,0,0x94,0x89,0x22,0x2,
+0x20,0x48,0x8,0x84,0x8,0,0x40,0x81,0x8,0x22,
+0x22,0xa,0x1,0x40,0x8,0x2,0,0x40,0x8,0,
+0,0,0,0x4,0x20,0xc2,0x10,0xc2,0x18,0x42,
+0x2,0x1,0xc,0x30,0x80,0x80,0x4,0x11,0,0x40,
+0xcc,0x8c,0x21,0x8,0x30,0x84,0x30,0x62,0x10,0xc0,
+0x80,0x41,0x8,0x21,0x4,0x21,0x4,0x10,0x82,0x2,
+0,0x40,0x8,0xc,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,0x84,0x4,0x2,0x10,0x14,0x1,0x1,
+0x18,0,0x14,0x8,0x98,0xc,0xc7,0xfc,0,0x24,
+0x48,0,0,0xf,0xf8,0x20,0x8,0x80,0,0x41,
+0x9,0x40,0x60,0,0,0x80,0x84,0x19,0x8f,0xa5,
+0xf5,0x9c,0x90,0,0x11,0x2,0x20,0x44,0x8,0x81,
+0x10,0x22,0x9,0x22,0,0x24,0x4,0x80,0x90,0x12,
+0,0x40,0x8,0x1,0,0x20,0x20,0x84,0x91,0x1,
+0x20,0x24,0x4,0x80,0x90,0x10,0x50,0x42,0x48,0x11,
+0x2,0x20,0x44,0x8,0x14,0x8,0x11,0x30,0x21,0x4,
+0x20,0x84,0x10,0x82,0x10,0x42,0x22,0x91,0xc,0x21,
+0x4,0x20,0x84,0x10,0x80,0x40,0x8,0x1,0,0x20,
+0x1e,0x86,0x10,0x84,0x10,0x82,0x10,0x42,0x8,0x40,
+0,0x21,0x4,0x10,0x82,0x10,0x42,0x8,0x41,0xc,
+0x21,0x4,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,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,0x1,0x80,0,0x9,0,0x30,0x30,
+0x2,0,0,0x4,0,0x80,0x44,0x3f,0xe0,0,
+0xff,0,0,0x20,0x20,0x80,0x80,0x8,0,0x81,
+0x10,0x1,0xc,0x40,0x8,0x11,0x1,0xd0,0,0,
+0xc,0,0,0,0x30,0x10,0x24,0x82,0x20,0xfc,
+0x20,0x2,0x8,0x78,0xf,0x2,0,0x3f,0x80,0x80,
+0x4,0x2c,0x1,0,0x94,0x89,0x22,0x2,0x20,0x88,
+0x8,0xf8,0x7,0x80,0x40,0x81,0x4,0x41,0x54,0x4,
+0x1,0x40,0x10,0x2,0,0x40,0x8,0,0,0,
+0,0,0x20,0x81,0x20,0x44,0x8,0x81,0x2,0x2,
+0x4,0x20,0x80,0x80,0x4,0x12,0,0x40,0x88,0x88,
+0x22,0x4,0x20,0x48,0x10,0x40,0x10,0x40,0x80,0x41,
+0x4,0x41,0x24,0x12,0x4,0x10,0x84,0xc,0,0x40,
+0x6,0x13,0x20,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,0x80,0x3f,0x2,0x10,0x14,0,0x1,0x4,0,
+0x14,0x8,0xec,0x19,0x80,0x4,0xff,0x27,0x88,0,
+0,0,0x80,0x7c,0x7,0,0,0x41,0x7,0x40,
+0x60,0,0x3,0xe0,0x78,0xc,0xc0,0x4c,0xa,0x41,
+0x30,0x20,0x11,0x2,0x20,0x44,0x8,0x81,0x10,0x22,
+0x9,0xe2,0,0x3c,0x7,0x80,0xf0,0x1e,0,0x40,
+0x8,0x1,0,0x20,0x78,0x84,0x91,0x1,0x20,0x24,
+0x4,0x80,0x90,0x10,0x20,0x44,0x48,0x11,0x2,0x20,
+0x44,0x8,0x14,0x8,0x11,0x8,0x1,0,0x20,0x4,
+0,0x80,0x10,0x2,0x1,0xa,0x4,0x40,0x88,0x11,
+0x2,0x20,0x40,0x40,0x8,0x1,0,0x20,0x21,0x84,
+0x11,0x2,0x20,0x44,0x8,0x81,0x10,0x23,0xfc,0x42,
+0x84,0x10,0x82,0x10,0x42,0x8,0x41,0x8,0x11,0x4,
+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,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,0x80,0,0x9,0,0x8,0xce,0x7,0x40,
+0,0x4,0,0x80,0x44,0x2,0,0,0,0,
+0,0x40,0x20,0x80,0x80,0x10,0,0x42,0x10,0x1,
+0x8,0x20,0x8,0x20,0x80,0x10,0,0,0x3,0,
+0,0,0xc0,0x60,0x24,0x84,0x10,0x82,0x20,0x2,
+0x8,0x48,0x9,0x2,0xf,0x20,0x80,0x81,0x4,0x32,
+0x1,0,0x88,0x88,0xa2,0x2,0x3f,0x8,0x8,0x84,
+0,0x40,0x40,0x81,0x4,0x41,0x54,0xa,0,0x80,
+0x20,0x2,0,0x20,0x8,0,0,0,0,0x7,
+0xe0,0x81,0x20,0x4,0x8,0xff,0x2,0x2,0x4,0x20,
+0x80,0x80,0x4,0x1c,0,0x40,0x88,0x88,0x22,0x4,
+0x20,0x48,0x10,0x40,0xe,0,0x80,0x41,0x4,0x41,
+0x24,0xc,0x2,0x20,0x8,0x2,0,0x40,0x8,0,
+0xc0,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,0x1,0,0x80,
+0x4,0x2,0x10,0x7f,0,0,0xc4,0,0x14,0x8,
+0,0x33,0,0x4,0,0x25,0x8,0,0,0,
+0x80,0,0,0,0,0x41,0x1,0x40,0,0,
+0,0,0,0x6,0x60,0x94,0x12,0x42,0x50,0x20,
+0x20,0x84,0x10,0x82,0x10,0x42,0x8,0x41,0x1f,0x22,
+0,0x24,0x4,0x80,0x90,0x12,0,0x40,0x8,0x1,
+0,0x20,0x20,0x84,0x51,0x1,0x20,0x24,0x4,0x80,
+0x90,0x10,0x50,0x48,0x48,0x11,0x2,0x20,0x44,0x8,
+0x8,0x8,0x21,0x4,0x3f,0x7,0xe0,0xfc,0x1f,0x83,
+0xf0,0x7e,0x1f,0xfa,0,0x7f,0x8f,0xf1,0xfe,0x3f,
+0xc0,0x40,0x8,0x1,0,0x20,0x40,0x84,0x11,0x2,
+0x20,0x44,0x8,0x81,0x10,0x20,0,0x44,0x84,0x10,
+0x82,0x10,0x42,0x8,0x22,0x8,0x10,0x88,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,
+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,
+0x80,0,0x3f,0xc2,0x8,0x11,0x8,0x80,0,0x4,
+0,0x80,0,0x2,0,0,0,0,0,0x40,
+0x20,0x80,0x80,0x20,0,0x43,0xf8,0x1,0x8,0x20,
+0x10,0x20,0x80,0x10,0,0,0,0xc0,0xff,0x83,
+0,0x40,0x23,0xc7,0xf0,0x81,0x20,0x2,0x8,0x41,
+0x8,0x2,0x2,0x20,0x80,0x81,0x4,0x21,0x1,0x4,
+0x88,0x88,0xa2,0x2,0x20,0x8,0x8,0x84,0,0x20,
+0x40,0x81,0x2,0x81,0x54,0x11,0,0x80,0x20,0x2,
+0,0x20,0x8,0,0,0,0,0x8,0x20,0x81,
+0x20,0x4,0x8,0x80,0x2,0x2,0x4,0x20,0x80,0x80,
+0x4,0x12,0,0x40,0x88,0x88,0x22,0x4,0x20,0x48,
+0x10,0x40,0x1,0x80,0x80,0x41,0x2,0x81,0x54,0xc,
+0x2,0x20,0x10,0x2,0,0x40,0x8,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,0x1,0,0x44,0x8,0x1,
+0xe0,0x8,0x1,0,0x38,0,0x12,0x48,0xfc,0x33,
+0,0x4,0,0x24,0x88,0,0,0,0x80,0,
+0,0,0,0x41,0x1,0x40,0,0,0,0,
+0xfc,0x6,0x60,0xa4,0x10,0x82,0x90,0xe0,0x3f,0x87,
+0xf0,0xfe,0x1f,0xc3,0xf8,0x7f,0x11,0x2,0,0x20,
+0x84,0x10,0x82,0x10,0x40,0x40,0x8,0x1,0,0x20,
+0x20,0x84,0x51,0x1,0x20,0x24,0x4,0x80,0x90,0x10,
+0x88,0x50,0x48,0x11,0x2,0x20,0x44,0x8,0x8,0xf,
+0xc1,0x4,0x41,0x8,0x21,0x4,0x20,0x84,0x10,0x82,
+0x21,0x2,0,0x40,0x8,0x1,0,0x20,0,0x40,
+0x8,0x1,0,0x20,0x40,0x84,0x11,0x2,0x20,0x44,
+0x8,0x81,0x10,0x20,0,0x48,0x84,0x10,0x82,0x10,
+0x42,0x8,0x22,0x8,0x10,0x88,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,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,
+0x9,0x3,0x8,0x11,0x8,0x80,0,0x4,0,0x80,
+0,0x2,0,0,0,0,0,0x80,0x20,0x80,
+0x80,0x40,0,0x40,0x10,0x1,0x8,0x20,0x10,0x20,
+0x80,0x20,0,0,0,0x30,0,0xc,0,0,
+0x20,0x8,0x8,0x81,0x10,0x22,0x8,0x41,0x8,0x1,
+0x2,0x20,0x80,0x81,0x4,0x21,0x1,0x4,0x80,0x88,
+0x61,0x4,0x20,0x4,0x10,0x82,0x10,0x20,0x40,0x81,
+0x2,0x81,0x54,0x11,0,0x80,0x42,0x2,0,0x10,
+0x8,0,0,0,0,0x8,0x20,0x81,0x20,0x4,
+0x8,0x80,0x2,0x2,0x4,0x20,0x80,0x80,0x4,0x11,
+0,0x40,0x88,0x88,0x22,0x4,0x20,0x48,0x10,0x40,
+0x10,0x40,0x80,0x41,0x2,0x81,0x54,0x12,0x1,0x40,
+0x22,0x2,0,0x40,0x8,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,0x1,0x80,0x38,0x8,0x42,0x10,0x7f,
+0x1,0,0x8,0,0x9,0x90,0,0x19,0x80,0,
+0,0x14,0x70,0,0,0,0,0,0,0,
+0,0x41,0x1,0x40,0,0,0,0,0,0xc,
+0xc1,0x3e,0x21,0x4,0xf9,0,0x40,0x48,0x9,0x1,
+0x20,0x24,0x4,0x80,0xa1,0x11,0x2,0x20,0x84,0x10,
+0x82,0x10,0x40,0x40,0x8,0x1,0,0x20,0x20,0x84,
+0x30,0x82,0x10,0x42,0x8,0x41,0x8,0x21,0x4,0x20,
+0x88,0x11,0x2,0x20,0x44,0x8,0x8,0x8,0x1,0x4,
+0x41,0x8,0x21,0x4,0x20,0x84,0x10,0x82,0x21,0x2,
+0,0x40,0x8,0x1,0,0x20,0,0x40,0x8,0x1,
+0,0x20,0x40,0x84,0x11,0x2,0x20,0x44,0x8,0x81,
+0x10,0x20,0x60,0x50,0x84,0x10,0x82,0x10,0x42,0x8,
+0x14,0x8,0x10,0x50,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,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,0x1,0x80,0,0x9,0x2,
+0xf0,0x11,0x9,0x80,0,0x4,0,0x80,0,0x2,
+0,0x60,0,0x3,0,0x80,0x11,0,0x80,0x82,
+0x10,0x80,0x10,0xc2,0x4,0x40,0x10,0x11,0,0x40,
+0x18,0x6,0,0xc,0,0x30,0,0x60,0x20,0x8,
+0x8,0x82,0x18,0x42,0x10,0x41,0x8,0x1,0x84,0x20,
+0x80,0x80,0x88,0x20,0x81,0x4,0x80,0x88,0x61,0x8c,
+0x20,0x6,0x30,0x82,0x18,0x40,0x40,0x42,0x1,0,
+0x88,0x20,0x80,0x80,0x82,0x2,0,0x10,0x8,0,
+0,0,0,0x8,0x60,0xc2,0x10,0xc2,0x18,0x43,
+0x2,0x1,0xc,0x20,0x80,0x80,0x4,0x10,0x80,0x40,
+0x88,0x88,0x21,0x8,0x30,0x84,0x30,0x40,0x18,0x40,
+0x84,0x43,0x1,0,0x88,0x21,0x1,0x40,0x42,0x2,
+0,0x40,0x8,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,0x1,0x80,0x10,0x10,0x40,0,0x8,0x1,0x1,
+0x8,0,0xc,0x30,0,0xc,0xc0,0,0,0x18,
+0x20,0,0,0xf,0xf8,0,0,0,0,0x43,
+0x1,0x40,0,0,0,0,0,0x19,0x82,0x4,
+0x42,0x8,0x11,0,0x40,0x48,0x9,0x1,0x20,0x24,
+0x4,0x80,0xa1,0x11,0x84,0x20,0x84,0x10,0x82,0x10,
+0x40,0x40,0x8,0x1,0,0x20,0x21,0x4,0x30,0xc6,
+0x18,0xc3,0x18,0x63,0xc,0x62,0x2,0x51,0x84,0x20,
+0x84,0x10,0x82,0x10,0x8,0x8,0x1,0x24,0x43,0x8,
+0x61,0xc,0x21,0x84,0x30,0x86,0x22,0x89,0xc,0x21,
+0x84,0x30,0x86,0x10,0xc0,0x40,0x8,0x1,0,0x20,
+0x21,0x4,0x10,0x84,0x10,0x82,0x10,0x42,0x8,0x40,
+0x60,0x21,0x4,0x30,0x86,0x10,0xc2,0x18,0x14,0xc,
+0x20,0x50,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,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,0x1,0x80,0,0x9,0,0x40,0xe,
+0x6,0x60,0,0x2,0x1,0,0,0,0,0x60,
+0,0x3,0x1,0,0xe,0x7,0xf1,0xfe,0xf,0,
+0x78,0x3c,0x3,0x80,0x10,0xe,0x7,0x80,0x18,0x6,
+0,0,0,0,0,0x60,0x10,0xde,0x3d,0xfc,
+0x7,0x87,0xe0,0xff,0x1e,0,0x78,0x71,0xc7,0xf0,
+0x70,0x78,0xe7,0xfd,0xe3,0xde,0x20,0x70,0x7c,0x1,
+0xc1,0xe1,0x97,0x81,0xf0,0x3c,0x1,0,0x88,0x71,
+0xc3,0xe0,0xfe,0x2,0,0x8,0x8,0,0,0,
+0,0x7,0xb9,0xbc,0xf,0x1,0xec,0x3c,0xf,0xe0,
+0xf4,0x71,0xc7,0xf0,0x4,0x31,0xe3,0xf9,0xcc,0xdc,
+0x70,0xf0,0x2f,0x3,0xd1,0xfc,0x17,0x80,0x78,0x3d,
+0x81,0,0x88,0x73,0x80,0x80,0xfe,0x2,0,0x40,
+0x8,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,0x1,
+0x80,0x10,0x1f,0x80,0,0x3e,0x1,0x1,0x8,0,
+0x3,0xc0,0,0x2,0x20,0,0,0x7,0xc0,0,
+0,0,0,0,0,0,0,0x7d,0x81,0x40,
+0,0,0,0,0,0x22,0,0xe,0x7,0xc0,
+0x39,0x8,0xf1,0xfe,0x3f,0xc7,0xf8,0xff,0x1f,0xe3,
+0xf3,0xf0,0x78,0x7f,0x8f,0xf1,0xfe,0x3f,0xc3,0xf8,
+0x7f,0xf,0xe1,0xfc,0x7e,0xf,0x10,0x38,0x7,0,
+0xe0,0x1c,0x3,0x80,0,0x8e,0x3,0xc0,0x78,0xf,
+0x1,0xe0,0x3e,0x1c,0x3,0x98,0x3d,0xc7,0xb8,0xf7,
+0x1e,0xe3,0xdc,0x7b,0x9c,0x70,0xf0,0x1e,0x3,0xc0,
+0x78,0xf,0x3,0xf8,0x7f,0xf,0xe1,0xfc,0x1e,0xe,
+0x38,0x78,0xf,0x1,0xe0,0x3c,0x7,0x80,0,0x5e,
+0x3,0xd8,0x7b,0xf,0x61,0xec,0x8,0xb,0xc0,0x20,
+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,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,0x9,0,0x40,0,0,0,
+0,0x2,0x1,0,0,0,0,0xc0,0,0,
+0x1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xc,0,0,
+0,0,0,0,0xf,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0x88,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x2,0,0x8,0x8,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x4,0,
+0,0,0x4,0,0,0,0,0,0,0,
+0x20,0,0x10,0,0,0,0,0,0,0,
+0,0,0,0x80,0,0x2,0,0x40,0x8,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,0x1,0x80,0,
+0,0,0,0,0x1,0x1,0xf0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x40,0x7,0x60,0,0x4,
+0,0,0,0,0,0,0,0,0x1,0x8,
+0,0,0,0,0,0,0,0,0,0,
+0x20,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,0x40,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,0x8,0x8,0,0x20,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,
+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,0x9,0,0x40,0,0,0,0,0x1,
+0x2,0,0,0,0,0xc0,0,0,0x2,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xc,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,0x4,0x70,0,0,0,
+0,0,0,0,0,0,0,0,0,0x2,
+0,0x4,0x8,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x4,0,0,0,
+0x4,0,0,0,0,0,0,0,0x20,0,
+0x10,0,0,0,0,0,0,0,0,0,
+0x1,0,0,0x2,0,0x40,0x8,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,0x1,0x80,0,0,0,
+0,0,0x1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x40,0,0,0,0x2,0,0,
+0,0,0,0,0,0,0x1,0x8,0,0,
+0,0,0,0,0,0,0,0,0x10,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,0x20,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,0x10,0x8,0,0x40,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,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,0x1,0x80,0,0,0x2,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x18,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,0x3,0x80,0x4,
+0x38,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x8,0,0,0,0x8,0,
+0,0,0,0,0,0,0x20,0,0x10,0,
+0,0,0,0,0,0,0,0,0x1,0,
+0,0x1,0x80,0x40,0x30,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,0x1,0x80,0,0,0,0,0,
+0x1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x40,0,0,0,0xc,0,0,0,0,
+0,0,0,0,0,0xf0,0,0,0,0,
+0,0,0,0,0,0,0x60,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,
+0xc0,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,
+0x10,0x8,0,0x40,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,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,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,
+0x7,0xff,0,0,0,0,0,0,0,0,
+0,0x1,0xf0,0,0,0,0xf0,0,0,0,
+0,0,0,0,0x78,0,0x78,0,0,0,
+0,0,0,0,0,0,0xf,0x80,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,0x1,0x80,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,0x40,
+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,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,0xf8,0x1e,
+0x3,0xe0,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,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,
+};
+
+static WORD Courier18_ch_ofst[225] = {
+0,11,22,33,44,55,66,77,88,99,
+110,121,132,143,154,165,176,187,198,209,
+220,231,242,253,264,275,286,297,308,319,
+330,341,352,363,374,385,396,407,418,429,
+440,451,462,473,484,495,506,517,528,539,
+550,561,572,583,594,605,616,627,638,649,
+660,671,682,693,704,715,726,737,748,759,
+770,781,792,803,814,825,836,847,858,869,
+880,891,902,913,924,935,946,957,968,979,
+990,1001,1012,1023,1034,1045,1056,1067,1078,1089,
+1100,1111,1122,1133,1144,1155,1166,1177,1188,1199,
+1210,1221,1232,1243,1254,1265,1276,1287,1298,1309,
+1320,1331,1342,1353,1364,1375,1386,1397,1408,1419,
+1430,1441,1452,1463,1474,1485,1496,1507,1518,1529,
+1540,1551,1562,1573,1584,1595,1606,1617,1628,1639,
+1650,1661,1672,1683,1694,1705,1716,1727,1738,1749,
+1760,1771,1782,1793,1804,1815,1826,1837,1848,1859,
+1870,1881,1892,1903,1914,1925,1936,1947,1958,1969,
+1980,1991,2002,2013,2024,2035,2046,2057,2068,2079,
+2090,2101,2112,2123,2134,2145,2156,2167,2178,2189,
+2200,2211,2222,2233,2244,2255,2266,2277,2288,2299,
+2310,2321,2332,2343,2354,2365,2376,2387,2398,2409,
+2420,2431,2442,2453,2464,
+};
+
+static struct font_hdr Courier18_font = {
+STPROP, 18, "-Adobe-Courier-M-R-N--18-180-75", 32, 255,
+19, 15, 9, 4, 4,
+12, 11, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Courier18_ch_ofst, Courier18_data,
+428, 19,
+NULL,
+0, 0,   /* x/y offset */
+21,        /* lineHeight */
+16,	   /* psHeight */
+};
+
+MgFont *mgCourier18Font()
+{
+return &Courier18_font;
+}
+
+MgFont *mgLargeFixedFont()
+{
+return &Courier18_font;
+}
diff --git a/lib/font/mgCourier24.c b/lib/font/mgCourier24.c
new file mode 100644
index 0000000..0c42b87
--- /dev/null
+++ b/lib/font/mgCourier24.c
@@ -0,0 +1,1122 @@
+
+/* Courier24.c - compiled data for font -Adobe-Courier-M-R-N--24-240-75 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/courR24.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Courier24_data[10656] = {
+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,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,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,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x8,0,0,0x80,0,0,0,0,0,0,
+0x70,0,0,0,0,0x4,0,0,0x80,0,
+0,0,0,0x40,0,0x4,0,0,0,0,
+0,0,0,0,0x20,0,0x2,0,0,0,
+0,0,0,0,0,0,0,0x10,0,0x1,
+0,0,0,0,0,0x4,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,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,
+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,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,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,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,0x4,0,0x1,0,0xc,0,
+0x61,0,0,0,0x88,0,0,0,0,0x2,
+0,0x1,0,0xc,0,0,0,0x20,0,0x8,
+0,0x60,0,0,0,0,0x18,0x40,0x10,0,
+0x4,0,0x30,0x1,0x84,0,0,0,0,0,
+0,0x8,0,0x2,0,0x18,0,0,0,0x8,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x10,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,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,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,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,0,0,0,0x2,0,
+0x2,0,0x12,0,0x91,0,0xc6,0,0x88,0,
+0,0,0,0x1,0,0x2,0,0x12,0,0xc6,
+0,0x10,0,0x10,0,0x90,0x6,0x30,0,0,
+0x24,0x40,0x8,0,0x8,0,0x48,0x2,0x44,0x6,
+0x30,0,0,0,0,0x4,0,0x4,0,0x24,
+0,0xcc,0,0x10,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x70,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,0,0,0,0,0,0,0,0x12,0,
+0x10,0x1,0xc0,0,0,0,0,0,0x20,0x20,
+0,0x4,0,0,0,0,0,0,0,0,
+0,0x8,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,0x7,0x80,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,0xe,0x1,0,0,0xe0,0,0x40,
+0,0,0xc,0,0,0x1,0xc0,0,0,0,
+0x7,0,0,0,0x3e,0,0,0x70,0,0x2,
+0,0x1,0x1,0xc0,0x1,0xf0,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,0x6,0,0x10,0,0xc0,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,0x4,0,0,0,
+0,0,0,0,0x40,0x1,0xf8,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x3,0x80,0,0,0,0,0,0,
+0xc,0,0,0x1,0xfe,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x1,0,0x4,0,0x21,0,0x8e,0,
+0xc6,0,0x70,0,0,0,0,0,0x80,0x4,
+0,0x21,0,0xc6,0,0x8,0,0x20,0x1,0x8,
+0x6,0x30,0,0,0x23,0x80,0x4,0,0x10,0,
+0x84,0x2,0x38,0x6,0x30,0,0,0,0,0x2,
+0,0x8,0,0x42,0,0xcc,0,0x20,0,0,
+0x1,0xc0,0x8,0,0,0x80,0,0,0,0,
+0,0,0x88,0,0,0,0,0x4,0,0,
+0x40,0,0,0,0,0x80,0,0x8,0,0,
+0,0,0x3e,0x60,0,0,0x20,0,0x1,0,
+0,0,0,0,0,0,0,0,0,0x10,
+0,0x1,0,0,0,0,0,0x4,0x1c,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,0x2,0,
+0x73,0x80,0x12,0,0x10,0x2,0x20,0,0,0x1,
+0xc0,0,0x40,0x10,0,0x4,0,0,0,0,
+0,0,0,0,0,0x8,0x3,0x80,0x6,0,
+0x1c,0,0x1e,0,0x1c,0x3,0xfc,0,0x3c,0x1f,
+0xf0,0x7,0x80,0x7,0,0,0,0,0,0,
+0,0,0,0,0,0,0x18,0x40,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,0x8,0x1,0,
+0,0x20,0,0xa0,0,0,0x6,0,0,0,
+0x40,0,0,0,0x1,0,0,0,0x40,0,
+0,0x10,0,0x2,0,0x1,0,0x40,0,0x10,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x80,0,0,0,0,0,
+0,0,0,0,0,0,0,0x8,0,0x10,
+0,0x20,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,
+0x4,0,0,0,0,0,0,0,0x40,0x2,
+0x8,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x4,0x40,0,0,
+0xe,0,0x3c,0,0x18,0,0,0x6,0x48,0,
+0,0,0,0x6,0,0,0,0,0x3,0,
+0x6,0,0x1e,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,0x4,0,0,0,0,0,0,0,
+0,0,0,0,0x2,0x20,0x4,0,0x1,0,
+0xc,0,0x61,0,0,0,0x88,0,0,0,
+0,0x2,0,0,0x80,0x6,0,0,0,0x40,
+0,0x10,0,0xc0,0,0,0x43,0x80,0x18,0x40,
+0x10,0,0x2,0,0x18,0x1,0xc2,0,0,0,
+0,0,0,0x8,0,0x2,0,0x18,0,0,
+0,0x8,0x4,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,0x2,0,0x73,0x80,0x12,0,0x3d,0x4,
+0x10,0,0,0x1,0xc0,0,0x40,0x10,0,0x4,
+0,0x8,0,0,0,0,0,0,0,0x10,
+0xc,0x60,0x3a,0,0x63,0,0x61,0,0x14,0x2,
+0,0,0xc0,0x10,0x10,0x18,0x60,0x18,0x80,0,
+0,0,0,0,0,0,0,0,0x7,0xc0,
+0x10,0x20,0x3f,0x1,0xff,0x80,0x1e,0x47,0xfc,0xf,
+0xfe,0xf,0xfe,0x3,0xc8,0x7c,0x7c,0x3f,0xe0,0x1f,
+0xf3,0xe3,0xc7,0xf0,0xe,0x3,0xbc,0x3f,0x3,0xc0,
+0x3f,0xe0,0xf,0x1,0xff,0,0x3c,0x83,0xff,0x8f,
+0xf,0x1e,0xf,0x3e,0x3e,0x7c,0x7c,0xf0,0x78,0xff,
+0xc0,0x8,0,0x80,0,0x20,0x1,0x10,0,0,
+0x3,0,0,0,0x40,0,0,0,0x1,0,
+0,0,0x80,0,0,0x10,0,0x2,0,0x1,
+0,0x40,0,0x10,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x8,0,0x10,0,0x20,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,0x4,0,0x1c,0,0,0x7,
+0x8f,0,0x40,0x4,0x8,0xc,0x60,0xf,0x80,0x1e,
+0,0,0,0,0,0,0x1,0xf0,0,0,
+0x8,0x20,0x2,0,0x11,0,0x42,0,0x30,0,
+0,0xc,0x48,0,0,0,0,0x1a,0,0xe,
+0,0,0xd,0,0x1a,0,0x21,0,0,0,
+0x1f,0x80,0x3f,0,0x7e,0,0xfc,0x1,0xf8,0x3,
+0xf0,0x7,0xff,0x1,0xe4,0x7f,0xf0,0xff,0xe1,0xff,
+0xc3,0xff,0x81,0xff,0x3,0xfe,0x7,0xfc,0xf,0xf8,
+0x7f,0xc1,0xe1,0xf8,0x1e,0,0x3c,0,0x78,0,
+0xf0,0x1,0xe0,0,0,0x7,0x88,0xf0,0xf1,0xe1,
+0xe3,0xc3,0xc7,0x87,0x8f,0x7,0x8f,0x80,0x4,0x10,
+0x2,0,0x2,0,0x12,0,0x91,0,0xc6,0,
+0x88,0,0,0,0,0x1,0,0x1,0,0x9,
+0,0x63,0,0x20,0,0x20,0x1,0x20,0x6,0x30,
+0x6,0x80,0x24,0x40,0x8,0,0x4,0,0x24,0x2,
+0x22,0x3,0x18,0,0,0,0,0x4,0,0x4,
+0,0x24,0x1,0x8c,0,0x10,0x4,0,0xc,0x60,
+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,0x2,0,0x73,0x80,
+0x12,0,0x43,0x4,0x10,0x1,0xd0,0x1,0xc0,0,
+0x80,0x8,0,0x64,0xc0,0x8,0,0,0,0,
+0,0,0,0x10,0x8,0x20,0x2,0,0x80,0x80,
+0x80,0x80,0x24,0x2,0,0x1,0,0x10,0x10,0x10,
+0x20,0x10,0x40,0,0,0,0,0x3,0x80,0,
+0x1c,0,0x8,0x20,0x20,0x20,0x5,0,0x40,0x40,
+0x61,0xc2,0x3,0x2,0x2,0x2,0x2,0xc,0x38,0x10,
+0x10,0x2,0,0,0x80,0x81,0,0x80,0x6,0x3,
+0xc,0x4,0xc,0x30,0x8,0x10,0x30,0xc0,0x40,0x80,
+0xc3,0x82,0x10,0x84,0x2,0x8,0x2,0x10,0x4,0x10,
+0x10,0x20,0x20,0x80,0x40,0x8,0,0x80,0,0x20,
+0x2,0x8,0,0,0x1,0x80,0,0,0x40,0,
+0,0,0x1,0,0,0,0x80,0,0,0x10,
+0,0,0,0,0,0x40,0,0x10,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x80,0,0,0,0,0,0,0,
+0,0,0,0,0,0x8,0,0x10,0,0x20,
+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,0x4,0,
+0x23,0,0,0x2,0x2,0,0x40,0x4,0x8,0xc,
+0x60,0x30,0x60,0x21,0,0,0,0,0,0,
+0x6,0xc,0x7,0xf0,0x8,0x20,0x2,0,0x1,0,
+0x2,0,0x60,0,0,0xc,0x48,0,0,0,
+0,0x2,0,0x11,0,0,0x1,0,0x82,0x1,
+0x1,0x2,0,0,0x2,0x80,0x5,0,0xa,0,
+0x14,0,0x28,0,0x50,0x1,0x41,0x6,0x1c,0x10,
+0x10,0x20,0x20,0x40,0x40,0x80,0x80,0x10,0,0x20,
+0,0x40,0,0x80,0x20,0x30,0x60,0x20,0x61,0x80,
+0xc3,0x1,0x86,0x3,0xc,0x6,0x18,0x10,0x4,0x18,
+0x70,0x40,0x20,0x80,0x41,0,0x82,0x1,0x2,0x2,
+0x2,0,0x4,0x10,0x1,0,0x4,0,0x21,0,
+0x8e,0,0xc6,0,0x70,0,0,0,0,0,
+0x80,0x2,0,0x10,0x80,0x63,0,0x10,0,0x40,
+0x2,0x10,0x6,0x30,0x18,0x40,0x23,0x80,0x4,0,
+0x8,0,0x42,0x2,0x1c,0x3,0x18,0x1,0xc0,0,
+0,0x2,0,0x8,0,0x42,0x1,0x8c,0,0x20,
+0x4,0,0xc,0x60,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,
+0x2,0,0x73,0x80,0x12,0,0x81,0x4,0x10,0x2,
+0x60,0x1,0xc0,0,0x80,0x8,0,0x3f,0x80,0x8,
+0,0,0,0,0,0,0,0x20,0x10,0x10,
+0x2,0,0x80,0x80,0,0x80,0x24,0x2,0,0x2,
+0,0,0x20,0x20,0x10,0x20,0x20,0,0,0,
+0,0xe,0,0,0x7,0,0x8,0x10,0x20,0x20,
+0x8,0x80,0x40,0x20,0xc0,0xc2,0x1,0x2,0x2,0x2,
+0x2,0x18,0x18,0x10,0x10,0x2,0,0,0x80,0x82,
+0,0x80,0x6,0x3,0xa,0x4,0x18,0x18,0x8,0x8,
+0x60,0x60,0x40,0x41,0x1,0x82,0x10,0x84,0x2,0x8,
+0x2,0x10,0x4,0x8,0x20,0x10,0x40,0x80,0x80,0x8,
+0,0x40,0,0x20,0x4,0x4,0,0,0,0,
+0,0,0x40,0,0,0,0x1,0,0,0,
+0x80,0,0,0x10,0,0,0,0,0,0x40,
+0,0x10,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x80,0,0,0,
+0,0,0,0,0,0,0,0,0,0x8,
+0,0x10,0,0x20,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,0xe,0x80,0x40,0x2,0x1,0x1,0x4,0,
+0x40,0x4,0,0,0,0x40,0x10,0xf,0,0,
+0,0,0,0,0x8,0x2,0,0,0x8,0x20,
+0x2,0,0x1,0,0x4,0,0,0,0,0xc,
+0x48,0,0,0,0,0x2,0,0x20,0x80,0,
+0x1,0x1,0x2,0x2,0x2,0x4,0,0,0x4,0x40,
+0x8,0x80,0x11,0,0x22,0,0x44,0,0x88,0x2,
+0x41,0xc,0xc,0x10,0x10,0x20,0x20,0x40,0x40,0x80,
+0x80,0x10,0,0x20,0,0x40,0,0x80,0x20,0x10,
+0x50,0x20,0xc0,0xc1,0x81,0x83,0x3,0x6,0x6,0xc,
+0xc,0x8,0x8,0x30,0x30,0x40,0x20,0x80,0x41,0,
+0x82,0x1,0x1,0x4,0x2,0,0x4,0x10,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,0x20,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1,0xc0,0,0x8,0,0,0,0,0,
+0,0,0,0,0x4,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,0x2,0,0x21,0,0x12,0,
+0x80,0x2,0x20,0x2,0,0x1,0xc0,0,0x80,0x8,
+0,0xe,0,0x8,0,0,0,0,0,0,
+0,0x20,0x10,0x10,0x2,0,0,0x80,0,0x80,
+0x44,0x2,0,0x2,0,0,0x20,0x20,0x10,0x20,
+0x20,0xe,0,0x1c,0,0x38,0,0,0x1,0xc0,
+0,0x10,0x20,0xe0,0x8,0x80,0x40,0x20,0x80,0x42,
+0,0x82,0x2,0x2,0x2,0x10,0x8,0x10,0x10,0x2,
+0,0,0x80,0x84,0,0x80,0x5,0x5,0x9,0x4,
+0x10,0x8,0x8,0x8,0x40,0x20,0x40,0x41,0,0x82,
+0x10,0x84,0x2,0x4,0x4,0x10,0x84,0x8,0x20,0x10,
+0x40,0x81,0,0x8,0,0x40,0,0x20,0x8,0x2,
+0,0,0,0,0xf,0,0x4f,0x80,0x3e,0x80,
+0xf9,0,0xf8,0x7,0xfc,0x7,0xce,0x13,0xc0,0x1e,
+0,0x7f,0x80,0x47,0x80,0x10,0x1d,0xce,0x1c,0xf0,
+0x3,0xe0,0x73,0xe0,0x1f,0x38,0x71,0xc0,0x3e,0x83,
+0xfe,0xe,0xe,0x1f,0x1f,0x3c,0x1e,0x7c,0x7c,0xf0,
+0xf0,0x7f,0xc0,0x8,0,0x10,0,0x20,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,0x3,0,0x31,0x80,0x40,0x1,
+0x7a,0x1,0x4,0,0x40,0xe,0,0,0,0x46,
+0x90,0x11,0,0x8,0x40,0,0,0,0x9,0xe2,
+0,0,0x4,0x40,0x2,0,0x2,0,0x1c,0,
+0,0xe,0xe,0xc,0x48,0,0,0,0,0x2,
+0,0x20,0x82,0x10,0x1,0x2,0x2,0x4,0xe,0x8,
+0x1,0x80,0x4,0x40,0x8,0x80,0x11,0,0x22,0,
+0x44,0,0x88,0x2,0x41,0x8,0x4,0x10,0x10,0x20,
+0x20,0x40,0x40,0x80,0x80,0x10,0,0x20,0,0x40,
+0,0x80,0x20,0x8,0x48,0x20,0x80,0x41,0,0x82,
+0x1,0x4,0x2,0x8,0x4,0x4,0x10,0x20,0x30,0x40,
+0x20,0x80,0x41,0,0x82,0x1,0x1,0x4,0x3,0xf8,
+0x4,0x10,0x7,0x80,0xf,0,0x1e,0,0x3c,0,
+0x78,0,0xf0,0x7,0x1c,0x3,0xe8,0x7,0xc0,0xf,
+0x80,0x1f,0,0x3e,0,0xf0,0x1,0xe0,0x3,0xc0,
+0x7,0x80,0x7,0xf0,0xe7,0x80,0x1f,0,0x3e,0,
+0x7c,0,0xf8,0x1,0xf0,0x1,0xc0,0x7,0xd0,0xe0,
+0xe1,0xc1,0xc3,0x83,0x87,0x7,0xf,0xf,0x4,0xf8,
+0x3c,0x3c,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,0x2,0,
+0x21,0,0xff,0x80,0x80,0x1,0xc7,0x2,0,0,
+0x80,0x1,0,0x4,0,0x1b,0,0x8,0,0,
+0,0,0,0,0,0x40,0x10,0x10,0x2,0,
+0,0x80,0x1,0,0x44,0x2,0,0x4,0,0,
+0x20,0x10,0x20,0x20,0x20,0xe,0,0x1c,0,0xe0,
+0,0,0,0x70,0,0x10,0x21,0x20,0x8,0x80,
+0x40,0x21,0,0x2,0,0x82,0x20,0x2,0x20,0x20,
+0,0x10,0x10,0x2,0,0,0x80,0x88,0,0x80,
+0x5,0x5,0x9,0x4,0x20,0x4,0x8,0x8,0x80,0x10,
+0x40,0x41,0,0x2,0x10,0x84,0x2,0x4,0x4,0x10,
+0x84,0x4,0x40,0x8,0x80,0x82,0,0x8,0,0x20,
+0,0x20,0,0,0,0,0,0,0x30,0x80,
+0x70,0x60,0xc1,0x83,0x7,0x3,0x6,0,0x80,0x18,
+0x38,0x14,0x20,0x2,0,0,0x80,0x42,0,0x10,
+0x6,0x31,0x5,0x8,0xc,0x18,0x1c,0x18,0x60,0xe0,
+0x16,0x20,0x41,0x80,0x80,0x2,0x2,0x4,0x4,0x10,
+0x4,0x10,0x10,0x40,0x20,0x40,0x40,0x8,0,0x10,
+0,0x20,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,0x3,0,
+0x20,0x80,0x40,0,0x84,0,0x88,0,0x40,0x11,
+0x80,0,0,0x89,0x88,0x21,0,0x31,0x80,0,
+0,0,0x11,0x11,0,0,0x3,0x80,0x2,0,
+0x4,0,0x2,0,0,0x2,0x2,0xc,0x48,0,
+0,0,0,0x2,0,0x20,0x81,0x8c,0x1,0x2,
+0x2,0x4,0x1,0x8,0x1,0x80,0x4,0x40,0x8,0x80,
+0x11,0,0x22,0,0x44,0,0x88,0x2,0x44,0x10,
+0,0x11,0,0x22,0,0x44,0,0x88,0,0x10,
+0,0x20,0,0x40,0,0x80,0x20,0x8,0x48,0x21,
+0,0x22,0,0x44,0,0x88,0x1,0x10,0x2,0x2,
+0x20,0x40,0x48,0x40,0x20,0x80,0x41,0,0x82,0x1,
+0,0x88,0x2,0x4,0x4,0x20,0x18,0x40,0x30,0x80,
+0x61,0,0xc2,0x1,0x84,0x3,0x8,0x18,0xa3,0xc,
+0x18,0x18,0x30,0x30,0x60,0x60,0xc0,0xc1,0x80,0x10,
+0,0x20,0,0x40,0,0x80,0x18,0x30,0x28,0x40,
+0x60,0xc0,0xc1,0x81,0x83,0x3,0x6,0x6,0xc,0,
+0,0x18,0x30,0x20,0x20,0x40,0x40,0x80,0x81,0x1,
+0x4,0x2,0x7,0x6,0x10,0x8,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,0x2,0,0x21,0,0x24,0,0x40,0,
+0x38,0x1,0,0,0x80,0x1,0,0x4,0,0x31,
+0x80,0x8,0,0,0,0,0,0,0,0x40,
+0x10,0x10,0x2,0,0x1,0,0x1e,0,0x84,0x3,
+0xf8,0x4,0xf0,0,0x40,0xf,0xc0,0x20,0x60,0xe,
+0,0x1c,0x3,0x80,0xf,0xff,0,0x1c,0,0x10,
+0x22,0x20,0x10,0x40,0x40,0x41,0,0x2,0,0x82,
+0x20,0x2,0x20,0x20,0,0x10,0x10,0x2,0,0,
+0x80,0x90,0,0x80,0x4,0x89,0x8,0x84,0x20,0x4,
+0x8,0x8,0x80,0x10,0x40,0x40,0xc0,0,0x10,0x4,
+0x2,0x2,0x8,0x11,0x44,0x4,0x40,0x8,0x80,0x2,
+0,0x8,0,0x20,0,0x20,0,0,0,0,
+0,0,0,0x40,0x60,0x20,0x80,0x82,0x3,0x2,
+0x2,0,0x80,0x10,0x18,0x18,0x10,0x2,0,0,
+0x80,0x44,0,0x10,0x4,0x21,0x6,0x4,0x8,0x8,
+0x18,0x8,0x40,0x60,0x18,0,0x40,0x80,0x80,0x2,
+0x2,0x4,0x4,0x10,0x4,0x8,0x20,0x40,0x20,0x40,
+0x80,0x8,0,0x10,0,0x20,0x7,0x84,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,0x40,0,0x40,0x1,0x2,0,
+0x88,0,0x40,0x10,0x40,0,0,0x90,0x88,0x23,
+0,0x63,0x3,0xff,0x80,0,0x11,0x11,0,0,
+0,0,0x7f,0xf0,0x8,0,0x2,0,0,0x2,
+0x2,0x6,0x48,0x1,0xc0,0,0,0x2,0,0x11,
+0,0xc6,0x1,0x4,0x2,0x8,0x1,0x10,0,0,
+0x8,0x20,0x10,0x40,0x20,0x80,0x41,0,0x82,0x1,
+0x4,0x4,0x44,0x10,0,0x11,0,0x22,0,0x44,
+0,0x88,0,0x10,0,0x20,0,0x40,0,0x80,
+0x20,0x8,0x44,0x21,0,0x22,0,0x44,0,0x88,
+0x1,0x10,0x2,0x1,0x40,0x40,0x88,0x40,0x20,0x80,
+0x41,0,0x82,0x1,0,0x88,0x2,0x2,0x4,0xe0,
+0,0x20,0,0x40,0,0x80,0x1,0,0x2,0,
+0x4,0x10,0x41,0x8,0x8,0x10,0x10,0x20,0x20,0x40,
+0x40,0x80,0x80,0x10,0,0x20,0,0x40,0,0x80,
+0x10,0x18,0x30,0x20,0x40,0x40,0x80,0x81,0x1,0x2,
+0x2,0x4,0x4,0,0,0x10,0x50,0x20,0x20,0x40,
+0x40,0x80,0x81,0x1,0x4,0x2,0x6,0x2,0x10,0x8,
+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,0x2,0,0,0,
+0x24,0,0x3c,0x1,0xc0,0x3,0,0,0,0x1,
+0,0x4,0,0x60,0xc1,0xff,0xc0,0,0x7,0xfe,
+0,0,0,0x80,0x10,0x10,0x2,0,0x2,0,
+0x2,0x1,0x4,0,0x4,0x5,0x8,0,0x40,0x18,
+0x60,0x18,0xa0,0,0,0,0x6,0,0,0,
+0,0x6,0,0x20,0x22,0x20,0x10,0x40,0x7f,0x81,
+0,0x2,0,0x83,0xe0,0x3,0xe0,0x20,0,0x1f,
+0xf0,0x2,0,0,0x80,0xb8,0,0x80,0x4,0x89,
+0x8,0x84,0x20,0x4,0x8,0x10,0x80,0x10,0x40,0x80,
+0x3c,0,0x10,0x4,0x2,0x2,0x8,0x11,0x44,0x2,
+0x80,0x5,0,0x4,0,0x8,0,0x10,0,0x20,
+0,0,0,0,0,0,0,0x40,0x40,0x11,
+0,0x84,0x1,0x4,0x1,0,0x80,0x20,0x8,0x10,
+0x10,0x2,0,0,0x80,0x48,0,0x10,0x4,0x21,
+0x4,0x4,0x10,0x4,0x10,0x4,0x80,0x20,0x10,0,
+0x40,0,0x80,0x2,0x2,0x2,0x8,0x10,0x84,0x4,
+0x40,0x20,0x40,0x1,0,0x8,0,0x10,0,0x20,
+0x8,0xc4,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,0x40,0x1,
+0xfc,0x1,0x2,0,0x50,0,0,0x8,0x20,0,
+0,0x90,0x8,0x1d,0x80,0xc6,0,0,0x87,0xfe,
+0x11,0xe1,0,0,0,0,0x2,0,0x11,0,
+0x42,0,0,0x2,0x2,0x1,0xc8,0x1,0xc0,0,
+0,0x2,0,0xe,0,0x63,0x1,0x9,0x82,0x17,
+0x21,0x26,0,0,0x8,0x20,0x10,0x40,0x20,0x80,
+0x41,0,0x82,0x1,0x4,0x4,0x7c,0x10,0,0x1f,
+0,0x3e,0,0x7c,0,0xf8,0,0x10,0,0x20,
+0,0x40,0,0x80,0xfc,0x8,0x44,0x21,0,0x22,
+0,0x44,0,0x88,0x1,0x10,0x2,0,0x80,0x41,
+0x8,0x40,0x20,0x80,0x41,0,0x82,0x1,0,0x50,
+0x2,0x2,0x4,0x18,0,0x20,0,0x40,0,0x80,
+0x1,0,0x2,0,0x4,0,0x40,0x90,0x8,0x20,
+0x8,0x40,0x10,0x80,0x21,0,0x40,0x10,0,0x20,
+0,0x40,0,0x80,0x20,0x8,0x20,0x20,0x80,0x21,
+0,0x42,0,0x84,0x1,0x8,0x2,0x1f,0xfc,0x20,
+0x88,0x20,0x20,0x40,0x40,0x80,0x81,0x1,0x2,0x4,
+0x4,0x1,0x8,0x10,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,
+0x2,0,0,0,0x24,0,0x2,0xe,0x1c,0x4,
+0x98,0,0,0x1,0,0x4,0,0,0,0x8,
+0,0,0,0,0,0,0,0x80,0x10,0x10,
+0x2,0,0x4,0,0x1,0x1,0x4,0,0x2,0x6,
+0x4,0,0x40,0x10,0x20,0x7,0x20,0,0,0,
+0x3,0x80,0,0,0,0x1c,0,0xc0,0x22,0x20,
+0x10,0x40,0x40,0x41,0,0x2,0,0x82,0x20,0x2,
+0x20,0x20,0,0x10,0x10,0x2,0,0,0x80,0xcc,
+0,0x80,0x4,0x51,0x8,0x44,0x20,0x4,0xf,0xe0,
+0x80,0x10,0x7f,0,0x3,0,0x10,0x4,0x2,0x2,
+0x8,0x9,0x48,0x1,0,0x2,0,0x8,0,0x8,
+0,0x10,0,0x20,0,0,0,0,0,0,
+0,0x40,0x40,0x11,0,0x4,0x1,0x4,0x1,0,
+0x80,0x20,0x8,0x10,0x10,0x2,0,0,0x80,0x50,
+0,0x10,0x4,0x21,0x4,0x4,0x10,0x4,0x10,0x4,
+0x80,0x20,0x10,0,0x3c,0,0x80,0x2,0x2,0x2,
+0x8,0x8,0x88,0x2,0x80,0x20,0x40,0x2,0,0x30,
+0,0x10,0,0x18,0x8,0x78,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,0x40,0,0x20,0x1,0x2,0x3,0xfe,0,
+0,0x4,0x10,0,0,0x90,0x8,0,0x1,0x8c,
+0,0,0x80,0,0x11,0x21,0,0,0,0,
+0x2,0,0x3f,0,0x3c,0,0,0x2,0x2,0,
+0x48,0x1,0xc0,0,0,0x1f,0xc0,0,0,0x31,
+0x8f,0xf2,0x9f,0xe8,0x9e,0x4a,0,0x80,0x8,0x20,
+0x10,0x40,0x20,0x80,0x41,0,0x82,0x1,0x4,0x4,
+0x44,0x10,0,0x11,0,0x22,0,0x44,0,0x88,
+0,0x10,0,0x20,0,0x40,0,0x80,0x20,0x8,
+0x42,0x21,0,0x22,0,0x44,0,0x88,0x1,0x10,
+0x2,0x1,0x40,0x42,0x8,0x40,0x20,0x80,0x41,0,
+0x82,0x1,0,0x20,0x2,0x2,0x4,0x8,0,0x20,
+0,0x40,0,0x80,0x1,0,0x2,0,0x4,0,
+0x40,0x90,0,0x20,0x8,0x40,0x10,0x80,0x21,0,
+0x40,0x10,0,0x20,0,0x40,0,0x80,0x20,0x8,
+0x20,0x20,0x80,0x21,0,0x42,0,0x84,0x1,0x8,
+0x2,0,0,0x21,0x8,0x20,0x20,0x40,0x40,0x80,
+0x81,0x1,0x2,0x4,0x4,0x1,0x8,0x10,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,0x2,0,0,0x1,0xff,0,
+0x1,0,0x22,0x8,0x90,0,0,0x1,0,0x4,
+0,0,0,0x8,0,0,0,0,0,0,
+0x1,0,0x10,0x10,0x2,0,0x8,0,0,0x82,
+0x4,0,0x2,0x4,0x4,0,0x80,0x20,0x10,0,
+0x20,0,0,0,0,0xe0,0xf,0xff,0,0x70,
+0x1,0,0x22,0x20,0x3f,0xe0,0x40,0x21,0,0x2,
+0,0x82,0x20,0x2,0x20,0x20,0xfc,0x10,0x10,0x2,
+0,0x80,0x80,0x86,0,0x80,0x4,0x71,0x8,0x44,
+0x20,0x4,0x8,0,0x80,0x10,0x42,0,0,0x80,
+0x10,0x4,0x2,0x1,0x10,0xa,0x28,0x2,0x80,0x2,
+0,0x10,0,0x8,0,0x8,0,0x20,0,0,
+0,0,0,0,0x1f,0xc0,0x40,0x11,0,0x4,
+0x1,0x7,0xff,0,0x80,0x20,0x8,0x10,0x10,0x2,
+0,0,0x80,0x70,0,0x10,0x4,0x21,0x4,0x4,
+0x10,0x4,0x10,0x4,0x80,0x20,0x10,0,0x3,0,
+0x80,0x2,0x2,0x2,0x8,0x9,0x48,0x1,0,0x20,
+0x80,0x4,0,0x8,0,0x10,0,0x20,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,0x2,0,0x20,0,0x20,0x1,
+0x2,0,0x20,0,0,0x2,0x8,0,0,0x88,
+0x88,0x3f,0x83,0x9c,0,0,0x80,0,0x11,0x11,
+0,0,0,0,0x2,0,0,0,0,0,
+0,0x2,0x2,0,0x48,0,0,0,0,0,
+0,0x3f,0x80,0x39,0xc0,0x24,0x80,0x40,0x80,0x92,
+0,0x80,0x1f,0xf0,0x3f,0xe0,0x7f,0xc0,0xff,0x81,
+0xff,0x3,0xfe,0xf,0xc4,0x10,0,0x11,0,0x22,
+0,0x44,0,0x88,0,0x10,0,0x20,0,0x40,
+0,0x80,0x20,0x8,0x42,0x21,0,0x22,0,0x44,
+0,0x88,0x1,0x10,0x2,0x2,0x20,0x44,0x8,0x40,
+0x20,0x80,0x41,0,0x82,0x1,0,0x20,0x2,0x2,
+0x4,0x4,0xf,0xe0,0x1f,0xc0,0x3f,0x80,0x7f,0,
+0xfe,0x1,0xfc,0xf,0xff,0x90,0,0x3f,0xf8,0x7f,
+0xf0,0xff,0xe1,0xff,0xc0,0x10,0,0x20,0,0x40,
+0,0x80,0x20,0x8,0x20,0x20,0x80,0x21,0,0x42,
+0,0x84,0x1,0x8,0x2,0,0,0x22,0x8,0x20,
+0x20,0x40,0x40,0x80,0x81,0x1,0x2,0x8,0x4,0x1,
+0x8,0x20,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,0x24,0,0x1,0,0x41,0x8,0x60,0,
+0,0x1,0,0x4,0,0,0,0x8,0,0,
+0,0,0,0,0x1,0,0x10,0x10,0x2,0,
+0x10,0,0,0x83,0xff,0,0x2,0x4,0x4,0,
+0x80,0x20,0x10,0,0x20,0,0,0,0,0x38,
+0,0,0x1,0xc0,0x1,0,0x21,0x20,0x20,0x20,
+0x40,0x21,0,0x2,0,0x82,0x1,0x2,0,0x20,
+0x8,0x10,0x10,0x2,0,0x80,0x80,0x82,0,0x80,
+0x84,0x1,0x8,0x24,0x20,0x4,0x8,0,0x80,0x10,
+0x41,0,0,0x80,0x10,0x4,0x2,0x1,0x10,0xa,
+0x28,0x4,0x40,0x2,0,0x10,0x40,0x8,0,0x8,
+0,0x20,0,0,0,0,0,0,0x20,0x40,
+0x40,0x11,0,0x4,0x1,0x4,0,0,0x80,0x20,
+0x8,0x10,0x10,0x2,0,0,0x80,0x48,0,0x10,
+0x4,0x21,0x4,0x4,0x10,0x4,0x10,0x4,0x80,0x20,
+0x10,0,0,0x80,0x80,0x2,0x2,0x1,0x10,0x9,
+0x48,0x2,0x80,0x10,0x80,0x8,0,0x8,0,0x10,
+0,0x20,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,0x2,0,
+0x31,0x80,0x20,0,0x84,0,0x20,0,0x40,0x1,
+0x88,0,0,0x47,0x10,0,0x1,0x8c,0,0,
+0,0,0x9,0x12,0,0,0,0,0x2,0,
+0,0,0,0,0,0x2,0x2,0,0x48,0,
+0,0,0,0,0,0,0,0x31,0x80,0x44,
+0x80,0x80,0x81,0x12,0x3,0,0x10,0x10,0x20,0x20,
+0x40,0x40,0x80,0x81,0x1,0x2,0x2,0x8,0x41,0x10,
+0,0x10,0x8,0x20,0x10,0x40,0x20,0x80,0x40,0x10,
+0,0x20,0,0x40,0,0x80,0x20,0x8,0x41,0x21,
+0,0x22,0,0x44,0,0x88,0x1,0x10,0x2,0x4,
+0x10,0x48,0x8,0x40,0x20,0x80,0x41,0,0x82,0x1,
+0,0x20,0x2,0x4,0x4,0x4,0x10,0x20,0x20,0x40,
+0x40,0x80,0x81,0x1,0x2,0x2,0x4,0x10,0x40,0x10,
+0,0x20,0,0x40,0,0x80,0x1,0,0,0x10,
+0,0x20,0,0x40,0,0x80,0x20,0x8,0x20,0x20,
+0x80,0x21,0,0x42,0,0x84,0x1,0x8,0x2,0x1,
+0xc0,0x24,0x8,0x20,0x20,0x40,0x40,0x80,0x81,0x1,
+0x1,0x8,0x4,0x1,0x4,0x20,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,0x24,0,0x81,0,
+0x41,0x8,0x20,0,0,0x1,0,0x4,0,0,
+0,0x8,0,0,0,0,0,0,0x2,0,
+0x10,0x10,0x2,0,0x20,0,0,0x80,0x4,0,
+0x2,0x4,0x4,0,0x80,0x20,0x10,0,0x40,0,
+0,0,0,0xe,0,0,0x7,0,0,0,
+0x20,0xf0,0x20,0x20,0x40,0x20,0x80,0x42,0,0x82,
+0x1,0x2,0,0x10,0x8,0x10,0x10,0x2,0,0x80,
+0x80,0x83,0,0x80,0x84,0x1,0x8,0x24,0x10,0x8,
+0x8,0,0x40,0x20,0x40,0x81,0,0x80,0x10,0x4,
+0x2,0x1,0x10,0xa,0x28,0x8,0x20,0x2,0,0x20,
+0x40,0x8,0,0x4,0,0x20,0,0,0,0,
+0,0,0x40,0x40,0x40,0x11,0,0x4,0x1,0x4,
+0,0,0x80,0x20,0x8,0x10,0x10,0x2,0,0,
+0x80,0x44,0,0x10,0x4,0x21,0x4,0x4,0x10,0x4,
+0x10,0x4,0x80,0x20,0x10,0,0,0x80,0x80,0x2,
+0x2,0x1,0x10,0x9,0x48,0x4,0x40,0x11,0,0x10,
+0,0x8,0,0x10,0,0x20,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,0x2,0,0xe,0,0x20,0x1,0x7a,0x3,
+0xfe,0,0x40,0,0x70,0,0,0x40,0x10,0,
+0,0xc6,0,0,0,0,0x8,0x2,0,0,
+0,0,0x2,0,0,0,0,0,0,0x2,
+0x2,0,0x48,0,0,0,0,0,0,0,
+0,0x63,0,0x48,0x80,0x81,0x1,0x22,0x4,0,
+0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x81,0x1,0x2,
+0x2,0x8,0x41,0x8,0x4,0x10,0x8,0x20,0x10,0x40,
+0x20,0x80,0x40,0x10,0,0x20,0,0x40,0,0x80,
+0x20,0x8,0x41,0x20,0x80,0x41,0,0x82,0x1,0x4,
+0x2,0x8,0x4,0x8,0x8,0x30,0x10,0x40,0x20,0x80,
+0x41,0,0x82,0x1,0,0x20,0x3,0xf8,0x4,0x4,
+0x20,0x20,0x40,0x40,0x80,0x81,0x1,0x2,0x2,0x4,
+0x4,0x20,0x40,0x10,0,0x20,0,0x40,0,0x80,
+0x1,0,0,0x10,0,0x20,0,0x40,0,0x80,
+0x20,0x8,0x20,0x20,0x80,0x21,0,0x42,0,0x84,
+0x1,0x8,0x2,0x1,0xc0,0x28,0x8,0x20,0x20,0x40,
+0x40,0x80,0x81,0x1,0x1,0x10,0x4,0x1,0x4,0x40,
+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,
+0x24,0,0xc2,0,0x41,0x8,0x30,0,0,0,
+0x80,0x8,0,0,0,0x8,0,0x38,0,0,
+0,0xe0,0x2,0,0x8,0x20,0x2,0,0x40,0x1,
+0,0x80,0x4,0,0x4,0x2,0x4,0x1,0,0x10,
+0x20,0,0x40,0xe,0,0x1c,0,0x3,0x80,0,
+0x1c,0,0,0,0x20,0,0x40,0x10,0x40,0x20,
+0xc0,0xc2,0x1,0x2,0x1,0x2,0,0x18,0x8,0x10,
+0x10,0x2,0,0x81,0,0x81,0,0x80,0x84,0x1,
+0x8,0x14,0x18,0x18,0x8,0,0x60,0x60,0x40,0x81,
+0x80,0x80,0x10,0x4,0x2,0,0xa0,0xc,0x18,0x8,
+0x20,0x2,0,0x40,0x40,0x8,0,0x4,0,0x20,
+0,0,0,0,0,0,0x40,0x40,0x60,0x20,
+0x80,0xc2,0x3,0x2,0,0,0x80,0x10,0x18,0x10,
+0x10,0x2,0,0,0x80,0x42,0,0x10,0x4,0x21,
+0x4,0x4,0x8,0x8,0x18,0x8,0x40,0x60,0x10,0,
+0x80,0x80,0x80,0x2,0x6,0,0xa0,0x5,0x50,0x8,
+0x20,0x9,0,0x20,0x40,0x8,0,0x10,0,0x20,
+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,0x2,0,0x4,0,
+0x40,0x82,0x1,0,0x20,0,0x40,0,0x20,0,
+0,0x30,0x60,0,0,0x63,0,0,0,0,
+0x6,0xc,0,0,0,0,0,0,0,0,
+0,0,0,0x2,0x6,0,0x48,0,0,0,
+0,0,0,0,0,0xc6,0,0x90,0x81,0x2,
+0x2,0x42,0x8,0,0x20,0x8,0x40,0x10,0x80,0x21,
+0,0x42,0,0x84,0x1,0x10,0x41,0xc,0xc,0x10,
+0x8,0x20,0x10,0x40,0x20,0x80,0x40,0x10,0,0x20,
+0,0x40,0,0x80,0x20,0x10,0x40,0xa0,0xc0,0xc1,
+0x81,0x83,0x3,0x6,0x6,0xc,0xc,0x10,0x4,0x30,
+0x30,0x40,0x20,0x80,0x41,0,0x82,0x1,0,0x20,
+0x2,0,0x4,0x84,0x20,0x20,0x40,0x40,0x80,0x81,
+0x1,0x2,0x2,0x4,0x4,0x20,0x40,0x88,0xc,0x10,
+0,0x20,0,0x40,0,0x80,0,0x10,0,0x20,
+0,0x40,0,0x80,0x10,0x10,0x20,0x20,0x40,0x40,
+0x80,0x81,0x1,0x2,0x2,0x4,0x4,0x1,0xc0,0x10,
+0x10,0x20,0x60,0x40,0xc0,0x81,0x81,0x3,0,0x90,
+0x6,0x2,0x2,0x40,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,
+0x3,0,0,0,0x24,0,0xbc,0,0x22,0x4,
+0x50,0,0,0,0x80,0x8,0,0,0,0x8,
+0,0x38,0,0,0,0xe0,0x4,0,0xc,0x60,
+0x2,0,0x80,0x80,0xc1,0,0x4,0x6,0xc,0x3,
+0x8,0x1,0,0x18,0x60,0x1,0x80,0xe,0,0x1c,
+0,0,0,0,0,0,0x1,0x80,0x20,0,
+0x40,0x10,0x40,0x40,0x61,0x82,0x3,0x2,0x1,0x2,
+0,0xc,0x10,0x10,0x10,0x2,0,0x43,0,0x81,
+0x80,0x80,0x84,0x1,0x8,0xc,0xc,0x30,0x8,0,
+0x30,0xc0,0x40,0x41,0xc1,0,0x10,0x2,0x4,0,
+0xe0,0xc,0x18,0x10,0x10,0x2,0,0x80,0x40,0x8,
+0,0x2,0,0x20,0,0,0,0,0,0,
+0x40,0xc0,0x70,0x60,0xc1,0x83,0x7,0x3,0x3,0,
+0x80,0x18,0x38,0x10,0x10,0x2,0,0,0x80,0x41,
+0,0x10,0x4,0x21,0x4,0x4,0xc,0x18,0x1c,0x18,
+0x60,0xe0,0x10,0,0xc1,0,0x43,0x1,0xa,0,
+0xe0,0x6,0x30,0x10,0x10,0xa,0,0x40,0x40,0x8,
+0,0x10,0,0x20,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,
+0x2,0,0x4,0,0x80,0x80,0,0,0x20,0,
+0x40,0x10,0x20,0,0,0xf,0x80,0,0,0x31,
+0x80,0,0,0,0x1,0xf0,0,0,0,0,
+0x7f,0xf0,0,0,0,0,0,0x3,0xa,0,
+0x48,0,0,0,0,0,0,0,0x1,0x8c,
+0x1,0x1f,0xc2,0x4,0x4,0x7f,0x8,0,0x20,0x8,
+0x40,0x10,0x80,0x21,0,0x42,0,0x84,0x1,0x10,
+0x41,0x6,0x18,0x10,0x8,0x20,0x10,0x40,0x20,0x80,
+0x40,0x10,0,0x20,0,0x40,0,0x80,0x20,0x30,
+0x40,0x60,0x61,0x80,0xc3,0x1,0x86,0x3,0xc,0x6,
+0x18,0,0,0x58,0x60,0x20,0x40,0x40,0x80,0x81,
+0x1,0x2,0,0x20,0x2,0,0x4,0x88,0x20,0x60,
+0x40,0xc0,0x81,0x81,0x3,0x2,0x6,0x4,0xc,0x20,
+0xa1,0xc,0x18,0x18,0x18,0x30,0x30,0x60,0x60,0xc0,
+0xc0,0x10,0,0x20,0,0x40,0,0x80,0x18,0x30,
+0x20,0x20,0x60,0xc0,0xc1,0x81,0x83,0x3,0x6,0x6,
+0xc,0,0,0x38,0x30,0x10,0xa0,0x21,0x40,0x42,
+0x80,0x85,0,0xa0,0x7,0x6,0x2,0x80,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,0x3,0,0,0,0x24,0,
+0x10,0,0x1c,0x3,0x8c,0,0,0,0x80,0x8,
+0,0,0,0,0,0x70,0,0,0,0xe0,
+0x4,0,0x3,0x80,0x3f,0xe0,0xff,0x80,0x3e,0,
+0x1e,0x1,0xf0,0,0xf0,0x1,0,0x7,0x80,0x3e,
+0,0xe,0,0x38,0,0,0,0,0,0,
+0x1,0x80,0x10,0,0xf0,0x79,0xff,0x80,0x1e,0x7,
+0xfc,0xf,0xff,0xf,0xe0,0x3,0xe0,0x7c,0x7c,0x3f,
+0xe0,0x3c,0x3,0xe0,0xe7,0xff,0x8f,0x7,0xbf,0xc,
+0x3,0xc0,0x3f,0x80,0xf,0x1,0xf0,0x71,0x3e,0,
+0xfe,0x1,0xf8,0,0x40,0xc,0x18,0x7c,0x7c,0x1f,
+0xc0,0xff,0xc0,0x8,0,0x2,0,0x20,0,0,
+0,0,0,0,0x3f,0x71,0xcf,0x80,0x3e,0,
+0xf9,0xc0,0xfc,0x7,0xfc,0x7,0xc8,0x7c,0x7c,0x3f,
+0xe0,0,0x81,0xc3,0xc3,0xff,0x9f,0x31,0x9f,0x1f,
+0x3,0xe0,0x13,0xe0,0x1f,0x20,0xff,0x80,0xbe,0,
+0x3c,0,0xf3,0,0x40,0x6,0x30,0x7c,0x7c,0x6,
+0,0x7f,0xc0,0x8,0,0x10,0,0x20,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,0x2,0,0x4,0x1,0xff,0,
+0,0x1,0xfc,0,0x40,0x10,0x20,0,0,0,
+0,0,0,0x8,0x40,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x2,0xf3,0,0x48,0,0,0x1,0,0,
+0,0,0x2,0x10,0,0,0x80,0x8,0x80,0x2,
+0x8,0,0x78,0x3c,0xf0,0x79,0xe0,0xf3,0xc1,0xe7,
+0x83,0xcf,0x7,0xf9,0xff,0x1,0xe0,0x7f,0xf8,0xff,
+0xf1,0xff,0xe3,0xff,0xc1,0xff,0x3,0xfe,0x7,0xfc,
+0xf,0xf8,0x7f,0xc1,0xf8,0x60,0x1e,0,0x3c,0,
+0x78,0,0xf0,0x1,0xe0,0,0,0x87,0x80,0x1f,
+0x80,0x3f,0,0x7e,0,0xfc,0x1,0xfc,0xf,0x80,
+0x1e,0x70,0x1f,0xb8,0x3f,0x70,0x7e,0xe0,0xfd,0xc1,
+0xfb,0x83,0xf7,0x1f,0x1e,0x3,0xe0,0x7,0xe0,0xf,
+0xc0,0x1f,0x80,0x3f,0x1,0xff,0x3,0xfe,0x7,0xfc,
+0xf,0xf8,0x7,0xc0,0xf8,0xf8,0x1f,0,0x3e,0,
+0x7c,0,0xf8,0x1,0xf0,0,0,0x47,0xc0,0xf,
+0x30,0x1e,0x60,0x3c,0xc0,0x79,0x80,0x60,0x4,0xf8,
+0x1,0x80,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,0x24,0,0x10,0,0,0,0,0,
+0,0,0x40,0x10,0,0,0,0,0,0x60,
+0,0,0,0,0x8,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x30,0,0,
+0,0,0,0,0,0,0x18,0x60,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,0xc,0x30,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x8,0,0x1,
+0,0x20,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x8,0,0,0,0,0,0x80,0,0,0,
+0,0,0,0,0,0,0x10,0,0,0x20,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x4,0,0,0,0x8,0,0x10,
+0,0x20,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,0x2,0,
+0,0,0,0,0,0,0,0,0x40,0x10,
+0x40,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x2,0,0,0x48,0,
+0,0x1,0,0,0,0,0,0,0,0x1,
+0xc0,0x1f,0x80,0x7,0x8,0x10,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x80,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,
+0x80,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,0x40,0x4,0,0x1,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,0x10,0,
+0,0,0,0,0,0,0x40,0x10,0,0,
+0,0,0,0xc0,0,0,0,0,0x8,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x60,0,0,0,0,0,0,0,0,
+0x7,0xc0,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,0x33,0xc0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x8,0,0x1,0,0x20,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x8,0,0,0,0,0,
+0x80,0,0,0,0,0,0,0,0,0,
+0x10,0,0,0x20,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x4,0,0,
+0,0x8,0,0x10,0,0x20,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,0x2,0,0,0,0,0,0,0,
+0,0,0x40,0x1f,0x80,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x2,
+0,0x3,0xce,0,0,0,0x80,0,0,0,
+0,0,0,0,0,0,0,0,0x4,0x10,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x40,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,0x40,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,0x40,0x4,0,0x1,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,0x10,0,0,0,0,0,0,0,
+0x20,0x20,0,0,0,0,0,0x80,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,0x40,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,0xe,0,0,0,0xe0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x10,0,
+0,0,0,0x1,0,0,0,0,0,0,
+0,0,0,0,0x10,0,0,0x20,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x8,0,0,0,0x6,0,0x10,0,0xc0,
+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,0x2,0,0,0,
+0,0,0,0,0,0,0x40,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,0x2,0,0,0,0,0,0x4,
+0x80,0,0,0,0,0,0,0,0,0,
+0,0,0x3,0xe0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x2,0x40,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,0x2,0x40,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,0x80,
+0x4,0,0x2,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,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,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x30,0,0,0,0,0x3,0,0,
+0,0,0,0,0,0,0,0,0x10,0,
+0,0x20,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x8,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,0,0,
+0x2,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,0x2,0,0,
+0,0,0,0x3,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,0x1,0x80,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,0x1,0x80,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,0x80,0x4,0,0x2,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,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,
+0x7f,0xff,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xf,0xc0,0,0,0,
+0,0x7c,0,0,0,0,0,0,0,0,
+0,0,0x7e,0,0x1,0xf8,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xfe,
+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,0,0,0x2,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,0x2,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,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,0xf,0xe0,0x1f,0x80,
+0x3f,0x80,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,
+};
+
+static WORD Courier24_ch_ofst[225] = {
+0,15,30,45,60,75,90,105,120,135,
+150,165,180,195,210,225,240,255,270,285,
+300,315,330,345,360,375,390,405,420,435,
+450,465,480,495,510,525,540,555,570,585,
+600,615,630,645,660,675,690,705,720,735,
+750,765,780,795,810,825,840,855,870,885,
+900,915,930,945,960,975,990,1005,1020,1035,
+1050,1065,1080,1095,1110,1125,1140,1155,1170,1185,
+1200,1215,1230,1245,1260,1275,1290,1305,1320,1335,
+1350,1365,1380,1395,1410,1425,1440,1455,1470,1485,
+1500,1515,1530,1545,1560,1575,1590,1605,1620,1635,
+1650,1665,1680,1695,1710,1725,1740,1755,1770,1785,
+1800,1815,1830,1845,1860,1875,1890,1905,1920,1935,
+1950,1965,1980,1995,2010,2025,2040,2055,2070,2085,
+2100,2115,2130,2145,2160,2175,2190,2205,2220,2235,
+2250,2265,2280,2295,2310,2325,2340,2355,2370,2385,
+2400,2415,2430,2445,2460,2475,2490,2505,2520,2535,
+2550,2565,2580,2595,2610,2625,2640,2655,2670,2685,
+2700,2715,2730,2745,2760,2775,2790,2805,2820,2835,
+2850,2865,2880,2895,2910,2925,2940,2955,2970,2985,
+3000,3015,3030,3045,3060,3075,3090,3105,3120,3135,
+3150,3165,3180,3195,3210,3225,3240,3255,3270,3285,
+3300,3315,3330,3345,3360,
+};
+
+static struct font_hdr Courier24_font = {
+STPROP, 24, "-Adobe-Courier-M-R-N--24-240-75", 32, 255,
+24, 19, 12, 5, 5,
+16, 15, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Courier24_ch_ofst, Courier24_data,
+444, 24,
+NULL,
+0, 0,   /* x/y offset */
+27,        /* lineHeight */
+22,	   /* psHeight */
+};
+
+MgFont *mgCourier24Font()
+{
+return &Courier24_font;
+}
diff --git a/lib/font/mgCourier34.c b/lib/font/mgCourier34.c
new file mode 100644
index 0000000..c7262cc
--- /dev/null
+++ b/lib/font/mgCourier34.c
@@ -0,0 +1,2161 @@
+
+/* Courier34.c - compiled data for font -Adobe-Courier-M-R-N--34-240-10 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 100dpi/courR24.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Courier34_data[20992] = {
+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,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,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,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,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,
+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,
+0x6,0,0,0,0xc0,0,0x40,0,0,0,
+0,0,0,0xe,0,0,0,0,0,0,
+0x6,0,0,0x1,0x80,0,0x40,0,0,0,
+0x3,0,0,0,0xc0,0,0x40,0,0,0,
+0,0,0,0,0,0x6,0,0,0,0x60,
+0,0x40,0,0,0,0,0,0,0,0,
+0,0,0,0x30,0,0,0xc,0,0x4,0,
+0,0,0,0,0xc0,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,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,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,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,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,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,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,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,0,0,0,0,0,0x3,0,0,0x1,
+0x80,0,0xe0,0,0,0,0,0,0,0x1b,
+0,0,0,0,0,0,0x3,0,0,0x3,
+0,0,0xe0,0,0,0,0x1,0x80,0,0x1,
+0x80,0,0xe0,0,0,0,0,0,0,0,
+0,0x3,0,0,0,0xc0,0,0xe0,0,0,
+0,0,0,0,0,0,0,0,0,0x18,
+0,0,0x18,0,0xe,0,0,0,0,0x1,
+0x80,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,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,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,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,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,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,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,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,0,0,0,
+0,0,0x1,0x80,0,0x3,0,0x1,0xb0,0,
+0x38,0x40,0x6,0xc,0,0x11,0,0,0,0,
+0,0,0x1,0x80,0,0x6,0,0x1,0xb0,0,
+0x61,0x80,0,0xc0,0,0x3,0,0x1,0xb0,0,
+0x60,0xc0,0,0,0,0x38,0x40,0x1,0x80,0,
+0x1,0x80,0x1,0xb0,0,0x38,0x40,0xc,0xc,0,
+0,0,0,0,0,0xc,0,0,0x30,0,
+0x1b,0,0x6,0xc,0,0x3,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,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,
+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,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,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,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,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,
+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,0,0,0,0,0,0,0,0xc0,
+0,0x6,0,0x3,0x18,0,0x6e,0xc0,0xf,0x1e,
+0,0x11,0,0,0,0,0,0,0,0xc0,
+0,0xc,0,0x3,0x18,0,0xf3,0xc0,0,0x60,
+0,0x6,0,0x3,0x18,0,0xf1,0xe0,0,0,
+0,0x6e,0xc0,0,0xc0,0,0x3,0,0x3,0x18,
+0,0x6e,0xc0,0x1e,0x1e,0,0,0,0,0,
+0,0x6,0,0,0x60,0,0x31,0x80,0xf,0x1e,
+0,0x6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1c,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,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,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,0x40,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,0x20,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,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,0x8,0,0,0,0,0,
+0,0,0,0,0xc,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,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,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,0x6,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,0x60,0,0xc,0,0x6,
+0xc,0,0x43,0x80,0x6,0xc,0,0x1b,0,0,
+0,0,0,0,0,0x60,0,0x18,0,0x6,
+0xc,0,0x61,0x80,0,0x30,0,0xc,0,0x6,
+0xc,0,0x60,0xc0,0,0,0,0x43,0x80,0,
+0x60,0,0x6,0,0x6,0xc,0,0x43,0x80,0xc,
+0xc,0,0,0,0,0,0,0x3,0,0,
+0xc0,0,0x60,0xc0,0x6,0xc,0,0xc,0,0,
+0,0,0,0,0x6,0,0,0x1,0x80,0,
+0x40,0,0,0,0,0,0,0x36,0,0,
+0,0,0,0,0x6,0,0,0,0xc0,0,
+0x40,0,0,0,0x6,0,0,0x1,0x80,0,
+0,0,0,0,0,0,0,0,0,0x3,
+0,0,0,0xc0,0,0x60,0,0,0,0,
+0,0,0,0,0,0,0,0x60,0,0,
+0x18,0,0,0,0,0,0,0,0xc0,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,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,0x2,0,0,0,0,0x8,0x80,
+0,0x40,0,0,0,0,0,0,0x7,0,
+0,0x4,0,0x40,0,0,0x40,0,0,0,
+0,0,0,0,0,0,0,0,0,0x60,
+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,
+0x1,0xf0,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,
+0xc,0,0,0,0,0,0x40,0,0,0,
+0x6,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,0x1,0x80,
+0,0x40,0,0x30,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,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,0x40,0,0xf,0xf0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x1,0xf0,0,0,0,0x1,0xe0,0,0xf,0,
+0,0xc,0,0,0,0x3,0xff,0x80,0,0,
+0,0,0,0x1c,0,0,0,0,0,0,
+0x18,0,0x61,0x80,0x4,0x3c,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xe,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,0x3e,0,
+0x3,0,0,0x3,0,0,0xe0,0,0,0,
+0,0,0,0x22,0,0,0,0,0,0,
+0x3,0,0,0x1,0x80,0,0xe0,0,0,0,
+0x3,0,0,0x3,0,0,0x80,0,0,0,
+0,0,0,0,0,0x1,0x80,0,0x1,0x80,
+0,0xf0,0,0,0,0,0,0,0,0,
+0,0,0,0x30,0,0,0x30,0,0x4,0,
+0,0,0,0x1,0x80,0xf0,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,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,0x7,
+0,0xf,0x1e,0,0x8,0x80,0,0x40,0,0x3c,
+0,0,0,0,0x7,0,0,0xc,0,0x60,
+0,0,0x40,0,0,0,0,0,0,0,
+0,0,0,0,0,0x40,0x1,0xf0,0,0xc,
+0,0x1,0xf8,0,0x1f,0,0,0x18,0,0x7f,
+0xe0,0,0x7c,0,0xff,0xe0,0x1,0xf0,0,0x1f,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0x18,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,0x7,0xc0,0x4,0,0,0x7c,
+0,0,0xe0,0,0,0,0x3,0,0,0,
+0,0xf0,0,0,0,0,0,0xf,0,0,
+0,0,0x7c,0,0,0,0x78,0,0,0xc,
+0,0,0x18,0x3,0xc0,0,0xf,0xc0,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,0x3,0,0,0x40,0,0x18,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x40,0,0,0,0,0,0,0,
+0,0,0x40,0,0x38,0x10,0x3,0xc,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0x18,0,0,
+0,0x3,0x30,0,0x19,0x80,0,0x18,0,0,
+0,0xe,0x44,0,0,0,0,0,0,0x34,
+0,0,0,0,0,0,0x78,0,0x47,0x80,
+0xc,0x66,0,0x60,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,0x40,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x63,0,0x1,0x80,0,0x6,
+0,0x1,0xb0,0,0x38,0x40,0xc,0x30,0,0x22,
+0,0,0,0,0,0,0x1,0x80,0,0x3,
+0,0x1,0xb0,0,0xc1,0x80,0x1,0x80,0,0x6,
+0,0x1,0xc0,0,0xc3,0,0x1f,0x3,0,0x38,
+0x40,0,0xc0,0,0x3,0,0x1,0x98,0,0x38,
+0x40,0x6,0x18,0,0,0,0,0,0,0x18,
+0,0,0x60,0,0xe,0,0xc,0x18,0,0x3,
+0,0x10,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,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,0x7,0,0xf,0x1e,0,
+0x8,0x80,0x1,0xf2,0,0x66,0,0,0,0,
+0x7,0,0,0x8,0,0x20,0,0,0x40,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x40,0x3,0x18,0,0x3c,0,0x6,0xc,0,
+0x71,0xc0,0,0x28,0,0x40,0,0x1,0xc2,0,
+0x80,0x20,0x6,0xc,0,0x70,0xc0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x3f,0,0x6,0x8,0x1,0xfe,0,0x7f,0xf8,0,
+0x1f,0x10,0x7f,0xe0,0x7,0xff,0xe0,0x7f,0xff,0,
+0x1f,0x10,0x3f,0x1f,0x80,0xff,0xe0,0x1,0xff,0xc7,
+0xf0,0xfc,0x3f,0xe0,0xf,0x80,0x3e,0xf8,0x1f,0xc0,
+0x1f,0,0x7f,0xf0,0,0x1f,0,0x7f,0xf0,0,
+0x1f,0x20,0x3f,0xff,0x87,0xf1,0xfc,0xfe,0xf,0xe7,
+0xe0,0xfc,0x3e,0xf,0x83,0xe0,0xf8,0xf,0xfe,0,
+0x4,0,0x4,0,0,0x4,0,0x1,0xb0,0,
+0,0,0x1,0x80,0,0,0,0x10,0,0,
+0,0,0,0x1,0,0,0,0,0xc3,0,
+0,0,0x8,0,0,0xc,0,0,0x18,0,
+0x40,0,0,0x40,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x6,0,0,0x40,0,0xc,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x40,0,
+0xf,0x80,0,0,0x3,0xe0,0xf8,0,0x40,0,
+0x20,0x10,0x7,0x9e,0,0x1f,0,0x1,0xe0,0,
+0,0,0,0,0,0,0,0x3,0xf8,0,
+0x7f,0xc0,0x2,0x8,0,0,0,0x2,0x18,0,
+0x30,0xc0,0,0x30,0,0,0,0x1c,0x44,0,
+0,0,0,0,0,0x4,0,0,0xe0,0,
+0,0,0x8,0,0xc0,0x80,0x18,0x3,0,0xc0,
+0,0,0x1f,0xe0,0x1,0xfe,0,0x1f,0xe0,0x1,
+0xfe,0,0x1f,0xe0,0x1,0xfe,0,0xf,0xff,0xc0,
+0x1f,0x10,0x7f,0xfe,0x7,0xff,0xe0,0x7f,0xfe,0x7,
+0xff,0xe0,0xf,0xfe,0,0xff,0xe0,0xf,0xfe,0,
+0xff,0xe0,0x7f,0xe0,0xf,0x81,0xfc,0x1,0xf0,0,
+0x1f,0,0x1,0xf0,0,0x1f,0,0x1,0xf0,0,
+0,0,0x1,0xf0,0xc7,0xf1,0xfc,0x7f,0x1f,0xc7,
+0xf1,0xfc,0x7f,0x1f,0xc3,0xe0,0xf8,0x7f,0,0,
+0x41,0,0,0xc0,0,0xc,0,0x3,0x18,0,
+0x6e,0xc0,0x1e,0x78,0,0x36,0,0,0,0,
+0,0,0,0xc0,0,0x6,0,0x3,0x18,0x1,
+0xe3,0xc0,0,0xc0,0,0xc,0,0x3,0x60,0x1,
+0xe7,0x80,0x13,0xce,0,0x6e,0xc0,0,0x60,0,
+0x6,0,0x3,0xc,0,0x6e,0xc0,0xf,0x3c,0,
+0,0,0,0,0,0xc,0,0,0xc0,0,
+0x1b,0,0x1e,0x3c,0,0x6,0,0x10,0,0,
+0x60,0x60,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,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,0x7,0,0xf,0x1e,0,0x8,0x80,0x7,0x1e,
+0,0xc3,0,0,0,0,0x7,0,0,0x18,
+0,0x30,0,0,0x40,0,0x4,0,0,0,
+0,0,0,0,0,0,0,0xc0,0x6,0xc,
+0,0xe4,0,0xc,0x2,0,0xc0,0x60,0,0x28,
+0,0x40,0,0x3,0,0,0x80,0x20,0x4,0x4,
+0,0x40,0x60,0,0,0,0,0,0,0,
+0x80,0,0,0x20,0,0,0xe1,0xc0,0xc,0xc,
+0,0xa,0,0x8,0x6,0,0x71,0xd0,0x10,0x38,
+0,0x80,0x20,0x8,0x1,0,0x71,0xd0,0x8,0x2,
+0,0x4,0,0,0x4,0,0x80,0x20,0x2,0,
+0x2,0x80,0x28,0x1c,0x1,0,0x60,0xc0,0x8,0x1c,
+0,0x71,0xc0,0x8,0x1c,0,0x71,0xa0,0x20,0x40,
+0x81,0,0x10,0x30,0x1,0x82,0,0x8,0x18,0x3,
+0x1,0x80,0x30,0x8,0x2,0,0x4,0,0x6,0,
+0,0x4,0,0x1,0x10,0,0,0,0,0xc0,
+0,0,0,0x10,0,0,0,0,0,0x1,
+0,0,0,0,0x80,0,0,0,0x8,0,
+0,0xc,0,0,0x18,0,0x40,0,0,0x40,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x4,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x4,0,0,0x40,
+0,0x4,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x40,0,0x30,0xc0,0,0,
+0x1,0x80,0x30,0,0x40,0,0x20,0x10,0x3,0xc,
+0,0x71,0xc0,0x3,0x30,0,0,0,0,0,
+0,0,0,0xe,0xe,0,0x7f,0xc0,0x6,0xc,
+0,0,0,0x6,0x8,0,0,0x40,0,0x60,
+0,0,0,0x18,0x44,0,0,0,0,0,
+0,0x4,0,0x3,0xb8,0,0,0,0x8,0x1,
+0x80,0x80,0x30,0x3,0x1,0x80,0,0,0,0xa0,
+0,0xa,0,0,0xa0,0,0xa,0,0,0xa0,
+0,0xa,0,0x1,0x20,0x40,0x71,0xd0,0x8,0x2,
+0,0x80,0x20,0x8,0x2,0,0x80,0x20,0,0x40,
+0,0x4,0,0,0x40,0,0x4,0,0x10,0x38,
+0x1,0xc0,0x10,0x7,0x1c,0,0x71,0xc0,0x7,0x1c,
+0,0x71,0xc0,0x7,0x1c,0,0,0,0x7,0x1d,
+0x81,0,0x10,0x10,0x1,0x1,0,0x10,0x10,0x1,
+0x1,0x80,0x30,0x8,0,0,0xc1,0x80,0,0x60,
+0,0x18,0,0x6,0xc,0,0x43,0x80,0xc,0x30,
+0,0x1c,0,0,0,0,0,0,0,0x60,
+0,0xc,0,0x6,0xc,0,0xc1,0x80,0,0x60,
+0,0x18,0,0x6,0x30,0,0xc3,0,0,0x78,
+0,0x43,0x80,0,0x30,0,0xc,0,0x6,0x6,
+0,0x43,0x80,0x6,0x18,0,0,0,0,0,
+0,0x6,0,0x1,0x80,0,0x31,0x80,0xc,0x18,
+0,0xc,0,0x10,0,0,0xf0,0xf0,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,
+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,0x7,0,0xf,
+0x1e,0,0x19,0x80,0x4,0x6,0,0x81,0,0x1,
+0xf8,0,0x7,0,0,0x10,0,0x10,0,0x8,
+0x42,0,0x4,0,0,0,0,0,0,0,
+0,0,0,0x80,0x4,0x4,0,0x4,0,0x8,
+0x2,0,0,0x20,0,0x48,0,0x40,0,0x2,
+0,0,0,0x60,0xc,0x6,0,0xc0,0x20,0,
+0,0,0,0,0,0x3,0x80,0,0,0x38,
+0,0,0x80,0x40,0x8,0x4,0,0xa,0,0x8,
+0x2,0,0x80,0x30,0x10,0xc,0,0x80,0x20,0x8,
+0x1,0,0xc0,0x30,0x8,0x2,0,0x4,0,0,
+0x4,0,0x80,0x60,0x2,0,0x2,0x80,0x28,0x14,
+0x1,0,0xc0,0x60,0x8,0x2,0,0xc0,0x60,0x8,
+0x2,0,0xc0,0x60,0x20,0x40,0x81,0,0x10,0x10,
+0x1,0x2,0,0x8,0x8,0x2,0,0xc0,0x60,0x8,
+0x6,0,0x4,0,0x2,0,0,0x4,0,0x3,
+0x18,0,0,0,0,0,0,0,0,0x10,
+0,0,0,0,0,0x1,0,0,0,0x1,
+0x80,0,0,0,0x8,0,0,0,0,0,
+0,0,0x40,0,0,0x40,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x4,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x4,0,0,0x40,0,0x4,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x40,0,0x20,0x60,0,0,0,0xc0,0x60,0,
+0x40,0,0x20,0,0,0,0x1,0xc0,0x70,0,
+0x10,0,0,0,0,0,0,0,0,0x18,
+0x3,0,0,0,0x4,0x4,0,0x4,0,0,
+0x18,0,0,0x40,0,0,0,0,0,0x38,
+0x44,0,0,0,0,0,0,0x4,0,0x2,
+0x8,0,0,0,0x8,0x1,0,0x80,0x20,0x6,
+0x3,0,0,0,0x1,0xb0,0,0x1b,0,0x1,
+0xb0,0,0x1b,0,0x1,0xb0,0,0x1b,0,0x1,
+0x20,0x40,0xc0,0x30,0x8,0x2,0,0x80,0x20,0x8,
+0x2,0,0x80,0x20,0,0x40,0,0x4,0,0,
+0x40,0,0x4,0,0x10,0xc,0x1,0x40,0x10,0xc,
+0x6,0,0xc0,0x60,0xc,0x6,0,0xc0,0x60,0xc,
+0x6,0,0,0,0xc,0x7,0x1,0,0x10,0x10,
+0x1,0x1,0,0x10,0x10,0x1,0,0xc0,0x60,0x8,
+0,0,0x80,0x80,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,0xc,
+0x18,0,0,0,0,0xf0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0xc,0,0,0,0,0,0,0,
+0,0,0x60,0xc0,0,0,0,0,0,0x10,
+0,0,0x60,0x60,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,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,0x7,0,0xf,0x1e,0,0x11,0,
+0x8,0x2,0,0x81,0,0x3,0x30,0,0xe,0,
+0,0x30,0,0x18,0,0xf,0x5e,0,0x4,0,
+0,0,0,0,0,0,0,0,0x1,0x80,
+0x4,0x4,0,0x4,0,0x8,0x2,0,0,0x20,
+0,0xc8,0,0x40,0,0x6,0,0,0,0x40,
+0x8,0x2,0,0x80,0x30,0,0,0,0,0,
+0,0xe,0,0,0,0xe,0,0,0x80,0x40,
+0x18,0x4,0,0x11,0,0x8,0x3,0x1,0x80,0x10,
+0x10,0x6,0,0x80,0x20,0x8,0x1,0x1,0x80,0x10,
+0x8,0x2,0,0x4,0,0,0x4,0,0x80,0x40,
+0x2,0,0x2,0x40,0x48,0x12,0x1,0x1,0x80,0x30,
+0x8,0x3,0x1,0x80,0x30,0x8,0x3,0,0x80,0x60,
+0x20,0x40,0x81,0,0x10,0x10,0x1,0x2,0,0x8,
+0xc,0x6,0,0x40,0x40,0x8,0x4,0,0x4,0,
+0x3,0,0,0x4,0,0x6,0xc,0,0,0,
+0,0,0,0,0,0x10,0,0,0,0,
+0,0x1,0,0,0,0x1,0,0,0,0,
+0x8,0,0,0,0,0,0,0,0x40,0,
+0,0x40,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x4,0,
+0,0x40,0,0x4,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,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x1,0xf8,0,0x60,0,
+0x18,0x3,0,0x40,0x40,0,0x40,0,0x30,0,
+0,0,0x3,0,0x18,0,0x10,0,0,0,
+0,0,0,0,0,0x30,0x1,0x80,0,0,
+0x4,0x4,0,0x4,0,0,0x10,0,0x1,0x80,
+0,0,0,0,0,0x30,0x44,0,0,0,
+0,0,0,0x4,0,0x6,0xc,0,0,0,
+0x8,0x3,0,0x80,0x60,0x1c,0x6,0,0,0,
+0x1,0x10,0,0x11,0,0x1,0x10,0,0x11,0,
+0x1,0x10,0,0x11,0,0x3,0x20,0x41,0x80,0x30,
+0x8,0x2,0,0x80,0x20,0x8,0x2,0,0x80,0x20,
+0,0x40,0,0x4,0,0,0x40,0,0x4,0,
+0x10,0x6,0x1,0x60,0x10,0x18,0x3,0x1,0x80,0x30,
+0x18,0x3,0x1,0x80,0x30,0x18,0x3,0,0,0,
+0x8,0x6,0x1,0,0x10,0x10,0x1,0x1,0,0x10,
+0x10,0x1,0,0x40,0x40,0x8,0,0,0x80,0x80,
+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,
+0x3,0x98,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1e,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x10,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,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,0x2,
+0,0x6,0xc,0,0x11,0,0x8,0,0,0xc3,
+0,0x6,0,0,0xe,0,0,0x30,0,0x18,
+0,0x1,0xf0,0,0x4,0,0,0,0,0,
+0,0,0,0,0x1,0,0x8,0x2,0,0x4,
+0,0,0x2,0,0,0x20,0,0x88,0,0x40,
+0,0x4,0,0,0,0x40,0x8,0x2,0,0x80,
+0x30,0,0,0,0,0,0,0x38,0,0,
+0,0x3,0x80,0,0,0x60,0x10,0x4,0,0x11,
+0,0x8,0x1,0x1,0,0x10,0x10,0x2,0,0x80,
+0x20,0x8,0x1,0x1,0,0x10,0x8,0x2,0,0x4,
+0,0,0x4,0,0x80,0x80,0x2,0,0x2,0x40,
+0x48,0x12,0x1,0x1,0,0x10,0x8,0x1,0x1,0,
+0x10,0x8,0x1,0,0x80,0x20,0x20,0x40,0x81,0,
+0x10,0x18,0x3,0x2,0,0x8,0x4,0x4,0,0x60,
+0xc0,0x8,0xc,0,0x4,0,0x1,0,0,0x4,
+0,0x4,0x4,0,0,0,0,0,0,0,
+0,0x10,0,0,0,0,0,0x1,0,0,
+0,0x1,0,0,0,0,0x8,0,0,0,
+0,0,0,0,0x40,0,0,0x40,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x4,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x4,0,0,0x40,0,0x4,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x3,0xe,0,0x40,0,0xd,0xf6,0,0x60,
+0xc0,0,0x40,0,0xf8,0,0,0,0x2,0x1e,
+0x88,0x3,0xf0,0,0,0,0,0,0,0,
+0,0x67,0xe0,0xc0,0,0,0x6,0xc,0,0x4,
+0,0,0x30,0,0x7,0,0,0,0,0,
+0,0x30,0x44,0,0,0,0,0,0,0x4,
+0,0x4,0x4,0,0,0,0x8,0x6,0,0x80,
+0xc0,0x6,0xc,0,0,0,0x1,0x10,0,0x11,
+0,0x1,0x10,0,0x11,0,0x1,0x10,0,0x11,
+0,0x2,0x20,0x41,0,0x10,0x8,0x2,0,0x80,
+0x20,0x8,0x2,0,0x80,0x20,0,0x40,0,0x4,
+0,0,0x40,0,0x4,0,0x10,0x2,0x1,0x20,
+0x10,0x10,0x1,0x1,0,0x10,0x10,0x1,0x1,0,
+0x10,0x10,0x1,0x1,0,0x10,0x18,0xf,0x1,0,
+0x10,0x10,0x1,0x1,0,0x10,0x10,0x1,0,0x60,
+0xc0,0xf,0xf0,0,0x80,0x80,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,0xe,0xc,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xc,0,0,0,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x10,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,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,0x2,0,0x6,0xc,0,
+0x11,0,0xc,0,0,0x66,0,0x4,0,0,
+0xe,0,0,0x20,0,0x8,0,0,0xe0,0,
+0x4,0,0,0,0,0,0,0,0,0,
+0x3,0,0x8,0x2,0,0x4,0,0,0x6,0,
+0,0x20,0x1,0x8,0,0x40,0,0xc,0,0,
+0,0xc0,0xc,0x6,0,0x80,0x30,0,0xe0,0,
+0xe,0,0,0xe0,0,0,0,0,0xe0,0,
+0,0x20,0x10,0x1c,0,0x11,0,0x8,0x1,0x3,
+0,0x10,0x10,0x3,0,0x82,0x20,0x8,0x21,0x3,
+0,0x10,0x8,0x2,0,0x4,0,0,0x4,0,
+0x81,0x80,0x2,0,0x2,0x20,0x88,0x11,0x1,0x3,
+0,0x18,0x8,0x1,0x3,0,0x18,0x8,0x1,0,
+0x80,0x20,0x20,0x40,0x81,0,0x10,0x8,0x2,0x3,
+0xe,0x18,0x2,0x8,0,0x20,0x80,0x8,0x18,0,
+0x4,0,0x1,0x80,0,0x4,0,0xc,0x6,0,
+0,0,0,0,0,0x3e,0,0x11,0xf8,0,
+0x1f,0x10,0x3,0xf1,0,0x3f,0,0x1f,0xfe,0,
+0x3f,0x1e,0x8,0xf0,0,0xfc,0,0xf,0xfc,0,
+0x43,0xf0,0,0x40,0xe,0x70,0xe0,0x38,0xf0,0,
+0x3f,0x80,0x1,0xf8,0,0x3f,0,0xf,0xf,0x80,
+0x1f,0x20,0x3f,0xfc,0x7,0x81,0xe0,0x7e,0xf,0xc7,
+0xc0,0x7c,0x3e,0xf,0x83,0xe0,0xf8,0xf,0xfe,0,
+0x4,0,0,0x40,0,0x4,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xe,0,0x6,0x2,0,
+0x40,0,0x7,0x1c,0,0x20,0x80,0,0x40,0x1,
+0x8c,0,0,0,0x6,0x31,0x8c,0x6,0x30,0,
+0x6,0xc,0,0,0,0,0,0x42,0x30,0x40,
+0,0,0x2,0x8,0,0x4,0,0,0x60,0,
+0x1,0x80,0,0,0x7,0x81,0xe0,0x38,0x44,0,
+0,0,0,0,0,0x4,0,0x6,0xc,0x3,
+0x6,0,0x8,0x4,0,0x80,0x80,0x3,0x8,0,
+0xe,0,0x3,0x18,0,0x31,0x80,0x3,0x18,0,
+0x31,0x80,0x3,0x18,0,0x31,0x80,0x2,0x20,0x43,
+0,0x10,0x8,0x2,0,0x80,0x20,0x8,0x2,0,
+0x80,0x20,0,0x40,0,0x4,0,0,0x40,0,
+0x4,0,0x10,0x3,0x1,0x30,0x10,0x30,0x1,0x83,
+0,0x18,0x30,0x1,0x83,0,0x18,0x30,0x1,0x81,
+0x80,0x30,0x10,0x9,0x1,0,0x10,0x10,0x1,0x1,
+0,0x10,0x10,0x1,0,0x20,0x80,0x8,0x1e,0,
+0x81,0x80,0x3,0xe0,0,0x3e,0,0x3,0xe0,0,
+0x3e,0,0x3,0xe0,0,0x3e,0,0x1f,0xf,0x80,
+0x1f,0x90,0x3,0xf0,0,0x3f,0,0x3,0xf0,0,
+0x3f,0,0xf,0xc0,0,0xfc,0,0xf,0xc0,0,
+0xfc,0,0x8,0x6,0x3,0x8f,0,0x3,0xf8,0,
+0x3f,0x80,0x3,0xf8,0,0x3f,0x80,0x3,0xf8,0,
+0,0,0x1,0xf9,0x87,0x81,0xe0,0x78,0x1e,0x7,
+0x81,0xe0,0x78,0x1e,0x3,0xe0,0xf8,0x11,0xf8,0x3,
+0xe0,0xf8,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,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,0x2,0,0x4,0x8,0,0xff,0xf0,0x6,0,
+0,0x3c,0x1c,0x4,0,0,0xe,0,0,0x20,
+0,0x8,0,0,0xa0,0,0x4,0,0,0,
+0,0,0,0,0,0,0x2,0,0x8,0x2,
+0,0x4,0,0,0x4,0,0,0x40,0x3,0x8,
+0,0x4f,0,0x8,0xf8,0,0,0x80,0x4,0x4,
+0,0x80,0x30,0x1,0xf0,0,0x1f,0,0x1,0x80,
+0,0,0,0,0x30,0,0,0x60,0x10,0x74,
+0,0x20,0x80,0x8,0x3,0x2,0,0,0x10,0x1,
+0,0x82,0,0x8,0x20,0x2,0,0,0x8,0x2,
+0,0x4,0,0,0x4,0,0x82,0,0x2,0,
+0x2,0x20,0x88,0x10,0x81,0x2,0,0x8,0x8,0x1,
+0x2,0,0x8,0x8,0x3,0,0x80,0,0x20,0x40,
+0x81,0,0x10,0x8,0x2,0x1,0xa,0x10,0x1,0x10,
+0,0x11,0,0,0x10,0,0x4,0,0,0x80,
+0,0x4,0,0x8,0x2,0,0,0,0,0,
+0,0xe3,0x80,0x17,0xe,0,0x71,0xf0,0xe,0x1d,
+0,0xe1,0xc0,0x1,0,0,0xe1,0xd0,0xb,0x9c,
+0,0x4,0,0,0x4,0,0x40,0xc0,0,0x40,
+0x2,0x99,0x30,0xb,0x9c,0,0xe0,0xe0,0xf7,0xe,
+0,0xe1,0xde,0x1,0x38,0xc0,0x71,0xe0,0x4,0,
+0,0x80,0x20,0x18,0x3,0x3,0,0x18,0x18,0x3,
+0x1,0,0x10,0x8,0x6,0,0x4,0,0,0x40,
+0,0x4,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1f,0,0xc,0x2,0,0x40,0,0x4,0x4,
+0,0x31,0x80,0,0x40,0x1,0x6,0,0,0,
+0x4,0x60,0x84,0x4,0x10,0,0xc,0x18,0,0,
+0,0,0,0xc2,0x18,0x60,0,0,0x3,0x18,
+0,0x4,0,0,0xc0,0,0,0xc0,0,0,
+0,0x80,0x20,0x18,0x44,0,0,0,0,0,
+0,0x4,0,0x2,0x8,0x1,0x83,0,0x8,0xc,
+0,0x81,0x80,0x1,0x18,0,0x1f,0,0x2,0x8,
+0,0x20,0x80,0x2,0x8,0,0x20,0x80,0x2,0x8,
+0,0x20,0x80,0x2,0x20,0x2,0,0,0x8,0x20,
+0,0x82,0,0x8,0x20,0,0x82,0,0,0x40,
+0,0x4,0,0,0x40,0,0x4,0,0x10,0x1,
+0x1,0x18,0x10,0x20,0,0x82,0,0x8,0x20,0,
+0x82,0,0x8,0x20,0,0x80,0xc0,0x60,0x30,0x19,
+0x81,0,0x10,0x10,0x1,0x1,0,0x10,0x10,0x1,
+0,0x31,0x80,0x8,0x3,0,0x83,0,0xe,0x38,
+0,0xe3,0x80,0xe,0x38,0,0xe3,0x80,0xe,0x38,
+0,0xe3,0x80,0x71,0x98,0xc0,0x70,0xd0,0xe,0x1c,
+0,0xe1,0xc0,0xe,0x1c,0,0xe1,0xc0,0,0x40,
+0,0x4,0,0,0x40,0,0x4,0,0,0x3,
+0,0xb9,0xc0,0xe,0xe,0,0xe0,0xe0,0xe,0xe,
+0,0xe0,0xe0,0xe,0xe,0,0,0,0x7,0xf,
+0,0x80,0x20,0x8,0x2,0,0x80,0x20,0x8,0x2,
+0x1,0,0x10,0x17,0xe,0x1,0,0x10,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,
+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,0x2,0,0x4,
+0x8,0,0x11,0,0x3,0xc0,0,0,0xe0,0x6,
+0,0,0xe,0,0,0x60,0,0xc,0,0x1,
+0xb0,0,0x4,0,0,0,0,0,0,0,
+0,0,0x2,0,0x8,0x2,0,0x4,0,0,
+0xc,0,0,0x80,0x2,0x8,0,0x79,0xc0,0xb,
+0x8e,0,0,0x80,0x3,0x18,0,0xc0,0x50,0x1,
+0xf0,0,0x1f,0,0x7,0,0x3,0xff,0xf8,0,
+0x1c,0,0,0x40,0x10,0xc4,0,0x20,0x80,0x8,
+0x2,0x2,0,0,0x10,0x1,0,0x82,0,0x8,
+0x20,0x2,0,0,0x8,0x2,0,0x4,0,0,
+0x4,0,0x86,0,0x2,0,0x2,0x11,0x8,0x10,
+0x81,0x2,0,0x8,0x8,0x3,0x2,0,0x8,0x8,
+0x2,0,0xc0,0,0,0x40,0x1,0,0x10,0xc,
+0x6,0x1,0xa,0x10,0x1,0xb0,0,0x1b,0,0,
+0x30,0,0x4,0,0,0x80,0,0x4,0,0,
+0,0,0,0,0,0,0,0,0x80,0x14,
+0x3,0,0xc0,0x30,0x18,0x5,0x1,0x80,0x60,0x1,
+0,0x1,0x80,0x50,0xa,0x4,0,0x4,0,0,
+0x4,0,0x41,0x80,0,0x40,0x3,0xe,0x18,0xa,
+0x4,0x1,0x80,0x30,0x14,0x3,0x1,0x80,0x70,0x1,
+0x60,0,0xc0,0x60,0x4,0,0,0x80,0x20,0x8,
+0x2,0x1,0,0x10,0xc,0x6,0x1,0x80,0x30,0x8,
+0xc,0,0x4,0,0,0x40,0,0x4,0,0x3,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xe,0,0x8,
+0,0,0x60,0,0xc,0x6,0,0x1b,0,0,
+0x40,0x1,0x3,0x80,0,0,0xc,0xc0,0x86,0x6,
+0x70,0,0x18,0x30,0x1f,0xff,0x80,0,0,0x82,
+0x8,0x20,0,0,0x1,0xf0,0,0x4,0,0,
+0x80,0,0,0x40,0,0,0,0x80,0x20,0x1c,
+0x44,0,0,0,0,0,0,0x4,0,0x3,
+0xb8,0,0xc1,0x80,0x8,0x18,0,0x83,0,0x1,
+0x30,0,0xe,0,0x2,0x8,0,0x20,0x80,0x2,
+0x8,0,0x20,0x80,0x2,0x8,0,0x20,0x80,0x6,
+0x22,0x2,0,0,0x8,0x20,0,0x82,0,0x8,
+0x20,0,0x82,0,0,0x40,0,0x4,0,0,
+0x40,0,0x4,0,0x10,0x1,0x1,0x8,0x10,0x20,
+0,0x82,0,0x8,0x20,0,0x82,0,0x8,0x20,
+0,0x80,0x60,0xc0,0x20,0x30,0x81,0,0x10,0x10,
+0x1,0x1,0,0x10,0x10,0x1,0,0x1b,0,0x8,
+0x1,0,0x8e,0,0,0x8,0,0,0x80,0,
+0x8,0,0,0x80,0,0x8,0,0,0x80,0,
+0xf0,0x40,0xc0,0x30,0x18,0x6,0x1,0x80,0x60,0x18,
+0x6,0x1,0x80,0x60,0,0x40,0,0x4,0,0,
+0x40,0,0x4,0,0x3,0xf9,0,0xe0,0x40,0x18,
+0x3,0x1,0x80,0x30,0x18,0x3,0x1,0x80,0x30,0x18,
+0x3,0,0,0,0xc,0x6,0,0x80,0x20,0x8,
+0x2,0,0x80,0x20,0x8,0x2,0x1,0x80,0x30,0x1c,
+0x3,0x1,0x80,0x30,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,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,0x2,0,0x4,0x8,0,0x11,0,
+0,0x78,0,0x7,0,0x2,0,0,0xe,0,
+0,0x60,0,0xc,0,0x3,0x18,0,0x4,0,
+0,0,0,0,0,0,0,0,0x6,0,
+0x8,0x2,0,0x4,0,0,0x18,0,0xf,0,
+0x4,0x8,0,0x40,0x60,0xa,0x2,0,0x1,0x80,
+0x1,0xf0,0,0x40,0xd0,0,0xe0,0,0xe,0,
+0x1c,0,0,0,0,0,0x7,0,0x1,0xc0,
+0x10,0x84,0,0x20,0x80,0x8,0x6,0x2,0,0,
+0x10,0x1,0,0xfe,0,0xf,0xe0,0x2,0,0,
+0x8,0x2,0,0x4,0,0,0x4,0,0x9c,0,
+0x2,0,0x2,0x11,0x8,0x10,0x41,0x2,0,0x8,
+0x8,0x2,0x2,0,0x8,0x8,0xc,0,0x70,0,
+0,0x40,0x1,0,0x10,0x4,0x4,0x1,0x11,0x10,
+0,0xe0,0,0xa,0,0,0x60,0,0x4,0,
+0,0xc0,0,0x4,0,0,0,0,0,0,
+0,0,0,0,0xc0,0x18,0x1,0,0x80,0x10,
+0x10,0x3,0x1,0,0x20,0x1,0,0x1,0,0x30,
+0xc,0x6,0,0x4,0,0,0x4,0,0x43,0,
+0,0x40,0x3,0x6,0x8,0xc,0x6,0x1,0,0x10,
+0x18,0x1,0x1,0,0x30,0x1,0x80,0,0x80,0x20,
+0x4,0,0,0x80,0x20,0x8,0x2,0x1,0,0x10,
+0x6,0xc,0,0x80,0x20,0x8,0x18,0,0x4,0,
+0,0x40,0,0x4,0,0xf,0x81,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,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x8,0,0,0x20,0,
+0x8,0x2,0,0xa,0,0,0x40,0x1,0x80,0xc0,
+0,0,0x8,0x80,0x2,0x3,0xdc,0,0x30,0x60,
+0,0,0x80,0,0,0x82,0x8,0x20,0,0,
+0,0,0x3,0xff,0xf8,0x1,0x80,0,0,0x40,
+0,0,0,0x80,0x20,0xf,0x44,0,0xe,0,
+0,0,0,0x4,0,0,0xe0,0,0x60,0xc0,
+0x8,0x11,0x80,0x82,0x3c,0xc3,0x21,0x80,0,0,
+0x6,0xc,0,0x60,0xc0,0x6,0xc,0,0x60,0xc0,
+0x6,0xc,0,0x60,0xc0,0x4,0x22,0x2,0,0,
+0x8,0x20,0,0x82,0,0x8,0x20,0,0x82,0,
+0,0x40,0,0x4,0,0,0x40,0,0x4,0,
+0x10,0x1,0x1,0xc,0x10,0x20,0,0x82,0,0x8,
+0x20,0,0x82,0,0x8,0x20,0,0x80,0x31,0x80,
+0x20,0x60,0x81,0,0x10,0x10,0x1,0x1,0,0x10,
+0x10,0x1,0,0xa,0,0x8,0x1,0x80,0x83,0x80,
+0,0xc,0,0,0xc0,0,0xc,0,0,0xc0,
+0,0xc,0,0,0xc0,0,0x60,0x60,0x80,0x30,
+0x10,0x2,0x1,0,0x20,0x10,0x2,0x1,0,0x20,
+0,0x40,0,0x4,0,0,0x40,0,0x4,0,
+0xe,0xd,0x80,0xc0,0x60,0x10,0x1,0x1,0,0x10,
+0x10,0x1,0x1,0,0x10,0x10,0x1,0,0,0,
+0x10,0xd,0,0x80,0x20,0x8,0x2,0,0x80,0x20,
+0x8,0x2,0,0x80,0x20,0x18,0x1,0,0x80,0x20,
+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,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,0x2,
+0,0,0,0,0x11,0,0,0xe,0,0x38,
+0,0x3,0,0,0,0,0,0x60,0,0xc,
+0,0x2,0x8,0x3,0xff,0xf8,0,0,0x3,0xff,
+0xf8,0,0,0,0x4,0,0x8,0x2,0,0x4,
+0,0,0x30,0,0,0xc0,0xc,0x8,0,0,
+0x20,0xc,0x3,0,0x1,0,0x7,0x1c,0,0x73,
+0x90,0,0,0,0,0,0x30,0,0,0,
+0,0,0x1,0x80,0x7,0,0x10,0x84,0,0x40,
+0x40,0xf,0xfc,0x2,0,0,0x10,0x1,0,0x82,
+0,0x8,0x20,0x2,0,0,0xf,0xfe,0,0x4,
+0,0,0x4,0,0xe6,0,0x2,0,0x2,0x11,
+0x8,0x10,0x41,0x2,0,0x8,0x8,0x1c,0x2,0,
+0x8,0xf,0xf0,0,0x1e,0,0,0x40,0x1,0,
+0x10,0x4,0x4,0x1,0x11,0x10,0,0x40,0,0xe,
+0,0,0xc0,0,0x4,0,0,0x40,0,0x4,
+0,0,0,0,0,0,0,0,0,0,
+0x40,0x18,0x1,0x81,0x80,0x10,0x30,0x3,0x3,0,
+0x30,0x1,0,0x3,0,0x30,0xc,0x2,0,0x4,
+0,0,0x4,0,0x46,0,0,0x40,0x2,0x4,
+0x8,0xc,0x2,0x3,0,0x18,0x18,0x1,0x83,0,
+0x30,0x1,0x80,0,0xc0,0,0x4,0,0,0x80,
+0x20,0xc,0x6,0x1,0xe,0x10,0x3,0x18,0,0xc0,
+0x60,0,0x30,0,0xc,0,0,0x40,0,0x6,
+0,0x18,0xe3,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,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x8,0,0x3,0xfe,0,0x8,0x2,0,0xe,
+0,0,0,0,0xe0,0x70,0,0,0x8,0x80,
+0x2,0,0,0,0x60,0xc0,0,0,0x83,0xff,
+0xf8,0x82,0x18,0x20,0,0,0,0,0,0x4,
+0,0x3,0,0,0x30,0xc0,0,0,0,0x80,
+0x20,0x3,0xc4,0,0x1f,0,0,0,0,0x4,
+0,0,0,0,0x30,0x60,0x8,0x33,0x80,0x86,
+0x66,0x66,0x63,0x80,0,0,0x4,0x4,0,0x40,
+0x40,0x4,0x4,0,0x40,0x40,0x4,0x4,0,0x40,
+0x40,0x4,0x3e,0x2,0,0,0xf,0xe0,0,0xfe,
+0,0xf,0xe0,0,0xfe,0,0,0x40,0,0x4,
+0,0,0x40,0,0x4,0,0x7f,0x1,0x1,0x4,
+0x10,0x20,0,0x82,0,0x8,0x20,0,0x82,0,
+0x8,0x20,0,0x80,0x1b,0,0x20,0x40,0x81,0,
+0x10,0x10,0x1,0x1,0,0x10,0x10,0x1,0,0xe,
+0,0x8,0x1,0x80,0x80,0xc0,0,0x4,0,0,
+0x40,0,0x4,0,0,0x40,0,0x4,0,0,
+0x40,0,0x60,0x21,0x80,0x10,0x30,0x3,0x3,0,
+0x30,0x30,0x3,0x3,0,0x30,0,0x40,0,0x4,
+0,0,0x40,0,0x4,0,0x18,0x3,0x80,0x80,
+0x20,0x30,0x1,0x83,0,0x18,0x30,0x1,0x83,0,
+0x18,0x30,0x1,0x80,0,0,0x30,0x19,0x80,0x80,
+0x20,0x8,0x2,0,0x80,0x20,0x8,0x2,0,0xc0,
+0x60,0x18,0x1,0x80,0xc0,0x60,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,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,0x2,0,0,0,0,
+0x11,0,0,0x3,0x1,0xc0,0,0x7,0x80,0,
+0,0,0,0x60,0,0xc,0,0x6,0xc,0,
+0x4,0,0,0,0,0,0,0,0,0,
+0xc,0,0x8,0x2,0,0x4,0,0,0x60,0,
+0,0x20,0x8,0x8,0,0,0x30,0xc,0x1,0,
+0x1,0,0x4,0x4,0,0x1e,0x10,0,0,0,
+0,0,0x1c,0,0,0,0,0,0x7,0,
+0x4,0,0x10,0x84,0,0x40,0x40,0x8,0x3,0x2,
+0,0,0x10,0x1,0,0x82,0,0x8,0x20,0x2,
+0,0,0x8,0x2,0,0x4,0,0,0x4,0,
+0x81,0,0x2,0,0x2,0xa,0x8,0x10,0x21,0x2,
+0,0x8,0xf,0xf0,0x2,0,0x8,0x8,0x30,0,
+0x3,0x80,0,0x40,0x1,0,0x10,0x6,0xc,0x1,
+0x11,0x10,0,0xe0,0,0x4,0,0,0x80,0,
+0x4,0,0,0x60,0,0x4,0,0,0,0,
+0,0,0,0,0,0,0x40,0x10,0,0x81,
+0,0,0x20,0x1,0x2,0,0x10,0x1,0,0x2,
+0,0x10,0x8,0x2,0,0x4,0,0,0x4,0,
+0x4c,0,0,0x40,0x2,0x4,0x8,0x8,0x2,0x2,
+0,0x8,0x10,0,0x82,0,0x10,0x1,0,0,
+0x70,0,0x4,0,0,0x80,0x20,0x4,0x4,0x1,
+0xa,0x10,0x1,0xb0,0,0x40,0x40,0,0x60,0,
+0x18,0,0,0x40,0,0x3,0,0x10,0x36,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,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x8,0,0,
+0x20,0,0x8,0x2,0,0xff,0xe0,0,0,0,
+0x30,0x18,0,0,0x8,0x80,0x2,0,0,0,
+0xc1,0x80,0,0,0x80,0,0,0x82,0x30,0x20,
+0,0,0,0,0,0x4,0,0x6,0x8,0,
+0x19,0x80,0,0,0,0x80,0x20,0,0x44,0,
+0x1f,0,0,0,0,0x4,0,0,0,0,
+0x18,0x30,0x7f,0x62,0x87,0xec,0xc2,0x3c,0xc2,0x80,
+0,0,0x4,0x4,0,0x40,0x40,0x4,0x4,0,
+0x40,0x40,0x4,0x4,0,0x40,0x40,0x4,0x22,0x2,
+0,0,0x8,0x20,0,0x82,0,0x8,0x20,0,
+0x82,0,0,0x40,0,0x4,0,0,0x40,0,
+0x4,0,0x10,0x1,0x1,0x6,0x10,0x20,0,0x82,
+0,0x8,0x20,0,0x82,0,0x8,0x20,0,0x80,
+0xe,0,0x20,0xc0,0x81,0,0x10,0x10,0x1,0x1,
+0,0x10,0x10,0x1,0,0x4,0,0x8,0x1,0,
+0x80,0x20,0,0x4,0,0,0x40,0,0x4,0,
+0,0x40,0,0x4,0,0,0x40,0x1e,0x40,0x21,
+0,0x10,0x20,0x1,0x2,0,0x10,0x20,0x1,0x2,
+0,0x10,0,0x40,0,0x4,0,0,0x40,0,
+0x4,0,0x30,0x1,0x80,0x80,0x20,0x20,0,0x82,
+0,0x8,0x20,0,0x82,0,0x8,0x20,0,0x83,
+0xff,0xf0,0x20,0x30,0x80,0x80,0x20,0x8,0x2,0,
+0x80,0x20,0x8,0x2,0,0x40,0x40,0x10,0,0x80,
+0x40,0x40,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,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,0x2,0,0,0,0,0x11,0,0,0x1,
+0,0x3,0xc0,0xc,0x86,0,0,0,0,0x60,
+0,0xc,0,0,0,0,0x4,0,0,0,
+0,0,0,0,0,0,0x8,0,0x8,0x2,
+0,0x4,0,0,0xc0,0,0,0x10,0x10,0x8,
+0,0,0x10,0xc,0x1,0,0x3,0,0xc,0x6,
+0,0,0x20,0,0,0,0,0,0x7,0,
+0,0,0,0,0x1c,0,0x4,0,0x10,0xc4,
+0,0x40,0x40,0x8,0x1,0x2,0,0,0x10,0x1,
+0,0x82,0,0x8,0x20,0x2,0x3,0xf8,0x8,0x2,
+0,0x4,0,0x10,0x4,0,0x81,0x80,0x2,0,
+0x2,0xa,0x8,0x10,0x21,0x2,0,0x8,0x8,0,
+0x2,0,0x8,0x8,0x18,0,0,0xc0,0,0x40,
+0x1,0,0x10,0x2,0x8,0x1,0x11,0x10,0x1,0x10,
+0,0x4,0,0x1,0x80,0,0x4,0,0,0x20,
+0,0x4,0,0,0,0,0,0,0,0,
+0,0x7f,0xc0,0x10,0,0x81,0,0,0x20,0x1,
+0x3,0xff,0xf0,0x1,0,0x2,0,0x10,0x8,0x2,
+0,0x4,0,0,0x4,0,0x78,0,0,0x40,
+0x2,0x4,0x8,0x8,0x2,0x2,0,0x8,0x10,0,
+0x82,0,0x10,0x1,0,0,0x1f,0,0x4,0,
+0,0x80,0x20,0x6,0xc,0x1,0x8a,0x30,0,0xe0,
+0,0x60,0xc0,0,0x40,0,0x38,0,0,0x40,
+0,0x3,0x80,0,0x1c,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,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xc,0,0,0x20,0,0xc,0x6,
+0,0x4,0,0,0,0,0x18,0x8,0,0,
+0x8,0xc0,0x2,0x7,0xfc,0x1,0x83,0,0,0,
+0x80,0,0,0x83,0xe0,0x20,0,0,0,0,
+0,0x4,0,0x7,0xf8,0,0xf,0,0,0,
+0,0x80,0x20,0,0x44,0,0xe,0,0,0,
+0,0x3f,0x80,0x7,0xfc,0,0xc,0x18,0,0x46,
+0x80,0x18,0x6,0x1,0x86,0x80,0,0,0xc,0x6,
+0,0xc0,0x60,0xc,0x6,0,0xc0,0x60,0xc,0x6,
+0,0xc0,0x60,0xc,0x22,0x2,0,0,0x8,0x20,
+0,0x82,0,0x8,0x20,0,0x82,0,0,0x40,
+0,0x4,0,0,0x40,0,0x4,0,0x10,0x1,
+0x1,0x2,0x10,0x20,0,0x82,0,0x8,0x20,0,
+0x82,0,0x8,0x20,0,0x80,0xe,0,0x21,0x80,
+0x81,0,0x10,0x10,0x1,0x1,0,0x10,0x10,0x1,
+0,0x4,0,0x8,0x3,0,0x80,0x30,0x7,0xfc,
+0,0x7f,0xc0,0x7,0xfc,0,0x7f,0xc0,0x7,0xfc,
+0,0x7f,0xc0,0x73,0xff,0xe1,0,0,0x3f,0xff,
+0x3,0xff,0xf0,0x3f,0xff,0x3,0xff,0xf0,0,0x40,
+0,0x4,0,0,0x40,0,0x4,0,0x20,0,
+0x80,0x80,0x20,0x20,0,0x82,0,0x8,0x20,0,
+0x82,0,0x8,0x20,0,0x80,0,0,0x20,0x60,
+0x80,0x80,0x20,0x8,0x2,0,0x80,0x20,0x8,0x2,
+0,0x60,0xc0,0x10,0,0x80,0x60,0xc0,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,
+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,0x1,0xff,0xe0,0,0x1,0,0x6,0x60,0x8,
+0xcc,0,0,0,0,0x60,0,0xc,0,0,
+0,0,0x4,0,0,0,0,0,0,0,
+0,0,0x8,0,0x8,0x2,0,0x4,0,0x1,
+0x80,0,0,0x10,0x1f,0xff,0,0,0x10,0xc,
+0x1,0,0x2,0,0x8,0x2,0,0,0x20,0,
+0,0,0,0,0x1,0x80,0x3,0xff,0xf8,0,
+0x30,0,0x4,0,0x10,0x64,0,0xff,0xe0,0x8,
+0x1,0x82,0,0,0x10,0x1,0,0x80,0,0x8,
+0,0x2,0,0x10,0x8,0x2,0,0x4,0,0x10,
+0x4,0,0x80,0x80,0x2,0,0x82,0x4,0x8,0x10,
+0x11,0x2,0,0x8,0x8,0,0x2,0,0x8,0x8,
+0xc,0,0,0x60,0,0x40,0x1,0,0x10,0x3,
+0x18,0x1,0x31,0x90,0x2,0x8,0,0x4,0,0x3,
+0x1,0,0x4,0,0,0x20,0,0x4,0,0,
+0,0,0,0,0,0,0x1,0xc0,0xc0,0x10,
+0,0x81,0,0,0x20,0x1,0x2,0,0,0x1,
+0,0x2,0,0x10,0x8,0x2,0,0x4,0,0,
+0x4,0,0x4c,0,0,0x40,0x2,0x4,0x8,0x8,
+0x2,0x2,0,0x8,0x10,0,0x82,0,0x10,0x1,
+0,0,0x1,0xc0,0x4,0,0,0x80,0x20,0x2,
+0x8,0,0x9b,0x20,0,0xe0,0,0x20,0x80,0,
+0xc0,0,0xc,0,0,0x40,0,0x6,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x4,0,0x6,
+0x2,0,0x20,0,0x4,0x4,0,0x4,0,0,
+0,0,0xe,0x8,0,0,0xc,0x60,0xc6,0,
+0,0x3,0x87,0,0,0,0x80,0,0,0xc2,
+0x30,0x60,0,0,0,0,0,0x4,0,0,
+0,0,0,0,0,0,0,0x80,0x20,0,
+0x44,0,0,0,0,0,0,0,0,0,
+0,0,0xe,0x1c,0,0xcc,0x80,0x10,0x4,0x1,
+0xc,0x80,0x4,0,0xf,0xfe,0,0xff,0xe0,0xf,
+0xfe,0,0xff,0xe0,0xf,0xfe,0,0xff,0xe0,0xf,
+0xe0,0x2,0,0,0x8,0,0,0x80,0,0x8,
+0,0,0x80,0,0,0x40,0,0x4,0,0,
+0x40,0,0x4,0,0x10,0x1,0x1,0x3,0x10,0x30,
+0x1,0x83,0,0x18,0x30,0x1,0x83,0,0x18,0x30,
+0x1,0x80,0x1b,0,0x33,0x1,0x81,0,0x10,0x10,
+0x1,0x1,0,0x10,0x10,0x1,0,0x4,0,0x8,
+0x1e,0,0x80,0x10,0x1c,0xc,0x1,0xc0,0xc0,0x1c,
+0xc,0x1,0xc0,0xc0,0x1c,0xc,0x1,0xc0,0xc0,0xc0,
+0xc0,0x1,0,0,0x20,0,0x2,0,0,0x20,
+0,0x2,0,0,0,0x40,0,0x4,0,0,
+0x40,0,0x4,0,0x20,0,0x80,0x80,0x20,0x20,
+0,0x82,0,0x8,0x20,0,0x82,0,0x8,0x20,
+0,0x80,0,0,0x20,0xc0,0x80,0x80,0x20,0x8,
+0x2,0,0x80,0x20,0x8,0x2,0,0x20,0x80,0x10,
+0,0x80,0x20,0x80,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,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,0x11,0,
+0x8,0x3,0,0xc,0x30,0x18,0x48,0,0,0,
+0,0x60,0,0xc,0,0,0,0,0x4,0,
+0,0,0,0,0,0,0,0,0x18,0,
+0xc,0x6,0,0x4,0,0x3,0,0,0,0x10,
+0,0x8,0,0,0x10,0xc,0x1,0,0x2,0,
+0x8,0x2,0,0,0x20,0,0,0,0,0,
+0,0xe0,0,0,0,0,0xe0,0,0,0,
+0x10,0x3e,0,0x80,0x20,0x8,0,0x83,0,0,
+0x10,0x3,0,0x80,0x10,0x8,0,0x3,0,0x10,
+0x8,0x2,0,0x4,0,0x10,0x4,0,0x80,0xc0,
+0x2,0,0x82,0x4,0x8,0x10,0x11,0x3,0,0x18,
+0x8,0,0x3,0,0x18,0x8,0x6,0x1,0,0x20,
+0,0x40,0x1,0,0x10,0x1,0x10,0x1,0x20,0x90,
+0x6,0xc,0,0x4,0,0x2,0x1,0,0x4,0,
+0,0x30,0,0x4,0,0,0,0,0,0,
+0,0,0x3,0,0x40,0x10,0,0x81,0,0,
+0x20,0x1,0x2,0,0,0x1,0,0x2,0,0x10,
+0x8,0x2,0,0x4,0,0,0x4,0,0x46,0,
+0,0x40,0x2,0x4,0x8,0x8,0x2,0x2,0,0x8,
+0x10,0,0x82,0,0x10,0x1,0,0,0,0x60,
+0x4,0,0,0x80,0x20,0x2,0x8,0,0x91,0x20,
+0x1,0xb0,0,0x31,0x80,0x1,0x80,0,0x4,0,
+0,0x40,0,0x4,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,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x4,0,0x3,0xe,0,0x20,0,
+0x7,0x1c,0,0xff,0xe0,0,0x40,0,0x3,0x8,
+0,0,0x4,0x31,0x84,0,0,0x1,0x83,0,
+0,0,0,0,0,0x42,0x18,0x40,0,0,
+0,0,0,0x4,0,0,0,0,0,0,
+0,0,0,0x80,0x20,0,0x44,0,0,0,
+0,0,0,0,0,0,0,0,0xc,0x18,
+0x1,0x88,0x80,0x30,0xc,0x3,0x8,0x80,0x4,0,
+0x8,0x2,0,0x80,0x20,0x8,0x2,0,0x80,0x20,
+0x8,0x2,0,0x80,0x20,0x8,0x20,0x3,0,0,
+0x8,0x1,0,0x80,0x10,0x8,0x1,0,0x80,0x10,
+0,0x40,0,0x4,0,0,0x40,0,0x4,0,
+0x10,0x3,0x1,0x1,0x90,0x10,0x1,0x1,0,0x10,
+0x10,0x1,0x1,0,0x10,0x10,0x1,0,0x31,0x80,
+0x12,0x1,0x1,0,0x10,0x10,0x1,0x1,0,0x10,
+0x10,0x1,0,0x4,0,0xf,0xf0,0,0x80,0x10,
+0x30,0x4,0x3,0,0x40,0x30,0x4,0x3,0,0x40,
+0x30,0x4,0x3,0,0x40,0x80,0x40,0x1,0,0,
+0x20,0,0x2,0,0,0x20,0,0x2,0,0,
+0,0x40,0,0x4,0,0,0x40,0,0x4,0,
+0x20,0,0x80,0x80,0x20,0x20,0,0x82,0,0x8,
+0x20,0,0x82,0,0x8,0x20,0,0x80,0,0,
+0x21,0x80,0x80,0x80,0x20,0x8,0x2,0,0x80,0x20,
+0x8,0x2,0,0x31,0x80,0x10,0,0x80,0x31,0x80,
+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,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,0x11,0,0xc,0x6,0,0x8,
+0x10,0x10,0x68,0,0,0,0,0x20,0,0x8,
+0,0,0,0,0x4,0,0x1,0xe0,0,0,
+0,0,0,0,0x10,0,0x4,0x4,0,0x4,
+0,0x6,0,0,0,0x10,0,0x8,0,0,
+0x30,0x4,0x1,0,0x2,0,0x8,0x2,0,0,
+0x40,0,0,0,0x1e,0,0,0x38,0,0,
+0,0x3,0x80,0,0,0,0x10,0,0,0x80,
+0x20,0x8,0,0x81,0,0,0x10,0x2,0,0x80,
+0x10,0x8,0,0x1,0,0x10,0x8,0x2,0,0x4,
+0,0x10,0x4,0,0x80,0x40,0x2,0,0x82,0,
+0x8,0x10,0x9,0x1,0,0x10,0x8,0,0x1,0,
+0x10,0x8,0x2,0x1,0,0x20,0,0x40,0x1,0x80,
+0x30,0x1,0x10,0x1,0xa0,0xb0,0x4,0x4,0,0x4,
+0,0x6,0x1,0,0x4,0,0,0x10,0,0x4,
+0,0,0,0,0,0,0,0,0x2,0,
+0x40,0x18,0x1,0x81,0x80,0,0x30,0x3,0x3,0,
+0,0x1,0,0x3,0,0x30,0x8,0x2,0,0x4,
+0,0,0x4,0,0x43,0,0,0x40,0x2,0x4,
+0x8,0x8,0x2,0x3,0,0x18,0x18,0x1,0x83,0,
+0x30,0x1,0,0x1,0,0x30,0x4,0,0,0x80,
+0x20,0x3,0x18,0,0x91,0x20,0x3,0x18,0,0x11,
+0,0x3,0,0,0x4,0,0,0x40,0,0x4,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x4,
+0,0x1,0xf8,0,0x20,0,0xd,0xf6,0,0x4,
+0,0,0x40,0,0x1,0xf8,0,0,0x6,0x1f,
+0xc,0,0,0,0xc1,0x80,0,0,0,0,
+0,0x67,0xc,0xc0,0,0,0,0,0,0x4,
+0,0,0,0,0,0,0,0,0,0x80,
+0x20,0,0x44,0,0,0,0,0,0,0,
+0,0,0,0,0x18,0x30,0x1,0x18,0x80,0x60,
+0x38,0x6,0x18,0x80,0xc,0,0x18,0x3,0x1,0x80,
+0x30,0x18,0x3,0x1,0x80,0x30,0x18,0x3,0x1,0x80,
+0x30,0x18,0x20,0x21,0,0x8,0x8,0x1,0,0x80,
+0x10,0x8,0x1,0,0x80,0x10,0,0x40,0,0x4,
+0,0,0x40,0,0x4,0,0x10,0x2,0x1,0,
+0x90,0x18,0x3,0x1,0x80,0x30,0x18,0x3,0x1,0x80,
+0x30,0x18,0x3,0,0x60,0xc0,0x1e,0x3,0x1,0x80,
+0x30,0x18,0x3,0x1,0x80,0x30,0x18,0x3,0,0x4,
+0,0x8,0,0,0x80,0x10,0x20,0x4,0x2,0,
+0x40,0x20,0x4,0x2,0,0x40,0x20,0x4,0x2,0,
+0x40,0x80,0x60,0x1,0x80,0,0x20,0,0x2,0,
+0,0x20,0,0x2,0,0,0,0x40,0,0x4,
+0,0,0x40,0,0x4,0,0x30,0x1,0x80,0x80,
+0x20,0x30,0x1,0x83,0,0x18,0x30,0x1,0x83,0,
+0x18,0x30,0x1,0x80,0,0,0x33,0x1,0x80,0x80,
+0x20,0x8,0x2,0,0x80,0x20,0x8,0x2,0,0x11,
+0,0x18,0x1,0x80,0x11,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,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,
+0x11,0,0xf,0x1c,0,0x8,0x10,0x18,0x38,0,
+0,0,0,0x20,0,0x8,0,0,0,0,
+0x4,0,0x1,0xe0,0,0,0,0,0xe0,0,
+0x30,0,0x4,0x4,0,0x4,0,0xc,0,0,
+0,0x30,0,0x8,0x1,0x80,0x20,0x6,0x3,0,
+0x6,0,0xc,0x6,0,0,0xc0,0,0xe0,0,
+0x1e,0,0,0xe,0,0,0,0xe,0,0,
+0,0,0x18,0,0x1,0,0x10,0x8,0x1,0x81,
+0x80,0x10,0x10,0x6,0,0x80,0x10,0x8,0,0x1,
+0x80,0x10,0x8,0x2,0,0x4,0,0x18,0xc,0,
+0x80,0x40,0x2,0,0x82,0,0x8,0x10,0x9,0x1,
+0x80,0x30,0x8,0,0x1,0x80,0x30,0x8,0x3,0x1,
+0x80,0x20,0,0x40,0,0x80,0x20,0,0xa0,0,
+0xa0,0xa0,0x8,0x2,0,0x4,0,0xc,0x1,0,
+0x4,0,0,0x18,0,0x4,0,0,0,0,
+0,0,0,0,0x2,0,0x40,0x18,0x1,0,
+0x80,0x18,0x10,0x3,0x1,0,0,0x1,0,0x1,
+0,0x30,0x8,0x2,0,0x4,0,0,0x4,0,
+0x41,0x80,0,0x40,0x2,0x4,0x8,0x8,0x2,0x1,
+0,0x10,0x18,0x1,0x1,0,0x30,0x1,0,0x1,
+0,0x30,0x4,0,0,0x80,0x60,0x1,0x10,0,
+0xb1,0xa0,0x6,0xc,0,0x1b,0,0x6,0x2,0,
+0x4,0,0,0x40,0,0x4,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x4,0,0,0x40,0,
+0x60,0,0x18,0x3,0,0x4,0,0,0x40,0,
+0,0xc0,0,0,0x3,0,0x18,0,0,0,
+0x60,0xc0,0,0,0,0,0,0x30,0x1,0x80,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xc0,0x60,0,0x44,0,
+0,0,0,0,0,0,0,0,0,0,
+0x30,0x60,0x3,0x1f,0xc0,0x40,0x60,0xc,0x1f,0xc0,
+0x18,0,0x10,0x1,0x1,0,0x10,0x10,0x1,0x1,
+0,0x10,0x10,0x1,0x1,0,0x10,0x10,0x20,0x21,
+0x80,0x10,0x8,0x1,0,0x80,0x10,0x8,0x1,0,
+0x80,0x10,0,0x40,0,0x4,0,0,0x40,0,
+0x4,0,0x10,0x6,0x1,0,0xd0,0x8,0x2,0,
+0x80,0x20,0x8,0x2,0,0x80,0x20,0x8,0x2,0,
+0xc0,0x60,0xc,0x2,0,0x80,0x20,0x8,0x2,0,
+0x80,0x20,0x8,0x2,0,0x4,0,0x8,0,0,
+0x88,0x30,0x20,0x4,0x2,0,0x40,0x20,0x4,0x2,
+0,0x40,0x20,0x4,0x2,0,0x40,0x80,0xe0,0,
+0x80,0x8,0x30,0,0x3,0,0,0x30,0,0x3,
+0,0,0,0x40,0,0x4,0,0,0x40,0,
+0x4,0,0x10,0x1,0,0x80,0x20,0x10,0x1,0x1,
+0,0x10,0x10,0x1,0x1,0,0x10,0x10,0x1,0,
+0xc,0,0x16,0x1,0,0x80,0x60,0x8,0x6,0,
+0x80,0x60,0x8,0x6,0,0x1b,0,0x18,0x1,0,
+0x1b,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,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,0x7,0,0,0,0,0x13,0,0x9,0xf0,
+0,0xc,0x30,0x8,0x30,0,0,0,0,0x30,
+0,0x18,0,0,0,0,0x4,0,0x3,0xc0,
+0,0,0,0x1,0xf0,0,0x20,0,0x6,0xc,
+0,0x4,0,0x18,0,0x1,0x80,0x60,0,0x8,
+0,0xc0,0x60,0x2,0x2,0,0x4,0,0x4,0x4,
+0,0x1,0x80,0x1,0xf0,0,0x3c,0,0,0x3,
+0x80,0,0,0x38,0,0,0xe,0,0x8,0,
+0x1,0,0x10,0x8,0x1,0,0x80,0x70,0x10,0xc,
+0,0x80,0x10,0x8,0,0,0xc0,0x10,0x8,0x2,
+0,0x4,0,0x8,0x8,0,0x80,0x60,0x2,0,
+0x82,0,0x8,0x10,0x5,0,0xc0,0x60,0x8,0,
+0,0xe0,0xe0,0x8,0x1,0x1,0xc0,0x60,0,0x40,
+0,0xc0,0x60,0,0xa0,0,0xa0,0xa0,0x18,0x3,
+0,0x4,0,0x8,0x1,0,0x4,0,0,0x8,
+0,0x4,0,0,0,0,0,0,0,0,
+0x2,0,0xc0,0x14,0x3,0,0xc0,0x30,0x18,0x5,
+0x1,0x80,0x30,0x1,0,0x1,0x80,0x50,0x8,0x2,
+0,0x4,0,0,0x4,0,0x40,0xc0,0,0x40,
+0x2,0x4,0x8,0x8,0x2,0x1,0x80,0x30,0x14,0x3,
+0x1,0x80,0x70,0x1,0,0x1,0x80,0x60,0x6,0x3,
+0,0xc0,0x60,0x1,0xb0,0,0xe0,0xe0,0xc,0x6,
+0,0xa,0,0x4,0x2,0,0x4,0,0,0x40,
+0,0x4,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x4,0,0,0x40,0,0x40,0x10,0,0,
+0,0x4,0,0,0x40,0,0,0x40,0,0,
+0x1,0x80,0x30,0,0,0,0x30,0x60,0,0,
+0,0,0,0x18,0x3,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xc0,0xe0,0,0x44,0,0,0,0,0,
+0,0,0,0,0,0,0x60,0xc0,0x6,0,
+0x80,0xc0,0xc0,0x18,0,0x80,0x70,0,0x10,0x1,
+0x1,0,0x10,0x10,0x1,0x1,0,0x10,0x10,0x1,
+0x1,0,0x10,0x10,0x20,0x20,0xc0,0x70,0x8,0x1,
+0,0x80,0x10,0x8,0x1,0,0x80,0x10,0,0x40,
+0,0x4,0,0,0x40,0,0x4,0,0x10,0xc,
+0x1,0,0x50,0xc,0x6,0,0xc0,0x60,0xc,0x6,
+0,0xc0,0x60,0xc,0x6,0x1,0x80,0x30,0xc,0x6,
+0,0xc0,0x60,0xc,0x6,0,0xc0,0x60,0xc,0x6,
+0,0x4,0,0x8,0,0,0x88,0x20,0x20,0xc,
+0x2,0,0xc0,0x20,0xc,0x2,0,0xc0,0x20,0xc,
+0x2,0,0xc0,0xc1,0x50,0x60,0xc0,0x38,0x18,0x3,
+0x1,0x80,0x30,0x18,0x3,0x1,0x80,0x30,0,0x40,
+0,0x4,0,0,0x40,0,0x4,0,0x18,0x3,
+0,0x80,0x20,0x18,0x3,0x1,0x80,0x30,0x18,0x3,
+0x1,0x80,0x30,0x18,0x3,0,0x1e,0,0x1c,0x6,
+0,0xc0,0xe0,0xc,0xe,0,0xc0,0xe0,0xc,0xe,
+0,0xa,0,0x1c,0x3,0,0xa,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,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,0xf,0x80,0,
+0,0,0x22,0,0,0x40,0,0x6,0x60,0xc,
+0x78,0,0,0,0,0x30,0,0x18,0,0,
+0,0,0x4,0,0x3,0xc0,0,0,0,0x1,
+0xf0,0,0x60,0,0x3,0x18,0,0x4,0,0x10,
+0x1,0,0xe1,0xc0,0,0x8,0,0x71,0xc0,0x3,
+0x8e,0,0x4,0,0x7,0x1c,0,0xe,0,0x1,
+0xf0,0,0x38,0,0,0,0x80,0,0,0x20,
+0,0,0x1f,0,0xc,0,0x3,0,0x18,0x8,
+0x3,0,0x71,0xc0,0x10,0x38,0,0x80,0x10,0x8,
+0,0,0x70,0x70,0x8,0x2,0,0x4,0,0xc,
+0x38,0,0x80,0x20,0x2,0,0x82,0,0x8,0x10,
+0x7,0,0x60,0xc0,0x8,0,0,0x31,0x80,0x8,
+0x1,0x81,0x71,0xc0,0,0x40,0,0x71,0xc0,0,
+0xe0,0,0xc0,0x60,0x30,0x1,0x80,0x4,0,0x18,
+0x1,0,0x4,0,0,0xc,0,0x4,0,0,
+0,0,0,0,0,0,0x3,0x3,0xc0,0x17,
+0xe,0,0x71,0xc0,0xe,0x1d,0,0xe0,0xe0,0x1,
+0,0,0xe1,0xd0,0x8,0x2,0,0x4,0,0,
+0x4,0,0x40,0x60,0,0x40,0x2,0x4,0x8,0x8,
+0x2,0,0xe0,0xe0,0x17,0xe,0,0xe1,0xd0,0x1,
+0,0x1,0xf1,0xc0,0x3,0xe,0,0x61,0xa0,0,
+0xa0,0,0x40,0x40,0x18,0x3,0,0xe,0,0xc,
+0x2,0,0x4,0,0,0x40,0,0x4,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x4,0,0,
+0x40,0,0xc0,0x30,0,0,0,0x4,0,0,
+0x40,0,0x80,0x40,0,0,0,0xf1,0xe0,0,
+0,0,0x18,0x30,0,0,0,0,0,0xe,
+0xe,0,0,0,0,0,0x3,0xff,0xf8,0,
+0,0,0,0,0,0,0,0xe1,0xa0,0,
+0x44,0,0,0,0,0,0,0,0,0,
+0,0,0xc1,0x80,0x4,0,0x81,0x81,0x80,0x30,
+0,0x80,0x40,0,0x30,0x1,0x83,0,0x18,0x30,
+0x1,0x83,0,0x18,0x30,0x1,0x83,0,0x18,0x10,
+0x20,0x20,0x71,0xc0,0x8,0x1,0,0x80,0x10,0x8,
+0x1,0,0x80,0x10,0,0x40,0,0x4,0,0,
+0x40,0,0x4,0,0x10,0x38,0x1,0,0x70,0x7,
+0x1c,0,0x71,0xc0,0x7,0x1c,0,0x71,0xc0,0x7,
+0x1c,0x1,0,0x10,0x1f,0xc,0,0x71,0xc0,0x7,
+0x1c,0,0x71,0xc0,0x7,0x1c,0,0x4,0,0x8,
+0,0,0x8c,0x60,0x30,0x3c,0x3,0x3,0xc0,0x30,
+0x3c,0x3,0x3,0xc0,0x30,0x3c,0x3,0x3,0xc0,0x63,
+0x58,0xc0,0x70,0xe0,0xe,0xe,0,0xe0,0xe0,0xe,
+0xe,0,0xe0,0xe0,0,0x40,0,0x4,0,0,
+0x40,0,0x4,0,0x6,0xe,0,0x80,0x20,0xe,
+0xe,0,0xe0,0xe0,0xe,0xe,0,0xe0,0xe0,0xe,
+0xe,0,0xc,0,0x1e,0x1c,0,0x61,0xa0,0x6,
+0x1a,0,0x61,0xa0,0x6,0x1a,0,0xe,0,0x17,
+0xe,0,0xe,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,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,0x7,0,0,0,0,0x22,0,
+0,0x40,0,0x3,0xc0,0x7,0xce,0,0,0,
+0,0x10,0,0x10,0,0,0,0,0,0,
+0x3,0,0,0,0,0,0xe0,0,0x40,0,
+0x1,0xf0,0,0xff,0xe0,0x1f,0xff,0,0x3f,0,
+0,0x7f,0,0x1f,0,0,0xf8,0,0x4,0,
+0x1,0xf0,0,0x78,0,0,0xe0,0,0x38,0,
+0,0,0,0,0,0,0,0,0xe,0,
+0x6,0,0xf,0xe0,0xfe,0x7f,0xfc,0,0x1f,0,
+0x7f,0xe0,0x7,0xff,0xf0,0x7f,0xc0,0,0x1f,0xc0,
+0x3f,0x1f,0x80,0xff,0xe0,0x3,0xe0,0x7,0xf0,0x3c,
+0x3f,0xff,0x8f,0xe0,0x7e,0x7f,0x3,0,0x1f,0,
+0x7f,0xe0,0,0x1f,0,0x7f,0,0xe1,0x1f,0,
+0xf,0xfe,0,0x1f,0,0,0x40,0,0xc0,0x60,
+0x7e,0xf,0xc0,0x7f,0xc0,0x1f,0xff,0,0x4,0,
+0,0x4,0,0x4,0,0,0,0,0,0,
+0,0,0x1,0xfe,0x78,0xf1,0xf8,0,0x1f,0,
+0x3,0xf1,0xe0,0x3f,0x80,0x1f,0xfe,0,0x3f,0x10,
+0x3e,0xf,0x81,0xff,0xf0,0,0x4,0x3,0xc0,0xf8,
+0x1f,0xff,0xf,0x87,0xe,0x3e,0xf,0x80,0x3f,0x80,
+0x11,0xf8,0,0x3f,0x10,0x1f,0xfe,0x1,0x1f,0,
+0x1,0xf8,0,0x3f,0x38,0,0xe0,0,0x40,0x40,
+0x3e,0xf,0x80,0x4,0,0xf,0xfe,0,0x4,0,
+0,0x40,0,0x4,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,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x4,0,0,0x40,0x1,0xff,0xe0,
+0,0,0,0x7f,0xc0,0,0x40,0,0x80,0x40,
+0,0,0,0x1f,0,0,0,0,0xc,0x18,
+0,0,0,0,0,0x3,0xf8,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xbf,0x38,0,0x44,0,0,0,
+0,0,0,0,0,0,0,0x1,0x83,0,
+0xc,0x3,0xc3,0x1,0xfe,0,0x3,0xc0,0xc0,0,
+0xfe,0xf,0xef,0xe0,0xfe,0xfe,0xf,0xef,0xe0,0xfe,
+0xfe,0xf,0xef,0xe0,0xfe,0x7d,0xff,0xe0,0x1f,0,
+0x7f,0xff,0x7,0xff,0xf0,0x7f,0xff,0x7,0xff,0xf0,
+0xf,0xfe,0,0xff,0xe0,0xf,0xfe,0,0xff,0xe0,
+0x7f,0xe0,0x7,0xf0,0x30,0x1,0xf0,0,0x1f,0,
+0x1,0xf0,0,0x1f,0,0x1,0xf0,0,0,0,
+0x31,0xf8,0,0x1f,0,0x1,0xf0,0,0x1f,0,
+0x1,0xf0,0,0x7f,0xc0,0x7f,0,0x7,0xc7,0xc0,
+0x1f,0xe7,0x81,0xfe,0x78,0x1f,0xe7,0x81,0xfe,0x78,
+0x1f,0xe7,0x81,0xfe,0x78,0x3e,0x4f,0x80,0x1f,0x80,
+0x3,0xf8,0,0x3f,0x80,0x3,0xf8,0,0x3f,0x80,
+0x1f,0xff,0x1,0xff,0xf0,0x1f,0xff,0x1,0xff,0xf0,
+0x3,0xf8,0x3,0xe0,0xf8,0x3,0xf8,0,0x3f,0x80,
+0x3,0xf8,0,0x3f,0x80,0x3,0xf8,0,0,0,
+0x33,0xf0,0,0x3f,0x38,0x3,0xf3,0x80,0x3f,0x38,
+0x3,0xf3,0x80,0x4,0,0x11,0xf8,0,0x4,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,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,0x22,0,0,0x40,0,0,
+0,0,0,0,0,0,0,0x18,0,0x30,
+0,0,0,0,0,0,0x7,0,0,0,
+0,0,0,0,0x40,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,0x70,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0x1c,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,0x8,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x4,0,0,0x4,0,0x4,
+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,0x10,0,0,0,0,
+0,0,0x4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x10,0,0,0,
+0x10,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xc,
+0,0,0,0,0x4,0,0,0x40,0,0x4,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xe,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x40,0,0x81,0xc0,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,0x80,
+0,0,0x44,0,0,0,0,0x40,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x80,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x4,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,0x20,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,0x4,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,0x20,0,0,0,
+0,0,0,0,0,0,0,0,0,0xc,
+0,0x10,0,0,0xc,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,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,
+0x22,0,0,0x40,0,0,0,0,0,0,
+0,0,0,0x8,0,0x20,0,0,0,0,
+0,0,0x6,0,0,0,0,0,0,0,
+0xc0,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,
+0x60,0,0,0,0,0,0,0,0,0,
+0,0,0x1,0xf0,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,0x3f,0x18,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x4,0,0,0x6,0,0x4,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,0x10,0,0,0,0,0,0,0x4,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x10,0,0,0,0x10,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x8,0,0,0,0,
+0x4,0,0,0x40,0,0x4,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xe,0,0,0,0,
+0,0,0,0,0,0,0,0,0x40,0,
+0xff,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,0x80,0,0x7,0xef,0x80,
+0,0,0,0x40,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x80,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x4,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,0,0,0,0,0,0,0,
+0x4,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,0x8,0,0x10,0,0,
+0x8,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,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,0x40,
+0,0,0,0,0,0,0,0,0,0xc,
+0,0x60,0,0,0,0,0,0,0x6,0,
+0,0,0,0,0,0,0x80,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,0x60,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,0x61,0xf0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x4,0,0,0x2,
+0,0x4,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,0x30,0,0,
+0,0,0,0,0xc,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x10,0,
+0,0,0x10,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x8,0,0,0,0,0x6,0,0,0x40,
+0,0xc,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xe,0,0,0,0,0,0,0,0,
+0,0,0,0,0x40,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,0x80,0,0,0,0,0,0,0,0x60,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xc0,0x20,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x6,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,0,
+0,0,0,0,0,0,0x6,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,0x8,0,0x10,0,0,0x8,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,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,0x4,0,0x40,0,0,
+0,0,0,0,0x4,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,0x40,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,0,0,0,0,0,
+0,0,0x7,0xc0,0,0,0,0x7c,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,0x20,0,0,0,0,0,0,
+0x8,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x10,0,0,0,0x10,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x18,0,0,
+0,0,0x3,0x80,0,0x40,0,0x38,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xe,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x40,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,0x80,0,0,
+0,0,0,0,0x1,0x30,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x60,0x20,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x13,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,0,0,0,0,0,
+0,0,0x13,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,0x18,0,0x10,
+0,0,0x18,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,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,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,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,0xe0,
+0,0,0,0,0,0,0x38,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x10,0,0,0,0x10,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x10,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,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,0xe,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,0x80,0,0,0,0,0,0,
+0x1,0xe0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x31,0xe0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1e,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,0,0,0,0,0,0,0,0x1e,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,0x10,0,0x10,0,0,0x10,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,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,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,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,0xf,0xff,0xfe,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x3f,0x80,0,0,0,0,
+0,0xf,0xe0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xff,0,0,0x1,
+0xfe,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x3,0xfe,
+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,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,0x4,
+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,0x80,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1f,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,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,0,
+0,0,0,0,0,0,0,0,0x1,0xfe,
+0,0xff,0,0x1,0xfe,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,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,
+};
+
+static WORD Courier34_ch_ofst[225] = {
+0,20,40,60,80,100,120,140,160,180,
+200,220,240,260,280,300,320,340,360,380,
+400,420,440,460,480,500,520,540,560,580,
+600,620,640,660,680,700,720,740,760,780,
+800,820,840,860,880,900,920,940,960,980,
+1000,1020,1040,1060,1080,1100,1120,1140,1160,1180,
+1200,1220,1240,1260,1280,1300,1320,1340,1360,1380,
+1400,1420,1440,1460,1480,1500,1520,1540,1560,1580,
+1600,1620,1640,1660,1680,1700,1720,1740,1760,1780,
+1800,1820,1840,1860,1880,1900,1920,1940,1960,1980,
+2000,2020,2040,2060,2080,2100,2120,2140,2160,2180,
+2200,2220,2240,2260,2280,2300,2320,2340,2360,2380,
+2400,2420,2440,2460,2480,2500,2520,2540,2560,2580,
+2600,2620,2640,2660,2680,2700,2720,2740,2760,2780,
+2800,2820,2840,2860,2880,2900,2920,2940,2960,2980,
+3000,3020,3040,3060,3080,3100,3120,3140,3160,3180,
+3200,3220,3240,3260,3280,3300,3320,3340,3360,3380,
+3400,3420,3440,3460,3480,3500,3520,3540,3560,3580,
+3600,3620,3640,3660,3680,3700,3720,3740,3760,3780,
+3800,3820,3840,3860,3880,3900,3920,3940,3960,3980,
+4000,4020,4040,4060,4080,4100,4120,4140,4160,4180,
+4200,4220,4240,4260,4280,4300,4320,4340,4360,4380,
+4400,4420,4440,4460,4480,
+};
+
+static struct font_hdr Courier34_font = {
+STPROP, 24, "-Adobe-Courier-M-R-N--34-240-10", 32, 255,
+32, 26, 16, 6, 6,
+19, 20, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Courier34_ch_ofst, Courier34_data,
+656, 32,
+NULL,
+0, 0,   /* x/y offset */
+34,        /* lineHeight */
+29,	   /* psHeight */
+};
+
+MgFont *mgCourier34Font()
+{
+return &Courier34_font;
+}
+
+MgFont *mgHugeFixedFont()
+{
+return &Courier34_font;
+}
diff --git a/lib/font/mgCourier8.c b/lib/font/mgCourier8.c
new file mode 100644
index 0000000..63e4076
--- /dev/null
+++ b/lib/font/mgCourier8.c
@@ -0,0 +1,273 @@
+
+/* Courier8.c - compiled data for font -Adobe-Courier-M-R-N--8-80-75-7 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/courR08.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Courier8_data[2120] = {
+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,
+0x20,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,
+0x4,0x8,0x85,0x1,0,0x4,0x8,0x80,0x40,0x88,
+0,0x15,0x2,0x21,0x40,0,0x20,0x44,0,0x80,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x2,0,0x4,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,0x10,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,0x3,
+0xc,0x70,0x2,0x11,0x4a,0x52,0x80,0x2,0x11,0x4a,
+0x21,0x14,0xa0,0x28,0x84,0x52,0x94,0,0x10,0x8a,
+0x51,0,0x8,0x11,0xa,0x2,0,0x4,0x8,0x80,
+0x40,0x88,0x8,0x15,0x2,0x21,0x40,0,0x20,0x44,
+0,0x80,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,0x1,0x14,0x52,0x34,0x4,0x10,
+0x84,0,0,0x1,0x10,0x84,0x21,0x1c,0x67,0x38,
+0xc0,0,0,0x2,0x30,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x62,0xc,0,0,0xc,0,0xc0,0x30,0x30,
+0x42,0x61,0x80,0,0,0,0x1,0,0,0,
+0,0x8,0x88,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x42,0x18,0x12,0x21,0x94,
+0xe6,0,0,0x73,0x88,0x3,0x38,0x40,0x70,0,
+0xc2,0x1,0x14,0xa2,0x40,0,0,0x1,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x64,0x22,0x94,0xa5,0,0x2,
+0x11,0x4a,0x21,0x14,0xa7,0x28,0x84,0x52,0x94,0x40,
+0x10,0x8a,0x51,0x30,0xa0,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,0x1,0x14,0x57,0x58,
+0xc4,0x10,0x8e,0x20,0,0x1,0x29,0x8a,0x53,0x10,
+0x85,0x29,0x40,0x1,0,0x45,0x29,0x9c,0x67,0x3d,
+0xe3,0x6d,0xce,0xce,0x25,0x92,0x70,0x9c,0x37,0xf7,
+0x3b,0x5a,0x4e,0x41,0x4,0xc0,0,0x4,0,0x40,
+0x20,0x10,0,0x20,0x80,0,0,0,0x1,0,
+0,0,0,0x10,0x84,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x2,0x22,0x4c,
+0x22,0x1,0x13,0,0,0x88,0x14,0x45,0x10,0x80,
+0xd0,0,0x45,0x1,0x25,0x14,0x6,0x31,0x8c,0x63,
+0x1e,0x4f,0x7b,0xde,0x73,0x9c,0xee,0x64,0x84,0x21,
+0x9,0x22,0xef,0x7b,0xdc,0xb0,0x90,0,0,0x2,
+0,0,0,0,0,0,0xe,0,0,0,
+0,0,0,0,0,0x10,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,0x1,0x15,
+0xf6,0x71,0,0x20,0x44,0x20,0,0x2,0x28,0x82,
+0x35,0x18,0x81,0x11,0x40,0x2,0x1c,0x21,0x59,0x4a,
+0x52,0x94,0xa4,0x28,0x84,0x52,0x3c,0xd5,0x29,0x4a,
+0x45,0x55,0x29,0x72,0x4a,0x41,0x5,0x20,0,0xc6,
+0x18,0xc6,0x71,0x58,0xc6,0x28,0x94,0xe1,0x38,0x57,
+0x9b,0xda,0xd5,0x65,0xa7,0x10,0x84,0x28,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x43,
+0x79,0x9e,0x23,0x81,0xd5,0x2b,0xc0,0xe8,0x8,0xe2,
+0x8,0x1a,0xd0,0,0x42,0x2b,0xce,0x68,0x45,0x29,
+0x4a,0x52,0xa8,0xa5,0x29,0x4a,0x21,0x8,0x45,0x35,
+0x4a,0x52,0x94,0xc5,0x29,0x4a,0x54,0x9c,0xac,0x63,
+0x18,0xc6,0x36,0x63,0x18,0xc6,0x63,0x18,0xc3,0x70,
+0x84,0x21,0x8,0xe2,0xeb,0x5a,0xd6,0x99,0xa0,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,
+0x1,0,0xa1,0x1d,0xa0,0x20,0x4a,0xf8,0x1c,0x2,
+0x28,0x84,0x17,0x84,0xe2,0x28,0xc4,0x22,0,0x22,
+0x69,0xce,0x42,0x98,0xc7,0x38,0x94,0x62,0x34,0xb5,
+0x39,0x4e,0x31,0x15,0x4d,0x21,0x84,0x41,0x4,0,
+0,0x65,0x21,0x4e,0x22,0x94,0x42,0x30,0x9a,0x52,
+0x94,0xa2,0x31,0xa,0x55,0x58,0xa2,0x20,0x82,0x50,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x44,0x21,0x88,0x2,0x81,0x90,0x50,0x4e,0xe8,
+0,0x47,0x30,0xa,0x51,0,0xe0,0x14,0xa5,0x94,
+0x47,0x39,0xce,0x73,0xbe,0x86,0x31,0x8c,0x21,0x8,
+0x4d,0x2d,0x4a,0x52,0x94,0xc7,0x29,0x4a,0x53,0x14,
+0x96,0x31,0x8c,0x63,0x1e,0x87,0x39,0xce,0x21,0x8,
+0x45,0x29,0x4a,0x52,0x94,0x5,0x29,0x4a,0x52,0x94,
+0xa0,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,0x1,0xf6,0x36,0x40,0x20,0x40,0x20,
+0,0x4,0x28,0x88,0x51,0x4,0xa2,0x28,0x40,0x1,
+0x1c,0x40,0x5d,0x4a,0x52,0x94,0x85,0x28,0x94,0x52,
+0xa4,0x95,0x21,0x4a,0x51,0x14,0x8e,0x71,0xa,0x40,
+0x84,0,0,0xa5,0x29,0x48,0x22,0x94,0x42,0x38,
+0x9a,0x52,0x94,0xa2,0x9,0x4a,0x57,0x98,0xa5,0x10,
+0x84,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x43,0x45,0x9e,0x23,0x81,0xd7,0x28,
+0,0xd8,0,0xe0,0,0xa,0x50,0,0x7,0x29,
+0x6a,0xac,0x85,0x29,0x4a,0x52,0xa8,0xa5,0x29,0x4a,
+0x21,0x8,0x45,0x25,0x4a,0x52,0x95,0x25,0x29,0x4a,
+0x52,0x1c,0x9a,0x52,0x94,0xa5,0x28,0xa4,0x21,0x8,
+0x21,0x8,0x45,0x29,0x4a,0x52,0x94,0x45,0x29,0x4a,
+0x52,0x94,0xa0,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,0x1,0,0xa2,0x59,0xa0,0x10,
+0x80,0x21,0,0x44,0x11,0xce,0x21,0x18,0xc2,0x11,
+0x84,0x20,0,0x2,0x43,0x7c,0x67,0x3d,0x83,0x6d,
+0xc8,0xcf,0xa5,0x92,0x60,0x99,0x63,0x98,0x8a,0x59,
+0x8e,0x40,0x84,0,0,0x5e,0x10,0xa6,0x71,0xb6,
+0xe2,0x6d,0xdb,0xd9,0x18,0x67,0x31,0x8d,0x22,0xa4,
+0x47,0x10,0x84,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x42,0x7a,0x48,0x20,0x81,
+0x10,0,0,0x88,0,0,0,0xd,0x50,0x8,
+0,0x2,0xe1,0x5c,0x8d,0xef,0x7b,0xde,0xee,0x4f,
+0x7b,0xde,0x73,0x9c,0xee,0x64,0x84,0x21,0x8,0xa,
+0x31,0x8c,0x63,0x31,0xa5,0x29,0x4a,0x52,0xb6,0x43,
+0x18,0xc6,0x73,0x9c,0xe6,0x6c,0x84,0x21,0x8,0xa,
+0x35,0xad,0x69,0x18,0x40,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,0,0xa2,0,
+0,0x10,0x80,0x1,0,0x8,0,0,0,0,
+0,0,0,0x40,0,0,0x38,0,0,0,
+0,0,0,0,0,0,0x1,0,0,0,
+0,0,0,0x60,0x4c,0xf,0x80,0,0,0,
+0,0x80,0x2,0,0,0,0x10,0x20,0,0,
+0,0,0x40,0x8,0x88,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x42,0,0,
+0x23,0,0xe0,0,0,0x70,0,0,0,0x8,
+0xd0,0x18,0,0,0x23,0x84,0x60,0,0,0,
+0,0x40,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x40,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1,0x10,0x40,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,0,
+0,0,0,0,0,0x2,0,0x8,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xc0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x3,0,0x6,0,0,0,0x38,0x70,
+0,0,0,0x1,0x80,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,0xc0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xc0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x6,0x39,0x80,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,
+};
+
+static WORD Courier8_ch_ofst[225] = {
+0,5,10,15,20,25,30,35,41,46,
+51,56,61,66,71,76,81,86,91,96,
+101,106,111,116,121,126,131,136,141,146,
+151,156,161,166,171,176,181,186,191,196,
+201,206,211,216,221,226,231,236,241,246,
+251,256,261,266,271,276,281,286,291,296,
+301,306,311,316,321,327,332,337,342,347,
+352,357,362,367,372,377,382,387,392,397,
+402,407,412,417,422,427,432,437,442,447,
+452,457,462,467,472,477,482,487,492,497,
+502,507,512,517,522,527,532,537,542,547,
+552,557,562,567,572,577,582,587,592,597,
+602,607,612,617,622,627,632,637,642,647,
+652,657,662,667,672,677,682,687,692,697,
+702,707,712,717,722,727,732,737,742,747,
+752,757,762,767,772,777,782,788,793,799,
+804,809,814,819,824,829,834,839,844,849,
+854,859,864,869,874,879,884,889,894,899,
+904,909,914,919,924,929,934,939,944,949,
+954,959,964,969,974,979,984,989,994,999,
+1004,1009,1014,1019,1024,1029,1034,1039,1044,1049,
+1054,1059,1064,1069,1074,1079,1084,1089,1094,1099,
+1104,1109,1114,1119,1124,
+};
+
+static struct font_hdr Courier8_font = {
+STPROP, 8, "-Adobe-Courier-M-R-N--8-80-75-7", 32, 255,
+10, 8, 5, 2, 2,
+7, 6, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Courier8_ch_ofst, Courier8_data,
+212, 10,
+NULL,
+0, 0,   /* x/y offset */
+10,        /* lineHeight */
+8,	   /* psHeight */
+};
+
+MgFont *mgCourier8Font()
+{
+return &Courier8_font;
+}
+
+MgFont *mgTinyFixedFont()
+{
+return &Courier8_font;
+}
diff --git a/lib/font/mgHelvetica10.c b/lib/font/mgHelvetica10.c
new file mode 100644
index 0000000..9897833
--- /dev/null
+++ b/lib/font/mgHelvetica10.c
@@ -0,0 +1,335 @@
+
+/* Helvetica10.c - compiled data for font AdobeHelv-M-R-N--10-100-75-75-P */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/helvR10.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Helvetica10_data[2782] = {
+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,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,0x8,
+0x4,0x10,0x28,0,0x80,0,0,0x80,0x41,0,
+0x21,0x40,0,0x50,0x40,0x10,0x20,0x50,0,0,
+0x1,0,0x80,0x80,0,0x80,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,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,
+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,0x4,0x8,0x28,0x50,0xa1,0x40,0,
+0,0x40,0x82,0x85,0x12,0xb4,0,0xa0,0x20,0x20,
+0x50,0xa0,0x90,0,0,0x81,0x1,0x42,0x41,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,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,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,0x80,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x20,0,
+0,0,0,0,0,0x81,0x11,0x40,0x20,0,
+0x10,0x42,0x4,0x20,0xa2,0x90,0x10,0x82,0x80,0,
+0x4,0x10,0x80,0x10,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,0x9,0x40,0x21,0x90,0x21,0x12,0x50,0,
+0x1,0x70,0x87,0x1c,0x13,0xe7,0x3e,0x71,0xc0,0,
+0,0x6,0xf,0x81,0xf,0xf,0x1e,0x1f,0x3e,0x78,
+0x84,0x84,0x89,0x4,0x13,0x11,0xe3,0xc3,0xc7,0x87,
+0x3e,0x85,0x6,0x22,0x8a,0xb,0xe7,0x31,0,0x40,
+0x40,0,0x80,0x60,0x41,0x50,0x80,0,0,0,
+0,0x8,0,0,0,0,0xa,0x80,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x18,0x8,0x93,0x94,0x1,0xc0,0,0,
+0x7,0,0,0x40,0x7c,0x1,0xc0,0x21,0x10,0x9c,
+0x40,0x4,0x8,0x10,0x20,0x40,0x81,0xf8,0xf1,0xf3,
+0xe7,0xcf,0x92,0x49,0xe1,0x88,0xf0,0xf0,0xf0,0xf0,
+0xf0,0x3,0xc4,0x24,0x24,0x24,0x28,0x28,0x18,0x42,
+0x2a,0x8a,0x50,0,0x8,0x85,0x2a,0xda,0xc5,0x8,
+0x21,0x45,0x14,0,0x2,0x21,0x4a,0x24,0xa,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,0x9,0x4a,0x72,0x50,
+0x51,0x21,0x20,0,0x1,0x89,0x88,0xa2,0x32,0x8,
+0x82,0x8a,0x20,0,0,0x9,0x10,0x41,0x8,0x90,
+0x91,0x10,0x20,0x84,0x84,0x84,0x91,0x6,0x33,0x12,
+0x12,0x24,0x24,0x48,0x88,0x85,0x6,0x22,0x89,0x10,
+0x25,0x11,0,0x20,0x40,0,0x80,0x80,0x40,0x10,
+0x80,0,0,0,0,0x8,0,0,0,0,
+0x12,0x40,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x2,0x25,0x28,0x94,0x40,
+0x70,0x40,0,0x1,0xc0,0x62,0x1f,0x80,0xe8,0x5,
+0x40,0x62,0x31,0x8,0x80,0x4,0x8,0x10,0x20,0x40,
+0x81,0x81,0x9,0x2,0x4,0x8,0x12,0x49,0x11,0x89,
+0x9,0x9,0x9,0x9,0x8,0x4,0x64,0x24,0x24,0x24,
+0x24,0x48,0x24,0,0,0,0x20,0,0,0,
+0,0x1,0x20,0,0,0,0,0,0,0,
+0,0x4,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,
+0x8,0xa,0xa9,0xa0,0x50,0x21,0x51,0,0x2,0x88,
+0x80,0x82,0x52,0x8,0x4,0x8a,0x24,0x84,0x2,0x1,
+0x26,0xa2,0x88,0x90,0x10,0x90,0x20,0x80,0x84,0x84,
+0xa1,0x6,0x32,0x92,0x12,0x24,0x24,0x48,0x8,0x84,
+0x89,0x24,0x51,0x10,0x44,0x92,0x80,0xe,0x58,0xc6,
+0x99,0xcd,0x59,0x52,0xbb,0x2c,0x72,0xc6,0xa9,0x9d,
+0x28,0xa4,0xa2,0x97,0x92,0x40,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x4e,
+0x20,0xc5,0x16,0,0x89,0x40,0,0x2,0x20,0x92,
+0x2a,0x12,0xe8,0xd,0xc0,0x22,0x11,0x4,0x81,0xa,
+0x14,0x28,0x50,0xa1,0x42,0x81,0x1,0x2,0x4,0x8,
+0x12,0x49,0x9,0x49,0x9,0x9,0x9,0x9,0xa,0x24,
+0xa4,0x24,0x24,0x24,0x24,0x4f,0x25,0xce,0x73,0x9c,
+0xe7,0x63,0x18,0xc6,0x32,0xa4,0xf7,0x1c,0x71,0xc7,
+0x1c,0x21,0xd9,0x4a,0x52,0x95,0x92,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,0x8,0x1f,0xa0,0x20,0x60,0x40,
+0x81,0,0x2,0x88,0x80,0x8c,0x53,0xcb,0x4,0x72,
+0x60,0x8,0xf1,0x2,0x49,0x22,0x8f,0x10,0x10,0x9f,
+0x3c,0x80,0xfc,0x84,0xe1,0x5,0x52,0x92,0x13,0xc4,
+0x27,0x87,0x8,0x84,0x89,0x24,0x20,0xa0,0x84,0x92,
+0x80,0x1,0x65,0x29,0xa4,0x93,0x65,0x54,0xa4,0xb2,
+0x8b,0x29,0xb2,0x49,0x28,0xa4,0x94,0x90,0x92,0x4c,
+0x80,0,0,0,0,0,0,0,0,0,
+0,0,0,0x15,0x71,0x25,0x13,0x81,0x34,0x5,
+0x3e,0x5,0xd0,0x9f,0x91,0x12,0xe8,0x4,0x14,0x24,
+0x12,0x19,0,0xa,0x14,0x28,0x50,0xa1,0x42,0xf9,
+0x1,0xf3,0xe4,0xf,0x92,0x4b,0xc9,0x49,0x9,0x9,
+0x9,0x9,0x9,0x44,0xa4,0x24,0x24,0x24,0x22,0x88,
+0xa8,0x21,0x8,0x42,0x10,0x94,0xa5,0x29,0x4a,0xa5,
+0x14,0xa2,0x8a,0x28,0xa2,0x2,0x69,0x4a,0x52,0x96,
+0x52,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,0x8,0xa,
+0x70,0x40,0xa4,0x40,0x87,0xc3,0x82,0x88,0x83,0x2,
+0x90,0x2c,0x88,0x89,0xa0,0x10,0,0x84,0x51,0x24,
+0x48,0x90,0x10,0x90,0x20,0x8c,0x84,0x84,0x91,0x5,
+0x52,0x52,0x12,0x4,0x24,0x40,0x88,0x84,0x89,0x54,
+0x50,0xa0,0x84,0x94,0x40,0x7,0x45,0x8,0xbc,0x91,
+0x45,0x58,0xa4,0xa2,0x8a,0x28,0xa1,0x89,0x25,0x15,
+0x8,0xa1,0x22,0x33,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x54,0x21,0x2f,
+0x84,0xc1,0x45,0xca,0x2,0xe5,0x90,0x62,0x3e,0x12,
+0x6b,0x5,0xca,0x4,0x82,0xc1,0x21,0x11,0x22,0x44,
+0x89,0x12,0x24,0x81,0x1,0x2,0x7,0xc8,0x12,0x49,
+0x9,0x29,0x9,0x9,0x9,0x9,0x8,0x85,0x24,0x24,
+0x24,0x24,0x22,0x88,0xa4,0xe7,0x39,0xce,0x73,0xf4,
+0x3d,0xef,0x7a,0xa5,0x14,0xa2,0x8a,0x28,0xa2,0xfa,
+0xa9,0x4a,0x52,0xa4,0x54,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,0x8,0x3e,0x28,0x58,0x98,0x40,0x81,0,
+0x2,0x88,0x84,0x2,0xf8,0x28,0x88,0x88,0x20,0x8,
+0xf1,0x4,0x52,0x47,0xc8,0x90,0x10,0x90,0x20,0x84,
+0x84,0x84,0x91,0x4,0x92,0x52,0x12,0x4,0xa4,0x48,
+0x88,0x84,0x50,0x88,0x50,0x41,0x4,0x90,0,0x9,
+0x45,0x8,0xa0,0x91,0x45,0x54,0xa4,0xa2,0x8a,0x28,
+0xa0,0x49,0x25,0x15,0x14,0xa2,0x12,0x40,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x54,0x20,0xc2,0x6,0x41,0x34,0x14,0x2,0x5,
+0x50,0x2,0,0x12,0x28,0,0x5,0x9,0x85,0x42,
+0x61,0x1f,0x3e,0x7c,0xf9,0xf3,0xe7,0x81,0x1,0x2,
+0x4,0x8,0x12,0x49,0x9,0x29,0x9,0x9,0x9,0x9,
+0x9,0x45,0x24,0x24,0x24,0x24,0x21,0xf,0x25,0x29,
+0x4a,0x52,0x94,0x84,0x21,0x8,0x42,0xa5,0x14,0xa2,
+0x8a,0x28,0xa2,0x3,0x29,0x4a,0x52,0xa4,0x54,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,0x14,0xa8,0xa4,
+0x98,0x40,0x81,0,0x4,0x88,0x88,0x22,0x12,0x28,
+0x90,0x8a,0x20,0x4,0x2,0,0x52,0x48,0x28,0x90,
+0x91,0x10,0x20,0x8c,0x84,0xa4,0x89,0x4,0x92,0x32,
+0x12,0x4,0x64,0x48,0x88,0x84,0x50,0x88,0x88,0x42,
+0x4,0x50,0,0x9,0x65,0x29,0xa4,0x93,0x45,0x52,
+0xa4,0xa2,0x8b,0x29,0xa2,0x49,0x22,0xa,0x22,0x64,
+0x12,0x40,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x55,0x25,0x2f,0x93,0x80,
+0x88,0xa,0,0x2,0x20,0,0,0x12,0x28,0,
+0xa,0xb,0xc4,0x82,0xf2,0x20,0xc1,0x83,0x6,0xc,
+0x18,0x81,0x9,0x2,0x4,0x8,0x12,0x49,0x11,0x19,
+0x9,0x9,0x9,0x9,0xa,0x26,0x24,0x24,0x24,0x24,
+0x21,0x8,0x25,0x29,0x4a,0x52,0x94,0x94,0xa5,0x29,
+0x4a,0xa5,0x14,0xa2,0x8a,0x28,0xa2,0x22,0x29,0x4a,
+0x52,0x66,0x4c,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,
+0x8,0x14,0x70,0x98,0x64,0x21,0,0x8,0x14,0x70,
+0x8f,0x9c,0x11,0xc7,0x10,0x71,0xc4,0x80,0,0x4,
+0x4d,0x88,0x2f,0xf,0x1e,0x1f,0x20,0x74,0x84,0x98,
+0x89,0xe4,0x92,0x31,0xe2,0x3,0xe4,0x47,0x8,0x78,
+0x20,0x88,0x88,0x43,0xe4,0x50,0,0x6,0xd8,0xc6,
+0x98,0x8d,0x45,0x52,0xa4,0xa2,0x72,0xc6,0xa1,0x8c,
+0xe2,0xa,0x22,0x47,0x92,0x40,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x4e,
+0x58,0x2,0x10,0xc0,0x70,0x5,0,0x1,0xc0,0xf,
+0x80,0x1e,0x28,0,0x14,0x10,0x89,0xc4,0x24,0x20,
+0xc1,0x83,0x6,0xc,0x18,0xf8,0xf1,0xf3,0xe7,0xcf,
+0x92,0x49,0xe1,0x18,0xf0,0xf0,0xf0,0xf0,0xf0,0x3,
+0xc3,0xc3,0xc3,0xc3,0xc1,0x8,0x28,0xd6,0xb5,0xad,
+0x6b,0x63,0x18,0xc6,0x32,0xa4,0xe4,0x9c,0x71,0xc7,
+0x1c,0x1,0xc7,0x39,0xce,0x45,0x88,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,0x20,0,0,0x21,
+0,0x8,0,0,0,0,0,0,0,0,
+0,0x80,0,0,0x20,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x10,0,0,0,0,0,0,0,0x4,0x10,
+0,0,0,0,0,0x1,0,0x40,0,0,
+0x2,0,0x80,0,0,0,0,0x40,0x12,0x40,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x48,0,0,0x14,0x40,0,0,
+0,0,0,0,0,0x10,0x28,0x20,0,0,
+0,0,0x4,0x80,0,0,0,0,0,0,
+0x20,0,0,0,0,0,0,0,0,0,
+0,0,0,0x4,0,0,0,0,0,0,
+0,0,0,0,0,0x1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x44,
+0x8,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,0x12,0,0x10,0,0,0,0,
+0,0,0,0,0x1,0,0,0,0x1f,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x6,0x30,0x1f,0x80,0,0,0,0xe,
+0,0,0,0,0x2,0,0x80,0,0,0,
+0,0x80,0xa,0x80,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x40,0,0,
+0x13,0x80,0,0,0,0,0,0,0,0x10,
+0x28,0x60,0,0,0,0,0x3,0,0,0,
+0,0,0,0,0x60,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x84,0x10,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,
+};
+
+static WORD Helvetica10_ch_ofst[225] = {
+0,3,6,10,16,22,31,39,41,45,
+49,53,59,62,66,69,72,78,84,90,
+96,102,108,114,120,126,132,135,138,144,
+149,155,161,172,179,186,194,202,209,215,
+223,231,234,239,246,252,261,269,277,284,
+292,299,306,311,319,326,335,342,349,356,
+359,362,365,371,377,380,385,391,396,402,
+407,411,417,423,425,427,432,434,442,448,
+454,460,466,470,475,479,484,490,498,504,
+509,514,517,520,523,530,533,536,539,542,
+545,548,551,554,557,560,563,566,569,572,
+575,578,581,584,587,590,593,596,599,602,
+605,608,611,614,617,620,623,626,629,632,
+635,641,647,652,658,661,667,670,679,683,
+689,696,700,709,712,716,722,725,728,731,
+736,742,745,748,751,755,761,770,779,788,
+794,801,808,815,822,829,836,846,854,861,
+868,875,882,885,888,891,894,902,910,918,
+926,934,942,950,956,964,972,980,988,996,
+1003,1010,1015,1020,1025,1030,1035,1040,1045,1053,
+1058,1063,1068,1073,1078,1080,1082,1084,1087,1093,
+1098,1104,1110,1116,1122,1128,1134,1140,1145,1150,
+1155,1160,1165,1171,1176,
+};
+
+static struct font_hdr Helvetica10_font = {
+STPROP, 10, "AdobeHelv-M-R-N--10-100-75-75-P", 32, 255,
+13, 11, 6, 2, 2,
+11, 11, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Helvetica10_ch_ofst, Helvetica10_data,
+214, 13,
+NULL,
+0, 0,   /* x/y offset */
+13, 	   /* lineHeight */
+9,	   /* psHeight */
+};
+
+MgFont *mgHelvetica10Font()
+{
+return &Helvetica10_font;
+}
diff --git a/lib/font/mgHelvetica12.c b/lib/font/mgHelvetica12.c
new file mode 100644
index 0000000..2ce7ad8
--- /dev/null
+++ b/lib/font/mgHelvetica12.c
@@ -0,0 +1,431 @@
+
+/* Helvetica12.c - compiled data for font AdobeHelv-M-R-N--12-120-75-75-P */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/helvR12.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Helvetica12_data[3750] = {
+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,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,0x80,
+0x10,0x10,0xa,0,0x2,0,0,0,0x20,0x8,
+0x10,0x1,0xa,0,0,0xa0,0x40,0x4,0x2,0x1,
+0x40,0,0,0,0x10,0x4,0x8,0,0x4,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,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,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,0,0,0,0,0x40,
+0x20,0x28,0x14,0xa,0x5,0,0,0,0x10,0x10,
+0x28,0x28,0x95,0xa0,0x1,0x40,0x20,0x8,0x5,0x2,
+0x80,0x90,0,0,0x8,0x8,0x14,0x24,0x8,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,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,0,0,0,0,0,0,0,
+0,0,0,0,0,0x8,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,0x10,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x2,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x1,0,0,0,0,0,0,
+0,0x10,0x10,0x40,0xa0,0x3,0,0,0x2,0x1,
+0x4,0,0x85,0x3,0x42,0x88,0x4,0x10,0x28,0,
+0,0x4,0x2,0x8,0,0x10,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,0,0,
+0x4,0xa0,0x2,0xc,0x40,0xc1,0xc,0x28,0,0,
+0x9,0xc1,0x7,0xe,0x4,0x7c,0x71,0xf1,0xc3,0x80,
+0,0,0,0xe0,0x7c,0x4,0x1f,0x7,0x8f,0x87,
+0xe7,0xe1,0xe2,0x9,0x2,0x42,0x40,0x80,0x90,0x43,
+0xc3,0xe0,0xf0,0xf8,0x79,0xfd,0x9,0x4,0x88,0x90,
+0x48,0x27,0xf3,0x8c,0,0x4,0x2,0,0,0x80,
+0x18,0x4,0x9,0x20,0x80,0,0,0,0,0,
+0x20,0,0,0,0,0,0xd6,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x6,0,0x44,0x9c,
+0xa3,0xe1,0xc0,0,0,0x3e,0x3c,0,0,0x20,
+0x7,0x80,0x7,0,0x41,0x10,0x4e,0x10,0,0x40,
+0x20,0x10,0x8,0x4,0x2,0x1,0xf8,0x78,0xfc,0xfc,
+0xfc,0xfc,0x92,0x4f,0x84,0x10,0xf0,0x3c,0xf,0x3,
+0xc0,0xf0,0,0x7a,0x42,0x42,0x42,0x42,0x41,0x20,
+0x1c,0x8,0x20,0xa1,0x42,0x84,0x80,0,0x1,0x2,
+0xa,0x14,0x4a,0xd1,0x85,0x4,0x8,0x28,0x50,0xa0,
+0,0x2,0x4,0x14,0x28,0x21,0x1,0x40,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,
+0x4,0xa2,0x87,0x12,0x81,0x21,0x12,0x10,0,0,
+0xa,0x27,0x8,0x91,0xc,0x40,0x88,0x12,0x24,0x40,
+0,0,0x1,0x11,0x82,0xa,0x10,0x88,0x48,0x44,
+0x4,0x2,0x12,0x9,0x2,0x44,0x40,0xc1,0x98,0x44,
+0x22,0x11,0x8,0x84,0x84,0x21,0x9,0x4,0x88,0x88,
+0x88,0x20,0x12,0x84,0x40,0,0x2,0,0,0x80,
+0x20,0x4,0,0x20,0x80,0,0,0,0,0,
+0x20,0,0,0,0,0x1,0x11,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x1,0x9,0,0x44,0xa2,
+0x4,0x10,0x40,0,0,0x41,0x1,0x80,0x1b,0x80,
+0xd,0,0x25,0,0xc2,0x30,0x82,0x20,0,0x40,
+0x20,0x10,0x8,0x4,0x2,0x2,0x80,0x84,0x80,0x80,
+0x80,0x80,0x92,0x48,0x46,0x11,0x8,0x42,0x10,0x84,
+0x21,0x8,0,0x84,0x42,0x42,0x42,0x42,0x41,0x20,
+0x22,0,0,0,0,0x3,0,0,0,0,
+0,0,0,0x2,0x80,0,0,0,0,0,
+0,0,0,0,0,0x1,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,0,0,
+0x4,0xa2,0x8a,0x92,0x81,0x21,0x12,0x28,0,0,
+0x12,0x21,0,0x81,0x14,0x40,0x80,0x22,0x24,0x40,
+0,0,0x1,0x11,0x35,0xa,0x10,0x90,0x8,0x24,
+0x4,0x4,0x2,0x9,0x2,0x48,0x40,0xc1,0x94,0x48,
+0x12,0x12,0x4,0x84,0x80,0x21,0x8,0x88,0x88,0x88,
+0x84,0x40,0x22,0x44,0xa0,0,0xe2,0xc3,0x86,0x8e,
+0x71,0xa5,0x89,0x24,0x94,0x8b,0xe,0x2c,0x34,0xa6,
+0x74,0x48,0xa2,0x30,0xa2,0x79,0x11,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x47,0x8,0x42,0x28,0xa0,
+0x9,0xc9,0x40,0,0,0x9c,0x82,0x42,0x24,0x84,
+0x5d,0,0x67,0,0x44,0x11,0x4,0x40,0,0xa0,
+0x50,0x28,0x14,0xa,0x5,0x2,0x81,0,0x80,0x80,
+0x80,0x80,0x92,0x48,0x25,0x12,0x4,0x81,0x20,0x48,
+0x12,0x4,0x1,0xa,0x42,0x42,0x42,0x42,0x22,0x3e,
+0x22,0x38,0x70,0xe1,0xc3,0x87,0xe,0xe1,0xc3,0x87,
+0xe,0x1c,0x49,0x20,0x4b,0xe,0x1c,0x38,0x70,0xe0,
+0x3,0xa8,0x91,0x22,0x44,0x89,0x62,0x20,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,
+0x4,0xf,0xca,0xd,0,0xc0,0x21,0,0x40,0,
+0x12,0x21,0x1,0x6,0x14,0x78,0xb0,0x21,0xc4,0x49,
+0x6,0,0xc0,0x22,0x49,0x11,0x10,0x90,0x8,0x24,
+0x4,0x4,0x2,0x9,0x2,0x50,0x40,0xa2,0x94,0x48,
+0x12,0x12,0x4,0x84,0x60,0x21,0x8,0x88,0x49,0x5,
+0x4,0x40,0x42,0x45,0x10,0x1,0x13,0x24,0x49,0x91,
+0x22,0x66,0x49,0x28,0x9b,0x4c,0x91,0x32,0x4c,0xc9,
+0x24,0x48,0xa2,0x29,0x22,0x9,0x11,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xa,0x88,0x3c,0x10,0x98,
+0xa,0x28,0x2,0x9f,0x80,0x94,0x82,0x42,0x9,0x4,
+0x5d,0,0x20,0x28,0x44,0x12,0x2,0x40,0x41,0x10,
+0x88,0x44,0x22,0x11,0x8,0x84,0x81,0,0x80,0x80,
+0x80,0x80,0x92,0x48,0x25,0x12,0x4,0x81,0x20,0x48,
+0x12,0x4,0x89,0x12,0x42,0x42,0x42,0x42,0x22,0x21,
+0x22,0x44,0x89,0x12,0x24,0x48,0x91,0x12,0x24,0x48,
+0x91,0x22,0x49,0x23,0xcc,0x91,0x22,0x44,0x89,0x10,
+0x84,0x48,0x91,0x22,0x44,0x89,0x92,0x20,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,
+0x4,0x2,0x87,0x1,0x1,0x40,0x21,0,0x40,0,
+0x22,0x21,0x2,0x1,0x24,0x4,0xc8,0x42,0x23,0xc0,
+0x18,0x7c,0x30,0x22,0x89,0x11,0x1f,0x10,0x8,0x27,
+0xe7,0xc4,0x73,0xf9,0x2,0x70,0x40,0xa2,0x92,0x48,
+0x13,0xe2,0x4,0xf8,0x18,0x21,0x8,0x88,0x55,0x2,
+0x2,0x80,0x82,0x24,0,0,0x12,0x24,0x8,0x91,
+0x22,0x24,0x49,0x30,0x92,0x48,0x91,0x22,0x44,0x88,
+0x24,0x48,0x92,0x46,0x22,0x11,0x11,0x32,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x4a,0x1e,0x24,0x7c,0x24,
+0xa,0x9,0xc5,0,0x80,0x98,0x81,0x8f,0x90,0x84,
+0x5d,0,0x27,0x14,0x49,0x12,0xcc,0x90,0x1,0x10,
+0x88,0x44,0x22,0x11,0x8,0x84,0xf9,0,0xfc,0xfc,
+0xfc,0xfc,0x92,0x5e,0x24,0x92,0x4,0x81,0x20,0x48,
+0x12,0x4,0x51,0x12,0x42,0x42,0x42,0x42,0x14,0x21,
+0x2c,0x4,0x8,0x10,0x20,0x40,0x81,0x12,0x4,0x48,
+0x91,0x22,0x49,0x24,0x48,0x91,0x22,0x44,0x89,0x10,
+0x4,0xc8,0x91,0x22,0x44,0x89,0x11,0x20,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,
+0x4,0xf,0xc2,0x82,0x62,0x28,0x21,0x1,0xf0,0x78,
+0x22,0x21,0x4,0x1,0x44,0x4,0x88,0x42,0x20,0x40,
+0x60,0,0xc,0x42,0x89,0x1f,0x10,0x90,0x8,0x24,
+0x4,0x4,0x12,0x9,0x2,0x48,0x40,0x94,0x91,0x48,
+0x12,0x2,0x24,0x88,0x4,0x21,0x8,0x50,0x55,0x5,
+0x1,0x1,0x2,0x24,0,0,0xf2,0x24,0x8,0x9f,
+0x22,0x24,0x49,0x30,0x92,0x48,0x91,0x22,0x44,0x86,
+0x24,0x45,0x12,0x46,0x24,0x22,0x10,0xcc,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x4a,0x4,0x24,0x10,0x22,
+0xa,0x28,0xa,0,0xbc,0x94,0x80,0x2,0x3f,0x4,
+0x4d,0x10,0x20,0xa,0x13,0x5,0x20,0xb0,0x41,0xf0,
+0xf8,0x7c,0x3e,0x1f,0xf,0x87,0x81,0,0x80,0x80,
+0x80,0x80,0x92,0x48,0x24,0x52,0x4,0x81,0x20,0x48,
+0x12,0x4,0x21,0x22,0x42,0x42,0x42,0x42,0x8,0x21,
+0x22,0x3c,0x78,0xf1,0xe3,0xc7,0x8f,0xf2,0x7,0xcf,
+0x9f,0x3e,0x49,0x24,0x48,0x91,0x22,0x44,0x89,0x13,
+0xe5,0x48,0x91,0x22,0x44,0x91,0x11,0x40,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,
+0x4,0x5,0xa,0x82,0x92,0x10,0x21,0,0x40,0,
+0x22,0x21,0x8,0x11,0x7e,0x44,0x88,0x42,0x20,0x40,
+0x18,0x7c,0x30,0x42,0x9a,0x20,0x90,0x90,0x8,0x24,
+0x4,0x4,0x12,0x9,0x22,0x44,0x40,0x94,0x91,0x48,
+0x12,0x2,0x14,0x84,0x84,0x21,0x8,0x50,0x22,0x8,
+0x81,0x2,0x2,0x24,0,0x1,0x12,0x24,0x8,0x90,
+0x22,0x24,0x49,0x28,0x92,0x48,0x91,0x22,0x44,0x81,
+0x24,0x45,0x15,0x49,0x14,0x21,0x11,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x4a,0x4,0x3c,0x7c,0x22,
+0x9,0xc8,0x5,0,0x80,0x94,0x80,0x2,0,0x4,
+0x45,0,0,0x14,0x15,0x4,0x41,0x50,0x42,0x9,
+0x4,0x82,0x41,0x20,0x90,0x48,0x81,0,0x80,0x80,
+0x80,0x80,0x92,0x48,0x24,0x52,0x4,0x81,0x20,0x48,
+0x12,0x4,0x51,0x42,0x42,0x42,0x42,0x42,0x8,0x3e,
+0x22,0x44,0x89,0x12,0x24,0x48,0x91,0x2,0x4,0x8,
+0x10,0x20,0x49,0x24,0x48,0x91,0x22,0x44,0x89,0x10,
+0x6,0x48,0x91,0x22,0x44,0x51,0x11,0x40,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,
+0,0x5,0xa,0x82,0x92,0x30,0x21,0,0x40,0,
+0x42,0x21,0x8,0x11,0x4,0x44,0x88,0x82,0x24,0x40,
+0x6,0,0xc0,0x2,0x6c,0x20,0x90,0x88,0x48,0x44,
+0x4,0x2,0x32,0x9,0x22,0x42,0x40,0x88,0x90,0xc4,
+0x22,0x1,0x8,0x84,0x84,0x21,0x8,0x20,0x22,0x8,
+0x81,0x4,0x2,0x14,0,0x1,0x13,0x24,0x49,0x91,
+0x22,0x64,0x49,0x24,0x92,0x48,0x91,0x32,0x4c,0x89,
+0x24,0xc2,0x8,0x90,0x94,0x41,0x11,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x4c,0x89,0x42,0x10,0x92,
+0x4,0x10,0x2,0x80,0,0x41,0,0,0,0x4,
+0xc5,0,0,0x28,0x27,0x88,0x81,0x78,0x82,0x9,
+0x4,0x82,0x41,0x20,0x90,0x48,0x80,0x84,0x80,0x80,
+0x80,0x80,0x92,0x48,0x44,0x31,0x8,0x42,0x10,0x84,
+0x21,0x8,0x88,0x84,0x42,0x42,0x42,0x42,0x8,0x20,
+0x22,0x44,0x89,0x12,0x24,0x48,0x91,0x12,0x24,0x48,
+0x91,0x22,0x49,0x24,0x48,0x91,0x22,0x44,0x89,0x10,
+0x84,0x49,0x93,0x26,0x4c,0x51,0x90,0xc0,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,
+0x4,0x5,0x7,0x4,0x61,0xc8,0x21,0,0x1,0x1,
+0x41,0xc1,0xf,0x8e,0x4,0x38,0x70,0x81,0xc3,0x89,
+0,0,0,0x41,0,0x20,0x9f,0x7,0x8f,0x87,
+0xe4,0x1,0xd2,0x9,0x1c,0x41,0x7c,0x88,0x90,0x43,
+0xc2,0,0xf4,0x84,0x78,0x20,0xf0,0x20,0x22,0x10,
+0x41,0x7,0xf2,0x14,0,0,0xea,0xc3,0x86,0x8e,
+0x21,0xa4,0x49,0x22,0x92,0x48,0x8e,0x2c,0x34,0x86,
+0x33,0x42,0x8,0x90,0x88,0x79,0x11,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x47,0x16,0,0x10,0x8c,
+0x3,0xe0,0,0,0,0x3e,0,0xf,0x80,0x7,
+0x45,0x2,0,0,0x41,0x11,0xe2,0x10,0x82,0x9,
+0x4,0x82,0x41,0x20,0x90,0x48,0xf8,0x78,0xfc,0xfc,
+0xfc,0xfc,0x92,0x4f,0x84,0x10,0xf0,0x3c,0xf,0x3,
+0xc0,0xf0,0x1,0x78,0x3c,0x3c,0x3c,0x3c,0x8,0x20,
+0x2c,0x3a,0x74,0xe9,0xd3,0xa7,0x4e,0xe1,0xc3,0x87,
+0xe,0x1c,0x49,0x23,0x88,0x8e,0x1c,0x38,0x70,0xe0,
+0xb,0x86,0x8d,0x1a,0x34,0x21,0x60,0x80,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,
+0,0,0x2,0,0,0,0x12,0,0x1,0,
+0,0,0,0,0,0,0,0,0,0x1,
+0,0,0,0,0xf8,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,0x2,0x4,0,0,0,0,0,0,
+0,0x20,0x1,0,0,0,0,0x20,0x4,0,
+0,0,0,0,0x8,0x1,0x11,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x44,0,0,0,0x82,
+0,0,0,0,0,0,0,0,0,0x4,
+0x5,0x1,0,0,0,0,0,0x1,0x10,0,
+0,0,0,0,0,0,0,0x10,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x21,0,0x80,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,
+0,0,0,0,0,0,0x12,0,0x2,0,
+0,0,0,0,0,0,0,0,0,0x2,
+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,0x2,0x4,0x7,0xf0,0,0,0,0,
+0x2,0x20,0x1,0,0,0,0,0x20,0x4,0,
+0,0,0,0,0x10,0x1,0x11,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x40,0,0,0,0xa2,
+0,0,0,0,0,0,0,0,0,0x4,
+0x5,0x1,0,0,0,0,0,0x1,0x10,0,
+0,0,0,0,0,0,0,0x10,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,0x40,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x41,0,0x80,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,
+0,0,0,0,0,0,0xc,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,0x3,0xc,0,0,0,0,0,0,
+0x1,0xc0,0x2,0,0,0,0,0x20,0x4,0,
+0,0,0,0,0x20,0,0xd6,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x40,0,0,0,0x1c,
+0,0,0,0,0,0,0,0,0,0x4,
+0x5,0x6,0,0,0,0,0,0,0xe0,0,
+0,0,0,0,0,0,0,0x60,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,0x1,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x81,0x3,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,0,
+};
+
+static WORD Helvetica12_ch_ofst[225] = {
+0,4,7,12,19,26,37,46,49,53,
+57,62,69,73,78,81,85,92,99,106,
+113,120,127,134,141,148,155,158,161,168,
+175,182,189,201,210,218,227,236,244,252,
+261,270,273,280,288,295,306,315,325,333,
+343,351,359,366,374,383,394,403,412,421,
+424,428,431,437,444,446,453,460,467,474,
+481,485,492,499,502,505,511,514,523,530,
+537,544,551,555,561,564,571,578,587,593,
+600,606,610,613,617,624,628,632,636,640,
+644,648,652,656,660,664,668,672,676,680,
+684,688,692,696,700,704,708,712,716,720,
+724,728,732,736,740,744,748,752,756,760,
+763,770,777,784,791,794,800,803,814,819,
+826,834,839,850,854,859,866,870,874,876,
+883,890,893,896,900,905,912,922,932,942,
+949,958,967,976,985,994,1003,1014,1023,1031,
+1039,1047,1055,1058,1061,1064,1067,1076,1085,1095,
+1105,1115,1125,1135,1142,1152,1160,1168,1176,1184,
+1193,1201,1208,1215,1222,1229,1236,1243,1250,1261,
+1268,1275,1282,1289,1296,1299,1302,1305,1308,1315,
+1322,1329,1336,1343,1350,1357,1364,1371,1378,1385,
+1392,1399,1406,1413,1420,
+};
+
+static struct font_hdr Helvetica12_font = {
+STPROP, 12, "AdobeHelv-M-R-N--12-120-75-75-P", 32, 255,
+15, 12, 7, 3, 3,
+11, 12, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Helvetica12_ch_ofst, Helvetica12_data,
+250, 15,
+NULL,
+0, 0,   /* x/y offset */
+15,        /* lineHeight */
+11,	   /* psHeight */
+};
+
+MgFont *mgHelvetica12Font()
+{
+return &Helvetica12_font;
+}
diff --git a/lib/font/mgHelvetica14.c b/lib/font/mgHelvetica14.c
new file mode 100644
index 0000000..f74b50b
--- /dev/null
+++ b/lib/font/mgHelvetica14.c
@@ -0,0 +1,527 @@
+
+/* Helvetica14.c - compiled data for font AdobeHelv-M-R-N--14-140-75-75-P */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/helvR14.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Helvetica14_data[4658] = {
+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,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,0x8,0,0x40,0x10,0x6,
+0x80,0,0x1c,0,0,0,0x4,0,0x80,0x80,
+0x1,0x2,0x20,0,0,0xd0,0x20,0x1,0,0x40,
+0x1a,0,0,0,0,0x4,0,0x40,0x20,0,
+0x2,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,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,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,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x4,
+0,0x80,0x28,0xb,0x1,0xb0,0x22,0,0,0,
+0x2,0x1,0x1,0x41,0xb0,0x84,0x56,0xc0,0x1,0x60,
+0x10,0x2,0,0xa0,0x2c,0x6,0xc0,0,0,0x2,
+0,0x80,0x50,0x66,0x4,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,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,0x80,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,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,
+0x1c,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,0x6,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,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x2,0x50,0,0x80,0,0,0x8,0x48,
+0,0,0,0x2,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x30,0xf,
+0,0x40,0xfc,0xe,0x1f,0x7,0xf3,0xf8,0x3c,0x20,
+0x44,0x2,0x41,0x10,0x10,0x4,0xc1,0x7,0x7,0xe0,
+0x70,0x7e,0xe,0x3f,0xe8,0x12,0x2,0x41,0x4,0x81,
+0x40,0x5f,0xcf,0x1c,0,0x1,0,0x8,0,0,
+0x40,0x6,0,0x80,0x92,0x4,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x6,
+0xb0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x10,0xe0,0,0x1,0xc0,0,0,
+0,0,0,0,0,0x2,0,0x3e,0,0,
+0xc0,0x2,0x8,0x21,0x6,0x8,0,0x4,0,0x80,
+0x10,0x2,0,0x40,0x8,0x1,0xfe,0xe,0x1f,0xcf,
+0xe7,0xf3,0xf8,0x84,0x21,0x1f,0x6,0x8,0x38,0x7,
+0,0xe0,0x1c,0x3,0x80,0,0x38,0xa0,0x48,0x12,
+0x4,0x81,0x40,0x50,0x7,0x4,0x1,0x2,0x6,0x80,
+0x9,0,0,0,0x20,0x10,0x10,0x1,0xa,0xd,
+0x83,0x42,0,0x83,0x3,0x40,0,0,0x1,0,
+0x41,0x80,0,0x88,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,0x2,0x50,0xa3,0xe3,
+0x84,0xc,0x8,0x84,0x10,0,0,0x2,0x78,0x10,
+0x78,0x78,0xc,0xfc,0x78,0xfc,0x78,0x78,0,0,
+0,0,0xcc,0x30,0xc0,0x40,0x86,0x31,0x90,0xc4,
+0x2,0,0xc3,0x20,0x44,0x2,0x42,0x10,0x10,0x4,
+0xc1,0x18,0xc4,0x31,0x8c,0x43,0x31,0x82,0x8,0x12,
+0x2,0x41,0x4,0x81,0x20,0x80,0x49,0x4,0x20,0,
+0x80,0x8,0,0,0x40,0x8,0,0x80,0x92,0x4,
+0,0,0,0,0,0,0,0x80,0,0,
+0,0,0,0x8,0x88,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x7,0x80,0x10,0x51,0xb6,0xc3,
+0xc0,0x20,0,0,0x3,0xc3,0xcc,0,0x31,0x84,
+0,0x74,0,0x11,0x20,0x6,0x10,0x62,0x9,0x10,
+0,0x4,0,0x80,0x10,0x2,0,0x40,0x8,0x3,
+0x80,0x31,0x90,0x8,0x4,0x2,0,0x84,0x21,0x10,
+0xc6,0x8,0xc6,0x18,0xc3,0x18,0x63,0xc,0x60,0,
+0xc7,0x20,0x48,0x12,0x4,0x81,0x20,0x90,0x8,0x82,
+0x2,0x5,0xb,0xd,0x86,0,0,0,0x10,0x20,
+0x28,0xcc,0x95,0xa7,0x5,0x81,0x1,0x4,0x85,0x8c,
+0xc0,0,0,0x80,0x82,0x46,0x61,0x8,0xd,0x80,
+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,
+0x2,0x50,0xa4,0x94,0x48,0x12,0x8,0x84,0x7c,0,
+0,0x4,0x84,0x70,0x84,0x84,0x14,0x80,0x84,0x4,
+0x84,0x84,0,0,0,0,0x84,0x40,0x20,0xa0,
+0x82,0x20,0x90,0x44,0x2,0,0x81,0x20,0x44,0x2,
+0x44,0x10,0x18,0xc,0xa1,0x10,0x44,0x11,0x4,0x41,
+0x20,0x82,0x8,0x11,0x4,0x42,0x84,0x42,0x20,0x80,
+0x88,0x84,0x50,0,0,0x8,0,0,0x40,0x8,
+0,0x80,0x2,0x4,0,0,0,0,0,0,
+0,0x80,0,0,0,0,0,0x8,0x88,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x48,0x40,
+0x10,0x51,0x10,0xc,0x30,0xe0,0,0,0xc,0x30,
+0x12,0x8,0x4a,0x40,0,0xf4,0,0x31,0x20,0x2,
+0x10,0x22,0x2,0x10,0,0xa,0x1,0x40,0x28,0x5,
+0,0xa0,0x14,0x2,0x80,0x20,0x90,0x8,0x4,0x2,
+0,0x84,0x21,0x10,0x45,0x8,0x82,0x10,0x42,0x8,
+0x41,0x8,0x20,0,0x82,0x20,0x48,0x12,0x4,0x81,
+0x20,0x9f,0x88,0x80,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x9,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x8,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,0x2,0,0xa4,0x94,0x48,0x12,
+0x1,0x2,0x10,0x10,0,0x4,0x84,0x10,0x84,0x84,
+0x24,0x80,0x80,0x8,0x84,0x84,0x90,0,0,0,
+0x84,0x46,0xa0,0xa0,0x82,0x40,0x10,0x24,0x2,0x1,
+0,0x20,0x44,0x2,0x48,0x10,0x14,0x14,0x91,0x20,
+0x24,0x12,0x2,0x41,0x20,0x2,0x8,0x11,0x4,0x22,
+0x88,0x24,0x11,0x1,0x8,0x84,0x88,0,0x7,0x8b,
+0x87,0x87,0x47,0x9c,0x74,0xb8,0x92,0x24,0xb3,0x17,
+0xf,0x17,0xe,0x96,0x79,0xe8,0x48,0x51,0x16,0x38,
+0x3f,0x88,0x88,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x87,0x88,0x8,0x48,0x91,0x80,0x9,0x91,0x20,
+0,0,0xb,0x90,0x12,0x8,0x8,0x80,0x42,0xf4,
+0,0x11,0x20,0x2,0x20,0x24,0x1,0x20,0x8,0xa,
+0x1,0x40,0x28,0x5,0,0xa0,0x14,0x2,0x80,0x40,
+0x10,0x8,0x4,0x2,0,0x84,0x21,0x10,0x24,0x89,
+0x1,0x20,0x24,0x4,0x80,0x90,0x12,0x9,0x5,0x20,
+0x48,0x12,0x4,0x81,0x11,0x10,0xc8,0x8f,0xf,0xf,
+0xf,0xf,0xf,0xf,0x78,0x78,0x78,0x78,0x78,0x78,
+0x92,0x40,0x8b,0x87,0x87,0x87,0x87,0x87,0x81,0x3,
+0xd4,0x24,0x24,0x24,0x28,0x2b,0x90,0x40,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,0x2,0x3,
+0xf2,0x83,0x90,0xc,0x1,0x2,0x28,0x10,0,0x4,
+0x84,0x10,0x8,0x4,0x24,0x80,0x80,0x8,0x84,0x84,
+0x90,0x18,0,0xc0,0x4,0x89,0x21,0x10,0x82,0x40,
+0x10,0x24,0x2,0x1,0,0x20,0x44,0x2,0x50,0x10,
+0x14,0x14,0x91,0x20,0x24,0x32,0x2,0x42,0x18,0x2,
+0x8,0x10,0x88,0x22,0x88,0x18,0x11,0x3,0x8,0x85,
+0x4,0,0xc,0xcc,0xcc,0xcc,0xcc,0xc8,0xcc,0xcc,
+0x92,0x44,0xcc,0x99,0x99,0x99,0x99,0x98,0x84,0x88,
+0x48,0x51,0x12,0x28,0x20,0x88,0x88,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x8c,0xc4,0x7,0x88,0x90,
+0xe0,0x12,0x49,0xa1,0x27,0xf0,0x12,0x48,0xc,0x8,
+0x10,0x40,0x42,0xf4,0,0x10,0xc4,0x82,0x20,0x24,
+0x9,0x20,0x8,0x11,0x2,0x20,0x44,0x8,0x81,0x10,
+0x22,0x4,0x80,0x40,0x10,0x8,0x4,0x2,0,0x84,
+0x21,0x10,0x24,0x89,0x1,0x20,0x24,0x4,0x80,0x90,
+0x11,0x11,0x9,0x20,0x48,0x12,0x4,0x81,0x11,0x10,
+0x4b,0x19,0x99,0x99,0x99,0x99,0x99,0x98,0xcc,0xcc,
+0xcc,0xcc,0xcc,0xcc,0x92,0x47,0xcc,0xcc,0xcc,0xcc,
+0xcc,0xcc,0xc1,0x6,0x24,0x24,0x24,0x24,0x2c,0x2c,
+0xd8,0x40,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,0x2,0x1,0x41,0xc0,0x10,0x8,0x1,0x2,
+0,0x10,0,0x8,0x84,0x10,0x10,0x38,0x44,0xf8,
+0xb8,0x10,0x78,0x84,0,0x61,0xf8,0x30,0x8,0x91,
+0x21,0x10,0xfc,0x40,0x10,0x27,0xe3,0xf1,0xf,0x3f,
+0xc4,0x2,0x70,0x10,0x12,0x24,0x89,0x20,0x27,0xe2,
+0x2,0x7c,0x6,0x2,0x8,0x10,0x88,0x22,0x88,0x18,
+0xa,0x2,0x8,0x44,0,0,0,0x48,0x48,0x8,
+0x48,0x48,0x84,0x84,0x92,0x84,0x88,0x90,0x90,0x90,
+0x90,0x90,0x80,0x88,0x48,0x51,0x11,0x44,0x41,0x10,
+0x84,0x64,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x9,
+0x4,0x4,0x85,0x1,0x30,0x12,0x8,0x2,0x40,0x10,
+0x12,0x48,0,0x7f,0x22,0x40,0x42,0x74,0,0x10,
+0x2,0x42,0x44,0x29,0x86,0x44,0,0x11,0x2,0x20,
+0x44,0x8,0x81,0x10,0x22,0x4,0xfc,0x40,0x1f,0x8f,
+0xc7,0xe3,0xf0,0x84,0x21,0x3c,0x24,0x49,0x1,0x20,
+0x24,0x4,0x80,0x90,0x10,0xa1,0x11,0x20,0x48,0x12,
+0x4,0x81,0xa,0x10,0x49,0,0x80,0x80,0x80,0x80,
+0x80,0x80,0x84,0x80,0x84,0x84,0x84,0x84,0x92,0x48,
+0x48,0x48,0x48,0x48,0x48,0x48,0x40,0x4,0x64,0x24,
+0x24,0x24,0x24,0x48,0x48,0x80,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,0x2,0x1,0x40,0xa0,
+0x20,0x14,0x81,0x2,0,0xfe,0x1e,0x8,0x84,0x10,
+0x20,0x4,0x84,0x4,0xc4,0x10,0x84,0x7c,0x1,0x80,
+0,0xc,0x10,0x91,0x22,0x8,0x82,0x40,0x10,0x24,
+0x2,0x1,0x1,0x20,0x44,0x2,0x48,0x10,0x12,0x24,
+0x89,0x20,0x24,0x2,0x22,0x42,0x1,0x82,0x8,0x10,
+0x88,0x14,0x50,0x24,0x4,0x4,0x8,0x44,0,0,
+0x7,0xc8,0x48,0x8,0x4f,0xc8,0x84,0x84,0x93,0x4,
+0x88,0x90,0x90,0x90,0x90,0x90,0x78,0x88,0x44,0x89,
+0x20,0x84,0x42,0x20,0x82,0xb4,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x89,0x1f,0x4,0x9f,0xc1,0x10,0x12,
+0x9,0xe4,0x80,0x17,0x93,0x88,0,0x8,0x79,0x80,
+0x42,0x34,0x60,0x11,0xe1,0x20,0x4c,0xa,0x40,0x4c,
+0x8,0x20,0x84,0x10,0x82,0x10,0x42,0x8,0x41,0x8,
+0x80,0x40,0x10,0x8,0x4,0x2,0,0x84,0x21,0x10,
+0x24,0x49,0x1,0x20,0x24,0x4,0x80,0x90,0x10,0x41,
+0x21,0x20,0x48,0x12,0x4,0x81,0x4,0x10,0xc8,0x8f,
+0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0xfc,0x80,0xfc,0xfc,
+0xfc,0xfc,0x92,0x48,0x48,0x48,0x48,0x48,0x48,0x48,
+0x4f,0xe4,0xa4,0x24,0x24,0x24,0x24,0x48,0x48,0x80,
+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,
+0x2,0x7,0xe0,0x90,0x4e,0x22,0x81,0x2,0,0x10,
+0,0x8,0x84,0x10,0x40,0x4,0xfe,0x4,0x84,0x20,
+0x84,0x4,0,0x61,0xf8,0x30,0x20,0x93,0x43,0xf8,
+0x82,0x40,0x10,0x24,0x2,0x1,0x1,0x20,0x44,0x2,
+0x44,0x10,0x11,0x44,0x85,0x20,0x24,0x2,0x12,0x41,
+0,0x82,0x8,0x10,0x50,0x14,0x50,0x42,0x4,0xc,
+0x8,0x44,0,0,0xc,0x48,0x48,0x8,0x48,0x8,
+0x84,0x84,0x92,0x84,0x88,0x90,0x90,0x90,0x90,0x90,
+0xc,0x88,0x44,0x89,0x20,0x82,0x44,0x10,0x84,0x98,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x8a,0x4,0x7,
+0x82,0x1,0x10,0x12,0x48,0x2,0x40,0x10,0x12,0x48,
+0,0x8,0,0,0x42,0x14,0,0,0x2,0x40,
+0x94,0x10,0x40,0x94,0x10,0x3f,0x87,0xf0,0xfe,0x1f,
+0xc3,0xf8,0x7f,0xf,0x80,0x40,0x10,0x8,0x4,0x2,
+0,0x84,0x21,0x10,0x24,0x29,0x1,0x20,0x24,0x4,
+0x80,0x90,0x10,0xa1,0x41,0x20,0x48,0x12,0x4,0x81,
+0x4,0x1f,0x88,0x98,0x98,0x98,0x98,0x98,0x98,0x98,
+0x80,0x80,0x80,0x80,0x80,0x80,0x92,0x48,0x48,0x48,
+0x48,0x48,0x48,0x48,0x40,0x5,0x24,0x24,0x24,0x24,
+0x22,0x48,0x44,0x80,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,0x2,0x84,0x90,0x91,0x21,
+0x1,0x2,0,0x10,0,0x10,0x84,0x10,0x80,0x84,
+0x4,0x84,0x84,0x20,0x84,0x84,0,0x18,0,0xc0,
+0,0x8d,0x82,0x8,0x82,0x20,0x90,0x44,0x2,0,
+0x81,0x20,0x44,0x42,0x42,0x10,0x11,0x44,0x85,0x10,
+0x44,0x1,0xc,0x41,0x20,0x82,0x8,0x10,0x50,0x14,
+0x50,0x42,0x4,0x8,0x8,0x24,0,0,0x8,0x48,
+0x48,0x48,0x48,0x8,0x84,0x84,0x92,0x44,0x88,0x90,
+0x90,0x90,0x90,0x90,0x4,0x88,0x44,0x8a,0xa1,0x42,
+0x88,0x8,0x88,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x8a,0x48,0x8,0x5f,0xd1,0x90,0x9,0x90,0x1,
+0x20,0,0xa,0x50,0,0x8,0,0,0x42,0x14,
+0,0,0x4,0x80,0xa4,0x10,0x80,0xa4,0x20,0x20,
+0x84,0x10,0x82,0x10,0x42,0x8,0x41,0x8,0x80,0x20,
+0x90,0x8,0x4,0x2,0,0x84,0x21,0x10,0x44,0x28,
+0x82,0x10,0x42,0x8,0x41,0x8,0x21,0x10,0x82,0x20,
+0x48,0x12,0x4,0x81,0x4,0x10,0x8,0x90,0x90,0x90,
+0x90,0x90,0x90,0x90,0x80,0x84,0x80,0x80,0x80,0x80,
+0x92,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x41,0x6,
+0x24,0x24,0x24,0x24,0x22,0x88,0x45,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,0x2,0x2,
+0x84,0x90,0x91,0x22,0x81,0x2,0,0x10,0x40,0x50,
+0x84,0x10,0x80,0x84,0x4,0x84,0x84,0x40,0x84,0x84,
+0x90,0,0,0,0x20,0x40,0x4,0x4,0x82,0x31,
+0x90,0xc4,0x2,0,0xc7,0x20,0x44,0x42,0x41,0x10,
+0x10,0x84,0x83,0x18,0xc4,0x1,0x8c,0x41,0x31,0x82,
+0x4,0x20,0x20,0x8,0x20,0x81,0x4,0x10,0x8,0x24,
+0,0,0xc,0xcc,0xcc,0xcc,0xcc,0xc8,0xcc,0x84,
+0x92,0x24,0x88,0x90,0x99,0x99,0x99,0x90,0x84,0x8c,
+0xc3,0x4,0x42,0x21,0x90,0x8,0x88,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x8c,0xcc,0x40,0x2,0x10,
+0xe0,0xc,0x30,0,0,0,0xc,0x30,0,0,
+0,0,0x66,0x14,0,0,0,0x1,0x3e,0x21,
+0x1,0x3e,0x40,0x40,0x48,0x9,0x1,0x20,0x24,0x4,
+0x80,0x90,0x80,0x31,0x90,0x8,0x4,0x2,0,0x84,
+0x21,0x10,0xc4,0x18,0xc6,0x18,0xc3,0x18,0x63,0xc,
+0x62,0x9,0xc6,0x10,0x84,0x21,0x8,0x42,0x4,0x10,
+0x8,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0xcc,0xcc,
+0xcc,0xcc,0xcc,0xcc,0x92,0x4c,0xc8,0x4c,0xcc,0xcc,
+0xcc,0xcc,0xc1,0x4,0x66,0x66,0x66,0x66,0x61,0x8c,
+0xc3,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,0x2,0x2,0x83,0xe1,0xe,0x1c,0x41,0x2,
+0,0,0x40,0x50,0x78,0x10,0xfc,0x78,0x4,0x78,
+0x78,0x40,0x78,0x78,0x90,0,0,0,0x20,0x60,
+0x84,0x4,0xfc,0xe,0x1f,0x7,0xf2,0,0x39,0x20,
+0x44,0x3c,0x40,0x9f,0x90,0x84,0x83,0x7,0x4,0,
+0x72,0x41,0xe,0x2,0x3,0xc0,0x20,0x8,0x20,0x81,
+0x4,0x1f,0xc8,0x24,0,0,0x7,0x6b,0x87,0x87,
+0x47,0x88,0x74,0x84,0x92,0x14,0x88,0x90,0x8f,0x17,
+0xe,0x90,0x78,0x67,0x43,0x4,0x46,0x31,0x1f,0x88,
+0x88,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x87,
+0x9b,0x80,0x2,0x10,0x30,0x3,0xc0,0,0,0,
+0x3,0xc0,0,0x7f,0,0,0x5a,0x14,0,0,
+0,0x1,0x4,0x23,0xc1,0x4,0x42,0x40,0x48,0x9,
+0x1,0x20,0x24,0x4,0x80,0x90,0xfe,0xe,0x1f,0xcf,
+0xe7,0xf3,0xf8,0x84,0x21,0x1f,0x4,0x18,0x38,0x7,
+0,0xe0,0x1c,0x3,0x80,0x2,0x38,0xf,0x3,0xc0,
+0xf0,0x3c,0x4,0x10,0xb,0xe,0xce,0xce,0xce,0xce,
+0xce,0xcf,0x78,0x78,0x78,0x78,0x78,0x78,0x92,0x47,
+0x88,0x47,0x87,0x87,0x87,0x87,0x80,0xb,0xc3,0xa3,
+0xa3,0xa3,0xa1,0xb,0x82,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,0,0,0x80,
+0,0,0,0x84,0,0,0x40,0,0,0,
+0,0,0,0,0,0,0,0,0x10,0,
+0,0,0,0x1f,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,0x8,0x4,0,0,
+0,0,0,0,0,0,0x4,0,0x10,0,
+0,0,0,0x10,0,0x80,0,0,0,0,
+0,0x1,0,0x8,0x88,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x88,0,0,0,0x11,0x10,0,
+0,0,0,0,0,0,0,0,0,0,
+0x40,0x14,0x2,0,0,0,0,0,0,0,
+0x42,0,0,0,0,0,0,0,0,0,
+0,0x4,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,0x10,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x1,0x8,0x2,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,0,0,0x80,0,0,0,0x84,0,0,
+0x80,0,0,0,0,0,0,0,0,0,
+0,0,0x20,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,
+0x8,0x4,0,0,0,0,0,0,0,0,
+0xcc,0,0x10,0,0,0,0,0x10,0,0x80,
+0,0,0,0,0,0x3,0,0x8,0x88,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x80,0,0,
+0,0x11,0xb0,0,0,0,0,0,0,0,
+0,0,0,0,0x40,0x14,0x9,0,0,0,
+0,0,0,0,0x66,0,0,0,0,0,
+0,0,0,0,0,0x12,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,0x48,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x3,0x8,0x6,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,0,0,0,0,0,
+0,0x48,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,0xe,0x1c,0x3,0xfc,0,0,
+0,0,0,0,0x78,0,0x60,0,0,0,
+0,0x10,0,0x80,0,0,0,0,0,0x6,
+0,0x6,0xb0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x80,0,0,0,0,0xe0,0,0,0,
+0,0,0,0,0,0,0,0,0x40,0x14,
+0x6,0,0,0,0,0,0,0,0x18,0,
+0,0,0,0,0,0,0,0,0,0xc,
+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,0x30,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x6,0x8,0xc,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,
+};
+
+static WORD Helvetica14_ch_ofst[225] = {
+0,4,8,13,21,29,41,51,54,59,
+64,71,80,83,88,91,95,103,111,119,
+127,135,143,151,159,167,175,178,182,190,
+199,207,215,228,239,248,258,268,277,286,
+297,307,312,320,330,338,351,361,372,381,
+392,401,410,419,429,440,455,465,474,483,
+487,491,495,502,510,515,523,531,539,547,
+555,559,567,575,578,581,588,591,602,610,
+618,626,634,639,647,651,659,667,677,684,
+691,698,703,706,711,719,723,727,731,735,
+739,743,747,751,755,759,763,767,771,775,
+779,783,787,791,795,799,803,807,811,815,
+819,823,827,831,835,839,843,847,851,855,
+859,867,875,883,890,893,901,906,918,924,
+932,941,946,958,962,968,977,982,987,992,
+1000,1008,1012,1017,1022,1028,1036,1048,1060,1072,
+1080,1091,1102,1113,1124,1135,1146,1160,1170,1179,
+1188,1197,1206,1211,1216,1221,1226,1236,1246,1257,
+1268,1279,1290,1301,1310,1321,1331,1341,1351,1361,
+1370,1379,1386,1394,1402,1410,1418,1426,1434,1447,
+1455,1463,1471,1479,1487,1490,1493,1496,1499,1507,
+1515,1523,1531,1539,1547,1555,1564,1572,1580,1588,
+1596,1604,1611,1619,1626,
+};
+
+static struct font_hdr Helvetica14_font = {
+STPROP, 14, "AdobeHelv-M-R-N--14-140-75-75-P", 32, 255,
+17, 14, 8, 3, 3,
+15, 15, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Helvetica14_ch_ofst, Helvetica14_data,
+274, 17,
+NULL,
+0, 0,   /* x/y offset */
+19,        /* lineHeight */
+13,	   /* psHeight */
+};
+
+MgFont *mgHelvetica14Font()
+{
+return &Helvetica14_font;
+}
+
+MgFont *mgMediumFont()
+{
+return &Helvetica14_font;
+}
diff --git a/lib/font/mgHelvetica18.c b/lib/font/mgHelvetica18.c
new file mode 100644
index 0000000..1a21963
--- /dev/null
+++ b/lib/font/mgHelvetica18.c
@@ -0,0 +1,845 @@
+
+/* Helvetica18.c - compiled data for font AdobeHelv-M-R-N--18-180-75-75-P */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/helvR18.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Helvetica18_data[7832] = {
+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,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,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,0x30,0,0x30,0xc,0x1,0x90,0,0x1,0xe0,
+0,0,0,0,0x30,0,0x60,0x30,0,0x18,
+0x6,0x60,0,0,0x6,0x40,0x30,0,0x6,0,
+0x30,0,0xc8,0,0,0,0,0,0x6,0,
+0x6,0,0x60,0,0,0x6,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,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,
+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,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x18,0,0x60,
+0x1e,0x2,0xd0,0x33,0x3,0x30,0,0,0,0,
+0x18,0,0xc0,0x78,0x19,0x8c,0xc,0xf6,0x60,0,
+0xb,0x40,0x18,0,0xc,0,0x78,0x1,0x68,0x3,
+0x60,0,0,0,0x3,0,0xc,0,0xf0,0xc,
+0xc0,0xc,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,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,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,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xc,0,0xc0,0x33,0x2,0x60,0x33,
+0x3,0x30,0,0,0,0,0xc,0x1,0x80,0xcc,
+0x19,0x86,0x19,0x9e,0x60,0,0x9,0x80,0xc,0,
+0x18,0,0xcc,0x1,0x30,0x3,0x60,0,0,0,
+0x1,0x80,0x18,0x1,0x98,0xc,0xc0,0x18,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,
+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,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,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,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,0x1,0xe0,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,
+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,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,0x1,0x9b,0,0x1,0,0,
+0,0,0x20,0x90,0x10,0,0,0,0x6,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0xe0,0x7,0xe0,
+0x6,0x7,0xf8,0x3,0xe0,0xff,0x7,0xfc,0xff,0x81,
+0xf0,0x60,0x31,0x80,0x33,0x3,0x98,0x6,0,0x66,
+0x3,0x3,0xe0,0x7f,0x80,0x7c,0xf,0xf0,0x1f,0x7,
+0xfe,0x60,0x33,0,0xcc,0x18,0x33,0x1,0x98,0x6,
+0x7f,0xe7,0xe3,0xc0,0,0x3,0,0xc,0,0,
+0,0xc0,0,0xe0,0x1,0x80,0x66,0x60,0x30,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0x6c,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,0x6,0x1e,0,0,
+0,0x70,0,0,0,0,0,0,0,0,
+0,0x18,0,0x3f,0,0,0x38,0,0,0,
+0,0,0,0,0,0xc,0,0xc0,0xc,0,
+0xc0,0xc,0,0xc0,0x7,0xff,0x3,0xe0,0xff,0x9f,
+0xf3,0xfe,0x7f,0xc6,0x18,0x61,0x8f,0xf0,0x70,0x30,
+0x3e,0,0x7c,0,0xf8,0x1,0xf0,0x3,0xe0,0,
+0x1,0xf3,0x30,0x19,0x80,0xcc,0x6,0x60,0x33,0,
+0xcc,0,0x38,0x30,0x3,0x3,0x3,0x20,0,0xe0,
+0,0,0,0x60,0x1,0x81,0x80,0x1,0x84,0xc0,
+0x18,0x1,0x90,0x60,0x1,0x80,0x60,0x19,0,0,
+0,0,0x6,0,0x30,0x30,0,0,0xc6,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,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,
+0x1,0x9b,0x9,0x7,0xc3,0xc3,0x1,0xe0,0x21,0x98,
+0x10,0,0,0,0x6,0x3c,0x3,0x3,0xc0,0xf0,
+0x3,0x3f,0x83,0xc3,0xfc,0x3c,0xf,0,0,0,
+0,0,0x7,0xf0,0x1f,0xf8,0x6,0x7,0xfc,0xf,
+0xf8,0xff,0x87,0xfc,0xff,0x87,0xfc,0x60,0x31,0x80,
+0x33,0x7,0x18,0x6,0,0x67,0x3,0xf,0xf8,0x7f,
+0xc1,0xff,0xf,0xf8,0x7f,0xc7,0xfe,0x60,0x33,0,
+0xcc,0x18,0x33,0x83,0x98,0x6,0x7f,0xe7,0xe3,0xc1,
+0,0x1,0x80,0xc,0,0,0,0xc0,0x1,0xe0,
+0x1,0x80,0x66,0x60,0x30,0,0,0,0,0,
+0,0,0,0x1,0x80,0,0,0,0,0,
+0,0,0x6,0x66,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,0x78,
+0,0x18,0x66,0x3f,0x36,0x7,0xc0,0xc8,0,0,
+0,0x3,0xe1,0xf3,0x80,0x3,0x8e,0x30,0,0x72,
+0,0xc,0x6c,0,0x30,0x30,0x60,0x61,0xc0,0xc0,
+0,0xc,0,0xc0,0xc,0,0xc0,0xc,0,0xc0,
+0x7,0xff,0xf,0xf8,0xff,0x9f,0xf3,0xfe,0x7f,0xc6,
+0x18,0x61,0x8f,0xf8,0x70,0x30,0xff,0x81,0xff,0x3,
+0xfe,0x7,0xfc,0xf,0xf8,0,0x7,0xff,0x30,0x19,
+0x80,0xcc,0x6,0x60,0x33,0,0xcc,0,0x7c,0x18,
+0x6,0x7,0x85,0xa3,0x61,0xb0,0,0,0,0x30,
+0x3,0x3,0xc0,0xd8,0xcd,0xed,0x8d,0x82,0xd0,0x30,
+0x3,0,0xf0,0x2d,0x6,0xc0,0,0,0x3,0,
+0x60,0x78,0x33,0x1,0x86,0,0x66,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,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,0x1,0x9b,0x9,0xf,
+0xe7,0xe6,0x3,0xf0,0x23,0xc,0x7c,0,0,0,
+0x4,0x7e,0x1f,0xf,0xe1,0xf8,0x7,0x3f,0x87,0xf3,
+0xfc,0x7e,0x1f,0x80,0,0,0,0,0x6,0x30,
+0x38,0x1c,0xf,0x6,0xe,0x1c,0x1c,0xc1,0xc6,0,
+0xc0,0xe,0xe,0x60,0x31,0x80,0x33,0xe,0x18,0x7,
+0,0xe7,0x83,0x1c,0x1c,0x60,0xe3,0x83,0x8c,0x1c,
+0xe0,0xe0,0x60,0x60,0x31,0x81,0x8c,0x18,0x31,0x83,
+0xc,0xc,0,0x66,0x20,0xc3,0x80,0,0xc0,0xc,
+0,0,0,0xc0,0x1,0x80,0x1,0x80,0,0x60,
+0x30,0,0,0,0,0,0,0,0,0x1,
+0x80,0,0,0,0,0,0,0,0xc,0x63,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x20,0xfc,0,0x18,0x66,0x61,
+0xb6,0x18,0x30,0x38,0,0,0,0xc,0x18,0x6,
+0xc0,0x7,0xdf,0x60,0,0xf2,0,0x1c,0x44,0,
+0x70,0x30,0xe0,0x63,0xe0,0xc0,0,0x1e,0x1,0xe0,
+0x1e,0x1,0xe0,0x1e,0x1,0xe0,0xd,0x80,0x1c,0x1c,
+0xc0,0x18,0x3,0,0x60,0x6,0x18,0x61,0x8c,0x1c,
+0x78,0x31,0xc1,0xc3,0x83,0x87,0x7,0xe,0xe,0x1c,
+0x1c,0,0xe,0xe,0x30,0x19,0x80,0xcc,0x6,0x60,
+0x31,0x81,0x8c,0,0xc6,0xc,0xc,0xc,0xc4,0xc3,
+0x61,0xb0,0,0,0,0x18,0x6,0x6,0x60,0xd8,
+0x7b,0x3d,0x8e,0x2,0x60,0x18,0x6,0x1,0x98,0x26,
+0x6,0xc0,0,0,0x1,0x80,0xc0,0xcc,0x33,0x3,
+0x6,0,0x66,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,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,0x1,0x92,0x9,0x19,0x66,0x66,0x3,0x30,
+0x23,0xc,0x38,0,0,0,0x4,0x66,0x1f,0xc,
+0x33,0xc,0xf,0x30,0x6,0x30,0xc,0xe7,0x31,0xc0,
+0,0,0,0,0x6,0x30,0x60,0xc,0xf,0x6,
+0x6,0x18,0xc,0xc0,0xc6,0,0xc0,0xc,0x6,0x60,
+0x31,0x80,0x33,0x1c,0x18,0x7,0,0xe7,0x83,0x18,
+0xc,0x60,0x63,0x1,0x8c,0xc,0xc0,0x60,0x60,0x60,
+0x31,0x81,0x8c,0x3c,0x31,0xc7,0xc,0xc,0,0xc6,
+0x20,0xc6,0xc0,0,0,0xc,0,0,0,0xc0,
+0x1,0x80,0x1,0x80,0,0x60,0x30,0,0,0,
+0,0,0,0,0,0x1,0x80,0,0,0,
+0,0,0,0,0xc,0x63,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x21,0x86,0,0xc,0xc6,0x61,0x80,0x20,0x8,0x48,
+0,0,0,0x10,0x4,0x4,0x41,0x84,0xd3,0,
+0,0xf2,0,0x1c,0x44,0,0x70,0x60,0xe0,0xc2,
+0x61,0x80,0,0x1e,0x1,0xe0,0x1e,0x1,0xe0,0x1e,
+0x1,0xe0,0xd,0x80,0x18,0xc,0xc0,0x18,0x3,0,
+0x60,0x6,0x18,0x61,0x8c,0xc,0x6c,0x31,0x80,0xc3,
+0x1,0x86,0x3,0xc,0x6,0x18,0xc,0,0xc,0x1e,
+0x30,0x19,0x80,0xcc,0x6,0x60,0x31,0x81,0x8f,0xf0,
+0xc6,0,0,0,0,0,0,0xe0,0,0,
+0,0,0,0,0,0,0,0,0x13,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x6,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,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,0x1,0x92,
+0x7f,0xd9,0x6,0x6c,0x3,0x30,0x26,0x6,0x38,0x18,
+0,0,0xc,0xc3,0x3,0,0x33,0xc,0x1b,0x30,
+0xc,0,0x18,0xc3,0x30,0xcc,0x60,0,0,0,
+0,0x70,0xc7,0x66,0x19,0x86,0x6,0x38,0,0xc0,
+0x66,0,0xc0,0x1c,0x6,0x60,0x31,0x80,0x33,0x38,
+0x18,0x7,0x81,0xe6,0xc3,0x38,0xe,0x60,0x67,0x1,
+0xcc,0xc,0xe0,0,0x60,0x60,0x31,0x81,0x86,0x3c,
+0x60,0xc6,0x6,0x18,0x1,0x86,0x30,0xcc,0x60,0,
+0xf,0x8d,0xe0,0x7c,0x1e,0xc3,0xc7,0xe3,0xd9,0x9c,
+0x66,0x63,0x33,0x31,0x8c,0xe0,0xf8,0x6f,0x3,0xd9,
+0xb1,0xe7,0xec,0x33,0xc,0xc6,0x33,0xc,0xc3,0x3f,
+0x8c,0x63,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xc1,0xf1,0x86,0x61,0x8c,
+0xc6,0x78,0,0x23,0x88,0xd8,0,0,0,0x13,
+0xe4,0x6,0xc1,0x80,0xc6,0x3,0xc,0xf2,0,0xc,
+0x6c,0,0x30,0xc0,0x61,0x80,0xc3,0,0x60,0x33,
+0x3,0x30,0x33,0x3,0x30,0x33,0x3,0x30,0x19,0x80,
+0x38,0,0xc0,0x18,0x3,0,0x60,0x6,0x18,0x61,
+0x8c,0x6,0x6c,0x33,0x80,0xe7,0x1,0xce,0x3,0x9c,
+0x7,0x38,0xe,0,0x1c,0x37,0x30,0x19,0x80,0xcc,
+0x6,0x60,0x30,0xc3,0xf,0xf8,0xc6,0x3e,0x1f,0xf,
+0x87,0xc3,0xe1,0xf0,0xfb,0xc0,0xf8,0x3c,0xf,0x3,
+0xc0,0xf0,0xcc,0xc6,0xf,0x86,0x70,0x7c,0xf,0x81,
+0xf0,0x3e,0x7,0xc0,0,0x1c,0xd8,0x66,0x19,0x86,
+0x61,0x98,0x66,0xf0,0xc3,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,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,0x1,0x80,0x7f,0xdd,0x7,0xec,
+0x1,0xe0,0x6,0x6,0x44,0x18,0,0,0xc,0xc3,
+0x3,0,0x70,0x18,0x33,0x3f,0xc,0,0x30,0xc3,
+0x30,0xcc,0x60,0xc,0,0x18,0,0xe0,0xce,0xe6,
+0x19,0x86,0xc,0x30,0,0xc0,0x66,0,0xc0,0x18,
+0,0x60,0x31,0x80,0x33,0x70,0x18,0x7,0x81,0xe6,
+0x63,0x30,0x6,0x60,0xe6,0,0xcc,0x1c,0x7c,0,
+0x60,0x60,0x30,0xc3,0x6,0x24,0x60,0x6c,0x6,0x18,
+0x3,0x6,0x30,0xc8,0x20,0,0x1d,0xcf,0xf0,0xfe,
+0x3f,0xc7,0xe7,0xe7,0xf9,0xbe,0x66,0x66,0x33,0x7b,
+0xcd,0xf1,0xfc,0x7f,0x87,0xf9,0xb3,0xf7,0xec,0x33,
+0xc,0xc6,0x33,0x9c,0xc3,0x3f,0x8c,0x63,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xc3,0xf9,0x80,0x7f,0x8c,0xc6,0x3e,0,0x44,
+0x44,0x68,0x24,0,0,0x22,0x12,0x3,0x81,0x81,
+0x86,0x3,0xc,0xf2,0,0xc,0x38,0x90,0x30,0xc0,
+0x61,0x80,0xc3,0,0x60,0x33,0x3,0x30,0x33,0x3,
+0x30,0x33,0x3,0x30,0x19,0x80,0x30,0,0xc0,0x18,
+0x3,0,0x60,0x6,0x18,0x61,0x8c,0x6,0x66,0x33,
+0,0x66,0,0xcc,0x1,0x98,0x3,0x30,0x6,0xc0,
+0xd8,0x73,0x30,0x19,0x80,0xcc,0x6,0x60,0x30,0xc3,
+0xc,0x1c,0xc6,0x77,0x3b,0x9d,0xce,0xe7,0x73,0xb9,
+0xdf,0xe1,0xfc,0x7e,0x1f,0x87,0xe1,0xf8,0xcc,0xc6,
+0x1f,0xc6,0xf8,0xfe,0x1f,0xc3,0xf8,0x7f,0xf,0xe0,
+0x60,0x7f,0x98,0x66,0x19,0x86,0x61,0x98,0x67,0xf8,
+0xc3,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,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,
+0x1,0x80,0x12,0xf,0x3,0xd8,0x3,0xe0,0x6,0x6,
+0,0x18,0,0,0x8,0xc3,0x3,0,0xe0,0x70,
+0x33,0x3f,0x8d,0xc0,0x30,0x66,0x30,0xc0,0,0x3c,
+0x7f,0x1e,0x1,0xc1,0x8c,0x66,0x30,0xc7,0xfc,0x30,
+0,0xc0,0x67,0xf8,0xff,0x18,0,0x7f,0xf1,0x80,
+0x33,0xe0,0x18,0x6,0xc3,0x66,0x63,0x30,0x6,0x7f,
+0xc6,0,0xcf,0xf8,0x1f,0,0x60,0x60,0x30,0xc3,
+0x6,0x66,0x60,0x38,0x3,0x30,0x6,0x6,0x10,0xc0,
+0,0,0x18,0xce,0x30,0xc6,0x31,0xcc,0x31,0x86,
+0x19,0xc6,0x66,0x6c,0x33,0x9c,0xce,0x31,0x8c,0x71,
+0x86,0x39,0xc6,0x31,0x8c,0x33,0xc,0xc6,0x31,0x98,
+0xc3,0x1,0x8c,0x63,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0x58,0xc0,
+0x33,0x7,0x86,0x37,0,0x48,0x4,0,0x6c,0xff,
+0x80,0x22,0x12,0,0xf,0xf3,0x13,0x3,0xc,0x72,
+0,0xc,0,0xd8,0x31,0x88,0x63,0x72,0x66,0x20,
+0,0x61,0x86,0x18,0x61,0x86,0x18,0x61,0x86,0x18,
+0x31,0xfe,0x30,0,0xff,0x1f,0xe3,0xfc,0x7f,0x86,
+0x18,0x61,0x9f,0x86,0x66,0x33,0,0x66,0,0xcc,
+0x1,0x98,0x3,0x30,0x6,0x61,0x98,0xe3,0x30,0x19,
+0x80,0xcc,0x6,0x60,0x30,0x66,0xc,0xc,0xdc,0x63,
+0x31,0x98,0xcc,0x66,0x33,0x19,0x8c,0x31,0x8c,0xc3,
+0x30,0xcc,0x33,0xc,0xcc,0xc6,0x18,0xc7,0x18,0xc6,
+0x18,0xc3,0x18,0x63,0xc,0x60,0x60,0x63,0x18,0x66,
+0x19,0x86,0x61,0x98,0x67,0x18,0xc3,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,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,0x1,0x80,0x12,0x7,
+0xc0,0x18,0x7,0x76,0x6,0x6,0,0x18,0,0,
+0x8,0xc3,0x3,0x1,0xc0,0x78,0x63,0x31,0xcf,0xe0,
+0x60,0x7e,0x1f,0xc0,0,0xf0,0x7f,0x7,0x81,0x81,
+0x98,0xc6,0x30,0xc7,0xfe,0x30,0,0xc0,0x67,0xf8,
+0xff,0x18,0x3e,0x7f,0xf1,0x80,0x33,0xf0,0x18,0x6,
+0xc3,0x66,0x33,0x30,0x6,0x7f,0x86,0,0xcf,0xf0,
+0x3,0xc0,0x60,0x60,0x30,0xc3,0x6,0x66,0x60,0x38,
+0x1,0xe0,0xe,0x6,0x10,0xc0,0,0,0x1,0xcc,
+0x19,0x80,0x60,0xcc,0x31,0x8c,0x19,0x86,0x66,0x78,
+0x33,0x18,0xcc,0x33,0x6,0x60,0xcc,0x19,0x86,0x1,
+0x8c,0x31,0x98,0x66,0x60,0xf0,0x66,0x3,0x18,0x61,
+0x86,0x60,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x6,0x41,0xf8,0x33,0x1f,0xe0,0x63,
+0x80,0x48,0x4,0xf8,0xd8,0xff,0x80,0x23,0xe2,0,
+0xf,0xf7,0xdf,0x3,0xc,0x32,0,0xc,0x7c,0x6c,
+0x31,0x18,0x62,0xfb,0xe4,0x60,0,0x61,0x86,0x18,
+0x61,0x86,0x18,0x61,0x86,0x18,0x31,0xfe,0x30,0,
+0xff,0x1f,0xe3,0xfc,0x7f,0x86,0x18,0x61,0x9f,0x86,
+0x63,0x33,0,0x66,0,0xcc,0x1,0x98,0x3,0x30,
+0x6,0x33,0x19,0xc3,0x30,0x19,0x80,0xcc,0x6,0x60,
+0x30,0x3c,0xc,0xc,0xdc,0x7,0x3,0x81,0xc0,0xe0,
+0x70,0x38,0x1c,0x33,0,0xc3,0x30,0xcc,0x33,0xc,
+0xcc,0xc6,0x30,0x66,0x19,0x83,0x30,0x66,0xc,0xc1,
+0x98,0x30,0,0xc7,0x98,0x66,0x19,0x86,0x61,0x8c,
+0xc6,0xc,0x66,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,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,0x1,0,0x12,0x1,0xe0,0x33,0xc6,0x36,
+0x6,0x6,0,0xff,0x1,0xf0,0x18,0xc3,0x3,0x3,
+0x80,0x1c,0xc3,0,0xcc,0x30,0x60,0x66,0xe,0xc0,
+0x1,0xc0,0,0x1,0xc1,0x81,0x98,0xcc,0x3f,0xc6,
+0x7,0x30,0,0xc0,0x66,0,0xc0,0x18,0x3e,0x60,
+0x31,0x80,0x33,0x38,0x18,0x6,0x66,0x66,0x33,0x30,
+0x6,0x60,0x6,0,0xcc,0x18,0,0xe0,0x60,0x60,
+0x30,0x66,0x3,0x66,0xc0,0x6c,0,0xc0,0xc,0x6,
+0x18,0xc0,0,0,0xf,0xcc,0x19,0x80,0x60,0xcf,
+0xf1,0x8c,0x19,0x86,0x66,0x7c,0x33,0x18,0xcc,0x33,
+0x6,0x60,0xcc,0x19,0x87,0xe1,0x8c,0x31,0x98,0x66,
+0x60,0x60,0x66,0x6,0x30,0x60,0xcf,0xc0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x46,
+0x40,0x60,0x33,0x3,0,0x61,0x80,0x48,0x4,0x1,
+0xb0,0x1,0x9f,0x22,0x42,0,0x1,0x87,0xce,0x3,
+0xc,0x12,0x30,0xc,0,0x36,0x33,0x38,0x66,0x99,
+0xcc,0xe0,0x60,0x7f,0x87,0xf8,0x7f,0x87,0xf8,0x7f,
+0x87,0xf8,0x3f,0x80,0x30,0,0xc0,0x18,0x3,0,
+0x60,0x6,0x18,0x61,0x8c,0x6,0x63,0x33,0,0x66,
+0,0xcc,0x1,0x98,0x3,0x30,0x6,0x1e,0x1b,0x83,
+0x30,0x19,0x80,0xcc,0x6,0x60,0x30,0x18,0xc,0x1c,
+0xc6,0x3f,0x1f,0x8f,0xc7,0xe3,0xf1,0xf8,0xff,0xf3,
+0,0xff,0x3f,0xcf,0xf3,0xfc,0xcc,0xc6,0x30,0x66,
+0x19,0x83,0x30,0x66,0xc,0xc1,0x98,0x33,0xfc,0xcd,
+0x98,0x66,0x19,0x86,0x61,0x8c,0xc6,0xc,0x66,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,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,0x1,0,
+0xff,0x81,0x30,0x37,0xe6,0x1e,0x6,0x6,0,0xff,
+0x1,0xf0,0x18,0xc3,0x3,0x7,0,0xc,0xff,0x80,
+0xcc,0x30,0xc0,0xc3,0,0xc0,0x3,0,0,0,
+0x61,0x81,0x98,0xcc,0x7f,0xe6,0x3,0x38,0,0xc0,
+0x66,0,0xc0,0x1c,0x6,0x60,0x31,0x8c,0x33,0x1c,
+0x18,0x6,0x66,0x66,0x1b,0x38,0xe,0x60,0x7,0xd,
+0xcc,0x18,0,0x60,0x60,0x60,0x30,0x66,0x3,0x66,
+0xc0,0xc6,0,0xc0,0x18,0x6,0x18,0xc0,0,0,
+0x1c,0xcc,0x19,0x80,0x60,0xcc,0x1,0x8c,0x19,0x86,
+0x66,0x6c,0x33,0x18,0xcc,0x33,0x6,0x60,0xcc,0x19,
+0x81,0xf1,0x8c,0x31,0x98,0x69,0x60,0x60,0x66,0xc,
+0x18,0x61,0x99,0x80,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x46,0x40,0x60,0x7f,0x9f,
+0xe0,0x71,0x80,0x44,0x44,0x1,0xb0,0x1,0x9f,0x22,
+0x22,0,0x1,0x80,0,0x3,0xc,0x12,0x30,0,
+0,0x36,0x6,0x78,0xc,0x18,0x19,0xe0,0x60,0xff,
+0xcf,0xfc,0xff,0xcf,0xfc,0xff,0xcf,0xfc,0x7f,0x80,
+0x38,0,0xc0,0x18,0x3,0,0x60,0x6,0x18,0x61,
+0x8c,0x6,0x61,0xb3,0x80,0xe7,0x1,0xce,0x3,0x9c,
+0x7,0x38,0xe,0xc,0x1b,0x7,0x30,0x19,0x80,0xcc,
+0x6,0x60,0x30,0x18,0xf,0xf8,0xc6,0x73,0x39,0x9c,
+0xce,0x67,0x33,0x99,0xcc,0x3,0,0xc0,0x30,0xc,
+0x3,0,0xcc,0xc6,0x30,0x66,0x19,0x83,0x30,0x66,
+0xc,0xc1,0x98,0x33,0xfc,0xd9,0x98,0x66,0x19,0x86,
+0x61,0x8c,0xc6,0xc,0x66,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,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,0xff,0x99,0x30,0x66,
+0x66,0x1c,0x6,0x6,0,0x18,0,0,0x10,0xc3,
+0x3,0xe,0x3,0xc,0xff,0xb0,0xcc,0x30,0xc0,0xc3,
+0,0xc0,0x1,0xc0,0x7f,0x1,0xc0,0x1,0x99,0x98,
+0x60,0x66,0x3,0x18,0xc,0xc0,0xc6,0,0xc0,0xc,
+0x6,0x60,0x31,0x8c,0x33,0xe,0x18,0x6,0x24,0x66,
+0xf,0x18,0xc,0x60,0x3,0xd,0x8c,0xc,0xc0,0x60,
+0x60,0x60,0x30,0x66,0x3,0x42,0xc1,0xc7,0,0xc0,
+0x30,0x6,0x8,0xc0,0,0,0x18,0xcc,0x19,0x80,
+0x60,0xcc,0x1,0x8c,0x19,0x86,0x66,0x66,0x33,0x18,
+0xcc,0x33,0x6,0x60,0xcc,0x19,0x80,0x31,0x8c,0x30,
+0x90,0x29,0x40,0xf0,0x24,0x18,0xc,0x63,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xc6,0x40,0xc0,0x61,0x83,0,0x39,0x80,0x23,
+0x88,0,0xd8,0x1,0x80,0x12,0x14,0,0x1,0x80,
+0,0x3,0xc,0x12,0,0,0,0x6c,0x6,0xd8,
+0xc,0x30,0x1b,0x60,0x60,0xc0,0xcc,0xc,0xc0,0xcc,
+0xc,0xc0,0xcc,0xc,0x61,0x80,0x18,0xc,0xc0,0x18,
+0x3,0,0x60,0x6,0x18,0x61,0x8c,0xc,0x60,0xf1,
+0x80,0xc3,0x1,0x86,0x3,0xc,0x6,0x18,0xc,0x1e,
+0xe,0x6,0x30,0x19,0x80,0xcc,0x6,0x60,0x30,0x18,
+0xf,0xf0,0xc6,0x63,0x31,0x98,0xcc,0x66,0x33,0x19,
+0x8c,0x3,0,0xc0,0x30,0xc,0x3,0,0xcc,0xc6,
+0x30,0x66,0x19,0x83,0x30,0x66,0xc,0xc1,0x98,0x30,
+0,0xf1,0x98,0x66,0x19,0x86,0x61,0x84,0x86,0xc,
+0x24,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,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,0x24,0x1d,0x70,0x66,0x67,0x3e,0x6,0x6,
+0,0x18,0,0,0x10,0x66,0x3,0xc,0x3,0x1c,
+0x3,0x31,0xce,0x30,0xc0,0xe7,0x31,0x80,0,0xf0,
+0x7f,0x7,0x80,0x1,0x9f,0xf0,0x60,0x66,0x7,0x1c,
+0x1c,0xc1,0xc6,0,0xc0,0xe,0xe,0x60,0x31,0x8e,
+0x73,0x7,0x18,0x6,0x3c,0x66,0xf,0x1c,0x1c,0x60,
+0x3,0x87,0x8c,0xc,0xe0,0xe0,0x60,0x30,0x60,0x3c,
+0x1,0xc3,0x81,0x83,0,0xc0,0x60,0x6,0x8,0xc0,
+0,0,0x18,0xce,0x30,0xc6,0x31,0xce,0x31,0x86,
+0x39,0x86,0x66,0x67,0x33,0x18,0xcc,0x31,0x8c,0x71,
+0x86,0x39,0x86,0x31,0x8c,0x70,0xf0,0x39,0xc1,0x98,
+0x3c,0x30,0xc,0x63,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xc3,0x59,0x82,
+0,0x3,0x6,0x1f,0,0x20,0x8,0,0x6c,0,
+0,0x10,0x4,0,0,0,0,0x3,0x9c,0x12,
+0,0,0,0xd8,0xc,0xfc,0x18,0x60,0x33,0xf0,
+0xe0,0xc0,0xcc,0xc,0xc0,0xcc,0xc,0xc0,0xcc,0xc,
+0x61,0x80,0x1c,0x1c,0xc0,0x18,0x3,0,0x60,0x6,
+0x18,0x61,0x8c,0x1c,0x60,0xf1,0xc1,0xc3,0x83,0x87,
+0x7,0xe,0xe,0x1c,0x1c,0x33,0x1e,0xe,0x18,0x30,
+0xc1,0x86,0xc,0x30,0x60,0x18,0xc,0,0xc6,0x63,
+0x31,0x98,0xcc,0x66,0x33,0x19,0x8e,0x31,0x8c,0xe3,
+0x38,0xce,0x33,0x8c,0xcc,0xc6,0x18,0xc6,0x18,0xc6,
+0x18,0xc3,0x18,0x63,0xc,0x60,0x60,0x63,0x18,0xe6,
+0x39,0x8e,0x63,0x87,0x87,0x18,0x3c,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,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,0x1,0x80,0x24,0xf,
+0xe0,0xc7,0xe3,0xf7,0x6,0x6,0,0x18,0x30,0x3,
+0x30,0x7e,0x3,0xf,0xf1,0xf8,0x3,0x3f,0x87,0xe1,
+0x80,0x7e,0x3f,0x8c,0x60,0x3c,0,0x1e,0x1,0x80,
+0xce,0xe0,0xc0,0x37,0xfe,0xf,0xf8,0xff,0x87,0xfc,
+0xc0,0x7,0xfe,0x60,0x31,0x87,0xe3,0x3,0x9f,0xe6,
+0x18,0x66,0x7,0xf,0xf8,0x60,0x1,0xff,0xc,0xc,
+0x7f,0xc0,0x60,0x3f,0xe0,0x3c,0x1,0x81,0x83,0x83,
+0x80,0xc0,0x7f,0xe6,0xc,0xc0,0,0,0x1d,0xcf,
+0xf0,0xfe,0x3f,0xc7,0xf1,0x87,0xf9,0x86,0x66,0x63,
+0x33,0x18,0xcc,0x31,0xfc,0x7f,0x87,0xf9,0x87,0xe1,
+0xcf,0xb0,0x60,0x19,0x83,0x9c,0x18,0x3f,0x8c,0x63,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xc3,0xfb,0xfe,0,0x3,0x6,0x7,
+0,0x18,0x30,0,0x24,0,0,0xc,0x18,0,
+0xf,0xf0,0,0x3,0xfc,0x12,0,0,0,0x90,
+0x18,0x18,0x30,0xf8,0x60,0x61,0xc1,0x80,0x78,0x7,
+0x80,0x78,0x7,0x80,0x78,0x6,0xc1,0xff,0xf,0xf8,
+0xff,0x9f,0xf3,0xfe,0x7f,0xc6,0x18,0x61,0x8f,0xf8,
+0x60,0x70,0xff,0x81,0xff,0x3,0xfe,0x7,0xfc,0xf,
+0xf8,0x61,0xbf,0xfc,0x1f,0xf0,0xff,0x87,0xfc,0x3f,
+0xe0,0x18,0xc,0,0xde,0x77,0x3b,0x9d,0xce,0xe7,
+0x73,0xb9,0xdf,0xf1,0xfc,0x7f,0x1f,0xc7,0xf1,0xfc,
+0xcc,0xc6,0x1f,0xc6,0x18,0xfe,0x1f,0xc3,0xf8,0x7f,
+0xf,0xe0,0x60,0xff,0x1f,0x67,0xd9,0xf6,0x7d,0x83,
+0x7,0xf8,0x18,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,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,0x1,0x80,0x24,0x7,0xc0,0xc3,0xc1,0xe3,
+0x86,0x6,0,0x18,0x30,0x3,0x30,0x3c,0x3,0xf,
+0xf0,0xf0,0x3,0x1f,0x3,0xc1,0x80,0x3c,0x1f,0xc,
+0x60,0xc,0,0x18,0x1,0x80,0xe0,0,0xc0,0x37,
+0xfc,0x3,0xe0,0xff,0x7,0xfc,0xc0,0x1,0xf6,0x60,
+0x31,0x83,0xc3,0x1,0xdf,0xe6,0x18,0x66,0x3,0x3,
+0xe0,0x60,0,0x7d,0x8c,0xc,0x3f,0,0x60,0xf,
+0x80,0x18,0x1,0x81,0x83,0x1,0x80,0xc0,0x7f,0xe6,
+0xc,0xc0,0,0,0xe,0xcd,0xe0,0x7c,0x1e,0xc3,
+0xc1,0x83,0xd9,0x86,0x66,0x63,0xb3,0x18,0xcc,0x30,
+0xf8,0x6f,0x3,0xd9,0x83,0xc0,0xc7,0x30,0x60,0x19,
+0x83,0xc,0x18,0x3f,0x8c,0x63,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xc1,
+0xf3,0x7c,0,0x3,0x6,0x3,0x80,0x7,0xc0,0,
+0,0,0,0x3,0xe0,0,0xf,0xf0,0,0x3,
+0x6c,0x12,0x3,0,0,0,0x18,0x18,0x30,0xf8,
+0x60,0x63,0x81,0x80,0x78,0x7,0x80,0x78,0x7,0x80,
+0x78,0x6,0xc1,0xff,0x3,0xe0,0xff,0x9f,0xf3,0xfe,
+0x7f,0xc6,0x18,0x61,0x8f,0xf0,0x60,0x30,0x3e,0,
+0x7c,0,0xf8,0x1,0xf0,0x3,0xe0,0xc0,0xf1,0xf0,
+0x7,0xc0,0x3e,0x1,0xf0,0xf,0x80,0x18,0xc,0,
+0xdc,0x3b,0x1d,0x8e,0xc7,0x63,0xb1,0xd8,0xeb,0xc0,
+0xf8,0x3c,0xf,0x3,0xc0,0xf0,0xcc,0xc6,0xf,0x86,
+0x18,0x7c,0xf,0x81,0xf0,0x3e,0x7,0xc0,0x1,0x9c,
+0xe,0x63,0x98,0xe6,0x39,0x83,0x6,0xf0,0x18,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,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,0x1,0,0,0,0,0x3,0xc,0,0,
+0x10,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x20,0,0,0,
+0,0,0x70,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,0x1,
+0x80,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x6,0,0xc0,0,0,
+0,0,0,0,0,0,0,0,0x18,0,
+0x6,0,0,0,0,0,0,0x60,0,0x18,
+0,0,0,0,0,0,0,0,0x18,0,
+0xc,0x63,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xc0,0x80,0,0,0,
+0x6,0x61,0x80,0,0,0,0,0,0,0,
+0,0,0,0,0,0x3,0,0x12,0x3,0x80,
+0,0,0,0,0,0,0,0x3,0x18,0,
+0,0,0,0,0,0,0,0,0,0,
+0x3,0x80,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,0xe0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x3,0x6,0,0x18,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,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,0x1,0,0,
+0,0,0x3,0xc,0,0,0x10,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x20,0,0,0,0,0,0x3f,0xe0,
+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,0x6,0,0xc0,0,0,0,0,0,0,
+0,0,0,0x6,0x30,0,0x6,0,0,0,
+0,0,0,0x60,0,0x18,0,0,0,0,
+0,0,0,0,0x18,0,0xc,0x63,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xc0,0x80,0,0,0,0x6,0x61,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x3,0,0x12,0,0xc0,0,0,0,0,
+0,0,0,0x3,0x18,0,0,0,0,0,
+0,0,0,0,0,0,0,0xc0,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,0x30,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0x6,0,
+0x18,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,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,0x1,0x98,
+0,0,0x20,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x40,0,
+0,0,0,0,0xf,0xc0,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,0x7,0x83,0xc0,
+0xf,0xfc,0,0,0,0,0,0,0,0x7,
+0xf0,0,0x1e,0,0,0,0,0,0,0x60,
+0,0x18,0,0,0,0,0,0,0,0,
+0x70,0,0x6,0x66,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xc0,0,0,
+0,0,0x6,0x3f,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0,0x12,
+0x6,0xc0,0,0,0,0,0,0,0,0x3,
+0xf8,0,0,0,0,0,0,0,0,0,
+0,0,0x6,0xc0,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,0x1,0xb0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xe,0x6,0,0x70,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,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,0x90,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,0x7,0x83,0xc0,0xf,0xfc,0,0,
+0,0,0,0,0,0x1,0xc0,0,0x1c,0,
+0,0,0,0,0,0x60,0,0x18,0,0,
+0,0,0,0,0,0,0x70,0,0x3,0x6c,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xc0,0,0,0,0,0,0x1e,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x3,0,0x12,0x7,0x80,0,0,
+0,0,0,0,0,0x1,0xf0,0,0,0,
+0,0,0,0,0,0,0,0,0x7,0x80,
+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,0x1,0xe0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xe,
+0x6,0,0x70,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,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,
+};
+
+static WORD Helvetica18_ch_ofst[225] = {
+0,5,11,16,26,36,52,65,68,74,
+80,87,97,102,109,114,119,129,139,149,
+159,169,179,189,199,209,219,224,229,239,
+250,260,270,288,300,313,327,340,351,362,
+376,389,395,405,418,428,444,457,472,484,
+499,511,524,536,549,563,581,594,608,620,
+625,630,635,644,654,658,667,678,688,699,
+709,715,726,736,740,744,753,757,771,781,
+792,803,814,820,829,835,845,855,869,879,
+889,898,904,908,914,924,929,934,939,944,
+949,954,959,964,969,974,979,984,989,994,
+999,1004,1009,1014,1019,1024,1029,1034,1039,1044,
+1049,1054,1059,1064,1069,1074,1079,1084,1089,1094,
+1100,1110,1120,1130,1140,1144,1154,1160,1175,1182,
+1191,1202,1209,1223,1228,1235,1245,1251,1257,1261,
+1271,1281,1285,1290,1296,1303,1312,1327,1342,1357,
+1367,1379,1391,1403,1415,1427,1439,1457,1471,1482,
+1493,1504,1515,1521,1527,1533,1539,1552,1565,1580,
+1595,1610,1625,1640,1650,1665,1678,1691,1704,1717,
+1731,1743,1752,1761,1770,1779,1788,1797,1806,1821,
+1831,1841,1851,1861,1871,1875,1879,1884,1889,1900,
+1910,1921,1932,1943,1954,1965,1975,1986,1996,2006,
+2016,2026,2036,2047,2057,
+};
+
+static struct font_hdr Helvetica18_font = {
+STPROP, 18, "AdobeHelv-M-R-N--18-180-75-75-P", 32, 255,
+22, 18, 11, 4, 4,
+18, 18, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Helvetica18_ch_ofst, Helvetica18_data,
+356, 22,
+NULL,
+0, 0,   /* x/y offset */
+25,        /* lineHeight */
+16,	   /* psHeight */
+};
+
+MgFont *mgHelvetica18Font()
+{
+return &Helvetica18_font;
+}
+
+MgFont *mgLargeFont()
+{
+return &Helvetica18_font;
+}
diff --git a/lib/font/mgHelvetica24.c b/lib/font/mgHelvetica24.c
new file mode 100644
index 0000000..67332eb
--- /dev/null
+++ b/lib/font/mgHelvetica24.c
@@ -0,0 +1,1245 @@
+
+/* Helvetica24.c - compiled data for font AdobeHelv-M-R-N--24-240-75-75-P */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/helvR24.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Helvetica24_data[11890] = {
+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,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,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,0,0,0,0,
+0,0,0,0,0x18,0,0,0x60,0,0xc0,
+0,0,0,0,0,0x38,0,0,0,0,
+0,0,0x60,0,0x3,0,0xc,0,0,0x3,
+0,0x30,0xc0,0,0,0,0,0,0x1,0x80,
+0,0x3,0,0x6,0,0,0,0,0,0,
+0,0,0,0,0x60,0,0,0xc0,0x1,0x80,
+0,0,0,0x6,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,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,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,
+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,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,0xc,0,0,0xc0,0x1,0xe0,
+0x1,0xc4,0x1,0x8c,0,0x6c,0,0,0,0,
+0,0,0x30,0,0x6,0,0x1e,0,0x33,0x1,
+0x80,0x61,0xe3,0x30,0,0,0x3,0x88,0,0xc0,
+0,0x6,0,0xf,0,0x7,0x10,0x1,0x98,0,
+0,0,0,0,0x30,0,0x1,0x80,0x3,0xc0,
+0x1,0x98,0,0xc,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,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,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,
+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,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,0x6,0,0x1,0x80,0x3,0x30,
+0x3,0x6c,0x1,0x8c,0,0x6c,0,0,0,0,
+0,0,0x18,0,0xc,0,0x33,0,0x33,0,
+0xc0,0xc3,0x33,0x30,0,0,0x6,0xd8,0,0x60,
+0,0xc,0,0x19,0x80,0xd,0xb0,0x1,0x98,0,
+0,0,0,0,0x18,0,0x3,0,0x6,0x60,
+0x1,0x98,0,0x18,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,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,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,
+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,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,0x3,0,0x3,0,0x6,0x18,
+0x2,0x38,0,0,0,0x38,0,0,0,0,
+0,0,0xc,0,0x18,0,0x61,0x80,0,0,
+0x61,0x86,0x18,0,0,0,0x4,0x70,0,0x30,
+0,0x18,0,0x30,0xc0,0x8,0xe0,0,0,0,
+0,0,0,0,0xc,0,0x6,0,0xc,0x30,
+0,0,0,0x30,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,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,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,
+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,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,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,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,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,0xc6,0x60,0,0,0xc0,0,0,0,0,
+0,0xc0,0x66,0,0x80,0,0,0,0,0x6,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x3,0xe0,0,0xff,0,0x3,0x80,
+0x3f,0xf0,0x1,0xf8,0x7,0xfe,0x1,0xff,0xe1,0xff,
+0xc0,0x7e,0,0xc0,0xc,0x18,0,0x61,0x80,0x70,
+0x60,0x1,0x80,0x3,0xe,0,0xc0,0x3f,0,0xff,
+0xe0,0xf,0xc0,0x3f,0xf8,0x1,0xf0,0x3f,0xff,0x18,
+0x1,0x8c,0,0x66,0x3,0x1,0x98,0,0xcc,0,
+0xcf,0xff,0x8f,0x60,0x78,0xc,0,0,0x30,0,
+0x1,0x80,0,0,0,0x60,0,0x3,0x80,0,
+0x30,0x1,0x86,0x18,0x1,0x80,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x31,
+0x8c,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,0x18,0x1f,0,0,
+0,0,0x78,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x60,0,0x3,0xf8,
+0,0,0x7,0,0,0,0,0,0,0,
+0,0,0,0,0x7,0,0x3,0x80,0x1,0xc0,
+0,0xe0,0,0x70,0,0x38,0,0x1f,0xff,0xc0,
+0x7e,0x1,0xff,0xe1,0xff,0xe1,0xff,0xe1,0xff,0xe0,
+0xc0,0xc0,0xc0,0xc1,0xff,0x80,0x70,0x6,0x1,0xf8,
+0,0x7e,0,0x1f,0x80,0x7,0xe0,0x1,0xf8,0,
+0,0x1,0xf8,0x26,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x8c,0,0xc6,0,0,0x70,0x3,0,
+0x1,0x80,0x30,0x7,0x10,0,0,0xe0,0,0,
+0,0,0x6,0,0x3,0,0x60,0,0x6,0x1,
+0x18,0x1,0xc0,0,0,0x6,0,0x3,0,0x60,
+0,0,0,0,0,0,0,0x60,0,0xc,
+0x1,0x80,0,0,0x6,0xc,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,0,0,
+0,0xc6,0x60,0,0,0xc0,0,0x6,0,0x3c,
+0,0xc0,0x66,0,0x80,0,0,0,0,0x6,
+0x1f,0,0x30,0x7,0x80,0x3e,0,0x18,0x3f,0xe0,
+0x3c,0x1f,0xfc,0xe,0,0xf8,0,0,0,0,
+0,0,0,0xf,0xf0,0x3,0xff,0xc0,0x3,0x80,
+0x3f,0xfc,0x7,0xfe,0x7,0xff,0x81,0xff,0xe1,0xff,
+0xc1,0xff,0x80,0xc0,0xc,0x18,0,0x61,0x80,0xe0,
+0x60,0x1,0xc0,0x7,0xf,0,0xc0,0xff,0xc0,0xff,
+0xf0,0x3f,0xf0,0x3f,0xfc,0x7,0xfc,0x3f,0xff,0x18,
+0x1,0x8c,0,0x66,0x3,0x1,0x9c,0x1,0xce,0x1,
+0xcf,0xff,0x8f,0x60,0x78,0xc,0,0,0x18,0,
+0x1,0x80,0,0,0,0x60,0,0x7,0x80,0,
+0x30,0x1,0x86,0x18,0x1,0x80,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0,0,
+0,0,0,0,0,0,0,0,0,0x61,
+0x86,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,0xf,0xc0,0,0x1c,0x3,0x98,0x3f,0x86,0x60,
+0,0,0xcc,0,0,0,0,0,0,0,
+0x7e,0x3c,0,0,0x79,0xf0,0xc0,0,0xf,0xf8,
+0,0x3,0xd,0x80,0,0xc,0x6,0x1,0x80,0xc0,
+0xf8,0x18,0,0,0x7,0,0x3,0x80,0x1,0xc0,
+0,0xe0,0,0x70,0,0x38,0,0x1f,0xff,0xc1,
+0xff,0x81,0xff,0xe1,0xff,0xe1,0xff,0xe1,0xff,0xe0,
+0xc0,0xc0,0xc0,0xc1,0xff,0xe0,0x78,0x6,0x7,0xfe,
+0x1,0xff,0x80,0x7f,0xe0,0x1f,0xf8,0x7,0xfe,0,
+0,0x7,0xfe,0x66,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x8e,0x1,0xc6,0,0x1,0xfc,0x1,0x80,
+0x3,0,0x78,0xd,0xb0,0x33,0x1,0xb0,0,0,
+0,0,0x3,0,0x6,0,0xf0,0xc,0xc3,0x3,
+0x3c,0xcc,0xe3,0x1,0xc4,0x3,0,0x6,0,0xf0,
+0xe,0x20,0xc6,0,0,0,0,0x30,0,0x18,
+0x3,0xc0,0x19,0x80,0xc,0xc,0,0x19,0x80,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,0xc6,0x60,0x33,0x7,0xf0,0x3c,0xc,0,0x7e,
+0,0xc0,0xc3,0x6,0xb0,0,0,0,0,0x6,
+0x3f,0x80,0x30,0x1f,0xe0,0xff,0,0x38,0x3f,0xe0,
+0xff,0x1f,0xfc,0x3f,0x83,0xfe,0,0,0,0,
+0,0,0,0xe,0x38,0xf,0x1,0xe0,0x6,0xc0,
+0x30,0x1c,0xf,0xf,0x6,0x3,0xc1,0x80,0x1,0x80,
+0x3,0xc3,0xc0,0xc0,0xc,0x18,0,0x61,0x81,0xc0,
+0x60,0x1,0xc0,0x7,0xf,0,0xc1,0xe1,0xe0,0xc0,
+0x30,0x78,0x78,0x30,0xc,0xe,0xe,0,0xc0,0x18,
+0x1,0x8e,0,0xe6,0x3,0x1,0x8e,0x3,0x86,0x1,
+0x80,0x3,0x8c,0x60,0x18,0x1e,0,0,0xc,0,
+0x1,0x80,0,0,0,0x60,0,0x6,0,0,
+0x30,0x1,0x86,0x18,0x1,0x80,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0,0,
+0,0,0,0,0,0,0,0,0,0xc1,
+0x83,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,0x1f,0xf0,0,0xc,0x3,0x18,0x71,0xc6,0x60,
+0x3f,0x80,0xcc,0,0,0,0,0,0x1f,0xc0,
+0x7e,0x66,0,0,0xff,0xf9,0x80,0,0xf,0x30,
+0,0x3,0x18,0xc0,0,0xc,0x6,0x1,0x80,0xc1,
+0xfc,0x18,0,0,0xd,0x80,0x6,0xc0,0x3,0x60,
+0x1,0xb0,0,0xd8,0,0x6c,0,0x33,0,0x3,
+0xc3,0xc1,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0xf0,0x78,0x6,0xf,0xf,
+0x3,0xc3,0xc0,0xf0,0xf0,0x3c,0x3c,0xf,0xf,0,
+0,0xf,0xf,0xc6,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x86,0x1,0x86,0,0x3,0x8c,0,0xc0,
+0x6,0,0xcc,0x8,0xe0,0x33,0x1,0x10,0,0,
+0,0,0x1,0x80,0xc,0x1,0x98,0xc,0xc1,0x86,
+0x66,0xcc,0x3c,0x3,0x6c,0x1,0x80,0xc,0x1,0x98,
+0x1b,0x60,0xc6,0,0,0,0,0x18,0,0x30,
+0x6,0x60,0x19,0x80,0x18,0xc,0,0x19,0x80,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,0xc6,0x60,0x33,0xf,0xf8,0x7e,0xc,0,0xe7,
+0,0xc0,0xc3,0x3,0xe0,0,0,0,0,0xc,
+0x71,0xc0,0x70,0x18,0x70,0xc3,0,0x38,0x30,0x1,
+0xc3,0,0x1c,0x31,0x83,0x8e,0,0,0,0,
+0,0,0,0x1c,0x18,0x1c,0,0x70,0x6,0xc0,
+0x30,0x6,0x1c,0x3,0x86,0,0xe1,0x80,0x1,0x80,
+0x7,0,0xe0,0xc0,0xc,0x18,0,0x61,0x83,0x80,
+0x60,0x1,0xe0,0xf,0xd,0x80,0xc3,0x80,0x70,0xc0,
+0x18,0xe0,0x1c,0x30,0x6,0x1c,0x6,0,0xc0,0x18,
+0x1,0x86,0,0xc6,0x7,0x81,0x86,0x3,0x7,0x3,
+0x80,0x7,0xc,0x30,0x18,0x12,0,0,0x6,0,
+0x1,0x80,0,0,0,0x60,0,0x6,0,0,
+0x30,0,0,0x18,0x1,0x80,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0,0,
+0,0,0,0,0,0,0,0,0,0xc1,
+0x83,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,
+0x18,0x38,0x38,0,0xe,0x7,0x18,0x60,0xc0,0,
+0xe0,0xe0,0xc,0,0,0,0,0,0x70,0x70,
+0,0xc3,0,0x1,0x8f,0x1b,0,0,0x1f,0x30,
+0,0xf,0x18,0xc0,0,0x3c,0xc,0x7,0x81,0x81,
+0x8c,0x30,0,0,0xd,0x80,0x6,0xc0,0x3,0x60,
+0x1,0xb0,0,0xd8,0,0x6c,0,0x33,0,0x7,
+0,0xe1,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0x38,0x6c,0x6,0x1c,0x3,
+0x87,0,0xe1,0xc0,0x38,0x70,0xe,0x1c,0x3,0x80,
+0,0x1c,0x3,0x86,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x87,0x3,0x86,0,0x3,0x6,0,0x60,
+0xc,0x1,0x86,0,0,0,0x1,0xb0,0,0,
+0,0,0,0xc0,0x18,0x3,0xc,0,0,0xcc,
+0xc3,0,0x78,0x2,0x38,0,0xc0,0x18,0x3,0xc,
+0x11,0xc0,0,0,0,0,0,0xc,0,0x60,
+0xc,0x30,0,0,0x30,0xc,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,0,0,
+0,0xc6,0x60,0x33,0x1c,0xdc,0xc3,0x18,0,0xc3,
+0,0xc1,0x81,0x81,0xc0,0,0,0,0,0xc,
+0x60,0xc3,0xf0,0x30,0x31,0x81,0x80,0x78,0x30,0x1,
+0x81,0x80,0x18,0x60,0xc7,0x6,0,0,0,0,
+0,0,0,0x18,0x18,0x38,0,0x18,0xc,0x40,
+0x30,0x6,0x18,0x1,0x86,0,0x61,0x80,0x1,0x80,
+0x6,0,0x60,0xc0,0xc,0x18,0,0x61,0x87,0,
+0x60,0x1,0xe0,0xf,0xd,0xc0,0xc3,0,0x30,0xc0,
+0x18,0xc0,0xc,0x30,0x6,0x18,0x6,0,0xc0,0x18,
+0x1,0x87,0x1,0xc3,0x7,0x83,0x3,0x6,0x3,0x3,
+0,0xe,0xc,0x30,0x18,0x33,0,0,0,0,
+0x1,0x80,0,0,0,0x60,0,0x6,0,0,
+0x30,0,0,0x18,0x1,0x80,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0,0,
+0,0,0,0,0,0,0,0,0,0xc1,
+0x83,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,
+0x18,0x30,0x19,0x80,0xc6,0x6,0x18,0x70,0xc0,0x1,
+0x80,0x30,0x7c,0,0,0,0,0,0xc0,0x18,
+0,0xc3,0,0,0xc,0x18,0,0,0x1f,0x30,
+0,0xf,0x18,0xc0,0,0x3c,0xc,0x7,0x81,0x80,
+0xc,0x30,0,0,0x18,0x80,0xc,0x40,0x6,0x20,
+0x3,0x10,0x1,0x88,0,0xc4,0,0x63,0,0x6,
+0,0x61,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0x18,0x6e,0x6,0x18,0x1,
+0x86,0,0x61,0x80,0x18,0x60,0x6,0x18,0x1,0x80,
+0,0x18,0x3,0x86,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x83,0x3,0x7,0xff,0x3,0x6,0,0,
+0,0,0,0,0,0,0,0xe0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1,0x8c,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xc,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,0,0,
+0,0xc2,0x20,0x66,0x18,0xcc,0xc3,0x18,0,0xc3,
+0,0x41,0x81,0x83,0x60,0,0,0,0,0xc,
+0x60,0xc3,0xf0,0x30,0x19,0x81,0x80,0xf8,0x30,0x3,
+0x81,0x80,0x30,0x60,0xc6,0x3,0x18,0x60,0,0,
+0,0,0,0x18,0x38,0x30,0,0x18,0xc,0x60,
+0x30,0x6,0x38,0x1,0x86,0,0x71,0x80,0x1,0x80,
+0xe,0,0x60,0xc0,0xc,0x18,0,0x61,0x8e,0,
+0x60,0x1,0xb0,0x1b,0xc,0xc0,0xc7,0,0x38,0xc0,
+0x19,0xc0,0xe,0x30,0x6,0x18,0,0,0xc0,0x18,
+0x1,0x83,0x1,0x83,0xc,0xc3,0x3,0x8e,0x3,0x87,
+0,0x1c,0xc,0x30,0x18,0x61,0x80,0,0,0xf,
+0x81,0x9e,0x1,0xf0,0x1e,0x60,0x38,0x1f,0x83,0xcc,
+0x33,0x81,0x86,0x18,0x31,0x86,0x71,0xe0,0x67,0,
+0x7c,0xc,0xf0,0xf,0x30,0xcc,0x3e,0xf,0xc6,0x6,
+0x30,0x1b,0x3,0x3,0x60,0x6c,0x3,0x3f,0xf0,0xc1,
+0x83,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,0x1,0x81,
+0xf0,0x30,0x1,0xdd,0xc7,0xe,0x18,0x38,0,0x3,
+0,0x18,0xcc,0,0,0,0,0x1,0x80,0xc,
+0,0xc3,0,0,0x18,0xf0,0x3,0x3,0x1f,0x30,
+0,0x3,0x18,0xc0,0,0xc,0x18,0x1,0x83,0,
+0x78,0x60,0x1,0x80,0x18,0xc0,0xc,0x60,0x6,0x30,
+0x3,0x18,0x1,0x8c,0,0xc6,0,0x63,0,0xe,
+0,0x61,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0x1c,0x66,0x6,0x38,0x1,
+0xce,0,0x73,0x80,0x1c,0xe0,0x7,0x38,0x1,0xc0,
+0,0x38,0x6,0xc6,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x83,0x87,0x7,0xff,0x83,0x6,0x3,0xe0,
+0x1f,0,0xf8,0x7,0xc0,0x3e,0x1,0xf0,0xf,0x87,
+0,0x7c,0x3,0x80,0x1c,0,0xe0,0x7,0x1,0x86,
+0x18,0x30,0x3e,0x6,0x70,0x7,0xc0,0x3e,0x1,0xf0,
+0xf,0x80,0x7c,0,0,0xf,0x99,0x81,0x86,0x6,
+0x18,0x18,0x60,0x66,0x1,0x8c,0xf0,0xc0,0x30,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,0xc0,0x3,0xff,0x98,0xc0,0xc3,0x30,0,0xc3,
+0,0x1,0x81,0x82,0x20,0xc,0,0,0,0x18,
+0xc0,0x60,0x30,0x30,0x19,0x81,0x80,0xd8,0x30,0x3,
+0,0,0x30,0x60,0xc6,0x3,0x18,0x60,0,0xc0,
+0,0xc,0,0,0x30,0x60,0x73,0xc,0xc,0x60,
+0x30,0x6,0x30,0,0x6,0,0x31,0x80,0x1,0x80,
+0xc,0,0,0xc0,0xc,0x18,0,0x61,0x9c,0,
+0x60,0x1,0xb0,0x1b,0xc,0xe0,0xc6,0,0x18,0xc0,
+0x19,0x80,0x6,0x30,0x6,0x1c,0,0,0xc0,0x18,
+0x1,0x83,0x1,0x83,0xc,0xc3,0x1,0xdc,0x1,0x86,
+0,0x1c,0xc,0x18,0x18,0x61,0x80,0,0,0x1f,
+0xc1,0xbf,0x3,0xf8,0x3f,0x60,0xfe,0x1f,0x87,0xec,
+0x37,0xe1,0x86,0x18,0x71,0x87,0xfb,0xf0,0x6f,0xc0,
+0xfe,0xd,0xf8,0x1f,0xb0,0xdc,0x7f,0x8f,0xc6,0x6,
+0x30,0x1b,0x3,0x3,0x70,0xec,0x3,0x3f,0xf0,0xc1,
+0x83,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,0x1,0x83,
+0xf8,0x38,0,0xff,0x83,0xc,0x18,0x1c,0,0x2,
+0x1f,0x8,0xcc,0,0,0,0,0x1,0xf,0x84,
+0,0x66,0x1,0x80,0x30,0xf0,0x3,0x3,0x1f,0x30,
+0,0x3,0x18,0xc0,0,0xc,0x18,0x1,0x83,0,
+0x78,0x60,0x1,0x80,0x18,0xc0,0xc,0x60,0x6,0x30,
+0x3,0x18,0x1,0x8c,0,0xc6,0,0x63,0,0xc,
+0,0x1,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0xc,0x67,0x6,0x30,0,
+0xcc,0,0x33,0,0xc,0xc0,0x3,0x30,0,0xd8,
+0x3,0x30,0xc,0xc6,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x81,0x86,0x6,0x1,0x83,0xc,0x7,0xf0,
+0x3f,0x81,0xfc,0xf,0xe0,0x7f,0x3,0xf8,0x1f,0xdf,
+0xc0,0xfe,0xf,0xe0,0x7f,0x3,0xf8,0x1f,0xc1,0x86,
+0x18,0x30,0x7f,0x6,0xfc,0xf,0xe0,0x7f,0x3,0xf8,
+0x1f,0xc0,0xfe,0,0xc0,0x1f,0xf1,0x81,0x86,0x6,
+0x18,0x18,0x60,0x66,0x1,0x8d,0xf8,0xc0,0x30,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,0xc0,0x3,0xff,0x9c,0xc0,0xc3,0x30,0,0x66,
+0,0x3,0,0xc0,0,0xc,0,0,0,0x18,
+0xc0,0x60,0x30,0,0x18,0x1,0x81,0x98,0x37,0x3,
+0,0,0x60,0x60,0xc6,0x3,0x18,0x60,0x3,0xc0,
+0,0xf,0,0,0x70,0x60,0xfb,0xc,0x18,0x30,
+0x30,0xc,0x30,0,0x6,0,0x31,0x80,0x1,0x80,
+0xc,0,0,0xc0,0xc,0x18,0,0x61,0xb8,0,
+0x60,0x1,0xb0,0x1b,0xc,0x60,0xc6,0,0x18,0xc0,
+0x31,0x80,0x6,0x30,0xc,0xf,0x80,0,0xc0,0x18,
+0x1,0x83,0x83,0x83,0xc,0xc3,0,0xf8,0x1,0xce,
+0,0x38,0xc,0x18,0x18,0xc0,0xc0,0,0,0x30,
+0xe1,0xe3,0x87,0x1c,0x71,0xe1,0xc7,0x6,0xe,0x3c,
+0x3c,0x61,0x86,0x18,0xe1,0x87,0x1e,0x38,0x78,0xc1,
+0xc7,0xf,0x1c,0x38,0xf0,0xfc,0xe1,0xc3,0x6,0x6,
+0x30,0x19,0x87,0x86,0x30,0xc6,0x3,0,0x60,0xc1,
+0x83,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,0x1,0x87,
+0x3c,0x18,0,0x63,0x3,0x9c,0x18,0x7e,0,0x6,
+0x31,0x8c,0xdc,0,0,0,0,0x3,0x8,0x46,
+0,0x3c,0x1,0x80,0x60,0x18,0x3,0x3,0x1f,0x30,
+0,0x3,0xd,0x80,0,0xc,0x30,0x1,0x86,0,
+0xc,0xc0,0x1,0x80,0x30,0x60,0x18,0x30,0xc,0x18,
+0x6,0xc,0x3,0x6,0x1,0x83,0,0xc3,0,0xc,
+0,0x1,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0xc,0x63,0x6,0x30,0,
+0xcc,0,0x33,0,0xc,0xc0,0x3,0x30,0,0xcc,
+0x6,0x30,0x18,0xc6,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x81,0xce,0x6,0,0xc3,0x1c,0xc,0x38,
+0x61,0xc3,0xe,0x18,0x70,0xc3,0x86,0x1c,0x30,0xf8,
+0xe1,0xc7,0x1c,0x70,0xe3,0x87,0x1c,0x38,0xe1,0x86,
+0x18,0x30,0xe3,0x87,0x8c,0x1c,0x70,0xe3,0x87,0x1c,
+0x38,0xe1,0xc7,0,0xc0,0x38,0xe1,0x81,0x86,0x6,
+0x18,0x18,0x60,0x63,0x1,0x8f,0x1c,0x60,0x30,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,0xc0,0,0x66,0xe,0xc0,0x7e,0x60,0,0x3c,
+0,0x3,0,0xc0,0,0xc,0,0,0,0x18,
+0xc0,0x60,0x30,0,0x30,0x3,0x3,0x98,0x3f,0xc3,
+0x3c,0,0x60,0x31,0x86,0x3,0,0,0xf,0x3,
+0xff,0x3,0xc0,0,0xe0,0xc1,0xc7,0xc,0x18,0x30,
+0x3f,0xf8,0x30,0,0x6,0,0x31,0xff,0xc1,0x80,
+0xc,0,0,0xff,0xfc,0x18,0,0x61,0xf8,0,
+0x60,0x1,0x98,0x33,0xc,0x70,0xc6,0,0x18,0xff,
+0xf1,0x80,0x6,0x3f,0xfc,0x3,0xf0,0,0xc0,0x18,
+0x1,0x81,0x83,0x3,0xc,0xc3,0,0x70,0,0xcc,
+0,0x70,0xc,0x18,0x18,0xc0,0xc0,0,0,0x30,
+0x61,0xc1,0x86,0xc,0x60,0xe1,0x83,0x6,0xc,0x1c,
+0x38,0x31,0x86,0x19,0xc1,0x86,0xc,0x18,0x70,0x61,
+0x83,0xe,0xc,0x30,0x70,0xe0,0xc0,0xc3,0x6,0x6,
+0x18,0x31,0x87,0x86,0x19,0x87,0x6,0,0xc0,0xc1,
+0x83,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,0x6,
+0x6c,0xc,0,0xc1,0x81,0x98,0x18,0xe7,0,0x4,
+0x60,0x84,0x76,0x6,0x61,0xff,0xf0,0x2,0x8,0x42,
+0,0,0x1,0x80,0xc3,0x18,0x3,0x3,0x1f,0x30,
+0,0x3,0x7,0x3,0x30,0xc,0x30,0x1,0x86,0x1,
+0x8c,0xc0,0,0,0x30,0x60,0x18,0x30,0xc,0x18,
+0x6,0xc,0x3,0x6,0x1,0x83,0,0xc3,0xff,0xcc,
+0,0x1,0xff,0xc1,0xff,0xc1,0xff,0xc1,0xff,0xc0,
+0xc0,0xc0,0xc0,0xc7,0xf8,0xc,0x63,0x86,0x30,0,
+0xcc,0,0x33,0,0xc,0xc0,0x3,0x30,0,0xc6,
+0xc,0x30,0x30,0xc6,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x80,0xcc,0x6,0,0xc3,0x38,0xc,0x18,
+0x60,0xc3,0x6,0x18,0x30,0xc1,0x86,0xc,0x30,0x70,
+0x61,0x83,0x18,0x30,0xc1,0x86,0xc,0x30,0x61,0x86,
+0x18,0x30,0xc1,0x87,0x6,0x18,0x30,0xc1,0x86,0xc,
+0x30,0x61,0x83,0,0xc0,0x30,0x61,0x81,0x86,0x6,
+0x18,0x18,0x60,0x63,0x83,0xe,0xc,0x70,0x60,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,0xc0,0,0x66,0x7,0xc0,0x3c,0x60,0,0x78,
+0,0x3,0,0xc0,0,0xc,0,0,0,0x18,
+0xc0,0x60,0x30,0,0x70,0x1e,0x3,0x18,0x38,0xe3,
+0x7e,0,0xc0,0x1f,0x7,0x7,0,0,0x3c,0x3,
+0xff,0,0xf0,0,0xc0,0xc3,0x86,0xc,0x18,0x30,
+0x3f,0xfc,0x30,0,0x6,0,0x31,0xff,0xc1,0xff,
+0x8c,0x7,0xf0,0xff,0xfc,0x18,0,0x61,0xfc,0,
+0x60,0x1,0x98,0x33,0xc,0x30,0xc6,0,0x18,0xff,
+0xe1,0x80,0x6,0x3f,0xf8,0,0x7c,0,0xc0,0x18,
+0x1,0x81,0x83,0x1,0x8c,0xc6,0,0x70,0,0xfc,
+0,0x70,0xc,0x18,0x18,0,0,0,0,0,
+0x61,0x80,0xcc,0,0xc0,0x63,0x1,0x86,0x18,0xc,
+0x30,0x31,0x86,0x1b,0x81,0x86,0xc,0x18,0x60,0x63,
+0x1,0x8c,0x6,0x60,0x30,0xc0,0xc0,0x3,0x6,0x6,
+0x18,0x31,0x87,0x86,0x1f,0x83,0x6,0x1,0xc0,0xc1,
+0x83,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,0xc,
+0x60,0x7f,0xc0,0xc1,0x87,0xfe,0,0xc3,0x80,0x4,
+0x40,0x4,0,0xc,0xc1,0xff,0xf0,0x2,0x8,0x42,
+0,0,0x1,0x81,0xff,0xf8,0x3,0x3,0xf,0x30,
+0,0x3,0,0x1,0x98,0xc,0x60,0xc1,0x8c,0x3d,
+0xfd,0x83,0,0,0x30,0x60,0x18,0x30,0xc,0x18,
+0x6,0xc,0x3,0x6,0x1,0x83,0,0xc3,0xff,0xcc,
+0,0x1,0xff,0xc1,0xff,0xc1,0xff,0xc1,0xff,0xc0,
+0xc0,0xc0,0xc0,0xc7,0xf8,0xc,0x61,0x86,0x30,0,
+0xcc,0,0x33,0,0xc,0xc0,0x3,0x30,0,0xc3,
+0x18,0x30,0x60,0xc6,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x80,0xfc,0x6,0,0xc3,0x3c,0,0x18,
+0,0xc0,0x6,0,0x30,0x1,0x80,0xc,0,0x60,
+0x33,0,0x30,0x19,0x80,0xcc,0x6,0x60,0x31,0x86,
+0x18,0x31,0x80,0xc6,0x6,0x30,0x19,0x80,0xcc,0x6,
+0x60,0x33,0x1,0x80,0,0x60,0xf1,0x81,0x86,0x6,
+0x18,0x18,0x60,0x61,0x83,0xc,0x6,0x30,0x60,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,0xc0,0,0xcc,0x1,0xf0,0,0xc0,0,0xfc,
+0x60,0x3,0,0xc0,0,0xc,0,0,0,0x30,
+0xc0,0x60,0x30,0,0xe0,0x1f,0x86,0x18,0,0x63,
+0xc7,0,0xc0,0x3f,0x83,0x8f,0,0,0xf0,0,
+0,0,0x3c,0x1,0x80,0xc3,0x6,0xc,0x30,0x18,
+0x30,0x6,0x30,0,0x6,0,0x31,0x80,0x1,0xff,
+0x8c,0x7,0xf0,0xc0,0xc,0x18,0,0x61,0xce,0,
+0x60,0x1,0x98,0x33,0xc,0x38,0xc6,0,0x18,0xc0,
+0x1,0x80,0x6,0x30,0x1c,0,0x1e,0,0xc0,0x18,
+0x1,0x81,0xc7,0x1,0x98,0x66,0,0xf8,0,0x78,
+0,0xe0,0xc,0xc,0x18,0,0,0,0,0x3,
+0xe1,0x80,0xcc,0,0xc0,0x63,0x1,0x86,0x18,0xc,
+0x30,0x31,0x86,0x1f,0x1,0x86,0xc,0x18,0x60,0x63,
+0x1,0x8c,0x6,0x60,0x30,0xc0,0xf8,0x3,0x6,0x6,
+0x1c,0x70,0xc4,0x8c,0xf,0x3,0x8e,0x3,0x81,0x81,
+0x81,0x83,0x86,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,0x8c,
+0xc0,0x7f,0xc0,0xc1,0x87,0xfe,0,0xc1,0xc0,0x4,
+0x40,0x4,0xfe,0x19,0x80,0,0x30,0x2,0xf,0x82,
+0,0,0x3f,0xfd,0xfd,0xf0,0x3,0x3,0xf,0x30,
+0xc0,0x3,0x1f,0xc0,0xcc,0xc,0x61,0xc1,0x8c,0x7e,
+0xf9,0x87,0x1,0x80,0x60,0x30,0x30,0x18,0x18,0xc,
+0xc,0x6,0x6,0x3,0x3,0x1,0x81,0x83,0,0xc,
+0,0x1,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0xc,0x61,0xc6,0x30,0,
+0xcc,0,0x33,0,0xc,0xc0,0x3,0x30,0,0xc1,
+0xb0,0x30,0xc0,0xc6,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x80,0x78,0x6,0,0xc3,0xe,0,0xf8,
+0x7,0xc0,0x3e,0x1,0xf0,0xf,0x80,0x7c,0x3,0xe0,
+0x33,0,0x30,0x19,0x80,0xcc,0x6,0x60,0x31,0x86,
+0x18,0x31,0x80,0xc6,0x6,0x30,0x19,0x80,0xcc,0x6,
+0x60,0x33,0x1,0x80,0,0x61,0xb1,0x81,0x86,0x6,
+0x18,0x18,0x60,0x61,0xc7,0xc,0x6,0x38,0xe0,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,0xc0,0,0xcc,0,0xf8,0,0xc7,0x81,0xce,
+0x60,0x3,0,0xc0,0x1,0xff,0xe0,0x1f,0x80,0x30,
+0xc0,0x60,0x30,0x3,0xc0,0x1,0x8e,0x18,0,0x33,
+0x83,0x1,0x80,0x60,0xc3,0xfb,0,0x3,0x80,0,
+0,0,0x7,0x1,0x80,0xc6,0x6,0xc,0x3f,0xf8,
+0x30,0x3,0x30,0,0x6,0,0x31,0x80,0x1,0x80,
+0xc,0,0x30,0xc0,0xc,0x18,0,0x61,0x87,0,
+0x60,0x1,0x8c,0x63,0xc,0x18,0xc6,0,0x18,0xc0,
+0x1,0x80,0x6,0x30,0xc,0,0x7,0,0xc0,0x18,
+0x1,0x80,0xc6,0x1,0x98,0x66,0x1,0xdc,0,0x78,
+0x1,0xc0,0xc,0xc,0x18,0,0,0,0,0x1f,
+0xe1,0x80,0xcc,0,0xc0,0x63,0xff,0x86,0x18,0xc,
+0x30,0x31,0x86,0x1f,0x81,0x86,0xc,0x18,0x60,0x63,
+0x1,0x8c,0x6,0x60,0x30,0xc0,0x7f,0x3,0x6,0x6,
+0xc,0x60,0xcc,0xcc,0x6,0x1,0x8c,0x3,0x3,0x1,
+0x80,0xc7,0xe6,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,0x8c,
+0xc0,0xc,0,0xc1,0x80,0x60,0,0xc0,0xc0,0x4,
+0x40,0x4,0xfe,0x33,0,0,0x33,0xf2,0x9,0x2,
+0,0,0x3f,0xfc,0,0,0x3,0x3,0x7,0x30,
+0xc0,0,0x1f,0xc0,0x66,0,0xc3,0xc0,0x18,0xc6,
+0x3,0xf,0x1,0x80,0x7f,0xf0,0x3f,0xf8,0x1f,0xfc,
+0xf,0xfe,0x7,0xff,0x3,0xff,0x81,0xff,0,0xc,
+0,0x1,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0xc,0x60,0xc6,0x30,0,
+0xcc,0,0x33,0,0xc,0xc0,0x3,0x30,0,0xc0,
+0xe0,0x31,0x80,0xc6,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x80,0x78,0x6,0x1,0x83,0x6,0x7,0xf8,
+0x3f,0xc1,0xfe,0xf,0xf0,0x7f,0x83,0xfc,0x1f,0xff,
+0xf3,0,0x3f,0xf9,0xff,0xcf,0xfe,0x7f,0xf1,0x86,
+0x18,0x31,0x80,0xc6,0x6,0x30,0x19,0x80,0xcc,0x6,
+0x60,0x33,0x1,0x9f,0xfe,0x63,0x31,0x81,0x86,0x6,
+0x18,0x18,0x60,0x60,0xc6,0xc,0x6,0x18,0xc0,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,0x80,0x3,0xff,0x80,0xdc,0x1,0x8f,0xc1,0x87,
+0x60,0x3,0,0xc0,0x1,0xff,0xe0,0x1f,0x80,0x30,
+0xc0,0x60,0x30,0x7,0,0,0xcc,0x18,0,0x33,
+0x1,0x81,0x80,0xe0,0xe0,0xf3,0,0x3,0x80,0x3,
+0xff,0,0x7,0x1,0x80,0xc6,0xc,0x1c,0x3f,0xf8,
+0x30,0x3,0x30,0,0xc6,0,0x31,0x80,0x1,0x80,
+0xc,0,0x30,0xc0,0xc,0x18,0x60,0x61,0x83,0x80,
+0x60,0x1,0x8c,0x63,0xc,0x1c,0xc6,0,0x18,0xc0,
+0x1,0x80,0x6,0x30,0x6,0,0x3,0,0xc0,0x18,
+0x1,0x80,0xc6,0x1,0x98,0x66,0x1,0x8c,0,0x30,
+0x1,0xc0,0xc,0xc,0x18,0,0,0,0,0x3c,
+0x61,0x80,0xcc,0,0xc0,0x63,0xff,0x86,0x18,0xc,
+0x30,0x31,0x86,0x19,0xc1,0x86,0xc,0x18,0x60,0x63,
+0x1,0x8c,0x6,0x60,0x30,0xc0,0xf,0x83,0x6,0x6,
+0xc,0x60,0xcc,0xcc,0xf,0x1,0x8c,0x7,0x3,0x1,
+0x80,0xc6,0x7e,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,0x1,0x8c,
+0xc0,0xc,0,0x63,0x7,0xfe,0,0x60,0x60,0x4,
+0x60,0x84,0,0x33,0,0,0x33,0xf2,0x8,0x82,
+0,0,0x1,0x80,0,0,0x3,0x3,0x3,0x30,
+0xc0,0,0,0,0x66,0,0xc3,0xc0,0x18,0x6,
+0x3,0xf,0x1,0x80,0x7f,0xf0,0x3f,0xf8,0x1f,0xfc,
+0xf,0xfe,0x7,0xff,0x3,0xff,0x81,0xff,0,0xc,
+0,0x31,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0xc,0x60,0xe6,0x30,0,
+0xcc,0,0x33,0,0xc,0xc0,0x3,0x30,0,0xc0,
+0xe0,0x33,0,0xc6,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x80,0x30,0x7,0xff,0x83,0x3,0xf,0x18,
+0x78,0xc3,0xc6,0x1e,0x30,0xf1,0x87,0x8c,0x3c,0x7f,
+0xf3,0,0x3f,0xf9,0xff,0xcf,0xfe,0x7f,0xf1,0x86,
+0x18,0x31,0x80,0xc6,0x6,0x30,0x19,0x80,0xcc,0x6,
+0x60,0x33,0x1,0x9f,0xfe,0x66,0x31,0x81,0x86,0x6,
+0x18,0x18,0x60,0x60,0xc6,0xc,0x6,0x18,0xc0,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,0x80,0x3,0xff,0x80,0xcc,0x1,0x98,0x63,0x3,
+0xc0,0x3,0,0xc0,0,0xc,0,0,0,0x60,
+0xc0,0x60,0x30,0xe,0,0,0xcf,0xfe,0,0x33,
+0x1,0x83,0x80,0xc0,0x60,0x3,0,0,0xf0,0x3,
+0xff,0,0x3c,0x1,0x80,0xc6,0xc,0x18,0x60,0xc,
+0x30,0x3,0x38,0,0xc6,0,0x71,0x80,0x1,0x80,
+0xe,0,0x30,0xc0,0xc,0x18,0x60,0x61,0x81,0xc0,
+0x60,0x1,0x8c,0x63,0xc,0xc,0xc7,0,0x38,0xc0,
+0x1,0xc0,0xe,0x30,0x6,0x30,0x3,0,0xc0,0x18,
+0x1,0x80,0xee,0,0xd8,0x6c,0x3,0x8e,0,0x30,
+0x3,0x80,0xc,0x6,0x18,0,0,0,0,0x70,
+0x61,0x80,0xcc,0,0xc0,0x63,0,0x6,0x18,0xc,
+0x30,0x31,0x86,0x18,0xc1,0x86,0xc,0x18,0x60,0x63,
+0x1,0x8c,0x6,0x60,0x30,0xc0,0x1,0xc3,0x6,0x6,
+0x6,0xc0,0x6c,0xd8,0xf,0,0xd8,0xe,0x1,0x81,
+0x81,0x86,0x1c,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,0x1,0x8d,
+0x80,0xc,0,0xff,0x87,0xfe,0,0x70,0x60,0x6,
+0x31,0x8c,0,0x19,0x80,0,0x30,0x3,0x8,0x86,
+0,0,0x1,0x80,0,0,0x3,0x3,0x3,0x30,
+0,0,0,0,0xcc,0x1,0x86,0xc0,0x30,0xc,
+0x6,0x1b,0x1,0x80,0xc0,0x18,0x60,0xc,0x30,0x6,
+0x18,0x3,0xc,0x1,0x86,0,0xc3,0x3,0,0xe,
+0,0x31,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0x1c,0x60,0x66,0x38,0x1,
+0xce,0,0x73,0x80,0x1c,0xe0,0x7,0x38,0x1,0xc1,
+0xb0,0x36,0x1,0xc6,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x80,0x30,0x7,0xff,0x3,0x3,0x1c,0x18,
+0xe0,0xc7,0x6,0x38,0x31,0xc1,0x8e,0xc,0x70,0x60,
+0x3,0,0x30,0x1,0x80,0xc,0,0x60,0x1,0x86,
+0x18,0x31,0x80,0xc6,0x6,0x30,0x19,0x80,0xcc,0x6,
+0x60,0x33,0x1,0x80,0,0x66,0x31,0x81,0x86,0x6,
+0x18,0x18,0x60,0x60,0x6c,0xc,0x6,0xd,0x80,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,0,0,0xcc,0x18,0xcc,0x3,0x18,0x63,0x1,
+0x80,0x3,0,0xc0,0,0xc,0,0,0,0x60,
+0x60,0xc0,0x30,0x1c,0x1,0x80,0xcf,0xfe,0x60,0x33,
+0x1,0x83,0,0xc0,0x60,0x7,0,0,0x3c,0,
+0,0,0xf0,0,0,0xc6,0xc,0x38,0x60,0xc,
+0x30,0x3,0x18,0x1,0x86,0,0x61,0x80,0x1,0x80,
+0x6,0,0x70,0xc0,0xc,0x18,0x60,0x61,0x80,0xe0,
+0x60,0x1,0x86,0xc3,0xc,0xe,0xc3,0,0x30,0xc0,
+0,0xc1,0xcc,0x30,0x6,0x30,0x3,0,0xc0,0x18,
+0x1,0x80,0x6c,0,0xd8,0x6c,0x7,0x7,0,0x30,
+0x7,0,0xc,0x6,0x18,0,0,0,0,0x60,
+0x61,0x80,0xcc,0,0xc0,0x63,0,0x6,0x18,0xc,
+0x30,0x31,0x86,0x18,0xe1,0x86,0xc,0x18,0x60,0x63,
+0x1,0x8c,0x6,0x60,0x30,0xc0,0,0xc3,0x6,0x6,
+0x6,0xc0,0x68,0x58,0x19,0x80,0xd8,0xc,0,0xc1,
+0x83,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,0x1,0x8d,
+0x80,0x18,0x1,0xdd,0xc0,0x60,0x18,0x38,0x60,0x2,
+0x1f,0x8,0,0xc,0xc0,0,0x30,0x1,0x8,0x44,
+0,0,0x1,0x80,0,0,0x3,0x3,0x3,0x30,
+0,0,0,0x1,0x98,0x1,0x8c,0xc0,0x30,0x18,
+0x6,0x33,0x3,0,0xc0,0x18,0x60,0xc,0x30,0x6,
+0x18,0x3,0xc,0x1,0x86,0,0xc3,0x3,0,0x6,
+0,0x61,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0x18,0x60,0x76,0x18,0x1,
+0x86,0,0x61,0x80,0x18,0x60,0x6,0x18,0x1,0x83,
+0x18,0x1c,0x1,0x86,0,0x61,0x80,0x18,0x60,0x6,
+0x18,0x1,0x80,0x30,0x6,0,0x3,0x3,0x18,0x18,
+0xc0,0xc6,0x6,0x30,0x31,0x81,0x8c,0xc,0x60,0x60,
+0x3,0,0x30,0x1,0x80,0xc,0,0x60,0x1,0x86,
+0x18,0x31,0x80,0xc6,0x6,0x30,0x19,0x80,0xcc,0x6,
+0x60,0x33,0x1,0x80,0,0x6c,0x31,0x81,0x86,0x6,
+0x18,0x18,0x60,0x60,0x6c,0xc,0x6,0xd,0x80,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,0,0,0xcc,0x18,0xcc,0x3,0x18,0x63,0x3,
+0xc0,0x3,0,0xc0,0,0xc,0,0,0,0x60,
+0x60,0xc0,0x30,0x38,0x1,0x81,0x80,0x18,0x60,0x63,
+0x81,0x83,0,0xc0,0x66,0x6,0,0,0xf,0,
+0,0x3,0xc0,0,0,0xe7,0x1c,0x70,0x60,0xc,
+0x30,0x7,0x1c,0x3,0x86,0,0xe1,0x80,0x1,0x80,
+0x7,0,0xf0,0xc0,0xc,0x18,0x60,0x61,0x80,0x70,
+0x60,0x1,0x86,0xc3,0xc,0x6,0xc3,0x80,0x70,0xc0,
+0,0xe0,0xfc,0x30,0x6,0x38,0x7,0,0xc0,0xc,
+0x3,0,0x6c,0,0xf0,0x3c,0x6,0x3,0,0x30,
+0x7,0,0xc,0x6,0x18,0,0,0,0,0x60,
+0xe1,0xc1,0x86,0xc,0x60,0xe1,0x81,0x86,0xc,0x1c,
+0x30,0x31,0x86,0x18,0x71,0x86,0xc,0x18,0x60,0x61,
+0x83,0xe,0xc,0x30,0x70,0xc0,0xc0,0xc3,0x6,0xe,
+0x6,0xc0,0x78,0x78,0x39,0xc0,0x78,0x18,0,0xc1,
+0x83,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,0x1,0x8d,
+0x8c,0x18,0x1,0x80,0xc0,0x60,0x18,0x1c,0xc0,0x3,
+0,0x18,0,0x6,0x60,0,0x30,0x1,0x80,0xc,
+0,0,0x1,0x80,0,0,0x3,0x7,0x3,0x30,
+0,0,0,0x3,0x30,0x3,0x1f,0xf0,0x60,0x30,
+0xc,0x7f,0xc7,0,0xc0,0x18,0x60,0xc,0x30,0x6,
+0x18,0x3,0xc,0x1,0x86,0,0xc3,0x3,0,0x7,
+0,0xe1,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0x38,0x60,0x36,0x1c,0x3,
+0x87,0,0xe1,0xc0,0x38,0x70,0xe,0x1c,0x3,0x86,
+0xc,0x1c,0x3,0x83,0,0xc0,0xc0,0x30,0x30,0xc,
+0xc,0x3,0,0x30,0x6,0,0x3,0x6,0x18,0x38,
+0xc1,0xc6,0xe,0x30,0x71,0x83,0x8c,0x1c,0x60,0xf0,
+0x31,0x83,0x18,0x18,0xc0,0xc6,0x6,0x30,0x31,0x86,
+0x18,0x30,0xc1,0x86,0x6,0x18,0x30,0xc1,0x86,0xc,
+0x30,0x61,0x83,0,0xc0,0x38,0x61,0x83,0x86,0xe,
+0x18,0x38,0x60,0xe0,0x3c,0xe,0xc,0x7,0x80,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,0xc0,0x1,0x98,0x1c,0xdc,0x6,0x18,0x63,0x87,
+0x60,0x3,0,0xc0,0,0xc,0x3,0,0xc,0xc0,
+0x71,0xc0,0x30,0x30,0,0xc3,0x80,0x18,0x70,0xe1,
+0x83,0x7,0,0x71,0xc7,0xe,0x18,0x60,0x3,0xc0,
+0,0xf,0,0x1,0x80,0x63,0xf7,0xe0,0xc0,0x6,
+0x30,0xe,0xf,0xf,0x6,0x3,0xc1,0x80,0x1,0x80,
+0x3,0xc3,0xf0,0xc0,0xc,0x18,0x30,0xc1,0x80,0x38,
+0x60,0x1,0x86,0xc3,0xc,0x3,0xc1,0xe1,0xe0,0xc0,
+0,0x78,0x38,0x30,0x6,0x1e,0xe,0,0xc0,0xe,
+0x7,0,0x38,0,0x70,0x38,0xc,0x1,0x80,0x30,
+0xe,0,0xc,0x3,0x18,0,0,0,0,0x71,
+0xe1,0xe3,0x87,0x1c,0x71,0xe1,0xc3,0x86,0xe,0x3c,
+0x30,0x31,0x86,0x18,0x31,0x86,0xc,0x18,0x60,0x61,
+0xc7,0xf,0x1c,0x38,0xf0,0xc0,0xc1,0xc3,0x3,0x1e,
+0x3,0x80,0x38,0x70,0x30,0xc0,0x70,0x38,0,0xc1,
+0x83,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,0x1,0x87,
+0x1c,0x33,0x98,0,0,0x60,0x18,0xf,0x80,0x1,
+0x80,0x30,0,0,0,0,0,0,0xc0,0x18,
+0,0,0,0,0,0,0x3,0x8f,0x3,0x30,
+0,0,0,0,0,0x3,0x1f,0xf0,0x60,0x60,
+0xc,0x7f,0xce,0x1,0x80,0xc,0xc0,0x6,0x60,0x3,
+0x30,0x1,0x98,0,0xcc,0,0x66,0x3,0,0x3,
+0xc3,0xc1,0x80,0x1,0x80,0x1,0x80,0x1,0x80,0,
+0xc0,0xc0,0xc0,0xc1,0x80,0xf0,0x60,0x1e,0xf,0xf,
+0x3,0xc3,0xc0,0xf0,0xf0,0x3c,0x3c,0xf,0xf,0xc,
+0x6,0x3f,0xf,0x3,0x81,0xc0,0xe0,0x70,0x38,0x1c,
+0xe,0x7,0,0x30,0x6,0,0x3,0xe,0x1c,0x78,
+0xe3,0xc7,0x1e,0x38,0xf1,0xc7,0x8e,0x3c,0x71,0xf8,
+0x71,0xc7,0x1c,0x38,0xe1,0xc7,0xe,0x38,0x71,0x86,
+0x18,0x30,0xe3,0x86,0x6,0x1c,0x70,0xe3,0x87,0x1c,
+0x38,0xe1,0xc7,0,0xc0,0x30,0xe0,0xc7,0x83,0x1e,
+0xc,0x78,0x31,0xe0,0x38,0xf,0x1c,0x7,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,
+0,0xc0,0x1,0x98,0xf,0xf8,0x6,0xf,0xc1,0xfe,
+0x70,0x1,0x81,0x80,0,0xc,0x3,0,0xc,0xc0,
+0x3f,0x80,0x30,0x3f,0xf8,0xff,0,0x18,0x3f,0xc1,
+0xff,0x6,0,0x7f,0xc3,0xfc,0x18,0x60,0,0xc0,
+0,0xc,0,0x1,0x80,0x71,0xe3,0x80,0xc0,0x6,
+0x3f,0xfc,0x7,0xfe,0x7,0xff,0x81,0xff,0xe1,0x80,
+0x1,0xff,0xb0,0xc0,0xc,0x18,0x3f,0xc1,0x80,0x1c,
+0x7f,0xf1,0x83,0x83,0xc,0x3,0xc0,0xff,0xc0,0xc0,
+0,0x3f,0xfc,0x30,0x6,0xf,0xfc,0,0xc0,0x7,
+0xfe,0,0x38,0,0x60,0x18,0x1c,0x1,0xc0,0x30,
+0xf,0xff,0x8c,0x3,0x18,0,0,0,0,0x3f,
+0x71,0xbf,0x3,0xf8,0x3f,0x60,0xff,0x6,0x7,0xec,
+0x30,0x31,0x86,0x18,0x39,0x86,0xc,0x18,0x60,0x60,
+0xfe,0xd,0xf8,0x1f,0xb0,0xc0,0xff,0x83,0xc3,0xf6,
+0x3,0x80,0x30,0x30,0x70,0xe0,0x30,0x3f,0xf0,0xc1,
+0x83,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,0x1,0x87,
+0xf8,0x7f,0xf8,0,0,0x60,0x18,0x7,0,0,
+0xe0,0xe0,0,0,0,0,0,0,0x70,0x70,
+0,0,0x3f,0xfc,0,0,0x3,0xfb,0x3,0x30,
+0,0,0,0,0,0x6,0,0xc0,0xc0,0xfe,
+0x18,0x3,0xc,0x1,0x80,0xc,0xc0,0x6,0x60,0x3,
+0x30,0x1,0x98,0,0xcc,0,0x66,0x3,0xff,0xc1,
+0xff,0x81,0xff,0xe1,0xff,0xe1,0xff,0xe1,0xff,0xe0,
+0xc0,0xc0,0xc0,0xc1,0xff,0xe0,0x60,0x1e,0x7,0xfe,
+0x1,0xff,0x80,0x7f,0xe0,0x1f,0xf8,0x7,0xfe,0x18,
+0x3,0x67,0xfe,0x1,0xff,0x80,0x7f,0xe0,0x1f,0xf8,
+0x7,0xfe,0,0x30,0x6,0,0x3,0x3c,0xf,0xdc,
+0x7e,0xe3,0xf7,0x1f,0xb8,0xfd,0xc7,0xee,0x3f,0x1f,
+0xe0,0xfe,0xf,0xf0,0x7f,0x83,0xfc,0x1f,0xe1,0x86,
+0x18,0x30,0x7f,0x6,0x6,0xf,0xe0,0x7f,0x3,0xf8,
+0x1f,0xc0,0xfe,0,0xc0,0x7f,0xc0,0xfd,0x83,0xf6,
+0xf,0xd8,0x3f,0x60,0x18,0xd,0xf8,0x3,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,
+0,0xc0,0x1,0x98,0x7,0xf0,0x4,0x7,0x80,0x78,
+0,0x1,0x81,0x80,0,0,0x3,0,0xc,0xc0,
+0x1f,0,0x30,0x3f,0xf8,0x3e,0,0x18,0xf,0,
+0x7c,0x6,0,0x1f,0,0xf0,0x18,0x60,0,0,
+0,0,0,0x1,0x80,0x38,0,0,0xc0,0x6,
+0x3f,0xf0,0x1,0xf8,0x7,0xfe,0x1,0xff,0xe1,0x80,
+0,0x7e,0x30,0xc0,0xc,0x18,0x1f,0x81,0x80,0xc,
+0x7f,0xf1,0x83,0x83,0xc,0x1,0xc0,0x3f,0,0xc0,
+0,0xf,0xce,0x30,0x6,0x3,0xf0,0,0xc0,0x1,
+0xf8,0,0x38,0,0x60,0x18,0x18,0,0xc0,0x30,
+0xf,0xff,0x8c,0x3,0x18,0,0,0,0,0x1e,
+0x31,0x9e,0x1,0xf0,0x1e,0x60,0x3c,0x6,0x3,0xcc,
+0x30,0x31,0x86,0x18,0x19,0x86,0xc,0x18,0x60,0x60,
+0x7c,0xc,0xf0,0xf,0x30,0xc0,0x3f,0x1,0xc0,0xe6,
+0x3,0x80,0x30,0x30,0x60,0x60,0x30,0x3f,0xf0,0xc1,
+0x83,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,0x1,0x83,
+0xf0,0x78,0x70,0,0,0x60,0x18,0x3,0x80,0,
+0x3f,0x80,0,0,0,0,0,0,0x1f,0xc0,
+0,0,0x3f,0xfc,0,0,0x3,0x73,0x3,0x30,
+0x3,0,0,0,0,0x6,0,0xc0,0xc0,0xfe,
+0x18,0x3,0x1c,0x19,0x80,0xc,0xc0,0x6,0x60,0x3,
+0x30,0x1,0x98,0,0xcc,0,0x66,0x3,0xff,0xc0,
+0x7e,0x1,0xff,0xe1,0xff,0xe1,0xff,0xe1,0xff,0xe0,
+0xc0,0xc0,0xc0,0xc1,0xff,0x80,0x60,0xe,0x1,0xf8,
+0,0x7e,0,0x1f,0x80,0x7,0xe0,0x1,0xf8,0,
+0,0x41,0xf8,0,0x7e,0,0x1f,0x80,0x7,0xe0,
+0x1,0xf8,0,0x30,0x6,0,0x3,0x38,0x7,0x8c,
+0x3c,0x61,0xe3,0xf,0x18,0x78,0xc3,0xc6,0x1e,0x7,
+0x80,0x7c,0x3,0xc0,0x1e,0,0xf0,0x7,0x81,0x86,
+0x18,0x30,0x3e,0x6,0x6,0x7,0xc0,0x3e,0x1,0xf0,
+0xf,0x80,0x7c,0,0,0xcf,0x80,0x39,0x80,0xe6,
+0x3,0x98,0xe,0x60,0x18,0xc,0xf0,0x3,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,
+0,0,0,0,0,0xc0,0,0,0,0,
+0,0x1,0x81,0x80,0,0,0x1,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x20,0,0,
+0,0,0,0,0,0x1c,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,0xc,0,0x18,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xc,
+0,0,0x6,0,0,0,0,0,0,0,
+0,0xc,0,0,0x30,0,0,0,0,0,
+0,0,0,0,0,0,0x60,0,0,0xc1,
+0x83,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,0x1,0x86,
+0,0,0,0,0,0,0x18,0x61,0xc0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0,0x3,0x30,
+0x3,0x80,0,0,0,0,0,0,0,0,
+0,0,0x18,0x18,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x38,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,0x70,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,0x30,0xc,0,0x6,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,
+0,0,0,0,0,0xc0,0,0,0,0,
+0,0,0xc3,0,0,0,0x1,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x20,0,0,
+0,0,0,0,0,0xf,0x3,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,0xc,0,0x18,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x18,0xc,
+0,0,0x6,0,0,0,0,0,0,0,
+0,0xc,0,0,0x30,0,0,0,0,0,
+0,0,0,0,0,0,0x60,0,0,0xc1,
+0x83,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,0x1,0x86,
+0,0,0,0,0,0,0x18,0x60,0xc0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0,0x3,0x30,
+0,0xc0,0,0,0,0,0,0,0,0,
+0,0,0x18,0x38,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0xc,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,0x18,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,0x30,0xc,0,0x6,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0xc3,0,0,0,0x2,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x40,0,0,
+0,0,0,0,0,0x7,0xff,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,0xc,0,0x18,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1c,0x18,
+0,0,0x6,0,0,0,0,0,0,0,
+0,0xc,0,0,0x30,0,0,0,0,0,
+0,0,0,0,0,0,0xc0,0,0,0xc1,
+0x83,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,0x1,0x80,
+0,0,0,0,0,0,0x18,0x71,0xc0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0,0x3,0x30,
+0,0xc0,0,0,0,0,0,0,0,0,
+0,0,0x1c,0x70,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0xc,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,0x18,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,0x60,0xc,0,0xc,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x66,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,0xfc,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,0xf,0,0x78,0,0x1f,0xff,0x80,0,
+0,0,0,0,0,0,0,0,0xf,0xf8,
+0,0,0x1e,0,0,0,0,0,0,0,
+0,0xc,0,0,0x30,0,0,0,0,0,
+0,0,0,0,0,0x3,0xc0,0,0,0x61,
+0x86,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,0x1,0x80,
+0,0,0,0,0,0,0x18,0x3f,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0,0x3,0x30,
+0x7,0xc0,0,0,0,0,0,0,0,0,
+0,0,0xf,0xf0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x7c,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,0xf8,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,0x1,0xe0,0xc,0,0x3c,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x66,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,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0xf,0,0x78,0,0x1f,0xff,0x80,0,
+0,0,0,0,0,0,0,0,0x3,0xe0,
+0,0,0x1c,0,0,0,0,0,0,0,
+0,0xc,0,0,0x30,0,0,0,0,0,
+0,0,0,0,0,0x3,0x80,0,0,0x31,
+0x8c,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,0x1,0x80,
+0,0,0,0,0,0,0,0x1f,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0,0,0,
+0x3,0x80,0,0,0,0,0,0,0,0,
+0,0,0x7,0xc0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x38,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,0x70,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,0x1,0xc0,0xc,0,0x38,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,
+};
+
+static WORD Helvetica24_ch_ofst[225] = {
+0,6,12,20,34,47,69,86,92,100,
+108,118,132,138,146,152,159,172,185,198,
+211,224,237,250,263,276,289,295,301,316,
+331,346,358,383,400,417,435,453,469,483,
+502,520,528,541,559,573,594,612,630,646,
+664,681,697,713,731,748,770,787,803,818,
+825,832,839,851,865,872,885,899,911,925,
+938,946,960,973,979,985,997,1003,1023,1037,
+1050,1064,1078,1087,1099,1107,1121,1134,1152,1164,
+1177,1189,1197,1203,1211,1225,1231,1237,1243,1249,
+1255,1261,1267,1273,1279,1285,1291,1297,1303,1309,
+1315,1321,1327,1333,1339,1345,1351,1357,1363,1369,
+1375,1381,1387,1393,1399,1405,1411,1417,1423,1429,
+1435,1448,1462,1475,1489,1495,1508,1516,1535,1544,
+1558,1573,1581,1600,1608,1617,1631,1638,1645,1652,
+1666,1678,1684,1691,1698,1707,1721,1740,1759,1778,
+1790,1807,1824,1841,1858,1875,1892,1915,1933,1949,
+1965,1981,1997,2005,2013,2021,2029,2047,2065,2083,
+2101,2119,2137,2155,2169,2187,2205,2223,2241,2259,
+2275,2291,2306,2319,2332,2345,2358,2371,2384,2405,
+2417,2430,2443,2456,2469,2475,2481,2488,2494,2507,
+2521,2534,2547,2560,2573,2586,2600,2613,2627,2641,
+2655,2669,2682,2696,2709,
+};
+
+static struct font_hdr Helvetica24_font = {
+STPROP, 24, "AdobeHelv-M-R-N--24-240-75-75-P", 32, 255,
+29, 24, 14, 5, 5,
+25, 25, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Helvetica24_ch_ofst, Helvetica24_data,
+410, 29,
+NULL,
+0, 0,   /* x/y offset */
+31,        /* lineHeight */
+22,	   /* psHeight */
+};
+
+MgFont *mgHelvetica24Font()
+{
+return &Helvetica24_font;
+}
diff --git a/lib/font/mgHelvetica34.c b/lib/font/mgHelvetica34.c
new file mode 100644
index 0000000..8301891
--- /dev/null
+++ b/lib/font/mgHelvetica34.c
@@ -0,0 +1,2228 @@
+
+/* Helvetica34.c - compiled data for font AdobeHelv-M-R-N--34-240-100-100 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 100dpi/helvR24.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Helvetica34_data[21660] = {
+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,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,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,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x78,0,0,
+0x1e,0,0,0x80,0,0,0,0,0,0,
+0,0x78,0,0,0,0,0,0,0,0,
+0xf,0,0,0x1,0xe0,0,0x8,0,0,0,
+0x7,0x80,0x1e,0x10,0,0,0,0,0,0,
+0,0,0x78,0,0,0x3,0xc0,0,0x2,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x78,0,0,0x7,0x80,0,0x4,
+0,0,0,0,0,0xf,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,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,
+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,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,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,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,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,0x3c,0,0,
+0x3c,0,0x1,0xc0,0,0xe,0x30,0,0x73,0x80,
+0,0xcc,0,0,0,0,0,0,0,0,
+0x7,0x80,0,0x3,0xc0,0,0x1c,0,0x7,0xe,
+0x3,0xc0,0x3c,0x38,0xe3,0x80,0,0,0,0x71,
+0x80,0,0x3c,0,0,0x7,0x80,0,0x7,0,
+0,0x7,0x18,0,0,0,0,0,0,0,
+0,0,0,0x3c,0,0,0xf,0,0,0xe,
+0,0,0xe1,0xc0,0,0x1e,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,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,
+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,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,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,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,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,0x1c,0,0,
+0x38,0,0x3,0xe0,0,0x1f,0xf0,0,0x73,0x80,
+0,0x84,0,0,0,0,0,0,0,0,
+0x3,0x80,0,0x3,0x80,0,0x3e,0,0x7,0xe,
+0x1,0xc0,0x38,0x7c,0xe3,0x80,0,0,0,0xff,
+0x80,0,0x1c,0,0,0x7,0,0,0xf,0x80,
+0,0xf,0xf8,0,0xe,0x1c,0,0,0,0,
+0,0,0,0x1c,0,0,0xe,0,0,0x1f,
+0,0,0xe1,0xc0,0,0x1c,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,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,
+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,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,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,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,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,0xe,0,0,
+0x70,0,0x7,0x70,0,0x3f,0xe0,0,0x73,0x80,
+0,0x84,0,0,0,0,0,0,0,0,
+0x1,0xc0,0,0x7,0,0,0x77,0,0x7,0xe,
+0,0xe0,0x70,0xee,0xe3,0x80,0,0,0x1,0xff,
+0,0,0xe,0,0,0xe,0,0,0x1d,0xc0,
+0,0x1f,0xf0,0,0xe,0x1c,0,0,0,0,
+0,0,0,0xe,0,0,0x1c,0,0,0x3b,
+0x80,0,0xe1,0xc0,0,0x38,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,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,
+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,0x60,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,
+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,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,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,
+0x7,0x80,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,0x7,0,0,
+0xe0,0,0xe,0x38,0,0x31,0xc0,0,0,0,
+0,0xcc,0,0,0,0,0,0,0,0,
+0,0xe0,0,0xe,0,0,0xe3,0x80,0,0,
+0,0x70,0xe1,0xc7,0,0,0,0,0x1,0x8e,
+0,0,0x7,0,0,0x1c,0,0,0x38,0xe0,
+0,0x18,0xe0,0,0xe,0x1c,0,0,0,0,
+0,0,0,0x7,0,0,0x38,0,0,0x71,
+0xc0,0,0,0,0,0x70,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,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,
+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,0x60,0,0,
+0,0,0,0,0,0,0,0,0x1,0x80,
+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,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,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,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,
+0xf,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,0x78,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,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,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,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,0x7,0,0,0,0,0,0x60,0,0,
+0,0,0,0,0,0,0,0,0x1,0x80,
+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,0x3,
+0xe0,0,0x1,0xf0,0,0,0xf,0,0xf,0xff,
+0,0,0xfe,0,0x3f,0xfc,0,0x3f,0xff,0xc0,
+0xff,0xff,0,0x3f,0x80,0x7,0,0xe,0x7,0,
+0x3,0x83,0x80,0xf,0x7,0,0x1,0xe0,0,0xf0,
+0x78,0,0x70,0,0xfe,0,0x1f,0xff,0,0x1,
+0xfc,0,0x1f,0xff,0x80,0x1,0xfc,0x3,0xff,0xff,
+0x87,0,0xe,0x1e,0,0x3c,0x78,0x3,0x80,0x3c,
+0xf8,0,0xf7,0x80,0x3,0xc7,0xff,0xfc,0x7e,0,
+0x3f,0,0,0,0,0x7,0,0,0,0x1c,
+0,0,0,0,0,0xe0,0,0,0xf,0,
+0,0xe,0,0x3,0x87,0x1c,0,0xe,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,0x3,0xc0,
+0x3,0xc0,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,0x6,0,0x3c,0x3,0x9c,0,0xfe,
+0,0xf,0xc0,0,0,0,0,0,0,0x3,
+0xf0,0,0,0,0,0,0,0,0,0,
+0xe,0,0,0,0x1f,0xfc,0,0,0,0,
+0x78,0,0,0,0,0x3,0,0,0,0x60,
+0,0,0,0,0,0,0,0x1e,0,0,
+0x78,0,0x1,0xe0,0,0x7,0x80,0,0x1e,0,
+0,0,0,0,0xff,0xff,0xf0,0x1,0xf8,0,
+0xff,0xff,0x3,0xff,0xfc,0xf,0xff,0xf0,0x3f,0xff,
+0xc0,0xe0,0x70,0x38,0x1c,0xf,0xff,0,0x3c,0,
+0x38,0,0x7f,0,0,0x3f,0x80,0,0x1f,0xc0,
+0,0xf,0xe0,0,0x7,0xf0,0,0,0,0,
+0x7f,0x3,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0x38,0,0x38,0x38,0,0,
+0x7,0xc0,0x3,0xc0,0,0xf,0,0x4,0,0,
+0,0,0,0,0x38,0,0,0,0,0,
+0,0x1,0xe0,0,0x7,0x80,0x1,0,0,0,
+0x1e,0,0x78,0x40,0,0x78,0x40,0,0,0,
+0xf0,0,0x1,0xe0,0,0x20,0,0,0,0,
+0,0,0,0,0,0,0x3,0xc0,0,0x7,
+0x80,0,0x80,0,0,0,0x3,0xc0,0xe0,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,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,0x7,0,0,0,0,0x3,0xfc,0,0,
+0x3,0,0,0,0,0,0x18,0xc0,0x9,0x90,
+0,0,0,0,0,0,0x3,0x3,0xe0,0,
+0x18,0,0x3e,0,0xf,0x80,0,0x18,0x7,0xff,
+0x80,0x1e,0x1,0xff,0xfc,0x3,0xe0,0,0xf8,0,
+0,0,0,0,0,0,0,0,0,0xf,
+0xf8,0,0xf,0xfe,0,0,0xf,0,0xf,0xff,
+0xc0,0x3,0xff,0x80,0x3f,0xff,0,0x3f,0xff,0xc0,
+0xff,0xff,0,0xff,0xe0,0x7,0,0xe,0x7,0,
+0x3,0x83,0x80,0x1e,0x7,0,0x1,0xe0,0,0xf0,
+0x78,0,0x70,0x3,0xff,0x80,0x1f,0xff,0xc0,0x7,
+0xff,0,0x1f,0xff,0xe0,0x7,0xff,0x3,0xff,0xff,
+0x87,0,0xe,0x1e,0,0x3c,0x78,0x3,0x80,0x3c,
+0x78,0x1,0xe3,0xc0,0x7,0x87,0xff,0xfc,0x7e,0xc0,
+0x3f,0,0xc0,0,0,0x7,0x80,0,0,0x1c,
+0,0,0,0,0,0xe0,0,0,0x1f,0,
+0,0xe,0,0x3,0x87,0x1c,0,0xe,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,0x7,0xc1,
+0x83,0xe0,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,0x3c,0,0,
+0,0x70,0x3,0x86,0,0xff,0x3,0x9c,0x3,0xff,
+0x80,0x1d,0xe0,0,0,0,0,0,0,0x1f,
+0xfc,0x1,0xff,0x7,0xc0,0,0,0x7,0x81,0xf0,
+0x1c,0,0,0,0x7f,0xfc,0,0,0x1,0x81,
+0xfe,0,0,0x1,0x80,0x7,0,0x18,0,0xe0,
+0x3,0xe0,0,0xe0,0,0,0,0x1e,0,0,
+0x78,0,0x1,0xe0,0,0x7,0x80,0,0x1e,0,
+0,0x78,0,0,0xff,0xff,0xf0,0x7,0xfe,0,
+0xff,0xff,0x3,0xff,0xfc,0xf,0xff,0xf0,0x3f,0xff,
+0xc0,0xe0,0x70,0x38,0x1c,0xf,0xff,0xc0,0x3e,0,
+0x38,0x1,0xff,0xc0,0,0xff,0xe0,0,0x7f,0xf0,
+0,0x3f,0xf8,0,0x1f,0xfc,0,0,0,0x1,
+0xff,0xc6,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0x3c,0,0x78,0x38,0,0,
+0x1f,0xf0,0x1,0xe0,0,0x1e,0,0xe,0,0x7,
+0x18,0,0,0,0x6c,0,0,0,0,0,
+0,0,0xf0,0,0xf,0,0x3,0x80,0,0,
+0xf,0,0xf0,0xe0,0,0x3c,0xe0,0,0xe3,0,
+0x78,0,0x3,0xc0,0,0x70,0,0x38,0xc0,0,
+0,0,0,0,0,0,0x1,0xe0,0,0xf,
+0,0x1,0xc0,0,0,0,0x7,0x80,0xe0,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,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,0x7,0xe,0x70,0x7,0xe,0x7,0xfe,0x1,0xf0,
+0x7,0,0x1,0xf0,0,0xe0,0x30,0x60,0x1d,0xb8,
+0,0,0,0,0,0,0x3,0xf,0xf8,0,
+0x38,0,0xff,0x80,0x3f,0xe0,0,0x38,0x7,0xff,
+0x80,0x7f,0x81,0xff,0xfc,0xf,0xf8,0x3,0xfe,0,
+0,0,0,0,0,0,0,0,0,0x1f,
+0xfc,0,0x3f,0xff,0x80,0,0xf,0x80,0xf,0xff,
+0xe0,0x7,0xff,0xc0,0x3f,0xff,0x80,0x3f,0xff,0xc0,
+0xff,0xff,0x3,0xff,0xf0,0x7,0,0xe,0x7,0,
+0x3,0x83,0x80,0x3c,0x7,0,0x1,0xf0,0x1,0xf0,
+0x7c,0,0x70,0xf,0xef,0xe0,0x1f,0xff,0xe0,0x1f,
+0xdf,0xc0,0x1f,0xff,0xf0,0xf,0xff,0x83,0xff,0xff,
+0x87,0,0xe,0x1e,0,0x3c,0x78,0x7,0xc0,0x3c,
+0x3c,0x3,0xc3,0xc0,0x7,0x7,0xff,0xfc,0x70,0xc0,
+0x7,0x1,0xe0,0,0,0x3,0x80,0,0,0x1c,
+0,0,0,0,0,0xe0,0,0,0x3c,0,
+0,0xe,0,0x3,0x87,0x1c,0,0xe,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,0x7,0x1,
+0x80,0xe0,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,0xff,0x80,0,
+0,0x70,0x3,0x86,0x1,0xff,0x83,0x9c,0x7,0x1,
+0xe0,0x18,0x60,0,0,0,0,0,0,0x38,
+0xf,0x1,0xff,0xf,0xe0,0,0,0x1f,0xc3,0xf8,
+0x38,0,0,0,0xfe,0x30,0,0,0x3,0x81,
+0x86,0,0,0x3,0x80,0x6,0,0x38,0,0xc0,
+0x7,0xf0,0,0xc0,0,0,0,0x1e,0,0,
+0x78,0,0x1,0xe0,0,0x7,0x80,0,0x1e,0,
+0,0x78,0,0x1,0xff,0xff,0xf0,0xf,0xff,0x80,
+0xff,0xff,0x3,0xff,0xfc,0xf,0xff,0xf0,0x3f,0xff,
+0xc0,0xe0,0x70,0x38,0x1c,0xf,0xff,0xe0,0x3e,0,
+0x38,0x7,0xff,0xf0,0x3,0xff,0xf8,0x1,0xff,0xfc,
+0,0xff,0xfe,0,0x7f,0xff,0,0,0,0x7,
+0xff,0xfc,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0x1c,0,0x70,0x38,0,0,
+0x3f,0xf8,0,0xe0,0,0x1c,0,0x1f,0,0xf,
+0xf8,0x3,0x9c,0,0x44,0,0,0,0,0,
+0,0,0x70,0,0xe,0,0x7,0xc0,0x7,0x1c,
+0x7,0,0xe1,0xf1,0xce,0x1f,0xc0,0x1,0xff,0,
+0x38,0,0x3,0x80,0,0xf8,0,0x7f,0xc0,0xe,
+0x38,0,0,0,0,0,0,0xe0,0,0xe,
+0,0x3,0xe0,0x1,0xce,0,0x7,0,0xe0,0,
+0x7,0x1c,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,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,0x7,0xe,0x70,0x7,0xe,0xf,0x6f,0x7,0xf8,
+0x6,0,0x3,0xf8,0,0xe0,0x30,0x60,0xf,0xf0,
+0,0,0,0,0,0,0x3,0x1f,0xfc,0,
+0x38,0x1,0xff,0xc0,0x7f,0xf0,0,0x78,0x7,0xff,
+0x80,0xff,0xc1,0xff,0xfc,0x1f,0xfc,0x7,0xff,0,
+0,0,0,0,0,0,0,0,0,0x3c,
+0x1c,0,0xfc,0xf,0xe0,0,0x1f,0x80,0xe,0x3,
+0xe0,0xf,0x83,0xe0,0x38,0x7,0xc0,0x38,0,0,
+0xe0,0,0x7,0xe0,0xfc,0x7,0,0xe,0x7,0,
+0x3,0x83,0x80,0x78,0x7,0,0x1,0xf0,0x1,0xf0,
+0x7e,0,0x70,0x1f,0x1,0xf0,0x1c,0x1,0xe0,0x3e,
+0x3,0xe0,0x1c,0,0xf0,0x1e,0x7,0xc0,0x3,0x80,
+0x7,0,0xe,0xe,0,0x38,0x38,0x7,0xc0,0x38,
+0x1c,0x3,0xc1,0xe0,0xf,0,0,0x78,0x70,0x60,
+0x7,0x1,0xe0,0,0,0x1,0xc0,0,0,0x1c,
+0,0,0,0,0,0xe0,0,0,0x38,0,
+0,0xe,0,0x3,0x87,0x1c,0,0xe,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x38,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x6,0x1,
+0x80,0x60,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,0x1,0xff,0xc0,0,
+0,0x38,0x7,0x6,0x1,0xc7,0x80,0,0xc,0,
+0x70,0,0x60,0,0,0,0,0,0,0x60,
+0x3,0x80,0,0x1c,0x70,0,0,0x18,0xc7,0x1c,
+0,0,0,0,0xfe,0x30,0,0,0xf,0x83,
+0x87,0,0,0xf,0x80,0xe,0,0xf8,0x1,0x80,
+0x6,0x38,0x1,0x80,0,0,0,0x3f,0,0,
+0xfc,0,0x3,0xf0,0,0xf,0xc0,0,0x3f,0,
+0,0xfc,0,0x1,0xc7,0,0,0x1f,0x7,0x80,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0x1,0xf0,0x3f,0,
+0x38,0xf,0x80,0xf8,0x7,0xc0,0x7c,0x3,0xe0,0x3e,
+0x1,0xf0,0x1f,0,0xf8,0xf,0x80,0,0,0xf,
+0x80,0xf8,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0x1e,0,0xf0,0x38,0,0,
+0x3c,0x78,0,0x70,0,0x38,0,0x3b,0x80,0x1f,
+0xf0,0x3,0x9c,0,0x44,0,0,0,0,0,
+0,0,0x38,0,0x1c,0,0xe,0xe0,0x7,0x1c,
+0x3,0x81,0xc3,0xb9,0xce,0xf,0x80,0x3,0xfe,0,
+0x1c,0,0x7,0,0x1,0xdc,0,0xff,0x80,0xe,
+0x38,0,0,0,0,0,0,0x70,0,0x1c,
+0,0x7,0x70,0x1,0xce,0,0xe,0,0xe0,0,
+0x7,0x1c,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,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,0x7,0xe,0x70,0x6,0xc,0x1c,0x63,0x87,0x3c,
+0xe,0,0x7,0x9c,0,0xe0,0x60,0x30,0x7,0xe0,
+0,0,0,0,0,0,0x6,0x1e,0x3c,0,
+0x78,0x3,0xc1,0xe0,0x70,0x70,0,0x78,0x7,0,
+0x1,0xe1,0xc0,0,0x1c,0x1c,0x1e,0xf,0xf,0x80,
+0,0,0,0,0,0,0,0,0,0x38,
+0xe,0x1,0xf0,0x1,0xf0,0,0x1f,0x80,0xe,0,
+0xf0,0x1e,0,0xf0,0x38,0x3,0xc0,0x38,0,0,
+0xe0,0,0xf,0x80,0x3c,0x7,0,0xe,0x7,0,
+0x3,0x83,0x80,0xf0,0x7,0,0x1,0xf8,0x3,0xf0,
+0x7e,0,0x70,0x3e,0,0xf8,0x1c,0,0xf0,0x7c,
+0x1,0xf0,0x1c,0,0x78,0x1c,0x1,0xe0,0x3,0x80,
+0x7,0,0xe,0xf,0,0x78,0x38,0x7,0xc0,0x38,
+0x1e,0x7,0x80,0xe0,0xe,0,0,0xf8,0x70,0x60,
+0x7,0x3,0xf0,0,0,0,0xe0,0,0,0x1c,
+0,0,0,0,0,0xe0,0,0,0x38,0,
+0,0xe,0,0,0,0x1c,0,0xe,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x38,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x6,0x1,
+0x80,0x60,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,0x8,0x3,0xc3,0xc0,0,
+0,0x38,0x7,0x6,0x3,0x83,0xc0,0,0x18,0,
+0x18,0x1,0xe0,0,0,0,0,0,0,0xc0,
+0,0xc0,0,0x18,0x30,0x3,0x80,0x30,0x66,0xc,
+0,0,0,0x1,0xfe,0x30,0,0,0xf,0x83,
+0x3,0,0,0xf,0x80,0x1c,0,0xf8,0x3,0x80,
+0xc,0x18,0x3,0x80,0,0,0,0x3f,0,0,
+0xfc,0,0x3,0xf0,0,0xf,0xc0,0,0x3f,0,
+0,0xfc,0,0x3,0x87,0,0,0x3c,0x3,0xc0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x70,0x3f,0,
+0x38,0x1f,0,0x7c,0xf,0x80,0x3e,0x7,0xc0,0x1f,
+0x3,0xe0,0xf,0x81,0xf0,0x7,0xc0,0,0,0x1f,
+0,0x7c,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0xe,0,0xe0,0x38,0,0,
+0x78,0x3c,0,0x38,0,0x70,0,0x71,0xc0,0x18,
+0xe0,0x3,0x9c,0,0x6c,0,0,0,0,0,
+0,0,0x1c,0,0x38,0,0x1c,0x70,0x7,0x1c,
+0x1,0xc3,0x87,0x1d,0xce,0x1f,0x80,0x3,0x1c,0,
+0xe,0,0xe,0,0x3,0x8e,0,0xc7,0,0xe,
+0x38,0,0,0,0,0,0,0x38,0,0x38,
+0,0xe,0x38,0x1,0xce,0,0x1c,0,0xe0,0,
+0x7,0x1c,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,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,0x7,0xe,0x70,0x6,0xc,0x1c,0x63,0x8e,0xc,
+0xc,0,0xf,0xe,0,0xe0,0x60,0x30,0x3,0xc0,
+0,0,0,0,0,0,0x6,0x3c,0x1e,0x1,
+0xf8,0x3,0x80,0xe0,0xe0,0x38,0,0xf8,0x7,0,
+0x1,0xc0,0xe0,0,0x38,0x38,0xe,0xe,0x7,0x80,
+0,0,0,0,0,0,0,0,0,0x78,
+0xe,0x3,0xc0,0,0xf8,0,0x39,0xc0,0xe,0,
+0xf0,0x1c,0,0x70,0x38,0x1,0xe0,0x38,0,0,
+0xe0,0,0xf,0,0x1e,0x7,0,0xe,0x7,0,
+0x3,0x83,0x81,0xe0,0x7,0,0x1,0xf8,0x3,0xf0,
+0x7f,0,0x70,0x3c,0,0x78,0x1c,0,0x70,0x78,
+0,0xf0,0x1c,0,0x38,0x38,0,0xe0,0x3,0x80,
+0x7,0,0xe,0xf,0,0x78,0x3c,0xe,0xe0,0x78,
+0xf,0x7,0,0xf0,0x1e,0,0,0xf0,0x70,0x60,
+0x7,0x3,0x30,0,0,0,0,0,0,0x1c,
+0,0,0,0,0,0xe0,0,0,0x38,0,
+0,0xe,0,0,0,0x1c,0,0xe,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x38,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x6,0x1,
+0x80,0x60,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,0x18,0x7,0x81,0xe0,0,
+0,0x1c,0xe,0x6,0x3,0x81,0xc0,0,0x30,0x7e,
+0xc,0x1f,0xe0,0,0,0,0,0,0x1,0x80,
+0,0x60,0,0x18,0x30,0x3,0x80,0x30,0x66,0xc,
+0,0,0,0x1,0xfe,0x30,0,0,0x1,0x83,
+0x3,0,0,0x1,0x80,0x18,0,0x18,0x3,0,
+0xc,0x18,0x3,0,0,0,0,0x7f,0x80,0x1,
+0xfe,0,0x7,0xf8,0,0x1f,0xe0,0,0x7f,0x80,
+0x1,0xfe,0,0x3,0x87,0,0,0x78,0x1,0xe0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x78,0x3f,0x80,
+0x38,0x1e,0,0x3c,0xf,0,0x1e,0x7,0x80,0xf,
+0x3,0xc0,0x7,0x81,0xe0,0x3,0xc0,0,0,0x1e,
+0,0x7c,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0xf,0x1,0xe0,0x3f,0xfe,0,
+0x70,0x1c,0,0,0,0,0,0,0,0,
+0,0,0,0,0x38,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x3b,0xc0,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,0xe0,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,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,0x7,0xe,0x70,0xe,0x1c,0x38,0x63,0x8c,0xe,
+0x1c,0,0xe,0xe,0,0xe0,0xe0,0x38,0x7,0xe0,
+0,0,0,0,0,0,0x6,0x38,0xe,0x7,
+0xf8,0x7,0x80,0x70,0xe0,0x38,0x1,0xf8,0x7,0,
+0x3,0x80,0xe0,0,0x30,0x38,0xe,0x1e,0x3,0x80,
+0,0,0,0,0,0,0,0,0,0x70,
+0xe,0x7,0x80,0,0x78,0,0x39,0xc0,0xe,0,
+0x70,0x38,0,0x78,0x38,0,0xe0,0x38,0,0,
+0xe0,0,0x1e,0,0xe,0x7,0,0xe,0x7,0,
+0x3,0x83,0x83,0xc0,0x7,0,0x1,0xf8,0x3,0xf0,
+0x77,0x80,0x70,0x78,0,0x3c,0x1c,0,0x70,0xf0,
+0,0x78,0x1c,0,0x38,0x38,0,0xe0,0x3,0x80,
+0x7,0,0xe,0x7,0,0x70,0x3c,0xe,0xe0,0x78,
+0xf,0xf,0,0x70,0x3c,0,0x1,0xe0,0x70,0x30,
+0x7,0x3,0x30,0,0,0,0,0,0,0x1c,
+0,0,0,0,0,0xe0,0,0,0x38,0,
+0,0xe,0,0,0,0x1c,0,0xe,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x38,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x6,0x1,
+0x80,0x60,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,0x10,0x7,0,0xe0,0,
+0,0x1c,0xe,0x6,0x3,0x81,0xc0,0,0x60,0xff,
+0x86,0x38,0x60,0,0,0,0,0,0x3,0xf,
+0xf8,0x30,0,0x18,0x30,0x3,0x80,0,0x60,0x1c,
+0,0,0,0x3,0xfe,0x30,0,0,0x1,0x83,
+0x3,0,0,0x1,0x80,0x38,0,0x18,0x6,0,
+0,0x38,0x6,0,0,0,0,0x73,0x80,0x1,
+0xce,0,0x7,0x38,0,0x1c,0xe0,0,0x73,0x80,
+0x1,0xce,0,0x7,0x87,0,0,0x70,0,0xe0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x38,0x3b,0xc0,
+0x38,0x3c,0,0x1e,0x1e,0,0xf,0xf,0,0x7,
+0x87,0x80,0x3,0xc3,0xc0,0x1,0xe0,0,0,0x3c,
+0,0xde,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0x7,0x3,0xc0,0x3f,0xff,0x80,
+0x70,0x1c,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,0x11,0xe0,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,0xe0,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,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,0x7,0xe,0x70,0xe,0x1c,0x38,0x60,0xc,0xe,
+0x18,0,0xe,0xe,0,0xe0,0xc0,0x18,0xe,0x70,
+0,0,0,0,0,0,0xc,0x38,0xe,0x7,
+0xf8,0x7,0,0x70,0xe0,0x38,0x3,0xb8,0xe,0,
+0x3,0x80,0,0,0x70,0x38,0xe,0x1c,0x3,0xc0,
+0xe0,0,0,0,0,0,0,0,0,0x70,
+0xe,0x7,0,0,0x3c,0,0x39,0xc0,0xe,0,
+0x70,0x38,0,0x38,0x38,0,0xe0,0x38,0,0,
+0xe0,0,0x1c,0,0xe,0x7,0,0xe,0x7,0,
+0x3,0x83,0x87,0x80,0x7,0,0x1,0xd8,0x3,0x70,
+0x73,0x80,0x70,0x70,0,0x1c,0x1c,0,0x70,0xe0,
+0,0x38,0x1c,0,0x38,0x38,0,0,0x3,0x80,
+0x7,0,0xe,0x7,0,0x70,0x1c,0xe,0xe0,0x70,
+0x7,0x9e,0,0x78,0x3c,0,0x3,0xc0,0x70,0x30,
+0x7,0x7,0x38,0,0,0,0,0xf,0xe0,0x1c,
+0x7c,0,0x7c,0,0x7c,0xe0,0xf,0x80,0xff,0x3,
+0xe7,0xe,0x3e,0x3,0x87,0x1c,0xf,0xe,0x1c,0x78,
+0x1e,0x3,0x8f,0x80,0xf,0x80,0,0xf0,0,0xf8,
+0x3,0x9c,0x7,0xc0,0xff,0x38,0x7,0x38,0x3,0xb8,
+0xe,0x3,0xf8,0xf,0x38,0x7,0x1f,0xfe,0x6,0x1,
+0x80,0x60,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,0x70,0x1,0xf8,0x7,0,0xe0,0x73,
+0x18,0xe,0x1c,0x6,0x3,0xc0,0,0,0x61,0xc1,
+0xc6,0x30,0x60,0,0,0,0,0,0x3,0xf,
+0xfc,0x30,0,0x1c,0x70,0x3,0x80,0,0xc0,0x78,
+0,0xe,0x1,0xc3,0xfe,0x30,0,0,0x1,0x83,
+0x3,0,0,0x1,0x80,0x30,0,0x18,0xe,0,
+0,0xf0,0xe,0,0,0xe0,0,0x73,0x80,0x1,
+0xce,0,0x7,0x38,0,0x1c,0xe0,0,0x73,0x80,
+0x1,0xce,0,0x7,0x7,0,0,0x70,0,0xe0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x38,0x39,0xc0,
+0x38,0x38,0,0xe,0x1c,0,0x7,0xe,0,0x3,
+0x87,0,0x1,0xc3,0x80,0,0xe0,0,0,0x38,
+0x1,0x8e,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0x7,0x83,0xc0,0x3f,0xff,0xc0,
+0x70,0x1c,0x3,0xf8,0,0xfe,0,0x3f,0x80,0xf,
+0xe0,0x3,0xf8,0,0xfe,0,0x1f,0x3,0xe0,0,
+0xf8,0,0x7c,0,0x1f,0,0x7,0xc0,0x1,0xf0,
+0x3,0x81,0xc0,0xe0,0x70,0x7,0xf0,0,0x3c,0,
+0x3e,0,0x7,0xc0,0,0xf8,0,0x1f,0,0x3,
+0xe0,0,0,0,0x7,0xc3,0x1c,0x3,0x83,0x80,
+0x70,0x70,0xe,0xe,0x1,0xc3,0x80,0x70,0xe7,0xe0,
+0x38,0x7,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,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,0x7,0x4,0x20,0xff,0xff,0x38,0x60,0xc,0xe,
+0x38,0,0xf,0x1c,0,0xe1,0xc0,0x1c,0x1c,0x38,
+0x1,0xc0,0,0,0,0,0xc,0x70,0x7,0,
+0x38,0x7,0,0x70,0xe0,0x38,0x3,0xb8,0xe,0,
+0x3,0x80,0,0,0xe0,0x38,0xe,0x1c,0x1,0xc0,
+0xe0,0x70,0,0,0,0,0,0,0,0,
+0xe,0xe,0x3,0xe3,0x1c,0,0x79,0xe0,0xe,0,
+0xf0,0x70,0,0,0x38,0,0x70,0x38,0,0,
+0xe0,0,0x3c,0,0,0x7,0,0xe,0x7,0,
+0x3,0x83,0x8f,0,0x7,0,0x1,0xdc,0x7,0x70,
+0x73,0xc0,0x70,0xf0,0,0x1e,0x1c,0,0x71,0xe0,
+0,0x3c,0x1c,0,0x38,0x3c,0,0,0x3,0x80,
+0x7,0,0xe,0x7,0x80,0xf0,0x1c,0xe,0xe0,0x70,
+0x3,0x9c,0,0x3c,0x78,0,0x3,0xc0,0x70,0x30,
+0x7,0x6,0x18,0,0,0,0,0x3f,0xf8,0x1d,
+0xfe,0x1,0xff,0x1,0xfe,0xe0,0x3f,0xe0,0xff,0xf,
+0xf7,0xe,0xff,0x3,0x87,0x1c,0x1e,0xe,0x1d,0xfe,
+0x7f,0x83,0xbf,0xe0,0x3f,0xe0,0x3b,0xfc,0x3,0xfd,
+0xc3,0xbc,0x1f,0xf0,0xff,0x38,0x7,0x38,0x3,0xb8,
+0xe,0x3,0xbc,0xe,0x38,0x7,0x1f,0xfe,0x6,0x1,
+0x80,0x60,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,0x70,0x7,0xfc,0x7,0,0,0x7f,
+0xf8,0xe,0x1c,0x6,0x1,0xe0,0,0,0xc3,0x80,
+0xc3,0x30,0xe0,0,0,0,0,0,0x6,0xc,
+0xe,0x18,0,0xf,0xe0,0x3,0x80,0x1,0xc0,0x78,
+0,0xe,0x1,0xc3,0xfe,0x30,0,0,0x1,0x83,
+0x87,0,0,0x1,0x80,0x70,0,0x18,0xc,0,
+0,0xf8,0xc,0,0,0xe0,0,0xf3,0xc0,0x3,
+0xcf,0,0xf,0x3c,0,0x3c,0xf0,0,0xf3,0xc0,
+0x3,0xcf,0,0x7,0x7,0,0,0xf0,0,0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x1c,0x39,0xe0,
+0x38,0x38,0,0xe,0x1c,0,0x7,0xe,0,0x3,
+0x87,0,0x1,0xc3,0x80,0,0xe0,0,0,0x38,
+0x3,0xe,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0x3,0xc7,0x80,0x38,0x3,0xc0,
+0x70,0x3c,0xf,0xfe,0x3,0xff,0x80,0xff,0xe0,0x3f,
+0xf8,0xf,0xfe,0x3,0xff,0x80,0x7f,0xc7,0xf8,0x3,
+0xfe,0x1,0xff,0,0x7f,0xc0,0x1f,0xf0,0x7,0xfc,
+0x3,0x81,0xc0,0xe0,0x70,0x1f,0xf8,0xe,0xff,0,
+0xff,0x80,0x1f,0xf0,0x3,0xfe,0,0x7f,0xc0,0xf,
+0xf8,0,0,0,0x1f,0xf6,0x1c,0x3,0x83,0x80,
+0x70,0x70,0xe,0xe,0x1,0xc3,0x80,0x70,0xef,0xf0,
+0x38,0x7,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,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,0x7,0x4,0x20,0xff,0xff,0x1c,0x60,0xe,0xc,
+0x30,0,0x7,0xbc,0,0x41,0xc0,0x1c,0x8,0x10,
+0x1,0xc0,0,0,0,0,0xc,0x70,0x7,0,
+0x38,0,0,0x70,0,0x38,0x7,0x38,0xe,0xf8,
+0x3,0,0,0,0xe0,0x3c,0x1e,0x1c,0x1,0xc0,
+0xe0,0x70,0,0x3,0,0,0x6,0,0,0,
+0x1c,0xe,0x7,0xf7,0xe,0,0x70,0xe0,0xe,0,
+0xe0,0x70,0,0,0x38,0,0x70,0x38,0,0,
+0xe0,0,0x38,0,0,0x7,0,0xe,0x7,0,
+0x3,0x83,0x9f,0,0x7,0,0x1,0xdc,0x7,0x70,
+0x71,0xe0,0x70,0xe0,0,0xe,0x1c,0,0x71,0xc0,
+0,0x1c,0x1c,0,0x78,0x3e,0,0,0x3,0x80,
+0x7,0,0xe,0x3,0x80,0xe0,0x1c,0x1c,0x70,0x70,
+0x3,0xfc,0,0x1c,0x70,0,0x7,0x80,0x70,0x10,
+0x7,0xe,0x1c,0,0,0,0,0x3c,0x78,0x1f,
+0xff,0x3,0xff,0x83,0xff,0xe0,0x7f,0xf0,0xff,0x1f,
+0xff,0xf,0xff,0x83,0x87,0x1c,0x3c,0xe,0x1f,0xfe,
+0xff,0x83,0xff,0xe0,0x7f,0xf0,0x3f,0xfe,0x7,0xff,
+0xc3,0xfc,0x3f,0xf0,0xff,0x38,0x7,0x1c,0x7,0x1c,
+0x1f,0x7,0x1c,0x1c,0x3c,0xe,0x1f,0xfe,0x6,0x1,
+0x80,0x60,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,0x70,0xf,0x3e,0x7,0,0,0x3f,
+0xf8,0x7,0x38,0x6,0x1,0xf8,0,0,0xc3,0,
+0x3,0x39,0xe0,0,0,0,0,0,0x6,0xc,
+0x6,0x18,0,0x7,0xc0,0x3,0x80,0x7,0x80,0x1c,
+0,0xe,0x1,0xc3,0xfe,0x30,0,0,0x1,0x81,
+0x86,0,0,0x1,0x80,0xe0,0,0x18,0x1c,0,
+0,0x1c,0x18,0,0,0xe0,0,0xe1,0xc0,0x3,
+0x87,0,0xe,0x1c,0,0x38,0x70,0,0xe1,0xc0,
+0x3,0x87,0,0xf,0x7,0,0,0xf0,0,0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x1c,0x38,0xf0,
+0x38,0x78,0,0xf,0x3c,0,0x7,0x9e,0,0x3,
+0xcf,0,0x1,0xe7,0x80,0,0xf0,0x80,0x8,0x78,
+0x3,0xf,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0x1,0xc7,0,0x38,0x1,0xc0,
+0x70,0x78,0xf,0x1f,0x3,0xc7,0xc0,0xf1,0xf0,0x3c,
+0x7c,0xf,0x3f,0x3,0xc7,0xc0,0xf1,0xfe,0x3c,0x7,
+0xff,0x3,0xe7,0x80,0xf1,0xe0,0x3c,0x78,0xf,0x1e,
+0x3,0x81,0xc0,0xe0,0x70,0x3f,0xf8,0xf,0xff,0x81,
+0xff,0xc0,0x3f,0xf8,0x7,0xff,0,0xff,0xe0,0x1f,
+0xfc,0,0x1c,0,0x3f,0xfc,0x1c,0x3,0x83,0x80,
+0x70,0x70,0xe,0xe,0x1,0xc3,0x80,0xf0,0xff,0xf8,
+0x38,0xf,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,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,0x7,0,0,0xff,0xff,0x1f,0x60,0x7,0x3c,
+0x70,0,0x3,0xf8,0,0x1,0xc0,0x1c,0,0,
+0x1,0xc0,0,0,0,0,0x18,0x70,0x7,0,
+0x38,0,0,0xe0,0,0x70,0xe,0x38,0xf,0xfe,
+0x7,0x1e,0,0x1,0xc0,0x1e,0x3c,0x1c,0x1,0xc0,
+0xe0,0x70,0,0xf,0,0,0x7,0x80,0,0,
+0x1c,0x1c,0xf,0x3f,0xe,0,0x70,0xe0,0xe,0x3,
+0xe0,0x70,0,0,0x38,0,0x70,0x38,0,0,
+0xe0,0,0x38,0,0,0x7,0,0xe,0x7,0,
+0x3,0x83,0xbe,0,0x7,0,0x1,0xcc,0x6,0x70,
+0x71,0xe0,0x70,0xe0,0,0xe,0x1c,0,0xf1,0xc0,
+0,0x1c,0x1c,0,0x70,0x1f,0xe0,0,0x3,0x80,
+0x7,0,0xe,0x3,0x80,0xe0,0x1e,0x1c,0x70,0xf0,
+0x1,0xf8,0,0x1e,0xf0,0,0xf,0,0x70,0x18,
+0x7,0xc,0xc,0,0,0,0,0x70,0x3c,0x1f,
+0x7,0x83,0x83,0xc7,0xc3,0xe0,0xf0,0x78,0x38,0x3e,
+0x1f,0xf,0x83,0xc3,0x87,0x1c,0x78,0xe,0x1f,0xf,
+0xc3,0xc3,0xe0,0xf0,0xf0,0x78,0x3e,0xf,0xf,0x87,
+0xc3,0xf0,0x38,0x78,0x38,0x38,0x7,0x1c,0x7,0x1c,
+0x1f,0x7,0x1e,0x38,0x1c,0xe,0,0x1e,0x6,0x1,
+0x80,0x60,0x6,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,0x70,0x1e,0x2f,0x3,0x80,0,0x38,
+0x70,0x7,0x38,0x6,0x3,0xfe,0,0,0xc7,0,
+0x3,0x1f,0x70,0,0,0,0,0,0x6,0xc,
+0x6,0x18,0,0,0,0x3,0x80,0xe,0,0xc,
+0,0xe,0x1,0xc1,0xfe,0x30,0x30,0,0x1,0x81,
+0xfe,0,0,0x1,0x80,0xc0,0,0x18,0x18,0,
+0,0xc,0x38,0,0,0xe0,0,0xe1,0xc0,0x3,
+0x87,0,0xe,0x1c,0,0x38,0x70,0,0xe1,0xc0,
+0x3,0x87,0,0xe,0x7,0,0,0xe0,0,0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x1c,0x38,0xf0,
+0x38,0x70,0,0x7,0x38,0,0x3,0x9c,0,0x1,
+0xce,0,0,0xe7,0,0,0x71,0xc0,0x1c,0x70,
+0x6,0x7,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0x1,0xef,0,0x38,0x1,0xe0,
+0x71,0xf0,0x1c,0x7,0x7,0x1,0xc1,0xc0,0x70,0x70,
+0x1c,0x1c,0x7,0x7,0x1,0xc1,0xc0,0xf8,0xe,0x7,
+0x7,0x7,0x81,0xc1,0xe0,0x70,0x78,0x1c,0x1e,0x7,
+0x3,0x81,0xc0,0xe0,0x70,0x78,0x3c,0xf,0x83,0xc3,
+0xc1,0xe0,0x78,0x3c,0xf,0x7,0x81,0xe0,0xf0,0x3c,
+0x1e,0,0x1c,0,0x78,0x78,0x1c,0x3,0x83,0x80,
+0x70,0x70,0xe,0xe,0x1,0xc1,0xc0,0xe0,0xf8,0x3c,
+0x1c,0xe,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,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,0x7,0,0,0x1c,0x38,0xf,0xf0,0x7,0xf8,
+0x60,0,0x1,0xf0,0,0x1,0x80,0xc,0,0,
+0x1,0xc0,0,0,0,0,0x18,0x70,0x7,0,
+0x38,0,0x1,0xe0,0x7,0xf0,0xe,0x38,0xf,0xff,
+0x7,0x7f,0x80,0x1,0xc0,0xf,0xf8,0x1c,0x3,0xc0,
+0,0x70,0,0x3f,0,0,0x7,0xf0,0,0,
+0x38,0x1c,0x1c,0x1f,0xe,0,0xf0,0xf0,0xf,0xff,
+0xc0,0x70,0,0,0x38,0,0x70,0x3f,0xff,0xc0,
+0xff,0xfc,0x38,0,0,0x7,0xff,0xfe,0x7,0,
+0x3,0x83,0xff,0,0x7,0,0x1,0xce,0xe,0x70,
+0x70,0xf0,0x70,0xe0,0,0xe,0x1c,0x1,0xe1,0xc0,
+0,0x1c,0x1c,0x1,0xf0,0xf,0xfc,0,0x3,0x80,
+0x7,0,0xe,0x3,0xc1,0xe0,0xe,0x1c,0x70,0xe0,
+0,0xf0,0,0xe,0xe0,0,0x1e,0,0x70,0x18,
+0x7,0xc,0xc,0,0,0,0,0x70,0x1c,0x1e,
+0x3,0x87,0x1,0xc7,0x1,0xe0,0xe0,0x38,0x38,0x38,
+0xf,0xf,0x1,0xc3,0x87,0x1c,0xf0,0xe,0x1e,0x7,
+0x81,0xc3,0xc0,0x70,0xe0,0x38,0x3c,0x7,0xe,0x3,
+0xc3,0xc0,0x70,0x38,0x38,0x38,0x7,0x1c,0x7,0x1c,
+0x1b,0x7,0xe,0x38,0x1c,0xe,0,0x3c,0x6,0x1,
+0x80,0x60,0x1f,0x3,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,0x1c,0x27,0x3,0x80,0,0x30,
+0x30,0x3,0xf0,0x6,0x7,0x1f,0,0,0x86,0,
+0x1,0,0,0x1c,0x70,0,0,0,0x4,0xc,
+0xc,0x8,0,0,0x1,0xff,0xff,0x1c,0x6,0xc,
+0,0xe,0x1,0xc1,0xfe,0x30,0x78,0,0x1,0x80,
+0x78,0xe,0x38,0x1,0x81,0xc0,0x60,0x18,0x38,0x3c,
+0xc,0xc,0x30,0x60,0,0,0x1,0xe1,0xe0,0x7,
+0x87,0x80,0x1e,0x1e,0,0x78,0x78,0x1,0xe1,0xe0,
+0x7,0x87,0x80,0xe,0x7,0xff,0xe0,0xe0,0,0,
+0xff,0xff,0x3,0xff,0xfc,0xf,0xff,0xf0,0x3f,0xff,
+0xc0,0xe0,0x70,0x38,0x1c,0x7f,0xe0,0x1c,0x38,0x78,
+0x38,0x70,0,0x7,0x38,0,0x3,0x9c,0,0x1,
+0xce,0,0,0xe7,0,0,0x71,0xe0,0x3c,0x70,
+0xc,0x7,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0,0xee,0,0x38,0,0xe0,
+0x71,0xf0,0x1c,0x7,0x7,0x1,0xc1,0xc0,0x70,0x70,
+0x1c,0x1c,0x7,0x7,0x1,0xc1,0xc0,0x78,0xe,0xe,
+0x3,0x87,0x1,0xc1,0xc0,0x70,0x70,0x1c,0x1c,0x7,
+0x3,0x81,0xc0,0xe0,0x70,0x70,0x1c,0xf,0x1,0xc3,
+0x80,0xe0,0x70,0x1c,0xe,0x3,0x81,0xc0,0x70,0x38,
+0xe,0,0x1c,0,0x70,0x1c,0x1c,0x3,0x83,0x80,
+0x70,0x70,0xe,0xe,0x1,0xc1,0xc0,0xe0,0xf0,0x1c,
+0x1c,0xe,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,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,0x7,0,0,0x1c,0x38,0x7,0xfc,0x1,0xf0,
+0xe0,0,0x3,0xe0,0,0x3,0x80,0xe,0,0,
+0x1,0xc0,0,0,0,0,0x18,0x70,0x7,0,
+0x38,0,0x3,0xc0,0x7,0xe0,0x1c,0x38,0xf,0xf,
+0x87,0xff,0xc0,0x3,0x80,0x7,0xf0,0x1c,0x3,0xc0,
+0,0,0x1,0xfc,0x1f,0xff,0xc1,0xfc,0,0,
+0x70,0x18,0x38,0xe,0x6,0,0xf0,0xf0,0xf,0xff,
+0xc0,0x70,0,0,0x38,0,0x70,0x3f,0xff,0xc0,
+0xff,0xfc,0x38,0x3,0xff,0x7,0xff,0xfe,0x7,0,
+0x3,0x83,0xff,0,0x7,0,0x1,0xce,0xe,0x70,
+0x70,0x70,0x70,0xe0,0,0xe,0x1f,0xff,0xe1,0xc0,
+0,0x1c,0x1f,0xff,0xe0,0x3,0xff,0x80,0x3,0x80,
+0x7,0,0xe,0x1,0xc1,0xc0,0xe,0x18,0x70,0xe0,
+0,0xf0,0,0xf,0xe0,0,0x1e,0,0x70,0x18,
+0x7,0x1c,0xe,0,0,0,0,0,0x1c,0x1e,
+0x3,0xc7,0x1,0xcf,0x1,0xe1,0xe0,0x1c,0x38,0x78,
+0xf,0xe,0x1,0xc3,0x87,0x1d,0xe0,0xe,0x1c,0x7,
+0x1,0xc3,0x80,0x71,0xe0,0x3c,0x3c,0x7,0x9e,0x3,
+0xc3,0xc0,0x70,0,0x38,0x38,0x7,0xe,0xe,0xe,
+0x3b,0x87,0x7,0x70,0x1c,0x1c,0,0x38,0xe,0x1,
+0x80,0x70,0x1f,0xc3,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,0x1c,0x27,0xf,0xfc,0,0x70,
+0x38,0x3f,0xff,0x6,0xe,0xf,0x80,0,0x86,0,
+0x1,0,0,0x38,0xe0,0,0,0,0x4,0xf,
+0xf8,0x8,0,0,0x1,0xff,0xff,0x38,0x6,0xc,
+0,0xe,0x1,0xc0,0xfe,0x30,0x78,0,0x1,0x80,
+0,0x7,0x1c,0x1,0x81,0x80,0xe0,0x18,0x30,0xff,
+0xc,0xc,0x70,0xe0,0,0,0x1,0xc1,0xe0,0x7,
+0x87,0x80,0x1e,0x1e,0,0x78,0x78,0x1,0xe1,0xe0,
+0x7,0x7,0x80,0x1e,0x7,0xff,0xe0,0xe0,0,0,
+0xff,0xff,0x3,0xff,0xfc,0xf,0xff,0xf0,0x3f,0xff,
+0xc0,0xe0,0x70,0x38,0x1c,0x7f,0xe0,0x1c,0x38,0x38,
+0x38,0x70,0,0x7,0x38,0,0x3,0x9c,0,0x1,
+0xce,0,0,0xe7,0,0,0x70,0xf0,0x78,0x70,
+0x18,0x7,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0,0xfe,0,0x38,0,0xe0,
+0x71,0xf8,0,0x7,0,0x1,0xc0,0,0x70,0,
+0x1c,0,0x7,0,0x1,0xc0,0,0x70,0x7,0xe,
+0x3,0x8f,0,0xe3,0xc0,0x38,0xf0,0xe,0x3c,0x3,
+0x83,0x81,0xc0,0xe0,0x70,0x70,0x1c,0xf,0x1,0xc3,
+0x80,0xe0,0x70,0x1c,0xe,0x3,0x81,0xc0,0x70,0x38,
+0xe,0,0,0,0x70,0x3c,0x1c,0x3,0x83,0x80,
+0x70,0x70,0xe,0xe,0x1,0xc1,0xc0,0xe0,0xf0,0x1e,
+0x1c,0x1e,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,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,0x7,0,0,0x18,0x30,0x1,0xff,0,0,
+0xc0,0,0xf,0xf0,0,0x3,0x80,0xe,0,0,
+0x1,0xc0,0,0,0,0,0x10,0x70,0x7,0,
+0x38,0,0x7,0x80,0x7,0xf0,0x38,0x38,0xe,0x3,
+0x87,0xc1,0xe0,0x3,0x80,0x1f,0xfc,0xe,0x7,0xc0,
+0,0,0x7,0xe0,0x1f,0xff,0xc0,0x3f,0,0,
+0xf0,0x38,0x38,0xe,0x6,0,0xe0,0x70,0xf,0xff,
+0xe0,0x70,0,0,0x38,0,0x70,0x3f,0xff,0xc0,
+0xff,0xfc,0x38,0x3,0xff,0x7,0xff,0xfe,0x7,0,
+0x3,0x83,0xe7,0x80,0x7,0,0x1,0xc6,0xc,0x70,
+0x70,0x78,0x70,0xe0,0,0xe,0x1f,0xff,0xc1,0xc0,
+0,0x1c,0x1f,0xff,0xc0,0,0x3f,0xc0,0x3,0x80,
+0x7,0,0xe,0x1,0xc1,0xc0,0xe,0x38,0x38,0xe0,
+0x1,0xf8,0,0x7,0xc0,0,0x3c,0,0x70,0xc,
+0x7,0x18,0x6,0,0,0,0,0,0x3c,0x1c,
+0x1,0xce,0,0xe,0,0xe1,0xc0,0x1c,0x38,0x70,
+0x7,0xe,0x1,0xc3,0x87,0x1f,0xe0,0xe,0x1c,0x7,
+0x1,0xc3,0x80,0x71,0xc0,0x1c,0x38,0x3,0x9c,0x1,
+0xc3,0x80,0x38,0,0x38,0x38,0x7,0xe,0xe,0xe,
+0x3b,0x8e,0x7,0xf0,0xe,0x1c,0,0x70,0xe,0x1,
+0x80,0x70,0x31,0xf7,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,0x20,0x38,0x60,0xf,0xfc,0,0x70,
+0x38,0x3f,0xff,0,0xe,0x7,0xc0,0,0x86,0,
+0x1,0x3f,0xf0,0x71,0xc0,0xff,0xff,0,0x4,0xf,
+0xe0,0x8,0,0,0x1,0xff,0xff,0x30,0x7,0x1c,
+0,0xe,0x1,0xc0,0xfe,0x30,0x30,0,0x1,0x83,
+0xff,0x3,0x8e,0x1,0x83,0x81,0xe0,0x18,0x70,0xc3,
+0x86,0x1c,0xe1,0xe0,0,0xe0,0x1,0xc0,0xe0,0x7,
+0x3,0x80,0x1c,0xe,0,0x70,0x38,0x1,0xc0,0xe0,
+0x7,0x3,0x80,0x1c,0x7,0xff,0xe0,0xe0,0,0,
+0xff,0xff,0x3,0xff,0xfc,0xf,0xff,0xf0,0x3f,0xff,
+0xc0,0xe0,0x70,0x38,0x1c,0xe,0,0x1c,0x38,0x3c,
+0x38,0x70,0,0x7,0x38,0,0x3,0x9c,0,0x1,
+0xce,0,0,0xe7,0,0,0x70,0x78,0xf0,0x70,
+0x30,0x7,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0,0x7c,0,0x38,0x1,0xe0,
+0x70,0x3c,0,0x7,0,0x1,0xc0,0,0x70,0,
+0x1c,0,0x7,0,0x1,0xc0,0,0x70,0x7,0x1c,
+0,0xe,0,0xe3,0x80,0x38,0xe0,0xe,0x38,0x3,
+0x83,0x81,0xc0,0xe0,0x70,0xe0,0xe,0xe,0x1,0xc7,
+0,0x70,0xe0,0xe,0x1c,0x1,0xc3,0x80,0x38,0x70,
+0x7,0,0,0,0xe0,0x6e,0x1c,0x3,0x83,0x80,
+0x70,0x70,0xe,0xe,0x1,0xc1,0xe1,0xc0,0xe0,0xe,
+0x1e,0x1c,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,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,0x7,0,0,0x38,0x70,0,0x7f,0x80,0x1,
+0xc3,0xe0,0x1e,0x71,0xc0,0x3,0x80,0xe,0,0,
+0x1,0xc0,0,0,0,0,0x30,0x70,0x7,0,
+0x38,0,0x1f,0,0,0x78,0x38,0x38,0,0x3,
+0xc7,0x80,0xe0,0x7,0,0x3c,0x1e,0xf,0xff,0xc0,
+0,0,0x1f,0x80,0x1f,0xff,0xc0,0xf,0xc0,0,
+0xe0,0x38,0x78,0xe,0x6,0x1,0xe0,0x78,0xe,0x1,
+0xf0,0x70,0,0,0x38,0,0x70,0x38,0,0,
+0xe0,0,0x38,0x3,0xff,0x7,0,0xe,0x7,0,
+0x3,0x83,0xc3,0xc0,0x7,0,0x1,0xc7,0x1c,0x70,
+0x70,0x3c,0x70,0xe0,0,0xe,0x1f,0xff,0x1,0xc0,
+0,0x1c,0x1f,0xff,0xe0,0,0x7,0xe0,0x3,0x80,
+0x7,0,0xe,0x1,0xe1,0xc0,0xe,0x38,0x38,0xe0,
+0x1,0xf8,0,0x7,0xc0,0,0x78,0,0x70,0xc,
+0x7,0,0,0,0,0,0,0x1,0xfc,0x1c,
+0x1,0xce,0,0xe,0,0xe1,0xc0,0x1c,0x38,0x70,
+0x7,0xe,0x1,0xc3,0x87,0x1f,0xe0,0xe,0x1c,0x7,
+0x1,0xc3,0x80,0x71,0xc0,0x1c,0x38,0x3,0x9c,0x1,
+0xc3,0x80,0x3f,0,0x38,0x38,0x7,0xe,0xe,0xe,
+0x3b,0x8e,0x3,0xe0,0xe,0x1c,0,0xf0,0x1c,0x1,
+0x80,0x38,0x30,0x7e,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,0x20,0x38,0x40,0,0xc0,0,0x70,
+0x38,0x3f,0xff,0,0xe,0x1,0xc0,0,0x86,0,
+0x1,0x3f,0xf0,0xe3,0x80,0xff,0xff,0,0x4,0xc,
+0x70,0x8,0,0,0,0x3,0x80,0x3f,0xe3,0xf8,
+0,0xe,0x1,0xc0,0x7e,0x30,0,0,0x1,0x83,
+0xff,0x1,0xc7,0x1,0x87,0x3,0xe0,0x18,0x61,0x81,
+0x87,0xf8,0xc3,0xe0,0,0xe0,0x3,0xc0,0xf0,0xf,
+0x3,0xc0,0x3c,0xf,0,0xf0,0x3c,0x3,0xc0,0xf0,
+0xf,0x3,0xc0,0x3c,0x7,0,0,0xe0,0,0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x1c,0x38,0x1e,
+0x38,0x70,0,0x7,0x38,0,0x3,0x9c,0,0x1,
+0xce,0,0,0xe7,0,0,0x70,0x3f,0xe0,0x70,
+0x60,0x7,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0,0x7c,0,0x38,0x1,0xc0,
+0x70,0x1e,0,0x3f,0,0xf,0xc0,0x3,0xf0,0,
+0xfc,0,0x3f,0,0xf,0xc0,0x3,0xf0,0x7,0x1c,
+0,0xe,0,0xe3,0x80,0x38,0xe0,0xe,0x38,0x3,
+0x83,0x81,0xc0,0xe0,0x70,0xe0,0xe,0xe,0x1,0xc7,
+0,0x70,0xe0,0xe,0x1c,0x1,0xc3,0x80,0x38,0x70,
+0x7,0,0,0,0xe0,0xce,0x1c,0x3,0x83,0x80,
+0x70,0x70,0xe,0xe,0x1,0xc0,0xe1,0xc0,0xe0,0xe,
+0xe,0x1c,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,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,0x7,0,0,0x38,0x70,0,0x67,0x80,0x1,
+0x87,0xf8,0x1c,0x39,0xc0,0x3,0x80,0xe,0,0,
+0xff,0xff,0x80,0xf,0xf0,0,0x30,0x70,0x7,0,
+0x38,0,0x3e,0,0,0x3c,0x70,0x38,0,0x1,
+0xc7,0x80,0x70,0x7,0,0x38,0xe,0x7,0xfd,0xc0,
+0,0,0xfe,0,0,0,0,0x3,0xf8,0x1,
+0xc0,0x38,0x70,0x1c,0xe,0x1,0xff,0xf8,0xe,0,
+0x78,0x70,0,0,0x38,0,0x70,0x38,0,0,
+0xe0,0,0x38,0,0x7,0x7,0,0xe,0x7,0,
+0x3,0x83,0x81,0xc0,0x7,0,0x1,0xc7,0x1c,0x70,
+0x70,0x1c,0x70,0xe0,0,0xe,0x1c,0,0x1,0xc0,
+0,0x1c,0x1c,0x1,0xf0,0,0,0xf0,0x3,0x80,
+0x7,0,0xe,0,0xe3,0x80,0x7,0x38,0x39,0xc0,
+0x3,0x9c,0,0x3,0x80,0,0x78,0,0x70,0xc,
+0x7,0,0,0,0,0,0,0x1f,0xfc,0x1c,
+0x1,0xce,0,0xe,0,0xe1,0xff,0xfc,0x38,0x70,
+0x7,0xe,0x1,0xc3,0x87,0x1f,0x70,0xe,0x1c,0x7,
+0x1,0xc3,0x80,0x71,0xc0,0x1c,0x38,0x3,0x9c,0x1,
+0xc3,0x80,0x1f,0xe0,0x38,0x38,0x7,0x7,0x1c,0xe,
+0x31,0x8e,0x1,0xc0,0xe,0x38,0x1,0xe0,0x38,0x1,
+0x80,0x1c,0,0x3c,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,0x70,0x38,0x40,0,0xe0,0,0x30,
+0x30,0,0xe0,0,0xe,0x1,0xe0,0,0xc7,0,
+0x3,0,0,0xc3,0,0xff,0xff,0x1f,0xe6,0xc,
+0x30,0x18,0,0,0,0x3,0x80,0x3f,0xe1,0xf0,
+0,0xe,0x1,0xc0,0xe,0x30,0,0,0x1,0x80,
+0,0,0xc3,0x1,0x86,0x7,0x60,0x18,0xc1,0x81,
+0x81,0xe1,0x87,0x60,0,0xe0,0x3,0xff,0xf0,0xf,
+0xff,0xc0,0x3f,0xff,0,0xff,0xfc,0x3,0xff,0xf0,
+0xf,0xff,0xc0,0x3f,0xff,0,0,0xf0,0,0x70,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x1c,0x38,0xe,
+0x38,0x78,0,0xf,0x3c,0,0x7,0x9e,0,0x3,
+0xcf,0,0x1,0xe7,0x80,0,0xf0,0x1f,0xc0,0x70,
+0xc0,0xf,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0,0x38,0,0x38,0x3,0xc0,
+0x70,0xe,0x7,0xff,0x1,0xff,0xc0,0x7f,0xf0,0x1f,
+0xfc,0x7,0xff,0x1,0xff,0xc0,0x3f,0xff,0xff,0x1c,
+0,0xf,0xff,0xe3,0xff,0xf8,0xff,0xfe,0x3f,0xff,
+0x83,0x81,0xc0,0xe0,0x70,0xe0,0xe,0xe,0x1,0xc7,
+0,0x70,0xe0,0xe,0x1c,0x1,0xc3,0x80,0x38,0x70,
+0x7,0x7,0xff,0xf0,0xe1,0x8e,0x1c,0x3,0x83,0x80,
+0x70,0x70,0xe,0xe,0x1,0xc0,0xe3,0xc0,0xe0,0xe,
+0xe,0x3c,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,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,0x7,0,0x1,0xff,0xfe,0,0x63,0xc0,0x3,
+0x8f,0x38,0x38,0x3d,0x80,0x3,0x80,0xe,0,0,
+0xff,0xff,0x80,0xf,0xf0,0,0x30,0x70,0x7,0,
+0x38,0,0xf8,0,0,0x1c,0xe0,0x38,0,0x1,
+0xc7,0,0x70,0xe,0,0x70,0x7,0x1,0xf9,0xc0,
+0,0,0xf0,0,0,0,0,0,0x78,0x1,
+0xc0,0x38,0x70,0x1c,0xe,0x1,0xff,0xf8,0xe,0,
+0x38,0x70,0,0x38,0x38,0,0xf0,0x38,0,0,
+0xe0,0,0x3c,0,0x7,0x7,0,0xe,0x7,0xe,
+0x3,0x83,0x81,0xe0,0x7,0,0x1,0xc7,0x1c,0x70,
+0x70,0x1e,0x70,0xf0,0,0x1e,0x1c,0,0x1,0xe0,
+0,0x3c,0x1c,0,0xf0,0,0,0x70,0x3,0x80,
+0x7,0,0xe,0,0xe3,0x80,0x7,0x70,0x1d,0xc0,
+0x7,0x9e,0,0x3,0x80,0,0xf0,0,0x70,0x6,
+0x7,0,0,0,0,0,0,0x7e,0x1c,0x1c,
+0x1,0xce,0,0xe,0,0xe1,0xff,0xfc,0x38,0x70,
+0x7,0xe,0x1,0xc3,0x87,0x1e,0x78,0xe,0x1c,0x7,
+0x1,0xc3,0x80,0x71,0xc0,0x1c,0x38,0x3,0x9c,0x1,
+0xc3,0x80,0x3,0xf8,0x38,0x38,0x7,0x7,0x1c,0x6,
+0x31,0x8c,0x3,0xe0,0xf,0x38,0x1,0xc0,0x38,0x1,
+0x80,0x1c,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,0x70,0x38,0xc0,0,0xe0,0,0x38,
+0x70,0,0xe0,0,0x7,0,0xe0,0,0xc3,0x80,
+0xc3,0,0,0xe3,0x80,0,0x7,0x1f,0xe6,0xc,
+0x18,0x18,0,0,0,0x3,0x80,0,0,0,
+0,0xe,0x1,0xc0,0x6,0x30,0,0,0,0,
+0,0x1,0xc7,0,0xe,0x6,0x60,0x1,0xc0,0x3,
+0x80,0x3,0x86,0x60,0x1,0xe0,0x3,0xff,0xf0,0xf,
+0xff,0xc0,0x3f,0xff,0,0xff,0xfc,0x3,0xff,0xf0,
+0xf,0xff,0xc0,0x3f,0xff,0,0,0xf0,0,0x70,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x3c,0x38,0xf,
+0x38,0x78,0,0xf,0x3c,0,0x7,0x9e,0,0x3,
+0xcf,0,0x1,0xe7,0x80,0,0xf0,0xf,0x80,0x79,
+0x80,0xf,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0,0x38,0,0x3f,0xff,0x80,
+0x70,0xe,0x1f,0xe7,0x7,0xf9,0xc1,0xfe,0x70,0x7f,
+0x9c,0x1f,0xe7,0x7,0xf9,0xc0,0xff,0xff,0xff,0x1c,
+0,0xf,0xff,0xe3,0xff,0xf8,0xff,0xfe,0x3f,0xff,
+0x83,0x81,0xc0,0xe0,0x70,0xe0,0xe,0xe,0x1,0xc7,
+0,0x70,0xe0,0xe,0x1c,0x1,0xc3,0x80,0x38,0x70,
+0x7,0x7,0xff,0xf0,0xe3,0xe,0x1c,0x3,0x83,0x80,
+0x70,0x70,0xe,0xe,0x1,0xc0,0xf3,0x80,0xe0,0xe,
+0xf,0x38,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,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,0x2,0,0x1,0xff,0xfe,0,0x61,0xc0,0x3,
+0xc,0x1c,0x38,0x1f,0x80,0x3,0x80,0xe,0,0,
+0xff,0xff,0x80,0,0,0,0x60,0x70,0x7,0,
+0x38,0x1,0xe0,0x1,0xc0,0x1c,0xff,0xff,0,0x1,
+0xc7,0,0x70,0xe,0,0x70,0x7,0,0x1,0xc0,
+0,0,0xf0,0,0,0,0,0,0x78,0x1,
+0xc0,0x38,0x70,0x1c,0x1c,0x3,0xff,0xfc,0xe,0,
+0x38,0x78,0,0x38,0x38,0,0xe0,0x38,0,0,
+0xe0,0,0x1c,0,0x7,0x7,0,0xe,0x7,0xe,
+0x3,0x83,0x80,0xf0,0x7,0,0x1,0xc3,0x18,0x70,
+0x70,0xe,0x70,0xf0,0,0x1e,0x1c,0,0x1,0xe0,
+0x4,0x3c,0x1c,0,0x70,0x70,0,0x70,0x3,0x80,
+0x7,0,0xe,0,0xf3,0x80,0x7,0x70,0x1d,0xc0,
+0x7,0xe,0,0x3,0x80,0x1,0xe0,0,0x70,0x6,
+0x7,0,0,0,0,0,0,0x78,0x1c,0x1c,
+0x1,0xce,0,0xe,0,0xe1,0xc0,0,0x38,0x70,
+0x7,0xe,0x1,0xc3,0x87,0x1c,0x38,0xe,0x1c,0x7,
+0x1,0xc3,0x80,0x71,0xc0,0x1c,0x38,0x3,0x9c,0x1,
+0xc3,0x80,0,0x78,0x38,0x38,0x7,0x7,0x1c,0x7,
+0x71,0xdc,0x3,0xe0,0x7,0x38,0x3,0x80,0x1c,0x1,
+0x80,0x38,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,0x70,0x38,0xc0,0,0xc0,0,0x3f,
+0xf8,0x3f,0xff,0,0x7,0xc0,0xe0,0,0x61,0xe1,
+0xc6,0,0,0x71,0xc0,0,0x7,0,0x3,0xc,
+0xc,0x30,0,0,0,0x3,0x80,0,0,0,
+0,0xe,0x1,0xc0,0x6,0x30,0,0,0,0,
+0,0x3,0x8e,0,0x1c,0xc,0x60,0x1,0x80,0x7,
+0,0x3,0xc,0x60,0x1,0xc0,0x7,0xff,0xf8,0x1f,
+0xff,0xe0,0x7f,0xff,0x81,0xff,0xfe,0x7,0xff,0xf8,
+0x1f,0xff,0xe0,0x7f,0xff,0,0,0x70,0,0xf0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x38,0x38,0x7,
+0x38,0x38,0,0xe,0x1c,0,0x7,0xe,0,0x3,
+0x87,0,0x1,0xc3,0x80,0,0xe0,0xf,0x80,0x3b,
+0,0xe,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0,0x38,0,0x3f,0xff,0,
+0x70,0xe,0x1e,0x7,0x7,0x81,0xc1,0xe0,0x70,0x78,
+0x1c,0x1e,0x7,0x7,0x81,0xc1,0xf8,0x7f,0xff,0x1c,
+0,0xe,0,0x3,0x80,0,0xe0,0,0x38,0,
+0x3,0x81,0xc0,0xe0,0x70,0xe0,0xe,0xe,0x1,0xc7,
+0,0x70,0xe0,0xe,0x1c,0x1,0xc3,0x80,0x38,0x70,
+0x7,0x7,0xff,0xf0,0xe6,0xe,0x1c,0x3,0x83,0x80,
+0x70,0x70,0xe,0xe,0x1,0xc0,0x73,0x80,0xe0,0xe,
+0x7,0x38,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,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,0x2,0,0x1,0xff,0xfe,0x38,0x61,0xc0,0x7,
+0x1c,0xc,0x38,0xf,0,0x3,0x80,0xe,0,0,
+0x1,0xc0,0,0,0,0,0x60,0x38,0xe,0,
+0x38,0x3,0xc0,0x1,0xc0,0x1c,0xff,0xff,0x1c,0x1,
+0xc3,0,0x70,0xe,0,0x70,0x7,0,0x3,0x80,
+0,0,0xfe,0,0x1f,0xff,0xc0,0x3,0xf8,0x1,
+0xc0,0x38,0x70,0x38,0x1c,0x3,0xc0,0x3c,0xe,0,
+0x38,0x38,0,0x78,0x38,0,0xe0,0x38,0,0,
+0xe0,0,0x1e,0,0xf,0x7,0,0xe,0x7,0xe,
+0x3,0x83,0x80,0x70,0x7,0,0x1,0xc3,0xb8,0x70,
+0x70,0xf,0x70,0x78,0,0x3c,0x1c,0,0,0xf0,
+0xe,0x78,0x1c,0,0x78,0x78,0,0x70,0x3,0x80,
+0x7,0,0xe,0,0x77,0,0x7,0x70,0x1d,0xc0,
+0xf,0xf,0,0x3,0x80,0x3,0xc0,0,0x70,0x6,
+0x7,0,0,0,0,0,0,0xf0,0x1c,0x1c,
+0x1,0xce,0x1,0xce,0,0xe1,0xc0,0,0x38,0x70,
+0x7,0xe,0x1,0xc3,0x87,0x1c,0x3c,0xe,0x1c,0x7,
+0x1,0xc3,0x80,0x71,0xc0,0x1c,0x38,0x3,0x9c,0x1,
+0xc3,0x80,0,0x3c,0x38,0x38,0x7,0x3,0xb8,0x7,
+0x71,0xdc,0x7,0xf0,0x7,0x70,0x7,0,0xe,0x1,
+0x80,0x70,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,0x70,0x38,0x83,0x1,0xc0,0,0x7f,
+0xf8,0x3f,0xff,0,0x3,0xe0,0xe0,0,0x60,0xff,
+0x86,0,0,0x38,0xe0,0,0x7,0,0x3,0xc,
+0xe,0x30,0,0,0,0x3,0x80,0,0,0,
+0,0xe,0x1,0xc0,0x6,0x30,0,0,0,0,
+0,0x7,0x1c,0,0x18,0x1c,0x60,0x3,0x80,0xe,
+0,0x6,0x1c,0x60,0x3,0xc0,0x7,0x80,0x78,0x1e,
+0x1,0xe0,0x78,0x7,0x81,0xe0,0x1e,0x7,0x80,0x78,
+0x1e,0x1,0xe0,0x70,0x7,0,0,0x70,0,0xe0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x38,0x38,0x7,
+0xb8,0x3c,0,0x1e,0x1e,0,0xf,0xf,0,0x7,
+0x87,0x80,0x3,0xc3,0xc0,0x1,0xe0,0x1f,0xc0,0x3e,
+0,0x1e,0xe,0,0x1c,0xe,0,0x1c,0xe,0,
+0x1c,0xe,0,0x1c,0,0x38,0,0x3f,0xfe,0,
+0x70,0xe,0x3c,0x7,0xf,0x1,0xc3,0xc0,0x70,0xf0,
+0x1c,0x3c,0x7,0xf,0x1,0xc3,0xc0,0x70,0,0x1c,
+0x3,0x8e,0,0x3,0x80,0,0xe0,0,0x38,0,
+0x3,0x81,0xc0,0xe0,0x70,0xe0,0xe,0xe,0x1,0xc7,
+0,0x70,0xe0,0xe,0x1c,0x1,0xc3,0x80,0x38,0x70,
+0x7,0,0,0,0xec,0xe,0x1c,0x3,0x83,0x80,
+0x70,0x70,0xe,0xe,0x1,0xc0,0x77,0,0xe0,0xe,
+0x7,0x70,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,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,0x70,0xe0,0x38,0x61,0xc0,0x6,
+0x1c,0xc,0x38,0x7,0,0x3,0x80,0xe,0,0,
+0x1,0xc0,0,0,0,0,0x60,0x38,0xe,0,
+0x38,0x3,0x80,0x1,0xc0,0x1c,0xff,0xff,0x1c,0x3,
+0xc3,0x80,0x70,0x1c,0,0x70,0x7,0x1c,0x3,0x80,
+0,0,0x1f,0x80,0x1f,0xff,0xc0,0xf,0xc0,0,
+0,0x38,0x78,0x38,0x38,0x3,0x80,0x1c,0xe,0,
+0x38,0x3c,0,0x70,0x38,0x1,0xe0,0x38,0,0,
+0xe0,0,0xe,0,0xf,0x7,0,0xe,0x7,0xe,
+0x3,0x83,0x80,0x78,0x7,0,0x1,0xc3,0xb8,0x70,
+0x70,0x7,0xf0,0x3c,0,0x78,0x1c,0,0,0x78,
+0xf,0x70,0x1c,0,0x78,0x38,0,0xf0,0x3,0x80,
+0x7,0x80,0x1e,0,0x77,0,0x3,0xf0,0x1f,0xc0,
+0x1e,0x7,0x80,0x3,0x80,0x3,0xc0,0,0x70,0x2,
+0x7,0,0,0,0,0,0,0xe0,0x1c,0x1e,
+0x3,0xce,0x1,0xcf,0x1,0xe1,0xe0,0x1c,0x38,0x78,
+0xf,0xe,0x1,0xc3,0x87,0x1c,0x1c,0xe,0x1c,0x7,
+0x1,0xc3,0x80,0x71,0xe0,0x3c,0x3c,0x7,0x9e,0x3,
+0xc3,0x80,0x70,0x1c,0x38,0x38,0x7,0x3,0xb8,0x7,
+0x71,0xdc,0xf,0x70,0x7,0x70,0xf,0,0xe,0x1,
+0x80,0x70,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,0x70,0x38,0x87,0x1,0x80,0,0x73,
+0x18,0x3f,0xff,0x6,0x1,0xf1,0xc0,0,0x30,0x3e,
+0xc,0,0,0x1c,0x70,0,0x7,0,0x1,0x80,
+0,0x60,0,0,0,0x3,0x80,0,0,0,
+0,0xe,0x1,0xc0,0x6,0x30,0,0,0,0,
+0,0xe,0x38,0,0x38,0x38,0x60,0x3,0,0x3c,
+0,0xe,0x38,0x60,0x7,0x80,0x7,0,0x38,0x3c,
+0,0xe0,0x70,0x3,0x81,0xc0,0xe,0x7,0,0x38,
+0x1c,0,0xe0,0xf0,0x7,0,0,0x78,0x1,0xe0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x78,0x38,0x3,
+0xf8,0x1e,0,0x3c,0xf,0,0x1e,0x7,0x80,0xf,
+0x3,0xc0,0x7,0x81,0xe0,0x3,0xc0,0x3d,0xe0,0x1e,
+0,0x3c,0xf,0,0x3c,0xf,0,0x3c,0xf,0,
+0x3c,0xf,0,0x3c,0,0x38,0,0x38,0,0,
+0x70,0xe,0x38,0x7,0xe,0x1,0xc3,0x80,0x70,0xe0,
+0x1c,0x38,0x7,0xe,0x1,0xc3,0x80,0x70,0x7,0x1c,
+0x3,0x8e,0,0xe3,0x80,0x38,0xe0,0xe,0x38,0x3,
+0x83,0x81,0xc0,0xe0,0x70,0x70,0x1c,0xe,0x1,0xc3,
+0x80,0xe0,0x70,0x1c,0xe,0x3,0x81,0xc0,0x70,0x38,
+0xe,0,0,0,0x78,0x1c,0x1c,0x7,0x83,0x80,
+0xf0,0x70,0x1e,0xe,0x3,0xc0,0x77,0,0xf0,0x1c,
+0x7,0x70,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,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,0x70,0xe0,0x1c,0x63,0x80,0xe,
+0x1c,0xc,0x3c,0xf,0x80,0x3,0x80,0xc,0,0,
+0x1,0xc0,0,0,0,0,0xc0,0x38,0x1e,0,
+0x38,0x7,0,0,0xe0,0x38,0,0x38,0x1e,0x3,
+0x83,0x80,0xe0,0x1c,0,0x78,0xe,0x1e,0x7,0x80,
+0,0,0x7,0xe0,0x1f,0xff,0xc0,0x3f,0,0,
+0,0x1c,0x3c,0xfc,0xf0,0x7,0x80,0x1e,0xe,0,
+0x78,0x1e,0,0xf0,0x38,0x3,0xc0,0x38,0,0,
+0xe0,0,0xf,0,0x3f,0x7,0,0xe,0x7,0xf,
+0x7,0x83,0x80,0x3c,0x7,0,0x1,0xc1,0xb0,0x70,
+0x70,0x3,0xf0,0x3e,0,0xf8,0x1c,0,0,0x7c,
+0x7,0xf0,0x1c,0,0x78,0x3c,0,0xe0,0x3,0x80,
+0x3,0xc0,0x3c,0,0x77,0,0x3,0xe0,0xf,0x80,
+0x1e,0x7,0x80,0x3,0x80,0x7,0x80,0,0x70,0x3,
+0x7,0,0,0,0,0,0,0xe0,0x3c,0x1e,
+0x3,0x87,0x1,0xcf,0x1,0xe0,0xe0,0x3c,0x38,0x38,
+0x1f,0xe,0x1,0xc3,0x87,0x1c,0x1e,0xe,0x1c,0x7,
+0x1,0xc3,0x80,0x70,0xe0,0x38,0x3c,0x7,0xe,0x3,
+0xc3,0x80,0x70,0x1c,0x38,0x38,0xf,0x3,0xb8,0x3,
+0x60,0xd8,0xe,0x38,0x3,0xf0,0x1e,0,0x6,0x1,
+0x80,0x60,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,0x70,0x1d,0x87,0x3,0x80,0,0,
+0,0,0xe0,0x6,0,0xf9,0xc0,0,0x18,0,
+0x18,0,0,0,0,0,0x7,0,0,0xc0,
+0,0xc0,0,0,0,0,0,0,0,0,
+0,0xe,0x3,0xc0,0x6,0x30,0,0,0,0,
+0,0,0,0,0x30,0x3f,0xf8,0x6,0,0x70,
+0,0x1c,0x3f,0xf8,0xf,0,0xf,0,0x3c,0x3c,
+0,0xf0,0xf0,0x3,0xc3,0xc0,0xf,0xf,0,0x3c,
+0x3c,0,0xf0,0xf0,0x7,0,0,0x3c,0x3,0xc0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0,0x70,0x38,0x1,
+0xf8,0x1f,0,0x7c,0xf,0x80,0x3e,0x7,0xc0,0x1f,
+0x3,0xe0,0xf,0x81,0xf0,0x7,0xc0,0x78,0xf0,0x1f,
+0,0x7c,0x7,0x80,0x78,0x7,0x80,0x78,0x7,0x80,
+0x78,0x7,0x80,0x78,0,0x38,0,0x38,0,0,
+0x70,0x1c,0x38,0xf,0xe,0x3,0xc3,0x80,0xf0,0xe0,
+0x3c,0x38,0xf,0xe,0x3,0xc3,0x80,0x78,0x7,0xe,
+0x7,0x7,0,0xe1,0xc0,0x38,0x70,0xe,0x1c,0x3,
+0x83,0x81,0xc0,0xe0,0x70,0x70,0x1c,0xe,0x1,0xc3,
+0x80,0xe0,0x70,0x1c,0xe,0x3,0x81,0xc0,0x70,0x38,
+0xe,0,0,0,0x70,0x1c,0x1c,0x7,0x83,0x80,
+0xf0,0x70,0x1e,0xe,0x3,0xc0,0x3f,0,0xf0,0x1c,
+0x3,0xf0,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,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,0x7,0,0,0x60,0xc0,0x1c,0x63,0x80,0xc,
+0xc,0x1c,0x1e,0x1f,0xc0,0x1,0x80,0xc,0,0,
+0x1,0xc0,0x7,0,0,0x70,0xc0,0x1e,0x3c,0,
+0x38,0x7,0,0,0xf0,0x78,0,0x38,0xf,0xf,
+0x81,0xc1,0xe0,0x1c,0,0x3c,0x1e,0xf,0xf,0,
+0xe0,0x70,0x1,0xfc,0,0,0x1,0xfc,0,0x1,
+0xc0,0x1c,0x3f,0xdf,0xe0,0x7,0x80,0x1e,0xe,0,
+0xf0,0x1f,0x83,0xe0,0x38,0x7,0x80,0x38,0,0,
+0xe0,0,0x7,0xc0,0x7f,0x7,0,0xe,0x7,0x7,
+0x8f,0x3,0x80,0x1e,0x7,0,0x1,0xc1,0xf0,0x70,
+0x70,0x3,0xf0,0x1f,0x1,0xf0,0x1c,0,0,0x3e,
+0x3,0xe0,0x1c,0,0x38,0x1f,0x3,0xe0,0x3,0x80,
+0x3,0xe0,0x7c,0,0x3e,0,0x3,0xe0,0xf,0x80,
+0x3c,0x3,0xc0,0x3,0x80,0xf,0,0,0x70,0x3,
+0x7,0,0,0,0,0,0,0xe0,0x7c,0x1f,
+0x87,0x87,0x83,0x87,0x83,0xe0,0xf0,0x78,0x38,0x3c,
+0x1f,0xe,0x1,0xc3,0x87,0x1c,0xf,0xe,0x1c,0x7,
+0x1,0xc3,0x80,0x70,0xf0,0x78,0x3e,0xf,0xf,0x7,
+0xc3,0x80,0x78,0x38,0x38,0x3c,0x1f,0x1,0xf0,0x3,
+0xe0,0xf8,0x1c,0x3c,0x3,0xe0,0x1c,0,0x6,0x1,
+0x80,0x60,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,0x70,0x1f,0xf,0x7,0x38,0x60,0,
+0,0,0xe0,0x6,0,0x3f,0x80,0,0x1c,0,
+0x38,0,0,0,0,0,0x7,0,0,0xe0,
+0x1,0xc0,0,0,0,0,0,0,0,0,
+0,0xf,0x7,0xc0,0x6,0x30,0,0,0,0,
+0,0,0,0,0x70,0x3f,0xf8,0xe,0,0xe0,
+0,0x18,0x3f,0xf8,0x1e,0,0xf,0,0x3c,0x3c,
+0,0xf0,0xf0,0x3,0xc3,0xc0,0xf,0xf,0,0x3c,
+0x3c,0,0xf0,0xe0,0x7,0,0,0x1f,0x7,0xc0,
+0xe0,0,0x3,0x80,0,0xe,0,0,0x38,0,
+0,0xe0,0x70,0x38,0x1c,0xe,0x1,0xe0,0x38,0x1,
+0xf8,0xf,0x80,0xf8,0x7,0xc0,0x7c,0x3,0xe0,0x3e,
+0x1,0xf0,0x1f,0,0xf8,0xf,0x80,0xf0,0x78,0x1f,
+0x80,0xf8,0x7,0xc0,0xf8,0x7,0xc0,0xf8,0x7,0xc0,
+0xf8,0x7,0xc0,0xf8,0,0x38,0,0x38,0,0,
+0x70,0x3c,0x38,0x1f,0xe,0x7,0xc3,0x81,0xf0,0xe0,
+0x7c,0x38,0x1f,0xe,0x7,0xc3,0x81,0xf8,0xe,0xf,
+0xf,0x7,0x81,0xc1,0xe0,0x70,0x78,0x1c,0x1e,0x7,
+0x3,0x81,0xc0,0xe0,0x70,0x78,0x3c,0xe,0x1,0xc3,
+0xc1,0xe0,0x78,0x3c,0xf,0x7,0x81,0xe0,0xf0,0x3c,
+0x1e,0,0x1c,0,0x38,0x3c,0x1e,0x1f,0x83,0xc3,
+0xf0,0x78,0x7e,0xf,0xf,0xc0,0x3e,0,0xf8,0x3c,
+0x3,0xe0,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,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,0x7,0,0,0x60,0xc0,0xf,0x6f,0,0x1c,
+0xe,0x38,0x1f,0xfd,0xe0,0x1,0xc0,0x1c,0,0,
+0x1,0xc0,0x7,0,0,0x70,0xc0,0x1f,0xfc,0,
+0x38,0x7,0xff,0xf0,0x7f,0xf0,0,0x38,0xf,0xff,
+0x1,0xff,0xc0,0x38,0,0x1f,0xfc,0x7,0xfe,0,
+0xe0,0x70,0,0x7f,0,0,0x7,0xf0,0,0x1,
+0xc0,0x1e,0xf,0x9f,0xc0,0x7,0,0xe,0xf,0xff,
+0xe0,0xf,0xff,0xc0,0x3f,0xff,0x80,0x3f,0xff,0xe0,
+0xe0,0,0x3,0xff,0xf7,0x7,0,0xe,0x7,0x7,
+0xff,0x3,0x80,0xf,0x7,0xff,0xe1,0xc1,0xf0,0x70,
+0x70,0x1,0xf0,0xf,0xef,0xe0,0x1c,0,0,0x1f,
+0xdf,0xf0,0x1c,0,0x38,0x1f,0xff,0xc0,0x3,0x80,
+0x1,0xff,0xf8,0,0x3e,0,0x3,0xe0,0xf,0x80,
+0x78,0x1,0xe0,0x3,0x80,0xf,0xff,0xfc,0x70,0x3,
+0x7,0,0,0,0,0,0,0x79,0xfe,0x1f,
+0xff,0x3,0xff,0x87,0xff,0xe0,0x7f,0xf0,0x38,0x1f,
+0xff,0xe,0x1,0xc3,0x87,0x1c,0x7,0xe,0x1c,0x7,
+0x1,0xc3,0x80,0x70,0x7f,0xf0,0x3f,0xfe,0x7,0xff,
+0xc3,0x80,0x3f,0xf8,0x3c,0x1f,0xff,0x1,0xf0,0x3,
+0xe0,0xf8,0x1c,0x1c,0x3,0xe0,0x3f,0xff,0x6,0x1,
+0x80,0x60,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,0x70,0xf,0x1e,0xf,0xff,0xe0,0,
+0,0,0xe0,0x6,0,0x1f,0,0,0x7,0x1,
+0xe0,0,0,0,0,0,0,0,0,0x38,
+0xf,0,0,0,0x1,0xff,0xff,0,0,0,
+0,0xf,0xff,0xc0,0x6,0x30,0,0,0,0,
+0,0,0,0,0x60,0,0x60,0xc,0x1,0xc0,
+0,0x30,0,0x60,0x1c,0,0xe,0,0x1c,0x38,
+0,0x70,0xe0,0x1,0xc3,0x80,0x7,0xe,0,0x1c,
+0x38,0,0x71,0xe0,0x7,0xff,0xf0,0xf,0xff,0x80,
+0xff,0xff,0x83,0xff,0xfe,0xf,0xff,0xf8,0x3f,0xff,
+0xe0,0xe0,0x70,0x38,0x1c,0xf,0xff,0xe0,0x38,0,
+0xf8,0x7,0xff,0xf0,0x3,0xff,0xf8,0x1,0xff,0xfc,
+0,0xff,0xfe,0,0x7f,0xff,0x1,0xe0,0x3c,0x37,
+0xff,0xf0,0x3,0xff,0xf0,0x3,0xff,0xf0,0x3,0xff,
+0xf0,0x3,0xff,0xf0,0,0x38,0,0x38,0,0,
+0x73,0xf8,0x1e,0x7f,0x7,0x8f,0xc1,0xe3,0xf0,0x78,
+0xfc,0x1e,0x7f,0x7,0x8f,0xc3,0xe3,0xde,0x3c,0x7,
+0xfe,0x3,0xc7,0xc0,0xf1,0xf0,0x3c,0x7c,0xf,0x1f,
+0x3,0x81,0xc0,0xe0,0x70,0x3f,0xf8,0xe,0x1,0xc1,
+0xff,0xc0,0x3f,0xf8,0x7,0xff,0,0xff,0xe0,0x1f,
+0xfc,0,0x1c,0,0x7f,0xf8,0xf,0xff,0x81,0xff,
+0xf0,0x3f,0xfe,0x7,0xff,0xc0,0x3e,0,0xff,0xf8,
+0x3,0xe0,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,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,0x7,0,0,0xe1,0xc0,0xf,0xfe,0,0x18,
+0x7,0xf8,0xf,0xf8,0xf0,0x1,0xc0,0x1c,0,0,
+0x1,0xc0,0x7,0,0,0x71,0x80,0xf,0xf8,0,
+0x38,0x7,0xff,0xf0,0x3f,0xe0,0,0x38,0x7,0xfe,
+0,0xff,0x80,0x38,0,0xf,0xf8,0x7,0xfc,0,
+0xe0,0x70,0,0xf,0,0,0x7,0x80,0,0x1,
+0xc0,0xf,0,0,0,0xf,0,0xf,0xf,0xff,
+0xe0,0x3,0xff,0,0x3f,0xff,0,0x3f,0xff,0xe0,
+0xe0,0,0x1,0xff,0xc7,0x7,0,0xe,0x7,0x3,
+0xfe,0x3,0x80,0xf,0x87,0xff,0xe1,0xc0,0xe0,0x70,
+0x70,0,0xf0,0x3,0xff,0x80,0x1c,0,0,0x7,
+0xff,0x78,0x1c,0,0x38,0x7,0xff,0,0x3,0x80,
+0,0xff,0xf0,0,0x1c,0,0x1,0xc0,0x7,0,
+0x78,0x1,0xe0,0x3,0x80,0xf,0xff,0xfc,0x70,0x1,
+0x87,0,0,0,0,0,0,0x7f,0xdf,0x1d,
+0xfe,0x1,0xff,0x3,0xfe,0xe0,0x3f,0xe0,0x38,0xf,
+0xf7,0xe,0x1,0xc3,0x87,0x1c,0x7,0x8e,0x1c,0x7,
+0x1,0xc3,0x80,0x70,0x3f,0xe0,0x3b,0xfc,0x3,0xfd,
+0xc3,0x80,0x3f,0xf0,0x3f,0x1f,0xf7,0,0xe0,0x1,
+0xc0,0x70,0x38,0xe,0x1,0xc0,0x3f,0xff,0x6,0x1,
+0x80,0x60,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,0x70,0x7,0xfc,0xf,0xff,0xe0,0,
+0,0,0xe0,0x6,0,0xf,0,0,0x3,0xff,
+0x80,0,0,0,0,0,0,0,0,0x1f,
+0xfc,0,0,0,0x1,0xff,0xff,0,0,0,
+0,0xf,0xfd,0xc0,0x6,0x30,0,0,0,0,
+0,0,0,0,0xe0,0,0x60,0x1c,0x1,0xff,
+0x80,0x70,0,0x60,0x3c,0,0x1e,0,0x1e,0x78,
+0,0x79,0xe0,0x1,0xe7,0x80,0x7,0x9e,0,0x1e,
+0x78,0,0x79,0xc0,0x7,0xff,0xf0,0x7,0xfe,0,
+0xff,0xff,0x83,0xff,0xfe,0xf,0xff,0xf8,0x3f,0xff,
+0xe0,0xe0,0x70,0x38,0x1c,0xf,0xff,0xc0,0x38,0,
+0x78,0x1,0xff,0xc0,0,0xff,0xe0,0,0x7f,0xf0,
+0,0x3f,0xf8,0,0x1f,0xfc,0,0xc0,0x18,0x61,
+0xff,0xc0,0x1,0xff,0xe0,0x1,0xff,0xe0,0x1,0xff,
+0xe0,0x1,0xff,0xe0,0,0x38,0,0x38,0,0,
+0x73,0xf0,0x1f,0xf7,0xc7,0xfd,0xf1,0xff,0x7c,0x7f,
+0xdf,0x1f,0xf7,0xc7,0xfd,0xf1,0xff,0x9f,0xfc,0x3,
+0xfc,0x1,0xff,0,0x7f,0xc0,0x1f,0xf0,0x7,0xfc,
+0x3,0x81,0xc0,0xe0,0x70,0x1f,0xf0,0xe,0x1,0xc0,
+0xff,0x80,0x1f,0xf0,0x3,0xfe,0,0x7f,0xc0,0xf,
+0xf8,0,0x1c,0,0xdf,0xf0,0x7,0xfb,0x80,0xff,
+0x70,0x1f,0xee,0x3,0xfd,0xc0,0x1c,0,0xef,0xf0,
+0x1,0xc0,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,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,0x7,0,0,0xe1,0xc0,0x3,0xfc,0,0x38,
+0x3,0xe0,0x3,0xc0,0,0x1,0xc0,0x18,0,0,
+0,0,0x7,0,0,0x71,0x80,0x3,0xe0,0,
+0x38,0x7,0xff,0xf0,0xf,0x80,0,0x38,0x1,0xf0,
+0,0x3e,0,0x38,0,0x3,0xe0,0x1,0xf0,0,
+0xe0,0x70,0,0x3,0,0,0x6,0,0,0x1,
+0xc0,0x7,0x80,0,0,0xf,0,0xf,0xf,0xff,
+0x80,0,0xfc,0,0x3f,0xfc,0,0x3f,0xff,0xe0,
+0xe0,0,0,0x7f,0x7,0x7,0,0xe,0x7,0x1,
+0xf8,0x3,0x80,0x7,0xc7,0xff,0xe1,0xc0,0xe0,0x70,
+0x70,0,0xf0,0,0xfe,0,0x1c,0,0,0x1,
+0xfc,0x3c,0x1c,0,0x3c,0x1,0xfc,0,0x3,0x80,
+0,0x1f,0x80,0,0x1c,0,0x1,0xc0,0x7,0,
+0xf0,0,0xf0,0x3,0x80,0xf,0xff,0xfc,0x70,0x1,
+0x87,0,0,0,0,0,0,0x3f,0x8f,0x1c,
+0xfc,0,0x7c,0,0xfc,0xe0,0xf,0x80,0x38,0x3,
+0xc7,0xe,0x1,0xc3,0x87,0x1c,0x3,0xce,0x1c,0x7,
+0x1,0xc3,0x80,0x70,0xf,0x80,0x39,0xf8,0x1,0xf9,
+0xc3,0x80,0xf,0xc0,0x1f,0x7,0xc7,0,0xe0,0x1,
+0xc0,0x70,0x78,0xf,0x1,0xc0,0x3f,0xff,0x6,0x1,
+0x80,0x60,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,0x70,0x3,0xf8,0x6,0x7,0xc0,0,
+0,0,0xe0,0x6,0,0x7,0x80,0,0,0xfe,
+0,0,0,0,0,0,0,0,0,0x3,
+0xf0,0,0,0,0x1,0xff,0xff,0,0,0,
+0,0xf,0xf1,0xc0,0x6,0x30,0,0,0,0,
+0,0,0,0,0xc0,0,0x60,0x18,0x1,0xff,
+0x80,0x60,0,0x60,0x38,0x7,0x1e,0,0x1e,0x78,
+0,0x79,0xe0,0x1,0xe7,0x80,0x7,0x9e,0,0x1e,
+0x78,0,0x79,0xc0,0x7,0xff,0xf0,0x1,0xf8,0,
+0xff,0xff,0x83,0xff,0xfe,0xf,0xff,0xf8,0x3f,0xff,
+0xe0,0xe0,0x70,0x38,0x1c,0xf,0xff,0,0x38,0,
+0x78,0,0x7f,0,0,0x3f,0x80,0,0x1f,0xc0,
+0,0xf,0xe0,0,0x7,0xf0,0,0,0,0,
+0x7f,0,0,0x3f,0,0,0x3f,0,0,0x3f,
+0,0,0x3f,0,0,0x38,0,0x38,0,0,
+0x73,0xc0,0xf,0xe3,0xc3,0xf8,0xf0,0xfe,0x3c,0x3f,
+0x8f,0xf,0xe3,0xc3,0xf8,0xf0,0xfe,0x7,0xf0,0,
+0xf0,0,0xfe,0,0x3f,0x80,0x7,0xc0,0x1,0xf0,
+0x3,0x81,0xc0,0xe0,0x70,0x7,0xc0,0xe,0x1,0xc0,
+0x3e,0,0x7,0xc0,0,0xf8,0,0x1f,0,0x3,
+0xe0,0,0,0,0x87,0xc0,0x1,0xe0,0,0x3c,
+0,0x7,0x80,0,0xf0,0,0x1c,0,0xe3,0xc0,
+0x1,0xc0,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,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,0x60,0,0,
+0,0,0,0,0,0,0xc0,0x18,0,0,
+0,0,0x1,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,0x10,0,0,0,0,0,0,0,0,
+0,0x7,0xc0,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,0x18,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,0x70,0,
+0x7,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x7,0,0,0,0x7,0,0,0,0,0,
+0,0,0,0,0,0,0x38,0,0,0x1,
+0xc0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1,0xc0,0,0,0x6,0x1,
+0x80,0x60,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,0x70,0x2,0,0,0,0,0,
+0,0,0,0x6,0x7,0x3,0x80,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xe,0,0,0x6,0x30,0,0xc,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x38,0x7,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x60,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,0,0,0,0,0,0,0,0,0,
+0x60,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,0x1c,0,0xe0,0,
+0x1,0xc0,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,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,0x60,0,0,
+0,0,0,0,0,0,0xe0,0x38,0,0,
+0,0,0x3,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,0x30,0,0,0,0,0,0,0,0,
+0,0x3,0xe0,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,0,0,0,0x70,0,
+0x7,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x70,
+0x7,0,0,0,0x7,0,0,0,0,0,
+0,0,0,0,0,0,0x38,0,0,0x1,
+0xc0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x3,0x80,0,0,0x6,0x1,
+0x80,0x60,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,0x70,0x6,0,0,0,0,0,
+0,0,0,0x6,0x7,0x3,0x80,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xe,0,0,0x6,0x30,0,0xc,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x38,0x7,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x60,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,0,0,0,0,0,0,0,0,0,
+0x60,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,0x38,0,0xe0,0,
+0x3,0x80,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,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,0x60,0,0,
+0,0,0,0,0,0,0x60,0x30,0,0,
+0,0,0x3,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,0x30,0,0,0,0,0,0,0,0,
+0,0,0xf8,0x1e,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,0,0,0x70,0,
+0x7,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x70,
+0xe,0,0,0,0x7,0,0,0,0,0,
+0,0,0,0,0,0,0x38,0,0,0x1,
+0xc0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x3,0x80,0,0,0x6,0x1,
+0x80,0x60,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,0x70,0x4,0,0,0,0,0,
+0,0,0,0x6,0x7,0x83,0x80,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xe,0,0,0x6,0x30,0,0x1e,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x3c,0xf,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0xf0,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,0,0,0,0,0,0,0,0,0,
+0xf0,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,0x38,0,0xe0,0,
+0x3,0x80,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,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,0x60,0,0,
+0,0,0,0,0,0,0x60,0x70,0,0,
+0,0,0x6,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,0x60,0,0,0,0,0,0,0,0,
+0,0,0x7f,0xfe,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,0,0,0x70,0,
+0x7,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x78,
+0xe,0,0,0,0x7,0,0,0,0,0,
+0,0,0,0,0,0,0x38,0,0,0x1,
+0xc0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x7,0,0,0,0x6,0x1,
+0x80,0x60,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,0x70,0x4,0,0,0,0,0,
+0,0,0,0x6,0x3,0x87,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,0xe,0,0,0x6,0x30,0,0x7,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1e,0x1e,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x38,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,0,0,0,0,0,0,0,0,0,
+0x38,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,0x78,0,0xe0,0,
+0x7,0x80,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,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,0x30,0x60,0,0,
+0,0,0x4,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,0x40,0,0,0,0,0,0,0,0,
+0,0,0x1f,0xf8,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,0,0,0x70,0,
+0x7,0,0,0x3f,0xff,0xf0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3e,
+0x3c,0,0,0,0xf,0,0,0,0,0,
+0,0,0,0,0,0,0x38,0,0,0x1,
+0xc0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1f,0,0,0,0x7,0x1,
+0x80,0xe0,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,0x70,0,0,0,0,0,0,
+0,0,0,0x6,0x3,0xff,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,0xe,0,0,0x6,0x30,0,0x3,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1f,0xfc,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x18,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,0,0,0,0,0,0,0,0,0,
+0x18,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,0x1,0xf0,0,0xe0,0,
+0x1f,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,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,0x30,0x60,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,
+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,0x7e,0,
+0x3f,0,0,0x3f,0xff,0xf0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x1f,
+0xfc,0,0,0,0x3f,0,0,0,0,0,
+0,0,0,0,0,0,0x38,0,0,0x1,
+0xc0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1e,0,0,0,0x7,0xc1,
+0x83,0xe0,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,0x70,0,0,0,0,0,0,
+0,0,0,0x6,0x1,0xfe,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,0xe,0,0,0,0,0,0x67,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xf,0xf8,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0x38,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,0,0,0,0,0,0,0,0,0x3,
+0x38,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,0x1,0xf0,0,0xe0,0,
+0x1f,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,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,0x18,0xc0,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,
+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,0x7e,0,
+0x3f,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xf,
+0xf0,0,0,0,0x3e,0,0,0,0,0,
+0,0,0,0,0,0,0x38,0,0,0x1,
+0xc0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1c,0,0,0,0x3,0xc1,
+0x83,0xc0,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,0x70,0,0,0,0,0,0,
+0,0,0,0x6,0,0x78,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,0x3e,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1,0xe0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x1,0xf0,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,0,0,0,0,0,0,0,0,0x1,
+0xf0,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,0x1,0xc0,0,0,0,
+0x1c,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,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,
+};
+
+static WORD Helvetica34_ch_ofst[225] = {
+0,9,18,30,49,67,96,118,124,135,
+146,159,178,187,198,207,216,234,252,270,
+288,306,324,342,360,378,396,405,414,433,
+452,471,489,523,545,567,591,615,637,657,
+682,706,715,731,754,772,799,823,848,870,
+896,920,942,962,986,1008,1039,1061,1083,1103,
+1112,1121,1130,1146,1164,1175,1193,1211,1227,1245,
+1263,1272,1290,1308,1315,1322,1338,1345,1372,1390,
+1408,1426,1444,1455,1471,1480,1498,1514,1537,1553,
+1569,1585,1596,1605,1616,1635,1644,1653,1662,1671,
+1680,1689,1698,1707,1716,1725,1734,1743,1752,1761,
+1770,1779,1788,1797,1806,1815,1824,1833,1842,1851,
+1860,1869,1878,1887,1896,1905,1914,1923,1932,1941,
+1952,1971,1990,2008,2026,2035,2053,2064,2089,2101,
+2119,2138,2149,2174,2185,2198,2217,2228,2239,2250,
+2269,2286,2295,2306,2317,2329,2347,2375,2403,2431,
+2450,2472,2494,2516,2538,2560,2582,2614,2637,2659,
+2681,2703,2725,2734,2743,2752,2761,2784,2808,2833,
+2858,2883,2908,2933,2952,2977,3001,3025,3049,3073,
+3095,3117,3137,3155,3173,3191,3209,3227,3245,3274,
+3291,3309,3327,3345,3363,3372,3381,3390,3399,3418,
+3436,3455,3474,3493,3512,3531,3550,3569,3588,3607,
+3626,3645,3662,3681,3698,
+};
+
+static struct font_hdr Helvetica34_font = {
+STPROP, 24, "AdobeHelv-M-R-N--34-240-100-100", 32, 255,
+38, 31, 19, 7, 7,
+31, 34, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Helvetica34_ch_ofst, Helvetica34_data,
+570, 38,
+NULL,
+0, 0,   /* x/y offset */
+40,        /* lineHeight */
+29,	   /* psHeight */
+};
+
+MgFont *mgHelvetica34Font()
+{
+return &Helvetica34_font;
+}
+
+MgFont *mgHugeFont()
+{
+return &Helvetica34_font;
+}
+
diff --git a/lib/font/mgHelvetica8.c b/lib/font/mgHelvetica8.c
new file mode 100644
index 0000000..bea2d70
--- /dev/null
+++ b/lib/font/mgHelvetica8.c
@@ -0,0 +1,278 @@
+
+/* Helvetica8.c - compiled data for font AdobeHelv-M-R-N--8-80-75-75-P-4 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/helvR08.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Helvetica8_data[2211] = {
+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,0,0,0,0,0,0,0,0,
+0x10,0x10,0x82,0x80,0x20,0,0x2,0x4,0x20,0x11,
+0x40,0x1,0x48,0x8,0x41,0x40,0,0x4,0x4,0x20,
+0,0x80,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,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,0x1,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,0x8,
+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,0x8,0x21,0x45,0x14,0x50,0,0x1,0x8,0x51,
+0x4a,0xb4,0x2,0x84,0x10,0xa2,0x8a,0,0x2,0x8,
+0x51,0x41,0,0x2,0x4,0x46,0x80,0x80,0x1,0x9,
+0x4,0x50,0x49,0x48,0x12,0x14,0,0,0x82,0x40,
+0x10,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,0,0,0,0,0,0,0,
+0,0,0,0,0,0x1,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,
+0x4,0x4,0,0x40,0x40,0x85,0x44,0,0,0,
+0,0x20,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,0x20,0,0,0,
+0,0,0,0,0,0,0,0,0,0x20,
+0,0,0,0,0x1,0x8,0xab,0x29,0x40,0,
+0x92,0xaa,0xad,0x32,0x84,0x25,0x29,0x20,0,0x44,
+0xaa,0x20,0x14,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,0,0,0,0,0,
+0,0,0,0x15,0,0x9d,0x10,0x14,0,0,
+0x26,0x11,0x8c,0x23,0x9d,0xe6,0x30,0,0,0x1,
+0xf0,0x87,0x1c,0xf1,0xe7,0x9c,0x8a,0x24,0x90,0x8a,
+0x27,0x1c,0x71,0xc3,0xba,0x24,0xa4,0x92,0xc9,0xee,
+0xc0,0,0x4,0,0x40,0x80,0x80,0x44,0,0,
+0,0,0x20,0,0,0,0x16,0,0,0,
+0,0,0,0,0,0,0x1,0x6,0,0x13,
+0xc9,0xec,0,0x1,0xee,0x40,0x5d,0x7,0x83,0xc0,
+0x81,0x7,0,0x8,0x20,0x82,0x8,0x20,0xf9,0xc7,
+0x9e,0x79,0xea,0x48,0xe4,0x4e,0x38,0xe3,0x8e,0x1,
+0xe8,0xa2,0x8a,0x2c,0xa0,0x30,0,0,0,0x80,
+0,0,0,0,0x50,0,0,0,0,0x2,
+0,0,0x4,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,0,0,0,0,0,
+0,0,0,0,0x15,0x51,0xd5,0x28,0x22,0x42,
+0,0x29,0x32,0x42,0x22,0x20,0x29,0x48,0x8,0x8,
+0x62,0x8,0x84,0xa2,0x89,0x4,0x20,0x8a,0x25,0x10,
+0xdb,0x28,0x92,0x89,0x24,0x12,0x24,0xa4,0x92,0x48,
+0x2a,0x48,0,0xc7,0x19,0xc9,0xce,0xe5,0x55,0xe7,
+0x19,0xc7,0x53,0x75,0x4a,0xa9,0x4b,0xa5,0,0,
+0,0,0,0,0,0,0,0x9,0x9,0x14,
+0x54,0x2,0x12,0,0x2,0x10,0xa2,0x2e,0xd,0x7,
+0x41,0x8b,0x13,0x21,0x8,0x20,0x82,0x8,0x20,0xc2,
+0x24,0x10,0x41,0xa,0x48,0x96,0x51,0x45,0x14,0x51,
+0x2,0x28,0xa2,0x8a,0x24,0xbc,0x4b,0x18,0xc6,0x31,
+0x8d,0x19,0x11,0x12,0x92,0x3b,0x8c,0x63,0x18,0xc2,
+0x3c,0xaa,0xaa,0x97,0x24,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,0,0,0,
+0,0,0,0,0,0x15,0xfa,0x1a,0x12,0x22,
+0xe2,0,0x29,0x10,0x4c,0x63,0x38,0x46,0x4a,0x91,
+0xc4,0x14,0xc9,0x47,0x20,0x89,0xc7,0x26,0xfa,0x26,
+0x10,0xaa,0xa8,0x92,0x89,0x27,0x12,0x24,0xa4,0x8c,
+0x48,0x4a,0x54,0,0x24,0xa2,0x54,0x92,0x95,0x65,
+0x54,0xa5,0x29,0x64,0x25,0x4a,0xa9,0x48,0xa5,0x12,
+0,0,0,0,0,0,0,0,0x2,0x9c,
+0xe2,0x93,0x2,0xde,0x57,0x82,0xd0,0x4f,0x44,0x5d,
+0x3,0xd4,0x91,0x21,0x40,0x14,0x51,0x45,0x14,0x51,
+0x42,0x27,0x1c,0x71,0xca,0x49,0xd5,0x51,0x45,0x14,
+0x51,0x4a,0x68,0xa2,0x8a,0x24,0xa2,0x50,0x84,0x21,
+0x8,0x42,0xa2,0xaa,0xaa,0x92,0x4a,0x52,0x94,0xa5,
+0x20,0x48,0xaa,0xaa,0x94,0xa4,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,0,0,
+0,0,0,0,0,0,0x10,0x51,0x85,0xaa,
+0x22,0x4f,0x98,0x49,0x10,0x82,0xf0,0xa4,0x89,0x38,
+0x20,0x2,0x25,0x29,0xc4,0xa0,0x89,0x4,0x22,0x8a,
+0x27,0x10,0xaa,0xa8,0x9c,0x89,0xc0,0x92,0x24,0x9b,
+0xc,0x30,0x89,0x62,0,0xe4,0xa2,0x5c,0x92,0x95,
+0x65,0x54,0xa5,0x29,0x43,0x25,0x4a,0xa6,0x49,0x65,
+0xac,0,0,0,0,0,0,0,0,0xa,
+0x8,0xa7,0xc4,0x82,0x90,0xa0,0xb2,0xd0,0x2,0x78,
+0x5d,0x22,0xa,0xa9,0x76,0xa1,0x1c,0x71,0xc7,0x1c,
+0x71,0xf2,0x4,0x10,0x41,0xa,0x48,0x95,0x51,0x45,
+0x14,0x51,0x32,0xa8,0xa2,0x8a,0x23,0x22,0x4b,0x9c,
+0xe7,0x39,0xcf,0xa3,0xbb,0xba,0x92,0x4a,0x52,0x94,
+0xa5,0x2f,0x58,0xaa,0xaa,0x94,0xa4,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,0,
+0,0,0,0,0,0,0,0,0xf8,0x4a,
+0xac,0x22,0x2,0,0x49,0x11,0x2,0x20,0xa4,0x89,
+0x8,0x11,0xc4,0x4,0xf2,0x24,0xa2,0x89,0x4,0x22,
+0x8a,0xa4,0x90,0xaa,0x68,0x90,0x89,0x20,0x92,0x25,
+0x12,0x12,0x21,0x9,0x40,0,0xa4,0xa2,0x50,0x8e,
+0x95,0x55,0x54,0xa5,0x29,0x41,0x25,0x51,0x49,0x32,
+0x25,0,0,0,0,0,0,0,0,0,
+0xa,0x88,0xe1,0x13,0x2,0xde,0x50,0x82,0xb0,0,
+0,0x55,0x21,0xd4,0x58,0x89,0x62,0x22,0x8a,0x28,
+0xa2,0x8a,0x42,0x24,0x10,0x41,0xa,0x48,0x94,0xd1,
+0x45,0x14,0x51,0x33,0x28,0xa2,0x8a,0x22,0x3c,0x4a,
+0x94,0xa5,0x29,0x4a,0x22,0x22,0x22,0x92,0x4a,0x52,
+0x94,0xa5,0x20,0x68,0xaa,0xaa,0x64,0x98,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,
+0,0,0,0,0,0,0,0,0x10,0x53,
+0x8b,0x96,0x22,0x2,0x21,0x46,0x13,0xcc,0x23,0x18,
+0x86,0x32,0x88,0x8,0x24,0x2,0x27,0x1c,0xf1,0xe4,
+0x1c,0x8a,0x44,0x9c,0xaa,0x27,0x10,0x71,0x27,0x11,
+0xc2,0x12,0x12,0x21,0xe9,0x40,0,0xd7,0x19,0xcc,
+0x82,0x95,0x55,0x54,0x99,0xc7,0x46,0x23,0x21,0x49,
+0x23,0xa5,0,0,0,0,0,0,0,0,
+0,0x9,0x1f,0x11,0x11,0x82,0x10,0,0x2,0x10,
+0xf,0,0x75,0,0,0xbd,0x12,0xf4,0xa2,0x8a,
+0x28,0xa2,0x8a,0x79,0xc7,0x9e,0x79,0xea,0x48,0xe4,
+0x4e,0x38,0xe3,0x8e,0x4b,0xc7,0x1c,0x71,0xc2,0x20,
+0x53,0x5a,0xd6,0xb5,0xad,0x99,0x99,0x9a,0x92,0x32,
+0x4c,0x63,0x18,0xc2,0x70,0x66,0x66,0x47,0x10,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,0,0,0,0,0,0,0,0,0,
+0x1,0,0,0x14,0,0x20,0x40,0,0,0,
+0,0,0,0x80,0,0x3,0xc0,0,0,0,
+0,0,0,0,0,0,0,0,0x20,0,
+0,0,0,0,0,0xd,0xc1,0xf0,0,0,
+0,0xc,0x1,0,0,0x1,0x1,0,0,0,
+0,0x40,0x16,0,0,0,0,0,0,0,
+0,0,0x9,0,0,0x10,0x81,0xe0,0,0x1,
+0xe0,0,0,0x45,0x8,0,0x8,0x38,0x23,0,
+0,0,0,0,0x1,0,0,0,0,0,
+0,0,0,0,0,0x2,0,0,0,0,
+0,0x40,0,0,0,0,0x10,0,0,0,
+0,0,0,0,0,0x80,0,0,0x84,0x20,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x40,0,0,0,
+0,0,0,0x1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x10,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x2,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x8,0,0,0x7,0,0,0,
+0,0,0,0,0x45,0x10,0,0,0,0,
+0,0,0,0,0,0x2,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x20,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,
+};
+
+static WORD Helvetica8_ch_ofst[225] = {
+0,2,4,8,13,18,25,31,33,36,
+39,43,49,51,54,56,59,64,69,74,
+79,84,89,94,99,104,109,111,113,118,
+122,127,132,141,147,153,159,165,171,177,
+183,189,191,195,201,206,213,219,225,231,
+237,243,249,253,259,265,273,279,285,291,
+294,296,298,303,308,311,316,321,325,330,
+334,338,343,348,350,352,356,358,364,369,
+374,379,384,388,392,396,400,405,411,416,
+421,425,428,430,433,439,441,443,445,447,
+449,451,453,455,457,459,461,463,465,467,
+469,471,473,475,477,479,481,483,485,487,
+489,491,493,495,497,499,501,503,505,507,
+509,514,519,524,530,532,537,541,548,551,
+556,562,565,572,575,579,584,587,590,592,
+596,601,603,605,607,610,615,622,629,636,
+641,647,653,659,665,671,677,685,691,697,
+703,709,715,717,720,723,726,732,738,744,
+750,756,762,768,773,779,785,791,797,803,
+809,815,821,826,831,836,841,846,851,857,
+861,865,869,873,877,879,882,885,888,893,
+898,903,908,913,918,923,928,935,939,943,
+947,951,956,961,966,
+};
+
+static struct font_hdr Helvetica8_font = {
+STPROP, 8, "AdobeHelv-M-R-N--8-80-75-75-P-4", 32, 255,
+11, 9, 5, 2, 2,
+9, 9, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Helvetica8_ch_ofst, Helvetica8_data,
+201, 11,
+NULL,
+0, 0,   /* x/y offset */
+11,        /* lineHeight */
+9,	   /* psHeight */
+};
+
+MgFont *mgHelvetica8Font()
+{
+return &Helvetica8_font;
+}
diff --git a/lib/font/mgHelveticaBold10.c b/lib/font/mgHelveticaBold10.c
new file mode 100644
index 0000000..d4bcde2
--- /dev/null
+++ b/lib/font/mgHelveticaBold10.c
@@ -0,0 +1,345 @@
+
+/* HelveticaBold10.c - compiled data for font AdobeHelv-B-R-N--10-100-75-75-P */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/helvB10.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE HelveticaBold10_data[2821] = {
+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,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,0x20,0x8,0x10,0x14,0,0x10,
+0,0,0x10,0x10,0x80,0x22,0x40,0,0xa1,0,
+0x20,0x80,0xa0,0,0,0x4,0x2,0x8,0,0x8,
+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,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,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,0x10,0x10,0x28,0x28,0x28,0x28,0,0,0x8,
+0x21,0x45,0x14,0xb4,0x1,0x40,0x80,0x41,0x41,0x41,
+0x40,0,0x2,0x4,0x14,0x28,0x10,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,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,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,0x8,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x10,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x2,0x1,0x18,0x52,0x84,
+0,0,0x80,0x84,0x29,0x4,0xaa,0x14,0x80,0x84,
+0x28,0xa0,0,0x20,0x21,0xa,0x8,0x2,0x80,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,0xc,0xa0,0x8,0x62,0x70,0x45,0x14,0,0,
+0x17,0xc,0x71,0xc1,0xbe,0x73,0xe7,0x1c,0,0,
+0x1,0xc0,0,0x71,0xf0,0xf3,0xc7,0xdf,0x1e,0x66,
+0xc3,0x66,0xc3,0x6,0xc6,0x38,0xf8,0x71,0xf1,0xe7,
+0xec,0xd8,0xd9,0x9b,0x1b,0xd,0xfb,0xa3,0x88,0x4,
+0x3,0,0xc,0x3,0x81,0x86,0xd8,0x60,0,0,
+0,0,0x1,0x80,0,0,0,0,0xc,0xb0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1,0xc0,0x42,0x4e,0x51,0xe1,
+0xc0,0,0,0x78,0xe0,0,0x10,0x7,0xc0,0xe,
+0,0x84,0x42,0x71,0,0x38,0x38,0x38,0x38,0x38,
+0x38,0x3f,0x8f,0x3e,0xfb,0xef,0xb6,0xdb,0xc6,0x31,
+0xc1,0xc1,0xc1,0xc1,0xc0,0x7,0x59,0xb3,0x66,0xcd,
+0x86,0xc0,0xe1,0x2,0x34,0xa2,0x8a,0,0,0x41,
+0xa,0x28,0x9a,0xac,0x28,0x41,0xa,0x50,0xa0,0,
+0x10,0x42,0x8a,0x11,0x82,0x80,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,0xc,0xa5,
+0x1c,0xb4,0xd8,0x4d,0x88,0,0,0x1d,0xbc,0xdb,
+0x63,0xb0,0xd8,0x6d,0xb6,0,0,0x3,0x61,0xf0,
+0x71,0x99,0x9b,0x66,0x18,0x33,0x66,0xc3,0x6c,0xc3,
+0x8e,0xe6,0x6c,0xcc,0xd9,0x9b,0x31,0x8c,0xd8,0xd9,
+0x9b,0x1b,0xc,0x1b,0x21,0x9c,0x2,0x3,0,0xc,
+0x6,0x1,0x80,0x18,0x60,0,0,0,0,0x1,
+0x80,0,0,0,0,0x18,0x98,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x23,0x5b,0x66,0x59,0x2,0x10,0x40,0,0,
+0x84,0x6,0x63,0xe0,0xe,0x80,0x4a,0x1,0x88,0xc4,
+0x22,0,0x38,0x38,0x38,0x38,0x38,0x38,0x3c,0x19,
+0xb0,0xc3,0xc,0x36,0xdb,0x66,0x33,0x63,0x63,0x63,
+0x63,0x60,0xd,0x99,0xb3,0x66,0xcd,0x86,0xf9,0x90,
+0,0,0,0x4,0,0,0,0,0,0,
+0x14,0,0,0,0,0,0,0,0,0,
+0x1,0x80,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,0xc,0xa5,0x2a,0x68,0xd8,
+0x48,0x94,0x60,0,0x2d,0x8c,0x18,0x65,0xb0,0xc0,
+0x6d,0xb6,0x48,0xc0,0x60,0x66,0x8,0xd9,0x9b,0xb,
+0x36,0x18,0x61,0x66,0xc3,0x78,0xc3,0x8e,0xe6,0xc6,
+0xcd,0x8d,0x9b,0x81,0x8c,0xcd,0x99,0x99,0xb1,0x98,
+0x33,0x11,0xb6,0,0x73,0xc7,0x3c,0xe7,0x35,0xe6,
+0xdb,0x6b,0x65,0x8e,0x58,0xd5,0xb9,0xdb,0x6d,0xad,
+0x9b,0x6f,0x98,0x98,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xc,0xe3,0xe,
+0x24,0x5c,0x4,0xc9,0x40,0,0x1,0x7a,0xa,0x65,
+0x43,0x6e,0x80,0xce,0,0x90,0x48,0x14,0xc,0x6c,
+0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x30,0xb0,0xc3,0xc,
+0x36,0xdb,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x79,
+0xd9,0xb3,0x66,0xcc,0xcc,0xcd,0x93,0x8e,0x38,0xe3,
+0x8e,0x3f,0x1c,0xe3,0x8e,0x39,0xb6,0xce,0x58,0xe3,
+0x8e,0x38,0xe1,0x8e,0xed,0xb6,0xdb,0x6d,0xe6,0xc0,
+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,0xc,0xf,0xf8,0x10,0x70,0x18,0xc0,0x60,
+0,0x2d,0x8c,0x18,0xc5,0xbc,0xf0,0xc7,0x36,0x49,
+0x9f,0x30,0xc4,0xd4,0xd9,0xf3,0x3,0x37,0xde,0x60,
+0x7e,0xc3,0x70,0xc3,0xde,0xd6,0xc6,0xcd,0x8d,0x99,
+0xe1,0x8c,0xcd,0x8d,0xb0,0xe1,0x98,0x63,0x11,0xa2,
+0,0x9b,0x6d,0x6d,0xb6,0x6d,0xb6,0xde,0x6d,0xb6,
+0xdb,0x6d,0xb7,0x6d,0x9b,0x6d,0xac,0xf3,0x61,0x98,
+0x98,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1,0xb7,0x9b,0x3c,0x4e,0x5,
+0x28,0,0x1f,0x1,0x4a,0xd,0xfa,0x23,0x6e,0x80,
+0x40,0,0x90,0x48,0x64,0,0x6c,0x6c,0x6c,0x6c,
+0x6c,0x6c,0x6f,0xb0,0x3e,0xfb,0xef,0xb6,0xdb,0xb6,
+0xb6,0x36,0x36,0x36,0x36,0x33,0xda,0xd9,0xb3,0x66,
+0xcc,0xcc,0xcd,0xa4,0xd3,0x4d,0x34,0xd3,0x4d,0xb5,
+0xb6,0xdb,0x6d,0xb6,0xdb,0x6d,0xb6,0xdb,0x6d,0xb0,
+0x1b,0x6d,0xb6,0xdb,0x6d,0xb6,0xc0,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,0x8,
+0x5,0x1c,0x10,0xde,0x18,0xc1,0xf8,0xf0,0x4d,0x8c,
+0x30,0x69,0x86,0xd8,0xcd,0x9e,0x3,0,0x19,0x89,
+0x24,0xd9,0x9b,0x3,0x36,0x18,0x67,0x66,0xc3,0x78,
+0xc3,0x56,0xd6,0xc6,0xf9,0x8d,0xf0,0x71,0x8c,0xcd,
+0x8d,0xb0,0xe0,0xf0,0xe3,0x9,0x80,0,0x7b,0x2c,
+0x4d,0xf6,0x4d,0xb6,0xdc,0x6d,0xb6,0xdb,0x65,0x36,
+0x39,0x9b,0x6d,0xac,0x63,0x63,0x30,0x8c,0xd8,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x5,0x43,0x1b,0x7e,0x13,0x5,0x9,0xcd,0x81,
+0x79,0x72,0,0x67,0xc3,0x66,0xb0,0x4e,0xd8,0x24,
+0x16,0x9,0xc,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,
+0x30,0x30,0xc3,0xc,0x36,0xdb,0x36,0xb6,0x36,0x36,
+0x36,0x36,0x31,0x9a,0xd9,0xb3,0x66,0xcc,0x78,0xcd,
+0x93,0xcf,0x3c,0xf3,0xcf,0x3f,0xb1,0xf7,0xdf,0x7d,
+0xb6,0xdb,0x6d,0xb6,0xdb,0x6d,0xb7,0xff,0x6d,0xb6,
+0xdb,0x6d,0x96,0xc0,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,0x8,0xf,0x8e,0x2c,
+0xcc,0x18,0xc0,0x60,0,0x4d,0x8c,0x60,0x6f,0xe6,
+0xd8,0xcd,0x86,0x1,0x9f,0x31,0x8a,0x25,0xfd,0x9b,
+0xb,0x36,0x18,0x63,0x66,0xc3,0x6c,0xc3,0x76,0xce,
+0xc6,0xc1,0xad,0x9a,0x31,0x8c,0xc7,0xf,0xf1,0xb0,
+0x60,0xc3,0x9,0x80,0,0xdb,0x2c,0x4d,0x86,0x4d,
+0xb6,0xde,0x6d,0xb6,0xdb,0x65,0x36,0xd,0x9b,0x28,
+0xd8,0xf3,0x66,0x18,0x99,0xb0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x5,0x43,
+0xe,0x18,0x19,0x4,0xe8,0x1b,0x1,0x1,0x4a,0,
+0x60,0x3,0x62,0x80,0,0x6c,0x4c,0x2a,0x13,0xc,
+0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfc,0x30,0xb0,0xc3,
+0xc,0x36,0xdb,0x36,0x76,0x36,0x36,0x36,0x36,0x33,
+0xdc,0xd9,0xb3,0x66,0xcc,0x30,0xf9,0x96,0xdb,0x6d,
+0xb6,0xdb,0x6c,0x31,0x86,0x18,0x61,0xb6,0xdb,0x6d,
+0xb6,0xdb,0x6d,0xb0,0x1b,0x6d,0xb6,0xdb,0x6d,0x96,
+0xc0,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,0xa,0x2a,0x56,0xdc,0x18,0xc0,
+0x62,0x2,0x8d,0x8c,0xc3,0x61,0xb6,0xd9,0x8d,0xb6,
+0x48,0xc0,0x60,0xa,0x49,0x8d,0x99,0x9b,0x66,0x18,
+0x33,0x66,0xdb,0x66,0xc3,0x26,0xce,0x6c,0xc0,0xd9,
+0x9b,0x31,0x8c,0xc7,0x6,0x63,0x18,0x61,0x83,0x5,
+0x80,0,0xdb,0x6d,0x6d,0xb6,0x6d,0xb6,0xdb,0x6d,
+0xb6,0xdb,0x6d,0xb6,0x6d,0x9b,0x38,0xd9,0x99,0xec,
+0x18,0x98,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xd,0xb3,0x5b,0x7e,0x4e,
+0x2,0x10,0xd,0x80,0,0x84,0,0,0x3,0x62,
+0x80,0,0xd8,0x5e,0x24,0x17,0x98,0xc6,0xc6,0xc6,
+0xc6,0xc6,0xc6,0xcc,0x19,0xb0,0xc3,0xc,0x36,0xdb,
+0x66,0x73,0x63,0x63,0x63,0x63,0x66,0x6d,0x99,0xb3,
+0x66,0xcc,0x30,0xc1,0x96,0xdb,0x6d,0xb6,0xdb,0x6d,
+0xb5,0xb6,0xdb,0x6d,0xb6,0xdb,0x6d,0xb6,0xdb,0x6d,
+0xb1,0x9b,0x6d,0xb6,0xdb,0x3d,0xb3,0xc0,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,
+0xc,0xa,0x1c,0x8c,0x76,0x8,0x80,0x2,0x2,0x87,
+0xc,0xf9,0xc1,0x9c,0x71,0x87,0x1c,0x48,0,0x1,
+0x89,0xb1,0x8d,0xf0,0xf3,0xc7,0xd8,0x1d,0x66,0xce,
+0x63,0xfb,0x26,0xc6,0x38,0xc0,0x79,0x99,0xe1,0x87,
+0x82,0x4,0x23,0x18,0x61,0xfb,0x5,0x80,0,0x6f,
+0xc7,0x3c,0xe6,0x3d,0xb6,0xd9,0xed,0xb6,0xce,0x78,
+0xf6,0x38,0xcd,0x10,0xd9,0x98,0xcf,0x98,0x98,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0xc,0xe6,0xc0,0x18,0x47,0x1,0xe0,0,
+0,0,0x78,0x1,0xf8,0x3,0xa2,0x80,0,0,
+0x84,0x4e,0x21,0x30,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,
+0xcf,0x8f,0x3e,0xfb,0xef,0xb6,0xdb,0xc6,0x31,0xc1,
+0xc1,0xc1,0xc1,0xc0,0x17,0xf,0x1e,0x3c,0x78,0x30,
+0xc1,0xa3,0x6d,0xb6,0xdb,0x6d,0xb7,0x1c,0xe3,0x8e,
+0x39,0xb6,0xce,0x6c,0xe3,0x8e,0x38,0xe0,0xe,0x34,
+0xd3,0x4d,0x19,0xe1,0x80,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,0x8,
+0,0,0xd,0x80,0x2,0,0,0,0,0,
+0,0,0,0,0x8,0,0,0x4,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x4,0,0,0,0,0,0,
+0,0,0x3,0x1,0x80,0,0,0,0,0,
+0xc,0,0xc0,0,0,0,0x60,0x30,0,0,
+0,0,0,0xc0,0x18,0x98,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xc,
+0x80,0,0,0x53,0,0,0,0,0,0,
+0,0,0x3,0x2,0x82,0,0,0,0,0,
+0x36,0,0,0,0,0,0,0,0x4,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,0x8,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x19,
+0x81,0x80,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,0x5,
+0,0x4,0,0,0,0,0,0,0,0,
+0,0x10,0,0,0x3,0xe0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3,
+0x83,0x81,0xf8,0,0,0,0,0x38,0,0x80,
+0,0,0,0x60,0x30,0,0,0,0,0x1,
+0x80,0xc,0xb0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xc,0,0,0,
+0x4e,0,0,0,0,0,0,0,0,0x3,
+0x2,0x86,0,0,0,0,0,0x1c,0,0,
+0,0,0,0,0,0xc,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,0x18,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x31,0x83,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,
+};
+
+static WORD HelveticaBold10_ch_ofst[225] = {
+0,3,7,12,18,24,32,40,43,47,
+51,55,61,64,69,72,76,82,88,94,
+100,106,112,118,124,130,136,139,142,147,
+153,158,164,175,183,190,198,205,211,217,
+225,232,235,241,248,254,264,272,280,287,
+295,302,309,316,323,331,342,350,359,366,
+370,374,378,383,389,392,398,404,409,415,
+421,425,431,437,440,443,449,452,461,467,
+473,479,485,489,495,499,505,511,519,526,
+532,538,543,546,551,557,560,563,566,569,
+572,575,578,581,584,587,590,593,596,599,
+602,605,608,611,614,617,620,623,626,629,
+632,635,638,641,644,647,650,653,656,659,
+663,669,675,681,688,691,697,700,710,715,
+722,729,734,744,747,751,757,760,763,766,
+772,778,781,784,787,792,799,808,817,826,
+832,840,848,856,864,872,880,890,898,904,
+910,916,922,925,928,931,934,941,949,957,
+965,973,981,989,995,1003,1010,1017,1024,1031,
+1040,1047,1053,1059,1065,1071,1077,1083,1089,1098,
+1103,1109,1115,1121,1127,1130,1133,1136,1139,1145,
+1151,1157,1163,1169,1175,1181,1187,1193,1199,1205,
+1211,1217,1223,1229,1235,
+};
+
+static struct font_hdr HelveticaBold10_font = {
+STPROP, 10, "AdobeHelv-B-R-N--10-100-75-75-P", 32, 255,
+13, 11, 6, 2, 2,
+11, 11, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+HelveticaBold10_ch_ofst, HelveticaBold10_data,
+217, 13,
+NULL,
+0, 0,   /* x/y offset */
+13,        /* lineHeight */
+9,	   /* psHeight */
+};
+
+MgFont *mgHelveticaBold10Font()
+{
+return &HelveticaBold10_font;
+}
+
+MgFont *mgSmallBoldFont()
+{
+return &HelveticaBold10_font;
+}
+
diff --git a/lib/font/mgHelveticaBold12.c b/lib/font/mgHelveticaBold12.c
new file mode 100644
index 0000000..70462bd
--- /dev/null
+++ b/lib/font/mgHelveticaBold12.c
@@ -0,0 +1,424 @@
+
+/* HelveticaBold12.c - compiled data for font AdobeHelv-B-R-N--12-120-75-75-P */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/helvB12.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE HelveticaBold12_data[3675] = {
+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,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,0x6,0x1,0x83,0x83,0x40,0x3,
+0,0,0,0x30,0xc,0x1c,0,0xc3,0x70,0,
+0x3,0x41,0x80,0x18,0xe,0x3,0x40,0,0,0,
+0x30,0x6,0xe,0,0x1,0x80,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,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,
+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,0x3,
+0x3,0x6,0xc5,0x86,0xc4,0x80,0,0,0x18,0x18,
+0x36,0x36,0x66,0xde,0xc0,0x5,0x80,0xc0,0x30,0x1b,
+0x5,0x83,0x30,0,0,0x18,0xc,0x1b,0xd,0x83,
+0,0,0,0,0,0,0,0xc0,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,
+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,0x30,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,0x30,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3,
+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,0x6,0x6,0x1c,
+0x34,0x1,0x20,0,0,0xc0,0x61,0xc0,0x31,0x70,
+0x6c,0x34,0xc0,0x61,0xc3,0x40,0,0,0x60,0x30,
+0xe0,0,0xc0,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,0x6,0x50,0,0x87,0x10,
+0x38,0x21,0x98,0x20,0,0,0xd,0xe1,0x87,0x8f,
+0x3,0x3e,0x79,0xf9,0xe3,0xc0,0,0,0,0x1e,
+0x7,0xc0,0xc3,0xf0,0x79,0xf0,0xfc,0xfc,0x7c,0x63,
+0x30,0x66,0x33,0x6,0xc,0xc6,0x1e,0x1f,0x87,0x87,
+0xe1,0xf3,0xfd,0x8d,0x87,0x99,0xe1,0xe1,0xff,0x7c,
+0xe1,0,0x18,0x6,0,0x1,0x80,0x1c,0x6,0xd,
+0xb0,0x60,0,0,0,0,0,0,0xc0,0,
+0,0,0,0,0x6,0x6c,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x7,0,0x66,0x67,0x9b,
+0x1f,0xe,0,0,0,0x7c,0x78,0,0x33,0x60,
+0x3,0xe0,0xc,0x60,0x3,0x18,0xc6,0x31,0x80,0x3,
+0x3,0x3,0x3,0x3,0x3,0x1,0xfe,0x1e,0x7e,0x7e,
+0x7e,0x7e,0x66,0x63,0x1f,0xc,0x61,0xe0,0x78,0x1e,
+0x7,0x81,0xe0,0,0xf4,0xc6,0x63,0x31,0x98,0xd8,
+0x6c,0x7,0x83,0xc,0x36,0x58,0xd8,0xc0,0,0,
+0x60,0xc3,0x66,0xdb,0xdd,0xb8,0x58,0x60,0xc3,0x65,
+0x8d,0x80,0,0x30,0x61,0xb3,0x61,0x8c,0xd,0x80,
+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,
+0x6,0x50,0xa3,0xcd,0xb0,0x6c,0x23,0xc,0xf8,0,
+0,0xf,0x37,0x8c,0xd9,0x87,0x30,0xcc,0x1b,0x36,
+0x60,0,0,0,0x33,0x18,0x21,0xe3,0x18,0xcd,
+0x98,0xc0,0xc0,0xc6,0x63,0x30,0x66,0x63,0x6,0xc,
+0xe6,0x33,0x18,0xcc,0xc6,0x33,0x18,0x61,0x8d,0x87,
+0x99,0xe1,0xe1,0x83,0x6c,0x63,0x80,0,0x6,0,
+0x1,0x80,0x30,0x6,0,0x30,0x60,0,0,0,
+0,0,0,0xc0,0,0,0,0,0,0xc,
+0x66,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x1,
+0xd,0x80,0x66,0x6c,0xc0,0x20,0x83,0,0,0,
+0x82,0x3,0,0x5d,0x80,0x7,0x40,0x1c,0xd0,0x7,
+0x31,0xcc,0x59,0x80,0x3,0x3,0x3,0x3,0x3,0x3,
+0x3,0x60,0x33,0x60,0x60,0x60,0x60,0x66,0x63,0x19,
+0x8c,0x63,0x30,0xcc,0x33,0xc,0xc3,0x30,0x1,0x98,
+0xc6,0x63,0x31,0x98,0xd8,0x6c,0xc,0xc0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x48,0,0,0,0,0,0,0,0,0,
+0,0,0xc,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,0x6,0x50,0xa6,0xad,0xa0,
+0x6c,0x23,0xc,0x70,0,0,0xb,0x31,0x80,0xc1,
+0x8b,0x60,0xc0,0x33,0x36,0x66,0x60,0,0,0x33,
+0x10,0x11,0x23,0x19,0x81,0x8c,0xc0,0xc1,0x80,0x63,
+0x30,0x66,0xc3,0x7,0x1c,0xe6,0x61,0x98,0xd8,0x66,
+0x33,0x18,0x61,0x8c,0xcd,0x99,0xb3,0x33,0x6,0x64,
+0x66,0xc0,0x1,0xe6,0xc7,0x8d,0x9e,0x79,0xb6,0xcd,
+0xb3,0x6b,0xb9,0xb1,0xe6,0xc7,0x5b,0x79,0xec,0xd8,
+0xd9,0x9b,0x36,0x37,0xcc,0x66,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x67,0x8c,0x33,0x24,0x6e,0,
+0x4e,0x4f,0,0,0x1,0x39,0x4,0x8c,0x33,0x6,
+0x6f,0x40,0xc,0xd0,0x3,0x30,0xcc,0x33,0x3,0x7,
+0x87,0x87,0x87,0x87,0x87,0x82,0x60,0x60,0x60,0x60,
+0x60,0x60,0x66,0x63,0x18,0xce,0x66,0x19,0x86,0x61,
+0x98,0x66,0x18,0x3,0x3c,0xc6,0x63,0x31,0x98,0xcc,
+0xcf,0xcc,0xcf,0x1e,0x3c,0x78,0xf1,0xe3,0xbc,0x78,
+0xf1,0xe3,0xc7,0x9b,0x66,0xc,0xd8,0xf1,0xe3,0xc7,
+0x8f,0,0x3d,0xcd,0x9b,0x36,0x6c,0x6d,0x98,0xc0,
+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,
+0x6,0x3,0xf6,0x87,0x40,0x38,0x6,0x6,0x50,0xc0,
+0,0x1b,0x31,0x81,0x87,0xb,0x7c,0xc0,0x31,0xe6,
+0x66,0x60,0xc0,0x18,0x6,0x23,0x53,0x33,0x19,0x81,
+0x8c,0xc0,0xc1,0x80,0x63,0x30,0x67,0x83,0x7,0x1c,
+0xd6,0x61,0x98,0xd8,0x66,0x31,0xc0,0x61,0x8c,0xcc,
+0x99,0x1e,0x33,0xc,0x66,0x6c,0x60,0x3,0x37,0x6c,
+0xdb,0xb3,0x33,0x77,0x6d,0xb6,0x6c,0xcd,0xdb,0x37,
+0x6d,0xdf,0xcc,0xcc,0xd8,0xd9,0x9b,0x36,0x30,0xcc,
+0x66,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x6d,
+0xcc,0x1e,0x7e,0x67,0,0x51,0x4b,0x9,0x3f,0x1,
+0x29,0x4,0x8c,0x61,0x86,0x6f,0x40,0xc,0x62,0x43,
+0x60,0xd8,0x1b,0x3,0x4,0x84,0x84,0x84,0x84,0x84,
+0x86,0x60,0x60,0x60,0x60,0x60,0x60,0x66,0x63,0x18,
+0xce,0x66,0x19,0x86,0x61,0x98,0x66,0x1b,0x33,0x2c,
+0xc6,0x63,0x31,0x98,0xcc,0xcc,0x6c,0xd9,0xb3,0x66,
+0xcd,0x9b,0x36,0x66,0xcd,0x9b,0x36,0x6c,0xdb,0x66,
+0x3e,0xed,0x9b,0x36,0x6c,0xd9,0x8c,0x66,0xcd,0x9b,
+0x36,0x6c,0x6e,0xd8,0xc0,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,0x6,0x1,0x43,0xc0,0x40,
+0x79,0x6,0x6,0,0xc0,0,0x1b,0x31,0x83,0x1,
+0x93,0x6,0xf8,0x63,0x33,0xe0,0x3,0x9f,0x8e,0xc,
+0x24,0x93,0x33,0xf1,0x81,0x8c,0xfc,0xf9,0x9e,0x7f,
+0x30,0x67,0x83,0x7,0xbc,0xd6,0x61,0x9f,0x98,0x67,
+0xe0,0x70,0x61,0x8c,0xcc,0xdb,0xc,0x1e,0x18,0x66,
+0x60,0,0,0x36,0x6c,0x19,0xb3,0x33,0x36,0x6d,
+0xbc,0x6c,0xcd,0x9b,0x36,0x6c,0xdc,0xe0,0xcc,0xcd,
+0x8d,0xb1,0xe3,0x61,0x8c,0x66,0x3b,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x9,0x1f,0x12,0x18,0xd,0x80,
+0x50,0x40,0x1b,0x1,0x1,0x31,0x3,0x3f,0x7f,0x6,
+0x6f,0x4c,0xc,0x3,0x63,0x6c,0xdb,0x76,0xc0,0xc,
+0xcc,0xcc,0xcc,0xcc,0xcc,0xc6,0x7e,0x60,0x7e,0x7e,
+0x7e,0x7e,0x66,0x63,0x3c,0xcf,0x66,0x19,0x86,0x61,
+0x98,0x66,0x19,0xe3,0x6c,0xc6,0x63,0x31,0x98,0xc4,
+0x8c,0x6d,0x81,0x83,0x6,0xc,0x18,0x30,0x66,0xc1,
+0x9b,0x36,0x6c,0xdb,0x66,0x66,0xcd,0x9b,0x36,0x6c,
+0xd9,0x80,0x6e,0xcd,0x9b,0x36,0x66,0xcc,0xcd,0x80,
+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,
+0x4,0x1,0x40,0xe0,0x9c,0xcf,0x6,0x6,0x3,0xf0,
+0x78,0x13,0x31,0x86,0x1,0xa3,0x6,0xcc,0x63,0x30,
+0x60,0x6,0,0x3,0xc,0x28,0x93,0xf3,0x19,0x81,
+0x8c,0xc0,0xc1,0x86,0x63,0x30,0x66,0xc3,0x6,0xac,
+0xce,0x61,0x98,0x19,0x66,0x60,0x38,0x61,0x8c,0x48,
+0xdb,0x1e,0xc,0x18,0x62,0x60,0,0x1,0xf6,0x6c,
+0x19,0xbf,0x33,0x36,0x6d,0xbc,0x6c,0xcd,0x9b,0x36,
+0x6c,0xd8,0x38,0xcc,0xcd,0x8d,0xb0,0xc3,0x61,0x18,
+0x63,0x6e,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x2a,
+0xc,0x12,0x7e,0xc,0xc0,0x51,0x4f,0x36,0x1,0x79,
+0x29,0,0xc,0,0x6,0x67,0x4c,0,0xf1,0xb0,
+0x5c,0x15,0x85,0xc3,0xf,0xcf,0xcf,0xcf,0xcf,0xcf,
+0xc7,0xe0,0x60,0x60,0x60,0x60,0x60,0x66,0x63,0x18,
+0xcc,0xe6,0x19,0x86,0x61,0x98,0x66,0x18,0xc3,0x4c,
+0xc6,0x63,0x31,0x98,0xc7,0x8c,0x6c,0xcf,0x9f,0x3e,
+0x7c,0xf9,0xf3,0xfe,0xc1,0xfb,0xf7,0xef,0xdb,0x66,
+0x66,0xcd,0x9b,0x36,0x6c,0xd9,0xbf,0x76,0xcd,0x9b,
+0x36,0x66,0xcc,0xcd,0x80,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,0x7,0xe4,0xa0,0xb6,
+0xc6,0x6,0x6,0,0xc0,0,0x13,0x31,0x8c,0x1,
+0xbf,0xe6,0xcc,0x63,0x30,0x60,0x3,0x9f,0x8e,0,
+0x29,0xa6,0x1b,0x19,0x81,0x8c,0xc0,0xc1,0x86,0x63,
+0x36,0x66,0x63,0x6,0xec,0xce,0x61,0x98,0x19,0xe6,
+0x33,0x18,0x61,0x8c,0x78,0x66,0x33,0xc,0x30,0x62,
+0x60,0,0x3,0x36,0x6c,0x19,0xb0,0x33,0x36,0x6d,
+0xb6,0x6c,0xcd,0x9b,0x36,0x6c,0xd8,0x1c,0xcc,0xc7,
+0xd,0xb1,0xe1,0xc3,0xc,0x66,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x6a,0xc,0x1e,0x18,0x6c,0xc0,
+0x4e,0x40,0x1b,0x1,0x1,0x29,0,0xc,0,0x6,
+0x63,0x40,0,0x3,0x60,0xd4,0x33,0xd,0x43,0x18,
+0x78,0x78,0x78,0x78,0x78,0x6c,0x60,0x60,0x60,0x60,
+0x60,0x60,0x66,0x63,0x18,0xcc,0xe6,0x19,0x86,0x61,
+0x98,0x66,0x19,0xe3,0xcc,0xc6,0x63,0x31,0x98,0xc3,
+0xf,0xcc,0xd9,0xb3,0x66,0xcd,0x9b,0x36,0x60,0xc1,
+0x83,0x6,0xc,0x1b,0x66,0x66,0xcd,0x9b,0x36,0x6c,
+0xd9,0x80,0x66,0xcd,0x9b,0x36,0x63,0x8c,0xc7,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,
+0x6,0x2,0x86,0xa1,0xb6,0xcf,0x6,0x6,0,0xc3,
+0x1,0xb3,0x31,0x8c,0x19,0x83,0x66,0xcc,0xc3,0x36,
+0x66,0x60,0xc0,0x18,0xc,0x26,0xc6,0x1b,0x18,0xcd,
+0x98,0xc0,0xc0,0xc6,0x63,0x36,0x66,0x33,0x6,0x4c,
+0xc6,0x33,0x18,0xc,0xc6,0x33,0x18,0x60,0xd8,0x30,
+0x66,0x61,0x8c,0x60,0x63,0x60,0,0x3,0x37,0x6c,
+0xdb,0xb3,0x33,0x76,0x6d,0xb3,0x6c,0xcd,0x9b,0x37,
+0x6d,0xd8,0xcc,0xdd,0xc7,0x6,0x63,0x31,0xc6,0xc,
+0x66,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x6e,
+0xdd,0xb3,0x18,0x66,0xc0,0x20,0x80,0x9,0,0,
+0x82,0,0,0,0x6,0xe1,0x40,0,0x2,0x41,
+0xbe,0x66,0x1b,0xe3,0x18,0x78,0x78,0x78,0x78,0x78,
+0x6c,0x60,0x33,0x60,0x60,0x60,0x60,0x66,0x63,0x19,
+0x8c,0x63,0x30,0xcc,0x33,0xc,0xc3,0x33,0x31,0x98,
+0x6c,0x36,0x1b,0xd,0x83,0xc,0xc,0xd9,0xb3,0x66,
+0xcd,0x9b,0x36,0x66,0xcd,0x9b,0x36,0x6c,0xdb,0x66,
+0x66,0xcd,0x9b,0x36,0x6c,0xd9,0x8c,0x66,0xdd,0xbb,
+0x76,0xe3,0x8e,0xc7,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,0x6,0x2,0x83,0xc1,0x1c,
+0x79,0x86,0x6,0,0x3,0x1,0xb1,0xe1,0x8f,0xcf,
+0x3,0x3c,0x78,0xc1,0xe3,0xc6,0x60,0,0,0xc,
+0x10,0x6,0x1b,0xf0,0x79,0xf0,0xfc,0xc0,0x7a,0x63,
+0x33,0xc6,0x1b,0xf6,0x4c,0xc6,0x1e,0x18,0x7,0xe6,
+0x31,0xf0,0x60,0xf8,0x30,0x66,0x61,0x8c,0x7f,0x63,
+0x60,0,0x1,0xde,0xc7,0x8d,0x9e,0x31,0xb6,0x6d,
+0xb1,0xec,0xcd,0x99,0xe6,0xc6,0xd8,0x78,0x66,0xc2,
+0x6,0x63,0x30,0xc7,0xcc,0x66,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x67,0x9b,0,0x18,0x63,0x80,
+0x1f,0,0,0,0,0x7c,0,0x3f,0,0x7,
+0x61,0x40,0xc0,0,0x1,0x8c,0x67,0x98,0xc6,0x18,
+0x78,0x78,0x78,0x78,0x78,0x6c,0x7e,0x1e,0x7e,0x7e,
+0x7e,0x7e,0x66,0x63,0x1f,0xc,0x61,0xe0,0x78,0x1e,
+0x7,0x81,0xe0,0x1,0xf0,0x7c,0x3e,0x1f,0xf,0x83,
+0xc,0xd,0x8e,0xdd,0xbb,0x76,0xed,0xdb,0xbc,0x78,
+0xf1,0xe3,0xc7,0x9b,0x66,0x3c,0xcc,0xf1,0xe3,0xc7,
+0x8f,0,0xbc,0x6c,0xd9,0xb3,0x61,0x8d,0x83,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,0x80,0,0,0x3,0xc,0,0x1,
+0,0,0,0,0,0,0,0,0,0,
+0,0x20,0,0,0,0xf,0x80,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,0x60,0x60,0,0,0,0,
+0,0,0,0x30,0x1,0x80,0,0,0,0x6,
+0,0xc0,0,0,0,0,0,0,0x80,0xc,
+0x66,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x64,
+0,0,0,0x61,0xc0,0,0,0,0,0,
+0,0,0,0,0x6,0x1,0x40,0x60,0,0,
+0,0,0,0xc,0xc0,0,0,0,0,0,
+0,0,0xc,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x2,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x10,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1,0xc,0x2,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,0x80,0,
+0,0x3,0xc,0,0x2,0,0,0,0,0,
+0,0,0,0,0,0,0x40,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,0x60,
+0x60,0,0,0,0,0,0,0x3,0x30,0x1,
+0x80,0,0,0,0x6,0,0xc0,0,0,0,
+0,0,0x1,0x80,0xc,0x66,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x60,0,0,0,0x6c,0xc0,
+0,0,0,0,0,0,0,0,0,0x6,
+0x1,0x40,0x60,0,0,0,0,0,0xc,0xc0,
+0,0,0,0,0,0,0,0xc,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,0x18,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0xc,0x6,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,0x1,0x98,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,0x70,0xe0,0x1f,0xc0,0,0,
+0,0,0x1,0xe0,0x3,0,0,0,0,0x6,
+0,0xc0,0,0,0,0,0,0x3,0,0x6,
+0x6c,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x60,
+0,0,0,0x7,0x80,0,0,0,0,0,
+0,0,0,0,0x6,0x1,0x41,0xc0,0,0,
+0,0,0,0x7,0x80,0,0,0,0,0,
+0,0,0x38,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,0x70,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x6,0xc,0xc,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,
+};
+
+static WORD HelveticaBold12_ch_ofst[225] = {
+0,4,8,13,21,28,40,49,52,58,
+64,70,77,81,86,90,94,101,108,115,
+122,129,136,143,150,157,164,168,172,179,
+186,193,201,213,221,230,238,247,255,262,
+272,281,285,292,301,308,319,328,338,346,
+356,365,374,382,391,399,409,417,425,432,
+436,440,444,451,458,462,469,476,483,490,
+497,502,509,516,519,522,529,532,543,550,
+557,564,571,576,583,588,595,603,614,621,
+629,635,640,644,649,656,660,664,668,672,
+676,680,684,688,692,696,700,704,708,712,
+716,720,724,728,732,736,740,744,748,752,
+756,760,764,768,772,776,780,784,788,792,
+796,803,810,817,824,828,835,840,851,857,
+865,873,878,889,893,898,905,909,913,917,
+924,931,935,939,943,949,957,967,977,987,
+995,1003,1011,1019,1027,1035,1043,1056,1064,1072,
+1080,1088,1096,1100,1104,1109,1114,1123,1132,1142,
+1152,1162,1172,1182,1189,1199,1208,1217,1226,1235,
+1243,1251,1259,1266,1273,1280,1287,1294,1301,1312,
+1319,1326,1333,1340,1347,1350,1353,1357,1361,1368,
+1375,1382,1389,1396,1403,1410,1417,1424,1431,1438,
+1445,1452,1460,1467,1475,
+};
+
+static struct font_hdr HelveticaBold12_font = {
+STPROP, 12, "AdobeHelv-B-R-N--12-120-75-75-P", 32, 255,
+15, 12, 7, 3, 3,
+13, 13, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+HelveticaBold12_ch_ofst, HelveticaBold12_data,
+245, 15,
+NULL,
+0, 0,   /* x/y offset */
+15,        /* lineHeight */
+11,	   /* psHeight */
+};
+
+MgFont *mgHelveticaBold12Font()
+{
+return &HelveticaBold12_font;
+}
diff --git a/lib/font/mgHelveticaBold14.c b/lib/font/mgHelveticaBold14.c
new file mode 100644
index 0000000..0a8524e
--- /dev/null
+++ b/lib/font/mgHelveticaBold14.c
@@ -0,0 +1,579 @@
+
+/* HelveticaBold14.c - compiled data for font AdobeHelv-B-R-N--14-140-75-75-P */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/helvB14.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE HelveticaBold14_data[5168] = {
+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,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,0xc,0,0xc0,0x70,0x1a,0xd,0x83,0xc0,0,
+0,0,0x30,0x6,0xe,0xd,0x98,0x6e,0xd8,0,
+0xd,0x1,0x80,0x6,0,0xe0,0xd,0x1,0xb0,0,
+0,0,0xc0,0x6,0x3,0x80,0xd8,0x6,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,
+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,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,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,0x6,0x1,0x80,0xd8,0x2c,
+0xd,0x86,0x60,0,0,0,0x18,0xc,0x1b,0xd,
+0x8c,0xdb,0xd8,0,0x16,0,0xc0,0xc,0x1,0xb0,
+0x16,0x1,0xb0,0,0,0,0x60,0xc,0x6,0xc0,
+0xd8,0xc,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,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,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,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,0x3,0xc0,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,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,0,0,0,0,0,0,0,0,0,
+0,0,0x6,0x6c,0,0x10,0,0,0,0x63,
+0x30,0x80,0,0,0xc,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x1f,
+0x3,0xe0,0xc,0x1f,0xc0,0xf8,0xfc,0x1f,0xcf,0xe0,
+0xf8,0xc3,0x30,0x33,0xc,0xc0,0xc0,0x66,0xc,0x1e,
+0xf,0xe0,0x78,0x3f,0x83,0xf3,0xfd,0x83,0x60,0x78,
+0x61,0xe0,0xf0,0x3f,0xf3,0xf3,0xc3,0,0xc,0,
+0x60,0,0x1,0x80,0xe,0,0x60,0x33,0x30,0x30,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x19,0x98,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1,0x8f,
+0x36,0,0xe,0,0,0,0,0xf,0x80,0,
+0,0xc,0,0x3f,0,0x3,0x80,0,0,0,
+0,0,0,0x6,0x1,0x80,0x60,0x18,0x6,0x1,
+0x80,0x7f,0xe0,0xf8,0xfe,0x7f,0x3f,0x9f,0xcc,0xcc,
+0x63,0xf0,0x60,0xc1,0xe0,0x1e,0x1,0xe0,0x1e,0x1,
+0xe0,0,0xf,0x36,0xc,0xc1,0x98,0x33,0x6,0xc0,
+0xd8,0x3,0xc1,0x80,0xc1,0xc1,0xa3,0x61,0xc0,0,
+0,0xc,0x3,0x7,0xd,0xb0,0xdd,0xb3,0x60,0xd0,
+0x60,0xc,0x1c,0xd,0xd,0x80,0,0,0xc0,0x18,
+0x38,0x36,0x6,0x30,0xd,0x80,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x6,0x6c,0x36,0x7c,
+0x78,0x80,0xe0,0x66,0x1b,0xe0,0,0,0xc,0xe0,
+0x61,0xf1,0xf0,0x39,0xf8,0xf3,0xf9,0xf1,0xf0,0,
+0,0,0,0x31,0x8e,0x38,0xc,0x18,0xe3,0xdc,
+0xc7,0x18,0xc,0x3,0xdc,0xc3,0x30,0x33,0x18,0xc0,
+0xc0,0x67,0xc,0x73,0x8c,0x71,0xce,0x31,0xc7,0x38,
+0x61,0x83,0x60,0x78,0x61,0xe0,0xd8,0x60,0x33,0x30,
+0xc7,0x80,0x6,0,0x60,0,0x1,0x80,0x18,0,
+0x60,0x33,0x30,0x30,0,0,0,0,0,0,
+0,0xc,0,0,0,0,0,0,0x31,0x8c,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x1,
+0xe0,0x6,0x19,0x99,0xb6,0x1e,0x12,0,0,0,
+0xf,0,0x18,0,0x63,0x18,0,0x7a,0,0x36,
+0xc0,0x6,0x18,0x61,0x86,0x18,0,0x6,0x1,0x80,
+0x60,0x18,0x6,0x1,0x80,0x78,0x3,0xdc,0xc0,0x60,
+0x30,0x18,0xc,0xcc,0x63,0x1c,0x60,0xc7,0x38,0x73,
+0x87,0x38,0x73,0x87,0x38,0,0x39,0xe6,0xc,0xc1,
+0x98,0x33,0x6,0x61,0x98,0x6,0x60,0xc1,0x83,0x62,
+0xc3,0x63,0x60,0,0,0x6,0x6,0xd,0x8d,0x99,
+0xb7,0xb1,0xc1,0x60,0x30,0x18,0x36,0x16,0xd,0x80,
+0,0,0x60,0x30,0x6c,0x36,0xc,0x30,0xd,0x80,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x6,0x48,0x36,0xd6,0xcd,0x81,0xb0,0x46,0x19,0xc0,
+0,0,0x9,0xb1,0xe3,0x9b,0x38,0x79,0x81,0xd8,
+0x1b,0xbb,0xb8,0,0,0,0,0x31,0x9c,0x1c,
+0x1e,0x18,0x63,0x4,0xc3,0x18,0xc,0x3,0x4,0xc3,
+0x30,0x33,0x30,0xc0,0xe0,0xe7,0xc,0x61,0x8c,0x31,
+0x86,0x30,0xc6,0x18,0x61,0x83,0x30,0xd8,0x61,0xb1,
+0x98,0x60,0x63,0x30,0xcc,0xc0,0,0,0x60,0,
+0x1,0x80,0x18,0,0x60,0,0x30,0x30,0,0,
+0,0,0,0,0,0xc,0,0,0,0,
+0,0,0x31,0x8c,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x23,0x30,0x6,0x19,0x99,0x80,0x61,
+0x8e,0,0,0,0x30,0xc0,0x24,0x30,0xb5,0x80,
+0,0xfa,0,0x76,0xc0,0xe,0x18,0xe1,0x8b,0x18,
+0,0xf,0x3,0xc0,0xf0,0x3c,0xf,0x3,0xc0,0xd8,
+0x3,0x4,0xc0,0x60,0x30,0x18,0xc,0xcc,0x63,0xc,
+0x70,0xc6,0x18,0x61,0x86,0x18,0x61,0x86,0x18,0,
+0x30,0xc6,0xc,0xc1,0x98,0x33,0x6,0x61,0x9f,0xc6,
+0x60,0,0,0,0,0x1,0xc0,0,0,0,
+0,0,0,0,0,0x2,0x40,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x30,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x6,0,0x36,0xd6,0xcd,0x1,
+0xb0,0xc,0xf,0x61,0x80,0,0xb,0x18,0x63,0x1b,
+0x18,0xdb,0x1,0x98,0x33,0x1b,0x18,0xc6,0,0,
+0,0x1,0x99,0xac,0x12,0x18,0x66,0,0xc1,0x98,
+0xc,0x6,0,0xc3,0x30,0x33,0x60,0xc0,0xe0,0xe6,
+0x8c,0xc0,0xcc,0x33,0x3,0x30,0xc7,0,0x61,0x83,
+0x30,0xcc,0xf3,0x1b,0xc,0xc0,0xc3,0x10,0xc8,0x40,
+0,0x3c,0x7c,0xe,0xf,0x8f,0x3c,0x3a,0x6e,0x33,
+0x33,0x33,0x6e,0x37,0x7,0xd,0x81,0xb3,0x67,0x9f,
+0x63,0x61,0xe6,0x78,0xf0,0xff,0x31,0x8c,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x31,0xe3,0x36,0x33,
+0x31,0x9c,0,0x4c,0x9a,0,0,0,0x2f,0x40,
+0x24,0x30,0x33,0,0xc6,0xfa,0,0x36,0xc0,0x6,
+0x30,0x63,0x6,0x30,0xc,0x9,0x2,0x40,0x90,0x24,
+0x9,0x2,0x40,0x98,0x6,0,0xc0,0x60,0x30,0x18,
+0xc,0xcc,0x63,0x6,0x78,0xcc,0xc,0xc0,0xcc,0xc,
+0xc0,0xcc,0xd,0x86,0x61,0xe6,0xc,0xc1,0x98,0x33,
+0x6,0x33,0x18,0xe6,0x63,0xc3,0xc3,0xc3,0xc3,0xc3,
+0xc3,0xde,0xf,0xf,0xf,0xf,0xf,0x19,0x98,0xc1,
+0xe3,0x70,0x70,0x38,0x1c,0xe,0x7,0x3,0x1,0xd3,
+0x19,0x8c,0xc6,0x63,0x61,0xb6,0x30,0xc0,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x6,0,
+0xff,0xf0,0x7b,0,0xe0,0xc,0xc,0x1,0x80,0,
+0x1b,0x18,0x60,0x38,0x19,0x9b,0xe3,0,0x33,0x1b,
+0x18,0xc6,0xe,0,0x38,0x3,0x33,0x66,0x33,0x18,
+0xc6,0,0xc1,0x98,0xc,0x6,0,0xc3,0x30,0x33,
+0xc0,0xc0,0xf1,0xe6,0xcc,0xc0,0xcc,0x73,0x3,0x31,
+0xc3,0xc0,0x61,0x83,0x39,0xcc,0x93,0xe,0xc,0xc1,
+0xc3,0x18,0xc0,0,0,0x66,0x76,0x1f,0x1b,0x99,
+0x98,0x6e,0x77,0x33,0x36,0x33,0xbb,0x3b,0x8d,0x8e,
+0xc3,0x73,0xee,0xcc,0x63,0x61,0xe6,0x78,0xf0,0xc3,
+0x31,0x8c,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x33,0x71,0x83,0xe3,0x31,0x8f,0,0x92,0x5f,0xd,
+0x80,0,0x49,0x20,0x18,0x30,0x61,0x80,0xc6,0xfa,
+0,0x33,0x8d,0x86,0x30,0x63,0x3,0x30,0xc,0x19,
+0x86,0x61,0x98,0x66,0x19,0x86,0x61,0x98,0x6,0,
+0xc0,0x60,0x30,0x18,0xc,0xcc,0x63,0x6,0x6c,0xcc,
+0xc,0xc0,0xcc,0xc,0xc0,0xcc,0xc,0xcc,0x63,0x66,
+0xc,0xc1,0x98,0x33,0x6,0x33,0x18,0x66,0xc6,0x66,
+0x66,0x66,0x66,0x66,0x66,0x73,0x1d,0x9d,0x9d,0x9d,
+0x9d,0x99,0x98,0xc3,0x63,0xb8,0xd8,0x6c,0x36,0x1b,
+0xd,0x83,0x3,0x63,0x19,0x8c,0xc6,0x63,0x61,0xbb,
+0x30,0xc0,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x6,0,0x6c,0x78,0x6,0x1,0xcc,0xc,
+0xc,0x1,0x80,0,0x1b,0x18,0x60,0x30,0xf3,0x18,
+0x73,0x70,0x61,0xf3,0x98,0,0x38,0x7f,0xe,0x6,
+0x36,0x66,0x33,0x1f,0x86,0,0xc1,0x9f,0xcf,0xc6,
+0x3c,0xff,0x30,0x33,0xc0,0xc0,0xd1,0x66,0x4c,0xc0,
+0xcf,0xe3,0x3,0x3f,0x80,0xf0,0x61,0x83,0x19,0x8c,
+0x93,0xe,0x7,0x81,0x83,0x18,0xc0,0,0,0x6,
+0x63,0x31,0x31,0x99,0x98,0xc6,0x63,0x33,0x3c,0x33,
+0x33,0x31,0x98,0xcc,0x66,0x33,0xc,0xc,0x63,0x33,
+0x66,0x6d,0x99,0x86,0x61,0x86,0x39,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x6,0x47,0xe3,0x61,0xe0,0x1b,
+0x80,0x90,0x40,0x1b,0x1f,0xc0,0x49,0x20,0x1,0xfe,
+0xc5,0x80,0xc6,0x7a,0,0x30,0x6,0xc6,0x62,0x66,
+0xcb,0x62,0,0x19,0x86,0x61,0x98,0x66,0x19,0x86,
+0x61,0x9f,0xc6,0,0xfe,0x7f,0x3f,0x9f,0xcc,0xcc,
+0x67,0xc6,0x64,0xcc,0xc,0xc0,0xcc,0xc,0xc0,0xcc,
+0xc,0x78,0x66,0x66,0xc,0xc1,0x98,0x33,0x6,0x1e,
+0x18,0x66,0xc0,0x60,0x60,0x60,0x60,0x60,0x60,0x63,
+0x31,0x99,0x99,0x99,0x99,0x99,0x98,0xc6,0x33,0x19,
+0x8c,0xc6,0x63,0x31,0x98,0xc0,0x6,0x73,0x19,0x8c,
+0xc6,0x63,0x33,0x31,0x99,0x80,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x4,0,0x6c,0x1c,
+0x4,0x3,0xec,0xc,0xc,0xf,0xf0,0x7c,0x1b,0x18,
+0x60,0xe0,0x1b,0x18,0x1b,0xd8,0x63,0xb9,0xf8,0,
+0x60,0,0x3,0xc,0x36,0xc6,0x61,0x98,0xc6,0,
+0xc1,0x98,0xc,0x6,0xc,0xc3,0x30,0x33,0x60,0xc0,
+0xd1,0x66,0x6c,0xc0,0xcc,0x3,0x3,0x30,0xc0,0x38,
+0x61,0x83,0x19,0x8d,0x9b,0x1b,0x7,0x83,0x3,0x18,
+0xc0,0,0,0x3e,0x63,0x30,0x31,0x9f,0x98,0xc6,
+0x63,0x33,0x3c,0x33,0x33,0x31,0x98,0xcc,0x66,0x33,
+0x7,0x8c,0x63,0x33,0x36,0xc7,0x19,0x8c,0xc1,0x83,
+0x6f,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x16,0x81,
+0x83,0x63,0xf0,0x19,0x80,0x90,0x5f,0x36,0,0x5f,
+0x4e,0x20,0,0x30,0xf7,0,0xc6,0x3a,0x60,0x37,
+0xc3,0x66,0x66,0x67,0x6e,0x66,0xc,0x30,0xcc,0x33,
+0xc,0xc3,0x30,0xcc,0x33,0x18,0x6,0,0xc0,0x60,
+0x30,0x18,0xc,0xcc,0x63,0x6,0x66,0xcc,0xc,0xc0,
+0xcc,0xc,0xc0,0xcc,0xc,0x30,0x6c,0x66,0xc,0xc1,
+0x98,0x33,0x6,0x1e,0x18,0xe6,0x63,0xe3,0xe3,0xe3,
+0xe3,0xe3,0xe3,0xff,0x30,0x1f,0x9f,0x9f,0x9f,0x99,
+0x98,0xc6,0x33,0x19,0x8c,0xc6,0x63,0x31,0x98,0xdf,
+0xe6,0xb3,0x19,0x8c,0xc6,0x63,0x33,0x31,0x99,0x80,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x4,0x1,0xfe,0x16,0xd,0xe3,0x38,0xc,0xc,0x1,
+0x80,0,0x13,0x18,0x61,0xc0,0x1b,0xfc,0x1b,0x18,
+0xc3,0x18,0x18,0,0x38,0x7f,0xe,0xc,0x36,0xcc,
+0x7f,0x98,0x66,0,0xc1,0x98,0xc,0x6,0xc,0xc3,
+0x36,0x33,0x30,0xc0,0xdb,0x66,0x2c,0xc0,0xcc,0x3,
+0x1b,0x30,0xc0,0x18,0x61,0x83,0xf,0x5,0x9a,0x31,
+0x83,0x7,0x3,0x8,0xc0,0,0,0x66,0x63,0x30,
+0x31,0x98,0x18,0xc6,0x63,0x33,0x36,0x33,0x33,0x31,
+0x98,0xcc,0x66,0x33,0x1,0xcc,0x63,0x12,0x36,0xc7,
+0x9,0xc,0x61,0x86,0x46,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x16,0x81,0x83,0xe0,0xc0,0x19,0x80,0x92,
+0x40,0x1b,0,0x40,0x49,0x20,0,0x30,0,0,
+0xc6,0xa,0x60,0,0x6,0xc0,0xce,0xc,0x60,0xce,
+0xc,0x3f,0xcf,0xf3,0xfc,0xff,0x3f,0xcf,0xf3,0xf8,
+0x6,0,0xc0,0x60,0x30,0x18,0xc,0xcc,0x63,0x6,
+0x62,0xcc,0xc,0xc0,0xcc,0xc,0xc0,0xcc,0xc,0x78,
+0x78,0x66,0xc,0xc1,0x98,0x33,0x6,0xc,0x1f,0xc6,
+0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x60,0x30,0x18,
+0x18,0x18,0x18,0x19,0x98,0xc6,0x33,0x19,0x8c,0xc6,
+0x63,0x31,0x98,0xc0,0x6,0xb3,0x19,0x8c,0xc6,0x63,
+0x12,0x31,0x89,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,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xd8,0xd6,0xb,0x33,
+0x18,0xc,0xc,0x1,0x80,0,0x13,0x18,0x63,0x83,
+0x18,0x1b,0x1b,0x18,0xc3,0x1b,0x18,0,0xe,0,
+0x38,0,0x33,0xb8,0x61,0x98,0x63,0x4,0xc3,0x18,
+0xc,0x3,0xc,0xc3,0x36,0x33,0x18,0xc0,0xca,0x66,
+0x1c,0x61,0x8c,0x1,0x8e,0x30,0xc6,0x18,0x61,0x83,
+0xf,0x7,0xe,0x31,0x83,0x6,0x3,0xc,0xc0,0,
+0,0x66,0x63,0x31,0x31,0x98,0x18,0xc6,0x63,0x33,
+0x36,0x33,0x33,0x31,0x98,0xcc,0x66,0x33,0,0xcc,
+0x63,0x1e,0x19,0x8d,0x8f,0x18,0x31,0x8c,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x37,0x33,0x1e,0x33,
+0xf1,0x9d,0x80,0x4c,0x80,0xd,0x80,0x40,0x29,0x40,
+0,0x30,0,0,0xc6,0xa,0,0,0xd,0x80,
+0xd6,0xc,0xc0,0xd6,0x18,0x30,0xcc,0x33,0xc,0xc3,
+0x30,0xcc,0x33,0x18,0x3,0x4,0xc0,0x60,0x30,0x18,
+0xc,0xcc,0x63,0xc,0x61,0xc6,0x18,0x61,0x86,0x18,
+0x61,0x86,0x18,0xcc,0x30,0xc6,0xc,0xc1,0x98,0x33,
+0x6,0xc,0x18,0x6,0x66,0x66,0x66,0x66,0x66,0x66,
+0x66,0x60,0x31,0x98,0x18,0x18,0x18,0x19,0x98,0xc6,
+0x33,0x19,0x8c,0xc6,0x63,0x31,0x98,0xc3,0x7,0x33,
+0x19,0x8c,0xc6,0x63,0x1e,0x31,0x8f,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,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x6,0,
+0xd8,0xd6,0x1b,0x33,0x3c,0xc,0xc,0x1,0x83,0x1,
+0xb1,0xb0,0x63,0x3,0x38,0x1b,0xb1,0xb9,0x83,0x1b,
+0x38,0xc6,0,0,0,0xc,0x18,0,0xc0,0xd8,
+0xe3,0xdc,0xc7,0x18,0xc,0x3,0xdc,0xc3,0x37,0x73,
+0xc,0xc0,0xce,0x66,0x1c,0x73,0x8c,0x1,0xce,0x30,
+0xc7,0x70,0x60,0xc6,0x6,0x3,0xc,0x60,0xc3,0xc,
+0x3,0xc,0xc0,0,0,0x7e,0x76,0x1f,0x1b,0x9d,
+0x98,0x6e,0x63,0x33,0x33,0x33,0x33,0x31,0x8d,0x8e,
+0xc3,0x73,0xe,0xcd,0x77,0xc,0x19,0x98,0xc6,0x30,
+0x31,0x8c,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x33,0x37,0xd8,0,0xc1,0x8f,0,0x61,0x80,0,
+0,0,0x30,0xc0,0,0,0,0,0xee,0xa,
+0,0,0,0x1,0x9f,0x19,0x81,0x9f,0x30,0x60,
+0x78,0x1e,0x7,0x81,0xe0,0x78,0x1e,0x18,0x3,0xdc,
+0xc0,0x60,0x30,0x18,0xc,0xcc,0x63,0x1c,0x61,0xc7,
+0x38,0x73,0x87,0x38,0x73,0x87,0x39,0x86,0x79,0xc3,
+0x18,0x63,0xc,0x61,0x8c,0xc,0x18,0x6,0x67,0xe7,
+0xe7,0xe7,0xe7,0xe7,0xe7,0xf3,0x1d,0x9d,0x9d,0x9d,
+0x9d,0x99,0x98,0xc3,0x63,0x18,0xd8,0x6c,0x36,0x1b,
+0xd,0x83,0x3,0x63,0xb9,0xdc,0xee,0x77,0xc,0x3b,
+0x6,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,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x6,0,0xd8,0x7c,0x11,0xe1,0xf6,0xc,
+0xc,0,0x3,0x1,0xb0,0xe0,0x63,0xf9,0xf0,0x19,
+0xe0,0xf1,0x81,0xf1,0xf0,0xc6,0,0,0,0xc,
+0xc,0x60,0xc0,0xdf,0xc0,0xf8,0xfc,0x1f,0xcc,0,
+0xf4,0xc3,0x33,0xe3,0x6,0xfe,0xc4,0x66,0xc,0x1e,
+0xc,0,0x7b,0x30,0x63,0xe0,0x60,0x7c,0x6,0x3,
+0xc,0x60,0xc3,0xf,0xf3,0xc,0xc0,0,0,0x3b,
+0x6c,0xe,0xd,0x8f,0x18,0x3e,0x63,0x33,0x33,0x33,
+0x33,0x31,0x87,0xf,0x81,0xf3,0x7,0x86,0x3b,0xc,
+0x19,0x98,0xc6,0x3f,0x31,0x8c,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x33,0xe6,0xf0,0,0xc1,0x83,
+0x80,0x1e,0,0,0,0,0xf,0,0x1,0xfe,
+0,0,0xf6,0xa,0,0,0,0x1,0x86,0x19,
+0xe1,0x86,0x60,0x60,0x78,0x1e,0x7,0x81,0xe0,0x78,
+0x1e,0x1f,0xe0,0xf8,0xfe,0x7f,0x3f,0x9f,0xcc,0xcc,
+0x63,0xf0,0x60,0xc1,0xe0,0x1e,0x1,0xe0,0x1e,0x1,
+0xe0,0,0xcf,0x1,0xf0,0x3e,0x7,0xc0,0xf8,0xc,
+0x18,0x6,0xc3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xbe,
+0xf,0xf,0xf,0xf,0xf,0x19,0x98,0xc1,0xc3,0x18,
+0x70,0x38,0x1c,0xe,0x7,0,0x5,0xc1,0xd8,0xec,
+0x76,0x3b,0xc,0x3e,0x6,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,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x10,
+0,0,0,0x6,0x18,0,0x6,0,0,0,
+0,0,0,0,0,0,0,0,0,0xc,
+0,0,0,0,0x7,0xc0,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,0x3,0,
+0xc0,0,0,0,0,0,0,0,0,0x6,
+0,0x3,0,0,0,0,0,0xc,0,0x30,
+0,0,0,0,0,0,0x6,0,0x31,0x8c,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x32,0,
+0,0,0x1,0x99,0x80,0,0,0,0,0,
+0,0,0,0,0,0,0xc0,0xa,0x1,0x80,
+0,0,0,0,0,0,0x63,0,0,0,
+0,0,0,0,0,0,0,0x20,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,0x2,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xc,0x30,0x6,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,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x10,0,0,0,0x6,0x18,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,0x3,0,0xc0,0,0,0,0,0,
+0,0,0,0xce,0,0x7,0,0,0,0,
+0,0xc,0,0x30,0,0,0,0,0,0,
+0xc,0,0x31,0x8c,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x30,0,0,0,0x1,0x99,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0xc0,0xa,0xd,0x80,0,0,0,0,0,0,
+0x63,0,0,0,0,0,0,0,0,0,
+0x1,0xb0,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,0x1b,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x18,0x30,0xc,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,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,0x3,0x30,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,0x3,0xc3,0xc0,0x1f,
+0xe0,0,0,0,0,0,0,0x7c,0,0x6,
+0,0,0,0,0,0xc,0,0x30,0,0,
+0,0,0,0,0x1c,0,0x19,0x98,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x30,0,0,0,
+0,0xf,0,0,0,0,0,0,0,0,
+0,0,0,0,0xc0,0xa,0x7,0,0,0,
+0,0,0,0,0x3e,0,0,0,0,0,
+0,0,0,0,0,0xe0,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,0xe,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x38,0x30,0x1c,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,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+};
+
+static WORD HelveticaBold14_ch_ofst[225] = {
+0,4,8,15,24,32,45,56,60,65,
+70,76,85,89,94,98,102,110,118,126,
+134,142,150,158,166,174,182,187,192,200,
+209,217,226,240,250,260,271,282,291,300,
+311,321,325,333,343,351,364,375,387,397,
+409,420,430,438,449,459,473,482,492,501,
+506,510,515,523,531,536,544,553,561,570,
+578,583,592,601,605,609,617,621,633,642,
+651,660,669,675,683,688,697,705,715,722,
+730,736,742,746,752,761,765,769,773,777,
+781,785,789,793,797,801,805,809,813,817,
+821,825,829,833,837,841,845,849,853,857,
+861,865,869,873,877,881,885,889,893,897,
+901,909,917,925,934,938,946,951,963,969,
+978,987,992,1004,1009,1015,1024,1029,1034,1039,
+1048,1056,1060,1065,1069,1075,1084,1096,1108,1120,
+1129,1139,1149,1159,1169,1179,1189,1204,1215,1224,
+1233,1242,1251,1255,1259,1264,1269,1280,1291,1303,
+1315,1327,1339,1351,1360,1372,1383,1394,1405,1416,
+1426,1436,1444,1452,1460,1468,1476,1484,1492,1505,
+1514,1522,1530,1538,1546,1550,1554,1559,1564,1573,
+1582,1591,1600,1609,1618,1627,1636,1645,1654,1663,
+1672,1681,1689,1698,1706,
+};
+
+static struct font_hdr HelveticaBold14_font = {
+STPROP, 14, "AdobeHelv-B-R-N--14-140-75-75-P", 32, 255,
+17, 14, 8, 3, 3,
+14, 15, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+HelveticaBold14_ch_ofst, HelveticaBold14_data,
+304, 17,
+NULL,
+0, 0,   /* x/y offset */
+19,        /* lineHeight */
+13,	   /* psHeight */
+};
+
+MgFont *mgHelveticaBold14Font()
+{
+return &HelveticaBold14_font;
+}
+
+MgFont *mgMediumBoldFont()
+{
+return &HelveticaBold14_font;
+}
+
diff --git a/lib/font/mgHelveticaBold18.c b/lib/font/mgHelveticaBold18.c
new file mode 100644
index 0000000..96a2bc1
--- /dev/null
+++ b/lib/font/mgHelveticaBold18.c
@@ -0,0 +1,883 @@
+
+/* HelveticaBold18.c - compiled data for font AdobeHelv-B-R-N--18-180-75-75-P */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/helvB18.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE HelveticaBold18_data[8211] = {
+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,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,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,0x7,0,
+0x3,0x80,0x70,0x7,0x60,0,0,0,0,0,
+0,0,0x1c,0,0x1c,0x7,0,0x1,0xc0,0xe4,
+0,0,0,0xec,0x3,0x80,0,0x38,0,0xe0,
+0x1,0xd8,0,0,0,0,0,0x1,0xc0,0,
+0xe0,0x1c,0,0,0x1,0xc0,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,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,
+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,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x3,0x80,0x7,0,0xf8,
+0xf,0xe0,0x33,0,0xe0,0,0,0,0,0xe,
+0,0x38,0xf,0x81,0x98,0xe1,0xce,0xd8,0,0x1,
+0xfc,0x1,0xc0,0,0x70,0x1,0xf0,0x3,0xf8,0x3,
+0x30,0,0,0,0,0xe0,0x1,0xc0,0x3e,0x1,
+0x98,0x3,0x80,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,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,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,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,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x1,0xc0,0xe,0x1,0xdc,0xd,0xc0,0x33,
+0x1,0xb0,0,0,0,0,0x7,0,0x70,0x1d,
+0xc1,0x98,0x73,0x9b,0xd8,0,0x1,0xb8,0,0xe0,
+0,0xe0,0x3,0xb8,0x3,0x70,0x3,0x30,0,0,
+0,0,0x70,0x3,0x80,0x77,0x1,0x98,0x7,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,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,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,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,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,0x1,0xb0,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,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,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,0x3,0x8d,
+0x80,0,0x40,0,0,0,0x3,0xe,0x70,0x10,
+0,0,0,0x1,0x80,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x1f,0x80,0x7f,0,0x38,0x1f,0xc0,0xf,
+0x83,0xfc,0xf,0xfc,0xff,0xc0,0xf8,0x38,0x39,0xc0,
+0x73,0x83,0xce,0x1,0xc0,0x39,0xc0,0xe0,0x7e,0x7,
+0xf0,0x7,0xe0,0x7f,0x80,0xfc,0x7f,0xf7,0x7,0x38,
+0x39,0xc7,0x1d,0xc0,0xee,0xe,0x7f,0xef,0xe3,0xe0,
+0,0,0xe0,0,0xe0,0,0,0x7,0,0x1,
+0xe0,0,0xe0,0x1c,0xe7,0x1,0xc0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x3b,0x38,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,0xc1,0xe0,0,0,
+0x3,0xc0,0,0,0,0,0,0x7c,0,0,
+0,0x1,0xc0,0x1,0xfc,0,0,0x3c,0,0,
+0,0,0,0,0,0,0x1,0xc0,0xe,0,
+0x70,0x3,0x80,0x1c,0,0xe0,0x7,0xff,0x81,0xf0,
+0x7f,0xe7,0xfe,0x7f,0xe7,0xfe,0x73,0x8e,0x73,0xfc,
+0xe,0x7,0x3,0xf0,0x3,0xf0,0x3,0xf0,0x3,0xf0,
+0x3,0xf0,0,0,0x7e,0xe7,0x7,0x38,0x39,0xc1,
+0xce,0xe,0x70,0x73,0x80,0xf,0x7,0,0x38,0x1c,
+0xe,0xc0,0,0x70,0,0,0,0xe,0,0x38,
+0xe,0,0x7,0xc,0xe0,0xe,0,0x76,0xe,0,
+0x1c,0x3,0x80,0x76,0,0,0,0,0x3,0x80,
+0x7,0x3,0x80,0,0x7,0x38,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x3,0x8d,0x83,0x61,0xf0,
+0x78,0x60,0x3e,0x3,0x1c,0x38,0xd6,0,0,0,
+0x1,0x8e,0x1,0xc1,0xf0,0x7c,0x3,0x9f,0xe1,0xf1,
+0xff,0x1f,0x7,0xc0,0,0,0,0,0,0x3f,
+0xc1,0xff,0xc0,0x38,0x1f,0xf0,0x3f,0xe3,0xff,0xf,
+0xfc,0xff,0xc3,0xfe,0x38,0x39,0xc0,0x73,0x87,0x8e,
+0x1,0xc0,0x39,0xe0,0xe1,0xff,0x87,0xfc,0x1f,0xf8,
+0x7f,0xe1,0xfe,0x7f,0xf7,0x7,0x38,0x39,0xc7,0x1d,
+0xc0,0xee,0xe,0x7f,0xef,0xe3,0xe0,0xc0,0,0x70,
+0,0xe0,0,0,0x7,0,0x3,0xe0,0,0xe0,
+0x1c,0xe7,0x1,0xc0,0,0,0,0,0,0,
+0,0,0,0x1c,0,0,0,0,0,0,
+0,0,0x73,0x1c,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,0x3e,
+0,0x7,0x1c,0xc3,0xf1,0xb0,0x3e,0x4,0x60,0,
+0,0,0x3,0xe0,0x7c,0xf0,0,0x3c,0xf3,0x80,
+0x3,0xd8,0,0xc,0x66,0,0x6,0xc,0xc,0x18,
+0x3c,0x18,0,0x1,0xc0,0xe,0,0x70,0x3,0x80,
+0x1c,0,0xe0,0x7,0xff,0x87,0xfc,0x7f,0xe7,0xfe,
+0x7f,0xe7,0xfe,0x73,0x8e,0x73,0xff,0xf,0x7,0xf,
+0xfc,0xf,0xfc,0xf,0xfc,0xf,0xfc,0xf,0xfc,0,
+0x1,0xff,0xc7,0x7,0x38,0x39,0xc1,0xce,0xe,0x70,
+0x73,0x80,0x1f,0x83,0x80,0x70,0x3e,0x1f,0xc3,0x60,
+0xd8,0,0,0,0x7,0,0x70,0x1f,0x6,0x63,
+0x9d,0xf6,0xc3,0xe0,0xfe,0x7,0,0x38,0x7,0xc0,
+0xfe,0xc,0xc0,0,0,0x1,0xc0,0xe,0x7,0xc0,
+0xd8,0xe,0x38,0x1,0xb0,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,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x3,0x8d,0x83,0x63,0xf8,0xfc,0x60,0x7f,
+0x3,0x18,0x18,0x7c,0,0,0,0x1,0xbf,0x83,
+0xc3,0xf8,0xfe,0x7,0x9f,0xe3,0xf9,0xff,0x3f,0x8f,
+0xe0,0,0,0,0,0,0x39,0xc3,0xc1,0xe0,
+0x7c,0x1c,0x78,0x78,0xe3,0x87,0x8e,0,0xe0,0x7,
+0x8e,0x38,0x39,0xc0,0x73,0x8f,0xe,0x1,0xe0,0x79,
+0xe0,0xe3,0xc3,0xc7,0x1e,0x3c,0x3c,0x70,0xf3,0x8f,
+0x7,0x7,0x7,0x38,0x39,0xc7,0x1c,0xe1,0xce,0xe,
+0,0xee,0x60,0xe1,0xe0,0,0x38,0,0xe0,0,
+0,0x7,0,0x3,0x80,0,0xe0,0,0x7,0x1,
+0xc0,0,0,0,0,0,0,0,0,0,
+0x1c,0,0,0,0,0,0,0,0,0xe3,
+0xe,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x8,0x7f,0x80,0x7,0x1c,
+0xc6,0x39,0xb0,0xe3,0x83,0xe0,0,0,0,0xe,
+0x38,0x1,0xf8,0,0x7f,0xff,0,0x7,0xd8,0,
+0x3c,0x66,0,0x1e,0xc,0x3c,0x18,0x7e,0x18,0,
+0x3,0xe0,0x1f,0,0xf8,0x7,0xc0,0x3e,0x1,0xf0,
+0xf,0xc0,0xf,0x1c,0x70,0x7,0,0x70,0x7,0,
+0x73,0x8e,0x73,0x87,0x8f,0x7,0x1e,0x1e,0x1e,0x1e,
+0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0,0x3,0xc3,0x87,
+0x7,0x38,0x39,0xc1,0xce,0xe,0x70,0x73,0x80,0x39,
+0xc1,0xc0,0xe0,0x77,0x1b,0x83,0x60,0xd8,0,0,
+0,0x3,0x80,0xe0,0x3b,0x86,0x61,0xfb,0xbe,0xcf,
+0x80,0xdc,0x3,0x80,0x70,0xe,0xe0,0xdc,0xc,0xc0,
+0,0,0,0xe0,0x1c,0xe,0xe0,0xd8,0x1c,0x38,
+0x1,0xb0,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3,
+0x8d,0x83,0x67,0x5c,0xcc,0xc0,0x63,0x3,0x38,0x1c,
+0x38,0,0,0,0x1,0x3b,0x8f,0xc7,0x1d,0xce,
+0xf,0x9c,0x3,0x98,0x7,0x71,0xdc,0xe0,0,0,
+0,0,0,0x39,0xc7,0,0x60,0x7c,0x1c,0x38,
+0x70,0x73,0x83,0x8e,0,0xe0,0x7,0x7,0x38,0x39,
+0xc0,0x73,0x9e,0xe,0x1,0xe0,0x79,0xf0,0xe3,0x81,
+0xc7,0xe,0x38,0x1c,0x70,0x73,0x87,0x7,0x7,0x7,
+0x1c,0x71,0xc7,0x1c,0xf3,0xc7,0x1c,0x1,0xce,0x20,
+0xe3,0xf0,0,0,0,0xe0,0,0,0x7,0,
+0x3,0x80,0,0xe0,0,0x7,0x1,0xc0,0,0,
+0,0,0,0,0,0,0,0x1c,0,0,
+0,0,0,0,0,0,0xe3,0xe,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x8,0xe3,0x80,0x7,0x1c,0xc6,0x38,0x1,
+0x80,0xc6,0x60,0,0,0,0x18,0xc,0x1,0x98,
+0,0x67,0x98,0,0x7,0xd8,0,0x3c,0x66,0,
+0x1e,0x18,0x3c,0x30,0x66,0x30,0,0x3,0xe0,0x1f,
+0,0xf8,0x7,0xc0,0x3e,0x1,0xf0,0xd,0xc0,0xe,
+0xe,0x70,0x7,0,0x70,0x7,0,0x73,0x8e,0x73,
+0x83,0x8f,0x87,0x1c,0xe,0x1c,0xe,0x1c,0xe,0x1c,
+0xe,0x1c,0xe,0,0x3,0x87,0xc7,0x7,0x38,0x39,
+0xc1,0xce,0xe,0x38,0xe3,0xf8,0x39,0xc0,0,0,
+0,0,0,0,0x70,0,0,0,0,0,
+0,0,0,0,0,0,0,0xc0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x38,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,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0x89,0x1f,0xff,
+0x5c,0xcc,0x80,0x73,0x2,0x30,0xc,0x6c,0,0,
+0,0x3,0x71,0xcf,0xc7,0x1d,0xc6,0x1f,0x9c,0x7,
+0,0xe,0x71,0xdc,0x71,0xc7,0,0,0,0,
+0x3,0x86,0x3b,0x70,0x6c,0x1c,0x38,0xf0,0x73,0x81,
+0xce,0,0xe0,0xe,0x7,0x38,0x39,0xc0,0x73,0xbc,
+0xe,0x1,0xf0,0xf9,0xf8,0xe7,0x81,0xe7,0xe,0x78,
+0x1e,0x70,0x73,0xc0,0x7,0x7,0x7,0x1c,0x70,0xe7,
+0x38,0x33,0x7,0x1c,0x3,0x8e,0x30,0xe7,0x38,0,
+0x1,0xf0,0xef,0x1,0xe0,0xf7,0x7,0x8f,0xe3,0xdc,
+0xef,0x1c,0xe7,0x39,0xce,0xe7,0x1d,0xe0,0x78,0x3b,
+0xc0,0xf7,0x3b,0xf,0x3f,0x71,0xdc,0x7e,0x73,0xf1,
+0xf8,0xef,0xf0,0xe3,0xe,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x70,0xf8,
+0xe0,0x18,0x33,0xb8,0xc7,0,0x1,0x9c,0xc6,0x60,
+0,0,0,0x1b,0xe4,0x1,0x98,0,0xe,0x70,
+0x1c,0x77,0xd8,0,0xc,0x66,0,0x6,0x18,0xc,
+0x30,0x1c,0x30,0xe,0x3,0x60,0x1b,0,0xd8,0x6,
+0xc0,0x36,0x1,0xb0,0x1d,0xc0,0x1e,0xe,0x70,0x7,
+0,0x70,0x7,0,0x73,0x8e,0x73,0x81,0xcf,0xc7,
+0x3c,0xf,0x3c,0xf,0x3c,0xf,0x3c,0xf,0x3c,0xf,
+0,0x7,0x8e,0xe7,0x7,0x38,0x39,0xc1,0xce,0xe,
+0x38,0xe3,0xfe,0x39,0xc7,0xc1,0xf0,0x7c,0x1f,0x7,
+0xc1,0xf0,0x7c,0xf0,0x1e,0x7,0x80,0xf0,0x1e,0x3,
+0xc3,0x9c,0xe3,0x83,0xe1,0xde,0x7,0x80,0x78,0x7,
+0x80,0x78,0x7,0x80,0,0xf,0x37,0x1c,0xe3,0x9c,
+0x73,0x8e,0xe3,0xbb,0xc7,0x1c,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x3,0x80,0x1f,0xff,0x40,0xfd,0x80,
+0x3e,0,0x70,0xe,0x44,0xe,0,0,0x3,0x71,
+0xc1,0xc0,0x1c,0xe,0x1b,0x9f,0xc7,0,0x1c,0x71,
+0xd8,0x71,0xc7,0,0xe0,0x1,0xc0,0x7,0x8e,0x7f,
+0x30,0xee,0x1c,0x70,0xe0,0x3,0x81,0xce,0,0xe0,
+0xe,0,0x38,0x39,0xc0,0x73,0xf8,0xe,0x1,0xf0,
+0xf9,0xd8,0xe7,0,0xe7,0x1e,0x70,0xe,0x70,0xf1,
+0xf0,0x7,0x7,0x7,0x1c,0x70,0xe7,0x38,0x3f,0x3,
+0xb8,0x3,0x8e,0x30,0xee,0x1c,0,0x3,0xf8,0xff,
+0x87,0xf9,0xff,0x1f,0xcf,0xe7,0xfc,0xff,0x9c,0xe7,
+0x71,0xcf,0xff,0x9f,0xf1,0xfe,0x3f,0xe1,0xff,0x3f,
+0x3f,0xbf,0x71,0xdc,0x7e,0x73,0xf1,0xf8,0xef,0xf0,
+0xe3,0xe,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x71,0xfc,0xe0,0x1f,0xf3,
+0xb8,0xc3,0xc0,0x3,0x36,0x63,0xa1,0xdc,0,0,
+0x33,0x36,0x1,0xf8,0x38,0x3c,0x78,0x1c,0x77,0xd8,
+0,0xc,0x3c,0xee,0x6,0x30,0xc,0x60,0x1e,0x60,
+0xe,0x7,0x70,0x3b,0x81,0xdc,0xe,0xe0,0x77,0x3,
+0xb8,0x1d,0xc0,0x1c,0,0x70,0x7,0,0x70,0x7,
+0,0x73,0x8e,0x73,0x81,0xce,0xc7,0x38,0x7,0x38,
+0x7,0x38,0x7,0x38,0x7,0x38,0x7,0x70,0xe7,0x1c,
+0xe7,0x7,0x38,0x39,0xc1,0xce,0xe,0x1d,0xc3,0x8f,
+0x39,0xcf,0xe3,0xf8,0xfe,0x3f,0x8f,0xe3,0xf8,0xff,
+0xf8,0x7f,0x9f,0xc3,0xf8,0x7f,0xf,0xe3,0x9c,0xe3,
+0x8f,0xf1,0xff,0x1f,0xe1,0xfe,0x1f,0xe1,0xfe,0x1f,
+0xe0,0x70,0x3f,0xe7,0x1c,0xe3,0x9c,0x73,0x8e,0xe3,
+0xbf,0xe7,0x1c,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,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x3,0x80,0x6,0xc3,0xc0,0x7b,0,0x7c,0x60,0x70,
+0xe,0,0xe,0,0,0x3,0x71,0xc1,0xc0,0x38,
+0x3c,0x3b,0x9f,0xe7,0x70,0x1c,0x3f,0x98,0x71,0xc7,
+0x3,0xe7,0xf9,0xf0,0x7,0xc,0x66,0x30,0xc6,0x1f,
+0xf0,0xe0,0x3,0x81,0xcf,0xf8,0xff,0x8e,0,0x3f,
+0xf9,0xc0,0x73,0xf0,0xe,0x1,0xf0,0xf9,0xdc,0xe7,
+0,0xe7,0xfc,0x70,0xe,0x7f,0xe0,0xfc,0x7,0x7,
+0x7,0xc,0x60,0xe7,0x38,0x1e,0x3,0xb8,0x7,0xe,
+0x30,0xec,0xc,0,0x3,0x9c,0xf3,0x87,0x39,0xcf,
+0x1c,0xe3,0x87,0x3c,0xf3,0x9c,0xe7,0xe1,0xcf,0x7b,
+0x9e,0x71,0xce,0x3c,0xe1,0xcf,0x3f,0x73,0x9c,0x71,
+0xdc,0x7e,0x73,0xbb,0xb8,0xe0,0x70,0xe3,0xe,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x3,0x9c,0x70,0xe,0xe1,0xf0,0xc7,0xe0,
+0x3,0x60,0x60,0x3,0xb8,0,0,0x33,0x36,0,
+0xf0,0x38,0x71,0x98,0x1c,0x77,0xd8,0,0xc,0,
+0x77,0x6,0x33,0xc,0x6f,0x66,0x6c,0,0x6,0x30,
+0x31,0x81,0x8c,0xc,0x60,0x63,0x3,0x18,0x19,0xff,
+0x1c,0,0x7f,0xc7,0xfc,0x7f,0xc7,0xfc,0x73,0x8e,
+0x77,0xf1,0xce,0xe7,0x38,0x7,0x38,0x7,0x38,0x7,
+0x38,0x7,0x38,0x7,0x39,0xc7,0x38,0xe7,0x7,0x38,
+0x39,0xc1,0xce,0xe,0x1d,0xc3,0x87,0x3b,0x8e,0x73,
+0x9c,0xe7,0x39,0xce,0x73,0x9c,0xe7,0x1c,0x73,0x9c,
+0xe3,0x9c,0x73,0x8e,0x73,0x9c,0xe3,0x8e,0x71,0xe7,
+0x1c,0xe1,0xce,0x1c,0xe1,0xce,0x1c,0xe0,0x70,0x38,
+0xc7,0x1c,0xe3,0x9c,0x73,0x8e,0xe3,0xbc,0xe7,0x1c,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0x80,0x6,
+0xc1,0xf0,0x2,0,0xee,0x60,0x70,0xe,0,0xe,
+0,0x7c,0x2,0x71,0xc1,0xc0,0xf8,0x3e,0x33,0x9c,
+0xf7,0xf8,0x38,0x1f,0x1c,0xf0,0,0xf,0x87,0xf8,
+0x7c,0xe,0xc,0xc6,0x30,0xc6,0x1f,0xf8,0xe0,0x3,
+0x81,0xcf,0xf8,0xff,0x8e,0x3f,0x3f,0xf9,0xc0,0x73,
+0xf8,0xe,0x1,0xd9,0xb9,0xcc,0xe7,0,0xe7,0xf0,
+0x70,0xe,0x7f,0xc0,0x3e,0x7,0x7,0x7,0xe,0xe0,
+0xed,0xb8,0x3f,0x1,0xf0,0xe,0xe,0x10,0xe0,0,
+0,0,0x3c,0xe1,0xce,0x3,0x87,0x38,0x63,0x8e,
+0x1c,0xe3,0x9c,0xe7,0xc1,0xce,0x73,0x9c,0x73,0x87,
+0x38,0x73,0x87,0x38,0x70,0x1c,0x71,0xce,0xe6,0x73,
+0x1f,0x1d,0xc0,0xe1,0xc3,0x7,0xf,0x30,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3,
+0x20,0xfe,0xc,0x67,0xfc,0x6,0x30,0x2,0x60,0x27,
+0xe7,0x70,0xff,0x9f,0x23,0xc2,0,0x1,0xff,0x7f,
+0xf8,0x1c,0x73,0xd8,0,0xc,0x7e,0x3b,0x86,0x67,
+0xc,0xdf,0xfe,0xdc,0,0x6,0x30,0x31,0x81,0x8c,
+0xc,0x60,0x63,0x3,0x18,0x39,0xff,0x1c,0,0x7f,
+0xc7,0xfc,0x7f,0xc7,0xfc,0x73,0x8e,0x77,0xf1,0xce,
+0x67,0x38,0x7,0x38,0x7,0x38,0x7,0x38,0x7,0x38,
+0x7,0x1f,0x87,0x70,0xe7,0x7,0x38,0x39,0xc1,0xce,
+0xe,0xf,0x83,0x87,0x3b,0x80,0xf0,0x3c,0xf,0x3,
+0xc0,0xf0,0x3c,0xf,0x1c,0xe0,0x38,0x67,0xc,0xe1,
+0x9c,0x33,0x9c,0xe3,0x9c,0x39,0xc7,0x38,0x73,0x87,
+0x38,0x73,0x87,0x38,0x70,0,0x71,0xe7,0x1c,0xe3,
+0x9c,0x73,0x8e,0x77,0x38,0x73,0xb8,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,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x3,0,0x6,0xc0,0x78,0x6,
+0xf0,0xc7,0xe0,0x70,0xe,0,0x7f,0xc0,0x7c,0x6,
+0x71,0xc1,0xc1,0xf0,0xf,0x73,0x80,0x77,0x9c,0x38,
+0x3b,0x8f,0xf0,0,0x1e,0,0,0x1e,0xe,0xc,
+0xcc,0x31,0xc7,0x1c,0x3c,0xe0,0x3,0x81,0xce,0,
+0xe0,0xe,0x3f,0x38,0x39,0xc0,0x73,0xbc,0xe,0x1,
+0xd9,0xb9,0xce,0xe7,0,0xe7,0,0x70,0xe,0x70,
+0xe0,0xf,0x7,0x7,0x7,0xe,0xe0,0x6d,0xb0,0x33,
+0,0xe0,0x1c,0xe,0x18,0xe0,0,0,0,0xfc,
+0xe1,0xce,0x3,0x87,0x3f,0xe3,0x8e,0x1c,0xe3,0x9c,
+0xe7,0xc1,0xce,0x73,0x9c,0x73,0x87,0x38,0x73,0x87,
+0x38,0x7f,0x1c,0x71,0xce,0xe7,0x77,0xe,0x1d,0xc1,
+0xc3,0x83,0x3,0x9f,0xf0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x33,0x20,0x38,0xc,
+0x60,0xe0,0x6,0x38,0x3,0x60,0x67,0xee,0xe0,0xff,
+0x9f,0x33,0x66,0,0x1,0xff,0x7e,0xf0,0x1c,0x71,
+0xd8,0xc0,0xc,0x7e,0x1d,0xc6,0xc7,0xd,0x99,0xbd,
+0x9c,0xe,0xe,0x38,0x71,0xc3,0x8e,0x1c,0x70,0xe3,
+0x87,0x1c,0x39,0xc0,0x1c,0,0x70,0x7,0,0x70,
+0x7,0,0x73,0x8e,0x73,0x81,0xce,0x77,0x38,0x7,
+0x38,0x7,0x38,0x7,0x38,0x7,0x38,0x7,0xf,0x7,
+0xe0,0xe7,0x7,0x38,0x39,0xc1,0xce,0xe,0x7,0x3,
+0x8f,0x39,0xc3,0xf0,0xfc,0x3f,0xf,0xc3,0xf0,0xfc,
+0x3f,0xfc,0xe0,0x3f,0xe7,0xfc,0xff,0x9f,0xf3,0x9c,
+0xe3,0x9c,0x39,0xc7,0x38,0x73,0x87,0x38,0x73,0x87,
+0x38,0x73,0xfe,0x77,0xe7,0x1c,0xe3,0x9c,0x73,0x8e,
+0x77,0x38,0x73,0xb8,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,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x3,0,0x3f,0xf0,0x5c,0xd,0xf8,0xc3,0xc0,
+0x70,0xe,0,0x7f,0xc0,0x7c,0x6,0x71,0xc1,0xc3,
+0xc0,0x7,0x7f,0xc0,0x77,0x1c,0x70,0x71,0xc7,0xb0,
+0,0x38,0,0,0x7,0xe,0xc,0xcc,0x61,0xff,
+0x1c,0x1c,0xf0,0x73,0x81,0xce,0,0xe0,0xe,0x7,
+0x38,0x39,0xdc,0x73,0x9e,0xe,0x1,0xd9,0xb9,0xc6,
+0xe7,0x81,0xe7,0,0x78,0xce,0x70,0x73,0x87,0x7,
+0x7,0x7,0x6,0xc0,0x6d,0xb0,0x73,0x80,0xe0,0x1c,
+0xe,0x18,0xe0,0,0,0x1,0xdc,0xe1,0xce,0x3,
+0x87,0x3f,0xe3,0x8e,0x1c,0xe3,0x9c,0xe7,0xe1,0xce,
+0x73,0x9c,0x73,0x87,0x38,0x73,0x87,0x38,0x1f,0x9c,
+0x71,0xce,0xe7,0x57,0x1f,0x1d,0xc3,0x81,0xc3,0x7,
+0x19,0xe0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x33,0x40,0x38,0xe,0xe7,0xfc,0x7,
+0x18,0x3,0x36,0x60,0xe,0xe0,0x1,0x9f,0x33,0x66,
+0,0,0x38,0,0,0x1c,0x70,0xd8,0xc0,0,
+0,0x1d,0xc0,0xcf,0x1,0x83,0x81,0xbc,0xe,0xf,
+0xf8,0x7f,0xc3,0xfe,0x1f,0xf0,0xff,0x87,0xfc,0x3f,
+0xc0,0x1e,0xe,0x70,0x7,0,0x70,0x7,0,0x73,
+0x8e,0x73,0x81,0xce,0x37,0x3c,0xf,0x3c,0xf,0x3c,
+0xf,0x3c,0xf,0x3c,0xf,0xf,0x7,0xc1,0xe7,0x7,
+0x38,0x39,0xc1,0xce,0xe,0x7,0x3,0xfe,0x39,0xc7,
+0x71,0xdc,0x77,0x1d,0xc7,0x71,0xdc,0x77,0,0xe0,
+0x3f,0xe7,0xfc,0xff,0x9f,0xf3,0x9c,0xe3,0x9c,0x39,
+0xc7,0x38,0x73,0x87,0x38,0x73,0x87,0x38,0x73,0xfe,
+0x7e,0xe7,0x1c,0xe3,0x9c,0x73,0x8e,0x77,0x38,0x73,
+0xb8,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,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x3f,0xf7,0x5c,0x9,0x98,0xc1,0xc0,0x70,0xe,0,
+0xe,0,0,0x4,0x71,0xc1,0xc3,0x81,0xc7,0x7f,
+0xdc,0x77,0x1c,0x70,0x71,0xc0,0x70,0,0x1e,0x7,
+0xf8,0x1e,0,0xc,0xcc,0x61,0xff,0x1c,0x1c,0x70,
+0x73,0x83,0x8e,0,0xe0,0x7,0x7,0x38,0x39,0xdc,
+0x73,0x8f,0xe,0x1,0xcf,0x39,0xc3,0xe3,0x81,0xc7,
+0,0x38,0xec,0x70,0x73,0x87,0x7,0x7,0x7,0x7,
+0xc0,0x7d,0xf0,0xe1,0xc0,0xe0,0x38,0xe,0x8,0xe0,
+0,0,0x3,0x9c,0xe1,0xce,0x3,0x87,0x38,0x3,
+0x8e,0x1c,0xe3,0x9c,0xe7,0x71,0xce,0x73,0x9c,0x73,
+0x87,0x38,0x73,0x87,0x38,0x3,0x9c,0x71,0xc7,0xc3,
+0xde,0x3b,0x8f,0x87,0,0xe3,0xe,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x73,0x40,0x70,0x1f,0xf0,0xe0,0xc3,0x98,0x1,0x9c,
+0xc0,0x7,0x70,0x1,0x80,0x1b,0x3c,0,0,0x38,
+0,0,0x1c,0x70,0xd8,0,0,0,0x3b,0x81,
+0x9b,0x3,0xf,0x3,0x6c,0xe,0xf,0xf8,0x7f,0xc3,
+0xfe,0x1f,0xf0,0xff,0x87,0xfc,0x7f,0xc0,0xe,0xe,
+0x70,0x7,0,0x70,0x7,0,0x73,0x8e,0x73,0x83,
+0x8e,0x1f,0x1c,0xe,0x1c,0xe,0x1c,0xe,0x1c,0xe,
+0x1c,0xe,0x1f,0x83,0x81,0xc7,0x7,0x38,0x39,0xc1,
+0xce,0xe,0x7,0x3,0xf8,0x39,0xce,0x73,0x9c,0xe7,
+0x39,0xce,0x73,0x9c,0xe7,0,0xe0,0x38,0x7,0,
+0xe0,0x1c,0x3,0x9c,0xe3,0x9c,0x39,0xc7,0x38,0x73,
+0x87,0x38,0x73,0x87,0x38,0x70,0,0x78,0xe7,0x1c,
+0xe3,0x9c,0x73,0x8e,0x3e,0x38,0x71,0xf0,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x3,0x80,0xd,0x87,0x5c,
+0x19,0x98,0xe3,0xe0,0x70,0xe,0,0xe,0xe,0,
+0xec,0x3b,0x81,0xc7,0x1,0xcf,0x3,0x9c,0xf7,0x9c,
+0xe0,0x71,0xdc,0xe1,0xc7,0xf,0x87,0xf8,0x7c,0xe,
+0xe,0xff,0xc3,0x83,0x9c,0x3c,0x78,0xe3,0x87,0x8e,
+0,0xe0,0x7,0x8f,0x38,0x39,0xde,0xf3,0x87,0x8e,
+0x1,0xcf,0x39,0xc3,0xe3,0xc3,0xc7,0,0x3c,0x7c,
+0x70,0x73,0xcf,0x7,0x3,0x8e,0x7,0xc0,0x38,0xe0,
+0xe1,0xc0,0xe0,0x70,0xe,0xc,0xe0,0,0,0x3,
+0x9c,0xf3,0x87,0x39,0xcf,0x1c,0xe3,0x87,0x3c,0xe3,
+0x9c,0xe7,0x39,0xce,0x73,0x9c,0x71,0xce,0x3c,0xe1,
+0xcf,0x38,0x73,0x9c,0x73,0xc7,0xc3,0xde,0x3b,0x8f,
+0x8e,0,0xe3,0xe,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x73,0x8c,0xe1,
+0x98,0x30,0xe0,0xc1,0xf8,0x1,0x80,0xc0,0x3,0xb8,
+0x1,0x80,0x18,0xc,0,0,0,0,0,0x1c,
+0xf0,0xd8,0,0,0,0x77,0x1,0x9f,0x83,0x1c,
+0x3,0x7e,0x1c,0x1c,0x1c,0xe0,0xe7,0x7,0x38,0x39,
+0xc1,0xce,0xe,0x71,0xc0,0xf,0x1c,0x70,0x7,0,
+0x70,0x7,0,0x73,0x8e,0x73,0x87,0x8e,0x1f,0x1e,
+0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x39,
+0xc7,0xc3,0xc3,0x8e,0x1c,0x70,0xe3,0x87,0x1c,0x7,
+0x3,0x80,0x39,0xce,0x73,0x9c,0xe7,0x39,0xce,0x73,
+0x9c,0xef,0x9c,0x73,0x9c,0xe3,0x9c,0x73,0x8e,0x73,
+0x9c,0xe3,0x8e,0x71,0xc7,0x1c,0xe1,0xce,0x1c,0xe1,
+0xce,0x1c,0xe0,0x70,0x31,0xc7,0x3c,0xe7,0x9c,0xf3,
+0x9e,0x3e,0x3c,0xe1,0xf0,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,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x3,0x80,0xd,0x83,0xf8,0x31,0xf8,0x7f,
+0x70,0x70,0xe,0,0xe,0xe,0,0xec,0x3f,0x81,
+0xc7,0xfc,0xfe,0x3,0x9f,0xe3,0xf8,0xe0,0x3f,0x9f,
+0xe1,0xc7,0x3,0xe0,0x1,0xf0,0xe,0xe,0x7b,0x83,
+0x83,0x9f,0xf8,0x3f,0xe3,0xff,0xf,0xfc,0xe0,0x3,
+0xff,0x38,0x39,0xcf,0xe3,0x83,0xcf,0xf9,0xc6,0x39,
+0xc1,0xe1,0xff,0x87,0,0x1f,0xf8,0x70,0x71,0xfe,
+0x7,0x3,0xfe,0x3,0x80,0x38,0xe1,0xc0,0xe0,0xe0,
+0x7f,0xee,0xc,0xe0,0,0,0x3,0xfc,0xff,0x87,
+0xf9,0xff,0x1f,0xe3,0x87,0xfc,0xe3,0x9c,0xe7,0x3d,
+0xce,0x73,0x9c,0x71,0xfe,0x3f,0xe1,0xff,0x38,0x7f,
+0x1f,0x7f,0xc3,0x81,0x8c,0x71,0xc7,0xf,0xf0,0xe3,
+0xe,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x71,0xfd,0xff,0x80,0,0xe0,
+0xc0,0x70,0,0xe3,0x80,0x1,0xdc,0,0,0xe,
+0x38,0,0x1,0xff,0,0,0x1f,0xf0,0xd8,0,
+0,0,0xee,0x3,0x3,0x6,0x1f,0x86,0xc,0x3c,
+0x1c,0x1c,0xe0,0xe7,0x7,0x38,0x39,0xc1,0xce,0xe,
+0x71,0xff,0x87,0xfc,0x7f,0xe7,0xfe,0x7f,0xe7,0xfe,
+0x73,0x8e,0x73,0xff,0xe,0xf,0xf,0xfc,0xf,0xfc,
+0xf,0xfc,0xf,0xfc,0xf,0xfc,0x70,0xee,0xff,0x83,
+0xfe,0x1f,0xf0,0xff,0x87,0xfc,0x7,0x3,0x80,0x3b,
+0xcf,0xf3,0xfc,0xff,0x3f,0xcf,0xf3,0xfc,0xff,0xfc,
+0x7f,0x9f,0xe3,0xfc,0x7f,0x8f,0xf3,0x9c,0xe3,0x8f,
+0xf1,0xc7,0x1f,0xe1,0xfe,0x1f,0xe1,0xfe,0x1f,0xe0,
+0x70,0x7f,0xc7,0xfc,0xff,0x9f,0xf3,0xfe,0x1c,0x3f,
+0xe0,0xe0,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3,
+0x80,0xd,0x81,0xf0,0x30,0xf0,0x3e,0x78,0x30,0xc,
+0,0,0xe,0,0xec,0xe,0x1,0xc7,0xfc,0x7c,
+0x3,0x8f,0xc1,0xf0,0xe0,0x1f,0xf,0x81,0xc7,0,
+0xe0,0x1,0xc0,0xe,0x7,0,0x3,0x83,0x9f,0xe0,
+0xf,0x83,0xfc,0xf,0xfc,0xe0,0x1,0xfb,0x38,0x39,
+0xc7,0xc3,0x81,0xef,0xf9,0xc6,0x39,0xc0,0xe0,0x7e,
+0x7,0,0x7,0xfc,0x70,0x70,0xfc,0x7,0,0xf8,
+0x3,0x80,0x38,0xe1,0xc0,0xe0,0xe0,0x7f,0xee,0xc,
+0xe0,0,0,0x1,0xdc,0xef,0x1,0xe0,0xf7,0x7,
+0x83,0x83,0xdc,0xe3,0x9c,0xe7,0x1d,0xce,0x73,0x9c,
+0x70,0x78,0x3b,0xc0,0xf7,0x38,0x3c,0xf,0x3d,0xc3,
+0x81,0x8c,0x71,0xc7,0xf,0xf0,0xe3,0xe,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x71,0xf9,0xdf,0,0,0xe0,0xc0,0x38,0,
+0x3e,0,0,0,0,0,0x3,0xe0,0,0x1,
+0xff,0,0,0x1f,0x70,0xd8,0,0,0,0,
+0x3,0x3,0x6,0x1f,0x86,0xc,0x38,0x1c,0x1c,0xe0,
+0xe7,0x7,0x38,0x39,0xc1,0xce,0xe,0x71,0xff,0x81,
+0xf0,0x7f,0xe7,0xfe,0x7f,0xe7,0xfe,0x73,0x8e,0x73,
+0xfc,0xe,0x7,0x3,0xf0,0x3,0xf0,0x3,0xf0,0x3,
+0xf0,0x3,0xf0,0,0xc,0x7e,0,0xf8,0x7,0xc0,
+0x3e,0x1,0xf0,0x7,0x3,0x80,0x3b,0x87,0x71,0xdc,
+0x77,0x1d,0xc7,0x71,0xdc,0x79,0xf0,0x1e,0x7,0x80,
+0xf0,0x1e,0x3,0xc3,0x9c,0xe3,0x83,0xc1,0xc7,0x7,
+0x80,0x78,0x7,0x80,0x78,0x7,0x80,0,0xcf,0x3,
+0xdc,0x7b,0x8f,0x71,0xee,0x1c,0x3b,0xc0,0xe0,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,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x40,0,0,0,0,0x38,0x1c,0,0,0x6,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x2,0,0,0,0,
+0,0x3,0xc0,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,
+0xc,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xe,0,0xe0,0,0,
+0,0,0,0,0,0,0,0,0,0x1c,
+0,0,0xe0,0,0,0,0,0,0,0x38,
+0,0x7,0,0,0,0,0,0,0,0,
+0x7,0,0,0xe3,0xe,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x71,0,
+0,0,0,0,0xc7,0x18,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x1c,0,0xd8,0x6,0,0,0,0,0,0,
+0,0,0,0x73,0x80,0,0,0,0,0,
+0,0,0,0,0,0,0x1,0x80,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,0x18,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,0x1c,0x38,0,0xe0,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x40,0,0,
+0,0,0x18,0x18,0,0,0xc,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x4,0,0,0,0,0,0x1,0xff,
+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,0xe,0,0xe0,0,0,0,0,0,
+0,0,0,0,0,0x7,0x38,0,0,0xe0,
+0,0,0,0,0,0,0x38,0,0x7,0,
+0,0,0,0,0,0,0,0x6,0,0,
+0xe3,0xe,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x71,0,0,0,0,
+0,0xc7,0x18,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x1c,0,0xd8,
+0x7,0,0,0,0,0,0,0,0,0,
+0x73,0x80,0,0,0,0,0,0,0,0,
+0,0,0,0x1,0xc0,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,0x1c,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,0x18,
+0x38,0,0xc0,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,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x1c,
+0x38,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,0x7f,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,0xf,
+0x83,0xe0,0x3,0xff,0,0,0,0,0,0,
+0,0,0x7,0xf8,0,0x3,0xe0,0,0,0,
+0,0,0,0x38,0,0x7,0,0,0,0,
+0,0,0,0,0x1e,0,0,0x73,0x1c,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x70,0,0,0,0,0,0xc3,0xf0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1c,0,0xd8,0x1,0x80,0,
+0,0,0,0,0,0,0,0x7f,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x60,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,0x6,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,0x78,0x38,0x3,0xc0,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xe,0x70,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,0xf,0x83,0xe0,0x3,
+0xff,0,0,0,0,0,0,0,0,0x1,
+0xe0,0,0x3,0xc0,0,0,0,0,0,0,
+0x38,0,0x7,0,0,0,0,0,0,0,
+0,0x1c,0,0,0x3b,0x38,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x70,
+0,0,0,0,0,0x1,0xe0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1c,0,0xd8,0xf,0x80,0,0,0,0,
+0,0,0,0,0x3f,0,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0xe0,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,0x3e,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,0x70,0x38,0x3,0x80,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,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,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,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,0xf,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x3,0xc0,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,0x3c,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,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,
+};
+
+static WORD HelveticaBold18_ch_ofst[225] = {
+0,5,10,18,29,39,55,69,73,80,
+87,96,107,112,119,124,129,139,149,159,
+169,179,189,199,209,219,229,235,241,252,
+262,273,283,301,314,327,341,355,367,379,
+393,406,411,421,435,446,462,476,492,504,
+520,533,545,556,569,582,599,611,624,635,
+641,646,652,662,672,677,687,699,709,721,
+732,739,751,762,767,772,782,787,802,813,
+825,837,849,856,866,872,883,892,905,914,
+923,933,941,946,954,965,970,975,980,985,
+990,995,1000,1005,1010,1015,1020,1025,1030,1035,
+1040,1045,1050,1055,1060,1065,1070,1075,1080,1085,
+1090,1095,1100,1105,1110,1115,1120,1125,1130,1135,
+1141,1151,1162,1173,1183,1188,1198,1205,1220,1228,
+1239,1250,1257,1272,1279,1286,1297,1303,1309,1314,
+1325,1335,1339,1346,1352,1360,1371,1386,1401,1416,
+1426,1439,1452,1465,1478,1491,1504,1522,1536,1548,
+1560,1572,1584,1589,1595,1600,1605,1619,1633,1649,
+1665,1681,1697,1713,1724,1740,1753,1766,1779,1792,
+1805,1817,1827,1837,1847,1857,1867,1877,1887,1903,
+1913,1924,1935,1946,1957,1962,1967,1973,1978,1990,
+2001,2013,2025,2037,2049,2061,2072,2084,2095,2106,
+2117,2128,2137,2149,2158,
+};
+
+static struct font_hdr HelveticaBold18_font = {
+STPROP, 18, "AdobeHelv-B-R-N--18-180-75-75-P", 32, 255,
+23, 18, 11, 5, 5,
+18, 18, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+HelveticaBold18_ch_ofst, HelveticaBold18_data,
+357, 23,
+NULL,
+0, 0,   /* x/y offset */
+25,        /* lineHeight */
+16,	   /* psHeight */
+};
+
+MgFont *mgHelveticaBold18Font()
+{
+return &HelveticaBold18_font;
+}
+
+MgFont *mgLargeBoldFont()
+{
+return &HelveticaBold18_font;
+}
diff --git a/lib/font/mgHelveticaBold24.c b/lib/font/mgHelveticaBold24.c
new file mode 100644
index 0000000..30d013c
--- /dev/null
+++ b/lib/font/mgHelveticaBold24.c
@@ -0,0 +1,1277 @@
+
+/* HelveticaBold24.c - compiled data for font AdobeHelv-B-R-N--24-240-75-75-P */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/helvB24.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE HelveticaBold24_data[12209] = {
+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,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,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,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x3,0x80,0,0x3,0x80,0x7,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x38,0,0,0x70,0x3,0x80,0,
+0x1,0xc0,0x18,0xe0,0,0,0,0,0,0,
+0x70,0,0,0x70,0,0x70,0,0x3c,0xc0,0,
+0,0,0,0,0,0,0x38,0,0,0x38,
+0,0x78,0,0,0,0,0x38,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,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,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,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,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,0x1,0xc0,0,0x7,0,
+0xf,0x80,0x7,0x98,0x3,0x9c,0,0x3c,0,0,
+0,0,0,0,0x1c,0,0,0xe0,0x7,0xc0,
+0x1c,0xe0,0xe0,0x39,0xf3,0xb8,0,0,0x3,0x8c,
+0,0x38,0,0,0xe0,0,0xf8,0,0x7f,0xc0,
+0xe,0x38,0,0,0,0,0,0x1c,0,0,
+0x70,0,0xfc,0,0x38,0xe0,0,0x70,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,
+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,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,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,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,0xe0,0,0xe,
+0,0x1d,0xc0,0xf,0xf8,0x3,0x9c,0,0x66,0,
+0,0,0,0,0,0xe,0,0x1,0xc0,0xe,
+0xe0,0x1c,0xe0,0x70,0x73,0xbb,0xb8,0,0,0x7,
+0xfc,0,0x1c,0,0x1,0xc0,0x1,0xdc,0,0x67,
+0x80,0xe,0x38,0,0,0,0,0,0xe,0,
+0,0xe0,0x1,0xce,0,0x38,0xe0,0,0xe0,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,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,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,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,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,0x70,0,
+0x1c,0,0x38,0xe0,0xc,0xf0,0,0,0,0x66,
+0,0,0,0,0,0,0x7,0,0x3,0x80,
+0x1c,0x70,0,0,0x38,0xe7,0x1c,0,0,0,
+0x6,0x78,0,0xe,0,0x3,0x80,0x3,0x8e,0,
+0,0,0,0,0,0,0,0,0,0x7,
+0,0x1,0xc0,0x3,0x87,0,0,0,0x1,0xc0,
+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,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,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,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,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,
+0,0,0,0,0,0,0,0,0,0,
+0x66,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,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,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,0xe1,0xb0,0,0,
+0x60,0,0,0,0,0,0x18,0xc,0xc0,0x18,
+0,0,0,0,0,0x1c,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3,
+0xf0,0,0,0,0x1,0xe0,0xf,0xfe,0,0x3f,
+0x80,0xff,0xe0,0x1f,0xfe,0x1f,0xfe,0x3,0xf8,0x7,
+0,0x70,0xe0,0x3,0x87,0x1,0xe1,0xc0,0x3,0x80,
+0x3,0x87,0,0x70,0xf,0xe0,0x1f,0xfc,0,0xfe,
+0x1,0xff,0xc0,0xf,0xc1,0xff,0xfc,0xe0,0xe,0x38,
+0x1,0xce,0x7,0x3,0x9c,0,0xe7,0,0x73,0xff,
+0xf3,0xe7,0x1,0xf0,0x38,0,0,0x38,0,0,
+0x70,0,0,0,0x7,0,0,0xf,0,0,
+0x38,0,0x70,0xe1,0xc0,0x7,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,0xe1,0xc3,0x80,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,
+0x70,0x3f,0,0,0,0,0x3e,0,0,0,
+0,0,0,0,0x3f,0x80,0,0,0,0,
+0xe,0,0,0xf,0xe0,0,0,0x7,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0xf0,0,0x3c,0,0xf,0,0x3,0xc0,0,0xf0,
+0,0x3c,0,0xf,0xff,0xe0,0x1f,0xc0,0x7f,0xf8,
+0x7f,0xf8,0x7f,0xf8,0x7f,0xf8,0x70,0xe0,0xe0,0xe1,
+0xff,0xc0,0x38,0x3,0x80,0x7f,0,0xf,0xe0,0x1,
+0xfc,0,0x3f,0x80,0x7,0xf0,0,0,0x1,0xfc,
+0x33,0x80,0x38,0x70,0x7,0xe,0,0xe1,0xc0,0x1c,
+0x78,0xf,0x1c,0,0x1,0xe0,0xe,0,0x3,0x80,
+0x38,0x3,0xcc,0,0,0x1e,0,0,0,0,
+0,0x1c,0,0x7,0,0x70,0,0,0xe0,0x31,
+0xc0,0x7,0,0x3,0xcc,0x7,0,0x1,0xc0,0x1c,
+0x1,0xe6,0,0,0,0,0,0,0xe0,0,
+0x1c,0,0xe0,0,0,0,0x70,0x70,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,0xe1,0xb0,0x33,
+0x3,0xf8,0,0x3,0x80,0xf,0x80,0x18,0x1c,0xe0,
+0x18,0,0,0,0,0,0x1c,0x7e,0,0x70,
+0x1f,0,0xf8,0,0x70,0xff,0xc0,0xf8,0x7f,0xf8,
+0x3c,0x3,0xf0,0,0,0,0,0,0,0,
+0xf,0xf8,0,0xff,0x80,0x1,0xe0,0xf,0xff,0x80,
+0xff,0xe0,0xff,0xf8,0x1f,0xfe,0x1f,0xfe,0xf,0xfe,
+0x7,0,0x70,0xe0,0x3,0x87,0x3,0xc1,0xc0,0x3,
+0xc0,0x7,0x87,0x80,0x70,0x3f,0xf8,0x1f,0xff,0x3,
+0xff,0x81,0xff,0xf0,0x3f,0xf1,0xff,0xfc,0xe0,0xe,
+0x38,0x1,0xce,0x7,0x3,0x9e,0x1,0xe7,0x80,0xf3,
+0xff,0xf3,0xe7,0x1,0xf0,0x38,0,0,0x1c,0,
+0,0x70,0,0,0,0x7,0,0,0x1f,0,
+0,0x38,0,0x70,0xe1,0xc0,0x7,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0xe,0,0,0,0,0,0,0,0,0,
+0,0,0x1,0xc1,0xc1,0xc0,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,0xfc,0,0,0x70,
+0x1c,0x70,0x7f,0x87,0x70,0,0,0x7f,0,0,
+0,0,0,0,0,0x3f,0x8f,0,0,0x1e,
+0x3c,0x1c,0,0,0x3f,0xe0,0,0x6,0xf,0xc0,
+0,0xc,0x6,0x1,0x80,0xc0,0x78,0x18,0,0,
+0,0xf0,0,0x3c,0,0xf,0,0x3,0xc0,0,
+0xf0,0,0x3c,0,0xf,0xff,0xe0,0x7f,0xf0,0x7f,
+0xf8,0x7f,0xf8,0x7f,0xf8,0x7f,0xf8,0x70,0xe0,0xe0,
+0xe1,0xff,0xf0,0x3c,0x3,0x81,0xff,0xc0,0x3f,0xf8,
+0x7,0xff,0,0xff,0xe0,0x1f,0xfc,0,0,0x7,
+0xff,0x73,0x80,0x38,0x70,0x7,0xe,0,0xe1,0xc0,
+0x1c,0x38,0xe,0x1c,0,0x7,0xf8,0x7,0,0x7,
+0,0x7c,0x7,0xfc,0xe,0xe0,0x33,0,0,0,
+0,0,0xe,0,0xe,0,0xf8,0xe,0x70,0x70,
+0x73,0xe7,0x71,0xce,0x7,0xfc,0x3,0x80,0x3,0x80,
+0x3e,0x3,0xfe,0x7,0x70,0,0,0,0,0x70,
+0,0x38,0x1,0xf0,0x7,0x70,0,0xe0,0x70,0,
+0x39,0xc0,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,0xe1,0xb0,
+0x33,0x7,0xfc,0x1f,0x3,0x80,0x1f,0xc0,0x18,0x38,
+0x70,0xdb,0,0,0,0,0,0x18,0xff,0,
+0x70,0x7f,0xc3,0xfe,0,0xf0,0xff,0xc3,0xfe,0x7f,
+0xf8,0xff,0xf,0xf8,0,0,0,0,0,0,
+0,0xf,0x3c,0x3,0xff,0xe0,0x3,0xf0,0xe,0x7,
+0x81,0xf1,0xf0,0xe0,0x7c,0x1c,0,0x1c,0,0x1f,
+0x1f,0x7,0,0x70,0xe0,0x3,0x87,0x7,0x81,0xc0,
+0x3,0xc0,0x7,0x87,0x80,0x70,0x7c,0x7c,0x1c,0x7,
+0x7,0xc7,0xc1,0xc0,0x70,0x78,0xf8,0x7,0,0xe0,
+0xe,0x3c,0x3,0xce,0x7,0x3,0x8f,0x3,0xc3,0x80,
+0xe0,0,0xf3,0x83,0,0x70,0x7c,0,0,0xe,
+0,0,0x70,0,0,0,0x7,0,0,0x1c,
+0,0,0x38,0,0x70,0xe1,0xc0,0x7,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xe,0,0,0,0,0,0,0,0,
+0,0,0,0x3,0x81,0xc0,0xe0,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,0x1,0xfe,0,0,
+0x70,0x1c,0x70,0xf3,0xc7,0x70,0x1f,0xc0,0x63,0,
+0,0,0,0,0xf,0xe0,0,0x19,0x80,0,
+0x3f,0x7e,0x38,0,0,0x7c,0xc0,0,0x6,0x1c,
+0xe0,0,0xc,0x6,0x1,0x80,0xc0,0xfc,0x18,0,
+0,0x1,0xf8,0,0x7e,0,0x1f,0x80,0x7,0xe0,
+0x1,0xf8,0,0x7e,0,0x1f,0xc0,0,0xf8,0xf8,
+0x70,0,0x70,0,0x70,0,0x70,0,0x70,0xe0,
+0xe0,0xe1,0xc0,0xf8,0x3c,0x3,0x83,0xe3,0xe0,0x7c,
+0x7c,0xf,0x8f,0x81,0xf1,0xf0,0x3e,0x3e,0,0,
+0xf,0x8f,0xe3,0x80,0x38,0x70,0x7,0xe,0,0xe1,
+0xc0,0x1c,0x3c,0x1e,0x1c,0,0xf,0x38,0x3,0x80,
+0xe,0,0xee,0x6,0x78,0xe,0xe0,0x33,0,0,
+0,0,0,0x7,0,0x1c,0x1,0xdc,0xe,0x70,
+0x38,0xe7,0x77,0x70,0xf8,0x6,0x78,0x1,0xc0,0x7,
+0,0x77,0x3,0x3c,0x7,0x70,0,0,0,0,
+0x38,0,0x70,0x3,0xb8,0x7,0x70,0x1,0xc0,0x70,
+0,0x39,0xc0,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,0xe1,
+0xb0,0x33,0xf,0x6e,0x3f,0x87,0,0x3d,0xe0,0x18,
+0x38,0x70,0xff,0,0,0,0,0,0x19,0xe7,
+0x80,0xf0,0x71,0xe3,0x8e,0,0xf0,0xe0,0x7,0x8e,
+0,0x78,0xe7,0xf,0x3c,0,0,0,0,0,
+0,0,0x1e,0x1c,0x7,0xc0,0xf8,0x3,0xf0,0xe,
+0x1,0xc3,0xc0,0x78,0xe0,0x1e,0x1c,0,0x1c,0,
+0x3c,0x7,0x87,0,0x70,0xe0,0x3,0x87,0xf,0x1,
+0xc0,0x3,0xe0,0xf,0x87,0xc0,0x70,0xf0,0x1e,0x1c,
+0x3,0x8f,0x1,0xe1,0xc0,0x38,0xf0,0x38,0x7,0,
+0xe0,0xe,0x1c,0x3,0x8e,0x7,0x3,0x87,0x3,0x83,
+0xc1,0xe0,0x1,0xe3,0x83,0,0x70,0x6c,0,0,
+0x7,0,0,0x70,0,0,0,0x7,0,0,
+0x1c,0,0,0x38,0,0,0x1,0xc0,0x7,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0xe,0,0,0,0,0,0,0,
+0,0,0,0,0x3,0x81,0xc0,0xe0,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,0x1,0x83,0x87,0,
+0,0x38,0x38,0x70,0xe1,0xc0,0,0x78,0xf0,0xf,
+0,0,0,0,0,0x3c,0x78,0,0x30,0xc0,
+0,0x33,0x66,0x70,0,0,0x7c,0xc0,0,0x1e,
+0x18,0x60,0,0x3c,0xc,0x7,0x81,0x80,0xcc,0x30,
+0,0,0x1,0xf8,0,0x7e,0,0x1f,0x80,0x7,
+0xe0,0x1,0xf8,0,0x7e,0,0x19,0xc0,0x1,0xe0,
+0x3c,0x70,0,0x70,0,0x70,0,0x70,0,0x70,
+0xe0,0xe0,0xe1,0xc0,0x3c,0x3e,0x3,0x87,0x80,0xf0,
+0xf0,0x1e,0x1e,0x3,0xc3,0xc0,0x78,0x78,0xf,0,
+0,0x1e,0x1,0xc3,0x80,0x38,0x70,0x7,0xe,0,
+0xe1,0xc0,0x1c,0x1c,0x1c,0x1c,0,0xe,0x1c,0x1,
+0xc0,0x1c,0x1,0xc7,0,0,0,0,0x33,0,
+0,0,0,0,0x3,0x80,0x38,0x3,0x8e,0,
+0,0x1d,0xce,0x38,0x1,0xf0,0,0,0,0xe0,
+0xe,0,0xe3,0x80,0,0,0,0,0,0,
+0,0x1c,0,0xe0,0x7,0x1c,0,0,0x3,0x80,
+0x70,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,
+0xe1,0xb0,0x33,0xe,0x6e,0x71,0xc7,0,0x38,0xe0,
+0x18,0x70,0x38,0x3c,0,0,0,0,0,0x39,
+0xc3,0x87,0xf0,0xe0,0xe7,0x7,0x1,0xf0,0xe0,0x7,
+0x7,0,0x71,0xc3,0x9e,0x1c,0,0,0,0,
+0,0,0,0x1c,0x1c,0xf,0,0x3c,0x7,0x30,
+0xe,0x1,0xc3,0x80,0x38,0xe0,0xe,0x1c,0,0x1c,
+0,0x38,0x3,0x87,0,0x70,0xe0,0x3,0x87,0x1e,
+0x1,0xc0,0x3,0xe0,0xf,0x87,0xc0,0x70,0xe0,0xe,
+0x1c,0x3,0x8e,0,0xe1,0xc0,0x38,0xe0,0x38,0x7,
+0,0xe0,0xe,0x1e,0x7,0x87,0xf,0x87,0x3,0x87,
+0x1,0xc1,0xc0,0x3,0xc3,0x83,0x80,0x70,0xee,0,
+0,0,0,0,0x70,0,0,0,0x7,0,
+0,0x1c,0,0,0x38,0,0,0x1,0xc0,0x7,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xe,0,0,0,0,0,0,
+0,0,0,0,0,0x3,0x81,0xc0,0xe0,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,0x1,0x83,0x87,
+0xc,0x3,0x38,0x38,0x70,0xf1,0xc0,0,0xe0,0x38,
+0x3f,0,0,0,0,0,0x70,0x1c,0,0x30,
+0xc0,0,0x3,0x6,0,0,0,0xfc,0xc0,0,
+0x1e,0x18,0x60,0,0x3c,0xc,0x7,0x81,0x80,0xc,
+0x30,0,0,0x3,0x98,0,0xe6,0,0x39,0x80,
+0xe,0x60,0x3,0x98,0,0xe6,0,0x39,0xc0,0x1,
+0xc0,0x1c,0x70,0,0x70,0,0x70,0,0x70,0,
+0x70,0xe0,0xe0,0xe1,0xc0,0x1c,0x3e,0x3,0x87,0,
+0x70,0xe0,0xe,0x1c,0x1,0xc3,0x80,0x38,0x70,0x7,
+0,0,0x1c,0x3,0xc3,0x80,0x38,0x70,0x7,0xe,
+0,0xe1,0xc0,0x1c,0x1e,0x3c,0x1f,0xfc,0xe,0x1c,
+0,0,0,0,0,0,0,0,0,0x1e,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x6,0x18,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x70,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,0xe1,0x20,0x33,0xe,0x6e,0x60,0xce,0,0x38,
+0xe0,0x10,0x70,0x38,0x66,0,0,0,0,0,
+0x31,0xc3,0x87,0xf0,0xe0,0x77,0x7,0x1,0xf0,0xe0,
+0xe,0x7,0,0xe1,0xc3,0x9c,0xe,0x38,0x70,0,
+0,0,0,0,0x1c,0x3c,0x1e,0,0x1c,0x7,
+0x38,0xe,0x1,0xc7,0x80,0,0xe0,0xf,0x1c,0,
+0x1c,0,0x78,0,0x7,0,0x70,0xe0,0x3,0x87,
+0x3c,0x1,0xc0,0x3,0xf0,0x1f,0x87,0xe0,0x71,0xe0,
+0xf,0x1c,0x3,0x9e,0,0xf1,0xc0,0x38,0xe0,0,
+0x7,0,0xe0,0xe,0xe,0x7,0x7,0xf,0x87,0x1,
+0xce,0x1,0xe3,0xc0,0x7,0x83,0x81,0x80,0x71,0xc7,
+0,0,0,0x7,0xe0,0x77,0xc0,0x3f,0x1,0xf7,
+0x1,0xe0,0x7f,0x7,0xdc,0x3b,0xc0,0x70,0xe1,0xc3,
+0xc7,0xe,0xf3,0xe0,0x77,0xc0,0x1e,0x3,0xbe,0x1,
+0xf7,0xe,0x61,0xf8,0x3f,0x8e,0xe,0x38,0x1d,0xc1,
+0xc1,0xdc,0x1c,0xe0,0x39,0xff,0xc3,0x81,0xc0,0xe0,
+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,0x38,0x1f,0x83,
+0x80,0xe,0xf7,0x1c,0x70,0x70,0x78,0,0x1,0xc0,
+0x1c,0x73,0,0,0,0,0,0xe0,0xe,0,
+0x30,0xc0,0,0x7,0x1c,0,0x38,0x38,0xfc,0xc0,
+0,0x6,0x18,0x60,0,0xc,0x18,0x1,0x83,0,
+0x38,0x60,0,0xe0,0x3,0x9c,0,0xe7,0,0x39,
+0xc0,0xe,0x70,0x3,0x9c,0,0xe7,0,0x39,0xc0,
+0x3,0xc0,0,0x70,0,0x70,0,0x70,0,0x70,
+0,0x70,0xe0,0xe0,0xe1,0xc0,0x1e,0x3f,0x3,0x8f,
+0,0x79,0xe0,0xf,0x3c,0x1,0xe7,0x80,0x3c,0xf0,
+0x7,0x80,0,0x3c,0x7,0xe3,0x80,0x38,0x70,0x7,
+0xe,0,0xe1,0xc0,0x1c,0xe,0x38,0x1f,0xff,0xe,
+0x1c,0xf,0xc0,0x3f,0,0xfc,0x3,0xf0,0xf,0xc0,
+0x3f,0,0xfc,0x78,0x3,0xf0,0xf,0,0x3c,0,
+0xf0,0x3,0xc0,0x70,0xe1,0xc1,0xc0,0x7c,0xe,0xf8,
+0x3,0xc0,0xf,0,0x3c,0,0xf0,0x3,0xc0,0,
+0,0x1e,0x33,0x83,0x87,0x7,0xe,0xe,0x1c,0x1c,
+0x70,0x1c,0x77,0xc1,0xc0,0x70,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,0xe0,0x1,0xff,0xcf,0x60,0x60,0xce,0,
+0x38,0xe0,0,0x60,0x18,0x66,0x1,0xc0,0,0,
+0,0x33,0x81,0xc0,0x70,0xe0,0x77,0x7,0x3,0x70,
+0xe0,0xe,0,0,0xe1,0xc3,0x9c,0xe,0x38,0x70,
+0,0xe0,0,0x1c,0,0,0x38,0x3c,0x3e,0xce,
+0x7,0x38,0xe,0x1,0xc7,0,0,0xe0,0x7,0x1c,
+0,0x1c,0,0x70,0,0x7,0,0x70,0xe0,0x3,
+0x87,0x78,0x1,0xc0,0x3,0xb0,0x1b,0x87,0x70,0x71,
+0xc0,0x7,0x1c,0x3,0x9c,0,0x71,0xc0,0x38,0xf0,
+0,0x7,0,0xe0,0xe,0xe,0x7,0x7,0xd,0x87,
+0x1,0xfe,0,0xe3,0x80,0x7,0x83,0x81,0x80,0x71,
+0xc7,0,0,0,0xf,0xf0,0x7f,0xe0,0x7f,0x83,
+0xff,0x7,0xf8,0x7f,0xf,0xfc,0x3f,0xf0,0x70,0xe1,
+0xc7,0x87,0xf,0xff,0xf0,0x7f,0xe0,0x7f,0x83,0xff,
+0x3,0xff,0xe,0xe3,0xfc,0x3f,0x8e,0xe,0x38,0x1d,
+0xc1,0xc1,0xde,0x3c,0xe0,0x39,0xff,0xc3,0x81,0xc0,
+0xe0,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,0x38,0x3f,
+0xc3,0xc0,0x7,0xfe,0x1c,0x70,0x70,0x3c,0,0x1,
+0x8f,0x8c,0x63,0,0,0,0,0,0xcf,0xc6,
+0,0x19,0x80,0x70,0x1e,0x1c,0,0x38,0x38,0xfc,
+0xc0,0,0x6,0x1c,0xe0,0,0xc,0x18,0x1,0x83,
+0,0x38,0x60,0,0xe0,0x3,0x9c,0,0xe7,0,
+0x39,0xc0,0xe,0x70,0x3,0x9c,0,0xe7,0,0x39,
+0xc0,0x3,0x80,0,0x70,0,0x70,0,0x70,0,
+0x70,0,0x70,0xe0,0xe0,0xe1,0xc0,0xe,0x3b,0x83,
+0x8e,0,0x39,0xc0,0x7,0x38,0,0xe7,0,0x1c,
+0xe0,0x3,0x88,0x4,0x38,0xe,0xe3,0x80,0x38,0x70,
+0x7,0xe,0,0xe1,0xc0,0x1c,0xf,0x78,0x1c,0x7,
+0xe,0x1c,0x1f,0xe0,0x7f,0x81,0xfe,0x7,0xf8,0x1f,
+0xe0,0x7f,0x81,0xff,0xfe,0x7,0xf8,0x3f,0xc0,0xff,
+0x3,0xfc,0xf,0xf0,0x70,0xe1,0xc1,0xc1,0xfe,0xf,
+0xfc,0xf,0xf0,0x3f,0xc0,0xff,0x3,0xfc,0xf,0xf0,
+0x7,0,0x7f,0xe3,0x83,0x87,0x7,0xe,0xe,0x1c,
+0x1c,0x70,0x1c,0x7f,0xe1,0xc0,0x70,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,0xe0,0x1,0xff,0xc7,0xe0,0x71,0xdc,
+0,0x1d,0xc0,0,0xe0,0x1c,0,0x1,0xc0,0,
+0,0,0x73,0x81,0xc0,0x70,0,0x70,0x7,0x7,
+0x70,0xff,0xe,0,0x1,0xc1,0xc3,0x9c,0xe,0x38,
+0x70,0x3,0xe0,0,0x1f,0,0,0x78,0x38,0x7f,
+0xce,0xe,0x1c,0xe,0x3,0x87,0,0,0xe0,0x7,
+0x1c,0,0x1c,0,0x70,0,0x7,0,0x70,0xe0,
+0x3,0x87,0xf0,0x1,0xc0,0x3,0xb8,0x3b,0x87,0x70,
+0x71,0xc0,0x7,0x1c,0x7,0x1c,0,0x71,0xc0,0x70,
+0x7c,0,0x7,0,0xe0,0xe,0xf,0xf,0x7,0x1d,
+0xc7,0,0xfc,0,0xf7,0x80,0xf,0x3,0x81,0xc0,
+0x73,0x83,0x80,0,0,0x1c,0x78,0x7c,0xf0,0xf3,
+0xc7,0x9f,0xf,0x3c,0x1c,0x1e,0x7c,0x3c,0x70,0x70,
+0xe1,0xcf,0x7,0xf,0x3e,0x78,0x78,0xe0,0xf3,0xc3,
+0xe7,0x87,0x9f,0xf,0xe7,0x9e,0xe,0xe,0xe,0x38,
+0x1c,0xc1,0xc1,0x8e,0x38,0x70,0x38,0x3,0x83,0x81,
+0xc0,0xe0,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,0x38,
+0x7b,0xe1,0xc0,0x3,0x9c,0xe,0xe0,0x70,0xfe,0,
+0x3,0x9c,0xce,0x7f,0x80,0,0,0,0x1,0xcc,
+0x67,0,0xf,0,0x70,0x38,0x6,0,0x38,0x38,
+0xfc,0xc0,0,0x6,0xf,0xc0,0,0xc,0x30,0x1,
+0x86,0,0xc,0xc0,0,0xe0,0x7,0xe,0x1,0xc3,
+0x80,0x70,0xe0,0x1c,0x38,0x7,0xe,0x1,0xc3,0x80,
+0x71,0xc0,0x3,0x80,0,0x70,0,0x70,0,0x70,
+0,0x70,0,0x70,0xe0,0xe0,0xe1,0xc0,0xe,0x3b,
+0x83,0x8e,0,0x39,0xc0,0x7,0x38,0,0xe7,0,
+0x1c,0xe0,0x3,0x9c,0xe,0x38,0x1c,0xe3,0x80,0x38,
+0x70,0x7,0xe,0,0xe1,0xc0,0x1c,0x7,0x70,0x1c,
+0x3,0x8e,0x38,0x38,0xf0,0xe3,0xc3,0x8f,0xe,0x3c,
+0x38,0xf0,0xe3,0xc3,0x8f,0xcf,0xf,0x3c,0x79,0xe1,
+0xe7,0x87,0x9e,0x1e,0x78,0x70,0xe1,0xc1,0xc3,0xcf,
+0xf,0x1c,0x1e,0x78,0x79,0xe1,0xe7,0x87,0x9e,0x1e,
+0x78,0x7,0,0xf3,0xc3,0x83,0x87,0x7,0xe,0xe,
+0x1c,0x1c,0x38,0x1c,0x7c,0xf0,0xe0,0x70,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,0xe0,0,0x66,0x3,0xe0,0x3f,
+0x9c,0,0xf,0x80,0,0xe0,0x1c,0,0x1,0xc0,
+0,0,0,0x73,0x81,0xc0,0x70,0,0xe0,0xe,
+0x6,0x70,0xff,0x8e,0xf0,0x1,0xc0,0xe7,0x1c,0xe,
+0,0,0xf,0x80,0,0x7,0xc0,0,0xf0,0x78,
+0xe3,0x8e,0xe,0x1c,0xf,0xff,0x7,0,0,0xe0,
+0x7,0x1f,0xfc,0x1f,0xfc,0x70,0,0x7,0xff,0xf0,
+0xe0,0x3,0x87,0xf0,0x1,0xc0,0x3,0x98,0x33,0x87,
+0x38,0x71,0xc0,0x7,0x1f,0xff,0x1c,0,0x71,0xff,
+0xf0,0x3f,0xc0,0x7,0,0xe0,0xe,0x7,0xe,0x3,
+0x1d,0xc6,0,0x78,0,0x77,0,0x1e,0x3,0x81,
+0xc0,0x73,0x83,0x80,0,0,0x1c,0x38,0x78,0x70,
+0xe1,0xc7,0xf,0xe,0x1c,0x1c,0x1c,0x3c,0x38,0x38,
+0x70,0xe1,0xde,0x7,0xe,0x1c,0x38,0x70,0x70,0xe1,
+0xc3,0xc3,0x87,0xf,0xf,0x7,0xe,0xe,0xe,0xe,
+0x1c,0x38,0xe3,0xe3,0x87,0x70,0x78,0x70,0x7,0x3,
+0x81,0xc0,0xe0,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,0x73,0x60,0xe0,0x7,0xe,0xe,0xe0,0x71,0xef,
+0,0x3,0x38,0xc6,0x3d,0x83,0xb8,0xff,0xf0,0x1,
+0x8c,0x63,0,0,0,0x70,0x30,0x66,0,0x38,
+0x38,0xfc,0xc0,0,0x6,0x7,0x87,0x70,0xc,0x30,
+0x1,0x86,0,0xcc,0xc0,0,0,0x7,0xe,0x1,
+0xc3,0x80,0x70,0xe0,0x1c,0x38,0x7,0xe,0x1,0xc3,
+0x80,0x71,0xff,0xc3,0x80,0,0x7f,0xf0,0x7f,0xf0,
+0x7f,0xf0,0x7f,0xf0,0x70,0xe0,0xe0,0xef,0xfc,0xe,
+0x39,0xc3,0x8e,0,0x39,0xc0,0x7,0x38,0,0xe7,
+0,0x1c,0xe0,0x3,0x8e,0x1c,0x38,0x38,0xe3,0x80,
+0x38,0x70,0x7,0xe,0,0xe1,0xc0,0x1c,0x7,0xf0,
+0x1c,0x3,0x8e,0xf0,0x38,0x70,0xe1,0xc3,0x87,0xe,
+0x1c,0x38,0x70,0xe1,0xc3,0x87,0x87,0xe,0x1c,0x70,
+0xe1,0xc3,0x87,0xe,0x1c,0x38,0x70,0xe1,0xc1,0xc3,
+0x87,0xe,0xe,0x1c,0x38,0x70,0xe1,0xc3,0x87,0xe,
+0x1c,0x38,0x7,0,0xe1,0xc3,0x83,0x87,0x7,0xe,
+0xe,0x1c,0x1c,0x3c,0x38,0x78,0x70,0xf0,0xe0,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,0xe0,0,0x66,0,0xf0,
+0x1f,0x38,0,0x1f,0,0,0xe0,0x1c,0,0x1,
+0xc0,0,0,0,0x63,0x81,0xc0,0x70,0x1,0xe0,
+0x7c,0xc,0x70,0xe3,0xcf,0xfc,0x3,0x80,0x7e,0x1e,
+0x1e,0,0,0x3e,0x1,0xff,0x81,0xf0,0,0xe0,
+0x71,0xc3,0x8e,0xe,0x1c,0xf,0xff,0x87,0,0,
+0xe0,0x7,0x1f,0xfc,0x1f,0xfc,0x70,0x3f,0xc7,0xff,
+0xf0,0xe0,0x3,0x87,0xf8,0x1,0xc0,0x3,0x9c,0x73,
+0x87,0x1c,0x71,0xc0,0x7,0x1f,0xfe,0x1c,0,0x71,
+0xff,0xe0,0x7,0xf0,0x7,0,0xe0,0xe,0x7,0xe,
+0x3,0x9d,0xce,0,0x78,0,0x7f,0,0x1e,0x3,
+0x80,0xc0,0x70,0,0,0,0,0,0x38,0x70,
+0x39,0xc0,0xe,0x7,0x1c,0xe,0x1c,0x38,0x1c,0x38,
+0x38,0x70,0xe1,0xfc,0x7,0xe,0x1c,0x38,0x70,0x71,
+0xc0,0xe3,0x81,0xce,0x7,0xe,0x7,0,0xe,0xe,
+0xe,0x1c,0x38,0xe3,0xe3,0x87,0xf0,0x38,0x70,0xf,
+0x3,0x81,0xc0,0xe0,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,0xe3,0x7,0xfe,0x7,0xe,0x3f,0xf8,0x1,
+0xc7,0x80,0x3,0x38,0x6,0,0x7,0x70,0xff,0xf0,
+0x1,0x8c,0x63,0,0,0,0x70,0x3f,0x7e,0,
+0x38,0x38,0x7c,0xc0,0,0x6,0,0x3,0xb8,0xc,
+0x61,0x81,0x8c,0xf0,0xfd,0x86,0,0,0x7,0xe,
+0x1,0xc3,0x80,0x70,0xe0,0x1c,0x38,0x7,0xe,0x1,
+0xc3,0x80,0x71,0xff,0xc3,0x80,0,0x7f,0xf0,0x7f,
+0xf0,0x7f,0xf0,0x7f,0xf0,0x70,0xe0,0xe0,0xef,0xfc,
+0xe,0x38,0xe3,0x8e,0,0x39,0xc0,0x7,0x38,0,
+0xe7,0,0x1c,0xe0,0x3,0x87,0x38,0x38,0x70,0xe3,
+0x80,0x38,0x70,0x7,0xe,0,0xe1,0xc0,0x1c,0x3,
+0xe0,0x1c,0x3,0x8e,0xf8,0,0x70,0x1,0xc0,0x7,
+0,0x1c,0,0x70,0x1,0xc0,0x7,0x3,0x9c,0,
+0xe0,0x73,0x81,0xce,0x7,0x38,0x1c,0x70,0xe1,0xc1,
+0xc7,0x3,0x8e,0xe,0x38,0x1c,0xe0,0x73,0x81,0xce,
+0x7,0x38,0x1c,0,0x1,0xc3,0xe3,0x83,0x87,0x7,
+0xe,0xe,0x1c,0x1c,0x1c,0x38,0x70,0x38,0x70,0xe0,
+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,0xe0,0,0x66,0,
+0x7c,0,0x38,0,0x3f,0x9c,0,0xe0,0x1c,0,
+0x1,0xc0,0x1,0xfc,0,0x63,0x81,0xc0,0x70,0x3,
+0xc0,0x7f,0x1c,0x70,0x1,0xcf,0x9e,0x3,0x80,0xff,
+0xf,0x3e,0,0,0xf8,0x1,0xff,0x80,0x7c,0x1,
+0xc0,0x71,0x87,0xe,0x1c,0xe,0xe,0x1,0xc7,0,
+0,0xe0,0x7,0x1c,0,0x1c,0,0x70,0x3f,0xc7,
+0,0x70,0xe0,0x3,0x87,0xbc,0x1,0xc0,0x3,0x9c,
+0x73,0x87,0x1c,0x71,0xc0,0x7,0x1c,0,0x1c,0,
+0x71,0xc0,0xf0,0,0xf8,0x7,0,0xe0,0xe,0x7,
+0x9e,0x3,0x98,0xce,0,0xfc,0,0x3e,0,0x3c,
+0x3,0x80,0xc0,0x70,0,0,0,0,0x1,0xf8,
+0x70,0x39,0xc0,0xe,0x7,0x1c,0xe,0x1c,0x38,0x1c,
+0x38,0x38,0x70,0xe1,0xf8,0x7,0xe,0x1c,0x38,0x70,
+0x71,0xc0,0xe3,0x81,0xce,0x7,0xe,0x7,0xe0,0xe,
+0xe,0xe,0x1c,0x38,0x63,0x63,0x3,0xe0,0x3c,0xf0,
+0x1e,0x7,0x1,0xc0,0x70,0xf1,0xc0,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,0x38,0xe6,0x7,0xfe,0x7,0xe,0x3f,0xf8,
+0x1,0xc3,0xc0,0x3,0x38,0x6,0x7f,0x8e,0xe0,0,
+0x33,0xf9,0x8f,0xc3,0,0,0x7,0xff,0x3f,0x3c,
+0,0x38,0x38,0x7c,0xc3,0x80,0x6,0x1f,0xe1,0xdc,
+0xc,0x63,0x81,0x8d,0xf8,0x79,0x8e,0,0xe0,0xe,
+0x7,0x3,0x81,0xc0,0xe0,0x70,0x38,0x1c,0xe,0x7,
+0x3,0x81,0xc0,0xe1,0xc0,0x3,0x80,0,0x70,0,
+0x70,0,0x70,0,0x70,0,0x70,0xe0,0xe0,0xe1,
+0xc0,0xe,0x38,0xe3,0x8e,0,0x39,0xc0,0x7,0x38,
+0,0xe7,0,0x1c,0xe0,0x3,0x83,0xf0,0x38,0xe0,
+0xe3,0x80,0x38,0x70,0x7,0xe,0,0xe1,0xc0,0x1c,
+0x3,0xe0,0x1c,0x3,0x8e,0x3c,0x3,0xf0,0xf,0xc0,
+0x3f,0,0xfc,0x3,0xf0,0xf,0xc0,0x3f,0x3,0x9c,
+0,0xe0,0x73,0x81,0xce,0x7,0x38,0x1c,0x70,0xe1,
+0xc1,0xc7,0x3,0x8e,0xe,0x38,0x1c,0xe0,0x73,0x81,
+0xce,0x7,0x38,0x1c,0,0x1,0xc7,0xe3,0x83,0x87,
+0x7,0xe,0xe,0x1c,0x1c,0x1e,0x78,0x70,0x38,0x79,
+0xe0,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,0xe0,0,0x66,
+0,0x7e,0,0x71,0xf0,0x7b,0xdc,0,0xe0,0x1c,
+0,0x1f,0xfc,0x1,0xfc,0,0xe3,0x81,0xc0,0x70,
+0x7,0x80,0x7,0x18,0x70,0,0xef,0xe,0x7,0x1,
+0xc3,0x8f,0xfe,0,0x3,0xc0,0,0,0,0xf,
+0x1,0xc0,0x73,0x87,0x1c,0x1c,0xe,0xe,0,0xe7,
+0,0,0xe0,0x7,0x1c,0,0x1c,0,0x70,0x1,
+0xc7,0,0x70,0xe0,0x3,0x87,0x1e,0x1,0xc0,0x3,
+0x8c,0x63,0x87,0xe,0x71,0xc0,0x7,0x1c,0,0x1c,
+0,0x71,0xc0,0x70,0,0x3c,0x7,0,0xe0,0xe,
+0x3,0x9c,0x3,0xb8,0xee,0x1,0xfe,0,0x3e,0,
+0x78,0x3,0x80,0xe0,0x70,0,0,0,0,0xf,
+0xf8,0x70,0x39,0xc0,0xe,0x7,0x1f,0xfe,0x1c,0x38,
+0x1c,0x38,0x38,0x70,0xe1,0xfc,0x7,0xe,0x1c,0x38,
+0x70,0x71,0xc0,0xe3,0x81,0xce,0x7,0xe,0x3,0xfc,
+0xe,0xe,0xe,0xe,0x70,0x67,0x73,0x1,0xc0,0x1c,
+0xe0,0x1c,0xe,0x1,0xc0,0x39,0xfd,0xc0,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,0x38,0xe6,0,0xe0,0x7,0xe,0x3,
+0x80,0x1,0xc1,0xc0,0x3,0x38,0x6,0x7f,0x9d,0xc0,
+0,0x33,0xf9,0x8d,0x83,0,0,0x7,0xff,0,
+0,0,0x38,0x38,0x3c,0xc3,0x80,0,0x1f,0xe0,
+0xee,0,0xc7,0x80,0x19,0x98,0x3,0x1e,0,0xe0,
+0xe,0x7,0x3,0x81,0xc0,0xe0,0x70,0x38,0x1c,0xe,
+0x7,0x3,0x81,0xc0,0xe1,0xc0,0x3,0x80,0,0x70,
+0,0x70,0,0x70,0,0x70,0,0x70,0xe0,0xe0,
+0xe1,0xc0,0xe,0x38,0x73,0x8e,0,0x39,0xc0,0x7,
+0x38,0,0xe7,0,0x1c,0xe0,0x3,0x81,0xe0,0x39,
+0xc0,0xe3,0x80,0x38,0x70,0x7,0xe,0,0xe1,0xc0,
+0x1c,0x1,0xc0,0x1c,0x7,0xe,0x1c,0x1f,0xf0,0x7f,
+0xc1,0xff,0x7,0xfc,0x1f,0xf0,0x7f,0xc1,0xff,0xff,
+0x9c,0,0xff,0xf3,0xff,0xcf,0xff,0x3f,0xfc,0x70,
+0xe1,0xc1,0xc7,0x3,0x8e,0xe,0x38,0x1c,0xe0,0x73,
+0x81,0xce,0x7,0x38,0x1c,0x7f,0xf1,0xce,0xe3,0x83,
+0x87,0x7,0xe,0xe,0x1c,0x1c,0xe,0x70,0x70,0x38,
+0x39,0xc0,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,0xe0,0x3,
+0xff,0x80,0x6f,0,0x73,0xf8,0x71,0xfc,0,0xe0,
+0x1c,0,0x1f,0xfc,0x1,0xfc,0,0xc3,0x81,0xc0,
+0x70,0x1f,0,0x3,0xb8,0x70,0,0xee,0x7,0x7,
+0x3,0x81,0xc3,0xee,0,0x3,0xc0,0,0,0,
+0xf,0x1,0xc0,0x73,0x86,0x1c,0x1f,0xfe,0xe,0,
+0xe7,0,0,0xe0,0x7,0x1c,0,0x1c,0,0x70,
+0x1,0xc7,0,0x70,0xe3,0x83,0x87,0xf,0x1,0xc0,
+0x3,0x8e,0xe3,0x87,0x6,0x71,0xc0,0x7,0x1c,0,
+0x1c,0,0x71,0xc0,0x38,0,0x1c,0x7,0,0xe0,
+0xe,0x3,0x9c,0x1,0xb8,0xec,0x1,0xce,0,0x1c,
+0,0x78,0x3,0x80,0x60,0x70,0,0,0,0,
+0x1f,0x38,0x70,0x39,0xc0,0xe,0x7,0x1f,0xfe,0x1c,
+0x38,0x1c,0x38,0x38,0x70,0xe1,0xde,0x7,0xe,0x1c,
+0x38,0x70,0x71,0xc0,0xe3,0x81,0xce,0x7,0xe,0,
+0x7e,0xe,0xe,0xe,0xe,0x70,0x77,0x77,0x3,0xe0,
+0x1c,0xe0,0x3c,0xe,0x1,0xc0,0x39,0xdf,0xc0,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,0x38,0xe6,0,0xe0,0x3,0x9c,
+0x3f,0xf8,0,0xe0,0xe0,0x3,0x38,0xc6,0,0x1d,
+0xc0,0,0x33,0xf9,0x8c,0xc3,0,0,0,0x70,
+0,0,0,0x38,0x38,0x1c,0xc3,0x80,0,0,
+0,0xee,0,0xc7,0x80,0x18,0x18,0x3,0x1e,0,
+0xe0,0xf,0xff,0x3,0xff,0xc0,0xff,0xf0,0x3f,0xfc,
+0xf,0xff,0x3,0xff,0xc0,0xff,0xc0,0x3,0x80,0,
+0x70,0,0x70,0,0x70,0,0x70,0,0x70,0xe0,
+0xe0,0xe1,0xc0,0xe,0x38,0x33,0x8e,0,0x39,0xc0,
+0x7,0x38,0,0xe7,0,0x1c,0xe0,0x3,0x81,0xe0,
+0x3b,0x80,0xe3,0x80,0x38,0x70,0x7,0xe,0,0xe1,
+0xc0,0x1c,0x1,0xc0,0x1f,0xff,0xe,0xe,0x3e,0x70,
+0xf9,0xc3,0xe7,0xf,0x9c,0x3e,0x70,0xf9,0xc3,0xe7,
+0xff,0x9c,0,0xff,0xf3,0xff,0xcf,0xff,0x3f,0xfc,
+0x70,0xe1,0xc1,0xc7,0x3,0x8e,0xe,0x38,0x1c,0xe0,
+0x73,0x81,0xce,0x7,0x38,0x1c,0x7f,0xf1,0xdc,0xe3,
+0x83,0x87,0x7,0xe,0xe,0x1c,0x1c,0xe,0x70,0x70,
+0x38,0x39,0xc0,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,0xe0,
+0x3,0xff,0x8e,0x67,0,0xe7,0x1c,0xe0,0xf8,0,
+0xe0,0x1c,0,0x1,0xc0,0,0,0,0xc3,0x81,
+0xc0,0x70,0x3c,0,0x3,0xbf,0xfc,0,0xee,0x7,
+0xf,0x3,0x81,0xc0,0xe,0,0,0xf8,0x1,0xff,
+0x80,0x7c,0x1,0xc0,0x73,0x8e,0x38,0x3f,0xff,0xe,
+0,0xe7,0x80,0x38,0xe0,0xf,0x1c,0,0x1c,0,
+0x78,0x1,0xc7,0,0x70,0xe3,0x83,0x87,0x7,0x81,
+0xc0,0x3,0x8e,0xe3,0x87,0x7,0x71,0xe0,0xf,0x1c,
+0,0x1e,0,0xf1,0xc0,0x39,0xc0,0x1c,0x7,0,
+0xe0,0xe,0x3,0x9c,0x1,0xb8,0xec,0x3,0x87,0,
+0x1c,0,0xf0,0x3,0x80,0x60,0x70,0,0,0,
+0,0x3c,0x38,0x70,0x39,0xc0,0xe,0x7,0x1c,0,
+0x1c,0x38,0x1c,0x38,0x38,0x70,0xe1,0xce,0x7,0xe,
+0x1c,0x38,0x70,0x71,0xc0,0xe3,0x81,0xce,0x7,0xe,
+0,0xf,0xe,0xe,0xe,0xe,0x70,0x36,0x36,0x3,
+0xe0,0xf,0xc0,0x78,0x7,0x1,0xc0,0x71,0xc7,0x80,
+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,0x38,0xe6,0,0xe0,0x7,
+0xfe,0x3f,0xf8,0,0xf0,0xe0,0x3,0x9c,0xc6,0,
+0xe,0xe0,0,0x30,0x1,0xcc,0x63,0,0,0,
+0x70,0,0,0,0x38,0x38,0xc,0xc0,0,0,
+0,0x1,0xdc,0x1,0x8d,0x80,0x30,0x38,0x6,0x36,
+0,0xe0,0x1f,0xff,0x87,0xff,0xe1,0xff,0xf8,0x7f,
+0xfe,0x1f,0xff,0x87,0xff,0xe1,0xff,0xc0,0x3,0xc0,
+0x1c,0x70,0,0x70,0,0x70,0,0x70,0,0x70,
+0xe0,0xe0,0xe1,0xc0,0x1e,0x38,0x3b,0x8f,0,0x79,
+0xe0,0xf,0x3c,0x1,0xe7,0x80,0x3c,0xf0,0x7,0x83,
+0xf0,0x3f,0x1,0xe3,0xc0,0x78,0x78,0xf,0xf,0x1,
+0xe1,0xe0,0x3c,0x1,0xc0,0x1f,0xfe,0xe,0xe,0x78,
+0x71,0xe1,0xc7,0x87,0x1e,0x1c,0x78,0x71,0xe1,0xc7,
+0x87,0,0x1c,0,0xe0,0x3,0x80,0xe,0,0x38,
+0,0x70,0xe1,0xc1,0xc7,0x3,0x8e,0xe,0x38,0x1c,
+0xe0,0x73,0x81,0xce,0x7,0x38,0x1c,0,0x1,0xf8,
+0xe3,0x83,0x87,0x7,0xe,0xe,0x1c,0x1c,0x7,0xe0,
+0x70,0x38,0x1f,0x80,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,0xcc,0xe,0x67,0,0xe6,0xc,0xe0,0x70,
+0,0xe0,0x1c,0,0x1,0xc0,0,0,0x1,0xc1,
+0xc3,0x80,0x70,0x78,0x7,0x3,0xbf,0xfd,0xc0,0xee,
+0x7,0xe,0x3,0x81,0xc0,0xe,0,0,0x3e,0x1,
+0xff,0x81,0xf0,0,0,0x73,0x8e,0x38,0x38,0x7,
+0xe,0,0xe3,0x80,0x38,0xe0,0xe,0x1c,0,0x1c,
+0,0x38,0x3,0xc7,0,0x70,0xe3,0x83,0x87,0x3,
+0xc1,0xc0,0x3,0x87,0xc3,0x87,0x3,0xf0,0xe0,0xe,
+0x1c,0,0xe,0x1e,0xe1,0xc0,0x39,0xc0,0x1c,0x7,
+0,0xf0,0x1e,0x1,0xf8,0x1,0xf0,0x7c,0x7,0x87,
+0x80,0x1c,0,0xe0,0x3,0x80,0x70,0x70,0,0,
+0,0,0x38,0x38,0x70,0x39,0xc0,0xe,0x7,0x1c,
+0,0x1c,0x38,0x1c,0x38,0x38,0x70,0xe1,0xcf,0x7,
+0xe,0x1c,0x38,0x70,0x71,0xc0,0xe3,0x81,0xce,0x7,
+0xe,0x7,0x7,0xe,0xe,0xe,0x7,0xe0,0x3e,0x3e,
+0x7,0x70,0xf,0xc0,0x70,0x3,0x81,0xc0,0xe0,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,0x38,0xec,0x1,0xc0,
+0xe,0xf7,0x3,0x80,0x70,0x78,0xe0,0x1,0x8f,0x8c,
+0,0x7,0x70,0,0x30,0,0xcc,0x36,0,0,
+0,0x70,0,0,0,0x38,0x38,0xc,0xc0,0,
+0,0,0x3,0xb8,0x1,0x99,0x80,0x30,0xf0,0x6,
+0x66,0x1,0xc0,0x1c,0x3,0x87,0,0xe1,0xc0,0x38,
+0x70,0xe,0x1c,0x3,0x87,0,0xe1,0xc1,0xc0,0x1,
+0xc0,0x1c,0x70,0,0x70,0,0x70,0,0x70,0,
+0x70,0xe0,0xe0,0xe1,0xc0,0x1c,0x38,0x1f,0x87,0,
+0x70,0xe0,0xe,0x1c,0x1,0xc3,0x80,0x38,0x70,0x7,
+0x7,0x38,0x1e,0x1,0xc3,0xc0,0x78,0x78,0xf,0xf,
+0x1,0xe1,0xe0,0x3c,0x1,0xc0,0x1c,0,0xe,0xe,
+0x70,0x71,0xc1,0xc7,0x7,0x1c,0x1c,0x70,0x71,0xc1,
+0xc7,0x7,0,0x1c,0,0xe0,0x3,0x80,0xe,0,
+0x38,0,0x70,0xe1,0xc1,0xc7,0x3,0x8e,0xe,0x38,
+0x1c,0xe0,0x73,0x81,0xce,0x7,0x38,0x1c,0,0x1,
+0xf0,0xe3,0x83,0x87,0x7,0xe,0xe,0x1c,0x1c,0x7,
+0xe0,0x70,0x38,0x1f,0x80,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,0xcc,0xe,0x67,0x1,0xc6,0xc,0xe0,
+0xf8,0,0xe0,0x1c,0,0x1,0xc0,0,0,0x1,
+0x81,0xc3,0x80,0x70,0xf0,0x7,0x7,0x80,0x71,0xc1,
+0xe7,0xe,0xe,0x3,0x81,0xdc,0x1c,0,0,0xf,
+0x80,0,0x7,0xc0,0,0,0x71,0xce,0xf0,0x38,
+0x7,0xe,0x1,0xe3,0xc0,0x78,0xe0,0x1e,0x1c,0,
+0x1c,0,0x3c,0x7,0xc7,0,0x70,0xe3,0x83,0x87,
+0x1,0xe1,0xc0,0x3,0x87,0xc3,0x87,0x1,0xf0,0xf0,
+0x1e,0x1c,0,0xf,0xf,0xe1,0xc0,0x39,0xe0,0x3c,
+0x7,0,0x70,0x1c,0x1,0xf8,0x1,0xf0,0x7c,0x7,
+0x3,0x80,0x1c,0x1,0xe0,0x3,0x80,0x30,0x70,0,
+0,0,0,0x38,0x78,0x78,0x70,0xe1,0xc7,0xf,
+0xe,0xe,0x1c,0x1c,0x3c,0x38,0x38,0x70,0xe1,0xc7,
+0x87,0xe,0x1c,0x38,0x70,0x70,0xe1,0xc3,0xc3,0x87,
+0xf,0xe,0x7,0x7,0xe,0xe,0x1e,0x7,0xe0,0x3e,
+0x3e,0xf,0x78,0x7,0xc0,0xe0,0x3,0x81,0xc0,0xe0,
+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,0x38,0xec,0xe1,
+0xc0,0xc,0x3,0x3,0x80,0x70,0x3d,0xc0,0x1,0xc0,
+0x1c,0,0x3,0xb8,0,0,0,0xe0,0xe,0,
+0,0,0x70,0,0,0,0x38,0x78,0xc,0xc0,
+0,0,0,0x7,0x70,0x3,0x1f,0xe0,0x61,0xc0,
+0xc,0x7f,0x83,0xc0,0x1c,0x3,0x87,0,0xe1,0xc0,
+0x38,0x70,0xe,0x1c,0x3,0x87,0,0xe1,0xc1,0xc0,
+0x1,0xe0,0x3c,0x70,0,0x70,0,0x70,0,0x70,
+0,0x70,0xe0,0xe0,0xe1,0xc0,0x3c,0x38,0xf,0x87,
+0x80,0xf0,0xf0,0x1e,0x1e,0x3,0xc3,0xc0,0x78,0x78,
+0xf,0xe,0x1c,0x1e,0x3,0xc1,0xc0,0x70,0x38,0xe,
+0x7,0x1,0xc0,0xe0,0x38,0x1,0xc0,0x1c,0,0xe,
+0xe,0x70,0xf1,0xc3,0xc7,0xf,0x1c,0x3c,0x70,0xf1,
+0xc3,0xc7,0xf,0x83,0x8e,0x1c,0x70,0x71,0xc1,0xc7,
+0x7,0x1c,0x1c,0x70,0xe1,0xc1,0xc3,0x87,0xe,0xe,
+0x1c,0x38,0x70,0xe1,0xc3,0x87,0xe,0x1c,0x38,0x7,
+0,0xe1,0xc3,0x87,0x87,0xf,0xe,0x1e,0x1c,0x3c,
+0x3,0xe0,0x78,0x70,0xf,0x80,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,0xe0,0,0xcc,0xf,0x6f,0x1,0xc7,0x1c,
+0xf1,0xfc,0,0xe0,0x1c,0,0x1,0xc0,0x38,0,
+0x71,0x81,0xe7,0x80,0x70,0xe0,0x3,0x8f,0,0x71,
+0xe3,0xc7,0x9e,0x1e,0x1,0xc3,0x9e,0x7c,0x38,0x70,
+0x3,0xe0,0,0x1f,0,0x1,0xc0,0x79,0xff,0xe0,
+0x70,0x3,0x8e,0x7,0xc1,0xf1,0xf0,0xe0,0x7c,0x1c,
+0,0x1c,0,0x1f,0x1f,0xc7,0,0x70,0xe1,0xc7,
+0x87,0,0xf1,0xc0,0x3,0x83,0x83,0x87,0x1,0xf0,
+0x7c,0x7c,0x1c,0,0x7,0xc3,0xc1,0xc0,0x38,0xf8,
+0xf8,0x7,0,0x7c,0x7c,0,0xf0,0,0xe0,0x38,
+0xe,0x1,0xc0,0x1c,0x3,0xc0,0x3,0x80,0x30,0x70,
+0,0,0,0,0x3c,0xf8,0x7c,0xf0,0xf3,0xc7,
+0x9f,0xf,0x1e,0x1c,0x1e,0x7c,0x38,0x38,0x70,0xe1,
+0xc3,0x87,0xe,0x1c,0x38,0x70,0x70,0xf3,0xc3,0xe7,
+0x87,0x9f,0xe,0x7,0x8f,0xe,0x7,0x3e,0x3,0xc0,
+0x1c,0x1c,0xe,0x38,0x7,0x81,0xe0,0x3,0x81,0xc0,
+0xe0,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,0x38,0x7d,
+0xe3,0xb9,0xc0,0,0x3,0x80,0x70,0x1f,0x80,0,
+0xe0,0x38,0,0,0,0,0,0,0x70,0x1c,
+0,0,0,0,0,0,0,0x3c,0xf8,0xc,
+0xc0,0,0,0,0,0,0x3,0x1f,0xe0,0x61,
+0x80,0xc,0x7f,0x87,0x80,0x38,0x1,0xce,0,0x73,
+0x80,0x1c,0xe0,0x7,0x38,0x1,0xce,0,0x73,0x81,
+0xc0,0,0xf8,0xf8,0x70,0,0x70,0,0x70,0,
+0x70,0,0x70,0xe0,0xe0,0xe1,0xc0,0xf8,0x38,0xf,
+0x83,0xe3,0xe0,0x7c,0x7c,0xf,0x8f,0x81,0xf1,0xf0,
+0x3e,0x3e,0x1c,0xe,0x3f,0x8f,0x81,0xf1,0xf0,0x3e,
+0x3e,0x7,0xc7,0xc0,0xf8,0xf8,0x1,0xc0,0x1c,0,
+0xe,0x1c,0x79,0xf1,0xe7,0xc7,0x9f,0x1e,0x7c,0x79,
+0xf1,0xe7,0xc7,0x9f,0xc7,0x8f,0x3c,0x78,0xf1,0xe3,
+0xc7,0x8f,0x1e,0x3c,0x70,0xe1,0xc1,0xc3,0xcf,0xe,
+0xe,0x1e,0x78,0x79,0xe1,0xe7,0x87,0x9e,0x1e,0x78,
+0x7,0x1,0xf3,0xc1,0xcf,0x83,0x9f,0x7,0x3e,0xe,
+0x7c,0x3,0xc0,0x7c,0xf0,0xf,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,0xe0,0,0xcc,0x7,0xfe,0x3,0x83,
+0xf8,0x7f,0xce,0,0x60,0x18,0,0x1,0xc0,0x38,
+0,0x73,0x80,0xff,0,0x70,0xff,0xf3,0xff,0,
+0x70,0xff,0x83,0xfc,0x1c,0x1,0xff,0x8f,0xf8,0x38,
+0x70,0,0xe0,0,0x1c,0,0x1,0xc0,0x38,0xfb,
+0x80,0x70,0x3,0x8f,0xff,0x80,0xff,0xe0,0xff,0xf8,
+0x1f,0xff,0x1c,0,0xf,0xfd,0xc7,0,0x70,0xe1,
+0xff,0x7,0,0x79,0xff,0xe3,0x83,0x83,0x87,0,
+0xf0,0x3f,0xf8,0x1c,0,0x3,0xff,0xe1,0xc0,0x38,
+0x7f,0xf0,0x7,0,0x3f,0xf8,0,0xf0,0,0xe0,
+0x38,0x1e,0x1,0xe0,0x1c,0x3,0xff,0xf3,0x80,0x38,
+0x70,0,0,0,0,0x1f,0xfc,0x7f,0xe0,0x7f,
+0x83,0xff,0x7,0xfc,0x1c,0xf,0xfc,0x38,0x38,0x70,
+0xe1,0xc3,0xc7,0xe,0x1c,0x38,0x70,0x70,0x7f,0x83,
+0xff,0x3,0xff,0xe,0x3,0xfe,0xf,0x87,0xee,0x3,
+0xc0,0x1c,0x1c,0x1e,0x3c,0x3,0x81,0xff,0xc3,0x81,
+0xc0,0xe0,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,0x38,
+0x7f,0xc7,0xff,0xc0,0,0x3,0x80,0x70,0xf,0,
+0,0x78,0xf0,0,0,0,0,0,0,0x3c,
+0x78,0,0,0x7,0xff,0,0,0,0x3f,0xb8,
+0xc,0xc0,0,0,0,0,0,0x6,0x1,0x80,
+0xc1,0xf8,0x18,0x6,0x7,0,0x38,0x1,0xce,0,
+0x73,0x80,0x1c,0xe0,0x7,0x38,0x1,0xce,0,0x73,
+0x81,0xff,0xf0,0x7f,0xf0,0x7f,0xfc,0x7f,0xfc,0x7f,
+0xfc,0x7f,0xfc,0x70,0xe0,0xe0,0xe1,0xff,0xf0,0x38,
+0x7,0x81,0xff,0xc0,0x3f,0xf8,0x7,0xff,0,0xff,
+0xe0,0x1f,0xfc,0x8,0x4,0x77,0xff,0,0xff,0xe0,
+0x1f,0xfc,0x3,0xff,0x80,0x7f,0xf0,0x1,0xc0,0x1c,
+0,0xe,0xfc,0x3f,0xf8,0xff,0xe3,0xff,0x8f,0xfe,
+0x3f,0xf8,0xff,0xe3,0xf9,0xff,0x7,0xf8,0x3f,0xe0,
+0xff,0x83,0xfe,0xf,0xf8,0x70,0xe1,0xc1,0xc1,0xfe,
+0xe,0xe,0xf,0xf0,0x3f,0xc0,0xff,0x3,0xfc,0xf,
+0xf0,0x7,0x3,0x7f,0x81,0xfb,0x83,0xf7,0x7,0xee,
+0xf,0xdc,0x1,0xc0,0x7f,0xe0,0x7,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,0xe0,0,0xcc,0x1,0xfc,0x3,
+0x81,0xf0,0x1f,0x87,0,0x70,0x38,0,0,0,
+0x38,0,0x73,0x80,0x7e,0,0x70,0xff,0xf0,0xfc,
+0,0x70,0x3f,0x1,0xf8,0x1c,0,0x7e,0x3,0xe0,
+0x38,0x70,0,0,0,0,0,0x1,0xc0,0x3c,
+0,0,0x70,0x3,0x8f,0xfe,0,0x3f,0x80,0xff,
+0xe0,0x1f,0xff,0x1c,0,0x3,0xf8,0xc7,0,0x70,
+0xe0,0xfe,0x7,0,0x39,0xff,0xe3,0x83,0x83,0x87,
+0,0x70,0xf,0xe0,0x1c,0,0,0xfe,0xf1,0xc0,
+0x38,0x1f,0xc0,0x7,0,0xf,0xe0,0,0xf0,0,
+0xe0,0x38,0x1c,0,0xe0,0x1c,0x3,0xff,0xf3,0x80,
+0x38,0x70,0,0,0,0,0xf,0x9c,0x77,0xc0,
+0x3f,0x1,0xf7,0x1,0xf0,0x1c,0x7,0xdc,0x38,0x38,
+0x70,0xe1,0xc1,0xe7,0xe,0x1c,0x38,0x70,0x70,0x1e,
+0x3,0xbe,0x1,0xf7,0xe,0x1,0xfc,0x7,0x81,0xce,
+0x3,0xc0,0x1c,0x1c,0x1c,0x1c,0x3,0x81,0xff,0xc3,
+0x81,0xc0,0xe0,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,
+0x38,0x3f,0x87,0xcf,0x80,0,0x3,0x80,0x70,0x7,
+0x80,0,0x1f,0xc0,0,0,0,0,0,0,
+0xf,0xe0,0,0,0x7,0xff,0,0,0,0x3b,
+0x38,0xc,0xc0,0x7,0,0,0,0,0x6,0x1,
+0x80,0xc1,0xf8,0x18,0x6,0xf,0xe,0x38,0x1,0xce,
+0,0x73,0x80,0x1c,0xe0,0x7,0x38,0x1,0xce,0,
+0x73,0x81,0xff,0xf0,0x1f,0xc0,0x7f,0xfc,0x7f,0xfc,
+0x7f,0xfc,0x7f,0xfc,0x70,0xe0,0xe0,0xe1,0xff,0xc0,
+0x38,0x3,0x80,0x7f,0,0xf,0xe0,0x1,0xfc,0,
+0x3f,0x80,0x7,0xf0,0,0,0x61,0xfc,0,0x3f,
+0x80,0x7,0xf0,0,0xfe,0,0x1f,0xc0,0x1,0xc0,
+0x1c,0,0xe,0xf8,0x1f,0x38,0x7c,0xe1,0xf3,0x87,
+0xce,0x1f,0x38,0x7c,0xe1,0xf0,0x7c,0x3,0xf0,0xf,
+0x80,0x3e,0,0xf8,0x3,0xe0,0x70,0xe1,0xc1,0xc0,
+0x78,0xe,0xe,0x3,0xc0,0xf,0,0x3c,0,0xf0,
+0x3,0xc0,0,0x2,0x1e,0,0x73,0x80,0xe7,0x1,
+0xce,0x3,0x9c,0x1,0xc0,0x77,0xc0,0x7,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,0x60,
+0,0,0,0,0,0,0x70,0x38,0,0,
+0,0x18,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x30,0,0,0,0,0,0,0,
+0x1e,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,0x3,
+0x80,0,0x70,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1c,0,
+0,0,0xe0,0,0,0,0,0,0,0,
+0,0x3,0x80,0,0x7,0,0,0,0,0,
+0,0,0,0,0,0,0,0x7,0,0,
+0x3,0x81,0xc0,0xe0,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,0x38,0x18,0,0,0,0,0,0,0x70,
+0xe3,0xc0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x38,0,0xc,0xc0,0x7,0x80,0,0,0,0,
+0,0,0,0,0,0,0xe,0xe,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xf,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,0x3,0xc0,
+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,0x3,0x80,0x70,0,0xe,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,
+0x60,0,0,0,0,0,0,0x38,0x70,0,
+0,0,0x18,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x30,0,0,0,0,0,0,
+0,0xf,0x83,0x80,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,
+0x3,0x80,0,0x70,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x38,0x1c,
+0,0,0,0xe0,0,0,0,0,0,0,
+0,0,0x3,0x80,0,0x7,0,0,0,0,
+0,0,0,0,0,0,0,0,0x7,0,
+0,0x3,0x81,0xc0,0xe0,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,0x38,0x18,0,0,0,0,0,0,
+0x70,0xe1,0xc0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x38,0,0xc,0xc0,0x1,0xc0,0,0,0,
+0,0,0,0,0,0,0,0xe,0x1e,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0x80,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,
+0xe0,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,0x3,0x80,0x70,0,0xe,
+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,0,0,0,0,0,0,0x38,0x70,
+0,0,0,0x30,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x60,0,0,0,0,0,
+0,0,0x7,0xff,0x80,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,0x3,0x80,0,0x70,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3c,
+0x38,0,0,0,0xe0,0,0,0,0,0,
+0,0,0,0x3,0x80,0,0x7,0,0,0,
+0,0,0,0,0,0,0,0,0,0xe,
+0,0,0x3,0x81,0xc0,0xe0,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,0x38,0,0,0,0,0,0,
+0,0x70,0xf3,0xc0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x38,0,0xc,0xc0,0x1,0xc0,0,0,
+0,0,0,0,0,0,0,0,0xf,0x3c,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0x80,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,0xe0,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,0x7,0,0x70,0,
+0x1c,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,0,0,0,0,0,0,0x1c,
+0xe0,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,0x1,0xfe,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,0x3,0xe0,0x1,0xf0,0,0x1f,0xff,0x80,
+0,0,0,0,0,0,0,0,0,0,
+0x1f,0xf8,0,0,0x3,0xe0,0,0,0,0,
+0,0,0,0,0x3,0x80,0,0x7,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x3e,0,0,0x1,0xc1,0xc1,0xc0,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,0x38,0,0,0,0,0,
+0,0,0x70,0x7f,0x80,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x38,0,0xc,0xc0,0xf,0xc0,0,
+0,0,0,0,0,0,0,0,0,0x7,
+0xfc,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1f,0x80,
+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,0x7,0xe0,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,0x1f,0,0x70,
+0,0x7c,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,0,0,0,0,0,0,
+0xc,0xc0,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x3,0xe0,0x1,0xf0,0,0x1f,0xff,
+0x80,0,0,0,0,0,0,0,0,0,
+0,0x7,0xe0,0,0,0x3,0xc0,0,0,0,
+0,0,0,0,0,0x3,0x80,0,0x7,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x3c,0,0,0,0xe1,0xc3,0x80,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,0x38,0,0,0,0,
+0,0,0,0,0x3f,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x38,0,0xc,0xc0,0x7,0x80,
+0,0,0,0,0,0,0,0,0,0,
+0x3,0xf0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xf,
+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,0x3,0xc0,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,0x1e,0,
+0x70,0,0x78,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,
+};
+
+static WORD HelveticaBold24_ch_ofst[225] = {
+0,6,13,22,36,49,71,89,95,103,
+111,121,136,143,151,158,166,179,192,205,
+218,231,244,257,270,283,296,303,310,325,
+339,353,368,392,410,428,446,465,481,496,
+515,534,541,555,573,588,611,630,649,666,
+685,702,719,734,753,771,794,812,829,845,
+853,861,869,883,897,905,919,934,947,962,
+976,985,1000,1015,1022,1029,1043,1050,1071,1086,
+1100,1115,1130,1140,1153,1162,1177,1191,1210,1223,
+1238,1251,1261,1268,1278,1292,1298,1304,1310,1316,
+1322,1328,1334,1340,1346,1352,1358,1364,1370,1376,
+1382,1388,1394,1400,1406,1412,1418,1424,1430,1436,
+1442,1448,1454,1460,1466,1472,1478,1484,1490,1496,
+1503,1517,1531,1545,1559,1566,1580,1589,1608,1618,
+1631,1646,1654,1673,1682,1691,1706,1713,1720,1728,
+1743,1756,1763,1771,1778,1788,1801,1820,1839,1858,
+1873,1891,1909,1927,1945,1963,1981,2005,2023,2039,
+2055,2071,2087,2094,2102,2110,2117,2136,2155,2174,
+2193,2212,2231,2250,2265,2284,2303,2322,2341,2360,
+2377,2394,2408,2422,2436,2450,2464,2478,2492,2514,
+2527,2541,2555,2569,2583,2590,2597,2605,2612,2626,
+2641,2655,2669,2683,2697,2711,2726,2740,2755,2770,
+2785,2800,2815,2830,2845,
+};
+
+static struct font_hdr HelveticaBold24_font = {
+STPROP, 24, "AdobeHelv-B-R-N--24-240-75-75-P", 32, 255,
+29, 24, 14, 5, 5,
+24, 24, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+HelveticaBold24_ch_ofst, HelveticaBold24_data,
+421, 29,
+NULL,
+0, 0,   /* x/y offset */
+31,        /* lineHeight */
+22,	   /* psHeight */
+};
+
+MgFont *mgHelveticaBold24Font()
+{
+return &HelveticaBold24_font;
+}
diff --git a/lib/font/mgHelveticaBold34.c b/lib/font/mgHelveticaBold34.c
new file mode 100644
index 0000000..e8e7c33
--- /dev/null
+++ b/lib/font/mgHelveticaBold34.c
@@ -0,0 +1,2270 @@
+
+/* Helvetica34.c - compiled data for font AdobeHelv-B-R-N--34-240-100-100 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 100dpi/helvB24.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Helvetica34_data[22078] = {
+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,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,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,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,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,0x78,0,
+0,0x3,0xc0,0,0x18,0,0,0,0,0x7,
+0x9e,0,0x1,0xe0,0,0,0,0,0,0,
+0,0,0x78,0,0,0x7,0x80,0,0x30,0,
+0x1e,0x3c,0xf,0,0x1e,0x18,0x79,0xe0,0,0,
+0,0,0,0,0x3c,0,0,0,0x78,0,
+0,0xc0,0,0,0,0,0x3,0xcf,0,0,
+0,0,0,0,0,0x3c,0,0,0,0xf0,
+0,0x3,0,0,0x78,0xf0,0,0x1,0xe0,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,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,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,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,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,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,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,0x3c,
+0,0,0x7,0x80,0,0x3c,0,0,0xf1,0x80,
+0x7,0x9e,0,0x3,0x30,0,0,0,0,0,
+0,0,0,0x3c,0,0,0xf,0,0,0x78,
+0,0x1e,0x3c,0x7,0x80,0x3c,0x3c,0x79,0xe0,0,
+0,0,0x3c,0x60,0,0x1e,0,0,0,0xf0,
+0,0x1,0xe0,0,0x1,0xe3,0,0x3,0xcf,0,
+0,0,0,0,0,0,0x1e,0,0,0x1,
+0xe0,0,0x7,0x80,0,0x78,0xf0,0,0x3,0xc0,
+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,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,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,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,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,
+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,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,
+0x1e,0,0,0xf,0,0,0x7e,0,0x1,0xff,
+0x80,0x7,0x9e,0,0x2,0x10,0,0,0,0,
+0,0,0,0,0x1e,0,0,0x1e,0,0,
+0xfc,0,0x1e,0x3c,0x3,0xc0,0x78,0x7e,0x79,0xe0,
+0,0,0,0x7f,0xe0,0,0xf,0,0,0x1,
+0xe0,0,0x3,0xf0,0,0x3,0xff,0,0x3,0xcf,
+0,0,0,0,0,0,0,0xf,0,0,
+0x3,0xc0,0,0xf,0xc0,0,0x78,0xf0,0,0x7,
+0x80,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,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,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,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,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,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,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,0xf,0,0,0x1e,0,0,0xe7,0,0x3,
+0xff,0,0x7,0x9e,0,0x2,0x10,0,0,0,
+0,0,0,0,0,0xf,0,0,0x3c,0,
+0x1,0xce,0,0x1e,0x3c,0x1,0xe0,0xf0,0xe7,0x79,
+0xe0,0,0,0,0xff,0xc0,0,0x7,0x80,0,
+0x3,0xc0,0,0x7,0x38,0,0x7,0xfe,0,0x3,
+0xcf,0,0,0,0,0,0,0,0x7,0x80,
+0,0x7,0x80,0,0x1c,0xe0,0,0x78,0xf0,0,
+0xf,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,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,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,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,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,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,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,0x7,0x80,0,0x3c,0,0x1,0xc3,0x80,
+0x3,0x1e,0,0,0,0,0x3,0x30,0,0,
+0,0,0,0,0,0,0x7,0x80,0,0x78,
+0,0x3,0x87,0,0,0,0,0xf1,0xe1,0xc3,
+0x80,0,0,0,0,0xc7,0x80,0,0x3,0xc0,
+0,0x7,0x80,0,0xe,0x1c,0,0x6,0x3c,0,
+0,0,0,0,0,0,0,0,0,0x3,
+0xc0,0,0xf,0,0,0x38,0x70,0,0,0,
+0,0x1e,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,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,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,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,
+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,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,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,0,0,0,0,
+0,0,0,0,0,0,0,0x1,0xe0,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,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,0x6,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,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,0xf,0x83,0xc7,
+0x80,0,0,0x1,0x80,0,0,0,0,0x3,
+0xe0,0,0xf0,0xe,0x38,0,0,0,0,0,
+0,0,0,0x1,0x80,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,0x1f,0xc0,0,
+0x3,0xf8,0,0,0x3f,0,0xf,0xff,0xc0,0,
+0x7f,0x80,0x1f,0xff,0,0x1f,0xff,0xf0,0x7f,0xff,
+0x80,0xf,0xf0,0x3,0xe0,0xf,0x87,0xc0,0x1,0xf0,
+0xf8,0x7,0xe0,0xf8,0,0xf,0xe0,0xf,0xe1,0xf0,
+0x7,0xc0,0x7,0xfc,0,0xff,0xf8,0,0xf,0xf8,
+0,0xff,0xfe,0,0x7,0xf0,0xf,0xff,0xfe,0x3e,
+0,0xf8,0x7c,0,0xf9,0xf0,0x3f,0x3,0xf3,0xf0,
+0xf,0x8f,0xc0,0x3f,0x3f,0xff,0xe1,0xfe,0xc0,0x7f,
+0x80,0,0,0,0,0x1c,0,0,0,0xf0,
+0,0,0,0,0,0x78,0,0,0x1,0xf0,
+0,0,0x1e,0,0x1,0xe0,0xf0,0x78,0,0xf,
+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,0x3e,0xe,0xf,0x80,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,
+0x38,0x7,0xf8,0x3c,0xf0,0x3,0xfc,0,0x3e,0,
+0,0,0,0,0,0,0x1f,0xf0,0,0,
+0,0,0,0,0,0,0,0xf,0,0,
+0,0x7f,0xfc,0,0,0,0,0x7e,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1f,0x80,0,0x3f,0,0,
+0x7e,0,0,0xfc,0,0x1,0xf8,0,0,0,
+0,0x7,0xff,0xff,0xe0,0x7,0xf8,0x3,0xff,0xfe,
+0xf,0xff,0xf8,0x3f,0xff,0xe0,0xff,0xff,0x83,0xe1,
+0xf0,0x7c,0x1f,0x7,0xff,0xe0,0xf,0x80,0x3e,0,
+0x3f,0xe0,0,0x1f,0xf0,0,0xf,0xf8,0,0x7,
+0xfc,0,0x3,0xfe,0,0,0,0,0x3f,0xe0,
+0xe7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,
+0xc0,0x1f,0xf,0xc0,0x3f,0x1f,0,0,0x7,0xe0,
+0,0xf0,0,0x1,0xe0,0x1,0x80,0,0,0,
+0,0,0xf,0,0,0,0,0,0,0,
+0x1e,0,0,0x3c,0,0x30,0,0,0x1,0xe0,
+0x1e,0x18,0,0xf,0x4,0,0,0,0,0xf0,
+0,0,0xf0,0,0x18,0,0,0,0,0,
+0,0,0,0,0,0,0x3c,0,0,0x1e,
+0,0x6,0,0x7,0x8f,0,0x1,0xe0,0x3c,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,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,0xf,0x83,
+0xc7,0x80,0x3c,0x70,0x1,0x80,0,0,0,0,
+0xf,0xf8,0,0xf0,0x1e,0x3c,0,0x60,0,0,
+0,0,0,0,0x1,0x81,0xfc,0,0,0,
+0x1f,0xc0,0x7,0xf0,0,0x1f,0x1,0xff,0xe0,0xf,
+0xc0,0x7f,0xff,0x81,0xfc,0,0x3e,0,0,0,
+0,0,0,0,0,0,0,0,0x7f,0xf0,
+0,0x1f,0xff,0,0,0x3f,0,0xf,0xff,0xf0,
+0x1,0xff,0xe0,0x1f,0xff,0xe0,0x1f,0xff,0xf0,0x7f,
+0xff,0x80,0x3f,0xfc,0x3,0xe0,0xf,0x87,0xc0,0x1,
+0xf0,0xf8,0x7,0xe0,0xf8,0,0xf,0xe0,0xf,0xe1,
+0xf8,0x7,0xc0,0x1f,0xff,0,0xff,0xfe,0,0x3f,
+0xfe,0,0xff,0xff,0x80,0x1f,0xfc,0xf,0xff,0xfe,
+0x3e,0,0xf8,0x7c,0,0xf9,0xf0,0x3f,0x3,0xf1,
+0xf8,0x1f,0x8f,0xc0,0x3e,0x3f,0xff,0xe1,0xfe,0xc0,
+0x7f,0x80,0,0,0,0,0x1e,0,0,0,
+0xf0,0,0,0,0,0,0x78,0,0,0x3,
+0xf0,0,0,0x1e,0,0x1,0xe0,0xf0,0x78,0,
+0xf,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,0x7e,0xe,0xf,0xc0,
+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,0x1,0xf8,0,0,0x7,0xc0,
+0x3e,0x38,0xf,0xfc,0x3c,0xf0,0x1f,0xff,0,0x7f,
+0,0,0,0,0,0,0,0x7f,0xfc,0x7,
+0xfe,0xf,0x80,0,0,0x3f,0x3,0xc0,0x1e,0,
+0,0,0xff,0xfc,0,0,0,0xe0,0xff,0,
+0,0,0,0x3,0x80,0,0,0x70,0x1,0xf8,
+0,0xe0,0,0,0,0x1f,0x80,0,0x3f,0,
+0,0x7e,0,0,0xfc,0,0x1,0xf8,0,0x3,
+0xf0,0,0x7,0xff,0xff,0xe0,0x1f,0xfe,0x3,0xff,
+0xfe,0xf,0xff,0xf8,0x3f,0xff,0xe0,0xff,0xff,0x83,
+0xe1,0xf0,0x7c,0x1f,0x7,0xff,0xf8,0xf,0xc0,0x3e,
+0,0xff,0xf8,0,0x7f,0xfc,0,0x3f,0xfe,0,
+0x1f,0xff,0,0xf,0xff,0x80,0,0,0,0xff,
+0xf9,0xc7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,
+0x7,0xc0,0x1f,0xf,0xc0,0x3f,0x1f,0,0,0x1f,
+0xf8,0,0x78,0,0x3,0xc0,0x3,0xc0,0x1,0xe3,
+0x1,0xe7,0x80,0x19,0x80,0,0,0,0,0,
+0,0xf,0,0,0x78,0,0x78,0,0xf3,0xc0,
+0xf0,0x1c,0x3c,0xf3,0xcf,0x9e,0,0xf,0x18,0,
+0x78,0,0x1,0xe0,0,0x3c,0,0xf,0x18,0x3,
+0xc7,0x80,0,0,0,0,0,0x1e,0,0,
+0x3c,0,0xf,0,0x7,0x8f,0,0x3,0xc0,0x3c,
+0,0,0xf3,0xc0,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,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,0xf,
+0x83,0xc7,0x80,0x3c,0x70,0xf,0xf0,0x3,0x80,0xc,
+0,0x1f,0xfc,0,0xf0,0x3c,0x1e,0,0x60,0,
+0,0,0,0,0,0x1,0x83,0xfe,0,0x7,
+0,0x7f,0xf0,0x1f,0xfc,0,0x1f,0x1,0xff,0xe0,
+0x3f,0xf0,0x7f,0xff,0x87,0xff,0,0xff,0x80,0,
+0,0,0,0,0,0,0,0,0,0xff,
+0xf8,0,0x7f,0xff,0x80,0,0x7f,0x80,0xf,0xff,
+0xf8,0x3,0xff,0xf0,0x1f,0xff,0xf0,0x1f,0xff,0xf0,
+0x7f,0xff,0x80,0xff,0xfe,0x3,0xe0,0xf,0x87,0xc0,
+0x1,0xf0,0xf8,0xf,0xc0,0xf8,0,0xf,0xf0,0x1f,
+0xe1,0xf8,0x7,0xc0,0x3f,0xff,0x80,0xff,0xff,0,
+0x7f,0xff,0,0xff,0xff,0xc0,0x3f,0xfe,0xf,0xff,
+0xfe,0x3e,0,0xf8,0x3e,0x1,0xf0,0xf0,0x3f,0x3,
+0xe1,0xf8,0x1f,0x7,0xe0,0x7e,0x3f,0xff,0xe1,0xfe,
+0xe0,0x7f,0x80,0x1e,0,0,0,0xe,0,0,
+0,0xf0,0,0,0,0,0,0x78,0,0,
+0x7,0xf0,0,0,0x1e,0,0x1,0xe0,0xf0,0x78,
+0,0xf,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,0xfe,0xe,0xf,
+0xe0,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,0xf,0xfe,0,0,0x7,
+0xc0,0x3e,0x38,0x1f,0xfc,0x3c,0xf0,0x3c,0x7,0xc0,
+0xe3,0x80,0,0,0,0,0,0,0xf0,0x1f,
+0x7,0xfe,0x1f,0xc0,0,0,0x7f,0x8f,0xf0,0x1c,
+0,0,0x1,0xfc,0x60,0,0,0x1,0xe0,0xe7,
+0,0,0,0x60,0x7,0,0x6,0,0xe0,0x3,
+0xfc,0x1,0xc0,0,0,0,0x3f,0xc0,0,0x7f,
+0x80,0,0xff,0,0x1,0xfe,0,0x3,0xfc,0,
+0x7,0xf8,0,0x7,0xff,0xff,0xe0,0x3f,0xff,0x3,
+0xff,0xfe,0xf,0xff,0xf8,0x3f,0xff,0xe0,0xff,0xff,
+0x83,0xe1,0xf0,0x7c,0x1f,0x7,0xff,0xfc,0xf,0xc0,
+0x3e,0x1,0xff,0xfc,0,0xff,0xfe,0,0x7f,0xff,
+0,0x3f,0xff,0x80,0x1f,0xff,0xc0,0,0,0x1,
+0xff,0xff,0x87,0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,
+0x1f,0x7,0xc0,0x1f,0x7,0xe0,0x7e,0x1f,0,0,
+0x3f,0xfe,0,0x38,0,0x3,0x80,0x7,0xe0,0x3,
+0xff,0x1,0xe7,0x80,0x10,0x80,0,0,0,0,
+0,0,0x7,0,0,0x70,0,0xfc,0,0xf3,
+0xc0,0x70,0x38,0x7e,0xf3,0xc7,0xfc,0,0x1f,0xf8,
+0,0x38,0,0x1,0xc0,0,0x7e,0,0x1f,0xf8,
+0x3,0xc7,0x80,0,0,0,0,0,0xe,0,
+0,0x38,0,0x1f,0x80,0x7,0x8f,0,0x7,0x80,
+0x3c,0,0,0xf3,0xc0,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,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,
+0xf,0x83,0xc7,0x80,0x38,0xf0,0x3f,0xfc,0xf,0xe0,
+0x1c,0,0x1f,0xfc,0,0xf0,0x3c,0x1e,0x2,0x64,
+0,0,0,0,0,0,0x1,0x87,0xff,0,
+0xf,0,0xff,0xf8,0x3f,0xfe,0,0x3f,0x1,0xff,
+0xe0,0x7f,0xf8,0x7f,0xff,0x8f,0xff,0x81,0xff,0xc0,
+0,0,0,0,0,0,0,0,0,0,
+0xff,0xfc,0,0xfc,0xf,0xe0,0,0x7f,0x80,0xf,
+0xff,0xf8,0x7,0xff,0xf8,0x1f,0xff,0xf8,0x1f,0xff,
+0xf0,0x7f,0xff,0x81,0xff,0xff,0x3,0xe0,0xf,0x87,
+0xc0,0x1,0xf0,0xf8,0x1f,0x80,0xf8,0,0xf,0xf0,
+0x1f,0xe1,0xfc,0x7,0xc0,0x7f,0xff,0xc0,0xff,0xff,
+0x80,0xff,0xff,0x80,0xff,0xff,0xc0,0x7f,0xff,0xf,
+0xff,0xfe,0x3e,0,0xf8,0x3e,0x1,0xf0,0xf0,0x3f,
+0x3,0xe0,0xfc,0x3f,0x3,0xe0,0x7c,0x3f,0xff,0xe1,
+0xe0,0x60,0x7,0x80,0x3f,0,0,0,0xf,0,
+0,0,0xf0,0,0,0,0,0,0x78,0,
+0,0x7,0xc0,0,0,0x1e,0,0x1,0xe0,0xf0,
+0x78,0,0xf,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xf,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0xf8,0xe,
+0x3,0xe0,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,0x1f,0xff,0,0,
+0x3,0xe0,0x7c,0x38,0x3f,0x3e,0x3c,0xf0,0xf8,0x1,
+0xe0,0xc3,0x80,0,0,0,0,0,0x3,0xc0,
+0x7,0x87,0xfe,0x18,0xc0,0xf,0,0xf3,0xde,0x78,
+0x38,0,0,0x3,0xfc,0x60,0,0,0x7,0xe1,
+0xc3,0x80,0,0x1,0xe0,0x7,0,0xe,0,0xe0,
+0x7,0x9e,0x1,0xc0,0,0,0,0x3f,0xc0,0,
+0x7f,0x80,0,0xff,0,0x1,0xfe,0,0x3,0xfc,
+0,0x7,0xf8,0,0xf,0xff,0xff,0xe0,0x7f,0xff,
+0x83,0xff,0xfe,0xf,0xff,0xf8,0x3f,0xff,0xe0,0xff,
+0xff,0x83,0xe1,0xf0,0x7c,0x1f,0x7,0xff,0xfe,0xf,
+0xe0,0x3e,0x3,0xff,0xfe,0x1,0xff,0xff,0,0xff,
+0xff,0x80,0x7f,0xff,0xc0,0x3f,0xff,0xe0,0,0,
+0x3,0xff,0xff,0x7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,
+0xc0,0x1f,0x7,0xc0,0x1f,0x3,0xe0,0x7c,0x1f,0xff,
+0,0x7f,0xfe,0,0x1c,0,0x7,0,0xe,0x70,
+0x7,0xfe,0x1,0xe7,0x80,0x10,0x80,0,0,0,
+0,0,0,0x3,0x80,0,0xe0,0x1,0xce,0,
+0xf3,0xc0,0x38,0x38,0xe7,0xf3,0xc3,0xf8,0,0x3f,
+0xf0,0,0x3c,0,0x3,0x80,0,0xe7,0,0x3f,
+0xf0,0x3,0xc7,0x80,0,0,0,0,0,0x7,
+0,0,0x70,0,0x39,0xc0,0x7,0x8f,0,0x7,
+0,0x3c,0,0,0xf3,0xc0,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,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,0xf,0x83,0xc7,0x80,0x38,0xf0,0x7f,0xfe,0x1f,
+0xf0,0x18,0,0x1e,0x3c,0,0xf0,0x78,0xf,0x7,
+0x6e,0,0,0,0,0,0,0x3,0xf,0xff,
+0x80,0x1f,0,0xff,0xfc,0x3f,0xfe,0,0x7f,0x1,
+0xff,0xe0,0x7f,0xfc,0x7f,0xff,0x8f,0x8f,0x83,0xff,
+0xe0,0,0,0,0,0,0,0,0,0,
+0x1,0xf8,0xfc,0x1,0xf0,0x1,0xf0,0,0x7f,0x80,
+0xf,0x80,0xfc,0xf,0xe1,0xfc,0x1f,0x1,0xfc,0x1f,
+0,0,0x7c,0,0x1,0xfc,0x3f,0x83,0xe0,0xf,
+0x87,0xc0,0x1,0xf0,0xf8,0x3f,0,0xf8,0,0xf,
+0xf0,0x1f,0xe1,0xfc,0x7,0xc0,0xff,0x1f,0xe0,0xf8,
+0x1f,0x81,0xfe,0x3f,0xc0,0xf8,0x7,0xe0,0x7c,0x3f,
+0,0x1f,0,0x3e,0,0xf8,0x3e,0x1,0xf0,0xf0,
+0x3f,0x3,0xe0,0x7c,0x3e,0x3,0xf0,0xfc,0,0x3,
+0xe1,0xe0,0x60,0x7,0x80,0x3f,0,0,0,0x7,
+0,0,0,0xf0,0,0,0,0,0,0x78,
+0,0,0x7,0x80,0,0,0x1e,0,0,0,
+0,0x78,0,0xf,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0xf,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xf0,
+0xe,0x1,0xe0,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,0x20,0x1f,0xff,0x80,
+0,0x1,0xe0,0x78,0x38,0x3e,0x1e,0,0,0xe0,
+0,0x70,0x1f,0x80,0,0,0,0,0,0x3,
+0x80,0x1,0xc0,0,0x30,0x60,0xf,0,0xe1,0xdc,
+0x38,0x38,0,0,0x3,0xfc,0x60,0,0,0x7,
+0xe1,0xc3,0x80,0,0xf,0xe0,0xe,0,0x7e,0x1,
+0xc0,0x7,0xe,0x3,0x80,0,0,0,0x3f,0xc0,
+0,0x7f,0x80,0,0xff,0,0x1,0xfe,0,0x3,
+0xfc,0,0x7,0xf8,0,0xf,0x9e,0,0,0xfe,
+0x1f,0xc3,0xe0,0,0xf,0x80,0,0x3e,0,0,
+0xf8,0,0x3,0xe1,0xf0,0x7c,0x1f,0x7,0xc1,0xfe,
+0xf,0xe0,0x3e,0x7,0xf8,0xff,0x3,0xfc,0x7f,0x81,
+0xfe,0x3f,0xc0,0xff,0x1f,0xe0,0x7f,0x8f,0xf0,0,
+0,0x7,0xf8,0xff,0x7,0xc0,0x1f,0x7,0xc0,0x1f,
+0x7,0xc0,0x1f,0x7,0xc0,0x1f,0x3,0xf0,0xfc,0x1f,
+0xff,0xc0,0x7c,0x3f,0,0xe,0,0xe,0,0x1c,
+0x38,0x6,0x3c,0x1,0xe7,0x80,0x19,0x80,0,0,
+0,0,0,0,0x1,0xc0,0x1,0xc0,0x3,0x87,
+0,0xf3,0xc0,0x1c,0x71,0xc3,0xf3,0xc7,0xfc,0,
+0x31,0xe0,0,0x1e,0,0x7,0x80,0x1,0xc3,0x80,
+0x31,0xe0,0x3,0xc7,0x80,0,0,0,0,0,
+0x3,0x80,0,0xe0,0,0x70,0xe0,0,0,0,
+0xe,0,0x3c,0,0,0xf3,0xc0,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,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,0xf,0x83,0xc7,0x80,0x78,0xf0,0xfd,0xbe,
+0x1c,0x70,0x38,0,0x3e,0x3c,0,0xf0,0x78,0xf,
+0x7,0xfe,0,0,0,0,0,0,0x3,0xf,
+0x8f,0x80,0x7f,0x1,0xf8,0xfc,0x7c,0x1f,0,0x7f,
+0x1,0xc0,0,0xf8,0x7c,0,0xf,0x1f,0x7,0xc3,
+0xe3,0xe0,0,0,0,0,0,0,0,0,
+0,0x1,0xf0,0x7e,0x3,0xc0,0,0xf0,0,0xff,
+0xc0,0xf,0x80,0x7c,0xf,0x80,0x7c,0x1f,0,0x7c,
+0x1f,0,0,0x7c,0,0x3,0xf0,0xf,0x83,0xe0,
+0xf,0x87,0xc0,0x1,0xf0,0xf8,0x7e,0,0xf8,0,
+0xf,0xf0,0x1f,0xe1,0xfe,0x7,0xc0,0xfc,0x7,0xe0,
+0xf8,0xf,0xc1,0xf8,0xf,0xc0,0xf8,0x3,0xe0,0xf8,
+0xf,0x80,0x1f,0,0x3e,0,0xf8,0x1e,0x1,0xe0,
+0xf8,0x7f,0x87,0xc0,0x7e,0x7c,0x3,0xf0,0xf8,0,
+0x7,0xe1,0xe0,0x70,0x7,0x80,0x3f,0,0,0,
+0,0,0,0,0xf0,0,0,0,0,0,
+0x78,0,0,0x7,0x80,0,0,0x1e,0,0,
+0,0,0x78,0,0xf,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xf,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0xf0,0xe,0x1,0xe0,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,0x20,0x3f,0xf,
+0x80,0,0,0xf0,0xf0,0x38,0x3e,0x1e,0,0x1,
+0xc0,0,0x38,0x7f,0x80,0,0,0,0,0,
+0x7,0x1f,0xf0,0xe0,0,0x30,0x60,0xf,0,0xe1,
+0xdc,0x38,0,0,0,0x7,0xfc,0x60,0,0,
+0,0xe1,0xc3,0x80,0,0xf,0xe0,0x1c,0,0x7e,
+0x1,0xc0,0x7,0xe,0x7,0,0,0,0,0x7f,
+0xe0,0,0xff,0xc0,0x1,0xff,0x80,0x3,0xff,0,
+0x7,0xfe,0,0xf,0xfc,0,0xf,0x1e,0,0,
+0xf8,0x7,0xc3,0xe0,0,0xf,0x80,0,0x3e,0,
+0,0xf8,0,0x3,0xe1,0xf0,0x7c,0x1f,0x7,0xc0,
+0x3f,0xf,0xf0,0x3e,0x7,0xe0,0x3f,0x3,0xf0,0x1f,
+0x81,0xf8,0xf,0xc0,0xfc,0x7,0xe0,0x7e,0x3,0xf0,
+0,0,0x7,0xe0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,
+0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,0x3,0xf0,0xf8,
+0x1f,0xff,0xe0,0x7c,0x1f,0,0,0,0,0,
+0,0,0,0,0,0,0,0xf,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0xe,0x7e,
+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,0x3c,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,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,0xf,0x83,0xc7,0x80,0x78,0xe0,0xf9,
+0x9f,0x38,0x38,0x30,0,0x3e,0x3c,0,0xf0,0x70,
+0x7,0x3,0xfc,0,0,0,0,0,0,0x3,
+0x1f,0x7,0xc3,0xff,0x1,0xf0,0x7e,0x78,0x1f,0,
+0xff,0x3,0xc0,0,0xf0,0x3c,0,0x1f,0x1e,0x3,
+0xc7,0xc1,0xf0,0,0,0,0,0,0,0,
+0,0,0x1,0xf0,0x3e,0x7,0x80,0,0x78,0,
+0xff,0xc0,0xf,0x80,0x7c,0x1f,0,0x7e,0x1f,0,
+0x7e,0x1f,0,0,0x7c,0,0x7,0xe0,0x7,0xc3,
+0xe0,0xf,0x87,0xc0,0x1,0xf0,0xf8,0xfc,0,0xf8,
+0,0xf,0xf8,0x3f,0xe1,0xfe,0x7,0xc1,0xf8,0x3,
+0xf0,0xf8,0x7,0xc3,0xf0,0x7,0xe0,0xf8,0x3,0xe0,
+0xf0,0xf,0x80,0x1f,0,0x3e,0,0xf8,0x1f,0x3,
+0xe0,0xf8,0x7f,0x87,0xc0,0x3e,0x7c,0x1,0xf0,0xf8,
+0,0xf,0xc1,0xe0,0x70,0x7,0x80,0x7f,0x80,0,
+0,0,0,0,0,0xf0,0,0,0,0,
+0,0x78,0,0,0x7,0x80,0,0,0x1e,0,
+0x1,0xe0,0xf0,0x78,0,0xf,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xf,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xf0,0xe,0x1,0xe0,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,0x60,0x3e,
+0x7,0xce,0,0xe0,0xf0,0xf0,0x38,0x3f,0,0,
+0x3,0x81,0xf8,0x18,0xf3,0x80,0,0,0,0,
+0,0xe,0x1f,0xf8,0x60,0,0x30,0x60,0xf,0,
+0x1,0xc0,0x78,0,0,0,0x7,0xfc,0x60,0,
+0,0,0xe1,0xc3,0x80,0,0,0xe0,0x1c,0,
+0xe,0x3,0x80,0,0x1e,0x7,0,0,0,0,
+0x7f,0xe0,0,0xff,0xc0,0x1,0xff,0x80,0x3,0xff,
+0,0x7,0xfe,0,0xf,0xfc,0,0x1f,0x1e,0,
+0x1,0xf0,0x7,0xc3,0xe0,0,0xf,0x80,0,0x3e,
+0,0,0xf8,0,0x3,0xe1,0xf0,0x7c,0x1f,0x7,
+0xc0,0x3f,0xf,0xf0,0x3e,0xf,0xc0,0x1f,0x87,0xe0,
+0xf,0xc3,0xf0,0x7,0xe1,0xf8,0x3,0xf0,0xfc,0x1,
+0xf8,0,0,0xf,0xc0,0x3f,0x87,0xc0,0x1f,0x7,
+0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,0x1,0xf0,
+0xf8,0x1f,0xff,0xf0,0x78,0x1f,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x7,0xe0,0xf8,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x4,
+0x3f,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,0x3c,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,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,0xf,0x81,0x83,0,0x78,0xe0,
+0xf1,0x9f,0x38,0x38,0x70,0,0x1f,0x3c,0,0x60,
+0xf0,0x7,0x80,0xf0,0,0,0,0,0,0,
+0x7,0x1f,0x7,0xc3,0xff,0x1,0xf0,0x3e,0x78,0xf,
+0x1,0xef,0x3,0xc0,0x1,0xe0,0,0,0x1e,0x1e,
+0x3,0xc7,0x80,0xf0,0,0,0,0,0,0,
+0,0,0,0x1,0xe0,0x3e,0x7,0,0,0x3c,
+0,0xff,0xc0,0xf,0x80,0x7c,0x1f,0,0x3e,0x1f,
+0,0x3e,0x1f,0,0,0x7c,0,0x7,0xc0,0x7,
+0xc3,0xe0,0xf,0x87,0xc0,0x1,0xf0,0xf8,0xf8,0,
+0xf8,0,0xf,0xf8,0x3f,0xe1,0xff,0x7,0xc1,0xf0,
+0x1,0xf0,0xf8,0x7,0xc3,0xe0,0x3,0xe0,0xf8,0x3,
+0xe0,0xf0,0x7,0x80,0x1f,0,0x3e,0,0xf8,0x1f,
+0x3,0xe0,0xf8,0x7f,0x87,0xc0,0x3e,0xf8,0x1,0xf9,
+0xf0,0,0x1f,0x81,0xe0,0x30,0x7,0x80,0x7f,0x80,
+0,0,0,0,0x7f,0x80,0xf3,0xf0,0,0xfc,
+0,0x7e,0x78,0x3,0xf0,0x3f,0xf0,0x3f,0x3c,0x1e,
+0x3c,0x1,0xe0,0xf0,0x78,0x1f,0xf,0x7,0x8f,0x7,
+0xc0,0x1e,0x3e,0,0x1f,0xc0,0x1e,0x3e,0,0x1f,
+0x3c,0x1e,0x18,0xf,0xe0,0x3f,0xe3,0xc0,0x78,0xf8,
+0xf,0x9f,0x7,0xc1,0xf3,0xe0,0x7c,0x7c,0xf,0x8f,
+0xff,0xc0,0xf0,0xe,0x1,0xe0,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,0x3,0xe0,0x7,0xf0,
+0x3e,0x7,0xcf,0x7d,0xe0,0x79,0xe0,0x38,0x3f,0x80,
+0,0x3,0x83,0xfc,0x1c,0xe3,0x80,0,0,0,
+0,0,0xe,0x1c,0x3c,0x70,0,0x30,0x60,0xf,
+0,0x3,0xc1,0xf0,0,0x1e,0x3,0xc7,0xfc,0x60,
+0,0,0,0xe1,0xc3,0x80,0,0,0xe0,0x38,
+0,0xe,0x7,0,0,0x7c,0xe,0,0x3,0xe0,
+0,0x7f,0xe0,0,0xff,0xc0,0x1,0xff,0x80,0x3,
+0xff,0,0x7,0xfe,0,0xf,0xfc,0,0x1f,0x1e,
+0,0x1,0xf0,0x3,0xe3,0xe0,0,0xf,0x80,0,
+0x3e,0,0,0xf8,0,0x3,0xe1,0xf0,0x7c,0x1f,
+0x7,0xc0,0x1f,0xf,0xf8,0x3e,0xf,0x80,0xf,0x87,
+0xc0,0x7,0xc3,0xe0,0x3,0xe1,0xf0,0x1,0xf0,0xf8,
+0,0xf8,0,0,0xf,0x80,0x7f,0x87,0xc0,0x1f,
+0x7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,0x1,
+0xf9,0xf0,0x1f,0x3,0xf0,0x78,0x1f,0,0xff,0,
+0x3f,0xc0,0xf,0xf0,0x3,0xfc,0,0xff,0,0x3f,
+0xc0,0x1f,0xfb,0xfe,0,0x3f,0,0xf,0xc0,0x3,
+0xf0,0,0xfc,0,0x3f,0,0x3c,0x78,0x3c,0x1e,
+0,0xff,0x80,0xf3,0xf0,0,0xfe,0,0xf,0xe0,
+0,0xfe,0,0xf,0xe0,0,0xfe,0,0,0,
+0x1,0xfc,0x39,0xe0,0x3c,0x1e,0x3,0xc1,0xe0,0x3c,
+0x1e,0x3,0xc3,0xe0,0x7c,0x3c,0xfc,0x7,0xc0,0xf8,
+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,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,0xf,0x81,0x83,0x7,0xff,
+0xfc,0xf1,0x8f,0x38,0x38,0xe0,0,0x1f,0xf8,0,
+0x60,0xf0,0x7,0x81,0xf8,0,0,0,0,0,
+0,0x6,0x1f,0x7,0xc3,0xff,0x1,0xe0,0x3e,0x78,
+0xf,0x1,0xcf,0x3,0xc0,0x1,0xe0,0,0,0x3c,
+0x1e,0x3,0xc7,0x80,0xf0,0x7c,0xf,0x80,0,0,
+0,0,0,0,0x1,0xe0,0x3e,0xf,0x1,0xf7,
+0x1c,0x1,0xf3,0xe0,0xf,0x80,0x7c,0x1f,0,0x3e,
+0x1f,0,0x3f,0x1f,0,0,0x7c,0,0xf,0xc0,
+0,0x3,0xe0,0xf,0x87,0xc0,0x1,0xf0,0xf9,0xf8,
+0,0xf8,0,0xf,0xb8,0x3b,0xe1,0xff,0x87,0xc1,
+0xf0,0x1,0xf0,0xf8,0x7,0xc7,0xe0,0x3,0xf0,0xf8,
+0x3,0xe0,0xf8,0,0,0x1f,0,0x3e,0,0xf8,
+0xf,0x3,0xc0,0x78,0x7f,0x87,0xc0,0x1f,0xf8,0,
+0xf9,0xf0,0,0x1f,0x1,0xe0,0x38,0x7,0x80,0xf3,
+0xc0,0,0,0,0x1,0xff,0xe0,0xf7,0xfc,0x3,
+0xff,0,0xff,0x78,0xf,0xfc,0x3f,0xf0,0x7f,0xbc,
+0x1e,0xff,0x1,0xe0,0xf0,0x78,0x3e,0xf,0x7,0xbf,
+0xdf,0xf0,0x1e,0xff,0x80,0x7f,0xf0,0x1e,0xff,0,
+0x7f,0xbc,0x1e,0x78,0x3f,0xf8,0x3f,0xe3,0xc0,0x78,
+0xf8,0xf,0x9f,0x7,0xc1,0xf3,0xf0,0xfc,0x7c,0xf,
+0x8f,0xff,0xc0,0xf0,0xe,0x1,0xe0,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,0x3,0xe0,0x1f,
+0xf8,0x3e,0x3,0xcf,0xff,0xe0,0x79,0xe0,0x38,0x1f,
+0xe0,0,0x7,0x7,0x9e,0xc,0xe3,0x80,0,0,
+0,0,0,0x1c,0x1c,0x1c,0x30,0,0x18,0xc0,
+0xf,0,0x7,0x81,0xf0,0,0x1e,0x3,0xc7,0xfc,
+0x60,0,0,0,0xe0,0xe7,0,0,0,0xe0,
+0x38,0,0xe,0x7,0,0,0x7c,0xe,0,0x3,
+0xe0,0,0xf9,0xf0,0x1,0xf3,0xe0,0x3,0xe7,0xc0,
+0x7,0xcf,0x80,0xf,0x9f,0,0x1f,0x3e,0,0x1e,
+0x1e,0,0x1,0xf0,0x3,0xe3,0xe0,0,0xf,0x80,
+0,0x3e,0,0,0xf8,0,0x3,0xe1,0xf0,0x7c,
+0x1f,0x7,0xc0,0x1f,0x8f,0xfc,0x3e,0xf,0x80,0xf,
+0x87,0xc0,0x7,0xc3,0xe0,0x3,0xe1,0xf0,0x1,0xf0,
+0xf8,0,0xf8,0,0,0xf,0x80,0xf7,0x87,0xc0,
+0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,
+0,0xf9,0xf0,0x1f,0x1,0xf8,0x78,0x3e,0x3,0xff,
+0xc0,0xff,0xf0,0x3f,0xfc,0xf,0xff,0x3,0xff,0xc0,
+0xff,0xf0,0x3f,0xff,0xff,0,0xff,0xc0,0x3f,0xf0,
+0xf,0xfc,0x3,0xff,0,0xff,0xc0,0x3c,0x78,0x3c,
+0x1e,0x3,0xff,0xc0,0xf7,0xf8,0x3,0xff,0x80,0x3f,
+0xf8,0x3,0xff,0x80,0x3f,0xf8,0x3,0xff,0x80,0,
+0,0x7,0xff,0x71,0xe0,0x3c,0x1e,0x3,0xc1,0xe0,
+0x3c,0x1e,0x3,0xc3,0xe0,0x7c,0x3d,0xff,0x7,0xc0,
+0xf8,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,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,0xf,0x80,0,0x7,
+0xff,0xfc,0xf9,0x80,0x38,0x38,0xe0,0,0xf,0xf8,
+0,0,0xf0,0x7,0x83,0xfc,0,0xf0,0,0,
+0,0,0x6,0x1e,0x3,0xc0,0xf,0x1,0xe0,0x3e,
+0,0x1f,0x3,0xcf,0x3,0xdf,0x1,0xe7,0xc0,0,
+0x7c,0x1f,0x7,0xc7,0x80,0xf0,0x7c,0xf,0x80,0,
+0x18,0,0,0x18,0,0,0,0x7e,0xe,0x7,
+0xff,0x1c,0x1,0xf3,0xe0,0xf,0x80,0xf8,0x3e,0,
+0,0x1f,0,0x1f,0x1f,0,0,0x7c,0,0xf,
+0x80,0,0x3,0xe0,0xf,0x87,0xc0,0x1,0xf0,0xfb,
+0xf0,0,0xf8,0,0xf,0xb8,0x3b,0xe1,0xf7,0x87,
+0xc3,0xe0,0,0xf8,0xf8,0x7,0xc7,0xc0,0x1,0xf0,
+0xf8,0x7,0xc0,0xfe,0,0,0x1f,0,0x3e,0,
+0xf8,0xf,0x87,0xc0,0x78,0x73,0x87,0x80,0x1f,0xf0,
+0,0xff,0xe0,0,0x3f,0x1,0xe0,0x38,0x7,0x80,
+0xf3,0xc0,0,0,0,0x3,0xff,0xe0,0xff,0xfc,
+0x7,0xff,0x81,0xff,0xf8,0x1f,0xfe,0x3f,0xf0,0xff,
+0xfc,0x1f,0xff,0x81,0xe0,0xf0,0x78,0x7c,0xf,0x7,
+0xff,0xff,0xf0,0x1f,0xff,0x80,0xff,0xf8,0x1f,0xff,
+0x80,0xff,0xfc,0x1e,0xf8,0x7f,0xfc,0x3f,0xe3,0xc0,
+0x78,0x7c,0x1f,0xf,0x7,0xc1,0xe1,0xf0,0xf8,0x7c,
+0xf,0xf,0xff,0xc0,0xf0,0xe,0x1,0xe0,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,0x3,0xe0,
+0x3f,0xfc,0x3e,0,0x7,0xff,0xc0,0x3f,0xc0,0x38,
+0xf,0xf0,0,0x7,0xe,0x7,0xe,0xff,0x80,0,
+0,0,0,0,0x1c,0x1c,0x1c,0x30,0,0x1f,
+0xc3,0xff,0xfc,0xf,0,0x78,0,0x1e,0x3,0xc7,
+0xfc,0x60,0x30,0,0,0xe0,0xff,0,0,0,
+0xe0,0x70,0,0xe,0xe,0,0,0x7e,0x1c,0,
+0x3,0xe0,0,0xf9,0xf0,0x1,0xf3,0xe0,0x3,0xe7,
+0xc0,0x7,0xcf,0x80,0xf,0x9f,0,0x1f,0x3e,0,
+0x3e,0x1e,0,0x3,0xe0,0,0x3,0xe0,0,0xf,
+0x80,0,0x3e,0,0,0xf8,0,0x3,0xe1,0xf0,
+0x7c,0x1f,0x7,0xc0,0xf,0x8f,0xbc,0x3e,0x1f,0,
+0x7,0xcf,0x80,0x3,0xe7,0xc0,0x1,0xf3,0xe0,0,
+0xf9,0xf0,0,0x7c,0x10,0x4,0x1f,0,0xe7,0xc7,
+0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,
+0x1f,0,0xff,0xe0,0x1f,0,0xf8,0x78,0x7e,0x7,
+0xff,0xc1,0xff,0xf0,0x7f,0xfc,0x1f,0xff,0x7,0xff,
+0xc1,0xff,0xf0,0x3f,0xff,0xff,0x1,0xff,0xe0,0x7f,
+0xf8,0x1f,0xfe,0x7,0xff,0x81,0xff,0xe0,0x3c,0x78,
+0x3c,0x1e,0x7,0xff,0xc0,0xff,0xfc,0x7,0xff,0xc0,
+0x7f,0xfc,0x7,0xff,0xc0,0x7f,0xfc,0x7,0xff,0xc0,
+0x7,0x80,0xf,0xff,0xe1,0xe0,0x3c,0x1e,0x3,0xc1,
+0xe0,0x3c,0x1e,0x3,0xc3,0xe0,0x7c,0x3f,0xff,0x87,
+0xc0,0xf8,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,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,0xf,0x80,0,
+0x7,0xff,0xfc,0xff,0x80,0x1c,0x71,0xc0,0,0xf,
+0xf0,0,0x1,0xe0,0x3,0xc3,0x9c,0,0xf0,0,
+0,0,0,0x6,0x1e,0x3,0xc0,0xf,0,0,
+0x7e,0,0x3e,0x3,0x8f,0x3,0xff,0xc1,0xef,0xf0,
+0,0x78,0xf,0x8f,0x87,0x80,0xf0,0x7c,0xf,0x80,
+0,0xf8,0,0,0x1e,0,0,0,0xfc,0x1c,
+0xf,0x3f,0xe,0x1,0xf3,0xe0,0xf,0xff,0xf0,0x3e,
+0,0,0x1f,0,0x1f,0x1f,0xff,0xe0,0x7f,0xff,
+0xf,0x80,0,0x3,0xff,0xff,0x87,0xc0,0x1,0xf0,
+0xff,0xe0,0,0xf8,0,0xf,0xbc,0x7b,0xe1,0xf7,
+0xc7,0xc3,0xe0,0,0xf8,0xf8,0xf,0xc7,0xc0,0x1,
+0xf0,0xf8,0xf,0xc0,0x7f,0xe0,0,0x1f,0,0x3e,
+0,0xf8,0xf,0x87,0xc0,0x7c,0xf3,0xc7,0x80,0xf,
+0xf0,0,0x7f,0xe0,0,0x7e,0x1,0xe0,0x18,0x7,
+0x80,0xe1,0xc0,0,0,0,0x3,0xe1,0xf0,0xff,
+0xfe,0x7,0xff,0x83,0xff,0xf8,0x3f,0xff,0x7,0x81,
+0xff,0xfc,0x1f,0xff,0x81,0xe0,0xf0,0x78,0xf8,0xf,
+0x7,0xff,0xff,0xf8,0x1f,0xff,0xc1,0xff,0xfc,0x1f,
+0xff,0xc1,0xff,0xfc,0x1f,0xf8,0xf8,0x7c,0xf,0x3,
+0xc0,0x78,0x7c,0x1f,0xf,0x87,0xc3,0xe0,0xf9,0xf0,
+0x3c,0x1f,0xf,0xff,0xc0,0xf0,0xe,0x1,0xe0,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,0x3,
+0xe0,0x7f,0xfc,0x3f,0,0x3,0xc7,0x80,0x3f,0xc0,
+0x38,0x1f,0xfc,0,0x6,0xe,0x7,0x6,0x7b,0x80,
+0x20,0x40,0,0,0,0x18,0x1c,0x1c,0x38,0,
+0xf,0x83,0xff,0xfc,0x3e,0,0x38,0,0x1e,0x3,
+0xc3,0xfc,0x60,0x78,0,0,0xe0,0x7e,0x4,0x8,
+0,0xe0,0x70,0,0xe,0xe,0,0,0xe,0x38,
+0,0x3,0xe0,0,0xf9,0xf0,0x1,0xf3,0xe0,0x3,
+0xe7,0xc0,0x7,0xcf,0x80,0xf,0x9f,0,0x1f,0x3e,
+0,0x3e,0x1e,0,0x3,0xe0,0,0x3,0xff,0xfc,
+0xf,0xff,0xf0,0x3f,0xff,0xc0,0xff,0xff,0x3,0xe1,
+0xf0,0x7c,0x1f,0x7,0xc0,0xf,0x8f,0xbe,0x3e,0x1f,
+0,0x7,0xcf,0x80,0x3,0xe7,0xc0,0x1,0xf3,0xe0,
+0,0xf9,0xf0,0,0x7c,0x38,0xe,0x1f,0x1,0xc7,
+0xc7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,
+0xc0,0x1f,0,0x7f,0xe0,0x1f,0,0xf8,0x78,0xfc,
+0x7,0xc3,0xe1,0xf0,0xf8,0x7c,0x3e,0x1f,0xf,0x87,
+0xc3,0xe1,0xf0,0xf8,0x7c,0x3f,0xf,0x81,0xff,0xe0,
+0xff,0xfc,0x3f,0xff,0xf,0xff,0xc3,0xff,0xf0,0x3c,
+0x78,0x3c,0x1e,0xf,0xff,0xe0,0xff,0xfe,0xf,0xff,
+0xe0,0xff,0xfe,0xf,0xff,0xe0,0xff,0xfe,0xf,0xff,
+0xe0,0x7,0x80,0x1f,0xff,0xc1,0xe0,0x3c,0x1e,0x3,
+0xc1,0xe0,0x3c,0x1e,0x3,0xc1,0xe0,0x78,0x3f,0xff,
+0x83,0xc1,0xf0,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,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,0x7,0,
+0,0x7,0xff,0xfc,0x7f,0xc0,0x1f,0xf1,0x80,0,
+0xf,0xe0,0,0x1,0xe0,0x3,0xc1,0x8,0,0xf0,
+0,0,0,0,0xe,0x1e,0x3,0xc0,0xf,0,
+0,0x7c,0x1,0xfc,0x7,0x8f,0x3,0xff,0xe1,0xff,
+0xf8,0,0xf8,0x7,0xff,0x7,0xc1,0xf0,0x7c,0xf,
+0x80,0x3,0xf8,0x7f,0xff,0x1f,0xc0,0,0x1,0xfc,
+0x1c,0x1e,0x1e,0xe,0x3,0xe1,0xe0,0xf,0xff,0xf0,
+0x3e,0,0,0x1f,0,0x1f,0x1f,0xff,0xe0,0x7f,
+0xff,0xf,0x80,0,0x3,0xff,0xff,0x87,0xc0,0x1,
+0xf0,0xff,0xe0,0,0xf8,0,0xf,0xbc,0x7b,0xe1,
+0xf3,0xc7,0xc3,0xe0,0,0xf8,0xf8,0x1f,0x87,0xc0,
+0x1,0xf0,0xff,0xff,0x80,0x7f,0xfc,0,0x1f,0,
+0x3e,0,0xf8,0x7,0x87,0x80,0x7c,0xf3,0xcf,0x80,
+0xf,0xe0,0,0x7f,0xc0,0,0xfc,0x1,0xe0,0x1c,
+0x7,0x81,0xe1,0xe0,0,0,0,0x7,0xc0,0xf0,
+0xfc,0x3e,0xf,0x87,0xc3,0xe1,0xf8,0x3e,0x1f,0x7,
+0x81,0xf0,0xfc,0x1f,0x87,0xc1,0xe0,0xf0,0x79,0xf0,
+0xf,0x7,0xe3,0xf8,0xf8,0x1f,0x87,0xc1,0xf0,0x7c,
+0x1f,0x87,0xc1,0xf0,0xfc,0x1f,0xf8,0xf0,0x3e,0xf,
+0x3,0xc0,0x78,0x3c,0x1e,0xf,0x8f,0xe3,0xe0,0xf9,
+0xe0,0x3e,0x1f,0,0xf,0x80,0xf0,0xe,0x1,0xe0,
+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,
+0x3,0xe0,0x7c,0xbe,0x1f,0,0x7,0x83,0xc0,0x1f,
+0x80,0x38,0x3f,0xfe,0,0x6,0x1c,0,0x6,0,
+0,0x60,0xc3,0xff,0xfc,0,0x18,0x1c,0x38,0x38,
+0,0,0x3,0xff,0xfc,0x78,0x1c,0x38,0,0x1e,
+0x3,0xc3,0xfc,0x60,0x78,0,0,0xe0,0,0x6,
+0xc,0,0xe0,0xe0,0x70,0xe,0x1c,0x3f,0x7,0xe,
+0x38,0x70,0,0,0x1,0xf0,0xf0,0x3,0xe1,0xe0,
+0x7,0xc3,0xc0,0xf,0x87,0x80,0x1f,0xf,0,0x3e,
+0x1e,0,0x3e,0x1f,0xff,0xc3,0xe0,0,0x3,0xff,
+0xfc,0xf,0xff,0xf0,0x3f,0xff,0xc0,0xff,0xff,0x3,
+0xe1,0xf0,0x7c,0x1f,0x3f,0xfc,0xf,0x8f,0x9e,0x3e,
+0x1f,0,0x7,0xcf,0x80,0x3,0xe7,0xc0,0x1,0xf3,
+0xe0,0,0xf9,0xf0,0,0x7c,0x7c,0x1f,0x1f,0x3,
+0x87,0xc7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,
+0x7,0xc0,0x1f,0,0x7f,0xc0,0x1f,0,0xf8,0x78,
+0xfe,0xf,0x81,0xe3,0xe0,0x78,0xf8,0x1e,0x3e,0x7,
+0x8f,0x81,0xe3,0xe0,0x78,0x78,0x1e,0x7,0x83,0xe1,
+0xf0,0xf8,0x7c,0x3e,0x1f,0xf,0x87,0xc3,0xe1,0xf0,
+0x3c,0x78,0x3c,0x1e,0xf,0x83,0xe0,0xfc,0x3e,0xf,
+0x83,0xe0,0xf8,0x3e,0xf,0x83,0xe0,0xf8,0x3e,0xf,
+0x83,0xe0,0x7,0x80,0x1f,0x8f,0xc1,0xe0,0x3c,0x1e,
+0x3,0xc1,0xe0,0x3c,0x1e,0x3,0xc1,0xf0,0xf8,0x3f,
+0xf,0xc3,0xe1,0xf0,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,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,0x7,
+0,0,0,0xf1,0xc0,0x3f,0xf0,0xf,0xe3,0x80,
+0,0x3f,0xf1,0xe0,0x1,0xe0,0x3,0xc0,0,0,
+0xf0,0,0,0,0,0xc,0x1e,0x3,0xc0,0xf,
+0,0,0xfc,0x1,0xf8,0xf,0xf,0x3,0xff,0xe1,
+0xff,0xf8,0,0xf0,0x7,0xff,0x7,0xe3,0xf0,0x7c,
+0xf,0x80,0x1f,0xf8,0x7f,0xff,0x1f,0xf8,0,0x3,
+0xf8,0x3c,0x3c,0xe,0xe,0x3,0xe1,0xf0,0xf,0xff,
+0xf8,0x3e,0,0,0x1f,0,0x1f,0x1f,0xff,0xe0,
+0x7f,0xff,0xf,0x80,0xff,0xc3,0xff,0xff,0x87,0xc0,
+0x1,0xf0,0xff,0xf0,0,0xf8,0,0xf,0xbc,0x7b,
+0xe1,0xf3,0xe7,0xc3,0xe0,0,0xf8,0xff,0xff,0x87,
+0xc0,0x1,0xf0,0xff,0xff,0,0x3f,0xff,0,0x1f,
+0,0x3e,0,0xf8,0x7,0x87,0x80,0x3c,0xf3,0xcf,
+0x80,0x7,0xe0,0,0x3f,0xc0,0,0xfc,0x1,0xe0,
+0x1c,0x7,0x81,0xe1,0xe0,0,0,0,0x7,0xc0,
+0xf0,0xf8,0x1f,0xf,0x7,0xc7,0xc0,0xf8,0x7c,0xf,
+0x87,0x83,0xe0,0x7c,0x1f,0x3,0xc1,0xe0,0xf0,0x7b,
+0xe0,0xf,0x7,0xc1,0xf0,0x78,0x1f,0x3,0xc3,0xe0,
+0x3e,0x1f,0x3,0xe3,0xe0,0x7c,0x1f,0x80,0xf0,0x3e,
+0xf,0x3,0xc0,0x78,0x3c,0x1e,0x7,0x8f,0xe3,0xc0,
+0x7f,0xe0,0x3e,0x1e,0,0x1f,0,0xf0,0xe,0x1,
+0xe0,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,0xf8,0x9e,0x7f,0xf8,0x7,0x1,0xc0,
+0xf,0,0x38,0x38,0xff,0,0x6,0x1c,0,0x6,
+0,0,0xe1,0xc3,0xff,0xfc,0,0x18,0x1f,0xf0,
+0x38,0,0,0x3,0xff,0xfc,0x70,0x1c,0x38,0,
+0x1e,0x3,0xc1,0xfc,0x60,0x78,0,0,0xe0,0,
+0x7,0xe,0,0xe1,0xc0,0xf0,0xe,0x18,0x7f,0x87,
+0xe,0x70,0xf0,0,0,0x1,0xf0,0xf8,0x3,0xe1,
+0xf0,0x7,0xc3,0xe0,0xf,0x87,0xc0,0x1f,0xf,0x80,
+0x3e,0x1f,0,0x7c,0x1f,0xff,0xc3,0xe0,0,0x3,
+0xff,0xfc,0xf,0xff,0xf0,0x3f,0xff,0xc0,0xff,0xff,
+0x3,0xe1,0xf0,0x7c,0x1f,0x3f,0xfc,0xf,0x8f,0x9f,
+0x3e,0x1f,0,0x7,0xcf,0x80,0x3,0xe7,0xc0,0x1,
+0xf3,0xe0,0,0xf9,0xf0,0,0x7c,0x7e,0x3f,0x1f,
+0x7,0x7,0xc7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,
+0x1f,0x7,0xc0,0x1f,0,0x3f,0xc0,0x1f,0,0xf8,
+0x78,0xff,0xf,0x81,0xe3,0xe0,0x78,0xf8,0x1e,0x3e,
+0x7,0x8f,0x81,0xe3,0xe0,0x78,0x78,0x1e,0x7,0xc3,
+0xc0,0xf1,0xf0,0x3c,0x7c,0xf,0x1f,0x3,0xc7,0xc0,
+0xf0,0x3c,0x78,0x3c,0x1e,0x1f,0x1,0xf0,0xf8,0x3e,
+0x1f,0x1,0xf1,0xf0,0x1f,0x1f,0x1,0xf1,0xf0,0x1f,
+0x1f,0x1,0xf0,0x7,0x80,0x3e,0x7,0xe1,0xe0,0x3c,
+0x1e,0x3,0xc1,0xe0,0x3c,0x1e,0x3,0xc1,0xf0,0xf0,
+0x3e,0x7,0xc3,0xe1,0xe0,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,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,
+0x7,0,0,0,0xe1,0xc0,0xf,0xfc,0x3,0x83,
+0x7,0,0x7f,0xf1,0xe0,0x1,0xe0,0x3,0xc0,0,
+0,0xf0,0,0x3,0xfe,0,0xc,0x1e,0x3,0xc0,
+0xf,0,0x1,0xf8,0x1,0xfe,0xe,0xf,0x3,0xc3,
+0xf1,0xf8,0xfc,0x1,0xf0,0xf,0xff,0x83,0xff,0xf0,
+0,0,0,0x7f,0xf0,0x7f,0xff,0xf,0xfe,0,
+0x3,0xf0,0x38,0x38,0xe,0xe,0x3,0xe1,0xf0,0xf,
+0xff,0xfc,0x3e,0,0,0x1f,0,0x1f,0x1f,0xff,
+0xe0,0x7f,0xff,0xf,0x80,0xff,0xc3,0xff,0xff,0x87,
+0xc0,0x1,0xf0,0xff,0xf0,0,0xf8,0,0xf,0x9c,
+0x73,0xe1,0xf1,0xe7,0xc3,0xe0,0,0xf8,0xff,0xff,
+0x7,0xc0,0x1,0xf0,0xff,0xff,0,0x7,0xff,0x80,
+0x1f,0,0x3e,0,0xf8,0x7,0x87,0x80,0x3c,0xf3,
+0xcf,0,0xf,0xe0,0,0x3f,0x80,0x1,0xf8,0x1,
+0xe0,0xc,0x7,0x81,0xc0,0xf0,0,0,0,0,
+0x7,0xf0,0xf0,0x1f,0x1e,0x3,0xc7,0x80,0x78,0x78,
+0xf,0x87,0x83,0xe0,0x7c,0x1f,0x3,0xc1,0xe0,0xf0,
+0x7f,0xc0,0xf,0x7,0x81,0xe0,0x78,0x1e,0x3,0xc3,
+0xe0,0x3e,0x1f,0x3,0xe3,0xc0,0x3c,0x1f,0,0xf8,
+0,0xf,0x3,0xc0,0x78,0x3e,0x3e,0x7,0x8f,0xe3,
+0xc0,0x3f,0xc0,0x1e,0x1e,0,0x3f,0,0xf0,0xe,
+0x1,0xe0,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,0xf9,0x9e,0x7f,0xf8,0x7,0x1,
+0xc1,0xff,0xf8,0,0x78,0x7f,0x80,0x6,0x1c,0,
+0x6,0xff,0x81,0xe3,0xc3,0xff,0xfc,0x7f,0xd8,0x1f,
+0xe0,0x38,0,0,0,0xf,0,0xff,0xde,0x78,
+0,0x1e,0x3,0xc1,0xfc,0x60,0x30,0,0,0xe1,
+0xff,0x87,0x8f,0,0xe1,0xc1,0xf0,0xe,0x38,0xf3,
+0xc7,0x9e,0x70,0xf0,0x3,0xc0,0x1,0xf0,0xf8,0x3,
+0xe1,0xf0,0x7,0xc3,0xe0,0xf,0x87,0xc0,0x1f,0xf,
+0x80,0x3e,0x1f,0,0x7c,0x1f,0xff,0xc3,0xe0,0,
+0x3,0xff,0xfc,0xf,0xff,0xf0,0x3f,0xff,0xc0,0xff,
+0xff,0x3,0xe1,0xf0,0x7c,0x1f,0x3f,0xfc,0xf,0x8f,
+0x8f,0x3e,0x1f,0,0x7,0xcf,0x80,0x3,0xe7,0xc0,
+0x1,0xf3,0xe0,0,0xf9,0xf0,0,0x7c,0x3f,0x7e,
+0x1f,0xe,0x7,0xc7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,
+0xc0,0x1f,0x7,0xc0,0x1f,0,0x3f,0x80,0x1f,0x1,
+0xf8,0x78,0x3f,0x80,0x1f,0xe0,0x7,0xf8,0x1,0xfe,
+0,0x7f,0x80,0x1f,0xe0,0x7,0xf8,0,0x3e,0x7,
+0xc7,0xc0,0xf1,0xe0,0x3e,0x78,0xf,0x9e,0x3,0xe7,
+0x80,0xf8,0x3c,0x78,0x3c,0x1e,0x1f,0x1,0xf0,0xf0,
+0x1e,0x1f,0x1,0xf1,0xf0,0x1f,0x1f,0x1,0xf1,0xf0,
+0x1f,0x1f,0x1,0xf0,0,0,0x3e,0xf,0xe1,0xe0,
+0x3c,0x1e,0x3,0xc1,0xe0,0x3c,0x1e,0x3,0xc0,0xf0,
+0xf0,0x3e,0x7,0xc3,0xe1,0xe0,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,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,0x7,0,0,0,0xe1,0xc0,0x1,0xfe,0,
+0x7,0x1f,0xc0,0x7c,0xf9,0xc0,0x1,0xe0,0x3,0xc0,
+0,0,0xf0,0,0x3,0xfe,0,0xc,0x1e,0x3,
+0xc0,0xf,0,0x3,0xf0,0,0x3f,0x1e,0xf,0,
+0x1,0xf1,0xf0,0x7c,0x1,0xe0,0x1f,0x7,0xc3,0xff,
+0xf0,0,0,0x3,0xff,0xc0,0x7f,0xff,0x3,0xff,
+0xc0,0x7,0xc0,0x38,0x78,0xe,0xe,0x7,0xc0,0xf0,
+0xf,0x80,0x7c,0x3e,0,0,0x1f,0,0x1f,0x1f,
+0,0,0x7c,0,0xf,0x80,0xff,0xc3,0xe0,0xf,
+0x87,0xc0,0x1,0xf0,0xff,0xf8,0,0xf8,0,0xf,
+0x9e,0xf3,0xe1,0xf1,0xf7,0xc3,0xe0,0,0xf8,0xff,
+0xfc,0x7,0xc0,0x1,0xf0,0xff,0xff,0x80,0,0x7f,
+0x80,0x1f,0,0x3e,0,0xf8,0x3,0xcf,0,0x3c,
+0xe1,0xcf,0,0xf,0xf0,0,0x3f,0x80,0x3,0xf0,
+0x1,0xe0,0xc,0x7,0x83,0xc0,0xf0,0,0,0,
+0,0x7f,0xf0,0xf0,0xf,0x1e,0,0x7,0x80,0x78,
+0x7f,0xff,0x87,0x83,0xc0,0x3c,0x1e,0x3,0xc1,0xe0,
+0xf0,0x7f,0xe0,0xf,0x7,0x81,0xe0,0x78,0x1e,0x3,
+0xc3,0xc0,0x1e,0x1e,0x1,0xe3,0xc0,0x3c,0x1f,0,
+0xff,0x80,0xf,0x3,0xc0,0x78,0x1e,0x3c,0x7,0x8e,
+0xe3,0xc0,0x1f,0x80,0x1f,0x3e,0,0x7e,0x1,0xf0,
+0xe,0x1,0xf0,0x1c,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,0x1,0xc0,0xf1,0x80,0xf,0x80,0x7,
+0x1,0xc1,0xff,0xf8,0,0x78,0x1f,0x80,0x6,0x1c,
+0,0x6,0xff,0x83,0xc7,0x83,0xff,0xfc,0x7f,0xd8,
+0x1c,0x70,0x38,0,0,0,0xf,0,0xff,0xcf,
+0xf0,0,0x1e,0x3,0xc0,0x7c,0x60,0,0,0,
+0xe1,0xff,0x83,0xc7,0x80,0xe3,0x81,0xf0,0xe,0x70,
+0xe1,0xc3,0xfc,0xe1,0xf0,0x3,0xc0,0x3,0xe0,0x78,
+0x7,0xc0,0xf0,0xf,0x81,0xe0,0x1f,0x3,0xc0,0x3e,
+0x7,0x80,0x7c,0xf,0,0x7c,0x1f,0xff,0xc3,0xe0,
+0,0x3,0xe0,0,0xf,0x80,0,0x3e,0,0,
+0xf8,0,0x3,0xe1,0xf0,0x7c,0x1f,0x7,0xc0,0xf,
+0x8f,0x8f,0xbe,0x1f,0,0x7,0xcf,0x80,0x3,0xe7,
+0xc0,0x1,0xf3,0xe0,0,0xf9,0xf0,0,0x7c,0x1f,
+0xfc,0x1f,0x1c,0x7,0xc7,0xc0,0x1f,0x7,0xc0,0x1f,
+0x7,0xc0,0x1f,0x7,0xc0,0x1f,0,0x3f,0x80,0x1f,
+0x3,0xf0,0x78,0xf,0x80,0xff,0xe0,0x3f,0xf8,0xf,
+0xfe,0x3,0xff,0x80,0xff,0xe0,0x3f,0xf8,0x7,0xff,
+0xff,0xc7,0x80,0x1,0xff,0xfe,0x7f,0xff,0x9f,0xff,
+0xe7,0xff,0xf8,0x3c,0x78,0x3c,0x1e,0x1e,0,0xf0,
+0xf0,0x1e,0x1e,0,0xf1,0xe0,0xf,0x1e,0,0xf1,
+0xe0,0xf,0x1e,0,0xf0,0,0,0x3c,0x1d,0xe1,
+0xe0,0x3c,0x1e,0x3,0xc1,0xe0,0x3c,0x1e,0x3,0xc0,
+0xf0,0xf0,0x3c,0x3,0xc1,0xf3,0xe0,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,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,0x7,0,0,0,0xe3,0xc0,0x1,0xff,
+0,0x6,0x3f,0xe0,0xf8,0xff,0xc0,0x1,0xe0,0x3,
+0xc0,0,0x3f,0xff,0xc0,0x3,0xfe,0,0x18,0x1e,
+0x3,0xc0,0xf,0,0xf,0xe0,0,0x1f,0x9c,0xf,
+0,0x1,0xf1,0xe0,0x3c,0x3,0xe0,0x3e,0x3,0xe1,
+0xfe,0xf0,0,0,0x7,0xfe,0,0,0,0,
+0x7f,0xe0,0x7,0x80,0x38,0x70,0x1c,0x1e,0x7,0xc0,
+0xf8,0xf,0x80,0x3e,0x3e,0,0,0x1f,0,0x1f,
+0x1f,0,0,0x7c,0,0xf,0x80,0xff,0xc3,0xe0,
+0xf,0x87,0xc7,0xc1,0xf0,0xfc,0xfc,0,0xf8,0,
+0xf,0x9e,0xf3,0xe1,0xf0,0xf7,0xc3,0xe0,0,0xf8,
+0xff,0xf0,0x7,0xc0,0x11,0xf0,0xf8,0xf,0xc0,0,
+0xf,0xc0,0x1f,0,0x3e,0,0xf8,0x3,0xcf,0,
+0x3c,0xe1,0xcf,0,0x1f,0xf0,0,0x1f,0,0x3,
+0xe0,0x1,0xe0,0xe,0x7,0x83,0xc0,0xf0,0,0,
+0,0x1,0xff,0xf0,0xf0,0xf,0x1e,0,0x7,0x80,
+0x78,0x7f,0xff,0x87,0x83,0xc0,0x3c,0x1e,0x3,0xc1,
+0xe0,0xf0,0x7f,0xe0,0xf,0x7,0x81,0xe0,0x78,0x1e,
+0x3,0xc3,0xc0,0x1e,0x1e,0x1,0xe3,0xc0,0x3c,0x1e,
+0,0x7f,0xf0,0xf,0x3,0xc0,0x78,0x1e,0x3c,0x7,
+0x9e,0xf3,0xc0,0xf,0,0x1f,0x3c,0,0xfc,0x1,
+0xe0,0xe,0,0xf0,0x3f,0x6,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,0x1,0xc0,0xf1,0x80,0x7,0x80,
+0x7,0x83,0xc0,0xf,0,0,0x7c,0xf,0x80,0x6,
+0xe,0x7,0x6,0xff,0x83,0x87,0,0,0x3c,0x7f,
+0xd8,0x1c,0x78,0x38,0,0,0,0xf,0,0xff,
+0xc7,0xc0,0,0x1e,0x3,0xc0,0xc,0x60,0,0,
+0,0xe1,0xff,0x81,0xc3,0x80,0x3,0x83,0x70,0,
+0x70,0xe1,0xc1,0xf8,0xe3,0xf0,0x3,0xc0,0x3,0xe0,
+0x7c,0x7,0xc0,0xf8,0xf,0x81,0xf0,0x1f,0x3,0xe0,
+0x3e,0x7,0xc0,0x7c,0xf,0x80,0xf8,0x1e,0,0x3,
+0xe0,0,0x3,0xe0,0,0xf,0x80,0,0x3e,0,
+0,0xf8,0,0x3,0xe1,0xf0,0x7c,0x1f,0x7,0xc0,
+0xf,0x8f,0x87,0xbe,0x1f,0,0x7,0xcf,0x80,0x3,
+0xe7,0xc0,0x1,0xf3,0xe0,0,0xf9,0xf0,0,0x7c,
+0xf,0xf8,0x1f,0x1c,0x7,0xc7,0xc0,0x1f,0x7,0xc0,
+0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,0,0x1f,0,
+0x1f,0xff,0xf0,0x78,0xf,0xc3,0xff,0xe0,0xff,0xf8,
+0x3f,0xfe,0xf,0xff,0x83,0xff,0xe0,0xff,0xf8,0x3f,
+0xff,0xff,0xc7,0x80,0x1,0xff,0xfe,0x7f,0xff,0x9f,
+0xff,0xe7,0xff,0xf8,0x3c,0x78,0x3c,0x1e,0x1e,0,
+0xf0,0xf0,0x1e,0x1e,0,0xf1,0xe0,0xf,0x1e,0,
+0xf1,0xe0,0xf,0x1e,0,0xf1,0xff,0xfe,0x3c,0x39,
+0xe1,0xe0,0x3c,0x1e,0x3,0xc1,0xe0,0x3c,0x1e,0x3,
+0xc0,0xf9,0xe0,0x3c,0x3,0xc1,0xf3,0xc0,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,
+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,0x7,0,0,0xf,0xff,0xf8,0x1,
+0x9f,0,0xe,0x38,0xe0,0xf0,0x7f,0xc0,0x1,0xe0,
+0x3,0xc0,0,0x3f,0xff,0xc0,0x3,0xfe,0,0x18,
+0x1e,0x3,0xc0,0xf,0,0x1f,0xc0,0,0xf,0x9f,
+0xff,0xe0,0,0xf1,0xe0,0x3c,0x3,0xe0,0x3c,0x1,
+0xe0,0x3c,0xf0,0,0,0x7,0xf0,0,0,0,
+0,0xf,0xe0,0xf,0x80,0x38,0x70,0x1c,0x1c,0x7,
+0xff,0xf8,0xf,0x80,0x3e,0x1f,0,0x3e,0x1f,0,
+0x3f,0x1f,0,0,0x7c,0,0xf,0xc0,0x7,0xc3,
+0xe0,0xf,0x87,0xc7,0xc1,0xf0,0xf8,0x7e,0,0xf8,
+0,0xf,0x9e,0xf3,0xe1,0xf0,0x7f,0xc1,0xf0,0x1,
+0xf0,0xf8,0,0x7,0xe0,0x39,0xf0,0xf8,0x7,0xc0,
+0,0x7,0xc0,0x1f,0,0x3e,0,0xf8,0x3,0xcf,
+0,0x1f,0xe1,0xfe,0,0x1f,0xf8,0,0x1f,0,
+0x7,0xe0,0x1,0xe0,0xe,0x7,0x80,0,0,0,
+0,0,0x3,0xf8,0xf0,0xf0,0xf,0x1e,0,0x7,
+0x80,0x78,0x7f,0xff,0x87,0x83,0xc0,0x3c,0x1e,0x3,
+0xc1,0xe0,0xf0,0x7f,0xf0,0xf,0x7,0x81,0xe0,0x78,
+0x1e,0x3,0xc3,0xc0,0x1e,0x1e,0x1,0xe3,0xc0,0x3c,
+0x1e,0,0x1f,0xfc,0xf,0x3,0xc0,0x78,0x1e,0x3c,
+0x3,0xdc,0x77,0x80,0x1f,0x80,0xf,0x3c,0x1,0xf8,
+0x3,0x80,0xe,0,0x38,0x7f,0xce,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,0x1,0xc0,0xf3,0,0x7,
+0x80,0x3,0xc7,0x80,0xf,0,0,0x7e,0x7,0x80,
+0x7,0xe,0x7,0xe,0,0x3,0x87,0,0,0x3c,
+0x7f,0xdc,0x1c,0x38,0x30,0,0,0,0xf,0,
+0,0,0,0,0x1e,0x3,0xc0,0xc,0x60,0,
+0,0,0,0,0x1,0xc3,0x80,0x7,0x6,0x70,
+0,0xe0,0x3,0xc0,0x1,0xc7,0x70,0x7,0xc0,0x3,
+0xff,0xfc,0x7,0xff,0xf8,0xf,0xff,0xf0,0x1f,0xff,
+0xe0,0x3f,0xff,0xc0,0x7f,0xff,0x80,0xff,0xfe,0,
+0x1,0xf0,0x3,0xe3,0xe0,0,0xf,0x80,0,0x3e,
+0,0,0xf8,0,0x3,0xe1,0xf0,0x7c,0x1f,0x7,
+0xc0,0x1f,0xf,0x83,0xfe,0xf,0x80,0xf,0x87,0xc0,
+0x7,0xc3,0xe0,0x3,0xe1,0xf0,0x1,0xf0,0xf8,0,
+0xf8,0x7,0xf0,0xf,0xb8,0xf,0x87,0xc0,0x1f,0x7,
+0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,0,0x1f,
+0,0x1f,0xff,0xe0,0x78,0x7,0xc7,0xf1,0xe1,0xfc,
+0x78,0x7f,0x1e,0x1f,0xc7,0x87,0xf1,0xe1,0xfc,0x78,
+0x7f,0xff,0xff,0xc7,0x80,0x1,0xff,0xfe,0x7f,0xff,
+0x9f,0xff,0xe7,0xff,0xf8,0x3c,0x78,0x3c,0x1e,0x1e,
+0,0xf0,0xf0,0x1e,0x1e,0,0xf1,0xe0,0xf,0x1e,
+0,0xf1,0xe0,0xf,0x1e,0,0xf1,0xff,0xfe,0x3c,
+0x71,0xe1,0xe0,0x3c,0x1e,0x3,0xc1,0xe0,0x3c,0x1e,
+0x3,0xc0,0xf9,0xe0,0x3c,0x3,0xc1,0xf3,0xc0,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,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,0x7,0,0,0xf,0xff,0xf8,
+0x1,0x8f,0,0xc,0x70,0x70,0xf0,0x3f,0x80,0x1,
+0xe0,0x3,0xc0,0,0x3f,0xff,0xc0,0x3,0xfe,0,
+0x18,0x1f,0x7,0xc0,0xf,0,0x3f,0,0x78,0xf,
+0x9f,0xff,0xe0,0,0xf1,0xe0,0x3c,0x3,0xc0,0x3c,
+0x1,0xe0,0,0xf0,0,0,0x7,0xf0,0,0,
+0,0,0xf,0xe0,0xf,0x80,0x38,0x70,0x1c,0x1c,
+0x7,0xff,0xf8,0xf,0x80,0x3e,0x1f,0,0x3e,0x1f,
+0,0x3e,0x1f,0,0,0x7c,0,0x7,0xc0,0x7,
+0xc3,0xe0,0xf,0x87,0xc7,0xc1,0xf0,0xf8,0x7e,0,
+0xf8,0,0xf,0x9e,0xf3,0xe1,0xf0,0x7f,0xc1,0xf0,
+0x1,0xf0,0xf8,0,0x3,0xe0,0x7d,0xe0,0xf8,0x7,
+0xc1,0xf0,0x7,0xc0,0x1f,0,0x3e,0,0xf8,0x3,
+0xff,0,0x1f,0xe1,0xfe,0,0x3e,0xfc,0,0x1f,
+0,0xf,0xc0,0x1,0xe0,0x6,0x7,0x80,0,0,
+0,0,0,0x7,0xc0,0xf0,0xf0,0xf,0x1e,0,
+0x7,0x80,0x78,0x78,0,0x7,0x83,0xc0,0x3c,0x1e,
+0x3,0xc1,0xe0,0xf0,0x7f,0xf0,0xf,0x7,0x81,0xe0,
+0x78,0x1e,0x3,0xc3,0xc0,0x1e,0x1e,0x1,0xe3,0xc0,
+0x3c,0x1e,0,0x7,0xfe,0xf,0x3,0xc0,0x78,0xf,
+0x78,0x3,0xdc,0x77,0x80,0x3f,0x80,0xf,0x3c,0x1,
+0xf0,0x1,0xe0,0xe,0,0xf0,0x73,0xfe,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,0x1,0xc0,0xf3,0,
+0x7,0x80,0x7,0xff,0xc1,0xff,0xf8,0,0x3f,0x87,
+0x80,0x7,0x7,0x9e,0x1c,0,0x3,0xc7,0x80,0,
+0x3c,0x7f,0xdc,0x1c,0x1c,0x70,0,0,0,0xf,
+0,0,0,0,0,0x1e,0x3,0xc0,0xc,0x60,
+0,0,0,0,0,0x3,0xc7,0x80,0x7,0xe,
+0x70,0,0xe0,0x7,0x80,0x3,0x86,0x70,0x1f,0x80,
+0x3,0xff,0xfc,0x7,0xff,0xf8,0xf,0xff,0xf0,0x1f,
+0xff,0xe0,0x3f,0xff,0xc0,0x7f,0xff,0x80,0xff,0xfe,
+0,0x1,0xf0,0x3,0xe3,0xe0,0,0xf,0x80,0,
+0x3e,0,0,0xf8,0,0x3,0xe1,0xf0,0x7c,0x1f,
+0x7,0xc0,0x1f,0xf,0x83,0xfe,0xf,0x80,0xf,0x87,
+0xc0,0x7,0xc3,0xe0,0x3,0xe1,0xf0,0x1,0xf0,0xf8,
+0,0xf8,0x7,0xf0,0xf,0xf0,0xf,0x87,0xc0,0x1f,
+0x7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,0,
+0x1f,0,0x1f,0xff,0xc0,0x78,0x7,0xcf,0x81,0xe3,
+0xe0,0x78,0xf8,0x1e,0x3e,0x7,0x8f,0x81,0xe3,0xe0,
+0x78,0x7c,0x1e,0,0x7,0x80,0x1,0xe0,0,0x78,
+0,0x1e,0,0x7,0x80,0,0x3c,0x78,0x3c,0x1e,
+0x1f,0x1,0xf0,0xf0,0x1e,0x1e,0,0xf1,0xe0,0xf,
+0x1e,0,0xf1,0xe0,0xf,0x1e,0,0xf1,0xff,0xfe,
+0x3e,0xe3,0xe1,0xe0,0x3c,0x1e,0x3,0xc1,0xe0,0x3c,
+0x1e,0x3,0xc0,0x79,0xe0,0x3c,0x3,0xc0,0xf3,0xc0,
+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,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,0xf,0xff,
+0xf8,0xf1,0x8f,0,0x1c,0x70,0x70,0xf0,0x1f,0,
+0x1,0xe0,0x3,0xc0,0,0x3f,0xff,0xc0,0,0,
+0,0x38,0x1f,0x7,0xc0,0xf,0,0x7e,0,0x78,
+0xf,0x9f,0xff,0xe7,0x81,0xf1,0xe0,0x3c,0x7,0xc0,
+0x3c,0x1,0xe0,0,0xf0,0,0,0x7,0xfe,0,
+0,0,0,0x7f,0xe0,0,0,0x38,0x78,0x3c,
+0x38,0xf,0xff,0xfc,0xf,0x80,0x3e,0x1f,0x80,0x7e,
+0x1f,0,0x7e,0x1f,0,0,0x7c,0,0x7,0xe0,
+0x7,0xc3,0xe0,0xf,0x87,0xc7,0xc1,0xf0,0xf8,0x3f,
+0,0xf8,0,0xf,0x8e,0xe3,0xe1,0xf0,0x3f,0xc1,
+0xf8,0x3,0xf0,0xf8,0,0x3,0xf0,0x7f,0xe0,0xf8,
+0x7,0xc1,0xf0,0x7,0xc0,0x1f,0,0x3e,0,0xf8,
+0x1,0xfe,0,0x1f,0xe1,0xfe,0,0x7e,0x7c,0,
+0x1f,0,0x1f,0x80,0x1,0xe0,0x7,0x7,0x80,0,
+0,0,0,0,0x7,0xc0,0xf0,0xf0,0x1f,0x1e,
+0x3,0xc7,0x80,0x78,0x78,0,0x7,0x83,0xe0,0x7c,
+0x1e,0x3,0xc1,0xe0,0xf0,0x7c,0xf8,0xf,0x7,0x81,
+0xe0,0x78,0x1e,0x3,0xc3,0xe0,0x3e,0x1f,0x3,0xe3,
+0xc0,0x3c,0x1e,0,0,0x7e,0xf,0x3,0xc0,0x78,
+0xf,0x78,0x3,0xdc,0x77,0x80,0x3f,0xc0,0xf,0xf8,
+0x3,0xe0,0x1,0xf0,0xe,0x1,0xf0,0x60,0xfc,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,0x1,0xc0,0xf3,
+0x1e,0xf,0x80,0xf,0xff,0xe1,0xff,0xf8,0,0x3f,
+0xcf,0x80,0x3,0x3,0xfc,0x1c,0,0x3,0xe7,0xc0,
+0,0x3c,0,0xe,0x1c,0x1e,0x70,0,0,0,
+0xf,0,0,0,0,0,0x1e,0x3,0xc0,0xc,
+0x60,0,0,0,0,0,0x7,0x8f,0,0xe,
+0xc,0x70,0x1,0xc0,0xf,0,0x3,0x8c,0x70,0x3f,
+0x80,0x7,0xff,0xfe,0xf,0xff,0xfc,0x1f,0xff,0xf8,
+0x3f,0xff,0xf0,0x7f,0xff,0xe0,0xff,0xff,0xc1,0xff,
+0xfe,0,0x1,0xf8,0x7,0xe3,0xe0,0,0xf,0x80,
+0,0x3e,0,0,0xf8,0,0x3,0xe1,0xf0,0x7c,
+0x1f,0x7,0xc0,0x1f,0xf,0x81,0xfe,0xf,0xc0,0x1f,
+0x87,0xe0,0xf,0xc3,0xf0,0x7,0xe1,0xf8,0x3,0xf0,
+0xfc,0x1,0xf8,0xf,0xf8,0xf,0xe0,0x1f,0x87,0xc0,
+0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,0x7,0xc0,0x1f,
+0,0x1f,0,0x1f,0xff,0x80,0x78,0x7,0xcf,0x1,
+0xe3,0xc0,0x78,0xf0,0x1e,0x3c,0x7,0x8f,0x1,0xe3,
+0xe0,0x78,0xf8,0x1e,0,0x7,0xc0,0xf1,0xe0,0,
+0x78,0,0x1e,0,0x7,0x80,0,0x3c,0x78,0x3c,
+0x1e,0x1f,0x1,0xf0,0xf0,0x1e,0x1f,0x1,0xf1,0xf0,
+0x1f,0x1f,0x1,0xf1,0xf0,0x1f,0x1f,0x1,0xf1,0xff,
+0xfe,0x3f,0x83,0xe1,0xe0,0x3c,0x1e,0x3,0xc1,0xe0,
+0x3c,0x1e,0x3,0xc0,0x7f,0xc0,0x3e,0x7,0xc0,0xff,
+0x80,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,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,0xf,
+0xff,0xf8,0xf1,0x9f,0,0x18,0x70,0x70,0xf8,0xf,
+0x80,0x1,0xf0,0x7,0xc0,0,0,0xf0,0,0,
+0,0,0x30,0x1f,0x7,0xc0,0xf,0,0xfc,0,
+0x78,0x1f,0x9f,0xff,0xe7,0x81,0xf1,0xf0,0x7c,0x7,
+0xc0,0x3e,0x3,0xe7,0x81,0xe0,0,0,0x3,0xff,
+0x80,0x7f,0xff,0x3,0xff,0xc0,0,0,0x3c,0x78,
+0x7c,0x78,0xf,0xff,0xfc,0xf,0x80,0x3e,0xf,0x80,
+0x7c,0x1f,0,0x7c,0x1f,0,0,0x7c,0,0x7,
+0xe0,0xf,0xc3,0xe0,0xf,0x87,0xc7,0xc1,0xf0,0xf8,
+0x1f,0x80,0xf8,0,0xf,0x8f,0xe3,0xe1,0xf0,0x3f,
+0xc0,0xfc,0x7,0xe0,0xf8,0,0x1,0xf8,0x3f,0xc0,
+0xf8,0x7,0xc0,0xf8,0x7,0xc0,0x1f,0,0x3f,0x1,
+0xf8,0x1,0xfe,0,0x1f,0xc0,0xfe,0,0x7c,0x7e,
+0,0x1f,0,0x1f,0x80,0x1,0xe0,0x7,0x7,0x80,
+0,0,0,0,0,0x7,0x81,0xf0,0xf0,0x1f,
+0x1f,0x3,0xc7,0xc0,0xf8,0x7c,0xf,0x7,0x83,0xe0,
+0x7c,0x1e,0x3,0xc1,0xe0,0xf0,0x78,0xf8,0xf,0x7,
+0x81,0xe0,0x78,0x1e,0x3,0xc3,0xe0,0x3e,0x1f,0x3,
+0xe3,0xe0,0x7c,0x1e,0x1,0xf0,0x1e,0xf,0x3,0xe0,
+0xf8,0xf,0x78,0x3,0xfc,0x7f,0x80,0x7f,0xe0,0x7,
+0xf8,0x7,0xc0,0,0xf0,0xe,0x1,0xe0,0,0x38,
+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,0x1,0xc0,
+0xfa,0x1e,0xf,0,0xf,0x7d,0xe0,0xf,0,0x38,
+0x1f,0xff,0,0x3,0x81,0xf8,0x38,0,0x1,0xe3,
+0xc0,0,0x3c,0,0xe,0x1c,0xe,0xe0,0,0,
+0,0,0,0,0,0,0,0x1f,0x7,0xc0,
+0xc,0x60,0,0,0,0,0,0x7,0xe,0,
+0x1c,0x18,0x70,0x3,0x80,0x1e,0,0x7,0x1c,0x70,
+0x7f,0,0x7,0xff,0xfe,0xf,0xff,0xfc,0x1f,0xff,
+0xf8,0x3f,0xff,0xf0,0x7f,0xff,0xe0,0xff,0xff,0xc1,
+0xff,0xfe,0,0,0xf8,0x7,0xc3,0xe0,0,0xf,
+0x80,0,0x3e,0,0,0xf8,0,0x3,0xe1,0xf0,
+0x7c,0x1f,0x7,0xc0,0x3e,0xf,0x81,0xfe,0x7,0xe0,
+0x3f,0x3,0xf0,0x1f,0x81,0xf8,0xf,0xc0,0xfc,0x7,
+0xe0,0x7e,0x3,0xf0,0x1f,0xfc,0x7,0xe0,0x3f,0x7,
+0xe0,0x3f,0x7,0xe0,0x3f,0x7,0xe0,0x3f,0x7,0xe0,
+0x3f,0,0x1f,0,0x1f,0,0,0x78,0xf,0xcf,
+0x3,0xe3,0xc0,0xf8,0xf0,0x3e,0x3c,0xf,0x8f,0x3,
+0xe3,0xc0,0xf8,0xf8,0x1e,0x7,0xc7,0xc0,0xf1,0xf0,
+0x3c,0x7c,0xf,0x1f,0x3,0xc7,0xc0,0xf0,0x3c,0x78,
+0x3c,0x1e,0x1f,0x83,0xf0,0xf0,0x1e,0x1f,0x1,0xf1,
+0xf0,0x1f,0x1f,0x1,0xf1,0xf0,0x1f,0x1f,0x1,0xf0,
+0,0,0x3f,0x7,0xe1,0xf0,0x7c,0x1f,0x7,0xc1,
+0xf0,0x7c,0x1f,0x7,0xc0,0x7f,0xc0,0x3e,0x7,0xc0,
+0xff,0x80,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,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,0xf,0x80,0,
+0x1,0xc7,0x80,0xf9,0x9f,0,0x38,0x70,0x70,0xfc,
+0x3f,0xc0,0,0xf0,0x7,0x80,0,0,0xf0,0x3,
+0xe0,0,0x3e,0x30,0xf,0x8f,0x80,0xf,0x1,0xf8,
+0,0x7c,0x1f,0,0xf,0x7,0xc3,0xe0,0xf8,0xf8,
+0x7,0xc0,0x1f,0x8f,0xc7,0xc3,0xe0,0x7c,0xf,0x80,
+0x7f,0xf0,0x7f,0xff,0xf,0xfe,0,0xf,0x80,0x1c,
+0x3f,0xff,0xf0,0xf,0x80,0x7c,0xf,0x80,0x7e,0xf,
+0xe1,0xfc,0x1f,0x1,0xfc,0x1f,0,0,0x7c,0,
+0x3,0xf8,0x3f,0xc3,0xe0,0xf,0x87,0xc7,0xe3,0xf0,
+0xf8,0xf,0x80,0xf8,0,0xf,0x8f,0xe3,0xe1,0xf0,
+0x1f,0xc0,0xff,0x1f,0xe0,0xf8,0,0x1,0xfe,0x1f,
+0x80,0xf8,0x7,0xc0,0xfc,0x1f,0x80,0x1f,0,0x1f,
+0xc7,0xf0,0x1,0xfe,0,0xf,0xc0,0xfc,0,0xfc,
+0x3e,0,0x1f,0,0x3f,0,0x1,0xe0,0x3,0x7,
+0x80,0,0,0,0,0,0x7,0xc3,0xf0,0xf8,
+0x3e,0xf,0x87,0xc3,0xe1,0xf8,0x3e,0x1f,0x7,0x81,
+0xf0,0xfc,0x1e,0x3,0xc1,0xe0,0xf0,0x78,0x7c,0xf,
+0x7,0x81,0xe0,0x78,0x1e,0x3,0xc1,0xf0,0x7c,0x1f,
+0x87,0xc1,0xf0,0xfc,0x1e,0x1,0xf0,0x1e,0xf,0x3,
+0xe1,0xf8,0x7,0xf0,0x1,0xf8,0x3f,0,0xf9,0xe0,
+0x7,0xf8,0xf,0x80,0,0xf0,0xe,0x1,0xe0,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,0x3,
+0xe0,0x7e,0x3e,0x1e,0xf1,0x8e,0,0xe0,0xf,0,
+0x38,0xf,0xfc,0,0x1,0xc0,0,0x70,0,0,
+0xe1,0xc0,0,0x3c,0,0x7,0,0x1,0xc0,0,
+0,0,0,0,0,0,0,0,0x1f,0xf,
+0xc0,0xc,0x60,0,0,0,0,0,0x6,0xc,
+0,0x1c,0x1f,0xfc,0x3,0x80,0x3c,0,0x7,0x1f,
+0xfc,0x7e,0,0x7,0xc0,0x3e,0xf,0x80,0x7c,0x1f,
+0,0xf8,0x3e,0x1,0xf0,0x7c,0x3,0xe0,0xf8,0x7,
+0xc1,0xf0,0x1e,0,0,0xfe,0x1f,0xc3,0xe0,0,
+0xf,0x80,0,0x3e,0,0,0xf8,0,0x3,0xe1,
+0xf0,0x7c,0x1f,0x7,0xc0,0xfe,0xf,0x80,0xfe,0x7,
+0xf8,0xff,0x3,0xfc,0x7f,0x81,0xfe,0x3f,0xc0,0xff,
+0x1f,0xe0,0x7f,0x8f,0xf0,0x3f,0x7e,0x7,0xf8,0xff,
+0x3,0xf8,0xfe,0x3,0xf8,0xfe,0x3,0xf8,0xfe,0x3,
+0xf8,0xfe,0,0x1f,0,0x1f,0,0,0x78,0x1f,
+0x8f,0x87,0xe3,0xe1,0xf8,0xf8,0x7e,0x3e,0x1f,0x8f,
+0x87,0xe3,0xe1,0xf8,0xfc,0x3f,0xf,0xc3,0xe1,0xf0,
+0xf8,0x7c,0x3e,0x1f,0xf,0x87,0xc3,0xe1,0xf0,0x3c,
+0x78,0x3c,0x1e,0xf,0xc7,0xe0,0xf0,0x1e,0xf,0x83,
+0xe0,0xf8,0x3e,0xf,0x83,0xe0,0xf8,0x3e,0xf,0x83,
+0xe0,0,0,0x1f,0x8f,0xc1,0xf0,0xfc,0x1f,0xf,
+0xc1,0xf0,0xfc,0x1f,0xf,0xc0,0x3f,0xc0,0x3f,0xf,
+0x80,0x7f,0x80,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,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,0xf,0x80,
+0,0x3,0xc7,0x80,0x7f,0xfe,0,0x70,0x38,0xe0,
+0x7f,0xff,0xe0,0,0xf0,0x7,0x80,0,0,0xf0,
+0x3,0xe0,0,0x3e,0x30,0xf,0xff,0x80,0xf,0x1,
+0xff,0xfe,0x3f,0xff,0,0xf,0x3,0xff,0xe0,0xff,
+0xf8,0xf,0x80,0x1f,0xff,0x83,0xff,0xc0,0x7c,0xf,
+0x80,0x1f,0xf8,0x7f,0xff,0x1f,0xf8,0,0xf,0x80,
+0x1e,0x1f,0xcf,0xe0,0x1f,0,0x3e,0xf,0xff,0xfc,
+0x7,0xff,0xf8,0x1f,0xff,0xf8,0x1f,0xff,0xf8,0x7c,
+0,0x3,0xff,0xff,0xc3,0xe0,0xf,0x87,0xc7,0xff,
+0xe0,0xf8,0xf,0xc0,0xff,0xff,0xf,0x8f,0xe3,0xe1,
+0xf0,0x1f,0xc0,0x7f,0xff,0xc0,0xf8,0,0,0xff,
+0xff,0xc0,0xf8,0x7,0xc0,0x7f,0xff,0x80,0x1f,0,
+0x1f,0xff,0xf0,0,0xfc,0,0xf,0xc0,0xfc,0,
+0xf8,0x3f,0,0x1f,0,0x3f,0xff,0xe1,0xe0,0x3,
+0x87,0x80,0,0,0,0,0,0x7,0xff,0xf0,
+0xff,0xfe,0xf,0xff,0x83,0xff,0xf8,0x3f,0xfe,0x7,
+0x81,0xff,0xfc,0x1e,0x3,0xc1,0xe0,0xf0,0x78,0x3c,
+0xf,0x7,0x81,0xe0,0x78,0x1e,0x3,0xc1,0xff,0xfc,
+0x1f,0xff,0xc1,0xff,0xfc,0x1e,0,0xf8,0x3e,0xf,
+0xe3,0xff,0xf8,0x7,0xf0,0x1,0xf8,0x3f,0,0xf9,
+0xf0,0x7,0xf0,0xf,0xff,0xc0,0xf0,0xe,0x1,0xe0,
+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,
+0x3,0xe0,0x7f,0xfc,0x3f,0xff,0xc0,0,0,0xf,
+0,0x38,0x3,0xfe,0,0,0xf0,0x1,0xe0,0,
+0,0x60,0xc0,0,0,0,0x3,0xc0,0x3,0x80,
+0,0,0x3,0xff,0xfc,0,0,0,0,0x1f,
+0xff,0xc0,0xc,0x60,0,0,0,0,0,0x4,
+0x8,0,0x38,0x1f,0xfc,0x7,0,0x78,0,0xe,
+0x1f,0xfc,0xfc,0,0xf,0x80,0x1f,0x1f,0,0x3e,
+0x3e,0,0x7c,0x7c,0,0xf8,0xf8,0x1,0xf1,0xf0,
+0x3,0xe3,0xe0,0x1f,0xff,0xf0,0x7f,0xff,0x83,0xff,
+0xff,0xf,0xff,0xfc,0x3f,0xff,0xf0,0xff,0xff,0xc3,
+0xe1,0xf0,0x7c,0x1f,0x7,0xff,0xfc,0xf,0x80,0xfe,
+0x3,0xff,0xfe,0x1,0xff,0xff,0,0xff,0xff,0x80,
+0x7f,0xff,0xc0,0x3f,0xff,0xe0,0x7e,0x3f,0x7,0xff,
+0xfe,0x3,0xff,0xfe,0x3,0xff,0xfe,0x3,0xff,0xfe,
+0x3,0xff,0xfe,0,0x1f,0,0x1f,0,0,0x78,
+0xff,0x8f,0xff,0xe3,0xff,0xf8,0xff,0xfe,0x3f,0xff,
+0x8f,0xff,0xe3,0xff,0xf8,0xff,0xff,0xff,0x83,0xff,
+0xe0,0xff,0xfc,0x3f,0xff,0xf,0xff,0xc3,0xff,0xf0,
+0x3c,0x78,0x3c,0x1e,0xf,0xff,0xe0,0xf0,0x1e,0xf,
+0xff,0xe0,0xff,0xfe,0xf,0xff,0xe0,0xff,0xfe,0xf,
+0xff,0xe0,0x7,0x80,0x1f,0xff,0xc1,0xff,0xfc,0x1f,
+0xff,0xc1,0xff,0xfc,0x1f,0xff,0xc0,0x3f,0x80,0x3f,
+0xff,0x80,0x7f,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,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,0xf,
+0x80,0,0x3,0xc7,0,0x7f,0xfe,0,0x70,0x3f,
+0xe0,0x7f,0xfb,0xe0,0,0xf0,0x7,0x80,0,0,
+0xf0,0x3,0xe0,0,0x3e,0x60,0x7,0xff,0,0xf,
+0x1,0xff,0xfe,0x3f,0xfe,0,0xf,0x3,0xff,0xc0,
+0x7f,0xf0,0xf,0x80,0xf,0xff,0x83,0xff,0xc0,0x7c,
+0xf,0x80,0x3,0xf8,0x7f,0xff,0x1f,0xc0,0,0xf,
+0x80,0xe,0xf,0x87,0x80,0x1f,0,0x3e,0xf,0xff,
+0xfc,0x3,0xff,0xf0,0x1f,0xff,0xf0,0x1f,0xff,0xf8,
+0x7c,0,0x1,0xff,0xfd,0xc3,0xe0,0xf,0x87,0xc3,
+0xff,0xe0,0xf8,0x7,0xe0,0xff,0xff,0xf,0x87,0xc3,
+0xe1,0xf0,0xf,0xc0,0x3f,0xff,0x80,0xf8,0,0,
+0x7f,0xff,0xe0,0xf8,0x7,0xc0,0x3f,0xff,0,0x1f,
+0,0xf,0xff,0xe0,0,0xfc,0,0xf,0xc0,0xfc,
+0x1,0xf8,0x1f,0,0x1f,0,0x3f,0xff,0xe1,0xe0,
+0x3,0x87,0x80,0,0,0,0,0,0x7,0xff,
+0xf0,0xff,0xfc,0x7,0xff,0x1,0xff,0x78,0x1f,0xfe,
+0x7,0x80,0xff,0xfc,0x1e,0x3,0xc1,0xe0,0xf0,0x78,
+0x3e,0xf,0x7,0x81,0xe0,0x78,0x1e,0x3,0xc0,0xff,
+0xf8,0x1f,0xff,0x80,0xff,0xfc,0x1e,0,0xff,0xfc,
+0xf,0xe1,0xff,0xf8,0x7,0xf0,0x1,0xf8,0x3f,0x1,
+0xf0,0xf8,0x3,0xf0,0xf,0xff,0xc0,0xf0,0xe,0x1,
+0xe0,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,0x3,0xe0,0x3f,0xf8,0x7f,0xff,0xc0,0,0,
+0xf,0,0x38,0,0xff,0,0,0x7c,0x7,0xc0,
+0,0,0x20,0x40,0,0,0,0x1,0xf0,0xf,
+0,0,0,0x3,0xff,0xfc,0,0,0,0,
+0x1f,0xff,0xc0,0xc,0x60,0,0,0,0,0,
+0,0,0,0x38,0,0x70,0x7,0,0xff,0xc0,
+0xe,0,0x70,0xf8,0xf,0xf,0x80,0x1f,0x1f,0,
+0x3e,0x3e,0,0x7c,0x7c,0,0xf8,0xf8,0x1,0xf1,
+0xf0,0x3,0xe3,0xe0,0x1f,0xff,0xf0,0x3f,0xff,0x3,
+0xff,0xff,0xf,0xff,0xfc,0x3f,0xff,0xf0,0xff,0xff,
+0xc3,0xe1,0xf0,0x7c,0x1f,0x7,0xff,0xfc,0xf,0x80,
+0x7e,0x1,0xff,0xfc,0,0xff,0xfe,0,0x7f,0xff,
+0,0x3f,0xff,0x80,0x1f,0xff,0xc0,0x7c,0x1f,0x7,
+0xff,0xfc,0x1,0xff,0xfc,0x1,0xff,0xfc,0x1,0xff,
+0xfc,0x1,0xff,0xfc,0,0x1f,0,0x1f,0,0,
+0x78,0xff,0xf,0xff,0xe3,0xff,0xf8,0xff,0xfe,0x3f,
+0xff,0x8f,0xff,0xe3,0xff,0xf8,0x7f,0xf7,0xff,0x1,
+0xff,0xc0,0x7f,0xf8,0x1f,0xfe,0x7,0xff,0x81,0xff,
+0xe0,0x3c,0x78,0x3c,0x1e,0x7,0xff,0xc0,0xf0,0x1e,
+0x7,0xff,0xc0,0x7f,0xfc,0x7,0xff,0xc0,0x7f,0xfc,
+0x7,0xff,0xc0,0x7,0x80,0x3f,0xff,0x80,0xff,0xfc,
+0xf,0xff,0xc0,0xff,0xfc,0xf,0xff,0xc0,0x1f,0x80,
+0x3f,0xff,0,0x3f,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,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,
+0xf,0x80,0,0x3,0xc7,0,0x3f,0xf8,0,0xe0,
+0x1f,0xc0,0x1f,0xf1,0xf0,0,0xf0,0x7,0,0,
+0,0xf0,0x3,0xe0,0,0x3e,0x60,0x3,0xfe,0,
+0xf,0x1,0xff,0xfe,0x1f,0xfc,0,0xf,0x1,0xff,
+0x80,0x3f,0xe0,0xf,0x80,0x7,0xff,0,0xff,0x80,
+0x7c,0xf,0x80,0,0xf8,0,0,0x1e,0,0,
+0xf,0x80,0xf,0,0,0,0x3f,0,0x3f,0xf,
+0xff,0xf8,0x1,0xff,0xe0,0x1f,0xff,0xe0,0x1f,0xff,
+0xf8,0x7c,0,0,0x7f,0xf9,0xc3,0xe0,0xf,0x87,
+0xc1,0xff,0xc0,0xf8,0x3,0xf0,0xff,0xff,0xf,0x87,
+0xc3,0xe1,0xf0,0xf,0xc0,0x1f,0xff,0,0xf8,0,
+0,0x3f,0xff,0xf0,0xf8,0x7,0xe0,0x1f,0xfe,0,
+0x1f,0,0x7,0xff,0xc0,0,0xfc,0,0x7,0x80,
+0x78,0x3,0xf0,0x1f,0x80,0x1f,0,0x3f,0xff,0xe1,
+0xe0,0x1,0x87,0x80,0,0,0,0,0,0x3,
+0xfe,0xf0,0xf7,0xf8,0x3,0xff,0,0xff,0x78,0xf,
+0xf8,0x7,0x80,0x7f,0xbc,0x1e,0x3,0xc1,0xe0,0xf0,
+0x78,0x1f,0xf,0x7,0x81,0xe0,0x78,0x1e,0x3,0xc0,
+0x7f,0xf0,0x1e,0xff,0,0xff,0xbc,0x1e,0,0x7f,
+0xf8,0x7,0xe1,0xff,0x78,0x3,0xe0,0,0xf0,0x1e,
+0x3,0xf0,0xfc,0x3,0xf0,0xf,0xff,0xc0,0xf0,0xe,
+0x1,0xe0,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,0x3,0xe0,0x1f,0xf0,0x7f,0xff,0x80,0,
+0,0xf,0,0x38,0,0x3f,0,0,0x3f,0xff,
+0,0,0,0,0,0,0,0,0,0xff,
+0xfc,0,0,0,0x3,0xff,0xfc,0,0,0,
+0,0x1f,0xfb,0xc0,0xc,0x60,0,0,0,0,
+0,0,0,0,0x70,0,0x70,0xe,0,0xff,
+0xc0,0x1c,0,0x70,0xf8,0xf,0x1f,0x80,0x1f,0xbf,
+0,0x3f,0x7e,0,0x7e,0xfc,0,0xfd,0xf8,0x1,
+0xfb,0xf0,0x3,0xf7,0xc0,0x1f,0xff,0xf0,0x1f,0xfe,
+0x3,0xff,0xff,0xf,0xff,0xfc,0x3f,0xff,0xf0,0xff,
+0xff,0xc3,0xe1,0xf0,0x7c,0x1f,0x7,0xff,0xf0,0xf,
+0x80,0x7e,0,0xff,0xf8,0,0x7f,0xfc,0,0x3f,
+0xfe,0,0x1f,0xff,0,0xf,0xff,0x80,0x38,0xe,
+0xe,0xff,0xf8,0,0xff,0xf8,0,0xff,0xf8,0,
+0xff,0xf8,0,0xff,0xf8,0,0x1f,0,0x1f,0,
+0,0x78,0xfe,0x7,0xfd,0xe1,0xff,0x78,0x7f,0xde,
+0x1f,0xf7,0x87,0xfd,0xe1,0xff,0x78,0x3f,0xe3,0xfe,
+0,0xff,0xc0,0x3f,0xe0,0xf,0xf8,0x3,0xfe,0,
+0xff,0x80,0x3c,0x78,0x3c,0x1e,0x3,0xff,0x80,0xf0,
+0x1e,0x3,0xff,0x80,0x3f,0xf8,0x3,0xff,0x80,0x3f,
+0xf8,0x3,0xff,0x80,0x7,0x80,0x77,0xff,0,0xff,
+0xbc,0xf,0xfb,0xc0,0xff,0xbc,0xf,0xfb,0xc0,0x1f,
+0x80,0x3d,0xfe,0,0x3f,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,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,0xf,0x80,0,0x3,0x8f,0,0x7,0xe0,0,
+0xc0,0x7,0,0x7,0xc0,0,0,0x78,0xf,0,
+0,0,0xf0,0x3,0xe0,0,0x3e,0x60,0x1,0xfc,
+0,0xf,0x1,0xff,0xfe,0x7,0xf0,0,0xf,0,
+0x7e,0,0xf,0x80,0xf,0x80,0x1,0xfc,0,0x3e,
+0,0x7c,0xf,0x80,0,0x18,0,0,0x18,0,
+0,0xf,0x80,0x7,0x80,0,0,0x3e,0,0x1f,
+0xf,0xff,0xe0,0,0x7f,0x80,0x1f,0xff,0,0x1f,
+0xff,0xf8,0x7c,0,0,0x3f,0xe1,0xc3,0xe0,0xf,
+0x87,0xc0,0x7f,0,0xf8,0x3,0xf0,0xff,0xff,0xf,
+0x87,0xc3,0xe1,0xf0,0x7,0xc0,0x7,0xfc,0,0xf8,
+0,0,0xf,0xf9,0xe0,0xf8,0x3,0xe0,0x7,0xf0,
+0,0x1f,0,0x1,0xff,0,0,0x78,0,0x7,
+0x80,0x78,0x3,0xf0,0xf,0xc0,0x1f,0,0x3f,0xff,
+0xe1,0xe0,0x1,0x87,0x80,0,0,0,0,0,
+0x1,0xf8,0xf0,0xf1,0xf0,0,0xfc,0,0x7c,0x78,
+0x3,0xe0,0x7,0x80,0x3f,0x3c,0x1e,0x3,0xc1,0xe0,
+0xf0,0x78,0x1f,0xf,0x7,0x81,0xe0,0x78,0x1e,0x3,
+0xc0,0x1f,0xc0,0x1e,0x3e,0,0x3f,0x3c,0x1e,0,
+0x1f,0xe0,0x3,0xe0,0x7c,0x78,0x3,0xe0,0,0xf0,
+0x1e,0x3,0xe0,0x7c,0x3,0xe0,0xf,0xff,0xc0,0xf0,
+0xe,0x1,0xe0,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,0x3,0xe0,0xf,0xc0,0x30,0x3f,0,
+0,0,0xf,0,0x38,0,0x1f,0,0,0xf,
+0xfc,0,0,0,0,0,0,0,0,0,
+0x3f,0xf0,0,0,0,0x3,0xff,0xfc,0,0,
+0,0,0x1e,0xf3,0xc0,0xc,0x60,0,0xc,0,
+0,0,0,0,0,0x70,0,0x70,0xe,0,
+0xff,0xc0,0x1c,0,0x70,0xf8,0xf,0x1f,0,0xf,
+0xbe,0,0x1f,0x7c,0,0x3e,0xf8,0,0x7d,0xf0,
+0,0xfb,0xe0,0x1,0xf7,0xc0,0x1f,0xff,0xf0,0x7,
+0xf0,0x3,0xff,0xff,0xf,0xff,0xfc,0x3f,0xff,0xf0,
+0xff,0xff,0xc3,0xe1,0xf0,0x7c,0x1f,0x7,0xff,0xe0,
+0xf,0x80,0x3e,0,0x3f,0xe0,0,0x1f,0xf0,0,
+0xf,0xf8,0,0x7,0xfc,0,0x3,0xfe,0,0x10,
+0x4,0x1c,0x3f,0xe0,0,0x3f,0xe0,0,0x3f,0xe0,
+0,0x3f,0xe0,0,0x3f,0xe0,0,0x1f,0,0x1f,
+0,0,0x78,0xf8,0x3,0xf1,0xe0,0xfc,0x78,0x3f,
+0x1e,0xf,0xc7,0x83,0xf1,0xe0,0xfc,0x78,0xf,0x81,
+0xf8,0,0x3f,0,0xf,0x80,0x3,0xe0,0,0xf8,
+0,0x3e,0,0x3c,0x78,0x3c,0x1e,0,0xfe,0,
+0xf0,0x1e,0,0xfe,0,0xf,0xe0,0,0xfe,0,
+0xf,0xe0,0,0xfe,0,0x7,0x80,0xe1,0xfc,0,
+0x3e,0x3c,0x3,0xe3,0xc0,0x3e,0x3c,0x3,0xe3,0xc0,
+0x1f,0,0x3c,0x7c,0,0x3e,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,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,0x3,0x8f,0,0x1,0x80,
+0,0,0,0,0,0,0,0,0x78,0xf,
+0,0,0,0,0,0x60,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,0x1,0x80,0,0,0,0,0,
+0,0,0,0,0x3,0xe0,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,0xc0,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,0x1,0xe0,0,0x7,0x80,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3c,0,0,0,
+0,0xf0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1e,0,0,0,0x3c,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x3,0xe0,0,0,0,
+0xf0,0xe,0x1,0xe0,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,0x3,0xe0,0xc,0,0,0,
+0,0,0,0,0,0x38,0x3c,0xf,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,0x1e,0,0,0xc,0x60,0,0xc,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xfc,0x1f,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x1,0x80,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,0,0,0,0,0,0,
+0,0,0,0x18,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,0x1f,0,0x3c,0,0,0x3e,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,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,0x1,
+0x80,0,0,0,0,0,0,0,0,0x38,
+0xe,0,0,0,0,0,0x60,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,0x1,0x80,0,0,0,0,
+0,0,0,0,0,0x3,0xfc,0xf,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,
+0,0,0x1,0xe0,0,0x7,0x80,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x3,0xe0,0x7c,0,0,
+0,0,0xf0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x1e,0,0,0,0x3c,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0xe0,0,0,
+0,0xf0,0xe,0x1,0xe0,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,0x3,0xe0,0x8,0,0,
+0,0,0,0,0,0,0x38,0x3c,0xf,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,0x1e,0,0,0xc,0x60,0,
+0xc,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x7e,0x7f,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1,0x80,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,0,0,0,0,0,
+0,0,0,0,0x18,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,0x1f,0,0x3c,0,0,0x3e,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,
+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,
+0x1,0x80,0,0,0,0,0,0,0,0,
+0x3c,0x1e,0,0,0,0,0,0xe0,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,0x3,0x80,0,0,0,
+0,0,0,0,0,0,0,0xff,0xff,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,0,0,0x1,0xe0,0,0x7,0x80,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x3,0xe0,0x7c,0,
+0,0,0,0xf0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x1e,0,0,0,
+0x3c,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x7,0xc0,0,
+0,0,0xf0,0xe,0x1,0xe0,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,0x3,0xe0,0x8,0,
+0,0,0,0,0,0,0,0x38,0x3e,0x1f,
+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,0x1e,0,0,0xc,0x60,
+0,0x1f,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x7f,0xfe,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x3,0xe0,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,0,0,0,0,
+0,0,0,0,0,0x3e,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,0x3e,0,0x3c,0,0,0x7c,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,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,0x1c,0x1c,0,0,0,0,0x1,0xc0,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,0x7,0,0,0,
+0,0,0,0,0,0,0,0,0x7f,0xff,
+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,0,0,0x1,0xfe,0,0x7f,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x1,0xf9,0xf8,
+0,0,0,0x3,0xf0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x1e,0,0,
+0,0x3c,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1f,0xc0,
+0,0,0,0xf0,0xe,0x1,0xe0,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,0x3,0xe0,0,
+0,0,0,0,0,0,0,0,0x38,0x1f,
+0xfe,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,0x1e,0,0,0xc,
+0x60,0,0x7,0x80,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3f,
+0xfe,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x70,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,0,0,0,
+0,0,0,0,0,0,0x7,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,0xfe,0,0x3c,0,0x1,0xfc,
+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,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,0x1e,0x3c,0,0,0,0,0x3,0x80,
+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,0xe,0,0,
+0,0,0,0,0,0,0,0,0,0x1f,
+0xf8,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,0,0,0x1,0xfe,0,0x7f,0x80,
+0,0x1,0xff,0xff,0x80,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1,0xff,
+0xf8,0,0,0,0x3,0xf0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1e,0,
+0,0,0x3c,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x1f,
+0x80,0,0,0,0xfe,0xe,0xf,0xe0,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,0x3,0xe0,
+0,0,0,0,0,0,0,0,0,0x38,
+0x1f,0xfe,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,0x1e,0,0,
+0xc,0x60,0,0x3,0x80,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x3f,0xfc,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x70,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,0,0,
+0,0,0,0,0,0,0,0x7,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,0xfc,0,0x3c,0,0x1,
+0xf8,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,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,0xe,0x38,0,0,0,0,0x2,
+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,0x8,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,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x1,0xfe,0,0x7f,
+0x80,0,0x1,0xff,0xff,0x80,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0xff,0xf0,0,0,0,0x3,0xe0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x1e,
+0,0,0,0x3c,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x1f,0x80,0,0,0,0x7e,0xe,0xf,0xc0,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,0x3,
+0xe0,0,0,0,0,0,0,0,0,0,
+0x38,0xf,0xfc,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,0x1e,0,
+0,0xc,0x60,0,0x3f,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xf,0xf0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x7,0xe0,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,0,
+0,0,0,0,0,0,0,0,0x7e,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,0xfc,0,0x3c,0,
+0x1,0xf8,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,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,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,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,0x3f,0xc0,0,0,0,0x3,0xe0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x1e,0,0,0,0x3c,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1e,0,0,0,0,0x3e,0,0xf,0x80,
+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,0x3,0xf0,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,0x1e,
+0,0,0,0,0,0x3e,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,0x7,0xc0,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,
+0,0,0,0,0,0,0,0,0,0x7c,
+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,0xf0,0,0x3c,
+0,0x1,0xe0,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,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,
+};
+
+static WORD Helvetica34_ch_ofst[225] = {
+0,9,20,36,55,73,102,126,134,145,
+156,169,188,197,208,217,226,244,262,280,
+298,316,334,352,370,388,406,417,428,447,
+466,485,505,538,561,585,609,633,655,675,
+700,723,732,750,774,794,821,845,870,892,
+918,942,964,984,1008,1030,1061,1083,1105,1125,
+1136,1145,1156,1175,1193,1204,1222,1242,1260,1280,
+1298,1309,1329,1349,1358,1367,1386,1395,1425,1445,
+1465,1485,1505,1518,1537,1548,1568,1587,1613,1632,
+1651,1668,1681,1690,1703,1722,1731,1740,1749,1758,
+1767,1776,1785,1794,1803,1812,1821,1830,1839,1848,
+1857,1866,1875,1884,1893,1902,1911,1920,1929,1938,
+1947,1956,1965,1974,1983,1992,2001,2010,2019,2028,
+2039,2057,2075,2093,2111,2120,2138,2149,2175,2187,
+2205,2224,2235,2261,2272,2285,2304,2315,2326,2337,
+2357,2375,2384,2395,2406,2418,2436,2464,2492,2519,
+2539,2562,2585,2608,2631,2654,2677,2709,2732,2754,
+2776,2798,2820,2829,2839,2849,2859,2882,2906,2931,
+2956,2981,3006,3031,3050,3075,3099,3123,3147,3171,
+3193,3215,3235,3253,3271,3289,3307,3325,3343,3372,
+3390,3408,3426,3444,3462,3471,3480,3489,3498,3518,
+3538,3558,3578,3598,3618,3638,3657,3677,3697,3717,
+3737,3757,3776,3796,3815,
+};
+
+static struct font_hdr Helvetica34_font = {
+STPROP, 24, "AdobeHelv-B-R-N--34-240-100-100", 32, 255,
+38, 31, 19, 7, 7,
+32, 33, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Helvetica34_ch_ofst, Helvetica34_data,
+581, 38,
+NULL,
+0, 0,   /* x/y offset */
+40,        /* lineHeight */
+29,	   /* psHeight */
+};
+
+MgFont *mgHelveticaBold34Font()
+{
+return &Helvetica34_font;
+}
+
+MgFont *mgHugeBoldFont()
+{
+return &Helvetica34_font;
+}
+
diff --git a/lib/font/mgHelveticaBold8.c b/lib/font/mgHelveticaBold8.c
new file mode 100644
index 0000000..8129217
--- /dev/null
+++ b/lib/font/mgHelveticaBold8.c
@@ -0,0 +1,285 @@
+
+/* HelveticaBold8.c - compiled data for font AdobeHelv-B-R-N--8-80-75-75-P-5 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/helvB08.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE HelveticaBold8_data[2222] = {
+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,0,0,0,0,0,0,0,0,
+0,0x1,0x1,0x8,0x28,0x2,0,0,0x40,0x90,
+0x10,0x80,0xa,0x40,0x42,0xa,0,0,0x20,0x21,
+0,0x4,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,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,0x80,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,0x80,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,0x82,0x14,0x51,0x45,0,0,
+0x21,0x29,0x4b,0x50,0x14,0x20,0x85,0x14,0x50,0,
+0x10,0x42,0x8a,0x8,0,0x8,0x12,0x14,0x4,0,
+0x4,0x8,0x81,0x8,0x2,0x90,0x22,0x28,0,0x2,
+0x4,0x40,0x8,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,0,0,0,0,0,
+0,0,0,0,0x30,0,0x80,0,0x80,0,
+0,0,0,0,0,0,0,0,0,0x3,
+0x80,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x40,0xc0,0x18,0xc,0x18,0xac,0x40,
+0,0,0,0x1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xf3,0x80,0,0xf,0,0,0x40,
+0,0x38,0x4,0x48,0xb1,0,0,0,0,0x2,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x4,0x25,0x29,
+0x4a,0,0x2,0x11,0x4a,0xb5,0xd5,0x8,0x45,0x51,
+0x40,0x1,0x8,0xa5,0x10,0xa,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,0,0,
+0,0,0,0,0,0,0x35,0x51,0xcd,0x38,
+0x94,0x40,0,0x2c,0x23,0x18,0x67,0x3b,0xcc,0x60,
+0,0,0xcf,0xc7,0x3c,0x7b,0xcf,0x79,0xed,0xa3,
+0x6d,0x8c,0x6c,0x9c,0xf1,0xcf,0x1e,0xfb,0x6e,0xb6,
+0xdb,0x76,0xff,0x4c,0xc0,0,0xc0,0x18,0x18,0x18,
+0xc,0x40,0,0,0,0x3,0,0,0,0,
+0x13,0,0,0,0,0,0,0,0,0,
+0,0x43,0x45,0x69,0xd5,0x99,0x80,0,0x9,0xbe,
+0x4f,0x81,0xe0,0x68,0xc,0x99,0x32,0x1,0xc7,0x1c,
+0x71,0xc7,0x1f,0x9e,0xf7,0xbd,0xea,0xa7,0x32,0x71,
+0xc7,0x1c,0x70,0xe,0xed,0xb6,0xdb,0x76,0xc3,0x80,
+0,0,0x4,0,0,0,0,0,0x60,0,
+0,0,0,0x8,0,0,0x6,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,0,
+0,0,0,0,0,0,0,0,0x35,0xfb,
+0x16,0x28,0x14,0xe4,0,0x3a,0xe5,0xac,0xac,0x60,
+0xda,0xb5,0x10,0x21,0x98,0x6d,0xb6,0xcb,0x6c,0x63,
+0x2d,0xa3,0x69,0x8c,0x6c,0xb6,0xdb,0x6d,0xb0,0x63,
+0x66,0xb6,0xdb,0x34,0x3a,0x44,0xc0,0x1c,0xe3,0x39,
+0xbf,0x5c,0xad,0x5d,0x38,0xce,0x3a,0xbf,0xeb,0x55,
+0x6d,0xaf,0x22,0x80,0,0,0,0,0,0,
+0,0,0x4,0x45,0x3b,0x6b,0x1,0x6a,0x80,0,
+0x16,0x8a,0x47,0x37,0xa0,0xf8,0x5,0xa,0x14,0x23,
+0x6d,0xb6,0xdb,0x6d,0x8e,0x32,0xc6,0x31,0x8a,0xa5,
+0xb2,0xdb,0x6d,0xb6,0xdb,0x5b,0x6d,0xb6,0xdb,0x34,
+0xf3,0x5c,0xe7,0x39,0xce,0x7c,0x66,0x31,0x8c,0xaa,
+0xa7,0x18,0xc6,0x31,0x84,0x76,0xb5,0xad,0x6b,0x9a,
+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,0,0,0,0,0,0,0,0,
+0x20,0x53,0x9c,0x30,0x22,0x44,0,0x5a,0x61,0x99,
+0xae,0x70,0xcc,0xb5,0x27,0x91,0x13,0x2d,0xbc,0xc3,
+0x6f,0x7b,0xf,0xa3,0x71,0x8e,0xee,0xb2,0xdb,0x2d,
+0xbc,0x63,0x66,0xb6,0x8e,0x34,0x32,0x25,0x20,0x6,
+0xd6,0x5b,0x5a,0xda,0xad,0x5a,0xb5,0xad,0x5b,0xe3,
+0x6b,0x55,0x6d,0xa3,0x22,0x8b,0,0,0,0,
+0,0,0,0,0x5,0xec,0x29,0x63,0x81,0x88,
+0x14,0xf0,0x16,0x8f,0xe9,0x37,0xac,0x42,0x85,0xa,
+0x28,0x23,0x6d,0xb6,0xdb,0x6d,0x97,0xb0,0xf7,0xbd,
+0xea,0xae,0xba,0xcb,0x2c,0xb2,0xc9,0xdb,0x6d,0xb6,
+0xdb,0x34,0xdb,0x86,0x31,0x8c,0x63,0x1a,0xcd,0x6b,
+0x5a,0xaa,0x77,0xb5,0xad,0x6b,0x40,0xd6,0xb5,0xad,
+0x6b,0x5a,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,0,0,0,0,0,0,
+0,0,0,0xf9,0xc7,0x7c,0x22,0x1e,0x38,0x5a,
+0x63,0xd,0xf3,0x69,0x9a,0x70,0x40,0x8,0x15,0x2f,
+0xb6,0xc3,0x6c,0x63,0x6d,0xa3,0x79,0x8f,0xef,0xb2,
+0xf3,0x2f,0xe,0x63,0x66,0xb6,0x8e,0x3c,0x62,0x24,
+0,0x1e,0xd6,0x5b,0xda,0xda,0xae,0x5a,0xb5,0xad,
+0x5b,0x7b,0x6b,0x5f,0x39,0xa6,0x42,0x56,0,0,
+0,0,0,0,0,0,0x1,0x86,0x3b,0xeb,
+0x41,0x6b,0xa8,0x13,0x95,0x80,0x4e,0x35,0xac,0x79,
+0x42,0x87,0xa,0x3,0xef,0xbe,0xfb,0xef,0xbe,0x30,
+0xc6,0x31,0x8a,0xa5,0xbe,0xcb,0x2c,0xb2,0xc9,0xdd,
+0x6d,0xb6,0xdb,0x3c,0xf3,0x5e,0xf7,0xbd,0xef,0x3e,
+0xcf,0x7b,0xde,0xaa,0xd6,0xb5,0xad,0x6b,0x5e,0xd6,
+0xb5,0xad,0x6b,0x5a,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,0,0,0,0,
+0,0,0,0,0x20,0xa0,0xcd,0x68,0x22,0x4,
+0x82,0x9a,0x66,0x2c,0x6b,0x69,0x1a,0x35,0x27,0x91,
+0x13,0x2d,0xb6,0xcb,0x6c,0x63,0x2d,0xab,0x6d,0x8d,
+0x6d,0xb6,0xc3,0x6d,0xb6,0x63,0x67,0x1b,0x1b,0x18,
+0xe2,0x14,0,0x16,0xd6,0x5b,0x1b,0xda,0xad,0x5a,
+0xb5,0xad,0x5b,0x1b,0x79,0x9f,0x6c,0xec,0x22,0x80,
+0,0,0,0,0,0,0,0,0x5,0xe5,
+0x44,0xc9,0x41,0x98,0x14,0,0x18,0x80,0,0x3c,
+0xa0,0x2,0x85,0x89,0x16,0x23,0x6d,0xb6,0xdb,0x6d,
+0xb6,0x32,0xc6,0x31,0x8a,0xa5,0xb6,0xdb,0x6d,0xb6,
+0xdb,0x5b,0x6d,0xb6,0xdb,0x18,0xc3,0x56,0xb5,0xad,
+0x6b,0x58,0xcc,0x63,0x18,0xaa,0xd6,0xb5,0xad,0x6b,
+0x40,0xd7,0xbd,0xef,0x3b,0x4c,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,0,0,
+0,0,0,0,0,0,0x20,0xa3,0x96,0x34,
+0x22,0x4,0x82,0x8c,0x67,0x98,0x66,0x33,0xc,0xe5,
+0x10,0x21,0x19,0xcd,0xbc,0x7b,0xcf,0x61,0xed,0xa6,
+0x67,0xed,0x6c,0x9c,0xc1,0xed,0x9c,0x61,0xc2,0x1b,
+0x1b,0x18,0xfa,0x14,0,0x1b,0xe3,0x39,0x98,0xda,
+0xad,0x5a,0xb4,0xce,0x3b,0x71,0xa9,0x9,0x6c,0xcf,
+0x22,0x80,0,0,0,0,0,0,0,0,
+0xc,0x8f,0,0xc8,0xc0,0xf0,0,0,0xf,0x1,
+0xe0,0x24,0xa0,0,0xb,0xd2,0x2f,0x23,0x6d,0xb6,
+0xdb,0x6d,0xb7,0x9e,0xf7,0xbd,0xea,0xa7,0x32,0x71,
+0xc7,0x1c,0x70,0x1e,0x38,0xe3,0x8e,0x18,0xc2,0x9b,
+0xde,0xf7,0xbd,0xbe,0x66,0x31,0x8c,0xaa,0x66,0x98,
+0xc6,0x31,0x84,0xe2,0x94,0xa5,0x33,0x8c,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,
+0,0,0,0,0,0,0,0,0,0x1,
+0,0,0x14,0x1,0,0,0,0,0,0,
+0,0x2,0,0,0xc,0,0,0,0,0,
+0,0,0,0,0,0,0,0x10,0,0,
+0,0,0,0,0x2,0x4,0x1f,0,0,0,
+0x3,0x80,0x40,0,0,0xc,0x18,0,0,0,
+0,0xc0,0x13,0,0,0,0,0,0,0,
+0,0,0xc,0x80,0,0x2,0xc0,0,0,0,
+0,0,0,0x30,0xa1,0,0,0x83,0x2,0x60,
+0,0,0,0,0,0x8,0,0,0,0,
+0,0,0,0,0,0x20,0,0,0,0,
+0,0,0,0,0,0,0x40,0,0,0,
+0,0,0,0,0x1,0,0,0,0x33,0xc,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0x14,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,0x3,0xc,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,0xc,0,0,0x3,0x80,0,
+0,0,0,0,0,0x30,0xa3,0,0,0,
+0,0x78,0,0,0,0,0,0x18,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0xc0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x3,0x80,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,0,0,0,0,0,0,
+0,0,
+};
+
+static WORD HelveticaBold8_ch_ofst[225] = {
+0,2,5,9,14,19,25,31,34,37,
+40,43,48,50,54,56,59,64,69,74,
+79,84,89,94,99,104,109,111,113,117,
+122,126,131,140,146,152,158,164,169,174,
+180,186,188,193,199,204,212,218,224,230,
+236,242,248,254,260,266,275,281,288,294,
+297,300,303,307,312,315,320,325,329,334,
+339,342,347,352,354,356,361,363,370,375,
+380,385,390,393,398,401,406,411,417,423,
+428,433,437,439,443,448,450,452,454,456,
+458,460,462,464,466,468,470,472,474,476,
+478,480,482,484,486,488,490,492,494,496,
+498,500,502,504,506,508,510,512,514,516,
+519,524,529,534,540,542,547,550,558,562,
+568,574,578,586,588,591,596,598,600,602,
+607,612,614,616,618,622,628,635,642,649,
+654,660,666,672,678,684,690,698,704,709,
+714,719,724,726,728,730,732,738,744,750,
+756,762,768,774,779,785,791,797,803,809,
+816,822,827,832,837,842,847,852,857,864,
+868,873,878,883,888,890,892,894,896,901,
+906,911,916,921,926,931,936,941,946,951,
+956,961,966,971,976,
+};
+
+static struct font_hdr HelveticaBold8_font = {
+STPROP, 8, "AdobeHelv-B-R-N--8-80-75-75-P-5", 32, 255,
+11, 9, 5, 2, 2,
+9, 9, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+HelveticaBold8_ch_ofst, HelveticaBold8_data,
+202, 11,
+NULL,
+0, 0,   /* x/y offset */
+11,        /* lineHeight */
+10,	   /* psHeight */
+};
+
+MgFont *mgHelveticaBold8Font()
+{
+return &HelveticaBold8_font;
+}
+
+MgFont *mgTinyBoldFont()
+{
+return &HelveticaBold8_font;
+}
+
diff --git a/lib/font/mgMenlo12.c b/lib/font/mgMenlo12.c
new file mode 100644
index 0000000..86d31bc
--- /dev/null
+++ b/lib/font/mgMenlo12.c
@@ -0,0 +1,903 @@
+
+/* MenloMedium.c - compiled data for font -FreeType-Meslo */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: MesloLGM-Bold.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE MenloMedium_data[8480] = {
+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,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,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,
+0x18,0x1,0x81,0xe0,0,0,0,0,0,0,
+0x18,0x1,0x81,0xe0,0,0,0x1,0x80,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x6,0,0x60,0x78,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,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,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,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,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,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,0xc,0x3,0x3,0x30,0xe4,0x36,
+0x3,0,0,0,0xc,0x3,0x3,0x20,0xd8,0x18,
+0x3,0x1,0xc0,0xd8,0,0xe,0x41,0x80,0x18,0x1e,
+0xe,0x41,0xb0,0,0,0x3,0,0xc0,0xcc,0x33,
+0x1,0x80,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,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,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,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,0xc0,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,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,0x9c,0x36,0x4,0x80,0,0,0,0,
+0,0,0xd8,0xc,0,0x3,0x20,0xd8,0,0x9,
+0xc0,0xc0,0x30,0x13,0x9,0xc1,0xb0,0,0,0,
+0,0,0,0x33,0x3,0,0,0,0,0,
+0,0,0,0,0x3,0,0,0,0x18,0,
+0xc0,0,0,0x30,0,0,0xc0,0,0,0,
+0x3,0,0xc,0,0,0,0,0,0,0,
+0,0x70,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,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,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x30,0,0,0,0,0,0,0,
+0,0,0,0x3,0,0xc0,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x3,0,0,
+0,0,0,0,0,0,0,0xf0,0x3c,0x7,
+0x80,0,0x1c,0x7,0x1,0xc0,0,0,0x4,0x80,
+0,0,0x7f,0x1f,0xc7,0xf0,0,0,0x1f,0xc0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x18,0x66,0x19,0x86,0,0,0,
+0,0,0x30,0,0xc0,0xc0,0,0,0x4,0x80,
+0,0,0xc,0x1,0x80,0xe0,0,0x18,0,0xc1,
+0xe0,0,0x1d,0x80,0x1,0x80,0x18,0xc,0,0,
+0,0,0,0xc,0,0x60,0x70,0,0,0xc0,
+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,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,0,0,0,0x3,0x3,0x30,
+0x36,0x8,0xe,0x1,0xe0,0x30,0x6,0x6,0,0xc0,
+0,0,0,0,0,0x6,0x1e,0xf,0x83,0xe0,
+0xfc,0x7,0x1f,0xc1,0xf1,0xfe,0x3e,0x7,0x80,0,
+0,0,0,0,0,0x7c,0,0x7,0x87,0xe0,
+0x7c,0x7c,0x1f,0xc7,0xf0,0x3c,0x63,0x1f,0xc1,0xf1,
+0x86,0x30,0x1c,0xe7,0x18,0x78,0x7e,0x7,0x87,0xe0,
+0x7c,0x7f,0x98,0x66,0x1b,0x6,0x61,0x98,0x77,0xf8,
+0x78,0x60,0xf,0x1,0xc0,0,0x18,0,0x6,0,
+0,0x1,0x80,0,0xf0,0,0x60,0x3,0,0xc1,
+0x80,0x78,0,0,0,0,0,0,0,0,
+0,0x18,0,0,0,0,0,0,0,0,
+0x3c,0xc,0xe,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,0x3,0,0x40,
+0x3e,0,0x30,0xe0,0,0x78,0x36,0,0x1,0xe0,
+0,0,0,0,0x1,0xfe,0x1c,0,0,0,
+0x78,0x6,0,0,0,0,0,0,0,0xe0,
+0,0x30,0xc,0,0xc0,0x30,0x1e,0x7,0x81,0xe0,
+0x78,0x1c,0x3,0x1,0xfc,0x7c,0x7f,0x1f,0xc7,0xf1,
+0xfc,0x7f,0x1f,0xc7,0xf1,0xfc,0x7c,0x1c,0x61,0xe0,
+0x78,0x1e,0x7,0x81,0xe0,0,0x1e,0xd8,0x66,0x19,
+0x86,0x61,0x98,0x76,0,0xf8,0x18,0x1,0x81,0xe0,
+0xe4,0x1b,0x4,0x80,0,0,0x4,0x1,0x1,0xa0,
+0x6c,0xc,0x1,0x83,0x20,0xd8,0x1e,0xe,0x80,0xc0,
+0x30,0x1e,0xe,0x41,0xb0,0,0,0x6,0,0xc0,
+0x78,0x36,0x1,0x86,0,0xd8,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,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,
+0,0x3,0x3,0x30,0x26,0x8,0x1f,0x3,0xe0,0x30,
+0x6,0x3,0,0xc0,0,0,0,0,0,0xc,
+0x3f,0xf,0x87,0xf0,0xfe,0x7,0x1f,0xc3,0xf1,0xfe,
+0x7f,0xf,0xc0,0,0,0,0,0,0,0xfe,
+0xe,0x7,0x87,0xf8,0xfc,0x7f,0x1f,0xc7,0xf0,0xfe,
+0x63,0x1f,0xc1,0xf1,0x8e,0x30,0x1c,0xe7,0x18,0xfc,
+0x7f,0xf,0xc7,0xf0,0xfc,0x7f,0x98,0x66,0x1b,0x6,
+0x73,0x9c,0x67,0xf8,0x78,0x20,0xf,0x1,0xe0,0,
+0xc,0,0x6,0,0,0x1,0x80,0x1,0xf0,0,
+0x60,0x3,0,0x1,0x80,0x78,0,0,0,0,
+0,0,0,0,0,0x18,0,0,0,0,
+0,0,0,0,0x7c,0xc,0xf,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,0x3,0,0x40,0x7e,0,0x38,0xe0,0xc0,0xf8,
+0x36,0x7,0x81,0xf0,0,0,0,0x1,0xe1,0xfe,
+0x3e,0,0x3,0xc0,0xc,0xc,0,0x3,0xf8,0,
+0,0x7,0x81,0xf0,0,0x30,0xc,0,0xc0,0x30,
+0x1e,0x7,0x81,0xe0,0x78,0x1c,0x7,0x81,0xfc,0xfc,
+0x60,0x18,0x6,0x1,0xfc,0x7f,0x3,0x7,0xf1,0xfc,
+0x7f,0x1c,0x63,0xf0,0xfc,0x3f,0xf,0xc3,0xf0,0,
+0x3f,0x98,0x66,0x19,0x86,0x61,0x9c,0x66,0x1,0xfc,
+0xc,0x3,0x3,0x30,0x9c,0x1b,0x3,0,0,0,
+0,0,0x1,0x10,0x6c,0,0x3,0,0,0xd8,
+0x26,0xb,0x80,0,0,0x33,0x9,0xc1,0xb0,0,
+0,0x3,0,0,0xc8,0x36,0x3,0x6,0,0xd8,
+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,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,0,0x3,0x3,0x30,0x66,0x3e,
+0x11,0x3,0,0x30,0xc,0x3,0xe,0xdc,0,0,
+0,0,0,0xc,0x73,0x9,0x84,0x30,0x6,0xf,
+0x18,0x3,0,0xe,0x73,0x1c,0xe0,0,0,0,
+0,0,0,0x86,0x3f,0x7,0x86,0x38,0xc4,0x63,
+0x18,0x6,0,0xc2,0x63,0x3,0,0x31,0x9c,0x30,
+0x1e,0xe7,0x98,0xce,0x63,0x8c,0xe6,0x31,0xc4,0xc,
+0x18,0x66,0x3b,0x6,0x33,0xc,0xe0,0x38,0x60,0x30,
+0x3,0x3,0x30,0,0,0,0x6,0,0,0x1,
+0x80,0x1,0x80,0,0x60,0,0,0x1,0x80,0x18,
+0,0,0,0,0,0,0,0,0,0x7f,
+0x80,0,0,0,0,0,0,0,0x60,0xc,
+0x3,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,0x40,0x70,0,
+0x19,0xc0,0xc0,0xc0,0,0xc,0x40,0x30,0,0,
+0,0x2,0x18,0,0x22,0x3,0,0x60,0xc,0,
+0,0x7,0xd8,0,0,0x1,0x81,0x18,0,0x30,
+0xc,0x3,0,0,0x1e,0x7,0x81,0xe0,0x78,0x1e,
+0x7,0x83,0x60,0xc0,0x60,0x18,0x6,0x1,0x80,0xc,
+0x3,0,0xc0,0x30,0x63,0x1c,0x63,0x38,0xce,0x33,
+0x8c,0xe3,0x38,0,0x33,0x98,0x66,0x19,0x86,0x61,
+0x8c,0xe7,0xe1,0x84,0,0,0,0,0,0,
+0,0,0,0,0x1e,0x7,0x80,0,0,0x3c,
+0,0x3,0xc0,0,0x1f,0,0x1,0xe0,0x78,0,
+0,0,0,0x30,0x1e,0xc0,0x6,0x30,0,0,
+0,0x6,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,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,0,0,0,0x3,
+0x3,0x31,0xff,0x7e,0x11,0x3,0,0x30,0xc,0x3,
+0x83,0xf0,0x30,0,0,0,0,0x18,0x73,0x81,
+0x80,0x30,0x6,0x1b,0x18,0x7,0,0xc,0x63,0x18,
+0xe0,0,0x30,0x1,0x80,0x6,0,0x6,0x71,0x87,
+0x86,0x19,0xc0,0x63,0x98,0x6,0x1,0xc0,0x63,0x3,
+0,0x31,0xb8,0x30,0x1a,0xe7,0x99,0xc6,0x61,0x9c,
+0x66,0x31,0x80,0xc,0x18,0x67,0x3b,0x76,0x3f,0xe,
+0xc0,0x70,0x60,0x10,0x3,0x6,0x18,0,0,0xf,
+0xc6,0xe0,0x7c,0x1d,0x87,0x87,0xf0,0x76,0x6e,0xf,
+0x3,0xc1,0x8c,0x18,0x1b,0xe6,0xe0,0x78,0x6e,0x7,
+0x63,0x78,0x7e,0x7f,0x98,0xc6,0x1b,0x3,0x73,0x98,
+0x67,0xf0,0x60,0xc,0x3,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,
+0x1,0xf0,0x60,0x3f,0x99,0xc0,0xc0,0xc0,0,0x10,
+0x21,0xf0,0x24,0,0,0x4,0x8,0,0x22,0x3,
+0,0x60,0x30,0,0x18,0xc7,0xd8,0,0,0x1,
+0x81,0x18,0x88,0x30,0xc,0,0xc0,0x30,0x37,0xd,
+0xc3,0x70,0xfc,0x36,0x7,0x83,0x61,0xc0,0x60,0x18,
+0x6,0x1,0x80,0xc,0x3,0,0xc0,0x30,0x63,0x9e,
+0x67,0x19,0xc6,0x71,0x98,0x67,0x18,0x84,0x77,0x98,
+0x66,0x19,0x86,0x61,0x8e,0xc7,0xf1,0x98,0x3f,0xf,
+0xc3,0xf0,0xfc,0x3f,0xf,0xc7,0x70,0x7c,0x3f,0x8f,
+0xe1,0xe0,0x78,0x3c,0xf,0x3,0xc0,0xf0,0x3f,0x9b,
+0x83,0xf0,0xfc,0x1e,0x7,0x81,0xe0,0x30,0x3f,0x98,
+0xc6,0x31,0x8c,0x63,0x18,0x66,0xe1,0x86,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,
+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,0,0x3,0,0x1,0xff,0x68,0x1f,0x13,
+0x80,0,0x1c,0x1,0x81,0xe0,0x30,0,0,0,
+0,0x18,0x67,0x81,0x80,0x30,0x6,0x1b,0x1f,0x6,
+0xf0,0x1c,0x73,0x18,0xe0,0xc0,0x30,0x7,0x9f,0xe7,
+0x80,0xc,0x60,0x8d,0xc6,0x39,0x80,0x61,0x98,0x6,
+0x1,0x80,0x63,0x3,0,0x31,0xb0,0x30,0x1b,0xe6,
+0x99,0x86,0x61,0x98,0x66,0x31,0xc0,0xc,0x18,0x63,
+0x33,0x76,0x1e,0x7,0xc0,0x60,0x60,0x18,0x3,0,
+0,0,0,0xf,0xe7,0xf0,0xfc,0x3f,0x8f,0xe7,
+0xf0,0xfe,0x7f,0xf,0x3,0xc1,0x98,0x18,0x1f,0xe7,
+0xf0,0xfc,0x7f,0xf,0xe3,0xf8,0xfe,0x18,0x18,0xc6,
+0x3b,0x3,0x33,0x18,0xe7,0xf0,0x60,0xc,0x3,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,0x3,0x3,0xf0,0x60,0x1f,0x1d,0x80,
+0xc0,0x70,0,0x37,0xb3,0x30,0x6c,0,0,0x9,
+0xec,0,0x3e,0x3,0,0xc0,0xc,0,0x18,0xc7,
+0xd8,0,0,0x1,0x81,0x18,0xcc,0xf8,0x3e,0,
+0x40,0x30,0x33,0xc,0xc3,0x30,0xcc,0x36,0x6,0x83,
+0x61,0x80,0x7f,0x1f,0xc7,0xf1,0x80,0xc,0x3,0,
+0xc0,0x30,0x61,0x9e,0x66,0x19,0x86,0x61,0x98,0x66,
+0x19,0xce,0x67,0x98,0x66,0x19,0x86,0x61,0x87,0xc6,
+0x39,0xb0,0x3f,0x8f,0xe3,0xf8,0xfe,0x3f,0x8f,0xef,
+0xf8,0xfc,0x71,0x9c,0x63,0xf8,0xfe,0xc,0xf,0,
+0xc0,0xf0,0x71,0x9f,0xc7,0x39,0xce,0x3f,0xf,0xc3,
+0xf0,0,0x73,0x98,0xc6,0x31,0x8c,0x63,0x18,0xe7,
+0xf1,0x8e,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,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,0,0x3,0,0,
+0x4c,0x68,0xe,0xe7,0xc0,0,0x18,0x1,0x83,0xf0,
+0x30,0,0,0,0,0x30,0x6d,0x81,0x80,0x70,
+0x3c,0x33,0x1f,0xc7,0xf0,0x18,0x3e,0x1c,0xe0,0xc0,
+0x30,0x3e,0x1f,0xe1,0xf0,0x18,0xc6,0x8c,0xc7,0xf1,
+0x80,0x61,0x9f,0xc7,0xf1,0x9e,0x7f,0x3,0,0x31,
+0xf0,0x30,0x1b,0x66,0xd9,0x86,0x63,0x98,0x67,0xf0,
+0xf8,0xc,0x18,0x63,0x33,0x76,0x1c,0x7,0x80,0xe0,
+0x60,0x8,0x3,0,0,0,0,0,0x67,0x39,
+0xc0,0x73,0x9c,0x61,0x81,0xce,0x73,0x3,0,0xc1,
+0xb0,0x18,0x1b,0x67,0x31,0xce,0x73,0x9c,0xe3,0x88,
+0xc2,0x18,0x18,0xc7,0x33,0x36,0x3e,0x1c,0xc0,0x70,
+0x60,0xc,0x3,0x3,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,0x3,0x7,0x41,
+0xfc,0x11,0x3f,0xe0,0xc1,0xfc,0,0x2c,0x13,0xf1,
+0xd8,0,0,0x9,0x24,0,0x1c,0x1f,0xe1,0,
+0x4,0,0x18,0xc7,0xd8,0x30,0,0x1,0x81,0xf0,
+0x76,0x7,0,0xe7,0x80,0x70,0x33,0xc,0xc3,0x30,
+0xcc,0x37,0xc,0xc3,0x79,0x80,0x7f,0x1f,0xc7,0xf1,
+0xfc,0xc,0x3,0,0xc0,0x30,0xf9,0x9b,0x66,0x19,
+0x86,0x61,0x98,0x66,0x18,0xfc,0x6f,0x98,0x66,0x19,
+0x86,0x61,0x87,0x86,0x19,0xb8,0x1,0x80,0x60,0x18,
+0x6,0x1,0x80,0x60,0xd9,0xc0,0x7f,0x9f,0xe7,0x19,
+0xc6,0xc,0x3,0,0xc0,0x30,0x61,0x9c,0xc6,0x19,
+0x86,0x73,0x9c,0xe7,0x38,0,0x67,0x98,0xc6,0x31,
+0x8c,0x63,0x1c,0xc7,0x39,0xcc,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,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,
+0,0x3,0,0,0xcc,0x7c,0x3,0x86,0xd8,0,
+0x18,0x1,0x8e,0xdc,0x30,0,0x1f,0xe0,0,0x30,
+0x69,0x81,0x80,0xe0,0x3c,0x63,0x1,0xc7,0x38,0x38,
+0x3f,0xf,0xe0,0xc0,0,0x70,0,0,0x38,0x38,
+0xcf,0x8c,0xc7,0xf1,0x80,0x61,0x9f,0xc7,0xf1,0x9e,
+0x7f,0x3,0,0x31,0xf8,0x30,0x1b,0x66,0xd9,0x86,
+0x7f,0x18,0x67,0xe0,0x7c,0xc,0x18,0x63,0x33,0x56,
+0x1c,0x3,0x81,0xc0,0x60,0xc,0x3,0,0,0,
+0,0x7,0xe6,0x19,0x80,0x61,0x9f,0xe1,0x81,0x86,
+0x63,0x3,0,0xc1,0xf0,0x18,0x1b,0x66,0x31,0x86,
+0x61,0x98,0x63,0x80,0xf0,0x18,0x18,0xc3,0x31,0x36,
+0x1e,0xc,0xc0,0xe0,0x60,0xc,0x3,0x87,0x88,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,0x3,0x6,0x41,0xfc,0x11,0x7,0,0xc1,0x8c,
+0,0x2c,0x11,0xf1,0x90,0xff,0x9f,0xe9,0xc4,0,
+0,0x1f,0xe3,0xe0,0x78,0,0x18,0xc3,0xd8,0x30,
+0,0x7,0xc0,0xf0,0x32,0xf8,0x7,0x80,0x78,0x60,
+0x7f,0x1f,0xc7,0xf0,0xcc,0x77,0xc,0xc6,0x79,0x80,
+0x60,0x18,0x6,0x1,0xfc,0xc,0x3,0,0xc0,0x30,
+0xf9,0x9b,0x66,0x19,0x86,0x61,0x98,0x66,0x18,0x78,
+0x6d,0x98,0x66,0x19,0x86,0x61,0x83,0x86,0x39,0x9c,
+0x1f,0x87,0xe1,0xf8,0xfe,0x1f,0x87,0xe3,0xf9,0x80,
+0x7f,0x9f,0xe7,0xf9,0xfe,0xc,0x3,0,0xc0,0x30,
+0x61,0x98,0xc6,0x19,0x86,0x61,0x98,0x66,0x19,0xff,
+0x6d,0x98,0xc6,0x31,0x8c,0x63,0xc,0xc6,0x18,0xdc,
+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,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,0,0x3,0,0x3,0xfe,0x1f,
+0xc,0x6c,0xf8,0,0x18,0x1,0x80,0xc1,0xff,0,
+0x1f,0xe0,0,0x20,0x79,0x81,0x81,0xc0,0x6,0x7f,
+0xc0,0xc7,0x18,0x38,0x73,0x87,0x60,0,0,0x70,
+0,0,0x38,0x30,0xd8,0x9f,0xc6,0x19,0x80,0x61,
+0x98,0x6,0x1,0xc6,0x63,0x3,0,0x31,0xd8,0x30,
+0x1b,0x66,0x59,0x86,0x7e,0x18,0x66,0x60,0xe,0xc,
+0x18,0x63,0x73,0x5e,0x1e,0x3,0x1,0x80,0x60,0x4,
+0x3,0,0,0,0,0x1f,0xe6,0x19,0x80,0x61,
+0x9f,0xe1,0x81,0x86,0x63,0x3,0,0xc1,0xf0,0x18,
+0x1b,0x66,0x31,0x86,0x61,0x98,0x63,0,0x7c,0x18,
+0x18,0xc3,0x31,0xf6,0xc,0xf,0xc1,0xc1,0xe0,0xc,
+0x1,0xec,0xcc,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,0x3,0x6,0x40,0x60,0x1f,
+0x3f,0xe0,0x1,0xcc,0,0x2c,0x11,0xf0,0xc8,0xff,
+0x9f,0xe9,0x64,0,0,0x3,0,0,0,0,
+0x18,0xc0,0xd8,0x30,0,0,0x1,0xf8,0x64,0x6,
+0x3c,0x7,0x80,0xc0,0x7f,0x9f,0xe7,0xf9,0xfe,0x7f,
+0xf,0xc7,0xe1,0x80,0x60,0x18,0x6,0x1,0x80,0xc,
+0x3,0,0xc0,0x30,0x61,0x99,0x66,0x19,0x86,0x61,
+0x98,0x66,0x18,0x78,0x79,0x98,0x66,0x19,0x86,0x61,
+0x83,0x7,0xf9,0x8e,0x7f,0x9f,0xe7,0xf9,0xfe,0x7f,
+0x9f,0xef,0xf9,0x80,0x60,0x18,0x7,0xf9,0xfe,0xc,
+0x3,0,0xc0,0x30,0x61,0x98,0xc6,0x19,0x86,0x61,
+0x98,0x66,0x19,0xff,0x79,0x98,0xc6,0x31,0x8c,0x63,
+0xf,0xc6,0x18,0xdc,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,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,0,0,
+0,0x3,0xfe,0xb,0x10,0xfc,0x78,0,0x18,0x1,
+0x80,0xc1,0xff,0,0,0,0,0x60,0x73,0x81,
+0x83,0x80,0x6,0x7f,0xc0,0xc7,0x18,0x30,0x61,0x80,
+0xe0,0,0,0x1e,0x1f,0xe1,0xf0,0x30,0xd8,0x9f,
+0xe6,0x19,0xc0,0x63,0x98,0x6,0x1,0xc6,0x63,0x3,
+0,0x31,0x9c,0x30,0x18,0x66,0x79,0xc6,0x60,0x1c,
+0x66,0x70,0x6,0xc,0x18,0x63,0xe1,0x5c,0x3f,0x3,
+0x3,0x80,0x60,0x6,0x3,0,0,0,0,0x1c,
+0x66,0x19,0x80,0x61,0x98,0x1,0x81,0x86,0x63,0x3,
+0,0xc1,0x98,0x18,0x1b,0x66,0x31,0x86,0x61,0x98,
+0x63,0,0xe,0x18,0x18,0xc3,0xe1,0xfe,0x1e,0x7,
+0x83,0x81,0xe0,0xc,0x1,0xe0,0xf8,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,0x3,
+0x6,0x40,0x60,0x3f,0xbf,0xe0,0,0xfc,0,0x37,
+0xb1,0xf0,0x64,0x1,0x80,0xd,0x2c,0,0,0x3,
+0,0,0,0,0x18,0xc0,0xd8,0,0,0,
+0x1,0xf8,0xc8,0x6,0x23,0xc0,0x31,0x80,0x61,0x98,
+0x66,0x19,0xfe,0x7f,0xf,0xc7,0xe1,0xc0,0x60,0x18,
+0x6,0x1,0x80,0xc,0x3,0,0xc0,0x30,0x63,0x99,
+0xe7,0x19,0xc6,0x71,0x98,0x67,0x18,0xfc,0x71,0x9c,
+0xe7,0x39,0xce,0x61,0x83,0x7,0xe1,0x86,0x71,0x9c,
+0x67,0x19,0x86,0x71,0x9c,0x6c,0xc1,0x80,0x70,0x9c,
+0x26,0x1,0x80,0xc,0x3,0,0xc0,0x30,0x73,0x98,
+0xc7,0x39,0xce,0x61,0x98,0x66,0x18,0,0x73,0x98,
+0xc6,0x31,0x8c,0x63,0x7,0x86,0x18,0x78,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,
+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,0,0,0,0,0x98,0xb,0,0x9e,
+0x30,0,0x1c,0x1,0x80,0,0x30,0xc,0,0,
+0xc0,0x40,0x73,0x81,0x83,0x1,0x6,0x3,0x1,0xc7,
+0x38,0x70,0x73,0x80,0xc0,0xc0,0x30,0x7,0x9f,0xe7,
+0x80,0,0xd9,0x98,0x66,0x18,0xc4,0x63,0x18,0x6,
+0,0xc6,0x63,0x3,0x4,0x31,0x8c,0x30,0x18,0x66,
+0x79,0xce,0x60,0xc,0xe6,0x31,0xe,0xc,0x1c,0xe1,
+0xe1,0xdc,0x33,0x3,0x7,0,0x60,0x6,0x3,0,
+0,0,0,0x18,0xe7,0x39,0xc0,0x73,0x9c,0x21,
+0x81,0xce,0x63,0x3,0,0xc1,0x9c,0x1c,0x1b,0x66,
+0x31,0xce,0x73,0x9c,0xe3,0,0x6,0x1f,0x98,0xc1,
+0xe1,0xde,0x3f,0x7,0x87,0,0x60,0xc,0x3,0x80,
+0x70,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,0x3,0x7,0x40,0x60,0x20,0x6,0,
+0xc0,0x38,0,0x18,0x60,0,0x20,0x1,0x80,0x6,
+0x18,0,0,0,0,0,0,0,0x1c,0xc0,
+0xd8,0,0,0,0,0,0x80,0xa,0,0x60,
+0x31,0x84,0x61,0x98,0x66,0x19,0x86,0x63,0x98,0x66,
+0x60,0xe4,0x7f,0x1f,0xc7,0xf1,0x80,0xc,0x1f,0xc0,
+0xc0,0x30,0x63,0x18,0xe7,0x39,0xce,0x73,0x9c,0xe7,
+0x39,0xce,0x33,0x8f,0xc3,0xf0,0xfc,0x73,0x83,0x6,
+0x1,0x86,0x63,0x98,0xe6,0x39,0x8e,0x63,0x98,0xec,
+0xc1,0xc0,0x3f,0x8f,0xe7,0x9,0xc0,0x7f,0x83,0x7,
+0xf8,0x30,0x3f,0x18,0xc3,0xf0,0xfc,0x73,0x9c,0xe7,
+0x38,0x30,0x7f,0x18,0xc7,0xf1,0x8c,0x63,0x7,0x87,
+0x38,0x78,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,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,0,0x3,0,0x1,
+0x98,0x7f,0,0xf7,0xf0,0,0xc,0x3,0x80,0,
+0x30,0xc,0,0,0xc0,0xc0,0x3f,0xf,0xe7,0xf1,
+0xfe,0x3,0x1f,0xc3,0xf0,0x60,0x7f,0x8f,0xc0,0xc0,
+0x30,0x1,0x80,0x6,0,0x30,0xdf,0x98,0x67,0xf8,
+0xfc,0x7f,0x1f,0xc6,0,0xfe,0x63,0x1f,0xc7,0xf1,
+0x8e,0x3f,0x98,0x66,0x38,0xfc,0x60,0xf,0xc6,0x39,
+0xfe,0xc,0xf,0xc1,0xe1,0xcc,0x73,0x83,0x7,0xf8,
+0x60,0x3,0x3,0,0,0,0,0x1f,0xe7,0xf0,
+0xfc,0x3f,0x8f,0xe1,0x80,0xfe,0x63,0x1f,0xe0,0xc1,
+0x8c,0x1f,0x9b,0x66,0x30,0xfc,0x7f,0xf,0xe3,0,
+0xfe,0xf,0x9f,0xc1,0xe1,0xce,0x73,0x7,0x7,0xf0,
+0x60,0xc,0x3,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,0x3,0x3,0xf1,
+0xfe,0,0x6,0,0xc0,0x1c,0,0x7,0x80,0,
+0,0,0,0x1,0xe0,0,0,0x1f,0xe0,0,
+0,0,0x1f,0xe0,0xd8,0,0,0,0,0,
+0,0x1a,0,0x40,0x51,0xfc,0xe1,0xb8,0x6e,0x1b,
+0x86,0xe1,0x98,0x6c,0x7c,0xfc,0x7f,0x1f,0xc7,0xf1,
+0xfc,0x7f,0x1f,0xc7,0xf1,0xfc,0x7f,0x18,0xe3,0xf0,
+0xfc,0x3f,0xf,0xc3,0xf0,0x84,0x7f,0x7,0x81,0xe0,
+0x78,0x3f,0x3,0x6,0x1,0xbe,0x73,0x9f,0xe7,0xf9,
+0xfe,0x7f,0x9f,0xef,0xf8,0xfc,0x1f,0x87,0xe3,0xf8,
+0xfe,0x7f,0x9f,0xe7,0xf9,0xfe,0x1e,0x18,0xc1,0xe0,
+0x78,0x3f,0xf,0xc3,0xf0,0x30,0x7e,0x1f,0xc3,0xb1,
+0xfc,0x7f,0x7,0x87,0xf0,0x70,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,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,
+0,0x3,0,0x1,0x90,0x3e,0,0x63,0xd8,0,
+0xc,0x3,0,0,0x30,0xc,0,0,0xc0,0x80,
+0x1e,0xf,0xe7,0xf0,0xfc,0x3,0x1f,0x1,0xe0,0xe0,
+0x1e,0xf,0x80,0xc0,0x30,0,0,0,0,0x30,
+0x66,0xb8,0x67,0xf0,0x7c,0x7c,0x1f,0xc6,0,0x3c,
+0x63,0x1f,0xc3,0xe1,0x87,0x3f,0x98,0x66,0x38,0x78,
+0x60,0x7,0xc6,0x18,0xf8,0xc,0x7,0x81,0xe1,0x8c,
+0xe1,0x83,0x7,0xf8,0x60,0x3,0x3,0,0,0,
+0,0xf,0x66,0xe0,0x7c,0x1d,0x87,0xe1,0x80,0x76,
+0x63,0x1f,0xe0,0xc1,0x8e,0xf,0x9b,0x66,0x30,0x78,
+0x6e,0x7,0x63,0,0xfc,0,0xe,0xc1,0xe0,0xcc,
+0x63,0x83,0x7,0xf0,0x60,0xc,0x3,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,0x3,0x1,0xf1,0xfe,0,0x6,0,0xc0,0xc,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1f,0xe0,0,0,0,0x1b,0x60,0xd8,0,
+0x8,0,0,0,0,0x1f,0x1,0x80,0x90,0xf8,
+0,0,0,0x3,0x87,0xc1,0x98,0x6c,0x7c,0x7c,
+0,0,0,0x1,0xfc,0x7f,0,0x7,0xf1,0xfc,
+0x7c,0x18,0xe1,0xe0,0x78,0x1e,0x7,0x81,0xe0,0,
+0xde,0,0,0,0,0x1e,0x3,0x6,0x1,0xbc,
+0x3d,0x8f,0x63,0xd8,0xf6,0x3d,0x8f,0x67,0x38,0x7c,
+0,0,0x1,0xf8,0x7e,0,0x1f,0xe0,0x1,0xfe,
+0,0x18,0xc0,0,0,0x1e,0x7,0x81,0xe0,0,
+0x40,0xe,0xc0,0,0xec,0x3b,0x3,0x6,0xe0,0x30,
+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,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,0,0,0,0,0,0x8,
+0,0,0,0,0x6,0x3,0,0,0,0xc,
+0,0,0x1,0x80,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x30,0,
+0,0,0,0,0x70,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xe0,0,0,0,
+0,0,0,0,0,0,0,0,0x60,0x1,
+0x83,0,0,0,0,0,0,0,0,0,
+0,0,0,0xe,0,0,0,0xc0,0,0,
+0,0,0,0,0x60,0,0x60,0,0,0,
+0,0,0,0,0,0x7,0,0,0x60,0xc,
+0x3,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,0x40,0,0,
+0,0,0xc0,0xfc,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x18,0,0xd8,0,0x4,0,0,0,0,0x2,
+0x3,0,0xf8,0,0,0,0,0,0,0,
+0,0,0,0x8,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,0x8,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,
+0x7,0x6,0,0x70,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,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,0,0,
+0,0,0,0x8,0,0,0,0,0x6,0x6,
+0,0,0,0x18,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x60,0,0,0,0,0,0x3f,0x80,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x40,0,0,0,0,0,0,0,0,0,
+0,0,0x78,0,0xf,0,0x3,0xff,0,0,
+0,0,0,0,0,0,0,0xfc,0,0,
+0x7,0xc0,0,0,0,0,0,0,0x60,0,
+0x60,0,0,0,0,0,0,0,0,0x1e,
+0,0,0x7c,0xc,0xf,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,0x40,0,0,0,0,0xc0,0xf8,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x18,0,0xd8,0,0x1c,0,
+0,0,0,0x2,0x3,0xe0,0x10,0,0,0,
+0,0,0,0,0,0,0,0x8,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,0x8,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,0x1e,0x6,0x1,0xe0,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,
+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,0,0,0,0,0,0x8,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,0x1f,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,0x78,0,0xf,0,
+0x3,0xff,0,0,0,0,0,0,0,0,
+0,0xf8,0,0,0x7,0x80,0,0,0,0,
+0,0,0x60,0,0x60,0,0,0,0,0,
+0,0,0,0x1c,0,0,0x3c,0xc,0xe,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,
+0xc0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x18,0,
+0,0,0,0,0,0,0,0,0,0,
+0x10,0,0,0,0,0,0,0,0,0,
+0,0x78,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,0x78,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,0x1c,0x6,
+0x1,0xc0,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,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,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,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,0xc,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,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,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,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+};
+
+static WORD MenloMedium_ch_ofst[225] = {
+0,10,20,30,40,50,60,70,80,90,
+100,110,120,130,140,150,160,170,180,190,
+200,210,220,230,240,250,260,270,280,290,
+300,310,320,330,340,350,360,370,380,390,
+400,410,420,430,440,450,460,470,480,490,
+500,510,520,530,540,550,560,570,580,590,
+600,610,620,630,640,650,660,670,680,690,
+700,710,720,730,740,750,760,770,780,790,
+800,810,820,830,840,850,860,870,880,890,
+900,910,920,930,940,950,960,970,980,990,
+1000,1010,1020,1030,1040,1050,1060,1070,1080,1090,
+1100,1110,1120,1130,1140,1150,1160,1170,1180,1190,
+1200,1210,1220,1230,1240,1250,1260,1270,1280,1290,
+1300,1310,1320,1330,1340,1350,1360,1370,1380,1390,
+1400,1410,1420,1430,1440,1450,1460,1470,1480,1490,
+1500,1510,1520,1530,1540,1550,1560,1570,1580,1590,
+1600,1610,1620,1630,1640,1650,1660,1670,1680,1690,
+1700,1710,1720,1730,1740,1750,1760,1770,1780,1790,
+1800,1810,1820,1830,1840,1850,1860,1870,1880,1890,
+1900,1910,1920,1930,1940,1950,1960,1970,1980,1990,
+2000,2010,2020,2030,2040,2050,2060,2070,2080,2090,
+2100,2110,2120,2130,2140,2150,2160,2170,2180,2190,
+2200,2210,2220,2230,2240,
+};
+
+static struct font_hdr MenloMedium_font = {
+STPROP, 12, "-FreeType-Meslo", 32, 255,
+20, 16, 10, 4, 4,
+10, 10, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+MenloMedium_ch_ofst, MenloMedium_data,
+424, 20,
+NULL,
+0, 0,   /* x/y offset */
+0,        /* lineHeight */
+};
+
+MgFont *mgMenloMediumFont()
+{
+return &MenloMedium_font;
+}
diff --git a/lib/font/mgSail8.c b/lib/font/mgSail8.c
new file mode 100644
index 0000000..5c55d9a
--- /dev/null
+++ b/lib/font/mgSail8.c
@@ -0,0 +1,112 @@
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+/*	formerly known as sailfnt.c mgSmallFont() now mgSmallFont()	*/
+
+/* static char sail_name[] = "SAIL.FNT"; */
+
+static UBYTE sail_data[] = {
+	0x00,0xc5, 0x14,0x23, 0xe6,0x04, 0x11,0x00, 
+	0x00,0x00, 0x00,0x02, 0x30,0x87, 0x1c,0x13, 
+	0xe7,0x3e, 0x71,0xc0, 0x00,0x00, 0x00,0x1c, 
+	0x71,0xcf, 0x1c,0xf3, 0xef,0x9c, 0x89,0xc0, 
+	0xa2,0x82, 0x28,0x9c, 0xf1,0xcf, 0x1c,0xfa, 
+	0x28,0xa2, 0x8a,0x27, 0x9c,0x81, 0xc2,0x00, 
+	0x20,0x08, 0x00,0x08, 0x03,0x80, 0x80,0x41, 
+	0x10,0x30, 0x00,0x00, 0x00,0x00, 0x00,0x40, 
+	0x00,0x00, 0x00,0x00, 0x0c,0x21, 0x80,0x00, 
+	0x00,0xc5, 0x3e,0x7b, 0x2a,0x04, 0x20,0x8a, 
+	0x88,0x00, 0x00,0x04, 0x49,0x88, 0xa2,0x32, 
+	0x08,0x02, 0x8a,0x22, 0x04,0x10, 0x04,0x22, 
+	0x8a,0x28, 0xa2,0x8a, 0x08,0x22, 0x88,0x80, 
+	0xa4,0x83, 0x6c,0xa2, 0x8a,0x28, 0xa2,0x22, 
+	0x28,0xa2, 0x52,0x20, 0x90,0x40, 0x47,0x00, 
+	0x21,0xcb, 0x0e,0x69, 0xc4,0x1e, 0xb0,0x00, 
+	0x12,0x13, 0x4b,0x1c, 0xb1,0xab, 0x1e,0xfa, 
+	0x28,0xa2, 0x8a,0x2f, 0x90,0x20, 0x44,0x00, 
+	0x00,0xc5, 0x14,0xa0, 0x44,0x08, 0x40,0x47, 
+	0x08,0x00, 0x00,0x04, 0x58,0x80, 0x8c,0x53, 
+	0xcf,0x04, 0x72,0x22, 0x04,0x23, 0xe2,0x02, 
+	0xbb,0xef, 0x20,0x8b, 0xcf,0x20, 0xf8,0x80, 
+	0xa8,0x82, 0xaa,0xa2, 0xf2,0x2f, 0x18,0x22, 
+	0x28,0xaa, 0x21,0xc1, 0x10,0x20, 0x4a,0x80, 
+	0x10,0x2c, 0x90,0x9a, 0x2f,0x22, 0xc8,0xc3, 
+	0x14,0x12, 0xac,0xa2, 0xca,0x6c, 0xa0,0x42, 
+	0x28,0xa2, 0x52,0x21, 0x10,0x20, 0x4a,0x80, 
+	0x00,0xc0, 0x14,0x70, 0x8a,0x80, 0x40,0x4d, 
+	0xbe,0x03, 0xe0,0x08, 0x68,0x87, 0x02,0xf8, 
+	0x28,0x84, 0x89,0xe0, 0x00,0x40, 0x01,0x0c, 
+	0xba,0x28, 0xa0,0x8a, 0x08,0x26, 0x88,0x80, 
+	0xb8,0x82, 0xa9,0xa2, 0x82,0xaa, 0x04,0x22, 
+	0x25,0x2a, 0x50,0x82, 0x10,0x20, 0x42,0x00, 
+	0x01,0xe8, 0x90,0x8b, 0xe4,0x22, 0x88,0x41, 
+	0x18,0x12, 0xa8,0xa2, 0x8a,0x28, 0x1c,0x42, 
+	0x25,0x2a, 0x22,0x22, 0x20,0x20, 0x21,0x00, 
+	0x00,0x00, 0x3e,0x29, 0x69,0x00, 0x40,0x47, 
+	0x08,0x20, 0x02,0x08, 0x48,0x88, 0x22,0x12, 
+	0x28,0x88, 0x88,0x22, 0x04,0x23, 0xe2,0x00, 
+	0x82,0x28, 0xa2,0x8a, 0x08,0x22, 0x88,0x88, 
+	0xa4,0x82, 0x28,0xa2, 0x82,0x69, 0x22,0x22, 
+	0x25,0x36, 0x88,0x84, 0x10,0x10, 0x42,0x00, 
+	0x02,0x2c, 0x90,0x9a, 0x04,0x1c, 0x88,0x41, 
+	0x14,0x12, 0xa8,0xa2, 0xca,0x68, 0x02,0x42, 
+	0x65,0x2a, 0x51,0xe4, 0x10,0x20, 0x40,0x00, 
+	0x00,0xc0, 0x14,0xf2, 0x6e,0x80, 0x20,0x8a, 
+	0x88,0x20, 0x02,0x10, 0x31,0xcf, 0x9c,0x11, 
+	0xc7,0x08, 0x71,0xc2, 0x04,0x10, 0x04,0x08, 
+	0x72,0x2f, 0x1c,0xf3, 0xe8,0x1c, 0x89,0xc7, 
+	0x22,0xfa, 0x28,0x9c, 0x81,0xc8, 0x9c,0x21, 
+	0xc2,0x22, 0x88,0x87, 0x90,0x08, 0x42,0x00, 
+	0x01,0xab, 0x0e,0x69, 0xc4,0x02, 0x88,0x41, 
+	0x12,0x12, 0xa8,0x9c, 0xb1,0xa8, 0x3c,0x31, 
+	0xa2,0x14, 0x88,0x2f, 0x90,0x20, 0x40,0x00, 
+	0x00,0x00, 0x00,0x20, 0x00,0x00, 0x11,0x00, 
+	0x00,0x40, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
+	0x00,0x00, 0x00,0x00, 0x08,0x00, 0x00,0x00, 
+	0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
+	0x00,0x00, 0x00,0x00, 0x00,0x20, 0x00,0x00, 
+	0x00,0x00, 0x00,0x00, 0x1c,0x01, 0xc0,0x3e, 
+	0x00,0x00, 0x00,0x00, 0x00,0x3c, 0x00,0x06, 
+	0x00,0x00, 0x00,0x00, 0x80,0x20, 0x00,0x00, 
+	0x00,0x00, 0x01,0xc0, 0x0c,0x21, 0x80,0x00, 
+	};
+
+static WORD sail_ch_ofst[] = {
+0, 6, 12, 18, 24, 30, 36, 42,
+48, 54, 60, 66, 72, 78, 84, 90,
+96, 102, 108, 114, 120, 126, 132, 138,
+144, 150, 156, 162, 168, 174, 180, 186,
+192, 198, 204, 210, 216, 222, 228, 234,
+240, 246, 252, 258, 264, 270, 276, 282,
+288, 294, 300, 306, 312, 318, 324, 330,
+336, 342, 348, 354, 360, 366, 372, 378,
+384, 390, 396, 402, 408, 414, 420, 426,
+432, 438, 444, 450, 456, 462, 468, 474,
+480, 486, 492, 498, 504, 510, 516, 522,
+528, 534, 540, 546, 552, 558, 564, 570,
+576, 582, 588,
+};
+
+static struct font_hdr sail_font =
+	{
+	STPROP, 0, "SAIL.FNT", ' ',127,  
+	0,0,0,0,0,	/* *_dist */
+	6, 6,  /*widths... */
+	0,0,0,0,0,0,	/* through skew_m */
+	0, /*flags */
+	NULL, /* hz_ofst */
+	sail_ch_ofst,
+	sail_data,
+	72, 7,	/* frm_wdt,frm_hgt */
+	NULL,	/* next font */
+	0, -1,	/* x/y offset */
+	9,	/* lineHeight */
+	9,	/* psHeight */
+	};
+
+MgFont *mgSmallFont()
+{
+return &sail_font;
+}
+
diff --git a/lib/font/mgSixhi6.c b/lib/font/mgSixhi6.c
new file mode 100644
index 0000000..470502f
--- /dev/null
+++ b/lib/font/mgSixhi6.c
@@ -0,0 +1,210 @@
+/* sixhi.c - the data for the compiled-in Vpaint font. */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+/*	formerly known as sixhi.c mgTinyFont() now mgTinyFont()	*/
+
+static UBYTE sixhi_data[] = {
+0x0,0x82,0x4,0x21,0xcf,0xb6,0xd,0xe3,
+0x4,0xe3,0x81,0x50,0xf9,0x87,0xbc,0xc3,
+0xcc,0x3e,0x73,0xe0,0x38,0x1f,0x84,0x42,
+0x0,0xcd,0x94,0x7b,0x26,0xc,0x31,0x84,
+0x88,0x0,0x0,0x6,0x70,0x4f,0x3c,0x33,
+0xc7,0x3e,0x71,0xc3,0xc,0x18,0x6,0x1c,
+0x71,0xcf,0x1e,0xf3,0xef,0x9e,0x89,0xc0,
+0x92,0x42,0x28,0x9c,0xf1,0xcf,0x1e,0xfa,
+0x28,0xa2,0x8a,0x2f,0x9e,0xc1,0xe2,0x0,
+0x60,0x8,0x0,0x8,0x1,0x80,0x80,0x1,
+0x20,0x60,0x0,0x0,0x0,0x0,0x0,0x20,
+0x0,0x0,0x0,0x0,0xe,0x31,0xc4,0x0,
+0x79,0x41,0x8,0x51,0x2,0x0,0x21,0x44,
+0x14,0x21,0x5,0x8,0x20,0x7,0x88,0x51,
+0x2,0x10,0x51,0x45,0x4,0x1a,0x2f,0x6,
+0x10,0x41,0x4,0xf1,0xe7,0x1c,0x60,0x0,
+0x30,0xc0,0xc3,0x6c,0x69,0xa3,0x42,0x1,
+0xe4,0x1a,0x69,0x41,0x8,0x69,0xe7,0xbd,
+0x4b,0xa9,0xbc,0x7b,0xff,0x1c,0x7b,0xfc,
+0x1e,0xf3,0xd,0x8e,0xf9,0xbf,0xb6,0xf9,
+0xcd,0x5e,0x3b,0xe0,0x3e,0xd8,0xc0,0x0,
+0x1,0xcf,0xc0,0xf8,0xe0,0x0,0x71,0xc7,
+0xc,0x18,0x83,0x8c,0x78,0x86,0x6,0xc,
+0xc2,0x1a,0x30,0xc0,0x0,0x71,0xc7,0x3e,
+0x1,0xc2,0x6,0x62,0xaf,0x2a,0x1a,0x17,
+0x86,0x82,0x1,0x50,0xc8,0x80,0x84,0xc2,
+0xc,0x2,0x53,0x67,0x20,0x3f,0x42,0xf4,
+0x0,0xcd,0xbe,0xa3,0x4d,0xc,0x60,0xc3,
+0x8,0x0,0x0,0xc,0x98,0xc0,0x82,0x52,
+0x8,0x2,0x8a,0x23,0xc,0x31,0xe3,0x26,
+0x8a,0x28,0xa0,0x8a,0x8,0x20,0x88,0x80,
+0x94,0x43,0x6c,0xa2,0x8a,0x28,0xa0,0x22,
+0x28,0xa2,0x52,0x21,0x18,0x60,0x67,0x0,
+0x61,0xcf,0x1c,0x79,0xc2,0x1e,0xb1,0x81,
+0x24,0x21,0x4f,0x1c,0xf1,0xe7,0xe,0x72,
+0x28,0xa2,0x4a,0x27,0x8c,0x30,0xce,0x88,
+0x80,0x2,0x14,0x0,0x80,0x1e,0x50,0x2,
+0x0,0x50,0x80,0x0,0xfb,0xca,0x14,0x0,
+0x85,0x8,0x0,0x0,0xe,0x23,0x6d,0x88,
+0x20,0x82,0x8,0x0,0x0,0xa2,0x0,0x0,
+0x30,0xc0,0x6,0xf6,0xb2,0xc4,0x8c,0x72,
+0xc2,0x2c,0xb0,0x2,0x1c,0xeb,0x38,0xd7,
+0x1,0x2d,0x8c,0x8,0x61,0x8c,0x31,0xbd,
+0x86,0x1b,0xe7,0xc6,0xd9,0xb9,0xb6,0x18,
+0x6d,0x56,0x18,0x6f,0xe6,0xd8,0xa2,0x16,
+0x6b,0x66,0xfe,0x61,0xc6,0xbe,0x73,0x6d,
+0x9a,0x21,0xc4,0x12,0x3,0xe1,0x98,0x10,
+0xc0,0x2c,0x49,0xe0,0x7,0x68,0x63,0x0,
+0x3,0x62,0x3b,0xdf,0x6e,0x1c,0xb2,0x97,
+0x84,0xde,0xe1,0x50,0xc8,0x8f,0xbe,0xc3,
+0xef,0x8e,0x73,0x20,0xb7,0x60,0x62,0x94,
+0x0,0xc9,0x14,0x70,0x86,0x18,0x60,0xc7,
+0xbe,0x1,0xe0,0x18,0xa8,0x47,0x1c,0x93,
+0xcf,0x4,0x71,0xe0,0x0,0x60,0x1,0x8c,
+0xbb,0xef,0x20,0x8b,0xcf,0x26,0xf8,0x80,
+0x98,0x42,0xaa,0xa2,0xf2,0x2f,0x1c,0x22,
+0x28,0xaa,0x21,0x42,0x18,0x30,0x6d,0x80,
+0x30,0x28,0xa0,0x8b,0xe7,0xa2,0xc8,0x81,
+0x38,0x23,0xe8,0xa2,0x8a,0x24,0x98,0x22,
+0x28,0xaa,0x32,0x21,0x18,0x30,0x6b,0x9c,
+0x82,0x27,0x1c,0x71,0xc7,0x20,0x71,0xc7,
+0x18,0x21,0x87,0x1c,0x80,0xef,0x9c,0x71,
+0xc8,0xa2,0x89,0xc8,0x98,0x71,0xcf,0x1e,
+0x71,0x87,0x22,0xf1,0x2f,0xa2,0x61,0xe7,
+0xb6,0xcc,0xcd,0x9b,0x71,0xc5,0x96,0xba,
+0xe7,0x1c,0x70,0x0,0x8,0xea,0xdb,0x55,
+0x49,0x27,0xc,0x18,0x6d,0x8c,0x19,0xbd,
+0x86,0x18,0x66,0x46,0xd9,0xbd,0x9c,0xd8,
+0x6f,0x56,0x18,0x66,0xf6,0x71,0xc7,0x2d,
+0xd3,0xc6,0x54,0x33,0x66,0x8c,0xab,0xed,
+0x9c,0x72,0xa7,0x92,0x78,0x86,0x6,0x30,
+0xcf,0x80,0x30,0xc3,0x4,0x68,0xc1,0x0,
+0x0,0x8d,0x86,0x62,0xac,0xaa,0xe2,0xdf,
+0xdc,0x93,0xa3,0x58,0xd9,0xcc,0x6,0xd8,
+0x69,0x8c,0xdb,0xef,0xa4,0x40,0x21,0x68,
+0x0,0xc0,0x3e,0x29,0x6e,0x80,0x60,0xc3,
+0x8,0x30,0x3,0x30,0xc8,0x48,0x2,0xf8,
+0x28,0x88,0x88,0x23,0xc,0x31,0xe3,0xc,
+0xb2,0x28,0xa0,0x8a,0x8,0x22,0x88,0x88,
+0x94,0x42,0x29,0xa2,0x82,0x2a,0x2,0x22,
+0x25,0x36,0x50,0x84,0x18,0x18,0x60,0x0,
+0x3,0xe8,0xa0,0x8a,0x2,0x1e,0x88,0x81,
+0x24,0x22,0xa8,0xa2,0x8a,0x24,0x6,0x22,
+0x25,0x2a,0x31,0xe2,0xc,0x30,0xc1,0x32,
+0x82,0x2f,0x82,0x8,0x20,0xa0,0xfb,0xef,
+0x88,0x20,0x88,0xa2,0xf3,0x8a,0x22,0x8a,
+0x28,0xa2,0x7a,0x28,0x8e,0x20,0x8d,0x88,
+0x8,0x88,0xa2,0x89,0xa7,0x9c,0x61,0x0,
+0x8b,0x14,0xc6,0xf6,0xa,0x26,0x9a,0xa2,
+0xc8,0xa2,0x88,0x0,0x8,0x6a,0xf8,0xc0,
+0x4b,0xad,0x8c,0x38,0x6d,0x8c,0x19,0xbd,
+0x80,0x18,0x66,0x46,0xd9,0xb1,0x8e,0xd0,
+0x6c,0x56,0x18,0x66,0xc6,0x31,0xcd,0xad,
+0xd3,0x66,0x14,0x63,0x66,0x8c,0xab,0x65,
+0x36,0xaa,0xa4,0x12,0x0,0x0,0x0,0x30,
+0xc0,0x1a,0x0,0x3,0x34,0x69,0xe7,0x0,
+0x0,0x87,0x4,0x21,0xc9,0xb6,0x42,0x10,
+0x3c,0x18,0xe7,0x5c,0xd9,0xcc,0x6,0xf8,
+0x6d,0x8c,0xd8,0x67,0x3c,0x71,0xee,0xf0,
+0x0,0x0,0x14,0xf2,0x6d,0x0,0x31,0x84,
+0x88,0x30,0x3,0x20,0x70,0x4f,0xbc,0x13,
+0xc7,0x8,0x71,0xc3,0x4,0x18,0x6,0x0,
+0x82,0x2f,0x1e,0xf3,0xe8,0x1e,0x89,0xc7,
+0x12,0x7a,0x28,0x9c,0x81,0xc9,0xbc,0x21,
+0xe2,0x22,0x88,0x8f,0x9e,0x9,0xe0,0x0,
+0x1,0xef,0x1c,0x79,0xc2,0x2,0x89,0xc1,
+0x22,0x72,0x28,0x9c,0xf1,0xe4,0x1c,0x11,
+0xe2,0x36,0x48,0x27,0x8e,0x31,0xc0,0x3e,
+0x7a,0x28,0x3e,0xfb,0xef,0x9e,0x82,0x8,
+0x8,0x20,0x8f,0xbe,0x81,0xeb,0xa2,0x8a,
+0x28,0xa2,0xa,0x28,0x84,0x79,0xcf,0x8,
+0xf8,0x88,0xa2,0x89,0x60,0x0,0xc9,0x0,
+0x86,0x3c,0xc3,0x6c,0xfa,0x24,0x8c,0x79,
+0xef,0xbe,0x88,0x0,0x8,0x2b,0x1a,0x40,
+0x48,0x2c,0xbe,0x68,0x6d,0x8c,0x19,0xbf,
+0x80,0xf1,0xe6,0xde,0x73,0xff,0xbe,0xc0,
+0x6f,0xf6,0x18,0x67,0xc6,0x32,0x88,0x9a,
+0x6b,0xc6,0x14,0xc1,0xc7,0xcc,0x71,0xcd,
+0xb6,0x71,0xc3,0x92,0x7b,0xe7,0x9e,0x30,
+0x82,0x2c,0x0,0x0,0x1c,0x0,0x0,0x0,
+0x0,0x82,0x0,0x0,0x0,0x0,0x1,0xe3,
+0x18,0x10,0xb6,0x4c,0xf9,0xcf,0xbe,0x1b,
+0xef,0x8c,0xf8,0x60,0x7,0x58,0xac,0x0,
+0x0,0xc0,0x0,0x20,0x6,0x80,0x0,0x0,
+0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x8,0x0,0x0,0xc,
+0x78,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,
+0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0xe,
+0x0,0x0,0x0,0x0,0x80,0x20,0x0,0x0,
+0x0,0x0,0x3,0xc0,0x0,0x30,0x0,0x0,
+0xc1,0xe7,0x1e,0x79,0xe7,0xb8,0x71,0xc7,
+0x1c,0x71,0xc8,0xa2,0xf8,0x0,0x1c,0x71,
+0xc7,0x9e,0xf1,0xc7,0x80,0x0,0x8c,0x30,
+0x79,0xc7,0x1e,0x89,0x2f,0xbe,0x70,0x0,
+0xf,0x4,0xc0,0x0,0x79,0xcb,0x10,0x0,
+0x8,0xa2,0x70,0x0,0x0,0x29,0xe7,0x80,
+0x10,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,
+0x0,0x0,0x0,0x0,0x0,0x1,0x80,0x0,
+0x3,0x6,0x0,0xf8,0xc,0x8,0x70,0x0,
+0x1c,0xc0,0x80,0x0,0x0,0x0,0x0,0x33,
+0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,
+};
+
+static WORD sixhi_ch_ofst[257] = {
+0,6,12,18,24,30,36,42,
+48,54,60,66,72,78,84,90,
+96,102,108,114,120,126,132,138,
+144,150,156,162,168,174,180,186,
+192,198,204,210,216,222,228,234,
+240,246,252,258,264,270,276,282,
+288,294,300,306,312,318,324,330,
+336,342,348,354,360,366,372,378,
+384,390,396,402,408,414,420,426,
+432,438,444,450,456,462,468,474,
+480,486,492,498,504,510,516,522,
+528,534,540,546,552,558,564,570,
+576,582,588,594,600,606,612,618,
+624,630,636,642,648,654,660,666,
+672,678,684,690,696,702,708,714,
+720,726,732,738,744,750,756,762,
+768,774,780,786,792,798,804,810,
+816,822,828,834,840,846,852,858,
+864,870,876,882,888,894,900,906,
+912,918,924,930,936,942,948,954,
+960,966,972,978,984,990,996,1002,
+1008,1014,1020,1026,1032,1038,1044,1050,
+1056,1062,1068,1074,1080,1086,1092,1098,
+1104,1110,1116,1122,1128,1134,1140,1146,
+1152,1158,1164,1170,1176,1182,1188,1194,
+1200,1206,1212,1218,1224,1230,1236,1242,
+1248,1254,1260,1266,1272,1278,1284,1290,
+1296,1302,1308,1314,1320,1326,1332,1338,
+1344,1350,1356,1362,1368,1374,1380,1386,
+1392,1398,1404,1410,1416,1422,1428,1434,
+1440,1446,1452,1458,1464,1470,1476,1482,
+1488,1494,1500,1506,1512,1518,1524,1530,
+1536,};
+
+static struct font_hdr sixhi_font = 
+    {
+    STPROP, 8, "", 0, 255,
+    4, 4, 3, 1, 1,
+    5, 6, 0, 0,
+    1, 1, 0x5555, (short)0xaaaa,
+    0xc, NULL, 
+    sixhi_ch_ofst, sixhi_data,
+    192, 6,
+    NULL,
+    1, 0, /* x/y offset */
+    7,	/* lineHeight */
+    6,	/* psHeight */
+    };
+
+MgFont *mgTinyFont()
+{
+return &sixhi_font;
+}
+
diff --git a/lib/font/mgTimes10.c b/lib/font/mgTimes10.c
new file mode 100644
index 0000000..9c006eb
--- /dev/null
+++ b/lib/font/mgTimes10.c
@@ -0,0 +1,324 @@
+
+/* Times10.c - compiled data for font -Adobe-Times-M-R-N--10-100-75-7 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/timR10.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Times10_data[2678] = {
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x40,0x10,0x20,0x28,0,0x20,0,0,0x80,0x84,
+0x1,0x4,0x80,0,0xa1,0,0x42,0x5,0,0,
+0,0x40,0x10,0x20,0,0x10,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,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,
+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,0x20,0x20,0x50,0x50,
+0x50,0x50,0,0,0x41,0xa,0x28,0x89,0x54,0x1,
+0x40,0x80,0x85,0xa,0x14,0,0,0x20,0x20,0x50,
+0x50,0x20,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x80,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,0x40,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,0xe0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x20,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x2,0,0,0,0,0,0,0x20,
+0x91,0x41,0,0x8,0x24,0x8,0x24,0x4,0x29,0x4,
+0x42,0x80,0,0x10,0x42,0,0x40,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,0x15,0x29,
+0xcf,0xc6,0x11,0x45,0,0,0xb,0x8,0xc6,0x9,
+0xc6,0xf3,0x18,0,0,0x7,0x1e,0x4,0x3c,0x7d,
+0xf3,0xef,0x9f,0x77,0x73,0xf6,0xe3,0x8e,0xee,0x79,
+0xe3,0xcf,0xe,0xfb,0xbb,0xbb,0x77,0xee,0xee,0xfb,
+0x4c,0x40,0x20,0x80,0x18,0xc,0x10,0x4a,0x18,0,
+0,0,0,0,0,0,0,0,0x15,0,
+0,0,0,0,0,0,0,0,0,0,
+0xd1,0x8d,0x25,0xe,0x30,0,0,0x71,0xcc,0x43,
+0xe8,0xf,0x80,0x90,0x8,0x88,0x9c,0x80,0x20,0x20,
+0x20,0x20,0x20,0x20,0x3e,0x7d,0xf7,0xdf,0x7d,0xdd,
+0xdd,0xf3,0xb9,0xe3,0xc7,0x8f,0x1e,0,0x7d,0xdd,
+0xdd,0xdd,0xdd,0xdd,0xc1,0x11,0x2a,0xaa,0x80,0x4,
+0x4a,0xa4,0x4a,0xa7,0x50,0x88,0xa5,0x28,0,0x8,
+0x85,0x28,0x90,0xa0,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,0x15,0x2a,0x54,0x8a,0x12,0x22,
+0,0,0xc,0x99,0x29,0x19,0x8,0x94,0xa4,0,
+0,0x5,0x21,0xe,0x12,0xc4,0x99,0x24,0xb1,0x22,
+0x21,0x24,0x41,0x8c,0x64,0xcc,0x96,0x64,0x92,0xa9,
+0x11,0x12,0x22,0x44,0x44,0x8a,0x44,0xa0,0,0x80,
+0x8,0x10,0x10,0x2,0x8,0,0,0,0,0x8,
+0,0,0,0,0x24,0x80,0,0,0,0,
+0,0,0,0,0,0x9,0x4e,0x54,0x80,0x11,
+0x8,0,0,0x88,0x12,0x45,0x50,0x1d,0x1,0xa8,
+0x19,0x19,0x9,0,0x70,0x70,0x70,0x70,0x70,0x70,
+0x72,0xc4,0x92,0x49,0x24,0x88,0x88,0x99,0x93,0x36,
+0x6c,0xd9,0xb3,0,0xcc,0x88,0x88,0x88,0x88,0x88,
+0x82,0x80,0,0x1,0,0,0,0,0,0xa,
+0,0,0,0,0,0x40,0,0,0x10,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,
+0x10,0x7e,0x15,0xd,0xc2,0x25,0x8,0,0x14,0x88,
+0x21,0x2b,0x9c,0x24,0xa4,0x90,0x80,0x81,0x4e,0x8a,
+0x12,0x80,0x89,0x4,0x20,0x22,0x21,0x28,0x41,0x8c,
+0x54,0x84,0x94,0x24,0x98,0x21,0x11,0xb3,0x26,0x28,
+0x28,0x12,0x24,0xa0,0xc,0xe3,0x39,0xb9,0xdc,0xda,
+0x49,0xd9,0xc6,0x71,0xd5,0xdd,0x2d,0xed,0xef,0x7f,
+0x24,0x80,0,0,0,0,0,0,0,0,
+0x1,0x39,0xa,0xdd,0x40,0x26,0xa9,0x40,0x1,0x74,
+0x13,0xf2,0x22,0x5d,0,0x92,0x89,0x9,0x5,0x8,
+0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x80,0x82,0x8,
+0x20,0x88,0x88,0x89,0x52,0x14,0x28,0x50,0xa1,0x44,
+0x94,0x88,0x88,0x88,0x88,0x50,0xe2,0xb3,0x33,0x33,
+0x36,0x66,0x66,0x6c,0xcc,0xc7,0x71,0x8c,0x63,0x18,
+0x43,0xa5,0x29,0x4a,0xfc,0xb8,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,0x10,0x29,0x8a,0xce,
+0x84,0x10,0x8,0,0x14,0x88,0x46,0x48,0x52,0x23,
+0x24,0x1,0x3e,0x42,0x52,0x8a,0x1c,0x80,0x89,0xc7,
+0x27,0x3e,0x21,0x30,0x41,0x54,0x54,0x84,0xe4,0x27,
+0xc,0x21,0x10,0xa1,0x54,0x10,0x28,0x22,0x24,0,
+0x2,0x94,0x4a,0x92,0x92,0x4a,0x89,0x25,0x29,0x4a,
+0x4d,0x9,0x29,0x49,0x29,0x22,0x24,0x8c,0x80,0,
+0,0,0,0,0,0,0,0x4b,0x8a,0x21,
+0x20,0x28,0x82,0x8f,0x81,0x64,0xc,0x47,0xc2,0x5d,
+0x1,0xc1,0x5e,0x9e,0xda,0x80,0x50,0x50,0x50,0x50,
+0x50,0x50,0x5c,0x80,0xe3,0x8e,0x38,0x88,0x89,0xc9,
+0x52,0x14,0x28,0x50,0xa1,0x28,0xa4,0x88,0x88,0x88,
+0x88,0x50,0x93,0x8,0x88,0x88,0x8a,0x8a,0xaa,0xa4,
+0x44,0x49,0x4a,0x52,0x94,0xa4,0x4,0xa5,0x29,0x4a,
+0x52,0x90,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,0x10,0x7c,0x45,0x53,0x4,0x10,0x3e,0x1c,
+0x14,0x88,0x41,0x7c,0x52,0x44,0x9c,0x2,0,0x22,
+0x52,0x9f,0x12,0x80,0x89,0x4,0x21,0x22,0x21,0x28,
+0x41,0x54,0x4c,0x84,0x84,0x25,0x2,0x21,0x10,0xa1,
+0x54,0x28,0x10,0x42,0x24,0,0x6,0x94,0x4b,0x12,
+0x92,0x4b,0x89,0x25,0x29,0x4a,0x48,0xc9,0x25,0x2a,
+0x11,0x44,0x44,0x53,0,0,0,0,0,0,
+0,0,0x1,0x41,0xe,0xfc,0xa0,0x26,0xba,0x80,
+0xb9,0x54,0,0x40,0x2,0x4d,0x40,0x39,0x45,0x85,
+0x45,0x88,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf0,0x80,
+0x82,0x8,0x20,0x88,0x88,0x89,0x32,0x14,0x28,0x50,
+0xa1,0x10,0xa4,0x88,0x88,0x88,0x88,0x20,0xe2,0x99,
+0x99,0x99,0x9c,0x8c,0xcc,0xc4,0x44,0x49,0x4a,0x52,
+0x94,0xa5,0xf4,0xa5,0x29,0x4a,0x92,0xa0,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,0x2a,
+0x45,0x51,0xa4,0x10,0x8,0,0x24,0x88,0x81,0xa,
+0x52,0x44,0x88,0x1,0x3e,0x40,0x56,0x91,0x12,0xc4,
+0x99,0x24,0x31,0x22,0x25,0x24,0x49,0x24,0x4c,0xcc,
+0x86,0x64,0x92,0x21,0xb0,0x40,0x88,0x44,0x10,0x8a,
+0x14,0,0xa,0x94,0x4a,0x11,0x12,0x4a,0x49,0x25,
+0x29,0x4a,0x48,0x49,0x26,0x36,0x28,0xc9,0x24,0x80,
+0,0,0,0,0,0,0,0,0x1,0x4b,
+0x31,0x24,0x40,0x11,0x1,0x40,0x80,0x88,0,0,
+0x2,0x45,0,0x2,0x87,0xc4,0x87,0xc8,0x88,0x88,
+0x88,0x88,0x88,0x88,0x92,0xc4,0x92,0x49,0x24,0x88,
+0x88,0x99,0x33,0x36,0x6c,0xd9,0xb3,0x28,0xcc,0xd8,
+0xd8,0xd8,0xd8,0x20,0x82,0xaa,0xaa,0xaa,0xa8,0x88,
+0x88,0x84,0x44,0x49,0x4a,0x52,0x94,0xa4,0x4,0xa5,
+0x29,0x49,0x92,0x60,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,0x10,0x2b,0x88,0x8e,0xc2,0x20,
+0x8,0x40,0xa3,0x1d,0xee,0xb,0x8c,0x43,0x30,0x90,
+0x80,0x82,0x49,0x3b,0xbc,0x79,0xf3,0xee,0x1e,0x77,
+0x76,0x76,0xfb,0xae,0xe4,0x79,0xc3,0x8e,0xdc,0x70,
+0xe0,0x40,0x88,0xee,0x38,0xfa,0x14,0,0xe,0xe3,
+0x35,0xb9,0x9b,0x4a,0x7d,0xb7,0xb6,0x71,0xdd,0xc6,
+0xd2,0x14,0x6c,0x8f,0x24,0x80,0,0,0,0,
+0,0,0,0,0x1,0x73,0xc0,0x75,0x20,0xe,
+0,0,0,0x70,0x1,0xf0,0x3,0xa5,0,0,
+0x8,0x89,0xc8,0x91,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,
+0xde,0x79,0xf7,0xdf,0x7d,0xdd,0xdd,0xf3,0x91,0xe3,
+0xc7,0x8f,0x1e,0x44,0xf8,0x70,0x70,0x70,0x70,0x71,
+0xc7,0x3b,0xbb,0xbb,0xb6,0x66,0x66,0x6e,0xee,0xe6,
+0x6d,0x8c,0x63,0x18,0x47,0x1a,0xd6,0xb5,0x1c,0x40,
+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,0x80,0,0x2,0x20,0,0x40,0,0,
+0,0,0,0,0,0x10,0,0,0x20,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xc0,0,0,0,0,0,0,
+0,0x2,0x4,0,0,0,0,0x2,0x40,0x8,
+0,0,0,0x40,0x40,0,0,0,0x1,0,
+0x24,0x80,0,0,0,0,0,0,0,0,
+0x1,0x40,0,0x1,0xc0,0,0,0,0,0,
+0,0,0x2,0x5,0x8,0,0,0,0,0x14,
+0,0,0,0,0,0,0,0x20,0,0,
+0,0,0,0,0,0,0,0,0,0x1,
+0,0,0,0,0,0,0,0,0,0,
+0,0x40,0,0,0,0,0,0,0,0,
+0x8,0,0,0x3,0x10,0xc0,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,0,0,
+0x1,0x40,0,0x40,0,0,0,0,0,0,
+0,0x10,0,0,0x1f,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x60,
+0,0,0,0,0,0,0,0x3,0xc,0,
+0,0,0,0x3,0x80,0x10,0,0,0,0x60,
+0xe0,0,0,0,0x1,0,0x15,0,0,0,
+0,0,0,0,0,0,0x1,0,0,0,
+0,0,0,0,0,0,0,0,0x2,0x5,
+0x4,0,0,0,0,0x1c,0,0,0,0,
+0,0,0,0x10,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x20,0,0,
+0,0,0,0,0,0,0,0,0,0x2,
+0x18,0x80,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,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,0xf,0x80,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,0x18,0,0,0,
+0,0,0,0,0,0,0,0,0,0x60,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xc0,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,0,0,0,0,
+0,0,0,0,0,0,0,0,
+};
+
+static WORD Times10_ch_ofst[225] = {
+0,2,5,9,14,19,27,35,37,41,
+45,50,56,59,63,66,69,74,79,84,
+89,94,99,104,109,114,119,122,125,130,
+136,141,145,154,162,168,175,182,188,194,
+201,209,213,217,224,230,240,248,255,261,
+268,275,280,286,294,302,312,320,328,334,
+337,340,343,348,353,356,360,365,369,374,
+378,382,387,392,395,398,403,407,415,420,
+425,430,435,439,443,447,452,457,465,471,
+476,481,485,487,491,498,500,502,504,506,
+508,510,512,514,516,518,520,522,524,526,
+528,530,532,534,536,538,540,542,544,546,
+548,550,552,554,556,558,560,562,564,566,
+569,574,579,584,589,591,596,601,610,614,
+619,626,630,639,643,647,653,656,659,662,
+667,673,675,679,682,686,691,699,707,715,
+719,727,735,743,751,759,767,776,783,789,
+795,801,807,811,815,819,823,830,838,845,
+852,859,866,873,879,887,895,903,911,919,
+927,933,938,942,946,950,954,958,962,968,
+972,976,980,984,988,992,996,1000,1004,1009,
+1014,1019,1024,1029,1034,1039,1045,1050,1055,1060,
+1065,1070,1075,1080,1085,
+};
+
+static struct font_hdr Times10_font = {
+STPROP, 10, "-Adobe-Times-M-R-N--10-100-75-7", 32, 255,
+13, 10, 6, 3, 3,
+11, 10, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Times10_ch_ofst, Times10_data,
+206, 13,
+NULL,
+0, 0,   /* x/y offset */
+13,        /* lineHeight */
+9,	/* psHeight */
+};
+
+MgFont *mgTimes10Font()
+{
+return &Times10_font;
+}
diff --git a/lib/font/mgTimes12.c b/lib/font/mgTimes12.c
new file mode 100644
index 0000000..4e62260
--- /dev/null
+++ b/lib/font/mgTimes12.c
@@ -0,0 +1,424 @@
+
+/* Times12.c - compiled data for font -Adobe-Times-M-R-N--12-120-75-7 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/timR12.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Times12_data[3675] = {
+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,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,
+0x40,0x8,0x8,0x5,0,0x1,0,0,0,0x40,
+0x10,0x20,0x1,0x4,0x80,0,0xa,0x10,0x1,0x2,
+0x1,0x40,0,0,0,0x40,0x10,0x40,0,0x10,
+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,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,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,0x20,0x10,0x14,0xa,0x5,
+0x2,0x80,0,0,0x20,0x20,0x50,0x50,0x89,0x54,
+0,0x14,0x8,0x2,0x5,0x2,0x81,0x20,0,0,
+0x20,0x20,0xa0,0x90,0x20,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,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,0x10,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,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,0x1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x4,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,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,0x9,0x40,0x38,0x63,0xc,
+0x10,0xa0,0x40,0,0,0xb8,0x43,0x8e,0x8,0x70,
+0xdf,0x38,0xe0,0,0,0,0x60,0x3c,0x8,0x7e,
+0x1d,0x3f,0x3f,0xbf,0x9d,0x39,0xdc,0x7e,0xe7,0xc,
+0x7,0x87,0x3c,0x7e,0x3c,0x7e,0x3a,0xfe,0xe7,0xe3,
+0xf7,0x3b,0x9f,0x8f,0xfc,0xf3,0x88,0x1,0,0xc0,
+0x1,0x80,0x20,0x30,0x4b,0xc,0,0,0,0,
+0,0,0,0,0,0,0,0xcb,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x6,0,0x89,0x1c,0x3,0x86,0,
+0,0,0xe0,0xc,0,0xdc,0x40,0x3e,0x1,0x8,
+0x1,0x8,0x84,0xe2,0,0x20,0x10,0x8,0x4,0x2,
+0x1,0x3,0xfc,0x75,0xfd,0xfd,0xfd,0xfd,0xdd,0xdd,
+0xf8,0xc3,0x9e,0xf,0x7,0x83,0xc1,0xe0,0x1,0xeb,
+0x9f,0x9f,0x9f,0x9f,0x8f,0xc0,0xc2,0x2,0x10,0xa0,
+0x4,0,0,0x81,0x4,0x2,0x24,0x8,0x28,0x81,
+0x4,0x28,0,0,0x10,0x21,0,0x5,0x80,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,0,0,0,0,0,0,0,0,0,
+0x9,0x4a,0x54,0x9e,0x12,0x11,0x11,0x50,0,0,
+0xec,0xc4,0x51,0x18,0x83,0x11,0x45,0x30,0,0,
+0,0x90,0xc2,0x8,0x23,0x33,0x11,0x90,0x90,0xb3,
+0x10,0x88,0x24,0x42,0x6,0xc,0xc2,0x66,0x23,0x66,
+0x23,0x46,0x92,0x42,0x41,0x22,0x11,0x9,0x5,0xc,
+0x90,0x94,0,0x80,0x40,0,0x80,0x40,0x10,0x1,
+0x4,0,0,0,0,0,0,0,0,0,
+0,0x1,0x8,0x80,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x9,0x21,
+0x89,0x25,0x4c,0x61,0,0,0x3,0x19,0xf2,0x1,
+0x24,0x80,0x74,0x3,0x14,0x3,0x11,0x88,0x24,0,
+0x20,0x10,0x8,0x4,0x2,0x1,0x1,0x84,0xcc,0x84,
+0x84,0x84,0x84,0x88,0x88,0x8c,0x61,0x33,0x19,0x8c,
+0xc6,0x63,0x30,0x3,0x31,0x9,0x9,0x9,0x9,0x4,
+0x81,0x21,0x4,0x29,0x42,0x8a,0,0,0x42,0xa,
+0x29,0x4b,0x4e,0x50,0x42,0xa,0x51,0x40,0,0x8,
+0x42,0x8a,0x8,0x82,0x40,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,0,0,0,
+0,0,0,0,0,0x9,0x4a,0x50,0x94,0x12,
+0x11,0x10,0xe0,0,0,0xc5,0x40,0x41,0x18,0x82,
+0x2,0x45,0x10,0,0,0,0x11,0x81,0x14,0x21,
+0x21,0x10,0x90,0x10,0x21,0x10,0x88,0x24,0x82,0x6,
+0xc,0xc2,0x42,0x21,0x42,0x21,0x42,0x10,0x42,0x22,
+0x33,0x10,0x90,0x88,0x18,0x90,0x94,0,0,0x40,
+0,0x80,0x40,0x10,0x1,0x4,0,0,0,0,
+0,0x10,0,0,0,0,0x1,0x8,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x28,0x1e,0x51,0x30,0xb,0xa7,0,
+0,0x2,0xe8,0x12,0x10,0x48,0,0x74,0x1,0x14,
+0x1,0x10,0x88,0x44,0,0x50,0x28,0x14,0xa,0x5,
+0x2,0x82,0x80,0x84,0x80,0x80,0x80,0x80,0x88,0x88,
+0x84,0x61,0x21,0x10,0x88,0x44,0x22,0x10,0x2,0x31,
+0x9,0x9,0x9,0x8,0x88,0xf9,0x20,0,0,0,
+0x4,0,0,0,0,0,0,0x14,0,0,
+0,0,0,0,0,0,0,0,0x80,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,0,0,0,0,0,0,0,0,0,
+0x8,0x1f,0x30,0x68,0xd,0xc2,0x9,0x50,0x80,0x1,
+0x44,0x40,0x42,0x28,0xe7,0x82,0x65,0x12,0x41,0x80,
+0x30,0x21,0x35,0x14,0x23,0x40,0x10,0x51,0x11,0x40,
+0x10,0x88,0x25,0x2,0x5,0x14,0xa2,0x81,0x23,0x81,
+0x23,0x30,0x10,0x42,0x22,0x11,0x20,0xe0,0x48,0x30,
+0x88,0xa2,0,0xc,0x70,0xc3,0x8c,0xe3,0xdc,0xd9,
+0x25,0x6c,0xb0,0xcf,0xe,0xb3,0xbf,0x6c,0xfb,0x6d,
+0xe6,0xf1,0x8,0x80,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x21,0xc8,0x12,
+0x50,0x18,0x14,0x95,0,0,0x4,0x94,0xc,0x10,
+0x84,0x1b,0x74,0x1,0x8,0x1,0x20,0x90,0x28,0x10,
+0x50,0x28,0x14,0xa,0x5,0x2,0x82,0x89,0,0x88,
+0x88,0x88,0x88,0x88,0x88,0x82,0x51,0x40,0xa0,0x50,
+0x28,0x14,0x9,0x14,0x49,0x9,0x9,0x9,0x8,0x48,
+0x8d,0x43,0xc,0x30,0xc3,0xc,0x36,0x18,0xc3,0xc,
+0x33,0x6d,0x8e,0xb0,0xc3,0xc,0x30,0xc1,0x6,0xed,
+0xb6,0xdb,0x66,0xe6,0x60,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,0,0,0,
+0,0,0,0,0,0x8,0xa,0x18,0x10,0x3c,
+0x82,0x8,0x40,0x80,0x1,0x44,0x40,0x8e,0x28,0x34,
+0xc4,0x39,0x90,0x6,0x1f,0xc,0x42,0x49,0x22,0x3e,
+0x40,0x10,0x5f,0x1f,0x43,0x9f,0x88,0x27,0x2,0x5,
+0x14,0x92,0x81,0x3e,0x81,0x3e,0x1c,0x10,0x42,0x14,
+0x1b,0xa0,0x60,0x70,0x60,0x88,0xa2,0,0x12,0x49,
+0x24,0x92,0x44,0x92,0x49,0x44,0x92,0x49,0x24,0x92,
+0x64,0x91,0x24,0x92,0x45,0x24,0x91,0x8,0x86,0x40,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x2,0x7e,0x12,0xf8,0x2c,0x14,0x10,0xa,
+0x7e,0x4,0xe4,0,0x7d,0xf8,0x9,0x74,0x3,0x81,
+0x43,0xa5,0xd6,0xc9,0,0x88,0x44,0x22,0x11,0x8,
+0x84,0x44,0xf9,0,0xf8,0xf8,0xf8,0xf8,0x88,0x89,
+0xc2,0x49,0x40,0xa0,0x50,0x28,0x14,0x8,0xa4,0x49,
+0x9,0x9,0x9,0x8,0x70,0x85,0xc4,0x92,0x49,0x24,
+0x92,0x49,0x25,0x24,0x92,0x49,0x24,0x92,0x49,0x24,
+0x92,0x49,0x20,0x9,0x24,0x92,0x49,0x24,0x92,0x40,
+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,0,0,0,0,0,0,0,0,
+0x8,0xa,0x14,0x36,0x67,0x2,0x8,0x3,0xe1,0xe1,
+0x44,0x41,0x1,0x48,0x14,0x44,0x4c,0xf0,0x18,0,
+0x3,0x42,0x89,0x3e,0x21,0x40,0x10,0x51,0x11,0x41,
+0x10,0x88,0x25,0x82,0x4,0xa4,0x92,0x81,0x20,0x81,
+0x24,0x6,0x10,0x42,0x14,0xa,0xa0,0xb0,0x20,0xc0,
+0x88,0x80,0,0xe,0x49,0x4,0x9e,0x44,0x92,0x49,
+0x84,0x92,0x49,0x24,0x92,0x46,0x11,0x25,0x9a,0xc2,
+0x2c,0x22,0x8,0x49,0x80,0,0,0,0,0,
+0,0,0,0,0,0,0,0x22,0x88,0x12,
+0x21,0x24,0x14,0x97,0x14,0x2,0xf4,0xa4,0,0x10,
+0,0x9,0x34,0x40,0x1c,0xa0,0x4c,0x29,0x13,0x10,
+0xf8,0x7c,0x3e,0x1f,0xf,0x87,0xc7,0x89,0,0x88,
+0x88,0x88,0x88,0x88,0x88,0x82,0x49,0x40,0xa0,0x50,
+0x28,0x14,0x8,0x44,0x89,0x9,0x9,0x9,0x8,0x20,
+0x8d,0x23,0x8e,0x38,0xe3,0x8e,0x3f,0x21,0xe7,0x9e,
+0x79,0x24,0x92,0x49,0x24,0x92,0x49,0x27,0xc9,0x24,
+0x92,0x49,0x2c,0x92,0xc0,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,0,0,0,
+0,0,0,0,0,0x8,0x1f,0x14,0x29,0x42,
+0x2,0x8,0,0x80,0x2,0x44,0x42,0x1,0x7c,0x14,
+0x48,0x44,0x20,0x6,0x1f,0xc,0x42,0x92,0x22,0x21,
+0x21,0x10,0x90,0x10,0x21,0x10,0x88,0x24,0xc2,0x4,
+0xa4,0x8a,0x42,0x20,0x42,0x22,0x42,0x10,0x42,0x1c,
+0xc,0xc0,0x90,0x21,0x80,0x84,0x80,0,0x12,0x49,
+0x4,0x90,0x47,0x12,0x49,0x44,0x92,0x49,0x24,0x92,
+0x41,0x91,0x25,0xa,0x82,0x28,0x41,0x8,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x22,0x88,0x1e,0xf9,0x24,0xb,0xa0,0x28,
+0x2,0x6,0xa8,0,0x10,0,0x9,0x14,0,0,
+0x50,0x54,0x22,0x15,0x10,0x88,0x44,0x22,0x11,0x8,
+0x84,0x44,0x80,0x84,0x80,0x80,0x80,0x80,0x88,0x88,
+0x84,0x45,0x21,0x10,0x88,0x44,0x22,0x10,0xa3,0x11,
+0x9,0x9,0x9,0x8,0x20,0xf9,0x14,0x92,0x49,0x24,
+0x92,0x48,0x21,0x4,0x10,0x41,0x24,0x92,0x49,0x24,
+0x92,0x49,0x20,0x9,0x24,0x92,0x49,0x28,0x92,0x80,
+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,0,0,0,0,0,0,0,0,
+0,0xa,0x54,0x49,0x67,0x42,0x8,0,0x80,0x2,
+0x6c,0x44,0x51,0x9,0x36,0x48,0x44,0x60,0x1,0x80,
+0x30,0x2,0x92,0x41,0x23,0x33,0x11,0x90,0x90,0x33,
+0x10,0x88,0xa4,0x62,0x24,0x44,0x86,0x66,0x20,0x66,
+0x21,0x66,0x10,0x66,0x8,0x4,0x41,0x8,0x21,0x4,
+0x84,0x80,0,0x12,0x49,0x24,0x99,0x42,0x12,0x49,
+0x24,0x92,0x49,0x24,0x92,0x44,0x91,0x23,0xd,0x5,
+0x18,0x91,0x8,0x80,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x23,0x3d,0x21,
+0x21,0x34,0xc,0x60,0x14,0x2,0x3,0x18,0,0,
+0,0x9,0x14,0,0,0xa0,0x9e,0x44,0x27,0x91,
+0x4,0x82,0x41,0x20,0x90,0x48,0x28,0x84,0xcc,0x84,
+0x84,0x84,0x84,0x88,0x88,0x8c,0x43,0x33,0x19,0x8c,
+0xc6,0x63,0x31,0x13,0x31,0x99,0x99,0x99,0x98,0x20,
+0x81,0x14,0x92,0x49,0x24,0x92,0x4c,0xa5,0x96,0x59,
+0x65,0x24,0x92,0x49,0x24,0x92,0x49,0x21,0x9,0x24,
+0x92,0x49,0x18,0x91,0x80,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,0,0,0,
+0,0,0,0,0,0x8,0xa,0x38,0x46,0x3d,
+0x82,0x8,0,0x4,0xa,0x38,0xe7,0xce,0x8,0xe3,
+0x88,0x39,0x82,0x40,0,0,0x42,0x6c,0xe3,0xfe,
+0x1e,0x3f,0x3f,0xbc,0x1e,0x39,0xdc,0xce,0x77,0xee,
+0x4f,0xc2,0x3c,0x70,0x3c,0x71,0xdc,0x38,0x3c,0x8,
+0x4,0x43,0x9c,0x71,0xfc,0x84,0x80,0,0xd,0x70,
+0xc3,0x4e,0x43,0xbb,0xe9,0x3f,0xdb,0xec,0xc7,0xe,
+0xe7,0xc,0xd2,0x9,0xd,0x90,0xf1,0x8,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x21,0xdb,0,0x71,0x18,0x3,0x80,0xa,
+0,0x1,0xe0,0,0x7c,0,0xe,0x94,0,0x1,
+0x40,0x84,0x4f,0x21,0x23,0x8f,0xc7,0xe3,0xf1,0xf8,
+0xfc,0x7c,0xfc,0x79,0xfd,0xfd,0xfd,0xfd,0xdd,0xdd,
+0xf8,0xe1,0x1e,0xf,0x7,0x83,0xc1,0xe0,0x5,0xe0,
+0xf0,0xf0,0xf0,0xf0,0x71,0xc3,0x63,0x4d,0x34,0xd3,
+0x4d,0x37,0x18,0xe3,0x8e,0x3b,0xff,0xcc,0xec,0xc3,
+0xc,0x30,0xc0,0xe,0x1a,0x69,0xa6,0x90,0xe1,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,0,0,0,0,0,0,0,0,0,
+0,0,0x10,0,0,0x1,0x10,0,0x4,0,
+0,0,0,0,0,0,0,0,0x40,0,
+0,0x1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xc,
+0,0,0,0,0,0,0,0,0,0,
+0x80,0x80,0,0,0,0,0,0x4,0x40,0x8,
+0,0,0,0x4,0x2,0,0,0,0,0,
+0x10,0x1,0,0x80,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x22,0,0,
+0,0xc,0,0,0,0,0,0,0,0,
+0,0x8,0x14,0x8,0,0,0,0,0,0x40,
+0,0,0,0,0,0,0,0,0x20,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,0x10,0,0,
+0,0,0,0,0,0,0,0,0x10,0,
+0,0,0x10,0x81,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,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x1,0x10,0,0x8,0,0,0,0,0,0,
+0,0,0,0x80,0,0,0,0xf8,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x3,0,0,0,0,0,
+0,0,0,0,0,0x80,0x80,0,0,0,
+0,0,0x4,0x40,0x8,0,0,0,0x4,0x2,
+0,0,0,0,0,0x20,0x1,0,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x20,0,0,0,0x24,0,0,0,
+0,0,0,0,0,0,0x8,0x14,0x4,0,
+0,0,0,0,0x48,0,0,0,0,0,
+0,0,0,0x10,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,0x8,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x20,0x82,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,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xa0,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,
+0xe3,0x80,0xfc,0,0,0,0,0x3,0x80,0x10,
+0,0,0,0xe,0x7,0,0,0,0,0,
+0x60,0,0xc3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x20,0,0,
+0,0x38,0,0,0,0,0,0,0,0,
+0,0xc,0x14,0x1c,0,0,0,0,0,0x30,
+0,0,0,0,0,0,0,0,0x70,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,0x38,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x61,0xc6,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,0,0,0,0,
+0,0,0,0,0,
+};
+
+static WORD Times12_ch_ofst[225] = {
+0,3,6,11,17,23,33,43,45,50,
+55,61,68,71,75,78,81,87,93,99,
+105,111,117,123,129,135,141,144,147,154,
+161,168,173,184,193,201,209,218,226,233,
+242,251,255,260,269,276,287,296,305,312,
+321,329,336,343,352,361,373,382,391,399,
+403,406,410,416,422,426,432,438,444,450,
+456,460,466,472,475,478,484,487,496,502,
+508,514,520,524,530,534,540,546,555,561,
+567,573,579,582,588,595,598,601,604,607,
+610,613,616,619,622,625,628,631,634,637,
+640,643,646,649,652,655,658,661,664,667,
+670,673,676,679,682,685,688,691,694,697,
+701,707,713,720,726,729,735,738,748,753,
+760,768,772,783,787,792,799,803,807,811,
+817,824,827,830,834,839,846,855,864,873,
+878,887,896,905,914,923,932,943,951,959,
+967,975,983,987,991,995,999,1008,1017,1026,
+1035,1044,1053,1062,1069,1078,1086,1094,1102,1110,
+1119,1126,1132,1138,1144,1150,1156,1162,1168,1177,
+1182,1188,1194,1200,1206,1209,1212,1215,1218,1224,
+1230,1236,1242,1248,1254,1260,1267,1273,1279,1285,
+1291,1297,1303,1309,1315,
+};
+
+static struct font_hdr Times12_font = {
+STPROP, 12, "-Adobe-Times-M-R-N--12-120-75-7", 32, 255,
+15, 12, 7, 3, 3,
+12, 12, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Times12_ch_ofst, Times12_data,
+245, 15,
+NULL,
+0, 0,   /* x/y offset */
+15,        /* lineHeight */
+11,	/* psHeight */
+};
+
+MgFont *mgTimes12Font()
+{
+return &Times12_font;
+}
diff --git a/lib/font/mgTimes14.c b/lib/font/mgTimes14.c
new file mode 100644
index 0000000..5a0cdf4
--- /dev/null
+++ b/lib/font/mgTimes14.c
@@ -0,0 +1,500 @@
+
+/* Times14.c - compiled data for font -Adobe-Times-M-R-N--14-140-75-7 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/timR14.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Times14_data[4437] = {
+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,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,0x8,0,0x10,0x8,0,0,
+0,0x4,0,0,0,0x4,0,0x40,0x80,0x1,
+0x1,0x20,0,0,0,0x20,0,0x81,0,0,
+0,0,0,0x2,0,0x10,0x8,0,0,0x40,
+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,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,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,0,0,0,0,
+0,0,0,0,0,0xc,0,0x30,0x1c,0x3,
+0x40,0x90,0xa,0,0,0,0x6,0,0xc1,0xc0,
+0x91,0x83,0x72,0x80,0,0xd0,0x30,0x1,0x83,0x80,
+0x68,0x24,0,0,0x3,0,0x30,0x1c,0x9,0,
+0xc0,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,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,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,0,0,0,
+0,0,0,0,0,0,0x2,0,0x40,0x22,
+0x5,0x80,0x90,0x4,0,0,0,0x1,0x1,0x2,
+0x20,0x90,0x44,0x8a,0x80,0x1,0x60,0x8,0x2,0x4,
+0x40,0xb0,0x24,0,0,0,0x80,0x40,0x22,0x9,
+0x1,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,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,0x80,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,0x40,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,0x8,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,0x40,0,0,0,
+0,0,0,0,0x4,0x1,0x8,0,0,0x40,
+0,0,0x40,0x20,0x80,0x10,0x20,0,0,0x80,
+0x41,0,0,0,0,0x20,0x10,0x40,0,0x40,
+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,0,0,0x4,0x50,0x51,0xe3,0x8c,0xc,
+0x8,0x48,0x10,0,0,0x5,0xe0,0x87,0xf,0x2,
+0x1e,0xd,0xf8,0xe3,0xc0,0,0,0,0x7,0x3,
+0xe0,0x8,0x1f,0x83,0xd7,0xf0,0xfe,0x7f,0x1e,0x8e,
+0x73,0x8e,0x3b,0x9c,0xe,0xe,0x71,0xc3,0xc3,0xe0,
+0xf1,0xf8,0x3a,0x7f,0x39,0xdc,0x7e,0x73,0xf9,0xfc,
+0x77,0xf7,0x47,0x4,0,0x60,0xc,0,0x3,0,
+0x30,0x18,0x11,0x60,0xc0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x32,0x60,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xe,0,0xee,0x87,0x28,0x3c,
+0x38,0,0,0x1,0xe0,0x6,0,0x33,0x18,0x1,
+0xf0,0x2,0x30,0x2,0x8,0x82,0x30,0x80,0x2,0,
+0x40,0x8,0x1,0,0x20,0x4,0x1,0xfe,0x1e,0x9f,
+0xcf,0xe7,0xf3,0xf9,0xce,0x73,0xbf,0x87,0x1c,0x3c,
+0xf,0x3,0xc0,0xf0,0x3c,0,0xf,0x8e,0x73,0x9c,
+0xe7,0x39,0xdc,0x77,0x3,0x86,0x3,0x1c,0x34,0x50,
+0xa0,0,0,0x60,0x61,0xc2,0x99,0x75,0x6c,0x68,
+0xc0,0xc3,0x86,0x8a,0,0,0x30,0x30,0xe1,0x40,
+0xd8,0xa,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,0,0x4,0x50,0x52,0xa6,0xf8,
+0x12,0x8,0x48,0x54,0,0,0x7,0x33,0x8d,0x99,
+0x86,0x1c,0x19,0x9,0xb6,0x60,0,0,0,0x8,
+0x8c,0x18,0x8,0x8,0xc6,0x31,0x18,0x42,0x21,0x31,
+0x84,0x21,0x4,0x11,0x8,0x6,0xc,0x30,0x86,0x61,
+0x31,0x98,0x4c,0x66,0x49,0x10,0x88,0x24,0x21,0x10,
+0x88,0x24,0x34,0x41,0xa,0,0x10,0x4,0,0x1,
+0,0x50,0x8,0x11,0x20,0x40,0,0,0,0,
+0,0x2,0,0,0,0,0,0,0x42,0x10,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x1a,0,0x44,0x8b,0x28,
+0xc3,0x8,0,0,0x6,0x19,0xe9,0,0x4c,0xa0,
+0x3,0xa0,0x6,0x48,0x6,0x11,0x84,0x49,0,0x2,
+0,0x40,0x8,0x1,0,0x20,0x4,0,0xc2,0x31,
+0x88,0x44,0x22,0x11,0x8,0x84,0x21,0x8,0xc3,0x8,
+0x66,0x19,0x86,0x61,0x98,0x66,0,0x18,0x84,0x21,
+0x8,0x42,0x10,0x88,0x22,0x6,0xc1,0x4,0x22,0x58,
+0x50,0x40,0,0,0x10,0x82,0x22,0x86,0x8d,0x30,
+0xb0,0x21,0x4,0x4b,0xa,0,0,0x8,0x41,0x11,
+0x41,0x8,0xa,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,0,0x4,0x51,0xfa,0x84,
+0x90,0x12,0x8,0x84,0x38,0,0,0xa,0x10,0x88,
+0x90,0x86,0x20,0x20,0x11,0x14,0x20,0,0,0,
+0x8,0x98,0x8,0x14,0x8,0x4c,0x11,0x8,0x40,0x20,
+0x20,0x84,0x21,0x4,0x12,0x8,0x5,0x14,0x28,0x84,
+0x21,0x11,0x8,0x44,0x42,0x49,0x10,0x8c,0x66,0x23,
+0x19,0x4,0x44,0x64,0x21,0xa,0,0,0x4,0,
+0x1,0,0x40,0x8,0,0x20,0x40,0,0,0,
+0,0,0x2,0,0,0,0,0,0,0x42,
+0x10,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x1,0x10,0x22,0x6c,0x88,
+0,0x9d,0x28,0,0,0x5,0xc8,0x9,0,0x9,
+0,0x7,0xa0,0x2,0x48,0x2,0x10,0x84,0x11,0,
+0x5,0,0xa0,0x14,0x2,0x80,0x50,0xa,0x1,0x40,
+0x20,0x88,0x4,0x2,0x1,0,0x84,0x21,0x8,0x42,
+0x88,0x42,0x10,0x84,0x21,0x8,0x42,0,0x11,0x84,
+0x21,0x8,0x42,0x10,0x84,0x43,0xc4,0x40,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x48,0,0,0,0,0,0,0x1,0,0,
+0,0,0x8,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,0,0,0x4,0,0xa2,
+0x84,0xa0,0x1c,0,0x84,0x38,0x20,0,0xa,0x10,
+0x80,0x81,0xa,0x38,0x40,0x11,0x94,0x24,0x40,0x60,
+0xc,0,0x91,0xa4,0x14,0x8,0xc8,0x11,0x4,0x44,
+0x22,0x40,0x84,0x21,0x4,0x14,0x8,0x5,0x14,0x2c,
+0x88,0x11,0x12,0x4,0x44,0x60,0x8,0x10,0x84,0x42,
+0x22,0x9,0x6,0x40,0x44,0x21,0x11,0,0x1,0xc5,
+0x87,0x8f,0x1c,0xf3,0xcb,0x33,0x26,0x5b,0x73,0x61,
+0xcd,0x87,0xae,0x77,0xe6,0xef,0xdd,0xfb,0xf7,0xfc,
+0x42,0x10,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x1,0x1f,0x10,0x1c,0x28,
+0x8c,0x1,0x24,0xb8,0,0,0x9,0x24,0x6,0x8,
+0x10,0x83,0x37,0xa0,0x2,0x30,0x2,0x20,0x88,0xa,
+0x4,0x5,0,0xa0,0x14,0x2,0x80,0x50,0xa,0x1,
+0x44,0x40,0x88,0x84,0x42,0x21,0x10,0x84,0x21,0x8,
+0x22,0xc8,0x81,0x20,0x48,0x12,0x4,0x81,0x41,0x22,
+0x44,0x21,0x8,0x42,0x10,0x86,0x42,0x64,0x87,0xe,
+0x1c,0x38,0x70,0xe1,0xfc,0x38,0x70,0xe1,0xc3,0x9b,
+0x66,0x3d,0xb0,0xe1,0xc3,0x87,0xe,0x8,0x1e,0xcd,
+0x9b,0x36,0x6e,0xeb,0x3b,0x80,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,0x4,0,
+0xa1,0xc3,0x60,0x9,0xc1,0x2,0x54,0x20,0,0xa,
+0x10,0x81,0x86,0x1a,0x2c,0x78,0x20,0xe6,0x64,0x41,
+0x80,0x3,0x1,0x22,0x44,0x22,0xf,0x88,0x1,0x4,
+0x7c,0x3e,0x40,0x7,0xe1,0x4,0x18,0x8,0x5,0xb4,
+0x24,0x88,0x11,0x32,0x4,0x4c,0x38,0x8,0x10,0x84,
+0x42,0x22,0x6,0x2,0x80,0x84,0x21,0x11,0,0x3,
+0x26,0xcc,0x99,0x22,0x46,0x8d,0x91,0x24,0x4d,0xd9,
+0xb3,0x66,0xcc,0x9a,0x92,0x22,0x44,0x88,0x91,0x22,
+0x88,0x42,0x10,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x1,0x33,0x7c,0x22,
+0x7c,0xe,0x1,0x20,0x80,0x90,0,0x9,0xc4,0,
+0x8,0x24,0x81,0x17,0xa0,0x2,0x1,0x22,0x24,0x8b,
+0x4a,0x44,0x8,0x81,0x10,0x22,0x4,0x40,0x88,0x11,
+0x2,0x7c,0x40,0xf,0x87,0xc3,0xe1,0xf0,0x84,0x21,
+0x3e,0x22,0x48,0x81,0x20,0x48,0x12,0x4,0x81,0x22,
+0x26,0x44,0x21,0x8,0x42,0x10,0x82,0x82,0x27,0xc,
+0x99,0x32,0x64,0xc9,0x93,0x26,0x64,0x99,0x32,0x64,
+0xc9,0x22,0x6c,0xd9,0xb3,0x66,0xcd,0x9b,0x8,0x36,
+0x44,0x89,0x12,0x24,0x4d,0x91,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,0,0x4,
+0,0xa0,0xa0,0x58,0x3c,0x81,0x2,0x10,0x20,0,
+0x12,0x10,0x81,0x1,0x12,0x6,0xcc,0x21,0x33,0xc0,
+0x6,0xf,0xe0,0xc2,0x24,0x44,0x22,0x8,0xc8,0x1,
+0x4,0x44,0x22,0x43,0xc4,0x21,0x4,0x14,0x8,0x4,
+0xa4,0x26,0x88,0x11,0xe2,0x4,0x78,0xc,0x8,0x10,
+0x86,0xc3,0x56,0x6,0x1,0x1,0x84,0x11,0,0,
+0,0x64,0x48,0x11,0x3e,0x44,0x48,0x91,0x38,0x48,
+0x89,0x12,0x24,0x48,0x90,0xc2,0x22,0x44,0x88,0x8e,
+0x22,0x18,0x82,0x8,0xc4,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x24,0x10,
+0x22,0x10,0x13,0x1,0x20,0xb9,0x23,0xf8,0x9,0x44,
+0,0x7f,0x7b,0x1,0x13,0xa4,0x7,0x78,0x97,0x4d,
+0xd4,0xb4,0xc0,0x8,0x81,0x10,0x22,0x4,0x40,0x88,
+0x11,0x2,0x44,0x40,0x8,0x84,0x42,0x21,0x10,0x84,
+0x21,0x8,0x22,0x68,0x81,0x20,0x48,0x12,0x4,0x81,
+0x14,0x24,0x44,0x21,0x8,0x42,0x10,0x81,0x2,0x25,
+0x81,0x83,0x6,0xc,0x18,0x30,0x7c,0x40,0xf1,0xe3,
+0xc7,0x89,0x22,0x44,0x89,0x12,0x24,0x48,0x91,0,
+0x22,0x44,0x89,0x12,0x24,0x48,0x91,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,0,
+0x4,0x3,0xf0,0xa0,0xb4,0x65,0x1,0x2,0x1,0xfc,
+0x3c,0x12,0x10,0x82,0,0xa2,0x2,0x84,0x41,0x10,
+0x40,0xc,0,0,0x62,0x24,0x44,0x3e,0x8,0x48,
+0x1,0x4,0x40,0x20,0x40,0x84,0x21,0x4,0x12,0x8,
+0x4,0xa4,0x22,0x88,0x11,0x2,0x4,0x48,0x2,0x8,
+0x10,0x82,0x81,0x54,0x9,0x1,0x3,0x4,0x11,0,
+0,0x1,0xa4,0x48,0x11,0x20,0x46,0x48,0x91,0x28,
+0x48,0x89,0x12,0x24,0x48,0x90,0x62,0x22,0x28,0x49,
+0x4,0x14,0x31,0x2,0x5,0x38,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1,0x24,
+0x10,0x22,0x7c,0x91,0x1,0x24,0x82,0x40,0xb,0xc9,
+0x24,0,0x8,0,0x1,0x11,0xa4,0,0,0x48,
+0x54,0x10,0x85,0x44,0xf,0x81,0xf0,0x3e,0x7,0xc0,
+0xf8,0x1f,0x3,0xc0,0x40,0x8,0x4,0x2,0x1,0,
+0x84,0x21,0x8,0x22,0x28,0x81,0x20,0x48,0x12,0x4,
+0x81,0x8,0x28,0x44,0x21,0x8,0x42,0x10,0x81,0x2,
+0x64,0xc6,0x8d,0x1a,0x34,0x68,0xd1,0xa0,0x40,0x81,
+0x2,0x4,0x9,0x22,0x44,0x89,0x12,0x24,0x48,0x91,
+0x7f,0x22,0x44,0x89,0x12,0x22,0x88,0x8a,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,
+0,0,0x1,0x40,0xa1,0x24,0x42,0x1,0x2,0,
+0x20,0,0x12,0x10,0x84,0,0xbf,0x2,0x84,0x41,
+0x10,0x80,0x6,0xf,0xe0,0xc0,0x24,0xc8,0x41,0x8,
+0x4c,0x11,0x8,0x40,0x20,0x60,0x84,0x21,0x4,0x11,
+0x8,0x4,0x44,0x22,0x84,0x21,0x1,0x8,0x44,0x42,
+0x8,0x10,0x83,0x81,0x8c,0x11,0x81,0x6,0x4,0x11,
+0,0,0x2,0x24,0x48,0x11,0x20,0x43,0x88,0x91,
+0x24,0x48,0x89,0x12,0x24,0x48,0x90,0x32,0x22,0x28,
+0x77,0xe,0x14,0x60,0x82,0x8,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x1,
+0x28,0x10,0x1c,0x10,0x99,0,0x99,0x2,0x40,0x8,
+0x5,0x28,0,0x8,0,0x1,0x10,0xa0,0,0,
+0x48,0xa4,0x21,0xa,0x44,0x10,0x42,0x8,0x41,0x8,
+0x21,0x4,0x20,0x84,0x42,0x60,0x88,0x4,0x2,0x1,
+0,0x84,0x21,0x8,0x42,0x28,0x42,0x10,0x84,0x21,
+0x8,0x42,0x14,0x18,0x84,0x21,0x8,0x42,0x10,0x81,
+0x3,0xc4,0x48,0x91,0x22,0x44,0x89,0x12,0x20,0x40,
+0x81,0x2,0x4,0x9,0x22,0x44,0x89,0x12,0x24,0x48,
+0x91,0,0x22,0x44,0x89,0x12,0x22,0x88,0x8a,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,0,0x4,0x1,0x42,0xa3,0x24,0x67,0x21,0x2,
+0,0x20,0x80,0xa3,0x30,0x8c,0x59,0x82,0x24,0xcc,
+0x81,0xb3,0x4,0x41,0x80,0x3,0x2,0x33,0x70,0x41,
+0x8,0xc6,0x21,0x18,0x42,0x20,0x31,0x84,0x21,0x14,
+0x10,0x88,0x44,0x44,0x21,0x86,0x61,0x1,0x98,0x46,
+0x66,0x8,0x19,0x81,0x1,0x8c,0x30,0xc1,0xc,0x14,
+0x9,0,0,0x3,0x24,0xcc,0x5b,0x31,0x42,0x8,
+0x91,0x26,0x48,0x89,0x13,0x66,0xcd,0x90,0x92,0x36,
+0x10,0x22,0x11,0x8,0xc4,0x42,0x10,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x1,0x39,0x71,0x22,0x10,0x8e,0,0xc3,0x1,0x20,
+0x8,0x6,0x18,0,0,0,0x1,0xb0,0xa0,0,
+0,0x90,0xbe,0x22,0xb,0xe8,0x10,0x42,0x8,0x41,
+0x8,0x21,0x4,0x20,0x84,0x42,0x31,0x8,0x44,0x22,
+0x11,0x8,0x84,0x21,0x8,0xc2,0x18,0x66,0x19,0x86,
+0x61,0x98,0x66,0x22,0x31,0x86,0x61,0x98,0x66,0x19,
+0x81,0x2,0x5,0x4c,0x99,0x32,0x64,0xc9,0x93,0x32,
+0x62,0xc5,0x8b,0x16,0x29,0x22,0x6c,0x89,0xb3,0x66,
+0xcd,0x9b,0x8,0x36,0x6c,0xd9,0xb3,0x61,0xd,0x84,
+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,0,0x4,0x1,0x43,0xc2,0x18,0x39,0xc0,
+0x84,0,0x20,0x80,0xa1,0xe3,0xef,0xcf,0x2,0x38,
+0x78,0x80,0xe6,0x4,0x40,0x60,0xc,0x2,0x10,0,
+0xe3,0x9f,0x83,0xc7,0xf0,0xfe,0x70,0x1f,0xe,0x73,
+0x98,0x39,0xdf,0xce,0x4e,0x70,0x83,0xc3,0x80,0xf1,
+0xe3,0x5c,0x1c,0xf,0x1,0,0x88,0x79,0xe3,0x8f,
+0xf4,0x9,0,0,0x1,0xd7,0x87,0x8e,0x9e,0xf3,
+0xdd,0xf9,0x73,0xfd,0xdf,0xb9,0xc5,0x86,0xb8,0xe1,
+0x9b,0x10,0x22,0x3b,0x98,0xfc,0x42,0x10,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1,0x1e,0x5e,0,0x38,0x86,0,0x3c,0,
+0x90,0,0x1,0xe0,0,0x7f,0,0x1,0xd8,0xa0,
+0,0x1,0x21,0x4,0x47,0x90,0x50,0x38,0xe7,0x1c,
+0xe3,0x9c,0x73,0x8e,0x71,0xce,0xfe,0x1e,0x1f,0xcf,
+0xe7,0xf3,0xf9,0xce,0x73,0xbf,0x87,0x8,0x3c,0xf,
+0x3,0xc0,0xf0,0x3c,0x41,0x2f,0x3,0xc0,0xf0,0x3c,
+0xf,0x3,0x87,0xd,0x87,0x4e,0x9d,0x3a,0x74,0xe9,
+0xdc,0x3c,0x78,0xf1,0xe3,0xdf,0x77,0x39,0xdc,0xe1,
+0xc3,0x87,0xe,0x8,0x3c,0x36,0x6c,0xd9,0xb3,0xb,
+0xc,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,0,0,0,0,0x80,0,0,
+0,0x84,0,0,0x80,0x40,0,0,0,0,
+0,0,0,0,0,0x40,0,0,0,0xc,
+0x30,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x20,0,0,0,0,0,0,0,0,0,
+0,0x4,0x1,0,0,0,0,0,0,0,
+0x4,0x20,0x1,0,0,0,0,0x4,0,0x80,
+0,0,0,0,0,0x10,0,0x40,0x10,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x1,0x20,0,0,0,0x2,0,0,
+0,0,0,0,0,0,0,0,0x1,0,
+0xa0,0x20,0,0,0,0,0,0x11,0,0,
+0,0,0,0,0,0,0,0,0x8,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x40,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x10,0,0,0,0,0,0,0,
+0,0,0,0,0,0x40,0,0,0,0x2,
+0x8,0x8,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,0,0,0,0,0,0,
+0,0,0x48,0,0x1,0,0x40,0,0,0,
+0,0,0,0,0,0,0x80,0,0,0,
+0x3,0xc0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x18,0,0,0,0,0,0,0,0,
+0,0,0x4,0x1,0,0,0,0,0,0,
+0,0x6,0x60,0x5,0,0,0,0,0x4,0,
+0x80,0,0,0,0,0,0x50,0,0x40,0x10,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x1,0,0,0,0,0x1a,0,
+0,0,0,0,0,0,0,0,0,0x1,
+0,0xa0,0x10,0,0,0,0,0,0x11,0,
+0,0,0,0,0,0,0,0,0,0x4,
+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,0x8,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0xa,0x8,0x28,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,0,0,0,0,0,
+0,0,0,0x48,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,0xc,0,0,0,0,0,0,0,
+0,0,0,0x7,0x7,0,0x7f,0,0,0,
+0,0,0x3,0x80,0x6,0,0,0,0,0xe,
+0x1,0xc0,0,0,0,0,0,0x60,0,0x30,
+0x60,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1,0,0,0,0,0x1c,
+0,0,0,0,0,0,0,0,0,0,
+0x1,0x80,0xa0,0x60,0,0,0,0,0,0xe,
+0,0,0,0,0,0,0,0,0,0,
+0x18,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,0x30,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xc,0x1c,0x30,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,0,
+};
+
+static WORD Times14_ch_ofst[225] = {
+0,3,8,14,21,28,40,51,54,59,
+64,71,79,82,87,90,94,101,108,115,
+122,129,136,143,150,157,164,168,172,180,
+188,196,202,215,226,235,245,255,264,272,
+283,293,298,304,314,323,336,347,357,365,
+375,384,392,401,411,420,433,443,452,460,
+465,469,474,481,488,493,500,507,514,521,
+528,532,539,546,549,553,560,563,574,581,
+588,595,602,607,613,617,624,631,642,649,
+656,662,669,672,679,687,690,693,696,699,
+702,705,708,711,714,717,720,723,726,729,
+732,735,738,741,744,747,750,753,756,759,
+762,765,768,771,774,777,780,783,786,789,
+794,801,809,816,823,826,833,838,850,854,
+861,870,875,887,891,897,905,909,913,918,
+925,932,936,941,945,950,957,967,977,987,
+993,1004,1015,1026,1037,1048,1059,1072,1082,1091,
+1100,1109,1118,1123,1128,1133,1138,1148,1159,1169,
+1179,1189,1199,1209,1217,1227,1237,1247,1257,1267,
+1276,1284,1291,1298,1305,1312,1319,1326,1333,1344,
+1351,1358,1365,1372,1379,1382,1385,1389,1392,1399,
+1406,1413,1420,1427,1434,1441,1449,1456,1463,1470,
+1477,1484,1491,1498,1505,
+};
+
+static struct font_hdr Times14_font = {
+STPROP, 14, "-Adobe-Times-M-R-N--14-140-75-7", 32, 255,
+17, 14, 8, 3, 3,
+14, 13, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Times14_ch_ofst, Times14_data,
+261, 17,
+NULL,
+0, 0,   /* x/y offset */
+19,        /* lineHeight */
+13,	/* psHeight */
+};
+
+MgFont *mgTimes14Font()
+{
+return &Times14_font;
+}
diff --git a/lib/font/mgTimes18.c b/lib/font/mgTimes18.c
new file mode 100644
index 0000000..f99c369
--- /dev/null
+++ b/lib/font/mgTimes18.c
@@ -0,0 +1,764 @@
+
+/* Times18.c - compiled data for font -Adobe-Times-M-R-N--18-180-75-7 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/timR18.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Times18_data[7077] = {
+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,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3,
+0,0,0x60,0x2,0,0,0,0,0,0x18,
+0,0,0,0,0x18,0,0x60,0x10,0,0x6,
+0x6,0x10,0,0,0,0,0x30,0,0x6,0,
+0x40,0,0,0,0,0,0,0,0xc0,0,
+0x60,0x8,0,0,0x1,0x80,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,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,
+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,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,0,0,0x1,0x80,0,0xc0,
+0x7,0,0xe,0x80,0x36,0,0x24,0,0,0,
+0,0xc,0,0xc0,0x38,0xc,0xc3,0xc,0x3b,0x30,
+0,0x3,0xa0,0x18,0,0xc,0,0xe0,0x7,0x40,
+0x33,0,0,0,0,0x60,0,0xc0,0x1c,0x1,
+0x98,0x3,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,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,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,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,
+0,0,0,0,0x40,0x1,0,0x8,0x80,0x17,
+0,0x36,0,0x24,0,0,0,0,0x2,0x1,
+0,0x44,0xc,0xc0,0x90,0x47,0x30,0,0x5,0xc0,
+0x4,0,0x10,0x1,0x10,0xb,0x80,0x33,0,0,
+0,0,0x10,0x1,0,0x22,0x1,0x98,0x4,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,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,0x2,0,0,0,0,0,
+0,0x2,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,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,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x18,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,0x60,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,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,0x6,0x66,
+0x1b,0xf,0x83,0x83,0x3,0x80,0x60,0xcc,0x2,0,
+0,0,0x1,0x3c,0x6,0x7,0x87,0xc0,0x61,0xf8,
+0x1c,0xfe,0x3c,0x1e,0,0,0,0,0,0xf,
+0,0xfc,0,0x20,0x1f,0xe0,0x1e,0x5f,0xe0,0xff,
+0x9f,0xf0,0x3c,0x8f,0x1e,0x78,0xf3,0xcf,0x1e,0x3,
+0x80,0x73,0x83,0x81,0xe0,0x7f,0x81,0xe0,0x7f,0x81,
+0xd1,0xff,0x9e,0x1d,0xf0,0xff,0x9e,0x3f,0xc1,0xfc,
+0x3c,0xff,0x8f,0x87,0x81,0,0x6,0,0x70,0,
+0x3,0x80,0x3,0x80,0x70,0xc,0x67,0x3,0x80,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1,0xc9,0xc0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x1e,0,0x7,
+0xb9,0xf,0,0x7,0xc0,0xc0,0,0,0,0xf,
+0x80,0x7,0,0x7,0x38,0xc0,0x3,0xe0,0x1,0x1c,
+0,0x8,0x10,0x40,0x8e,0x4,0,0,0x80,0x1,
+0,0x2,0,0x4,0,0x8,0,0x10,0,0xff,
+0xc0,0x79,0x7f,0xcf,0xf9,0xff,0x3f,0xe7,0x9e,0x79,
+0xe7,0xf8,0x38,0x38,0x1e,0,0x78,0x1,0xe0,0x7,
+0x80,0x1e,0,0,0x1e,0xc7,0x87,0x3c,0x39,0xe1,
+0xcf,0xe,0xf0,0xf7,0x80,0x70,0xc0,0x6,0x4,0,
+0,0x1,0x80,0,0,0x30,0x3,0x8,0,0x60,
+0xc4,0x3,0,0,0x60,0x3,0x4,0,0,0,
+0,0,0x30,0x3,0x2,0,0,0x6e,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,
+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,0x6,0x66,0x1b,0x1a,0xc6,
+0xfe,0x6,0x40,0x61,0x86,0x1a,0xc0,0,0,0x1,
+0x66,0xe,0xf,0xcc,0xe0,0xe1,0xf0,0x70,0xfe,0x66,
+0x37,0,0,0,0,0,0x11,0x81,0xc6,0,
+0x70,0xc,0x70,0x61,0xcc,0x70,0x61,0x8c,0x30,0xc3,
+0x86,0xc,0x30,0x61,0x86,0xc,0x1,0xc0,0xe1,0x81,
+0x6,0x18,0x31,0xc6,0x18,0x31,0xc3,0x31,0x99,0x8c,
+0x8,0xe0,0x63,0xc,0x19,0xc1,0x9c,0x18,0xc3,0x8c,
+0x81,0x83,0x80,0x3,0,0x30,0,0x1,0x80,0x6,
+0x80,0x30,0xc,0x63,0x1,0x80,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x3,0x8,0x60,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x33,0,0x3,0x11,0x19,0x9b,
+0x18,0x31,0x20,0,0,0,0x30,0x63,0xe8,0x80,
+0x9,0xc5,0x80,0x7,0x40,0x3,0x36,0,0x18,0x30,
+0xc1,0x91,0xc,0,0x1,0xc0,0x3,0x80,0x7,0,
+0xe,0,0x1c,0,0x38,0,0x78,0xc1,0x87,0x30,
+0xc6,0x18,0xc3,0x18,0x63,0xc,0x30,0xc3,0x1c,0x18,
+0x10,0x61,0x81,0x86,0x6,0x18,0x18,0x60,0x61,0x80,
+0,0x61,0x83,0x2,0x18,0x10,0xc0,0x86,0x4,0x70,
+0x63,0,0xd8,0x60,0xc,0xe,0x6,0x86,0xc2,0x40,
+0,0,0x18,0x6,0x1c,0x36,0x31,0x8e,0xd9,0xb0,
+0xe8,0x30,0x6,0xe,0x3,0x46,0xc0,0,0,0x18,
+0x6,0x7,0x6,0xc0,0xc6,0x3,0x60,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,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x6,0x66,0x1b,0x1a,0x4c,0x44,0x6,0x40,
+0x63,0x3,0xa,0x80,0,0,0x3,0x42,0x1e,0x19,
+0xc8,0x60,0xe3,0,0xc0,0x84,0x62,0x63,0,0,
+0,0,0,0x18,0x87,0x3,0,0x70,0xc,0x30,
+0xc0,0xcc,0x18,0x60,0x8c,0x11,0x81,0x86,0xc,0x30,
+0x61,0x8c,0xc,0x1,0xc0,0xe1,0xc1,0xc,0xc,0x30,
+0xcc,0xc,0x30,0xc6,0x11,0x18,0x8c,0x8,0x60,0x43,
+0xc,0x10,0xe3,0xc,0x30,0x83,0xc,0xc1,0x82,0x80,
+0,0x80,0x30,0,0x1,0x80,0x4,0,0x30,0,
+0x3,0x1,0x80,0,0,0,0,0,0,0,
+0x1,0,0,0,0,0,0,0,0x6,0x8,
+0x30,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0xc,0x33,0,0x3,0x11,0x19,0x9b,0x20,0x8,0x20,
+0,0,0,0x40,0x10,0x8,0x80,0x1,0x8e,0,
+0xf,0x40,0x1,0x22,0,0x8,0x20,0x41,0x3,0x8,
+0,0x1,0xc0,0x3,0x80,0x7,0,0xe,0,0x1c,
+0,0x38,0,0x58,0x43,0x3,0x30,0x46,0x8,0xc1,
+0x18,0x23,0xc,0x30,0xc3,0x6,0x1c,0x10,0xc0,0xc3,
+0x3,0xc,0xc,0x30,0x30,0xc0,0xc0,0,0xc1,0xc3,
+0x2,0x18,0x10,0xc0,0x86,0x4,0x30,0xc3,0,0x8c,
+0x10,0x10,0x11,0xb,0x6,0xc2,0x40,0,0,0x4,
+0x8,0x22,0x36,0xa,0x11,0xd9,0xc1,0x70,0x8,0x8,
+0x11,0x5,0x86,0xc0,0,0,0x4,0x8,0x8,0x86,
+0xc1,0x6,0x3,0x60,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,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x6,
+0x44,0x1b,0x1a,0xc,0x48,0x6,0x40,0x43,0x3,0x7,
+0,0,0,0x2,0xc3,0x6,0x10,0xc0,0x61,0x63,
+0x1,0x80,0xc,0x62,0x61,0x80,0,0,0,0,
+0x19,0x86,0x1,0,0x50,0xc,0x30,0xc0,0x4c,0x18,
+0x60,0xc,0x1,0x80,0x86,0xc,0x30,0x61,0x98,0xc,
+0x1,0xe1,0xe1,0xe1,0xc,0xc,0x30,0xcc,0xc,0x30,
+0xc6,0,0x18,0xc,0x8,0x70,0x41,0x8c,0x10,0x66,
+0x6,0x20,0x7,0xc,0x41,0x86,0xc0,0,0,0x30,
+0,0x1,0x80,0xc,0,0x30,0,0x3,0x1,0x80,
+0,0,0,0,0,0,0,0x3,0,0,
+0,0,0,0,0,0x6,0x8,0x30,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x8,0x30,0x1b,
+0xb3,0xb1,0x1c,0,0x23,0xc8,0xe0,0,0,0,
+0x5f,0x10,0x8,0x81,0x1,0x38,0,0xf,0x40,0x1,
+0x22,0,0x8,0x60,0x43,0xe,0x18,0,0x1,0x40,
+0x2,0x80,0x5,0,0xa,0,0x14,0,0x28,0,
+0x58,0x3,0x1,0x30,0x6,0,0xc0,0x18,0x3,0xc,
+0x30,0xc3,0x6,0x1e,0x10,0xc0,0xc3,0x3,0xc,0xc,
+0x30,0x30,0xc0,0xc0,0,0xc3,0x43,0x2,0x18,0x10,
+0xc0,0x86,0x4,0x18,0x83,0xf9,0x8c,0,0,0,
+0,0,0x1,0x80,0,0,0,0,0,0,
+0,0,0x2,0x60,0,0,0,0,0,0,
+0,0,0x2,0,0,0,0,0,0x6,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,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,0x6,0,0xff,0xde,
+0xc,0xd8,0x6,0x80,0x2,0x1,0x1a,0xc0,0x80,0,
+0x2,0xc3,0x6,0,0xc0,0xc2,0x63,0xc1,0x80,0x8,
+0x74,0x61,0x99,0x80,0x30,0,0xc0,0x1,0x8c,0x7d,
+0x80,0xd8,0xc,0x31,0x80,0xc,0xc,0x60,0xc,0x3,
+0,0x6,0xc,0x30,0x61,0xb0,0xc,0x1,0x61,0x61,
+0x61,0x18,0x6,0x30,0xd8,0x6,0x30,0xc7,0,0x18,
+0xc,0x8,0x30,0xc1,0x86,0x30,0x34,0x6,0x40,0xe,
+0xc,0x61,0x84,0x40,0,0x3c,0x37,0xf,0xf,0x87,
+0x9f,0x1f,0x33,0x1c,0xe3,0x39,0x9c,0xc6,0x39,0x83,
+0xc7,0x70,0xf9,0xd9,0xa7,0xf9,0xde,0x7e,0x73,0xf1,
+0xf9,0xff,0x86,0x8,0x30,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x18,0x7c,0x30,0x1e,0xf1,0xa1,0xe,
+0,0x44,0x45,0x20,0,0,0,0x88,0x88,0x7,
+0x1,0x2,0xc,0x39,0xcf,0x40,0x1,0x36,0,0x8,
+0xc0,0x46,0x3,0x30,0xc,0x3,0x60,0x6,0xc0,0xd,
+0x80,0x1b,0,0x36,0,0x6c,0,0xd8,0x6,0,
+0x30,0x6,0,0xc0,0x18,0x3,0xc,0x30,0xc3,0x3,
+0x16,0x11,0x80,0x66,0x1,0x98,0x6,0x60,0x19,0x80,
+0x60,0x1,0x86,0x63,0x2,0x18,0x10,0xc0,0x86,0x4,
+0x19,0x3,0x1d,0x8c,0x78,0x3c,0x1e,0xf,0x7,0x83,
+0xc3,0xde,0x1e,0x1e,0x1e,0x1e,0x1e,0x73,0x9c,0xe1,
+0xf3,0x98,0x3c,0x1e,0xf,0x7,0x83,0xc0,0,0x7e,
+0xe7,0x73,0xb9,0xdc,0xfe,0x66,0xef,0x30,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x6,0,0x36,0xf,0xf,0xb0,0x3,
+0x3c,0x6,0x1,0x92,0x40,0x80,0,0x6,0xc3,0x6,
+0,0xc3,0x86,0x60,0xf3,0xf0,0x18,0x3c,0x61,0x99,
+0x80,0xe0,0,0x70,0x3,0xc,0xfc,0x80,0x98,0xc,
+0x61,0x80,0xc,0xc,0x61,0xc,0x23,0,0x6,0xc,
+0x30,0x61,0xe0,0xc,0x1,0x63,0x61,0x31,0x18,0x6,
+0x31,0x98,0x6,0x31,0x83,0xc0,0x18,0xc,0x8,0x30,
+0x81,0x86,0x20,0x38,0x3,0xc0,0xc,0xc,0x61,0x8c,
+0x60,0,0x66,0x3b,0x99,0x99,0x8c,0xcc,0x66,0x37,
+0x8c,0x63,0x11,0x8d,0xef,0x1b,0xc6,0x63,0xb9,0x98,
+0xdb,0x63,0x18,0xcc,0x66,0x63,0x31,0xb0,0xb3,0x86,
+0x8,0x30,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x18,0xd6,0x30,0xc,0x61,0xa0,0x1f,0,0x48,0x5,
+0xd0,0x88,0,0,0x88,0x88,0,0x1,0x2,0x4,
+0x18,0xcf,0x40,0x1,0x1c,0x44,0x8,0x88,0x45,0xc1,
+0x22,0xc,0x2,0x60,0x4,0xc0,0x9,0x80,0x13,0,
+0x26,0,0x4c,0,0x98,0x86,0,0x30,0x86,0x10,
+0xc2,0x18,0x43,0xc,0x30,0xc3,0x3,0x13,0x11,0x80,
+0x66,0x1,0x98,0x6,0x60,0x19,0x80,0x66,0x19,0x86,
+0x63,0x2,0x18,0x10,0xc0,0x86,0x4,0xf,0x3,0xd,
+0x98,0xc8,0x64,0x32,0x19,0xc,0x86,0x46,0x73,0x33,
+0x33,0x33,0x33,0x33,0x31,0x8c,0x63,0x31,0xbc,0x66,
+0x33,0x19,0x8c,0xc6,0x60,0x60,0xcc,0x63,0x31,0x98,
+0xcc,0x6c,0x67,0x76,0x30,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,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x2,0,0x36,0x7,0x87,0x27,0x7,0x18,0x6,0x1,
+0x82,0,0x80,0,0x4,0xc3,0x6,0x1,0x83,0xc4,
+0x60,0x33,0x18,0x18,0x3c,0x71,0x80,0x3,0x80,0,
+0x1c,0x3,0x18,0xcc,0x81,0x9c,0xf,0xf1,0x80,0xc,
+0xc,0x7f,0xf,0xe3,0x3,0xc7,0xfc,0x30,0x61,0xe0,
+0xc,0x1,0x73,0x61,0x39,0x18,0x6,0x3f,0x18,0x6,
+0x3f,0x1,0xe0,0x18,0xc,0x8,0x38,0x81,0xce,0x20,
+0x18,0x1,0x80,0x1c,0xc,0x21,0x88,0x20,0,0x66,
+0x31,0xb1,0xb1,0x98,0x6c,0x62,0x39,0x8c,0x63,0x21,
+0x8e,0x73,0x1c,0xcc,0x33,0x1b,0x18,0xe3,0x23,0x18,
+0xcc,0x46,0x26,0x1b,0x39,0xa3,0x6,0x8,0x30,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x1,0x96,0xfc,
+0x8,0x23,0xf0,0x23,0x80,0x48,0x4,0x1,0x98,0,
+0,0x8f,0x8,0,0x1,0x4,0x44,0x18,0xcf,0x40,
+0x1,0,0x66,0x9,0x98,0x4e,0x71,0x66,0,0x6,
+0x70,0xc,0xe0,0x19,0xc0,0x33,0x80,0x67,0,0xce,
+0x1,0x9f,0x86,0,0x3f,0x87,0xf0,0xfe,0x1f,0xc3,
+0xc,0x30,0xcf,0xc3,0x13,0x91,0x80,0x66,0x1,0x98,
+0x6,0x60,0x19,0x80,0x63,0x31,0x8c,0x63,0x2,0x18,
+0x10,0xc0,0x86,0x4,0x6,0x3,0xd,0xf0,0xcc,0x66,
+0x33,0x19,0x8c,0xc6,0x66,0x61,0x60,0x61,0x61,0x61,
+0x61,0x31,0x8c,0x66,0x19,0xcc,0xc3,0x61,0xb0,0xd8,
+0x6c,0x30,0x61,0x9e,0x63,0x31,0x98,0xcc,0x6e,0x46,
+0x37,0x20,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x2,0,0x36,
+0x3,0x80,0x6d,0x8d,0xb0,0x6,0x1,0x80,0,0x80,
+0x7c,0x4,0xc3,0x6,0x1,0x80,0xe8,0x60,0x3b,0xc,
+0x10,0x6e,0x3f,0x80,0xe,0x3,0xfc,0x7,0x6,0x19,
+0x8c,0x81,0xc,0xc,0x39,0x80,0xc,0xc,0x61,0xc,
+0x23,0x1,0x86,0xc,0x30,0x61,0xb0,0xc,0x1,0x32,
+0x61,0x1d,0x18,0x6,0x30,0x18,0x6,0x33,0,0x70,
+0x18,0xc,0x8,0x19,0x80,0xca,0x60,0x3c,0x1,0x80,
+0x38,0xc,0x31,0x80,0,0,0xe,0x31,0xb0,0x31,
+0x9f,0xec,0x62,0x31,0x8c,0x63,0x41,0x8c,0x63,0x18,
+0xcc,0x33,0x1b,0x18,0xc3,0x83,0x18,0xc6,0x43,0x66,
+0xe,0x19,0x6,0xc,0x8,0x18,0x79,0x80,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1,0x90,0x30,0xc,0x60,0xc0,
+0x31,0xc0,0x48,0x5,0xf3,0x31,0xff,0x7c,0x89,0x8,
+0,0x1f,0xff,0xb8,0x18,0xc7,0x4c,0x3,0xbe,0x33,
+0x1d,0x28,0xe8,0x6e,0x4a,0x4,0x4,0x30,0x8,0x60,
+0x10,0xc0,0x21,0x80,0x43,0,0x86,0x1,0xf8,0x86,
+0,0x30,0x86,0x10,0xc2,0x18,0x43,0xc,0x30,0xc3,
+0x3,0x11,0xd1,0x80,0x66,0x1,0x98,0x6,0x60,0x19,
+0x80,0x61,0xe1,0x98,0x63,0x2,0x18,0x10,0xc0,0x86,
+0x4,0x6,0x3,0xd,0x98,0x1c,0xe,0x7,0x3,0x81,
+0xc0,0xe0,0xff,0x60,0x7f,0x7f,0x7f,0x7f,0x31,0x8c,
+0x66,0x19,0x8c,0xc3,0x61,0xb0,0xd8,0x6c,0x30,0x1,
+0x96,0x63,0x31,0x98,0xcc,0x66,0x46,0x33,0x20,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,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x2,0x1,0xff,0x82,0xc0,0xd8,
+0x99,0xe0,0x6,0x1,0x80,0xf,0xf8,0x7c,0xc,0xc3,
+0x6,0x3,0,0x6f,0xf0,0x1b,0xc,0x30,0xc7,0x3,
+0,0x18,0,0,0x1,0x84,0x19,0x99,0x81,0xfc,
+0xc,0x19,0x80,0xc,0xc,0x60,0xc,0x3,0x1,0x86,
+0xc,0x30,0x61,0x98,0xc,0x1,0x36,0x61,0xd,0x18,
+0x6,0x30,0x18,0x6,0x31,0x80,0x38,0x18,0xc,0x8,
+0x1d,0,0xcb,0x40,0x6c,0x1,0x80,0x70,0xc,0x31,
+0x80,0,0,0x36,0x31,0xb0,0x31,0x98,0xc,0x66,
+0x31,0x8c,0x63,0xc1,0x8c,0x63,0x18,0xcc,0x33,0x1b,
+0x18,0xc1,0xc3,0x18,0xc6,0xc3,0x76,0x6,0x1b,0xc,
+0x18,0x8,0xc,0xcf,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x11,0xb0,0x30,0x1e,0xf3,0xf1,0x38,0xc0,0x44,
+0x44,0x6,0x60,0x1,0x7c,0x88,0x88,0,0x1,0,
+0,0x18,0xc1,0x4c,0,0,0x19,0x83,0x68,0x18,
+0x40,0xda,0x4,0x7,0xf0,0xf,0xe0,0x1f,0xc0,0x3f,
+0x80,0x7f,0,0xfe,0x1,0x18,0x6,0,0x30,0x6,
+0,0xc0,0x18,0x3,0xc,0x30,0xc3,0x3,0x10,0xd1,
+0x80,0x66,0x1,0x98,0x6,0x60,0x19,0x80,0x60,0xc1,
+0x98,0x63,0x2,0x18,0x10,0xc0,0x86,0x4,0x6,0x3,
+0x19,0x8c,0x6c,0x36,0x1b,0xd,0x86,0xc3,0x63,0x60,
+0x60,0x60,0x60,0x60,0x60,0x31,0x8c,0x66,0x19,0x8c,
+0xc3,0x61,0xb0,0xd8,0x6c,0x33,0xfd,0xb6,0x63,0x31,
+0x98,0xcc,0x66,0xc6,0x33,0x60,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,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,0x6c,0x2,0xc0,0x98,0x98,0xe0,0x6,
+0x1,0x80,0,0x80,0,0x8,0xc3,0x6,0x6,0,
+0x6f,0xf0,0x1b,0xc,0x30,0xc3,0x3,0,0xe,0x3,
+0xfc,0x7,0x4,0x19,0x99,0x3,0xe,0xc,0x18,0xc0,
+0xc,0x18,0x60,0xc,0x1,0x81,0x86,0xc,0x30,0x61,
+0x8c,0xc,0x1,0x1c,0x61,0x7,0xc,0xc,0x30,0xc,
+0xc,0x30,0xc0,0x18,0x18,0xc,0x8,0xd,0,0xd3,
+0x40,0x46,0x1,0x80,0x60,0xc,0x11,0x80,0,0,
+0x66,0x31,0xb0,0x31,0x98,0xc,0x3c,0x31,0x8c,0x63,
+0x61,0x8c,0x63,0x18,0xcc,0x33,0x1b,0x18,0xc0,0xe3,
+0x18,0xc2,0x81,0xd4,0xe,0xe,0xc,0xc,0x8,0x18,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x11,0xa0,
+0x20,0x1b,0xb0,0xc1,0x1c,0x40,0x23,0x88,0x3,0x30,
+0x1,0,0x5c,0xd0,0,0x1,0,0,0x18,0xc1,
+0x40,0,0,0x33,0x6,0x48,0x30,0x81,0x92,0xc,
+0xc,0x38,0x18,0x70,0x30,0xe0,0x61,0xc0,0xc3,0x81,
+0x87,0x3,0x18,0x3,0,0x30,0x6,0,0xc0,0x18,
+0x3,0xc,0x30,0xc3,0x6,0x10,0x70,0xc0,0xc3,0x3,
+0xc,0xc,0x30,0x30,0xc0,0xc1,0xe0,0xb0,0xc3,0x2,
+0x18,0x10,0xc0,0x86,0x4,0x6,0x3,0xf1,0x8c,0xcc,
+0x66,0x33,0x19,0x8c,0xc6,0x66,0x60,0x60,0x60,0x60,
+0x60,0x60,0x31,0x8c,0x66,0x19,0x8c,0xc3,0x61,0xb0,
+0xd8,0x6c,0x30,0x1,0xa6,0x63,0x31,0x98,0xcc,0x63,
+0x86,0x31,0xc0,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,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,
+0x6c,0x12,0xc1,0x99,0x98,0xf0,0x6,0x1,0x80,0,
+0x80,0,0x8,0x42,0x6,0xc,0x40,0x60,0x60,0x33,
+0x8c,0x20,0xc3,0x6,0,0x3,0x80,0,0x1c,0,
+0x19,0xbb,0x2,0x6,0xc,0x18,0xc0,0xcc,0x18,0x60,
+0x8c,0x1,0x81,0x86,0xc,0x30,0x61,0x8e,0xc,0x9,
+0x1c,0x61,0x7,0xc,0xc,0x30,0xc,0xc,0x30,0xc4,
+0x18,0x18,0xe,0x18,0xf,0,0x73,0xc0,0xc7,0x1,
+0x80,0xe0,0x8c,0x19,0x80,0,0,0x66,0x31,0xb0,
+0x31,0x9c,0x2c,0x20,0x31,0x8c,0x63,0x31,0x8c,0x63,
+0x18,0xcc,0x33,0x1b,0x18,0xc2,0x63,0x18,0xc3,0x81,
+0xdc,0x1b,0xe,0x18,0x86,0x8,0x30,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x11,0xa0,0xf0,0x80,0,
+0xc1,0xf,0x80,0x20,0x8,0x1,0x98,0x1,0,0x40,
+0x10,0,0x1,0,0,0x18,0xc1,0x40,0,0,
+0x66,0x4,0xfc,0x20,0x81,0x3f,0x18,0x8,0x18,0x10,
+0x30,0x20,0x60,0x40,0xc0,0x81,0x81,0x3,0x2,0x18,
+0x23,0x3,0x30,0x46,0x8,0xc1,0x18,0x23,0xc,0x30,
+0xc3,0x6,0x10,0x70,0xc0,0xc3,0x3,0xc,0xc,0x30,
+0x30,0xc0,0xc3,0x30,0xe0,0xc3,0x86,0x1c,0x30,0xe1,
+0x87,0xc,0x6,0x3,0x1,0xac,0xcc,0x66,0x33,0x19,
+0x8c,0xc6,0x66,0x60,0x60,0x60,0x60,0x60,0x60,0x31,
+0x8c,0x66,0x19,0x8c,0xc3,0x61,0xb0,0xd8,0x6c,0x30,
+0x61,0xe6,0x63,0x31,0x98,0xcc,0x63,0x86,0x31,0xc0,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x6,0,0x6c,0x1a,0xc3,
+0x1f,0x1d,0xbe,0x6,0x1,0x80,0,0x83,0,0xd8,
+0x66,0xf,0x1f,0xcc,0xc0,0x63,0x71,0xd8,0x60,0x66,
+0x1c,0x19,0x80,0xe0,0,0x70,0x6,0xc,0xee,0x6,
+0x7,0xc,0x30,0x71,0x8c,0x70,0x61,0x8c,0,0xe7,
+0x6,0xc,0x33,0x61,0x87,0xc,0x19,0x8,0x61,0x3,
+0x6,0x18,0x30,0x6,0x18,0x30,0x66,0x30,0x18,0x7,
+0x30,0x6,0,0x61,0x81,0x83,0x81,0x81,0xc1,0x8c,
+0x9,0x80,0,0,0x7e,0x3b,0x18,0x99,0x8e,0xcc,
+0x3e,0x31,0x8c,0x63,0x19,0x8c,0x63,0x18,0xc6,0x63,
+0xb1,0x98,0xc3,0x63,0x9d,0xc1,0,0x88,0x31,0x86,
+0x39,0x86,0x8,0x30,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x18,0xe5,0x7f,0x80,0,0xc1,0x7,0,
+0x18,0x30,0,0x88,0x1,0,0x30,0x60,0,0,
+0,0,0x1d,0xc1,0x40,0,0,0x44,0xc,0x8,
+0x61,0x3,0x2,0x18,0x18,0x1c,0x30,0x38,0x60,0x70,
+0xc0,0xe1,0x81,0xc3,0x3,0x86,0x18,0x61,0xc6,0x30,
+0xc6,0x18,0xc3,0x18,0x63,0xc,0x30,0xc3,0x1c,0x10,
+0x30,0x61,0x81,0x86,0x6,0x18,0x18,0x60,0x61,0x86,
+0x18,0x61,0x81,0xcc,0xe,0x60,0x73,0x3,0x98,0x6,
+0x3,0x1,0xac,0xfc,0x7e,0x3f,0x1f,0x8f,0xc7,0xe7,
+0xf3,0x33,0x33,0x33,0x33,0x33,0x31,0x8c,0x63,0x31,
+0x8c,0x66,0x33,0x19,0x8c,0xc6,0x60,0x60,0xcc,0x77,
+0x3b,0x9d,0xce,0xe1,0x87,0x60,0xc0,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,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x6,0,0x6c,0xf,0x82,0xe,0xf,0x1c,
+0x2,0x1,0,0,0x83,0,0xd0,0x3c,0x1f,0x9f,
+0xcf,0x80,0x63,0xc0,0xf0,0x60,0x3c,0x70,0x19,0x80,
+0x30,0,0xc0,0x6,0xc,0,0xf,0xf,0x9f,0xe0,
+0x1e,0x1f,0xe0,0xff,0x9e,0,0x3c,0xf,0x1e,0x7b,
+0xc3,0xc3,0x9f,0xfb,0x88,0xf3,0x81,0x1,0xe0,0x78,
+0x1,0xe0,0x78,0x75,0xe0,0x3c,0x3,0xe0,0x6,0,
+0x61,0x83,0xc3,0xc3,0xc1,0xff,0x8c,0x9,0x80,0,
+0,0x33,0x1e,0xf,0xf,0xc7,0x9e,0x3f,0xf9,0xde,
+0x67,0x1f,0xde,0xf7,0xbc,0xe3,0xc3,0x60,0xf9,0xe2,
+0xc1,0xce,0xe1,0,0x88,0x71,0x8c,0x3f,0x86,0x8,
+0x30,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x18,
+0xf9,0xcf,0,0x3,0xf1,0x3,0x80,0x7,0xc0,0,
+0,0,0,0xf,0x80,0,0x1f,0xf0,0,0x1e,
+0xe1,0x40,0x20,0,0,0x8,0x8,0x43,0xe2,0x2,
+0x30,0x3c,0x3e,0x78,0x7c,0xf0,0xf9,0xe1,0xf3,0xc3,
+0xe7,0x87,0xcf,0x7f,0xe0,0x78,0x7f,0xcf,0xf9,0xff,
+0x3f,0xe7,0x9e,0x79,0xe7,0xf8,0x38,0x10,0x1e,0,
+0x78,0x1,0xe0,0x7,0x80,0x1e,0,0,0xde,0,
+0xf8,0x7,0xc0,0x3e,0x1,0xf0,0xf,0x7,0x83,0xb8,
+0x66,0x33,0x19,0x8c,0xc6,0x63,0x33,0x1e,0x1e,0x1e,
+0x1e,0x1e,0x1e,0x7b,0xde,0xf1,0xe3,0xce,0x3c,0x1e,
+0xf,0x7,0x83,0xc0,0,0xf8,0x3b,0x9d,0xce,0xe7,
+0x61,0x7,0xc0,0x80,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,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,0x2,0,0,0,0,0x3,0x3,0,
+0,0x1,0,0x10,0,0,0,0,0,0,
+0,0,0,0,0,0,0x80,0,0,0,
+0,0x6,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,0xc0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xc,0x1,0x80,0,0,0,0,
+0,0,0,0,0x41,0x80,0,0x60,0,0,
+0,0,0,0x3,0,0x18,0,0,0,0,
+0,0,0,0xc,0,0x6,0,0x30,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x18,0x80,0,0,
+0,0,0x19,0x80,0,0,0,0,0,0,
+0,0,0,0,0,0,0x10,0x1,0x40,0x20,
+0,0,0,0,0,0,0,0x33,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x20,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1,0x80,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x8,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1,0x80,0,0,0,0,0x3,0x6,0x1,
+0x80,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,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,0x2,
+0,0,0,0,0x3,0x3,0,0,0x3,0,
+0x10,0,0,0,0,0,0,0,0,0,
+0,0,0x1,0x80,0,0,0,0,0x3,0x86,
+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,0x60,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0xc,0x1,0x80,0,0,0,0,0,0,0,
+0,0x60,0x80,0,0x60,0,0,0,0,0,
+0x3,0,0x18,0,0,0,0,0,0,0,
+0x8,0,0x6,0,0x30,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x19,0x80,0,0,0,0,0x19,
+0x80,0,0,0,0,0,0,0,0,0,
+0,0,0,0x10,0x1,0x40,0x10,0,0,0,
+0,0,0,0,0x23,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x10,
+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,0x4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x2,0x6,0x1,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,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,0x1,0x86,0,0,0x6,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x3,
+0,0,0,0,0,0,0xfc,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,0x38,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xf,0x7,0x80,
+0,0,0,0,0,0,0,0,0x71,0,
+0x1,0xc0,0,0,0,0,0,0x3,0,0x18,
+0,0,0,0,0,0,0,0x78,0,0x3,
+0,0x60,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x18,0,0,0,0,0,0xf,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x18,0x1,0x40,0xb0,0,0,0,0,0,0,
+0,0x31,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xb0,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,0x2c,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1e,0x6,0xf,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,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,0xcc,
+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,0x1e,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xf,0xf8,0,
+0,0,0,0,0,0x3e,0,0x1,0x80,0,
+0,0,0,0,0x7,0x80,0x3c,0,0,0,
+0,0,0,0,0x70,0,0x1,0xc1,0xc0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x18,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x18,0x1,0x40,
+0x60,0,0,0,0,0,0,0,0x1e,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x60,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,0x18,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1c,0xf,
+0xe,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,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,
+};
+
+static WORD Times18_ch_ofst[225] = {
+0,4,8,16,26,35,50,64,68,75,
+82,91,101,105,111,115,120,129,138,147,
+156,165,174,183,192,201,210,214,218,229,
+239,250,258,275,290,302,314,327,338,349,
+363,376,382,389,402,413,429,442,456,466,
+480,492,502,514,527,540,558,570,582,594,
+600,605,611,620,629,633,641,650,658,667,
+675,681,689,699,704,709,718,723,738,748,
+757,766,775,782,789,795,804,813,825,834,
+842,850,859,862,871,882,886,890,894,898,
+902,906,910,914,918,922,926,930,934,938,
+942,946,950,954,958,962,966,970,974,978,
+982,986,990,994,998,1002,1006,1010,1014,1018,
+1022,1031,1042,1053,1062,1065,1075,1080,1095,1100,
+1110,1121,1127,1142,1147,1154,1164,1169,1174,1178,
+1187,1195,1199,1205,1210,1216,1226,1239,1252,1265,
+1273,1288,1303,1318,1333,1348,1363,1380,1392,1403,
+1414,1425,1436,1442,1448,1454,1460,1473,1486,1500,
+1514,1528,1542,1556,1566,1580,1593,1606,1619,1632,
+1644,1654,1663,1672,1681,1690,1699,1708,1717,1729,
+1737,1745,1753,1761,1769,1774,1779,1784,1789,1798,
+1808,1817,1826,1835,1844,1853,1863,1872,1881,1890,
+1899,1908,1916,1925,1933,
+};
+
+static struct font_hdr Times18_font = {
+STPROP, 18, "-Adobe-Times-M-R-N--18-180-75-7", 32, 255,
+21, 17, 10, 4, 4,
+19, 18, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Times18_ch_ofst, Times18_data,
+337, 21,
+NULL,
+0, 0,   /* x/y offset */
+23,        /* lineHeight */
+16,	/* psHeight */
+};
+
+MgFont *mgTimes18Font()
+{
+return &Times18_font;
+}
diff --git a/lib/font/mgTimes24.c b/lib/font/mgTimes24.c
new file mode 100644
index 0000000..4558297
--- /dev/null
+++ b/lib/font/mgTimes24.c
@@ -0,0 +1,1193 @@
+
+/* Times24.c - compiled data for font -Adobe-Times-M-R-N--24-240-75-7 */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/timR24.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Times24_data[11368] = {
+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,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,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,0,0xc0,0,0x6,
+0,0x18,0,0,0,0,0,0,0,0,
+0,0,0,0,0x60,0,0x6,0,0x30,0,
+0,0x30,0x3,0x6,0,0,0,0,0,0,
+0x18,0,0,0x30,0,0x60,0,0,0,0,
+0,0,0,0,0,0x6,0,0,0xc,0,
+0x18,0,0,0,0,0x60,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,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,
+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,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,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,0xe0,0,0xe,0,0x3c,0,0x1c,
+0x80,0x18,0xc0,0x3,0x80,0,0,0,0,0,
+0x70,0,0xe,0,0x78,0x3,0x30,0x38,0x7,0xf,
+0x19,0x80,0,0,0x39,0,0x1c,0,0,0x70,
+0,0xf0,0,0x39,0,0x19,0x80,0,0,0,
+0,0x7,0,0,0x1c,0,0x3c,0,0x18,0xc0,
+0,0xe0,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,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,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,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,
+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,0x30,
+0,0x18,0,0x66,0,0x27,0,0x18,0xc0,0x4,
+0x40,0,0,0,0,0,0x18,0,0x18,0,
+0xcc,0x3,0x30,0xc,0xc,0x19,0x99,0x80,0,0,
+0x4e,0,0x6,0,0,0xc0,0x1,0x98,0,0x4e,
+0,0x19,0x80,0,0,0,0,0x1,0x80,0,
+0x30,0,0x66,0,0x18,0xc0,0x1,0x80,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,
+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,0x20,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,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,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,0x8,0,0x20,0,0x81,
+0,0,0,0,0,0x4,0x40,0,0,0,
+0,0,0x4,0,0x20,0x1,0x2,0,0,0x2,
+0x10,0x20,0x40,0,0,0,0,0,0x1,0,
+0x1,0,0x2,0x4,0,0,0,0,0,0,
+0,0,0,0,0x40,0,0x40,0,0x81,0,
+0,0,0x2,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,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,0x20,
+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,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,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,0x38,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,0x3,0x80,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,0x10,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,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,0x61,0x98,0x4,0x40,0xfc,0,0,0,0x3c,
+0,0xc0,0x24,0,0x20,0,0,0,0,0,
+0x61,0xe0,0x4,0x1,0xc0,0x1c,0,0x30,0x1f,0xc0,
+0x3c,0x7f,0xc1,0xe0,0x1e,0,0,0,0,0,
+0,0,0x1f,0,0x1f,0xc0,0,0x40,0x1f,0xf8,
+0,0xfc,0x9f,0xf8,0xf,0xff,0x1f,0xfe,0x3,0xf2,
+0x1f,0x83,0xf3,0xf0,0x7e,0x7e,0x3f,0x3f,0,0xf0,
+0,0xfb,0xc0,0x7c,0x7,0xe0,0x3f,0xf0,0x3,0xf0,
+0x1f,0xf8,0x3,0xc8,0xff,0xfc,0xfc,0x1f,0x7e,0xf,
+0xff,0x1f,0x9f,0xbf,0x7,0xdf,0x87,0xef,0xff,0xf,
+0xb0,0x3e,0x2,0,0,0x30,0,0x7,0,0,
+0,0x38,0,0x3,0x80,0x3,0x80,0xc,0x31,0xc0,
+0x1c,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x1,0xc6,0x38,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,0x7,0x80,0,0x7c,0x3e,
+0x60,0x4c,0,0x1,0xfc,0x7,0x80,0,0,0,
+0,0x3,0xf8,0,0x3,0x80,0,0xe,0x1c,0x6,
+0,0,0x7e,0,0,0x41,0xe0,0,0x8,0x2,
+0x2,0,0x81,0xc0,0x20,0,0,0x20,0,0x10,
+0,0x8,0,0x4,0,0x2,0,0x1,0,0x3,
+0xff,0xe0,0x1f,0x93,0xff,0xc7,0xff,0x8f,0xff,0x1f,
+0xfe,0x3f,0x3f,0x1f,0x9f,0x9f,0xf8,0xf,0x1,0xf0,
+0x1f,0x80,0x7,0xe0,0x1,0xf8,0,0x7e,0,0x1f,
+0x80,0,0,0x1f,0x90,0xfc,0x1f,0x3f,0x7,0xcf,
+0xc1,0xf3,0xf0,0x7d,0xf8,0x7e,0xfc,0,0x3c,0xc,
+0,0xc,0xc,0,0,0,0x7,0,0,0,
+0,0x60,0,0x60,0x30,0,0x18,0x6,0x60,0xc,
+0,0,0x1,0x80,0,0xc0,0x60,0,0,0,
+0,0,0,0x6,0,0x1,0x80,0x60,0,0,
+0x6,0x38,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x61,0x98,0x4,
+0x41,0xa7,0x7,0x83,0,0x66,0,0xc0,0x42,0,
+0x70,0,0,0,0,0,0x63,0x30,0xc,0x7,
+0xf0,0x7e,0,0x70,0x1f,0x80,0xe0,0xff,0xc3,0x30,
+0x77,0x80,0,0,0,0,0,0,0x31,0x80,
+0x78,0x70,0,0xe0,0x6,0xe,0x3,0x87,0x86,0xe,
+0x3,0x3,0x6,0x6,0xe,0x1e,0x6,0,0xc0,0xc0,
+0x18,0x18,0xc,0xc,0,0x30,0,0xe0,0xc0,0x10,
+0x1c,0x38,0xc,0x1c,0xe,0x1c,0x6,0xe,0xc,0x78,
+0xc3,0xc,0x30,0x4,0x18,0x3,0xc,0x6,0x6,0xe,
+0x3,0x6,0x1,0x8c,0x7,0xc,0x30,0x6,0x7,0,
+0,0x38,0,0x3,0,0,0,0x18,0,0x5,
+0x80,0x1,0x80,0xc,0x30,0xc0,0xc,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x3,0x6,
+0xc,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,0xc,0xc0,0,0x38,0x18,0x60,0x8c,0x33,0x7,
+0x7,0xc,0xc0,0,0,0,0,0xe,0xe,0xf,
+0xc4,0x40,0,0x13,0x26,0xe,0,0,0xe4,0,
+0,0xc3,0x30,0,0x18,0x6,0x6,0x1,0x82,0x60,
+0x60,0,0,0x70,0,0x38,0,0x1c,0,0xe,
+0,0x7,0,0x3,0x80,0x1,0xe0,0x60,0x70,0xf0,
+0xc0,0xc1,0x81,0x83,0x3,0x6,0x6,0xc,0xc,0x6,
+0x6,0x6,0xe,0x3,0,0x40,0x70,0xe0,0x1c,0x38,
+0x7,0xe,0x1,0xc3,0x80,0x70,0xe0,0,0,0x70,
+0xe0,0x30,0x4,0xc,0x1,0x3,0,0x40,0xc0,0x10,
+0x60,0x18,0x30,0,0x66,0xe,0,0x1c,0x1e,0x3,
+0xa0,0xcc,0x8,0x80,0,0,0,0x70,0,0xe0,
+0x78,0x19,0x9c,0xe,0xf6,0x67,0x18,0x1c,0x81,0xc0,
+0x1,0xc0,0xf0,0xe,0x41,0x98,0,0,0,0x7,
+0,0x3,0x80,0xf0,0xc,0xc0,0xe,0x18,0x1,0x98,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0x61,0x98,0x4,0x43,0x23,0xc,0xff,
+0,0xc2,0,0xc0,0x81,0x3,0x26,0,0,0,
+0,0,0x66,0x18,0x3c,0x4,0x38,0x47,0,0x70,
+0x20,0x1,0x80,0xc0,0xc6,0x18,0x61,0x80,0,0,
+0,0,0,0,0x20,0xc0,0xe0,0x18,0,0xe0,
+0x6,0x6,0x7,0x1,0x86,0x7,0x3,0x1,0x6,0x2,
+0x1c,0x6,0x6,0,0xc0,0xc0,0x18,0x18,0x18,0xc,
+0,0x38,0x1,0x60,0xe0,0x10,0x38,0x1c,0xc,0xc,
+0x1c,0xe,0x6,0x6,0x18,0x18,0x83,0x4,0x30,0x4,
+0x18,0x2,0xc,0x6,0x4,0x7,0x6,0x7,0x1,0x8,
+0xe,0xc,0x10,0x6,0x5,0,0,0xc,0,0x3,
+0,0,0,0x18,0,0xc,0,0x1,0x80,0,
+0,0xc0,0xc,0,0,0,0,0,0,0,
+0,0,0,0,0x20,0,0,0,0,0,
+0,0,0,0,0x6,0x6,0x6,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,0x18,0xc6,0x3,
+0x18,0x10,0x60,0xc0,0x33,0xc,0x1,0x80,0xc0,0,
+0,0,0,0x18,0x3,0xf,0xc8,0x20,0x30,0x23,
+0x46,0x18,0,0x1,0xe4,0,0x1,0x43,0x30,0,
+0x28,0xc,0xa,0x3,0x4,0x60,0xc0,0,0,0x70,
+0,0x38,0,0x1c,0,0xe,0,0x7,0,0x3,
+0x80,0x1,0x60,0x20,0xe0,0x30,0xc0,0x41,0x80,0x83,
+0x1,0x6,0x2,0xc,0xc,0x6,0x6,0x6,0x7,0x3,
+0x80,0x40,0xe0,0x70,0x38,0x1c,0xe,0x7,0x3,0x81,
+0xc0,0xe0,0x70,0,0,0xe0,0x70,0x30,0x4,0xc,
+0x1,0x3,0,0x40,0xc0,0x10,0x70,0x10,0x30,0,
+0xc3,0x3,0,0x30,0x12,0x5,0xc0,0xcc,0x8,0x80,
+0,0,0,0x18,0x1,0x80,0x48,0x19,0x86,0x18,
+0x96,0x61,0xe0,0x27,0,0x60,0x3,0,0x90,0x13,
+0x81,0x98,0,0,0,0x1,0x80,0x6,0,0x90,
+0xc,0xc0,0x18,0x18,0x1,0x98,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,0,0,
+0,0,0,0,0,0,0,0,0,0x61,
+0x98,0x4,0x43,0x21,0x18,0x46,0,0xc2,0,0xc1,
+0x81,0x83,0xae,0,0,0,0,0,0xc6,0x18,
+0xc,0x8,0x18,0x83,0,0xb0,0x20,0x3,0,0x81,
+0x86,0x18,0xc1,0xc0,0,0,0,0,0,0,
+0x30,0xc1,0xc0,0xc,0,0xb0,0x6,0x3,0xc,0,
+0x86,0x1,0x83,0x1,0x6,0x2,0x30,0x2,0x6,0,
+0xc0,0xc0,0x18,0x18,0x30,0xc,0,0x38,0x1,0x60,
+0xe0,0x10,0x60,0x6,0xc,0x6,0x30,0x3,0x6,0x7,
+0x18,0x8,0x83,0x4,0x30,0x4,0xc,0x6,0x6,0x6,
+0x4,0x3,0x4,0x3,0x3,0x8,0xc,0xc,0x18,0x6,
+0xd,0x80,0,0x2,0,0x3,0,0,0,0x18,
+0,0xc,0,0x1,0x80,0,0,0xc0,0xc,0,
+0,0,0,0,0,0,0,0,0,0,
+0x60,0,0,0,0,0,0,0,0,0,
+0x6,0x6,0x6,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,0x8,0x18,0x7,0x77,0xc,0x30,0x60,0xe0,
+0,0x18,0x78,0xc7,0xc0,0,0,0,0,0x33,
+0xf1,0x80,0x8,0x20,0x30,0x3,0x4,0x20,0,0x1,
+0xe4,0,0,0x43,0x30,0,0x8,0x8,0x2,0x2,
+0,0x40,0x80,0,0,0x58,0,0x2c,0,0x16,
+0,0xb,0,0x5,0x80,0x2,0xc0,0x1,0x60,0x21,
+0x80,0x10,0xc0,0x41,0x80,0x83,0x1,0x6,0x2,0xc,
+0xc,0x6,0x6,0x6,0x1,0x83,0x80,0x41,0x80,0x18,
+0x60,0x6,0x18,0x1,0x86,0,0x61,0x80,0x18,0,
+0x1,0x80,0x98,0x30,0x4,0xc,0x1,0x3,0,0x40,
+0xc0,0x10,0x30,0x30,0x30,0,0xc3,0,0x80,0x40,
+0x21,0,0,0,0x7,0,0,0,0,0x4,
+0x2,0,0x84,0,0x1,0x21,0x8,0x3,0xc0,0,
+0,0x10,0x4,0x1,0x8,0,0,0,0,0,
+0,0,0x40,0x8,0x1,0x8,0,0,0x20,0x18,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x61,0x10,0x4,0x43,0x20,
+0x30,0x44,0,0xc6,0,0x81,0,0x80,0x70,0x3,
+0,0,0,0,0xcc,0xc,0xc,0x8,0x18,0x83,
+0x1,0xb0,0x60,0x7,0,0x1,0x86,0x18,0xc0,0xc0,
+0,0,0,0,0,0,0x30,0xc3,0x80,0x4,
+0x1,0x30,0x6,0x3,0xc,0,0x86,0x1,0x83,0,
+0x6,0,0x30,0x2,0x6,0,0xc0,0xc0,0x18,0x18,
+0x60,0xc,0,0x2c,0x2,0x60,0xb0,0x10,0x60,0x6,
+0xc,0x6,0x30,0x3,0x6,0x3,0x18,0x8,0x3,0,
+0x30,0x4,0xc,0x4,0x6,0x6,0xc,0x1,0x88,0x3,
+0x82,0,0x1c,0xc,0x18,0x6,0x8,0x80,0,0,
+0,0x3,0,0,0,0x18,0,0xc,0,0x1,
+0x80,0,0,0xc0,0xc,0,0,0,0,0,
+0,0,0,0,0,0,0xe0,0,0,0,
+0,0,0,0,0,0,0x6,0x6,0x6,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,0x8,0x18,
+0x3,0xfe,0xc,0x20,0x60,0x70,0,0x11,0xcc,0x4c,
+0xc0,0,0,0,0,0x21,0x18,0x80,0x8,0x20,
+0x30,0x2,0x18,0,0,0x3,0xe4,0,0,0x43,
+0x30,0,0x8,0x18,0x2,0x6,0x1,0x81,0x80,0,
+0,0x98,0,0x4c,0,0x26,0,0x13,0,0x9,
+0x80,0x4,0xc0,0x2,0x60,0x1,0x80,0x10,0xc0,0x1,
+0x80,0x3,0,0x6,0,0xc,0xc,0x6,0x6,0x6,
+0x1,0x82,0xc0,0x41,0x80,0x18,0x60,0x6,0x18,0x1,
+0x86,0,0x61,0x80,0x18,0,0x1,0x81,0x18,0x30,
+0x4,0xc,0x1,0x3,0,0x40,0xc0,0x10,0x38,0x20,
+0x3f,0xc0,0xc3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xc,0x60,0,0,0,0,0,
+0,0,0,0,0,0,0x1,0x80,0,0,
+0,0,0,0,0,0x18,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x60,0,0x3f,0xf3,0xa0,0x30,0x4c,0,0xec,
+0,0x3,0,0xc3,0xae,0x3,0,0,0,0,
+0x8c,0xc,0xc,0,0x18,0x6,0x1,0x30,0x78,0x6,
+0,0x1,0x3,0x30,0xc0,0xc0,0,0,0x30,0,
+0xc,0,0x1,0xc3,0x7,0x66,0x1,0x18,0x6,0x3,
+0x18,0,0x6,0,0xc3,0,0x6,0,0x60,0,
+0x6,0,0xc0,0xc0,0x18,0x18,0xc0,0xc,0,0x2c,
+0x2,0x60,0x98,0x10,0xc0,0x3,0xc,0x6,0x60,0x1,
+0x86,0x7,0x1c,0,0x3,0,0x30,0x4,0xc,0x4,
+0x6,0xb,0x8,0x1,0xd0,0x1,0x86,0,0x38,0xc,
+0x8,0x6,0x18,0xc0,0,0,0xf,0x83,0x70,0xf,
+0x81,0xd8,0x1e,0x3f,0x87,0xf1,0x9c,0x1c,0x70,0xcf,
+0x8c,0x73,0x87,0x7,0x38,0x7,0x83,0xb8,0x7,0x63,
+0x98,0xf9,0xfd,0xc3,0x9e,0x3f,0xc7,0x9e,0xf1,0xef,
+0x1e,0xff,0x6,0x6,0x6,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,0xc0,0xf8,0x18,0x1,0x8c,0x6,0x60,
+0x60,0x78,0,0x31,0x6,0x6c,0xc0,0,0,0,
+0,0x61,0x8,0xc0,0x4,0x40,0x30,0x4,0x4,0,
+0x70,0xe3,0xe4,0,0,0x43,0x30,0,0x8,0x10,
+0x2,0x4,0,0x41,0,0xc,0,0x8c,0,0x46,
+0,0x23,0,0x11,0x80,0x8,0xc0,0x4,0x60,0x2,
+0x60,0x3,0,0,0xc0,0x1,0x80,0x3,0,0x6,
+0,0xc,0xc,0x6,0x6,0x6,0,0xc2,0x60,0x43,
+0,0xc,0xc0,0x3,0x30,0,0xcc,0,0x33,0,
+0xc,0x40,0x23,0x1,0xc,0x30,0x4,0xc,0x1,0x3,
+0,0x40,0xc0,0x10,0x18,0x60,0x30,0x70,0xc3,0x7,
+0xc0,0xf8,0x1f,0x3,0xe0,0x7c,0xf,0x81,0xe7,0x80,
+0xf8,0x1e,0x3,0xc0,0x78,0xf,0xe,0x38,0xe3,0x81,
+0xf0,0xe7,0,0xf0,0xf,0,0xf0,0xf,0,0xf0,
+0x3,0,0x3d,0x9c,0x38,0xe1,0xc7,0xe,0x38,0x73,
+0xc7,0x9b,0x87,0x8f,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,0,0,0,0,
+0,0,0,0,0,0,0,0x60,0,0x3f,
+0xf1,0xe0,0x30,0x98,0,0x78,0,0x3,0,0xc3,
+0x26,0x3,0,0,0,0x1,0x8c,0xc,0xc,0,
+0x18,0xc,0x3,0x30,0x7e,0xe,0xe0,0x3,0x1,0xe0,
+0xc0,0xc6,0x18,0,0xe0,0,0x7,0,0x3,0x87,
+0xf,0xe2,0x3,0x18,0x6,0x6,0x18,0,0x6,0,
+0xc3,0x4,0x6,0x4,0x60,0,0x6,0,0xc0,0xc0,
+0x18,0x19,0x80,0xc,0,0x26,0x2,0x60,0x98,0x10,
+0xc0,0x3,0xc,0xc,0x60,0x1,0x86,0x6,0xf,0,
+0x3,0,0x30,0x4,0x6,0xc,0x3,0xb,0x8,0,
+0xe0,0,0xc4,0,0x30,0xc,0xc,0x6,0x10,0x40,
+0,0,0x19,0xc3,0x9c,0x31,0xc7,0x38,0x63,0xc,
+0xc,0xc1,0xbe,0xc,0x30,0xc6,0xc,0x37,0xcf,0x83,
+0x7c,0x1c,0xe1,0xce,0x1c,0xe1,0xb9,0x98,0x60,0xc1,
+0x8c,0x19,0x83,0xc,0x60,0xc6,0xc,0xc3,0x6,0x6,
+0x6,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,0xc3,
+0x1c,0x18,0x3,0x6,0x6,0x40,0x60,0x9c,0,0x23,
+0,0x27,0x60,0x22,0,0,0,0x41,0x8,0x40,
+0x3,0x80,0x30,0xc,0x6,0,0x30,0x63,0xe4,0,
+0,0x41,0xe1,0x10,0x8,0x30,0x2,0xc,0,0x63,
+0,0xc,0x1,0x8c,0,0xc6,0,0x63,0,0x31,
+0x80,0x18,0xc0,0xc,0x60,0x6,0x60,0x83,0,0,
+0xc1,0x1,0x82,0x3,0x4,0x6,0x8,0xc,0xc,0x6,
+0x6,0x6,0,0xc2,0x60,0x43,0,0xc,0xc0,0x3,
+0x30,0,0xcc,0,0x33,0,0xc,0x60,0x63,0x2,
+0xc,0x30,0x4,0xc,0x1,0x3,0,0x40,0xc0,0x10,
+0xc,0x40,0x30,0x30,0xc6,0xc,0xe1,0x9c,0x33,0x86,
+0x70,0xce,0x19,0xc3,0x3c,0xc3,0x1c,0x63,0xc,0x61,
+0x8c,0x31,0x86,0x18,0x61,0x87,0x38,0x6f,0x83,0x9c,
+0x39,0xc3,0x9c,0x39,0xc3,0x9c,0x3,0,0xe7,0xc,
+0x18,0x60,0xc3,0x6,0x18,0x31,0x83,0x1c,0xe3,0x6,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0x60,0,0x8,0x80,0xf0,0x39,0x10,
+0,0x71,0xf0,0x6,0,0x60,0x70,0x3,0,0,
+0,0x1,0x8c,0xc,0xc,0,0x30,0x1e,0x2,0x30,
+0xf,0x8f,0x38,0x3,0x1,0xe0,0xc0,0xc6,0x18,0x3,
+0x83,0xff,0xc1,0xc0,0x3,0x6,0x1c,0x62,0x2,0x18,
+0x6,0x8,0x18,0,0x6,0,0xc3,0x4,0x6,0x4,
+0x60,0,0x6,0,0xc0,0xc0,0x18,0x1f,0,0xc,
+0,0x26,0x4,0x60,0x8c,0x10,0xc0,0x3,0xc,0x1c,
+0x60,0x1,0x86,0xe,0x3,0xc0,0x3,0,0x30,0x4,
+0x6,0x8,0x3,0xb,0x18,0,0x60,0,0xcc,0,
+0x70,0xc,0xc,0x6,0x30,0x60,0,0,0x18,0xc3,
+0xc,0x20,0xc6,0x18,0x41,0x8c,0x18,0x61,0xc7,0xc,
+0x30,0xcc,0xc,0x38,0xf1,0xc3,0x8e,0x18,0x61,0x86,
+0x18,0x61,0xdb,0x8,0x60,0xc1,0x8c,0x11,0x83,0x8,
+0x31,0x86,0x8,0x86,0x4,0x6,0x2,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,0x2,0x1c,0x7e,0x3,0x6,
+0x3,0xc0,0x1,0xe,0,0x22,0,0x20,0,0x66,
+0x3f,0xfc,0,0x41,0x18,0x40,0,0x7,0xff,0x88,
+0x46,0,0x30,0x61,0xe4,0,0,0x40,0x1,0x98,
+0x8,0x61,0x2,0x19,0xc4,0x66,0x10,0,0x1,0xc,
+0,0x86,0,0x43,0,0x21,0x80,0x10,0xc0,0x8,
+0x60,0x4,0x60,0x83,0,0,0xc1,0x1,0x82,0x3,
+0x4,0x6,0x8,0xc,0xc,0x6,0x6,0x6,0,0xc2,
+0x30,0x43,0,0xc,0xc0,0x3,0x30,0,0xcc,0,
+0x33,0,0xc,0x30,0xc3,0x2,0xc,0x30,0x4,0xc,
+0x1,0x3,0,0x40,0xc0,0x10,0xc,0xc0,0x30,0x18,
+0xd8,0xc,0x61,0x8c,0x31,0x86,0x30,0xc6,0x18,0xc3,
+0x18,0x62,0xc,0x41,0x88,0x31,0x6,0x20,0xc6,0x18,
+0x61,0x86,0x18,0x71,0xc3,0xc,0x30,0xc3,0xc,0x30,
+0xc3,0xc,0,0,0xc7,0xc,0x18,0x60,0xc3,0x6,
+0x18,0x31,0x82,0x18,0x63,0x4,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,0,0,
+0,0,0,0,0,0,0,0,0,0x60,
+0,0x8,0x80,0x3c,0x1e,0x30,0,0xf0,0xc0,0x6,
+0,0x60,0x20,0x3,0,0,0,0x1,0xc,0xc,
+0xc,0,0x30,0x7,0x6,0x30,0x3,0x8c,0x18,0x2,
+0x3,0x70,0x61,0xc0,0,0xe,0x3,0xff,0xc0,0x70,
+0x6,0x6,0x18,0x62,0x2,0xc,0x7,0xfc,0x18,0,
+0x6,0,0xc3,0xfc,0x7,0xfc,0x60,0,0x7,0xff,
+0xc0,0xc0,0x18,0x1f,0x80,0xc,0,0x23,0x4,0x60,
+0x86,0x10,0xc0,0x3,0xf,0xf0,0x60,0x1,0x87,0xf8,
+0x1,0xf0,0x3,0,0x30,0x4,0x3,0x18,0x1,0x93,
+0x18,0,0x70,0,0x68,0,0x60,0xc,0x4,0x6,
+0x20,0x20,0,0,0,0xc3,0x6,0x60,0xc,0x18,
+0xc1,0x8c,0x18,0x61,0x83,0xc,0x30,0xc8,0xc,0x30,
+0x60,0xc3,0x6,0x30,0x31,0x83,0x30,0x61,0x83,0x80,
+0x60,0xc1,0x86,0x10,0xc3,0x8,0x39,0x3,0x8,0xe,
+0xc,0x6,0x3,0x3,0x82,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,0x6,0x20,0x18,0x3,0x6,0x1,0x80,0x1,0x6,
+0,0x22,0,0x27,0xe0,0xcc,0x3f,0xfc,0,0x41,
+0xf0,0x40,0,0x7,0xff,0x91,0x44,0,0x30,0x61,
+0xe4,0,0,0x43,0xf0,0xcc,0x8,0x43,0x2,0x12,
+0x64,0x44,0x30,0,0x1,0x6,0,0x83,0,0x41,
+0x80,0x20,0xc0,0x10,0x60,0x8,0x30,0x4,0x7f,0x83,
+0,0,0xff,0x1,0xfe,0x3,0xfc,0x7,0xf8,0xc,
+0xc,0x6,0x6,0x3f,0xc0,0xc2,0x18,0x43,0,0xc,
+0xc0,0x3,0x30,0,0xcc,0,0x33,0,0xc,0x19,
+0x83,0x4,0xc,0x30,0x4,0xc,0x1,0x3,0,0x40,
+0xc0,0x10,0x6,0x80,0x30,0x18,0xce,0,0x60,0xc,
+0x1,0x80,0x30,0x6,0,0xc0,0x18,0x66,0,0xc1,
+0x98,0x33,0x6,0x60,0xc6,0x18,0x61,0x8c,0xc,0x60,
+0xc6,0x6,0x60,0x66,0x6,0x60,0x66,0x6,0,0x1,
+0x8d,0x8c,0x18,0x60,0xc3,0x6,0x18,0x30,0xc2,0x18,
+0x31,0x84,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,0,0,0,0,0,0,
+0,0,0,0,0,0x60,0,0x8,0x80,0x3e,
+0,0x63,0xc1,0xb8,0x80,0x6,0,0x60,0,0x7f,
+0xf8,0,0,0x3,0xc,0xc,0xc,0,0x60,0x3,
+0x84,0x30,0x1,0xcc,0xc,0x6,0x6,0x18,0x73,0xc0,
+0,0x38,0,0,0,0x1c,0x6,0x6,0x30,0x62,
+0x6,0xc,0x6,0x7,0x18,0,0x6,0,0xc3,0x4,
+0x6,0x4,0x60,0x1f,0x86,0,0xc0,0xc0,0x18,0x19,
+0xc0,0xc,0,0x23,0x8,0x60,0x86,0x10,0xc0,0x3,
+0xc,0,0x60,0x1,0x86,0x70,0,0x78,0x3,0,
+0x30,0x4,0x3,0x10,0x1,0x93,0x10,0,0xb8,0,
+0x78,0,0xe0,0xc,0x6,0x6,0,0,0,0,
+0x3,0xc3,0x6,0x60,0xc,0x18,0xff,0x8c,0x18,0x61,
+0x83,0xc,0x30,0xd0,0xc,0x30,0x60,0xc3,0x6,0x30,
+0x31,0x83,0x30,0x61,0x81,0xc0,0x60,0xc1,0x86,0x10,
+0xc3,0x8,0x1a,0x3,0x8,0x1c,0x8,0x6,0x1,0x7,
+0xc6,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,0x6,0x20,0x18,
+0x3,0x6,0xf,0xf0,0x1,0x86,0,0x22,0,0x20,
+0x1,0x98,0,0xc,0,0x41,0x20,0x40,0,0,
+0x30,0x3f,0x38,0,0x30,0x60,0xe4,0x30,0x1,0xf0,
+0,0x66,0x3e,0xc7,0xf,0xb4,0x63,0x8c,0x70,0x8,
+0x3,0x6,0x1,0x83,0,0xc1,0x80,0x60,0xc0,0x30,
+0x60,0x18,0x30,0xc,0x60,0x83,0,0,0xc1,0x1,
+0x82,0x3,0x4,0x6,0x8,0xc,0xc,0x6,0x6,0x6,
+0,0xc2,0x18,0x43,0,0xc,0xc0,0x3,0x30,0,
+0xcc,0,0x33,0,0xc,0xf,0x3,0x4,0xc,0x30,
+0x4,0xc,0x1,0x3,0,0x40,0xc0,0x10,0x7,0x80,
+0x30,0x18,0xc7,0x1,0xe0,0x3c,0x7,0x80,0xf0,0x1e,
+0x3,0xc0,0x7f,0xe6,0,0xff,0x9f,0xf3,0xfe,0x7f,
+0xc6,0x18,0x61,0x8c,0xc,0x60,0xc6,0x6,0x60,0x66,
+0x6,0x60,0x66,0x6,0x7f,0xf9,0x89,0x8c,0x18,0x60,
+0xc3,0x6,0x18,0x30,0xc2,0x18,0x31,0x84,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0x60,0,0x7f,0xe0,0x27,0,0x46,0x63,0x19,
+0,0x6,0,0x60,0,0x7f,0xf8,0x3,0xf8,0x3,
+0xc,0xc,0xc,0,0x40,0x1,0x8c,0x30,0,0xcc,
+0xc,0x6,0x4,0x1c,0x1d,0x80,0,0x60,0,0,
+0,0x6,0x4,0x6,0x30,0xc2,0x7,0xfc,0x6,0x3,
+0x18,0,0x6,0,0xc3,0x4,0x6,0x4,0x60,0x6,
+0x6,0,0xc0,0xc0,0x18,0x18,0xe0,0xc,0,0x21,
+0x88,0x60,0x83,0x10,0xc0,0x3,0xc,0,0x60,0x1,
+0x86,0x38,0,0x1c,0x3,0,0x30,0x4,0x3,0x10,
+0x1,0x91,0x90,0x1,0x1c,0,0x30,0x1,0xc0,0xc,
+0x6,0x6,0,0,0,0,0xe,0xc3,0x6,0x60,
+0xc,0x18,0xc0,0xc,0x18,0x61,0x83,0xc,0x30,0xf0,
+0xc,0x30,0x60,0xc3,0x6,0x30,0x31,0x83,0x30,0x61,
+0x81,0xf0,0x60,0xc1,0x86,0x20,0xc5,0x90,0xc,0x3,
+0x10,0x18,0x30,0x6,0,0xcc,0x7c,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,0xc6,0x40,0x18,0x1,0x8c,0x1,0x80,
+0x61,0xc4,0,0x23,0,0x20,0x3,0x30,0,0xc,
+0xfe,0x41,0x10,0x40,0,0,0x30,0,0,0,
+0x30,0x60,0x64,0x30,0,0,0,0x33,0,0x85,
+0,0x20,0x60,0x8,0x50,0x8,0x3,0xfe,0x1,0xff,
+0,0xff,0x80,0x7f,0xc0,0x3f,0xe0,0x1f,0xf0,0xf,
+0xe0,0x83,0,0,0xc1,0x1,0x82,0x3,0x4,0x6,
+0x8,0xc,0xc,0x6,0x6,0x6,0,0xc2,0xc,0x43,
+0,0xc,0xc0,0x3,0x30,0,0xcc,0,0x33,0,
+0xc,0x6,0x3,0x8,0xc,0x30,0x4,0xc,0x1,0x3,
+0,0x40,0xc0,0x10,0x3,0,0x30,0x30,0xc3,0x7,
+0x60,0xec,0x1d,0x83,0xb0,0x76,0xe,0xc1,0xd8,0x6,
+0,0xc0,0x18,0x3,0,0x60,0x6,0x18,0x61,0x8c,
+0xc,0x60,0xc6,0x6,0x60,0x66,0x6,0x60,0x66,0x6,
+0x7f,0xf9,0x99,0x8c,0x18,0x60,0xc3,0x6,0x18,0x30,
+0xc4,0x18,0x31,0x88,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,0,0,0,0,
+0,0,0,0,0,0,0,0x60,0,0x7f,
+0xe0,0x23,0,0xcc,0x26,0xd,0,0x6,0,0x60,
+0,0x3,0,0x3,0xf8,0x2,0xc,0xc,0xc,0,
+0xc0,0x1,0x8f,0xfc,0,0xcc,0xc,0x4,0xc,0xc,
+0x1,0x80,0,0x38,0x3,0xff,0xc0,0x1c,0x4,0x6,
+0x30,0xc6,0x4,0x6,0x6,0x1,0x98,0,0x6,0,
+0xc3,0,0x6,0,0x60,0x6,0x6,0,0xc0,0xc0,
+0x18,0x18,0x70,0xc,0,0x21,0x88,0x60,0x81,0x90,
+0xc0,0x3,0xc,0,0x60,0x1,0x86,0x18,0,0xc,
+0x3,0,0x30,0x4,0x1,0xb0,0,0xd1,0xb0,0x3,
+0xc,0,0x30,0x1,0x80,0xc,0x2,0x6,0,0,
+0,0,0x18,0xc3,0x6,0x60,0xc,0x18,0xc0,0xc,
+0xc,0xc1,0x83,0xc,0x30,0xd8,0xc,0x30,0x60,0xc3,
+0x6,0x30,0x31,0x83,0x30,0x61,0x80,0x78,0x60,0xc1,
+0x83,0x20,0x65,0x90,0xe,0x1,0x90,0x38,0x8,0x6,
+0x1,0x8,0x38,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,0xc6,
+0x40,0x18,0x3,0xfe,0xf,0xf0,0x60,0xe8,0,0x31,
+0x6,0x60,0x3,0x30,0,0xc,0xfe,0x61,0x18,0xc0,
+0,0,0x30,0,0,0,0x30,0x60,0x24,0,
+0,0,0,0x33,0x1,0x89,0,0x60,0x40,0x18,
+0x90,0x18,0x2,0x3,0x1,0x1,0x80,0x80,0xc0,0x40,
+0x60,0x20,0x30,0x10,0x18,0x8,0x60,0x3,0,0,
+0xc0,0x1,0x80,0x3,0,0x6,0,0xc,0xc,0x6,
+0x6,0x6,0,0xc2,0x6,0x43,0,0xc,0xc0,0x3,
+0x30,0,0xcc,0,0x33,0,0xc,0xf,0x3,0x8,
+0xc,0x30,0x4,0xc,0x1,0x3,0,0x40,0xc0,0x10,
+0x3,0,0x30,0x70,0xc3,0x8c,0x61,0x8c,0x31,0x86,
+0x30,0xc6,0x18,0xc3,0x18,0x6,0,0xc0,0x18,0x3,
+0,0x60,0x6,0x18,0x61,0x8c,0xc,0x60,0xc6,0x6,
+0x60,0x66,0x6,0x60,0x66,0x6,0,0x1,0x91,0x8c,
+0x18,0x60,0xc3,0x6,0x18,0x30,0x64,0x18,0x30,0xc8,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x11,0x4,0x23,0x1,0x98,
+0x26,0xe,0,0x6,0,0x60,0,0x3,0,0,
+0,0x6,0xe,0x1c,0xc,0x1,0x80,0x1,0x8f,0xfc,
+0,0xcc,0xc,0xc,0xc,0xc,0x3,0x80,0,0xe,
+0x3,0xff,0xc0,0x70,0x4,0x6,0x30,0xc4,0xc,0x6,
+0x6,0x1,0x8c,0,0x6,0x1,0x83,0,0x6,0,
+0x30,0x6,0x6,0,0xc0,0xc0,0x18,0x18,0x38,0xc,
+0,0x20,0xd0,0x60,0x81,0x90,0x60,0x6,0xc,0,
+0x30,0x3,0x6,0xc,0x10,0xc,0x3,0,0x30,0x4,
+0x1,0xa0,0,0xd1,0xa0,0x2,0x6,0,0x30,0x3,
+0x80,0xc,0x3,0x6,0,0,0,0,0x30,0xc3,
+0x6,0x60,0xc,0x18,0xc0,0xc,0xf,0x81,0x83,0xc,
+0x30,0xdc,0xc,0x30,0x60,0xc3,0x6,0x30,0x31,0x83,
+0x30,0x61,0x80,0x1c,0x60,0xc1,0x83,0x20,0x69,0x90,
+0x1b,0x1,0x90,0x30,0xc,0x6,0x3,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,0xc6,0x40,0x18,0x7,0x77,
+0x1,0x80,0x60,0x70,0,0x11,0xdc,0x40,0x1,0x98,
+0,0xc,0,0x23,0x8c,0x80,0,0,0x30,0,
+0,0,0x30,0x60,0x24,0,0,0,0,0x66,
+0x3,0x19,0,0xc0,0x80,0x31,0x90,0x18,0x6,0x3,
+0x3,0x1,0x81,0x80,0xc0,0xc0,0x60,0x60,0x30,0x30,
+0x18,0x18,0x60,0x1,0x80,0,0xc0,0x1,0x80,0x3,
+0,0x6,0,0xc,0xc,0x6,0x6,0x6,0x1,0x82,
+0x6,0x41,0x80,0x18,0x60,0x6,0x18,0x1,0x86,0,
+0x61,0x80,0x18,0x19,0x81,0x90,0x18,0x30,0x4,0xc,
+0x1,0x3,0,0x40,0xc0,0x10,0x3,0,0x3f,0xc0,
+0xc1,0x98,0x63,0xc,0x61,0x8c,0x31,0x86,0x30,0xc6,
+0x18,0x6,0,0xc0,0x18,0x3,0,0x60,0x6,0x18,
+0x61,0x8c,0xc,0x60,0xc6,0x6,0x60,0x66,0x6,0x60,
+0x66,0x6,0,0x1,0xb1,0x8c,0x18,0x60,0xc3,0x6,
+0x18,0x30,0x64,0x18,0x30,0xc8,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x11,0x4,0x23,0x1,0x18,0x26,0x6,0,0x6,
+0,0x60,0,0x3,0,0,0,0x6,0x6,0x18,
+0xc,0x3,0,0x1,0,0x30,0,0xce,0xc,0xc,
+0xc,0xc,0x3,0,0,0x3,0x80,0,0x1,0xc0,
+0,0x6,0x31,0xcc,0x8,0x6,0x6,0x1,0x8c,0,
+0x86,0x1,0x83,0,0x86,0,0x30,0x6,0x6,0,
+0xc0,0xc0,0x18,0x18,0x1c,0xc,0x2,0x20,0xd0,0x60,
+0x80,0xd0,0x60,0x6,0xc,0,0x30,0x3,0x6,0xe,
+0x10,0xc,0x3,0,0x30,0x8,0x1,0xe0,0,0xe1,
+0xe0,0x4,0x7,0,0x30,0x3,0,0x8c,0x3,0x6,
+0,0,0,0,0x30,0xc3,0x6,0x70,0xc,0x18,
+0xe0,0xc,0xc,0x1,0x83,0xc,0x30,0xce,0xc,0x30,
+0x60,0xc3,0x6,0x30,0x31,0x83,0x30,0x61,0x80,0xc,
+0x60,0xc1,0x83,0x40,0x68,0xa0,0x33,0x81,0xa0,0x70,
+0x4,0x6,0x2,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,0xc6,0x80,0x18,0x6,0x3,0x1,0x80,0x60,0x38,
+0,0x18,0x70,0xc0,0,0xcc,0,0xc,0,0x30,
+0x1,0x80,0,0,0x30,0,0,0,0x30,0x60,
+0x24,0,0,0,0,0xcc,0x2,0x11,0,0x81,
+0x80,0x21,0x10,0x38,0x4,0x3,0x2,0x1,0x81,0,
+0xc0,0x80,0x60,0x40,0x30,0x20,0x18,0x10,0x60,0x11,
+0x80,0x10,0xc0,0x21,0x80,0x43,0,0x86,0x1,0xc,
+0xc,0x6,0x6,0x6,0x1,0x82,0x3,0x41,0x80,0x18,
+0x60,0x6,0x18,0x1,0x86,0,0x61,0x80,0x18,0x30,
+0xc1,0xa0,0x18,0x30,0x8,0xc,0x2,0x3,0,0x80,
+0xc0,0x20,0x3,0,0x30,0,0xc1,0x98,0x63,0xc,
+0x61,0x8c,0x31,0x86,0x30,0xc6,0x18,0x7,0,0xe0,
+0x1c,0x3,0x80,0x70,0x6,0x18,0x61,0x8c,0xc,0x60,
+0xc6,0x6,0x60,0x66,0x6,0x60,0x66,0x6,0x3,0x1,
+0xa1,0x8c,0x18,0x60,0xc3,0x6,0x18,0x30,0x68,0x18,
+0x30,0xd0,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x11,0x6,0x26,
+0x3,0x18,0x47,0xf,0x8,0x6,0,0x60,0,0x3,
+0,0,0,0x4,0x6,0x18,0xc,0x6,0x4,0xc3,
+0,0x30,0xc1,0x86,0x18,0xc,0xe,0x18,0x6,0,
+0,0,0xe0,0,0x7,0,0,0x3,0x1b,0xd8,
+0x8,0x3,0x6,0x3,0x7,0x1,0x6,0x7,0x3,0,
+0x86,0,0x1c,0xe,0x6,0,0xc0,0xc3,0x18,0x18,
+0xe,0xc,0x2,0x20,0x60,0x60,0x80,0x70,0x38,0x1c,
+0xc,0,0x1c,0xe,0x6,0x7,0x18,0x18,0x3,0,
+0x18,0x8,0,0xc0,0,0x60,0xe0,0xc,0x3,0x80,
+0x30,0x7,0,0x8c,0x1,0x6,0,0,0,0,
+0x31,0xc3,0xc,0x38,0x46,0x18,0x70,0x8c,0x18,0x1,
+0x83,0xc,0x30,0xc7,0xc,0x30,0x60,0xc3,0x6,0x18,
+0x61,0x86,0x18,0x61,0x82,0xc,0x60,0xe3,0x81,0xc0,
+0x38,0xe0,0x21,0x80,0xe0,0x61,0x6,0x6,0x6,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,0xc3,0x84,0x3c,
+0x20,0,0x1,0x80,0x60,0x1c,0,0xc,0x1,0x80,
+0,0x66,0,0,0,0x18,0x3,0,0,0,
+0,0,0,0,0x38,0xe0,0x24,0,0,0,
+0x1,0x98,0x6,0x3f,0xc1,0x81,0,0x63,0xfc,0x30,
+0x4,0x1,0x82,0,0xc1,0,0x60,0x80,0x30,0x40,
+0x18,0x20,0xc,0x10,0x60,0x10,0xe0,0x20,0xc0,0x21,
+0x80,0x43,0,0x86,0x1,0xc,0xc,0x6,0x6,0x6,
+0x7,0x2,0x1,0xc0,0xe0,0x70,0x38,0x1c,0xe,0x7,
+0x3,0x81,0xc0,0xe0,0x70,0x60,0x60,0xe0,0x70,0x18,
+0x8,0x6,0x2,0x1,0x80,0x80,0x60,0x20,0x3,0,
+0x30,0,0xd9,0x98,0xe3,0x1c,0x63,0x8c,0x71,0x8e,
+0x31,0xc6,0x3c,0x23,0x84,0x70,0x8e,0x11,0xc2,0x38,
+0x46,0x18,0x61,0x86,0x18,0x60,0xc3,0xc,0x30,0xc3,
+0xc,0x30,0xc3,0xc,0x3,0,0xe3,0xe,0x38,0x71,
+0xc3,0x8e,0x1c,0x70,0x38,0x18,0x60,0x70,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0x60,0,0x11,0x7,0x2e,0x6,0x1c,0x83,0xfb,
+0xf0,0x3,0,0xc0,0,0x3,0,0xc0,0,0xcc,
+0x3,0x30,0xc,0xf,0xfc,0xe6,0,0x30,0xe3,0x87,
+0xb8,0x18,0x7,0x38,0x1c,0x6,0x18,0,0x30,0,
+0xc,0,0xc,0x3,0xe,0xf0,0x18,0x3,0x6,0xf,
+0x3,0xc7,0x6,0xe,0x3,0x1,0x86,0,0xf,0x1c,
+0x6,0,0xc0,0xc3,0x30,0x18,0x7,0xc,0x6,0x20,
+0x60,0x60,0x80,0x70,0x1c,0x38,0xc,0,0xe,0x1c,
+0x6,0x3,0x9e,0x30,0x3,0,0x1c,0x30,0,0xc0,
+0,0x60,0xc0,0x18,0x1,0xc0,0x30,0xe,0x1,0x8c,
+0x1,0x86,0,0,0,0,0x3e,0xc3,0x9c,0x3f,
+0x87,0x38,0x7f,0xc,0x1f,0xc1,0x83,0xc,0x30,0xc3,
+0x8c,0x30,0x60,0xc3,0x6,0x1c,0xe1,0xce,0x1c,0xe1,
+0x83,0x18,0x64,0x7d,0x81,0xc0,0x38,0xe0,0x60,0xc0,
+0xe0,0xc3,0x6,0x6,0x6,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,0xc3,0xf8,0x5f,0x60,0,0x1,0x80,
+0x60,0xc,0,0x7,0x7,0,0,0x22,0,0,
+0,0xe,0xe,0,0,0x7,0xff,0x80,0,0,
+0x3f,0x60,0x24,0,0,0,0x1,0x10,0x4,0x1,
+0x1,0x2,0x20,0x40,0x10,0x70,0xc,0x1,0x86,0,
+0xc3,0,0x61,0x80,0x38,0xc0,0x18,0x60,0xc,0x30,
+0x60,0x30,0x78,0xe0,0xc0,0x61,0x80,0xc3,0x1,0x86,
+0x3,0xc,0xc,0x6,0x6,0x6,0xe,0x2,0x1,0xc0,
+0x70,0xe0,0x1c,0x38,0x7,0xe,0x1,0xc3,0x80,0x70,
+0xe0,0x40,0x20,0x70,0xe0,0x1c,0x30,0x7,0xc,0x1,
+0xc3,0,0x70,0xc0,0x3,0,0x30,0,0xd9,0x1f,
+0x63,0xec,0x7d,0x8f,0xb1,0xf6,0x3e,0xc7,0xdf,0xc3,
+0xf8,0x7f,0xf,0xe1,0xfc,0x3f,0x86,0x18,0x61,0x87,
+0x38,0x60,0xc3,0x9c,0x39,0xc3,0x9c,0x39,0xc3,0x9c,
+0,0,0xe7,0x7,0xd8,0x3e,0xc1,0xf6,0xf,0xb0,
+0x38,0x1c,0xe0,0x70,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,0,0,0,0,
+0,0,0,0,0,0,0,0x60,0,0x11,
+0x1,0xf8,0xc,0xf,0x1,0xe1,0xe0,0x3,0,0xc0,
+0,0,0,0xe0,0,0xcc,0x1,0xe0,0x7f,0x8f,
+0xf8,0x78,0,0x30,0x7e,0x1,0xe0,0x18,0x1,0xe0,
+0xf0,0x6,0x1c,0,0,0,0,0,0xc,0x1,
+0x80,0,0x7e,0xf,0xdf,0xfc,0,0xfc,0x1f,0xf8,
+0xf,0xff,0x9f,0x80,0x3,0xf0,0x1f,0x83,0xf3,0xf1,
+0xe0,0x7e,0xf,0xbf,0xfe,0xf8,0x21,0xfb,0xe0,0x30,
+0x7,0xe0,0x3f,0,0x3,0xf0,0x1f,0x83,0xd3,0xc0,
+0xf,0xc0,0x7,0xe0,0,0xc0,0,0x60,0xc0,0x7e,
+0x7,0xe0,0xfc,0xf,0xff,0x8c,0x1,0x86,0,0,
+0,0,0x1c,0x62,0xf0,0xf,0x1,0xec,0x1e,0x1e,
+0xf,0xf3,0xc7,0x9e,0x31,0xe7,0xde,0x78,0xf1,0xe7,
+0x8f,0x7,0x81,0xb8,0x7,0x63,0xc3,0xe0,0x38,0x39,
+0xc0,0x80,0x10,0x40,0xf1,0xe0,0x40,0xff,0x6,0x6,
+0x6,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,0xc1,
+0xf0,0x73,0xc0,0,0x7,0xe0,0x60,0xc4,0,0x1,
+0xfc,0,0,0,0,0,0,0x3,0xf8,0,
+0,0x7,0xff,0x80,0,0,0x2e,0x70,0x24,0,
+0,0,0,0,0xc,0x1,0x3,0x7,0xe0,0xc0,
+0x10,0xe0,0x3f,0x7,0xff,0x83,0xff,0xc1,0xff,0xe0,
+0xff,0xf0,0x7f,0xf8,0x3f,0xf9,0xff,0xf0,0x1f,0x83,
+0xff,0xe7,0xff,0xcf,0xff,0x9f,0xff,0x3f,0x3f,0x1f,
+0x9f,0x9f,0xf8,0xf,0x80,0xc0,0x1f,0x80,0x7,0xe0,
+0x1,0xf8,0,0x7e,0,0x1f,0x80,0,0,0x9f,
+0x80,0x7,0xe0,0x1,0xf8,0,0x7e,0,0x1f,0x80,
+0xf,0xc0,0xfc,0x1,0xce,0xe,0x31,0xc6,0x38,0xc7,
+0x18,0xe3,0x1c,0x63,0x87,0x80,0xf0,0x1e,0x3,0xc0,
+0x78,0xf,0xf,0x3c,0xf3,0xc1,0xe0,0xf1,0xe0,0xf0,
+0xf,0,0xf0,0xf,0,0xf0,0,0x1,0xbc,0x3,
+0x9c,0x1c,0xe0,0xe7,0x7,0x38,0x10,0x1b,0x80,0x20,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0x20,0,0,
+0,0,0,0x1,0,0x80,0,0,0,0x20,
+0,0x18,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x4,0,
+0,0,0,0,0,0,0xc0,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,0xe0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xc,0,0x6,0,0,0,0,0,0,
+0,0,0,0,0,0,0x18,0x18,0,0,
+0x30,0,0,0,0,0,0,0,0x1,0x80,
+0,0x60,0,0,0,0,0,0,0,0,
+0,0,0xc0,0,0x6,0,0x6,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,0xc2,0,0,0,0,
+0,0,0,0xc8,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x20,0,0x24,0,0x20,0,0,0,
+0,0,0,0,0,0,0,0xc3,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x4,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,0x80,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,0x40,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x1,0x80,0,0,0,0,0,
+0,0,0x30,0x18,0,0x60,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,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x20,0,0,0,0,0,0x1,
+0x81,0x80,0,0,0,0x60,0,0x18,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xc,0,0,0,0,0,
+0,0,0x70,0x60,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,0x70,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xc,0,0x6,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x30,0x8,0,0,0x30,0,0,0,
+0,0,0,0,0x1,0x80,0,0x60,0,0,
+0,0,0,0,0,0,0,0,0x80,0,
+0x6,0,0x6,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,0xc2,0,0,0,0,0,0,0,0x70,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x20,0,
+0x24,0,0x60,0,0,0,0,0,0,0,
+0,0,0,0xc3,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0xc,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,0xc0,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,0x20,0x18,
+0,0x40,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,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x81,0,0,0,
+0,0xc0,0,0x18,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x18,0,0,0,0,0,0,0,0x1f,0x80,
+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,0x38,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xc,0,0x6,0,0,0,0,
+0,0,0,0,0,0,0,0,0x30,0x18,
+0,0,0x30,0,0,0,0,0,0,0,
+0x1,0x80,0,0x60,0,0,0,0,0,0,
+0,0,0,0x1,0x80,0,0x6,0,0x6,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,0xc0,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,0x60,0,0x24,0,0x78,0,
+0,0,0,0,0,0,0,0,0,0xc1,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xf,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,0xf0,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,0x60,0x18,0,0xc0,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,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x42,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,0x1c,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xf,
+0x80,0x3e,0,0xf,0xff,0x80,0,0,0,0,
+0,0,0,0,0x3c,0x70,0,0,0xe0,0,
+0,0,0,0,0,0,0x1,0x80,0,0x60,
+0,0,0,0,0,0,0,0,0,0xf,
+0,0,0x3,0,0xc,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,0xc0,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,
+0x70,0,0x24,0,0x18,0,0,0,0,0,
+0,0,0,0,0,0x63,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x3,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,
+0x30,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,0x3,
+0xc0,0x18,0x7,0x80,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,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x24,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,0x7,0x80,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xf,
+0xff,0x80,0,0,0,0,0,0,0,0,
+0xf,0xc0,0,0,0xc0,0,0,0,0,0,
+0,0,0x3,0xc0,0,0xf0,0,0,0,0,
+0,0,0,0,0,0xe,0,0,0x1,0xc0,
+0x38,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,0xc0,
+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,0x20,0,0x24,0x1,
+0x98,0,0,0,0,0,0,0,0,0,
+0,0x3e,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x33,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,0x3,0x30,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,0x3,0x80,0x3c,0x7,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,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,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,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,0xf0,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,0x1e,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,0x1,0xe0,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,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,
+};
+
+static WORD Times24_ch_ofst[225] = {
+0,6,14,24,37,49,68,86,92,100,
+108,120,134,141,150,156,163,175,187,199,
+211,223,235,247,259,271,283,289,296,309,
+323,336,347,369,386,402,418,435,450,464,
+482,501,509,520,537,551,573,591,609,624,
+642,658,671,687,705,722,745,763,779,794,
+802,809,817,828,841,849,860,872,883,895,
+906,913,925,938,944,950,962,968,988,1001,
+1013,1025,1037,1045,1055,1062,1075,1086,1103,1116,
+1127,1137,1147,1153,1163,1176,1182,1188,1194,1200,
+1206,1212,1218,1224,1230,1236,1242,1248,1254,1260,
+1266,1272,1278,1284,1290,1296,1302,1308,1314,1320,
+1326,1332,1338,1344,1350,1356,1362,1368,1374,1380,
+1388,1400,1412,1425,1439,1445,1457,1465,1484,1492,
+1505,1519,1528,1547,1555,1564,1578,1585,1592,1600,
+1613,1624,1630,1638,1645,1653,1665,1683,1701,1719,
+1730,1747,1764,1781,1798,1815,1832,1853,1869,1884,
+1899,1914,1929,1937,1945,1954,1962,1979,1997,2015,
+2033,2051,2069,2087,2101,2119,2137,2155,2173,2191,
+2207,2222,2234,2245,2256,2267,2278,2289,2300,2316,
+2327,2338,2349,2360,2371,2377,2383,2389,2395,2407,
+2420,2432,2444,2456,2468,2480,2494,2506,2519,2532,
+2545,2558,2569,2581,2592,
+};
+
+static struct font_hdr Times24_font = {
+STPROP, 24, "-Adobe-Times-M-R-N--24-240-75-7", 32, 255,
+28, 22, 14, 6, 6,
+24, 23, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Times24_ch_ofst, Times24_data,
+406, 28,
+NULL,
+0, 0,   /* x/y offset */
+31,        /* lineHeight */
+22,	/* psHeight */
+};
+
+MgFont *mgTimes24Font()
+{
+return &Times24_font;
+}
diff --git a/lib/font/mgTimes34.c b/lib/font/mgTimes34.c
new file mode 100644
index 0000000..19e2c1f
--- /dev/null
+++ b/lib/font/mgTimes34.c
@@ -0,0 +1,1962 @@
+
+/* Times34.c - compiled data for font -Adobe-Times-M-R-N--34-240-100- */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 100dpi/timR24.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Times34_data[19055] = {
+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,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,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,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,0,0,
+0,0,0,0x3,0,0,0,0,0xc0,0,
+0x18,0,0,0,0,0,0,0,0,0x38,
+0,0,0,0,0,0,0,0,0x18,0,
+0,0x3,0,0x1,0x80,0,0,0x3,0,0x1,
+0x81,0x80,0,0,0,0,0,0,0,0x1,
+0x80,0,0,0,0xc0,0,0x18,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0xc,0,0,0,0x18,0,0x1,0x80,0,0,
+0,0,0,0xc,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,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,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,
+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,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,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,0,0,0x3,0x80,
+0,0,0x1,0xc0,0,0x3c,0,0,0,0,
+0,0,0,0,0x7c,0,0,0,0,0,
+0,0,0,0x1c,0,0,0x7,0,0x3,0xc0,
+0,0,0x3,0x80,0x3,0x83,0xc0,0,0,0,
+0,0,0x70,0x40,0x1,0xc0,0,0,0x1,0xc0,
+0,0x3c,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xe,0,0,0,0x38,
+0,0x3,0xc0,0,0,0,0,0,0x1c,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,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,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,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,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,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,0,0,0x1,0xc0,0,0,0x3,0x80,0,
+0x7e,0,0,0x70,0x40,0,0xe3,0x80,0,0xc6,
+0,0,0,0,0,0,0,0,0xe,0,
+0,0xe,0,0x7,0xe0,0x1,0xc7,0x1,0xc0,0x7,
+0x7,0xe3,0x8e,0,0,0,0,0xfc,0xc0,0,
+0xe0,0,0,0x3,0x80,0,0x7e,0,0,0x70,
+0x40,0,0xe3,0x80,0,0,0,0,0,0,
+0x7,0,0,0,0x70,0,0x7,0xe0,0,0x1c,
+0x70,0,0,0x38,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,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,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,
+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,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,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,0,0,0,0x60,
+0,0,0x6,0,0,0xe7,0,0,0xfc,0xc0,
+0,0xe3,0x80,0,0x82,0,0,0,0,0,
+0,0,0,0x3,0,0,0x18,0,0xe,0x70,
+0x1,0xc7,0,0x60,0xc,0xe,0x73,0x8e,0,0,
+0,0x1,0x9f,0x80,0,0x30,0,0,0x6,0,
+0,0xe7,0,0,0xfc,0xc0,0,0xe3,0x80,0,
+0,0,0,0,0,0x1,0x80,0,0,0xc0,
+0,0xe,0x70,0,0x1c,0x70,0,0,0x60,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,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,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,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,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,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,0,0,0,0x30,0,0,0xc,0,0x1,
+0x81,0x80,0x1,0x9f,0x80,0,0xe3,0x80,0,0xc6,
+0,0,0,0,0,0,0,0,0x1,0x80,
+0,0x30,0,0x18,0x18,0x1,0xc7,0,0x30,0x18,
+0x18,0x1b,0x8e,0,0,0,0x1,0x7,0,0,
+0x18,0,0,0xc,0,0x1,0x81,0x80,0x1,0x9f,
+0x80,0,0xe3,0x80,0,0,0,0,0,0,
+0,0xc0,0,0x1,0x80,0,0x18,0x18,0,0x1c,
+0x70,0,0,0xc0,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,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,0,0,
+0,0,0x20,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,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,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,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,0x18,
+0,0,0x18,0,0x1,0,0x80,0x1,0x7,0,
+0,0,0,0,0x7c,0,0,0,0,0,
+0,0,0,0,0xc0,0,0x60,0,0x10,0x8,
+0,0,0,0x18,0x30,0x10,0x8,0,0,0,
+0,0,0,0,0,0xc,0,0,0x18,0,
+0x1,0,0x80,0x1,0x7,0,0,0,0,0,
+0,0,0,0x1,0,0,0x60,0,0x3,0,
+0,0x10,0x8,0,0,0,0,0x1,0x80,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,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,0,0,0,0,0x20,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,
+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,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,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,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x38,
+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,0x3,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,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,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xc,0x7,0x1c,0x3,
+0xc,0,0xfc,0,0xf0,0x4,0,0x1,0xf0,0,
+0xe0,0x6,0x60,0,0x30,0,0,0,0,0,
+0,0,0x30,0x3c,0,0xc,0,0x7e,0,0x3e,
+0,0x3,0,0x7f,0xc0,0x3,0xc1,0xff,0xe0,0x7e,
+0,0x3c,0,0,0,0,0,0,0,0,
+0,0,0xf,0x80,0,0x3f,0xe0,0,0x1,0x80,
+0x7,0xff,0xf0,0,0x3f,0xe2,0x7f,0xff,0,0x7f,
+0xff,0xe7,0xff,0xfc,0x3,0xfe,0x61,0xff,0xf,0xf9,
+0xff,0x7,0xfd,0xff,0x8f,0xf1,0xff,0,0x1f,0x80,
+0,0xfe,0x7c,0,0xfe,0,0xff,0,0x7f,0xfc,
+0,0x3f,0xc0,0x1f,0xff,0,0x3,0xf2,0x1f,0xff,
+0xfd,0xff,0x3,0xf9,0xfe,0x3,0xfb,0xfc,0xff,0x83,
+0xfb,0xff,0xf,0xf3,0xff,0x3,0xf0,0xff,0xff,0x8f,
+0xf0,0,0xfe,0,0xe0,0,0,0xc,0,0,
+0,0xc0,0,0,0,0,0xc0,0,0,0x7c,
+0,0,0x30,0,0x38,0xe,0xc,0,0x6,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,0x3c,
+0xc,0x7,0x80,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,0x1,0xf0,0,0,0x7f,0xf,0xcc,
+0x3,0xf0,0,0,0x3,0xf0,0,0xf0,0,0,
+0,0,0,0,0x3,0xf8,0,0,0x7,0x80,
+0,0,0x1e,0x7,0xc0,0x6,0,0,0x1,0xfe,
+0,0,0x1,0x81,0xf0,0,0,0x18,0,0x30,
+0x18,0,0x60,0x1f,0,0xc,0,0,0,0x18,
+0,0,0x18,0,0,0x18,0,0,0x18,0,
+0,0x18,0,0,0,0,0,0x7f,0xff,0xf0,
+0x3,0xfe,0x27,0xff,0xfe,0x7f,0xff,0xe7,0xff,0xfe,
+0x7f,0xff,0xe7,0xfc,0xff,0x9f,0xf3,0xfe,0x7f,0xff,
+0,0x7c,0,0xfe,0,0xff,0,0,0xff,0,
+0,0xff,0,0,0xff,0,0,0xff,0,0,
+0,0,0x1f,0xe6,0xf,0xf8,0x1f,0xcf,0xf8,0x1f,
+0xcf,0xf8,0x1f,0xcf,0xf8,0x1f,0xcf,0xfc,0xf,0xcf,
+0xf8,0,0xf,0x80,0x18,0,0x1,0x80,0x18,0,
+0,0,0,0,0xe0,0,0,0,0,0,
+0x60,0,0x6,0,0x30,0,0,0x18,0,0x60,
+0xc0,0,0x10,0,0,0,0xc,0,0,0x60,
+0x1,0x80,0,0,0,0,0,0,0,0,
+0,0xc0,0,0x3,0,0x6,0,0,0,0,
+0x18,0xc,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,0,0,0,0,0,0,
+0,0x1e,0x7,0x1c,0x3,0xc,0x3,0xa7,0x1,0xd8,
+0x3c,0,0x3,0x18,0,0xe0,0xc,0x30,0,0x78,
+0,0,0,0,0,0,0,0x30,0xe7,0,
+0x1c,0,0xff,0,0xff,0,0x7,0,0xff,0x80,
+0xe,0x3,0xff,0xe0,0xe3,0x80,0xc7,0,0,0,
+0,0,0,0,0,0,0,0x39,0xc0,0x1,
+0xf0,0x78,0,0x1,0x80,0x1,0xf0,0x7c,0,0xf0,
+0x7e,0x1f,0x3,0xc0,0x1f,0x1,0xe1,0xf0,0x3c,0xf,
+0xf,0xe0,0x7c,0x3,0xe0,0x7c,0x1,0xf0,0x7c,0x3,
+0xc0,0x7c,0,0x7,0xc0,0,0xf8,0x1e,0,0x38,
+0x3,0xc3,0xc0,0x1e,0x1f,0,0xf0,0xf0,0x7,0x87,
+0xc0,0xe,0x1e,0x1e,0x1c,0x3c,0x7c,0,0xe0,0xf8,
+0,0xe1,0xf0,0x3e,0x1,0xe0,0xfc,0x3,0xc0,0xfc,
+0,0xe0,0xe0,0xf,0xf,0x38,0,0x1e,0,0xe0,
+0,0,0xe,0,0,0x7,0xc0,0,0,0,
+0x7,0xc0,0,0,0xce,0,0x1,0xf0,0,0x38,
+0xe,0x7c,0,0x3e,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,0x70,0xc,0x1,0xc0,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,0x3,0x98,
+0,0,0x3c,0x3,0x8c,0x6,0x38,0,0,0xf,
+0xfc,0x1,0x38,0,0,0,0,0,0,0xf,
+0xfc,0,0,0xf,0xc0,0,0,0x27,0x8,0xe0,
+0xe,0,0,0x7,0x88,0,0,0x7,0x83,0x18,
+0,0,0x78,0,0x30,0x78,0,0x60,0x23,0x80,
+0xc,0,0,0,0x18,0,0,0x18,0,0,
+0x18,0,0,0x18,0,0,0x18,0,0,0x18,
+0,0,0xf,0xc0,0xf0,0xf,0x7,0xe1,0xf0,0x1e,
+0x1f,0x1,0xe1,0xf0,0x1e,0x1f,0x1,0xe1,0xf0,0x3e,
+0x7,0xc0,0xf8,0x1f,0x3,0xc0,0x1e,0,0x38,0x3,
+0xc3,0xc0,0x3,0xc3,0xc0,0x3,0xc3,0xc0,0x3,0xc3,
+0xc0,0x3,0xc3,0xc0,0,0,0,0x78,0x7c,0x3,
+0xe0,0x7,0x3,0xe0,0x7,0x3,0xe0,0x7,0x3,0xe0,
+0x7,0x3,0xf0,0x3,0x83,0xe0,0,0x18,0xe0,0x1c,
+0,0x3,0x80,0x3c,0,0,0,0,0x1,0xf0,
+0,0,0,0,0,0x70,0,0xe,0,0x78,
+0,0,0x1c,0,0xe1,0xe0,0,0x38,0,0,
+0,0xe,0,0,0xe0,0x3,0xc0,0,0,0,
+0,0,0,0,0,0,0xe0,0,0x7,0,
+0xf,0,0,0,0,0x38,0x7c,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,0,
+0,0,0,0,0,0,0x1e,0x7,0x1c,0x3,
+0xc,0x3,0x23,0x83,0x8f,0xc8,0,0x6,0x1c,0,
+0xe0,0x18,0x18,0,0x30,0,0,0,0,0,
+0,0,0x61,0xc3,0x80,0x7c,0x1,0xcf,0x81,0x87,
+0x80,0x7,0,0xff,0,0x1c,0x3,0,0xc1,0xc1,
+0xc1,0x83,0x80,0,0,0,0,0,0,0,
+0,0,0x60,0xe0,0x3,0xc0,0xc,0,0x3,0x80,
+0,0xe0,0x1e,0x1,0xc0,0x1e,0xe,0,0xe0,0xe,
+0,0x60,0xe0,0xc,0x1c,0x1,0xe0,0x38,0x1,0xc0,
+0x38,0,0xe0,0x38,0x3,0,0x38,0,0x3,0xc0,
+0x1,0xf0,0xf,0,0x10,0x7,0,0xe0,0xe,0x7,
+0x81,0xc0,0x38,0x3,0x81,0xe0,0x1c,0xe,0x18,0x1c,
+0xc,0x38,0,0x40,0x78,0,0xc0,0xf0,0x1c,0,
+0xc0,0x7c,0x3,0x80,0x78,0,0xc1,0x80,0x1e,0xe,
+0x18,0,0xe,0x1,0xf0,0,0,0x7,0,0,
+0x1,0xc0,0,0,0,0x1,0xc0,0,0x1,0x8e,
+0,0,0x70,0,0x38,0xe,0x1c,0,0xe,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,0xe0,
+0xc,0,0xe0,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,0x6,0x1c,0,0,0x1c,0x3,0xc,
+0xc,0x38,0x1c,0x70,0x38,0x7,0x3,0x18,0,0,
+0,0,0,0,0x38,0x7,0,0,0x18,0x60,
+0,0,0x43,0x90,0x60,0x1c,0,0,0xf,0x88,
+0,0,0x1,0x86,0x1c,0,0,0x18,0,0x60,
+0x18,0,0xc0,0x41,0x80,0x18,0,0,0,0x38,
+0,0,0x38,0,0,0x38,0,0,0x38,0,
+0,0x38,0,0,0x18,0,0,0xf,0x80,0x30,
+0x1c,0x1,0xe0,0xe0,0x6,0xe,0,0x60,0xe0,0x6,
+0xe,0,0x60,0xe0,0x1c,0x3,0x80,0x70,0xe,0,
+0xe0,0xf,0,0x10,0x7,0,0xe0,0x7,0,0xe0,
+0x7,0,0xe0,0x7,0,0xe0,0x7,0,0xe0,0,
+0,0,0xe0,0x1c,0x1,0xc0,0x2,0x1,0xc0,0x2,
+0x1,0xc0,0x2,0x1,0xc0,0x2,0x1,0xe0,0x3,0x1,
+0xc0,0,0x30,0x70,0xe,0,0x7,0,0x7e,0,
+0xe0,0x83,0x8e,0x3,0x18,0,0,0,0,0,
+0x38,0,0x1c,0,0xfc,0x3,0x8e,0xe,0x1,0xc3,
+0xf3,0x8e,0x1c,0x70,0xe,0x8,0x7,0,0x1,0xc0,
+0x7,0xe0,0xe,0x8,0x1c,0x70,0,0,0,0,
+0,0x70,0,0xe,0,0x1f,0x80,0x38,0xe0,0,
+0x70,0x1c,0,0x3,0x8e,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,0,0,0,
+0,0x1e,0x7,0x1c,0x3,0xc,0x6,0x21,0x87,0x4,
+0x18,0,0x6,0xc,0,0xe0,0x30,0xc,0x6,0x31,
+0x80,0,0,0,0,0,0,0x61,0x81,0x80,
+0xdc,0x3,0x3,0xc3,0x3,0x80,0xf,0,0x80,0,
+0x78,0x6,0,0xc3,0x80,0xc3,0x81,0xc0,0,0,
+0,0,0,0,0,0,0,0x60,0xe0,0xf,
+0,0x6,0,0x3,0xc0,0,0xe0,0xe,0x3,0x80,
+0xe,0xe,0,0x70,0xe,0,0x20,0xe0,0x4,0x38,
+0,0xe0,0x38,0x1,0xc0,0x38,0,0xe0,0x38,0x6,
+0,0x38,0,0x3,0xe0,0x1,0xf0,0xf,0x80,0x10,
+0xe,0,0x70,0xe,0x3,0x83,0x80,0x1c,0x3,0x80,
+0xf0,0x38,0x6,0x18,0x1c,0xc,0x38,0,0x40,0x3c,
+0,0x80,0x70,0x1e,0,0xc0,0x3c,0x3,0,0x3c,
+0x1,0x81,0x80,0x1e,0xe,0x1c,0,0xe,0x1,0xb0,
+0,0,0x1,0x80,0,0x1,0xc0,0,0,0,
+0x1,0xc0,0,0x1,0x86,0,0,0x70,0,0,
+0,0x1c,0,0xe,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,0xe0,0xc,0,0xe0,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,0x6,0x1c,
+0xc7,0xe3,0x1e,0x2,0xc,0xc,0x38,0x1c,0x70,0x60,
+0x1,0x83,0x18,0,0,0,0,0,0,0x60,
+0x1,0x83,0xff,0x30,0x30,0x3,0,0x1,0x80,0x60,
+0x30,0,0,0x1f,0x88,0,0,0x1,0x86,0xc,
+0,0,0x18,0,0xe0,0x18,0x1,0xc0,0x1,0x80,
+0x38,0,0,0,0x3c,0,0,0x3c,0,0,
+0x3c,0,0,0x3c,0,0,0x3c,0,0,0x3c,
+0,0,0x1b,0x80,0x10,0x38,0,0xe0,0xe0,0x2,
+0xe,0,0x20,0xe0,0x2,0xe,0,0x20,0xe0,0x1c,
+0x3,0x80,0x70,0xe,0,0x70,0xf,0x80,0x10,0xe,
+0,0x70,0xe,0,0x70,0xe,0,0x70,0xe,0,
+0x70,0xe,0,0x70,0,0,0x1,0xc0,0x1e,0x1,
+0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,
+0x2,0,0xf0,0x6,0x1,0xc0,0,0x30,0x70,0x3,
+0,0xc,0,0xe7,0x1,0xf1,0x83,0x8e,0x2,0x8,
+0,0,0,0,0,0xc,0,0x30,0x1,0xce,
+0x3,0x8e,0x3,0x3,0x7,0x3b,0x8e,0xf,0xf0,0x1f,
+0x18,0x1,0x80,0x3,0,0xe,0x70,0x1f,0x18,0x1c,
+0x70,0,0,0,0,0,0x18,0,0x18,0,
+0x39,0xc0,0x38,0xe0,0,0xc0,0x1c,0,0x3,0x8e,
+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,0,0,0,0,0x1e,0x2,0x8,0x3,
+0xc,0x6,0x20,0x87,0x4,0x30,0,0xe,0xc,0,
+0x40,0x70,0xe,0x7,0xb7,0x80,0,0,0,0,
+0,0,0xe3,0x81,0xc0,0x1c,0x2,0x3,0xc2,0x3,
+0x80,0xb,0x1,0x80,0,0xf0,0x4,0x1,0xc3,0x80,
+0xc3,0x1,0xc0,0,0,0,0,0,0,0,
+0,0,0x70,0x70,0x1c,0,0x3,0,0x3,0xc0,
+0,0xe0,0xf,0x7,0,0x6,0xe,0,0x38,0xe,
+0,0x20,0xe0,0x4,0x70,0,0x60,0x38,0x1,0xc0,
+0x38,0,0xe0,0x38,0xc,0,0x38,0,0x3,0xe0,
+0x1,0x70,0xf,0x80,0x10,0x1c,0,0x38,0xe,0x3,
+0xc7,0,0xe,0x3,0x80,0xf0,0x38,0x2,0x10,0x1c,
+0x4,0x38,0,0x40,0x3c,0x1,0x80,0x78,0x1e,0x1,
+0x80,0x1e,0x6,0,0x3e,0x3,0x1,0,0x3c,0xe,
+0xc,0,0xe,0x3,0x18,0,0,0,0xc0,0,
+0x1,0xc0,0,0,0,0x1,0xc0,0,0x3,0x80,
+0,0,0x70,0,0,0,0x1c,0,0xe,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x20,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xe0,
+0xc,0,0xe0,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,0x40,0xe,0x18,0xff,0xff,0xe,0x6,0xc,
+0xe,0x30,0x1c,0x70,0xc0,0,0xc0,0x78,0,0,
+0,0,0,0,0xc0,0,0xc3,0xff,0x30,0x30,
+0x3,0,0x1,0x80,0x60,0x60,0,0,0x1f,0x88,
+0,0,0x1,0x86,0xc,0,0,0x18,0,0xc0,
+0x18,0x1,0x80,0x1,0x80,0x30,0,0,0,0x3c,
+0,0,0x3c,0,0,0x3c,0,0,0x3c,0,
+0,0x3c,0,0,0x3c,0,0,0x1b,0x80,0x10,
+0x70,0,0x60,0xe0,0x2,0xe,0,0x20,0xe0,0x2,
+0xe,0,0x20,0xe0,0x1c,0x3,0x80,0x70,0xe,0,
+0x38,0xf,0x80,0x10,0x1c,0,0x38,0x1c,0,0x38,
+0x1c,0,0x38,0x1c,0,0x38,0x1c,0,0x38,0,
+0,0x3,0x80,0x37,0x1,0xc0,0x2,0x1,0xc0,0x2,
+0x1,0xc0,0x2,0x1,0xc0,0x2,0,0xf8,0xc,0x1,
+0xc0,0,0x70,0x70,0x1,0x80,0x18,0x1,0x81,0x83,
+0x1f,0x3,0x8e,0x3,0x18,0,0,0,0,0,
+0x6,0,0x60,0x3,0x3,0x3,0x8e,0x1,0x86,0xc,
+0xf,0x8e,0xf,0,0x31,0xf0,0,0xc0,0x6,0,
+0x18,0x18,0x31,0xf0,0x1c,0x70,0,0,0,0,
+0,0xc,0,0x30,0,0x60,0x60,0x38,0xe0,0x1,
+0x80,0x1c,0,0x3,0x8e,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,0,0,0,
+0,0x1e,0x2,0x8,0x3,0xc,0x6,0x20,0x8e,0x4,
+0x20,0,0xe,0xc,0,0x40,0x60,0x6,0x3,0xb7,
+0,0,0,0,0,0,0,0xc3,0x81,0xc0,
+0x1c,0x6,0x1,0xc0,0x3,0x80,0x1b,0x1,0,0,
+0xe0,0,0x1,0x83,0x80,0xc7,0,0xe0,0,0,
+0,0x2,0,0,0x2,0,0,0x70,0x70,0x38,
+0,0x1,0x80,0x7,0xe0,0,0xe0,0x7,0x7,0,
+0x6,0xe,0,0x38,0xe,0,0,0xe0,0,0x70,
+0,0x60,0x38,0x1,0xc0,0x38,0,0xe0,0x38,0x18,
+0,0x38,0,0x2,0xe0,0x3,0x70,0xb,0xc0,0x10,
+0x1c,0,0x38,0xe,0x1,0xc7,0,0xe,0x3,0x80,
+0x70,0x38,0x3,0x10,0x1c,0x4,0x38,0,0x40,0x1c,
+0x1,0x80,0x78,0xe,0x1,0x80,0x1e,0xc,0,0x1e,
+0x2,0x1,0,0x78,0xe,0xe,0,0xe,0x3,0x18,
+0,0,0,0x60,0,0x1,0xc0,0,0,0,
+0x1,0xc0,0,0x3,0x80,0,0,0x70,0,0,
+0,0x1c,0,0xe,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x20,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xe0,0xc,0,0xe0,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,0x40,0xe,0,
+0x3e,0x7c,0xf,0x4,0xc,0x7,0,0,0x1,0x80,
+0,0x61,0x98,0,0,0,0,0,0,0x8f,
+0xf0,0x60,0,0x30,0x30,0x3,0,0x3,0x80,0xc0,
+0xc0,0,0,0x3f,0x88,0,0,0x1,0x86,0xc,
+0,0,0x18,0x1,0x80,0x18,0x3,0,0x3,0,
+0x60,0,0,0,0x7e,0,0,0x7e,0,0,
+0x7e,0,0,0x7e,0,0,0x7e,0,0,0x7e,
+0,0,0x33,0x80,0,0x70,0,0x60,0xe0,0,
+0xe,0,0,0xe0,0,0xe,0,0,0xe0,0x1c,
+0x3,0x80,0x70,0xe,0,0x38,0xb,0xc0,0x10,0x1c,
+0,0x38,0x1c,0,0x38,0x1c,0,0x38,0x1c,0,
+0x38,0x1c,0,0x38,0,0,0x3,0x80,0x27,0x1,
+0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,
+0x2,0,0x78,0x8,0x1,0xff,0xc0,0x70,0x70,0,
+0xc0,0x30,0x1,0,0x82,0xe,0,0,0x1,0xf0,
+0,0,0,0,0,0x3,0,0xc0,0x2,0x1,
+0,0,0,0xcc,0x8,0x4,0,0x7f,0x80,0x20,
+0xe0,0,0x60,0xc,0,0x10,0x8,0x20,0xe0,0,
+0,0,0,0,0x1,0x80,0x6,0,0x60,0,
+0x40,0x20,0,0,0x3,0,0x1c,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,0,
+0,0,0,0,0,0,0xc,0x2,0x8,0x3,
+0xc,0x7,0x20,0xe,0x4,0x60,0,0xe,0x18,0,
+0x40,0xe0,0x7,0,0x78,0,0xc,0,0,0,
+0,0,0xc3,0,0xc0,0x1c,0x4,0x1,0xc0,0x3,
+0,0x33,0x3,0xf0,0x1,0xc0,0,0x1,0x83,0x81,
+0xc7,0,0xe0,0,0,0,0xe,0,0,0x3,
+0x80,0,0x30,0x70,0x38,0,0x1,0x80,0x6,0xe0,
+0,0xe0,0x7,0xe,0,0x2,0xe,0,0x1c,0xe,
+0,0,0xe0,0,0xe0,0,0x20,0x38,0x1,0xc0,
+0x38,0,0xe0,0x38,0x30,0,0x38,0,0x2,0xf0,
+0x3,0x70,0x9,0xe0,0x10,0x38,0,0x1c,0xe,0x1,
+0xce,0,0x7,0x3,0x80,0x70,0x3c,0,0,0x1c,
+0,0x38,0,0x40,0x1e,0x1,0,0x38,0xf,0x1,
+0x80,0xf,0x18,0,0xf,0x6,0,0,0x78,0xe,
+0x6,0,0xe,0x6,0xc,0,0,0,0,0,
+0x1,0xc0,0,0,0,0x1,0xc0,0,0x3,0x80,
+0,0,0x70,0,0,0,0x1c,0,0xe,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x60,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xe0,
+0xc,0,0xe0,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,0x80,0xe,0,0x78,0x1e,0x7,0xc,0xc,
+0x7,0x80,0,0x1,0x81,0xfc,0x63,0x18,0,0,
+0,0,0,0x1,0x83,0x1c,0x60,0,0x30,0x30,
+0x3,0,0x3,0x7,0x80,0,0,0,0x3f,0x88,
+0,0,0x1,0x86,0xc,0,0,0x18,0x1,0x80,
+0x18,0x3,0,0x1e,0,0x60,0,0,0,0x6e,
+0,0,0x6e,0,0,0x6e,0,0,0x6e,0,
+0,0x6e,0,0,0x6e,0,0,0x33,0x80,0,
+0xe0,0,0x20,0xe0,0,0xe,0,0,0xe0,0,
+0xe,0,0,0xe0,0x1c,0x3,0x80,0x70,0xe,0,
+0x1c,0x9,0xe0,0x10,0x38,0,0x1c,0x38,0,0x1c,
+0x38,0,0x1c,0x38,0,0x1c,0x38,0,0x1c,0,
+0,0x7,0,0x63,0x81,0xc0,0x2,0x1,0xc0,0x2,
+0x1,0xc0,0x2,0x1,0xc0,0x2,0,0x3c,0x18,0x1,
+0xc1,0xf0,0x70,0x70,0,0,0,0,0,0,
+0,0,0,0,0xe0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0x31,0xc0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xc0,0,0x1,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1c,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,0,0,0,0,0,0,
+0,0xc,0,0,0x3,0xc,0x7,0xa0,0xe,0xc,
+0x40,0,0xf,0x18,0,0x40,0xe0,0x7,0x3,0xb7,
+0,0xc,0,0,0,0,0,0xc7,0,0xe0,
+0x1c,0,0x1,0xc0,0x3,0,0x23,0x3,0xfc,0x3,
+0xc0,0,0x1,0x83,0xc1,0x87,0,0xe0,0,0,
+0,0x3e,0,0,0x3,0xe0,0,0,0xe0,0x70,
+0xf,0x18,0xc0,0x4,0xe0,0,0xe0,0xf,0xe,0,
+0x2,0xe,0,0x1c,0xe,0,0,0xe0,0,0xe0,
+0,0,0x38,0x1,0xc0,0x38,0,0xe0,0x38,0x60,
+0,0x38,0,0x2,0x70,0x6,0x70,0x9,0xe0,0x10,
+0x38,0,0x1c,0xe,0x1,0xce,0,0x7,0x3,0x80,
+0x70,0x3e,0,0,0x1c,0,0x38,0,0x40,0x1e,
+0x3,0,0x3c,0xf,0x3,0,0x7,0x98,0,0xf,
+0xc,0,0,0xf0,0xe,0x7,0,0xe,0x6,0xc,
+0,0,0,0,0,0x1,0xc0,0,0,0,
+0x1,0xc0,0,0x3,0x80,0,0,0x70,0,0,
+0,0x1c,0,0xe,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xe0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xe0,0xc,0,0xe0,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,0x80,0xe,0,
+0x70,0xe,0x7,0x88,0xc,0x3,0xc0,0,0x3,0x7,
+0x1c,0x33,0x18,0,0,0,0,0,0x3,0x3,
+0xc,0x30,0,0x18,0x60,0x3,0,0x6,0,0xe0,
+0,0,0,0x3f,0x88,0,0,0x1,0x87,0xc,
+0,0,0x18,0x3,0,0x18,0x6,0,0x3,0x80,
+0xc0,0,0,0,0x4e,0,0,0x4e,0,0,
+0x4e,0,0,0x4e,0,0,0x4e,0,0,0x4e,
+0,0,0x23,0x80,0x40,0xe0,0,0x20,0xe0,0,
+0xe,0,0,0xe0,0,0xe,0,0,0xe0,0x1c,
+0x3,0x80,0x70,0xe,0,0x1c,0x9,0xe0,0x10,0x38,
+0,0x1c,0x38,0,0x1c,0x38,0,0x1c,0x38,0,
+0x1c,0x38,0,0x1c,0x20,0x1,0x7,0,0xc3,0x81,
+0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,
+0x2,0,0x3c,0x30,0x1,0xc0,0x78,0x70,0x70,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,0xe0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1,0xe0,0,0x3,0,0,0,0,0,
+0,0,0,0,0,0,0x1c,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,0,
+0,0,0,0,0,0,0xc,0,0,0x3f,
+0xff,0x83,0xe0,0xc,0x8,0xc0,0,0x7,0x30,0,
+0,0xc0,0x3,0x7,0xb7,0x80,0xc,0,0,0,
+0,0x1,0x87,0,0xe0,0x1c,0,0x1,0xc0,0x6,
+0,0x63,0x3,0xfe,0x3,0x80,0,0x3,0x1,0xf3,
+0x7,0,0xe1,0x80,0xc0,0,0xf8,0,0,0,
+0xf8,0,0,0xe0,0xe0,0x3e,0xb8,0xc0,0xc,0x70,
+0,0xe0,0xe,0x1e,0,0,0xe,0,0x1e,0xe,
+0,0x80,0xe0,0x11,0xe0,0,0,0x38,0x1,0xc0,
+0x38,0,0xe0,0x38,0xc0,0,0x38,0,0x2,0x78,
+0x6,0x70,0x8,0xf0,0x10,0x78,0,0x1e,0xe,0x3,
+0xde,0,0x7,0x83,0x80,0xf0,0x1f,0,0,0x1c,
+0,0x38,0,0x40,0xe,0x3,0,0x1c,0xf,0x83,
+0,0x7,0xb0,0,0x7,0x8c,0,0x1,0xe0,0xe,
+0x3,0,0xe,0xe,0xe,0,0,0,0,0x3f,
+0x1,0xcf,0x80,0x3e,0,0x7d,0xc0,0x7c,0x1f,0xf8,
+0xf,0xc0,0x73,0xe0,0x38,0x6,0x1c,0x7f,0xe,0x6,
+0x3c,0x1e,0x1,0x8f,0,0x3c,0x1,0x9e,0,0x3f,
+0x20,0x33,0xf,0xa3,0xfd,0xf0,0xf8,0x7f,0x1f,0x3f,
+0x7f,0x1e,0x3f,0x3e,0x1f,0xc3,0xc7,0xff,0,0xe0,
+0xc,0,0xe0,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,0x1,
+0x80,0xf,0x80,0xe,0,0xe0,0x7,0x3,0x98,0xc,
+0x1,0xe0,0,0x3,0xe,0xc,0x33,0xbe,0,0,
+0,0,0,0x3,0x3,0xc,0x30,0,0xf,0xc0,
+0x3,0,0xc,0,0x70,0,0xf8,0x7c,0x3f,0x88,
+0,0,0x1,0x83,0x18,0,0,0x18,0x7,0,
+0x18,0xe,0,0x1,0xc1,0xc0,0,0xc0,0,0xc7,
+0,0,0xc7,0,0,0xc7,0,0,0xc7,0,
+0,0xc7,0,0,0xc7,0,0,0x63,0x80,0x41,
+0xe0,0,0,0xe0,0x8,0xe,0,0x80,0xe0,0x8,
+0xe,0,0x80,0xe0,0x1c,0x3,0x80,0x70,0xe,0,
+0x1e,0x8,0xf0,0x10,0x78,0,0x1e,0x78,0,0x1e,
+0x78,0,0x1e,0x78,0,0x1e,0x78,0,0x1e,0x70,
+0x3,0x8f,0,0x83,0xc1,0xc0,0x2,0x1,0xc0,0x2,
+0x1,0xc0,0x2,0x1,0xc0,0x2,0,0x1e,0x30,0x1,
+0xc0,0x38,0x70,0x60,0x1f,0x80,0x3f,0,0x7e,0,
+0xfc,0x1,0xf8,0x3,0xf0,0x7,0xe7,0xc0,0xf,0x80,
+0x1f,0,0x3e,0,0x7c,0,0xf8,0x3,0x1,0x80,
+0xc0,0x30,0x7,0xf0,0x18,0xf0,0x3,0xc0,0x3,0xc0,
+0x3,0xc0,0x3,0xc0,0x3,0xc0,0x1,0xe0,0,0x7a,
+0xf,0x87,0xc7,0xc3,0xe3,0xe1,0xf1,0xf0,0xf8,0xfe,
+0x1e,0x1c,0xf8,0x1f,0xc3,0xc0,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,0,0,
+0,0xc,0,0,0x3f,0xff,0x83,0xf0,0xc,0x18,
+0x80,0,0x7,0xe3,0xf8,0x1,0xc0,0x3,0x86,0x31,
+0x80,0xc,0,0,0,0,0x1,0x87,0,0xe0,
+0x1c,0,0x1,0x80,0xc,0,0xc3,0,0x3f,0x3,
+0x9e,0,0x3,0,0xfc,0x7,0,0xe3,0xc1,0xe0,
+0x3,0xe0,0,0,0,0x3e,0,0,0xc0,0xe0,
+0x38,0xf8,0x40,0x8,0x70,0,0xe0,0x1e,0x1e,0,
+0,0xe,0,0x1e,0xe,0,0x80,0xe0,0x11,0xe0,
+0,0,0x38,0x1,0xc0,0x38,0,0xe0,0x39,0x80,
+0,0x38,0,0x2,0x78,0x4,0x70,0x8,0x78,0x10,
+0x78,0,0x1e,0xe,0x3,0x9e,0,0x7,0x83,0x80,
+0xe0,0xf,0xc0,0,0x1c,0,0x38,0,0x40,0xf,
+0x2,0,0x1e,0x1f,0x83,0,0x3,0xe0,0,0x3,
+0xd8,0,0x1,0xe0,0xe,0x3,0x80,0xe,0xc,0x6,
+0,0,0,0,0x63,0x81,0xdf,0xc0,0xe3,0,
+0xc7,0xc1,0xce,0x3,0x80,0x18,0xfc,0x77,0xf0,0xf8,
+0x3e,0x1c,0x38,0xe,0x3e,0xfe,0x7f,0xf,0xbf,0x80,
+0xc7,0xf,0xbf,0x80,0x71,0xe1,0xf7,0x98,0xe0,0xe0,
+0x70,0x38,0x3c,0x6,0x1c,0x1c,0xc,0xe,0x18,0xf,
+0x1,0x86,0xf,0,0xe0,0xc,0,0xe0,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,0x3,0xc0,0x38,0xe0,0xe,0,
+0xe0,0x7,0x3,0xd0,0,0x7,0xf0,0,0x3,0xc,
+0x4,0x31,0xec,0x2,0x8,0,0,0,0x3,0x3,
+0xc,0x30,0,0x7,0x80,0x3,0,0x8,0,0x30,
+0,0x38,0x1c,0x1f,0x88,0,0,0x1,0x81,0xf0,
+0x41,0,0x18,0x6,0x8,0x18,0xc,0x78,0,0xc1,
+0x82,0x1,0xe0,0,0x87,0,0,0x87,0,0,
+0x87,0,0,0x87,0,0,0x87,0,0,0x87,
+0,0,0x63,0x80,0xc1,0xe0,0,0,0xe0,0x8,
+0xe,0,0x80,0xe0,0x8,0xe,0,0x80,0xe0,0x1c,
+0x3,0x80,0x70,0xe,0,0x1e,0x8,0x78,0x10,0x78,
+0,0x1e,0x78,0,0x1e,0x78,0,0x1e,0x78,0,
+0x1e,0x78,0,0x1e,0x38,0x7,0xf,0x1,0x83,0xc1,
+0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,
+0x2,0,0xf,0x60,0x1,0xc0,0x3c,0x70,0xc0,0x31,
+0xc0,0x63,0x80,0xc7,0x1,0x8e,0x3,0x1c,0x6,0x38,
+0xc,0x7e,0x70,0x38,0xc0,0x73,0x80,0xe7,0x1,0xce,
+0x3,0x9c,0x1f,0xf,0x87,0xc1,0xf0,0x18,0xf0,0xfb,
+0xf8,0xc,0x70,0xc,0x70,0xc,0x70,0xc,0x70,0xc,
+0x70,0,0xc0,0x1,0x8e,0x3,0x81,0xc1,0xc0,0xe0,
+0xe0,0x70,0x70,0x38,0x78,0xc,0x1d,0xfc,0xf,0x1,
+0x80,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,0,0,0,0xc,0,0,0x6,
+0x18,0x1,0xf8,0xc,0x11,0x87,0x80,0x7,0x80,0xe0,
+0x1,0xc0,0x3,0x80,0x30,0,0xc,0,0,0,
+0,0x1,0x87,0,0xe0,0x1c,0,0x3,0x80,0x1f,
+0,0x83,0,0xf,0x7,0xbf,0x80,0x3,0,0x7e,
+0x7,0x80,0xe3,0xc1,0xe0,0xf,0x80,0x3f,0xff,0xc0,
+0xf,0x80,0x1,0xc0,0xe0,0x70,0x70,0x40,0x18,0x78,
+0,0xe0,0x7c,0x1e,0,0,0xe,0,0x1e,0xe,
+0x1,0x80,0xe0,0x31,0xe0,0,0,0x38,0x1,0xc0,
+0x38,0,0xe0,0x3f,0x80,0,0x38,0,0x2,0x3c,
+0xc,0x70,0x8,0x7c,0x10,0x78,0,0x1e,0xe,0x7,
+0x9e,0,0x7,0x83,0x83,0xc0,0x7,0xf0,0,0x1c,
+0,0x38,0,0x40,0x7,0x6,0,0x1e,0x1b,0x86,
+0,0x1,0xe0,0,0x3,0xf0,0,0x3,0xc0,0xe,
+0x1,0x80,0xe,0x1c,0x7,0,0,0,0,0xe1,
+0xc1,0xe3,0xe1,0xc3,0x81,0x83,0xc3,0x7,0x3,0x80,
+0x30,0x7c,0x7c,0x78,0x38,0xe,0x1c,0x30,0xe,0xf,
+0x8f,0xc7,0x83,0xc3,0xc1,0x83,0x83,0xc7,0xc0,0xc0,
+0xe0,0x7f,0xb0,0x60,0xe0,0x70,0x38,0x1c,0x4,0x1c,
+0x1c,0xc,0xf,0x30,0x7,0x1,0x84,0xe,0,0xe0,
+0xc,0,0xe0,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,0x3,
+0xc0,0x71,0x70,0xff,0xe0,0xc0,0x3,0x1,0xf0,0,
+0xc,0x78,0,0x3,0x1c,0,0x30,0,0x6,0x18,
+0x7f,0xff,0x80,0x3,0x3,0x18,0x30,0,0,0x1,
+0xff,0xfe,0x10,0,0x30,0,0x38,0x1c,0x1f,0x88,
+0,0,0x1,0x80,0,0x61,0x80,0x18,0xc,0x18,
+0x18,0x18,0x9c,0,0xc3,0x6,0x1,0xe0,0x1,0x87,
+0x80,0x1,0x87,0x80,0x1,0x87,0x80,0x1,0x87,0x80,
+0x1,0x87,0x80,0x1,0x87,0x80,0,0xc3,0x81,0xc1,
+0xe0,0,0,0xe0,0x18,0xe,0x1,0x80,0xe0,0x18,
+0xe,0x1,0x80,0xe0,0x1c,0x3,0x80,0x70,0xe,0,
+0x1e,0x8,0x7c,0x10,0x78,0,0x1e,0x78,0,0x1e,
+0x78,0,0x1e,0x78,0,0x1e,0x78,0,0x1e,0x1c,
+0xe,0xf,0x3,0x3,0xc1,0xc0,0x2,0x1,0xc0,0x2,
+0x1,0xc0,0x2,0x1,0xc0,0x2,0,0xf,0xc0,0x1,
+0xc0,0x1c,0x73,0x80,0x70,0xe0,0xe1,0xc1,0xc3,0x83,
+0x87,0x7,0xe,0xe,0x1c,0x1c,0x38,0x30,0x70,0xe0,
+0xc1,0xc1,0x83,0x83,0x7,0x6,0xe,0x7,0x3,0x81,
+0xc0,0x70,0x30,0x78,0x3e,0x3c,0x18,0x38,0x18,0x38,
+0x18,0x38,0x18,0x38,0x18,0x38,0,0,0x3,0xf,
+0x3,0x81,0xc1,0xc0,0xe0,0xe0,0x70,0x70,0x38,0x38,
+0xc,0x1f,0x3e,0x7,0x1,0x80,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,0,0,
+0,0xc,0,0,0x6,0x18,0,0x7c,0x6,0x61,
+0xe,0xc0,0xf,0x80,0xc0,0x1,0xc0,0x3,0x80,0x78,
+0,0xc,0,0,0,0,0x3,0x87,0,0xe0,
+0x1c,0,0x3,0,0x7f,0x81,0x83,0,0x7,0x87,
+0xc3,0xc0,0x7,0,0x3f,0x3,0x80,0xe1,0x80,0xc0,
+0x3e,0,0x3f,0xff,0xc0,0x3,0xe0,0x1,0x81,0xc0,
+0xe0,0x70,0x40,0x18,0x38,0,0xff,0xf0,0x1e,0,
+0,0xe,0,0x1e,0xf,0xff,0x80,0xff,0xf1,0xe0,
+0x7,0xf8,0x3f,0xff,0xc0,0x38,0,0xe0,0x3f,0xc0,
+0,0x38,0,0x2,0x3c,0xc,0x70,0x8,0x3c,0x10,
+0x78,0,0x1e,0xe,0x1f,0x1e,0,0x7,0x83,0xff,
+0,0x3,0xf8,0,0x1c,0,0x38,0,0x40,0x7,
+0x86,0,0xe,0x13,0xc6,0,0x1,0xe0,0,0x1,
+0xf0,0,0x7,0x80,0xe,0x1,0xc0,0xe,0x18,0x3,
+0,0,0,0,0xe1,0xc1,0xc0,0xe1,0x83,0x83,
+0x81,0xc3,0x3,0x83,0x80,0x70,0x30,0x78,0x38,0x38,
+0xe,0x1c,0x60,0xe,0xf,0x7,0x83,0x83,0x81,0xc3,
+0x81,0xc3,0x81,0xc1,0xc0,0xe0,0x78,0x30,0x20,0xe0,
+0x70,0x38,0x1e,0xc,0xe,0xc,0x8,0x7,0x20,0x7,
+0x81,0x4,0x1e,0,0xe0,0xc,0,0xe0,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,0x1,0x80,0x61,0x70,0xff,0xe0,
+0xc0,0x3,0x1,0xe0,0,0x18,0x3c,0,0x3,0x1c,
+0,0x30,0,0xc,0x30,0x7f,0xff,0x80,0x3,0x3,
+0xe0,0x30,0,0,0x1,0xff,0xfe,0x20,0x58,0x30,
+0,0x38,0x1c,0xf,0x88,0,0,0x1,0x80,0,
+0x30,0xc0,0x18,0xc,0x38,0x18,0x19,0xe,0x60,0xc3,
+0xe,0,0xc0,0x1,0x83,0x80,0x1,0x83,0x80,0x1,
+0x83,0x80,0x1,0x83,0x80,0x1,0x83,0x80,0x1,0x83,
+0x80,0,0xc3,0xff,0xc1,0xe0,0,0,0xff,0xf8,
+0xf,0xff,0x80,0xff,0xf8,0xf,0xff,0x80,0xe0,0x1c,
+0x3,0x80,0x70,0x7f,0xe0,0x1e,0x8,0x3c,0x10,0x78,
+0,0x1e,0x78,0,0x1e,0x78,0,0x1e,0x78,0,
+0x1e,0x78,0,0x1e,0xe,0x1c,0xf,0x6,0x3,0xc1,
+0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,
+0x2,0,0x7,0xc0,0x1,0xc0,0x1c,0x70,0xf0,0x70,
+0xe0,0xe1,0xc1,0xc3,0x83,0x87,0x7,0xe,0xe,0x1c,
+0x1c,0x38,0x38,0x60,0xe0,0xc0,0xe1,0x81,0xc3,0x3,
+0x86,0x7,0x7,0x3,0x81,0xc0,0x70,0x70,0x38,0x3c,
+0x1c,0x38,0x1c,0x38,0x1c,0x38,0x1c,0x38,0x1c,0x38,
+0x1c,0,0,0x7,0xb,0x83,0x81,0xc1,0xc0,0xe0,
+0xe0,0x70,0x70,0x38,0x3c,0x8,0x1e,0xe,0x7,0x81,
+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,0,0,0,0,0xc,0,0,0x6,
+0x18,0,0x3e,0x3,0xc3,0x1c,0x60,0x3b,0xc0,0x80,
+0x1,0xc0,0x3,0x80,0x30,0,0xc,0,0,0,
+0,0x3,0x7,0,0xe0,0x1c,0,0x6,0,0x7,
+0xc3,0x3,0,0x3,0x87,0x1,0xc0,0x6,0,0x6f,
+0x83,0xc1,0xe0,0,0,0xf8,0,0,0,0,
+0,0xf8,0x3,0x1,0xc0,0xe0,0x60,0x40,0x10,0x38,
+0,0xe0,0x3c,0x1e,0,0,0xe,0,0x1e,0xe,
+0x1,0x80,0xe0,0x31,0xe0,0x1,0xf0,0x38,0x1,0xc0,
+0x38,0,0xe0,0x3f,0xe0,0,0x38,0,0x2,0x1c,
+0x18,0x70,0x8,0x1e,0x10,0x78,0,0x1e,0xf,0xf8,
+0x1e,0,0x7,0x83,0x9e,0,0,0xfc,0,0x1c,
+0,0x38,0,0x40,0x7,0x84,0,0xf,0x33,0xc6,
+0,0x1,0xf0,0,0,0xe0,0,0x7,0x80,0xe,
+0,0xc0,0xe,0x18,0x3,0,0,0,0,0xc1,
+0xc1,0xc0,0xf3,0x81,0x83,0x1,0xc6,0x3,0x83,0x80,
+0x70,0x30,0x70,0x38,0x38,0xe,0x1c,0xc0,0xe,0xe,
+0x7,0x3,0x83,0x81,0xc3,0x1,0xc3,0x81,0xe1,0x80,
+0xe0,0x70,0x38,0x20,0xe0,0x70,0x38,0xe,0xc,0xe,
+0xe,0x18,0x7,0xa0,0x3,0x83,0,0x3c,0,0xe0,
+0xc,0,0xe0,0xf,0x80,0xc0,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,0xe1,0x30,0xf,0,0xc0,0x3,0x1f,0xff,0,
+0x18,0x1c,0,0x3,0x1c,0,0x33,0xfc,0x18,0x60,
+0,0x1,0x80,0x3,0x3,0x70,0x30,0,0,0,
+0x3,0,0x7f,0x9c,0x60,0,0x38,0x1c,0x7,0x88,
+0x18,0,0x1,0x87,0xfc,0x18,0x60,0x18,0x18,0x38,
+0x18,0x30,0x6,0x71,0x86,0xe,0,0,0x1,0x3,
+0x80,0x1,0x3,0x80,0x1,0x3,0x80,0x1,0x3,0x80,
+0x1,0x3,0x80,0x1,0x3,0x80,0x1,0x83,0x81,0xc1,
+0xe0,0,0,0xe0,0x18,0xe,0x1,0x80,0xe0,0x18,
+0xe,0x1,0x80,0xe0,0x1c,0x3,0x80,0x70,0x7f,0xe0,
+0x1e,0x8,0x1e,0x10,0x78,0,0x1e,0x78,0,0x1e,
+0x78,0,0x1e,0x78,0,0x1e,0x78,0,0x1e,0x7,
+0x38,0xf,0x4,0x3,0xc1,0xc0,0x2,0x1,0xc0,0x2,
+0x1,0xc0,0x2,0x1,0xc0,0x2,0,0x3,0x80,0x1,
+0xc0,0x1c,0x70,0x38,0x60,0xe0,0xc1,0xc1,0x83,0x83,
+0x7,0x6,0xe,0xc,0x1c,0x18,0x38,0x38,0xe0,0x61,
+0x80,0xe3,0x1,0xc6,0x3,0x8c,0x7,0x7,0x3,0x81,
+0xc0,0x70,0x60,0x3c,0x38,0x1c,0x30,0x1c,0x30,0x1c,
+0x30,0x1c,0x30,0x1c,0x30,0x1c,0,0,0x6,0x1b,
+0x83,0x81,0xc1,0xc0,0xe0,0xe0,0x70,0x70,0x38,0x1c,
+0x18,0x1c,0xf,0x3,0x83,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,0,0,0,
+0,0xc,0,0,0x6,0x18,0,0x2f,0,0x6,
+0x38,0x20,0x71,0xe1,0x80,0x1,0xc0,0x3,0x80,0,
+0x7,0xff,0xf8,0,0,0,0x3,0x7,0,0xe0,
+0x1c,0,0x6,0,0x1,0xc2,0x3,0,0x3,0x87,
+0x1,0xe0,0x6,0x1,0xc7,0xc1,0xf7,0xe0,0,0x1,
+0xe0,0,0,0,0,0,0x3c,0x2,0x1,0xc0,
+0xe0,0xe0,0x40,0x30,0x3c,0,0xe0,0xf,0x1e,0,
+0,0xe,0,0x1e,0xe,0,0x80,0xe0,0x11,0xe0,
+0,0xe0,0x38,0x1,0xc0,0x38,0,0xe0,0x3c,0xf0,
+0,0x38,0,0x2,0x1e,0x18,0x70,0x8,0xf,0x10,
+0x78,0,0x1e,0xe,0,0x1e,0,0x7,0x83,0x8f,
+0,0,0x3e,0,0x1c,0,0x38,0,0x40,0x3,
+0x8c,0,0xf,0x31,0xcc,0,0x3,0x78,0,0,
+0xe0,0,0xf,0,0xe,0,0xe0,0xe,0,0,
+0,0,0,0,0x7,0xc1,0xc0,0x73,0,0x7,
+0x1,0xc7,0xff,0x83,0x80,0x70,0x30,0x70,0x38,0x38,
+0xe,0x1f,0x80,0xe,0xe,0x7,0x3,0x83,0x81,0xc7,
+0,0xe3,0x80,0xe3,0x80,0xe0,0x70,0x3c,0,0xe0,
+0x70,0x38,0xe,0x8,0x6,0xe,0x10,0x3,0xc0,0x3,
+0xc3,0,0x38,0,0xc0,0xc,0,0x60,0x1f,0xe1,
+0xc0,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,0xc3,0,0x7,0,
+0xe0,0x7,0,0xe0,0,0x18,0xe,0,0x3,0x1c,
+0,0x30,0,0x38,0xe0,0,0x1,0x80,0x3,0x3,
+0x30,0x30,0,0,0,0x3,0,0x7f,0xf,0xc0,
+0,0x38,0x1c,0x3,0x88,0x3c,0,0x7,0xe0,0,
+0x1c,0x70,0x7e,0x30,0x78,0x7e,0x70,0x6,0x3f,0xc,
+0x1e,0,0x40,0x3,0x3,0xc0,0x3,0x3,0xc0,0x3,
+0x3,0xc0,0x3,0x3,0xc0,0x3,0x3,0xc0,0x3,0x3,
+0xc0,0x1,0x83,0x80,0xc1,0xe0,0,0,0xe0,0x8,
+0xe,0,0x80,0xe0,0x8,0xe,0,0x80,0xe0,0x1c,
+0x3,0x80,0x70,0xe,0,0x1e,0x8,0xf,0x10,0x78,
+0,0x1e,0x78,0,0x1e,0x78,0,0x1e,0x78,0,
+0x1e,0x78,0,0x1e,0x3,0xf0,0xf,0xc,0x3,0xc1,
+0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,
+0x2,0,0x3,0x80,0x1,0xc0,0x3c,0x70,0x3c,0x3,
+0xe0,0x7,0xc0,0xf,0x80,0x1f,0,0x3e,0,0x7c,
+0,0xff,0xf8,0xc0,0x1,0xff,0xe3,0xff,0xc7,0xff,
+0x8f,0xff,0x7,0x3,0x81,0xc0,0x70,0xe0,0x1c,0x38,
+0x1c,0x70,0xe,0x70,0xe,0x70,0xe,0x70,0xe,0x70,
+0xe,0x7f,0xff,0x8e,0x11,0xc3,0x81,0xc1,0xc0,0xe0,
+0xe0,0x70,0x70,0x38,0x1e,0x18,0x1c,0x7,0x3,0xc3,
+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,0,0,0,0,0xc,0,0,0x7f,
+0xff,0,0x27,0,0x4,0x38,0x20,0xe0,0xe1,0,
+0x1,0xc0,0x3,0x80,0,0x7,0xff,0xf8,0,0xff,
+0,0x7,0x7,0,0xe0,0x1c,0,0xc,0,0x1,
+0xc7,0xff,0xe0,0x1,0x87,0,0xe0,0xe,0x1,0x83,
+0xc0,0x7d,0xc0,0,0x1,0xe0,0,0,0,0,
+0,0x3c,0x6,0x1,0xc1,0xc0,0xe0,0xc0,0x30,0x1c,
+0,0xe0,0x7,0x1e,0,0,0xe,0,0x1e,0xe,
+0,0x80,0xe0,0x11,0xe0,0,0xe0,0x38,0x1,0xc0,
+0x38,0,0xe0,0x38,0x78,0,0x38,0,0x2,0xe,
+0x10,0x70,0x8,0xf,0x90,0x78,0,0x1e,0xe,0,
+0x1e,0,0x7,0x83,0x87,0x80,0,0x1f,0,0x1c,
+0,0x38,0,0x40,0x3,0xcc,0,0x7,0x61,0xec,
+0,0x6,0x78,0,0,0xe0,0,0xf,0,0xe,
+0,0x60,0xe,0,0,0,0,0,0,0x1d,
+0xc1,0xc0,0x73,0,0x7,0x1,0xc6,0,0x3,0x80,
+0x70,0x30,0x70,0x38,0x38,0xe,0x1f,0,0xe,0xe,
+0x7,0x3,0x83,0x81,0xc7,0,0xe3,0x80,0xe3,0x80,
+0xe0,0x70,0x1f,0,0xe0,0x70,0x38,0x7,0x18,0x7,
+0x1e,0x10,0x1,0xc0,0x1,0xc2,0,0x78,0x3,0x80,
+0xc,0,0x38,0x38,0x7f,0x80,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,0x1,
+0x80,0xc2,0,0x7,0,0xe0,0x7,0,0xe0,0xc,
+0x1c,0x6,0,0x3,0x1e,0,0x30,0,0x71,0xc0,
+0,0x1,0x9f,0xe3,0x3,0x38,0x30,0,0,0,
+0x3,0,0,0,0,0,0x38,0x1c,0,0x88,
+0x3c,0,0,0,0,0xe,0x38,0,0x30,0xd8,
+0,0x60,0xe,0,0xc,0x36,0,0x40,0x3,0x1,
+0xc0,0x3,0x1,0xc0,0x3,0x1,0xc0,0x3,0x1,0xc0,
+0x3,0x1,0xc0,0x3,0x1,0xc0,0x3,0xff,0x80,0x41,
+0xe0,0,0,0xe0,0x8,0xe,0,0x80,0xe0,0x8,
+0xe,0,0x80,0xe0,0x1c,0x3,0x80,0x70,0xe,0,
+0x1e,0x8,0xf,0x90,0x78,0,0x1e,0x78,0,0x1e,
+0x78,0,0x1e,0x78,0,0x1e,0x78,0,0x1e,0x1,
+0xe0,0xf,0x8,0x3,0xc1,0xc0,0x2,0x1,0xc0,0x2,
+0x1,0xc0,0x2,0x1,0xc0,0x2,0,0x3,0x80,0x1,
+0xc0,0x38,0x70,0x1c,0xe,0xe0,0x1d,0xc0,0x3b,0x80,
+0x77,0,0xee,0x1,0xdc,0x3,0xb8,0,0xc0,0x1,
+0x80,0x3,0,0x6,0,0xc,0,0x7,0x3,0x81,
+0xc0,0x70,0xe0,0x1c,0x38,0x1c,0x70,0xe,0x70,0xe,
+0x70,0xe,0x70,0xe,0x70,0xe,0x7f,0xff,0x8e,0x11,
+0xc3,0x81,0xc1,0xc0,0xe0,0xe0,0x70,0x70,0x38,0xe,
+0x10,0x1c,0x7,0x1,0xc2,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,0,0,0,
+0,0xc,0,0,0x7f,0xff,0,0x23,0x80,0xc,
+0x70,0x20,0xc0,0xf3,0,0x1,0xc0,0x3,0x80,0,
+0,0xc,0,0,0xff,0,0x6,0x7,0,0xe0,
+0x1c,0,0x18,0,0,0xc7,0xff,0xe0,0x1,0x87,
+0,0xe0,0xc,0x3,0x81,0xe0,0x1,0xc0,0,0,
+0xf8,0,0,0,0,0,0xf8,0x4,0x1,0xc1,
+0xc0,0xe0,0x80,0x7f,0xfe,0,0xe0,0x7,0x8e,0,
+0,0xe,0,0x1c,0xe,0,0,0xe0,0,0xe0,
+0,0xe0,0x38,0x1,0xc0,0x38,0,0xe0,0x38,0x3c,
+0,0x38,0,0x2,0xf,0x30,0x70,0x8,0x7,0x90,
+0x38,0,0x1c,0xe,0,0xe,0,0x7,0x3,0x87,
+0x80,0,0xf,0,0x1c,0,0x38,0,0x40,0x1,
+0xc8,0,0x7,0x60,0xec,0,0x6,0x3c,0,0,
+0xe0,0,0x1e,0,0xe,0,0x70,0xe,0,0,
+0,0,0,0,0x31,0xc1,0xc0,0x73,0,0x7,
+0x1,0xc6,0,0x3,0x80,0x38,0x70,0x70,0x38,0x38,
+0xe,0x1f,0x80,0xe,0xe,0x7,0x3,0x83,0x81,0xc7,
+0,0xe3,0x80,0xe3,0x80,0xe0,0x70,0xf,0xc0,0xe0,
+0x70,0x38,0x7,0x10,0x7,0x17,0x30,0x1,0xe0,0x1,
+0xc6,0,0x70,0,0xc0,0xc,0,0x60,0x30,0x1f,
+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,0x1,0x80,0xc2,0,0x7,0,
+0x70,0xe,0,0xe0,0xc,0xe,0x6,0,0x1,0xe,
+0x4,0x60,0,0xe3,0x80,0,0x1,0x9f,0xe1,0x3,
+0x18,0x20,0,0,0,0x3,0,0,0,0,
+0,0x38,0x1c,0,0x88,0x18,0,0,0,0,
+0x7,0x1c,0,0x60,0x98,0,0xc0,0xc,0,0x18,
+0x26,0,0xc0,0x7,0xff,0xe0,0x7,0xff,0xe0,0x7,
+0xff,0xe0,0x7,0xff,0xe0,0x7,0xff,0xe0,0x7,0xff,
+0xe0,0x3,0x3,0x80,0x40,0xe0,0,0,0xe0,0,
+0xe,0,0,0xe0,0,0xe,0,0,0xe0,0x1c,
+0x3,0x80,0x70,0xe,0,0x1c,0x8,0x7,0x90,0x38,
+0,0x1c,0x38,0,0x1c,0x38,0,0x1c,0x38,0,
+0x1c,0x38,0,0x1c,0x1,0xe0,0x7,0x18,0x3,0x81,
+0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,0x2,0x1,0xc0,
+0x2,0,0x3,0x80,0x1,0xc0,0x78,0x70,0x1c,0x18,
+0xe0,0x31,0xc0,0x63,0x80,0xc7,0x1,0x8e,0x3,0x1c,
+0x6,0x38,0,0xc0,0x1,0x80,0x3,0,0x6,0,
+0xc,0,0x7,0x3,0x81,0xc0,0x70,0xe0,0x1c,0x38,
+0x1c,0x70,0xe,0x70,0xe,0x70,0xe,0x70,0xe,0x70,
+0xe,0,0,0xe,0x31,0xc3,0x81,0xc1,0xc0,0xe0,
+0xe0,0x70,0x70,0x38,0xe,0x30,0x1c,0x7,0x1,0xc6,
+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,0,0,0,0,0xc,0,0,0xc,
+0x30,0,0x23,0x80,0x8,0x70,0x21,0xc0,0x7e,0,
+0x1,0xc0,0x3,0x80,0,0,0xc,0,0,0,
+0,0x6,0x7,0,0xc0,0x1c,0,0x30,0,0,
+0xc7,0xff,0xe0,0x1,0x87,0,0xe0,0xc,0x3,0x1,
+0xe0,0x3,0x80,0,0,0x3e,0,0,0,0,
+0x3,0xe0,0x4,0x1,0xc1,0xc1,0xc1,0x80,0x60,0x1e,
+0,0xe0,0x3,0x8e,0,0,0xe,0,0x1c,0xe,
+0,0,0xe0,0,0xe0,0,0xe0,0x38,0x1,0xc0,
+0x38,0,0xe0,0x38,0x1e,0,0x38,0,0x2,0xf,
+0x20,0x70,0x8,0x3,0xd0,0x38,0,0x1c,0xe,0,
+0xe,0,0x7,0x3,0x83,0xc0,0x40,0x7,0,0x1c,
+0,0x38,0,0x40,0x1,0xd8,0,0x7,0xe0,0xf8,
+0,0xc,0x3e,0,0,0xe0,0,0x3c,0,0xe,
+0,0x30,0xe,0,0,0,0,0,0,0x61,
+0xc1,0xc0,0x73,0,0x7,0x1,0xc6,0,0x3,0x80,
+0x1c,0xe0,0x70,0x38,0x38,0xe,0x1d,0xc0,0xe,0xe,
+0x7,0x3,0x83,0x81,0xc7,0,0xe3,0x80,0xe3,0x80,
+0xe0,0x70,0x3,0xe0,0xe0,0x70,0x38,0x3,0xb0,0x3,
+0x33,0x20,0x3,0xe0,0,0xe4,0,0xe0,0,0xe0,
+0xc,0,0xe0,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,0x1,
+0x80,0xe6,0,0x7,0,0x78,0x1e,0x1f,0xff,0xc,
+0xf,0x6,0,0x1,0x87,0x98,0x60,0,0x71,0xc0,
+0,0x1,0x80,0x1,0x83,0x1c,0x60,0,0,0,
+0x3,0,0,0,0,0,0x38,0x1c,0,0x88,
+0,0,0,0,0,0xe,0x38,0,0xe1,0x18,
+0x1,0xc0,0x18,0,0x38,0x46,0,0x80,0x6,0x1,
+0xe0,0x6,0x1,0xe0,0x6,0x1,0xe0,0x6,0x1,0xe0,
+0x6,0x1,0xe0,0x6,0x1,0xe0,0x6,0x3,0x80,0,
+0xe0,0,0,0xe0,0,0xe,0,0,0xe0,0,
+0xe,0,0,0xe0,0x1c,0x3,0x80,0x70,0xe,0,
+0x1c,0x8,0x3,0xd0,0x38,0,0x1c,0x38,0,0x1c,
+0x38,0,0x1c,0x38,0,0x1c,0x38,0,0x1c,0x3,
+0xf0,0x7,0x30,0x3,0x81,0xc0,0x2,0x1,0xc0,0x2,
+0x1,0xc0,0x2,0x1,0xc0,0x2,0,0x3,0x80,0x1,
+0xc1,0xf0,0x70,0x1c,0x30,0xe0,0x61,0xc0,0xc3,0x81,
+0x87,0x3,0xe,0x6,0x1c,0xc,0x38,0,0xc0,0x1,
+0x80,0x3,0,0x6,0,0xc,0,0x7,0x3,0x81,
+0xc0,0x70,0xe0,0x1c,0x38,0x1c,0x70,0xe,0x70,0xe,
+0x70,0xe,0x70,0xe,0x70,0xe,0,0,0xe,0x21,
+0xc3,0x81,0xc1,0xc0,0xe0,0xe0,0x70,0x70,0x38,0x7,
+0x20,0x1c,0x7,0,0xe4,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,0,0,0,
+0,0,0,0,0xc,0x30,0x8,0x21,0x80,0x18,
+0x70,0x61,0xc0,0x3c,0,0x1,0xc0,0x3,0x80,0,
+0,0xc,0,0,0,0,0x6,0x3,0x81,0xc0,
+0x1c,0,0x60,0,0,0xc0,0x3,0,0x1,0x87,
+0,0xe0,0xc,0x3,0,0xe0,0x3,0x80,0,0,
+0xf,0x80,0x3f,0xff,0xc0,0xf,0x80,0,0x1,0xc1,
+0xc1,0xc1,0,0xc0,0xe,0,0xe0,0x3,0x87,0,
+0,0xe,0,0x38,0xe,0,0x10,0xe0,0,0x70,
+0,0xe0,0x38,0x1,0xc0,0x38,0,0xe0,0x38,0xf,
+0,0x38,0,0x42,0x7,0xa0,0x70,0x8,0x1,0xf0,
+0x1c,0,0x38,0xe,0,0x7,0,0xe,0x3,0x81,
+0xe0,0x40,0x7,0,0x1c,0,0x38,0,0x40,0,
+0xf8,0,0x3,0xc0,0xf8,0,0x18,0x1e,0,0,
+0xe0,0,0x3c,0,0x8e,0,0x38,0xe,0,0,
+0,0,0,0,0xc1,0xc1,0xc0,0x73,0x80,0x7,
+0x1,0xc7,0,0x3,0x80,0xf,0x80,0x70,0x38,0x38,
+0xe,0x1c,0xe0,0xe,0xe,0x7,0x3,0x83,0x81,0xc7,
+0,0xe3,0x80,0xe3,0x80,0xe0,0x70,0,0xf0,0xe0,
+0x70,0x38,0x3,0xa0,0x3,0xa3,0xe0,0x2,0xf0,0,
+0xe4,0x1,0xe0,0,0xe0,0xc,0,0xe0,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,0x1,0x80,0xe4,0,0x6,0,
+0x3e,0x7c,0,0xe0,0xc,0x7,0x8c,0,0x1,0x81,
+0xf0,0xc0,0,0x38,0xe0,0,0x1,0x80,0,0x8f,
+0x8f,0x40,0,0,0,0x3,0,0,0,0,
+0,0x38,0x1c,0,0x88,0,0,0,0,0,
+0x1c,0x70,0,0xc3,0x18,0x1,0x80,0x30,0,0x30,
+0xc6,0x1,0x80,0xc,0,0xe0,0xc,0,0xe0,0xc,
+0,0xe0,0xc,0,0xe0,0xc,0,0xe0,0xc,0,
+0xe0,0x6,0x3,0x80,0x8,0x70,0,0,0xe0,0x1,
+0xe,0,0x10,0xe0,0x1,0xe,0,0x10,0xe0,0x1c,
+0x3,0x80,0x70,0xe,0,0x38,0x8,0x1,0xf0,0x1c,
+0,0x38,0x1c,0,0x38,0x1c,0,0x38,0x1c,0,
+0x38,0x1c,0,0x38,0x7,0x38,0x3,0xa0,0x7,0x1,
+0xc0,0x6,0x1,0xc0,0x6,0x1,0xc0,0x6,0x1,0xc0,
+0x6,0,0x3,0x80,0x1,0xff,0xc0,0x70,0x1c,0x60,
+0xe0,0xc1,0xc1,0x83,0x83,0x7,0x6,0xe,0xc,0x1c,
+0x18,0x38,0,0xe0,0x1,0xc0,0x3,0x80,0x7,0,
+0xe,0,0x7,0x3,0x81,0xc0,0x70,0xe0,0x1c,0x38,
+0x1c,0x70,0xe,0x70,0xe,0x70,0xe,0x70,0xe,0x70,
+0xe,0,0,0xe,0x61,0xc3,0x81,0xc1,0xc0,0xe0,
+0xe0,0x70,0x70,0x38,0x7,0x20,0x1c,0x7,0,0xe4,
+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,0,0,0,0,0,0,0,0xc,
+0x30,0x8,0x21,0x80,0x10,0x60,0x41,0xc0,0x1e,0,
+0x1,0xc0,0x3,0x80,0,0,0xc,0,0,0,
+0,0xc,0x3,0x81,0xc0,0x1c,0,0xc0,0x20,0x1,
+0xc0,0x3,0,0x3,0x3,0x80,0xe0,0x18,0x3,0,
+0xe0,0x7,0,0,0,0x3,0xe0,0x3f,0xff,0xc0,
+0x3e,0,0,0,0xe1,0xc3,0xc3,0,0xc0,0xf,
+0,0xe0,0x7,0x87,0,0x2,0xe,0,0x38,0xe,
+0,0x10,0xe0,0,0x70,0,0xe0,0x38,0x1,0xc0,
+0x38,0,0xe0,0x38,0x7,0x80,0x38,0,0x42,0x7,
+0xe0,0x70,0x8,0,0xf0,0x1c,0,0x38,0xe,0,
+0x7,0,0xe,0x3,0x81,0xf0,0x60,0x7,0,0x1c,
+0,0x3c,0,0xc0,0,0xf0,0,0x3,0xc0,0x70,
+0,0x38,0xf,0,0,0xe0,0,0x78,0,0x8e,
+0,0x18,0xe,0,0,0,0,0,0x1,0xc1,
+0xc1,0xc0,0x63,0x80,0x47,0x81,0xc7,0,0x83,0x80,
+0x18,0,0x70,0x38,0x38,0xe,0x1c,0x70,0xe,0xe,
+0x7,0x3,0x83,0x81,0xc3,0x80,0xc3,0x80,0xc3,0xc0,
+0xe0,0x70,0x20,0x70,0xe0,0x70,0x38,0x3,0xe0,0x3,
+0xe3,0xc0,0x6,0x78,0,0x7c,0x1,0xc0,0x80,0xe0,
+0xc,0,0xe0,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,0x1,
+0x80,0x74,0x10,0x6,0x2,0xff,0xff,0,0xe0,0xc,
+0x3,0xf8,0,0,0xc0,0,0xc0,0,0x18,0x60,
+0,0x1,0x80,0,0xc0,0,0xc0,0,0,0,
+0x3,0,0,0,0,0,0x38,0x1c,0,0x88,
+0,0,0,0,0,0x18,0x60,0x1,0x86,0x18,
+0x3,0,0x20,0,0x61,0x86,0x3,0,0xc,0,
+0xf0,0xc,0,0xf0,0xc,0,0xf0,0xc,0,0xf0,
+0xc,0,0xf0,0xc,0,0xf0,0xc,0x3,0x80,0x8,
+0x70,0,0x20,0xe0,0x1,0xe,0,0x10,0xe0,0x1,
+0xe,0,0x10,0xe0,0x1c,0x3,0x80,0x70,0xe,0,
+0x38,0x8,0,0xf0,0x1c,0,0x38,0x1c,0,0x38,
+0x1c,0,0x38,0x1c,0,0x38,0x1c,0,0x38,0xe,
+0x1c,0x3,0xe0,0x7,0x1,0xe0,0x6,0x1,0xe0,0x6,
+0x1,0xe0,0x6,0x1,0xe0,0x6,0,0x3,0x80,0x1,
+0xc0,0,0x70,0x1c,0xe0,0xe1,0xc1,0xc3,0x83,0x87,
+0x7,0xe,0xe,0x1c,0x1c,0x38,0x38,0x8,0xe0,0x11,
+0xc0,0x23,0x80,0x47,0,0x8e,0x1,0x7,0x3,0x81,
+0xc0,0x70,0x70,0x18,0x38,0x1c,0x38,0xc,0x38,0xc,
+0x38,0xc,0x38,0xc,0x38,0xc,0,0,0x7,0x41,
+0x83,0x81,0xc1,0xc0,0xe0,0xe0,0x70,0x70,0x38,0x3,
+0xe0,0x1c,0x6,0,0x7c,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,0,0,0,
+0,0xc,0,0,0xc,0x30,0xc,0x23,0x80,0x30,
+0x60,0xc1,0xe0,0x3f,0x4,0,0xc0,0x3,0,0,
+0,0xc,0,0x30,0,0x6,0xc,0x1,0x81,0x80,
+0x1c,0x1,0x80,0x60,0x1,0x80,0x3,0,0x3,0x3,
+0x80,0xc0,0x18,0x3,0x80,0xe0,0xe,0x1,0x80,0xc0,
+0,0xf8,0,0,0,0xf8,0,0x6,0,0xe0,
+0xee,0xe6,0x1,0x80,0xf,0,0xe0,0x7,0x3,0x80,
+0x6,0xe,0,0x70,0xe,0,0x30,0xe0,0,0x38,
+0,0xe0,0x38,0x1,0xc0,0x38,0x30,0xe0,0x38,0x3,
+0xc0,0x38,0,0xc2,0x3,0xc0,0x70,0x8,0,0xf0,
+0xe,0,0x70,0xe,0,0x3,0x80,0x1c,0x3,0x80,
+0xf0,0x70,0x6,0,0x1c,0,0x1c,0,0x80,0,
+0xf0,0,0x3,0x80,0x70,0,0x30,0xf,0x80,0,
+0xe0,0,0xf0,0x1,0x8e,0,0x1c,0xe,0,0,
+0,0,0,0x1,0xc3,0xc1,0xc0,0xe1,0xc0,0xc3,
+0x83,0xc3,0x81,0x83,0x80,0x30,0,0x70,0x38,0x38,
+0xe,0x1c,0x78,0xe,0xe,0x7,0x3,0x83,0x81,0xc3,
+0x81,0xc3,0x81,0xc1,0xc1,0xe0,0x70,0x20,0x30,0xe0,
+0x70,0x78,0x1,0xe0,0x1,0xc1,0xc0,0x4,0x38,0,
+0x78,0x3,0x80,0x80,0xe0,0xc,0,0xe0,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,0x1,0x80,0x7c,0x30,0x7e,0x6,
+0xc7,0xe3,0,0xe0,0xc,0x1,0xe0,0,0,0x60,
+0x1,0x80,0,0xc,0x30,0,0,0,0,0x60,
+0x1,0x80,0,0,0,0x3,0,0,0,0,
+0,0x38,0x3c,0,0x88,0,0,0,0,0,
+0x30,0xc0,0x1,0x8f,0xfe,0x3,0,0x40,0,0x63,
+0xff,0x87,0,0x18,0,0xf0,0x18,0,0xf0,0x18,
+0,0xf0,0x18,0,0xf0,0x18,0,0xf0,0x18,0,
+0xf0,0xc,0x3,0x80,0x18,0x38,0,0x60,0xe0,0x3,
+0xe,0,0x30,0xe0,0x3,0xe,0,0x30,0xe0,0x1c,
+0x3,0x80,0x70,0xe,0,0x70,0x8,0,0xf0,0xe,
+0,0x70,0xe,0,0x70,0xe,0,0x70,0xe,0,
+0x70,0xe,0,0x70,0x1c,0xe,0x1,0xc0,0xe,0,
+0xe0,0x4,0,0xe0,0x4,0,0xe0,0x4,0,0xe0,
+0x4,0,0x3,0x80,0x1,0xc0,0,0x76,0x18,0xe1,
+0xe1,0xc3,0xc3,0x87,0x87,0xf,0xe,0x1e,0x1c,0x3c,
+0x38,0x7c,0x18,0x70,0x30,0xe0,0x61,0xc0,0xc3,0x81,
+0x87,0x3,0x7,0x3,0x81,0xc0,0x70,0x70,0x38,0x38,
+0x1c,0x38,0x1c,0x38,0x1c,0x38,0x1c,0x38,0x1c,0x38,
+0x1c,0,0xc0,0x7,0x43,0x83,0x83,0xc1,0xc1,0xe0,
+0xe0,0xf0,0x70,0x78,0x3,0xc0,0x1c,0xe,0,0x78,
+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,0,0,0,0,0x1e,0,0,0xc,
+0x30,0xe,0x23,0,0x20,0x60,0x80,0xf0,0x67,0xf8,
+0,0xe0,0x7,0,0,0,0xc,0,0x78,0,
+0xf,0xc,0x1,0xc3,0x80,0x1c,0x3,0xff,0xc3,0x83,
+0,0x3,0x7,0x6,0x1,0xc1,0xc0,0x18,0x1,0x81,
+0xc0,0x1c,0x3,0xc1,0xe0,0,0x3e,0,0,0x3,
+0xe0,0,0xf,0,0xe0,0x78,0x7c,0x1,0x80,0x7,
+0x80,0xe0,0xf,0x1,0xc0,0xc,0xe,0,0xe0,0xe,
+0,0x60,0xe0,0,0x1c,0,0xe0,0x38,0x1,0xc0,
+0x38,0x38,0xc0,0x38,0x1,0xe0,0x38,0x1,0x82,0x3,
+0xc0,0x70,0x8,0,0x70,0x7,0,0xe0,0xe,0,
+0x1,0xc0,0x38,0x3,0x80,0x78,0x38,0xe,0,0x1c,
+0,0x1e,0x1,0x80,0,0x70,0,0x1,0x80,0x70,
+0,0x60,0x7,0x80,0,0xe0,0,0xf0,0x1,0x8e,
+0,0xc,0xe,0,0,0,0,0,0x1,0xe5,
+0xd1,0xc0,0xc1,0xf1,0x83,0xc7,0xc3,0xe3,0x3,0x80,
+0x78,0,0x70,0x38,0x38,0xe,0x1c,0x3c,0xe,0xe,
+0x7,0x3,0x83,0x81,0xc1,0xc1,0x83,0xc1,0x81,0xe3,
+0xe0,0x70,0x30,0x30,0xe2,0x78,0xb8,0x1,0xc0,0x1,
+0xc1,0xc0,0xc,0x1c,0,0x38,0x7,0x80,0x80,0xe0,
+0xc,0,0xe0,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,0x1,
+0x80,0x3f,0xe0,0xc7,0xfc,0,0,0,0xe0,0xc,
+0,0xf0,0,0,0x38,0x7,0,0,0x6,0x18,
+0,0,0,0,0x38,0x7,0,0,0,0,
+0,0,0,0,0,0,0x3c,0x7c,0,0x88,
+0,0,0,0,0,0x61,0x80,0x3,0,0x18,
+0x6,0,0x81,0,0xc0,0x6,0x6,0,0x18,0,
+0x78,0x18,0,0x78,0x18,0,0x78,0x18,0,0x78,
+0x18,0,0x78,0x18,0,0x78,0x18,0x3,0x80,0x30,
+0x1c,0,0xc0,0xe0,0x6,0xe,0,0x60,0xe0,0x6,
+0xe,0,0x60,0xe0,0x1c,0x3,0x80,0x70,0xe,0,
+0xe0,0x8,0,0x70,0x7,0,0xe0,0x7,0,0xe0,
+0x7,0,0xe0,0x7,0,0xe0,0x7,0,0xe0,0x38,
+0x7,0x1,0xe0,0x1c,0,0xf0,0xc,0,0xf0,0xc,
+0,0xf0,0xc,0,0xf0,0xc,0,0x3,0x80,0x1,
+0xc0,0,0x77,0x38,0xf2,0xe9,0xe5,0xd3,0xcb,0xa7,
+0x97,0x4f,0x2e,0x9e,0x5d,0x3c,0xde,0x30,0x7c,0x60,
+0xf8,0xc1,0xf1,0x83,0xe3,0x7,0xc6,0x7,0x3,0x81,
+0xc0,0x70,0x38,0x30,0x38,0x1c,0x1c,0x18,0x1c,0x18,
+0x1c,0x18,0x1c,0x18,0x1c,0x18,0x1,0xe0,0x3,0xc3,
+0x3,0xc7,0xc1,0xe3,0xe0,0xf1,0xf0,0x78,0xf8,0x1,
+0xc0,0x1e,0xc,0,0x38,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,0,0,0,
+0,0x1e,0,0,0xc,0x30,0x7,0x26,0,0x60,
+0x33,0,0xff,0xc3,0xf0,0,0xe0,0x7,0,0,
+0,0xc,0,0x78,0,0xf,0x1c,0,0xe7,0,
+0x3e,0x7,0xff,0x83,0xce,0,0x3,0x7,0x9c,0,
+0xe3,0,0x38,0x1,0xc3,0x80,0x78,0x3,0xc1,0xe0,
+0,0xe,0,0,0x3,0x80,0,0xf,0,0x70,
+0,0,0x3,0x80,0x7,0x81,0xf0,0x3e,0,0xf0,
+0x78,0x1f,0x3,0xc0,0x1f,0x1,0xe1,0xf0,0,0xf,
+0x3,0xc0,0x7c,0x3,0xe0,0x7c,0x39,0xc0,0x7c,0x1,
+0xf0,0x7c,0x7,0x87,0x1,0x80,0xf8,0x1c,0,0x30,
+0x3,0xc3,0xc0,0x1f,0,0,0xf0,0xf0,0x7,0xc0,
+0x3c,0x3e,0x3c,0,0x3e,0,0xf,0x87,0,0,
+0x60,0,0x1,0x80,0x20,0,0xe0,0x7,0xc0,0x1,
+0xf0,0x1,0xe0,0x7,0xe,0,0xe,0xe,0,0,
+0,0,0,0,0xfd,0xf1,0xe3,0x80,0xff,0x1,
+0xfd,0xf1,0xfe,0x7,0xc0,0x7f,0xe0,0x70,0x38,0x38,
+0xe,0x1c,0x1e,0xe,0xe,0x7,0x3,0x83,0x81,0xc0,
+0xe3,0x3,0xe7,0,0xfe,0xe0,0x70,0x38,0x60,0xfc,
+0x3f,0xbe,0,0xc0,0,0xc1,0x80,0x18,0x1e,0,
+0x30,0x7,0x1,0x80,0xe0,0xc,0,0xe0,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,0x1,0x80,0x1f,0xc0,0xcf,0xf8,
+0,0,0,0xe0,0xc,0,0x78,0,0,0x1f,
+0xfc,0,0,0x2,0x8,0,0,0,0,0xf,
+0xfc,0,0,0,0x1,0xff,0xfe,0,0,0,
+0,0x3f,0xdf,0,0x88,0,0,0,0,0,
+0x41,0,0x6,0,0x18,0xc,0x1,0xfe,0x1,0x80,
+0x6,0xe,0,0x38,0,0x78,0x38,0,0x78,0x38,
+0,0x78,0x38,0,0x78,0x38,0,0x78,0x38,0,
+0x78,0x18,0x7,0xc0,0xf0,0xf,0x7,0x81,0xf0,0x1e,
+0x1f,0x1,0xe1,0xf0,0x1e,0x1f,0x1,0xe1,0xf0,0x3e,
+0x7,0xc0,0xf8,0x1f,0x3,0xc0,0x1c,0,0x30,0x3,
+0xc3,0xc0,0x3,0xc3,0xc0,0x3,0xc3,0xc0,0x3,0xc3,
+0xc0,0x3,0xc3,0xc0,0x70,0x3,0x83,0x78,0x78,0,
+0x7c,0x38,0,0x7c,0x38,0,0x7c,0x38,0,0x7c,
+0x38,0,0x7,0xc0,0x3,0xe0,0,0x77,0x30,0x7e,
+0xf8,0xfd,0xf1,0xfb,0xe3,0xf7,0xc7,0xef,0x8f,0xdf,
+0x1f,0x8f,0xe0,0x3f,0xc0,0x7f,0x80,0xff,0x1,0xfe,
+0x3,0xfc,0x7,0x3,0x81,0xc0,0x70,0x1c,0x60,0x38,
+0x1c,0xe,0x30,0xe,0x30,0xe,0x30,0xe,0x30,0xe,
+0x30,0x1,0xe0,0x1,0xc6,0x1,0xfd,0xf0,0xfe,0xf8,
+0x7f,0x7c,0x3f,0xbe,0x1,0x80,0x1f,0x18,0,0x30,
+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,0,0,0,0,0xc,0,0,0xc,
+0x30,0x1,0xfc,0,0x40,0x1e,0,0x3f,0x1,0xe0,
+0,0x60,0x6,0,0,0,0,0,0x38,0,
+0x6,0x18,0,0x3c,0,0xff,0x8f,0xff,0x81,0xfc,
+0,0x3,0x3,0xf0,0,0x3e,0,0x30,0,0x7f,
+0x3,0xc0,0x1,0x80,0xe0,0,0x2,0,0,0x2,
+0,0,0x6,0,0x30,0,0,0x7,0xe0,0x1f,
+0xe7,0xff,0xf8,0,0x3f,0xe0,0x7f,0xff,0,0x7f,
+0xff,0xe7,0xfc,0,0x3,0xff,0x1,0xff,0xf,0xf9,
+0xff,0x1f,0x1,0xff,0x8f,0xfd,0xff,0xff,0x9f,0xc1,
+0x83,0xfe,0x7f,0,0x10,0,0xff,0,0x7f,0xc0,
+0,0x3f,0xc0,0x1f,0xf0,0x3f,0x33,0xf8,0,0xff,
+0x80,0x3,0xfc,0,0,0x20,0,0x1,0,0x20,
+0x3,0xf8,0x1f,0xf0,0x7,0xfc,0x3,0xff,0xff,0xe,
+0,0x6,0xe,0,0,0,0,0,0,0x78,
+0xe0,0x7f,0,0x7c,0,0x79,0x80,0x78,0x1f,0xf0,
+0x3f,0xf9,0xfc,0xfe,0xfe,0xe,0x7f,0x3f,0xbf,0xbf,
+0x9f,0xcf,0xef,0xe7,0xf0,0x3c,0x3,0xbc,0,0x7c,
+0xe1,0xfc,0x2f,0xc0,0x70,0x1f,0x18,0,0x80,0,
+0x80,0x80,0x3c,0x3f,0,0x30,0xf,0xff,0,0xe0,
+0xc,0,0xe0,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,0x1,
+0x80,0x1f,0,0x78,0xf0,0,0,0x3,0xf8,0xc,
+0,0x38,0,0,0x7,0xf0,0,0,0,0,
+0,0,0,0,0x3,0xf0,0,0,0,0x1,
+0xff,0xfe,0,0,0,0,0x2f,0x98,0,0x88,
+0,0,0,0,0,0,0,0x6,0,0x18,
+0xc,0x1,0xfc,0x1,0x80,0x6,0xe,0,0x7e,0x1,
+0xfe,0x7e,0x1,0xfe,0x7e,0x1,0xfe,0x7e,0x1,0xfe,
+0x7e,0x1,0xfe,0x7e,0x1,0xfe,0x7f,0x1f,0xff,0xf0,
+0x3,0xfe,0x7,0xff,0xfe,0x7f,0xff,0xe7,0xff,0xfe,
+0x7f,0xff,0xe7,0xfc,0xff,0x9f,0xf3,0xfe,0x7f,0xff,
+0,0x7f,0,0x10,0,0xff,0,0,0xff,0,
+0,0xff,0,0,0xff,0,0,0xff,0,0x20,
+0x1,0x2,0x1f,0xe0,0,0x1f,0xe0,0,0x1f,0xe0,
+0,0x1f,0xe0,0,0x1f,0xe0,0,0x1f,0xf0,0xf,
+0xf8,0x1,0xf3,0xe0,0x3c,0x70,0x78,0xe0,0xf1,0xc1,
+0xe3,0x83,0xc7,0x7,0x8e,0xf,0x7,0xc0,0xf,0,
+0x1e,0,0x3c,0,0x78,0,0xf0,0x1f,0xcf,0xe7,
+0xf1,0xfc,0x7,0x80,0xfe,0x7f,0x3,0xc0,0x3,0xc0,
+0x3,0xc0,0x3,0xc0,0x3,0xc0,0,0xc0,0x1,0xf8,
+0,0xf9,0x80,0x7c,0xc0,0x3e,0x60,0x1f,0x30,0x1,
+0x80,0x1d,0xf0,0,0x30,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,0,0,0,
+0,0,0,0,0,0,0,0x20,0,0,
+0,0,0,0,0,0,0x70,0xe,0,0,
+0,0,0,0x8,0,0,0x18,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x20,
+0,0,0,0,0,0,0,0,0,0x38,
+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,0xf,0x80,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,0xe,0,0,0xe,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x1f,0xfc,0,0,0,
+0xe,0,0,0,0,0,0,0,0,0,
+0,0x3,0x80,0,0,0xe0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x20,0,0,0,0xe0,0,0,0xe0,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,0x1,0x80,0x10,0,0,0,
+0,0,0,0,0,0x3,0x1c,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x20,0,0,0x88,0,0x8,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1c,0x18,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x80,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,0x6,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,0x4,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,0x3,0,0,0,0,0,0,
+0,0,0,0,0x1,0x80,0x1c,0,0,0x20,
+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,0,0,0,0,0,0,0,0,
+0,0,0x20,0,0,0,0,0,0,0,
+0,0x30,0xc,0,0,0,0,0,0x10,0,
+0,0x30,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x40,0,0,0,0,0,
+0,0,0,0,0x1c,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,0x7,0xc0,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,0xe,
+0,0,0xe,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x60,0xc,0,0,0,0xe,0,0,0,0,
+0,0,0,0,0,0,0x3,0x80,0,0,
+0xe0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x20,0,0,0,0xe0,
+0,0,0xe0,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,0x1,
+0x80,0x30,0,0,0,0,0,0,0,0,
+0x7,0xc,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x70,0,0,0x88,
+0,0x18,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x1c,0x1c,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x1,0x80,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,0x4,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,0xc,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,0x2,0,
+0,0,0,0,0,0,0,0,0,0x1,
+0,0x1c,0,0,0x20,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,0,0,0,
+0,0,0,0,0,0,0,0x20,0,0,
+0,0,0,0,0,0,0x18,0x18,0,0,
+0,0,0,0x20,0,0,0x30,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x80,
+0,0,0,0,0,0,0,0,0,0xf,
+0,0xc,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,0x3,0xe0,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,0xe,0,0,0xe,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xc0,0xc,0,0,0,
+0xe,0,0,0,0,0,0,0,0,0,
+0,0x3,0x80,0,0,0xe0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x60,0,0,0,0x60,0,0,0xc0,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,0x3,0xc0,0x20,0,0,0,
+0,0,0,0,0,0x7,0xc,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x70,0,0,0x88,0,0x1e,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x1c,0x1c,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x1,0xe0,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,0,
+0,0,0,0xf,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,0x6,0,0,0,0,0,0,
+0,0,0,0,0x3,0,0x1c,0,0,0x60,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xc,0x30,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,0x3,0xe0,0x78,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,0x1,0xf0,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,0xf,
+0,0,0x1e,0,0,0x3f,0xff,0xe0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0xc0,0x1c,0,0,0,0xc,0,0,0,0,
+0,0,0,0,0,0,0x3,0x80,0,0,
+0xe0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x40,0,0,0,0x70,
+0,0x1,0xc0,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,0x3,
+0xc0,0x20,0,0,0,0,0,0,0,0,
+0x7,0x18,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x70,0,0,0x88,
+0,0x7,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xe,0xc,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x70,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,0,0,0,0,0x3,0x80,
+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,0x2,
+0,0x1c,0,0,0x40,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,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x6,0x60,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,
+0xff,0xe0,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,0x7c,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,0xf,0xe0,0,0xfe,0,0,
+0x3f,0xff,0xe0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xf0,0x38,0,0,0x1,
+0x8c,0,0,0,0,0,0,0,0,0,
+0,0x3,0x80,0,0,0xe0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x7,
+0xc0,0,0,0,0x3c,0,0x7,0x80,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,0x3,0xc0,0,0,0,0,
+0,0,0,0,0,0x3,0xf0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x70,0,0,0x88,0,0x3,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0xe,0xc,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x30,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,0,
+0,0,0,0x1,0x80,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,0x3e,0,0x1c,0,0x7,0xc0,
+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,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,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,0xf,0x80,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,
+0x7f,0xe0,0,0,0x1,0xd8,0,0,0,0,
+0,0,0,0,0,0,0x3,0x80,0,0,
+0xe0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xf,0x80,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,0x3,
+0xc0,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,0x70,0,0,0x88,
+0,0x7,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x7,0x38,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x70,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,0,0,0,0,0x3,0x80,
+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,0x7c,
+0,0x1c,0,0xf,0x80,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,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,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,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x1f,0x80,0,0,0,
+0xf0,0,0,0,0,0,0,0,0,0,
+0,0xf,0xf0,0,0x7,0xf8,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x7,
+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,0x1,0x80,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,0x20,0,0,0,0,0x3e,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x3,0xe0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x3,0xe0,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,0,
+0,0,0,0x1f,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,0x38,0,0x7f,0x80,0x7,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,0,0,0,0,
+};
+
+static WORD Times34_ch_ofst[225] = {
+0,8,19,33,50,66,93,119,125,136,
+147,164,183,191,202,210,220,236,252,268,
+284,300,316,332,348,364,380,389,398,417,
+436,455,469,500,524,546,568,592,612,630,
+654,678,689,702,726,746,776,800,824,842,
+866,888,906,926,950,973,1005,1029,1053,1073,
+1084,1095,1106,1122,1139,1150,1165,1181,1196,1212,
+1227,1239,1255,1271,1280,1289,1305,1314,1340,1356,
+1372,1389,1406,1417,1430,1439,1456,1473,1497,1514,
+1531,1546,1562,1569,1585,1603,1611,1619,1627,1635,
+1643,1651,1659,1667,1675,1683,1691,1699,1707,1715,
+1723,1731,1739,1747,1755,1763,1771,1779,1787,1795,
+1803,1811,1819,1827,1835,1843,1851,1859,1867,1875,
+1886,1903,1920,1937,1954,1961,1978,1989,2014,2023,
+2040,2058,2069,2094,2105,2118,2137,2147,2157,2168,
+2185,2200,2208,2219,2229,2239,2255,2280,2305,2330,
+2344,2368,2392,2416,2440,2464,2488,2518,2540,2560,
+2580,2600,2620,2631,2642,2653,2664,2688,2712,2736,
+2760,2784,2808,2832,2851,2875,2899,2923,2947,2971,
+2995,3014,3031,3046,3061,3076,3091,3106,3121,3143,
+3158,3173,3188,3203,3218,3227,3236,3246,3255,3272,
+3288,3304,3320,3336,3352,3368,3387,3404,3421,3438,
+3455,3472,3489,3506,3523,
+};
+
+static struct font_hdr Times34_font = {
+STPROP, 24, "-Adobe-Times-M-R-N--34-240-100-", 32, 255,
+37, 30, 18, 7, 7,
+34, 32, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Times34_ch_ofst, Times34_data,
+515, 37,
+NULL,
+0, 0,   /* x/y offset */
+40,        /* lineHeight */
+29,	   /* psHeight */
+};
+
+MgFont *mgTimes34Font()
+{
+return &Times34_font;
+}
diff --git a/lib/font/mgTimes8.c b/lib/font/mgTimes8.c
new file mode 100644
index 0000000..faa8de5
--- /dev/null
+++ b/lib/font/mgTimes8.c
@@ -0,0 +1,256 @@
+
+/* Times8.c - compiled data for font -Adobe-Times-M-R-N--8-80-75-75- */
+/* generated source code by utils/bdfToGem, do not edit */
+/* BDF data file input: 75dpi/timR08.bdf */
+
+#include "common.h"
+#include "memgfx.h"
+#include "../gemfont.h"
+
+static UBYTE Times8_data[2000] = {
+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,0,0,0x80,0x84,0x14,0x1,0,0,
+0x81,0x10,0x10,0xa0,0x1,0x48,0x8,0x41,0x40,0,
+0x2,0x2,0x10,0x1,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,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,0x8,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,0x1,0x20,0,0,0,0x70,0,0x40,0,
+0,0,0,0,0x41,0xa,0x28,0xa2,0x80,0,
+0x42,0x29,0x49,0x5a,0x2,0x84,0x10,0xa2,0x8a,0,
+0x1,0x4,0x28,0xa2,0,0x11,0x25,0xa8,0,0x82,
+0x4a,0x88,0x5,0x82,0x45,0xa0,0x8,0x24,0x2,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,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x10,0x8,0x1,0x1,0x80,0,0x2,0,0,0,
+0,0,0,0,0x7,0x80,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x7,0x32,0x4,0,0,0,0x5,
+0,0,0,0,0,0,0,0,0xd,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x98,0x7,0xa0,0,0xf,0,0xa,0x83,0xe0,
+0xc8,0x11,0x46,0,0,0,0,0x1,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x20,0,0,0,0,0xa,0x5a,0x14,0,0x44,
+0xa0,0x75,0xaa,0x44,0xaa,0,0x4,0x4a,0xa4,0xa,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x1a,0xad,0x92,0x92,0x4a,0x40,0x2,0x89,0x98,0x5c,
+0xdc,0x88,0x2,0x2,0x68,0x44,0x71,0xcf,0x3d,0xe7,
+0x33,0xfb,0x2e,0x77,0x66,0xe7,0x9c,0xe1,0xdf,0xcf,
+0x6d,0x3c,0xf6,0x7d,0x15,0,0x20,0x8,0x8,0x40,
+0x44,0,0,0,0x8,0,0,0,0x14,0x80,
+0,0,0,0,0,0,0,0,0x9,0x8,
+0x22,0xa0,0x8,0x50,0,0x16,0x84,0x45,0x3,0x40,
+0x54,0x12,0x49,0x14,0x41,0x4,0x10,0x41,0x7,0xb9,
+0xef,0x7b,0xdf,0xff,0xe6,0x6e,0x38,0xe3,0x8e,0x1,
+0xcc,0xf3,0xcf,0x3d,0xb0,0xc0,0,0x8,0,0,
+0,0,0x40,0,0,0x4,0x20,0,0x1,0x80,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x1b,0xf1,0xa3,0x12,0x44,0x40,0x5,0x58,0x44,0xd1,
+0x5,0x54,0x4,0xf1,0x19,0xca,0x2a,0x24,0x90,0x88,
+0x12,0x49,0x44,0x36,0x35,0x12,0x62,0x52,0x15,0x49,
+0x45,0x23,0x14,0x54,0x90,0x1,0x31,0x19,0x13,0xe5,
+0x54,0xd3,0x13,0x1a,0xed,0x55,0x54,0xab,0x94,0x9a,
+0,0,0,0,0,0,0,0,0x1,0x92,
+0x54,0xb0,0x9,0x72,0xbc,0x15,0x8a,0xea,0x2b,0x40,
+0x4a,0x94,0x52,0x20,0x41,0x4,0x10,0x41,0xa,0x44,
+0x84,0x21,0x9,0x24,0x93,0x51,0x45,0x14,0x51,0x4a,
+0x64,0x92,0x49,0x25,0x19,0x32,0x48,0x92,0x42,0x44,
+0x44,0xaa,0xac,0x44,0x44,0x40,0x6a,0xaa,0xaa,0xca,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x10,0xac,0x45,0x42,0x4b,0xe1,0x85,0x48,0x89,0x4d,
+0x88,0x8c,0x98,0,0xaa,0x4e,0x32,0x4,0x98,0xeb,
+0x9e,0x49,0x84,0x2a,0x35,0x13,0xa2,0x61,0x84,0x49,
+0x44,0xa3,0x8,0x24,0x90,0,0xaa,0x2b,0xbd,0x55,
+0x64,0xaa,0xaa,0xab,0x49,0x55,0x53,0x29,0x34,0xec,
+0,0,0,0,0,0,0,0,0xa,0x39,
+0xbe,0x28,0xa,0x45,0x5,0x96,0x84,0x4d,0x29,0x50,
+0xe1,0x49,0x29,0x54,0xa2,0x8a,0x28,0xa2,0x8f,0xc0,
+0xc6,0x31,0x89,0x25,0xd2,0xd1,0x45,0x14,0x51,0x32,
+0xa4,0x92,0x49,0x25,0x15,0x49,0x24,0x49,0xe4,0xee,
+0xee,0xaa,0x5a,0xaa,0xaa,0xae,0xaa,0xaa,0xaa,0xaa,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x1,0xf4,0xb4,0x82,0x40,0x40,0x5,0x49,0x5,0xe5,
+0x51,0x44,0x4,0xf1,0xb,0xca,0x2a,0x24,0x90,0x88,
+0x92,0x49,0x45,0x2a,0x2d,0x12,0x22,0x50,0x44,0x48,
+0x85,0xa4,0x88,0x4c,0x90,0x1,0xaa,0x2a,0x12,0x55,
+0x64,0xaa,0xaa,0xaa,0x29,0x55,0x53,0x2a,0x14,0x80,
+0,0,0,0,0,0,0,0,0xa,0x11,
+0x88,0x98,0x9,0x75,0x4,0x15,0x80,0x2,0x29,0x40,
+0x1d,0x53,0x46,0xb8,0xe3,0x8e,0x38,0xe3,0x8a,0x44,
+0x84,0x21,0x9,0x24,0x92,0x51,0x45,0x14,0x51,0x33,
+0x24,0x92,0x49,0x22,0x19,0x3b,0x6c,0xdb,0x84,0x88,
+0x88,0xaa,0x5a,0xaa,0xaa,0xa0,0xaa,0xaa,0xaa,0xaa,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0x10,0xb9,0x33,0xc2,0x40,0x42,0x18,0x9d,0xd8,0x58,
+0x90,0x98,0x92,0x2,0x28,0x1b,0x71,0xcf,0x3d,0x87,
+0x33,0xf3,0x6f,0x63,0x64,0xe6,0x1c,0xdb,0x8e,0x30,
+0x82,0xcc,0xdc,0x7c,0x50,0x1,0xb1,0x19,0x15,0x55,
+0x54,0xaa,0x93,0x1a,0x64,0xc8,0xa4,0x93,0x94,0x80,
+0,0,0,0,0,0,0,0,0x9,0xbe,
+0x48,0x88,0x8,0x42,0x80,0x10,0x80,0xe0,0x35,0x40,
+0x2,0xa7,0x89,0x79,0xb6,0xdb,0x6d,0xb6,0xdb,0xb9,
+0xef,0x7b,0xdf,0xff,0xe6,0x4e,0x38,0xe3,0x8e,0x49,
+0xc3,0xc,0x30,0xc2,0x31,0x5b,0x6c,0xdb,0x42,0x44,
+0x44,0xaa,0x2a,0x44,0x44,0x44,0xc6,0x66,0x64,0xc4,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+0,0x8,0,0x1,0x80,0x4,0x8,0,0,0,
+0,0,0x20,0,0x7,0x80,0,0,0,0,
+0,0,0,0,0,0,0x8,0,0,0,
+0,0,0,0x6,0x70,0xf0,0,0,0x2,0x1,
+0,0,0x2,0x8,0,0,0,0x10,0xd,0,
+0,0,0,0,0,0,0,0,0x9,0,
+0,0xb0,0x7,0x80,0,0xf,0,0,0x21,0x42,
+0,0x1,0xc,0x14,0,0,0,0,0,0x10,
+0,0,0,0,0,0,0,0,0,0x2,
+0,0,0,0,0x1,0,0,0,0x4,0,
+0,0,0,0,0,0,0x80,0,0x4,0x84,
+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,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,0x4,0,0,0,
+0,0,0,0,0,0,0,0,0,0x2,
+0,0,0x2,0x8,0,0,0,0x20,0,0,
+0,0,0,0,0,0,0,0,0x8,0,
+0,0,0,0,0,0,0,0,0,0x4,
+0,0,0,0,0,0,0,0,0,0x20,
+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,0x9,0x88,
+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,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,
+};
+
+static WORD Times8_ch_ofst[225] = {
+0,2,4,7,11,15,21,27,29,32,
+35,39,44,47,50,52,55,59,63,67,
+71,75,79,83,87,91,95,97,100,104,
+109,113,116,123,129,134,140,146,151,156,
+162,168,171,174,180,185,193,199,205,210,
+216,222,227,232,238,244,252,258,264,269,
+271,274,276,280,284,287,290,294,298,302,
+306,309,313,317,319,321,325,328,334,338,
+342,346,350,353,356,359,363,367,373,378,
+382,386,389,391,394,400,402,404,406,408,
+410,412,414,416,418,420,422,424,426,428,
+430,432,434,436,438,440,442,444,446,448,
+450,452,454,456,458,460,462,464,466,468,
+470,474,478,482,488,490,494,499,506,509,
+513,519,522,529,532,535,540,542,544,546,
+550,555,557,560,563,566,570,576,582,588,
+591,597,603,609,615,621,627,633,639,644,
+649,654,659,662,665,668,671,677,683,689,
+695,701,707,713,718,724,730,736,742,748,
+754,759,763,766,769,772,776,779,782,788,
+792,796,800,804,808,810,812,814,816,820,
+824,828,832,836,840,844,848,852,856,860,
+864,868,872,876,880,
+};
+
+static struct font_hdr Times8_font = {
+STPROP, 8, "-Adobe-Times-M-R-N--8-80-75-75-", 32, 255,
+10, 8, 5, 2, 2,
+9, 8, 0, 0,
+0, 0, 0x5555, (WORD)0xaaaa,
+0x0, NULL,
+Times8_ch_ofst, Times8_data,
+200, 10,
+NULL,
+0, 0,   /* x/y offset */
+10,        /* lineHeight */
+9,	   /* psHeight */
+};
+
+MgFont *mgTimes8Font()
+{
+return &Times8_font;
+}
diff --git a/lib/foo b/lib/foo
new file mode 100644
index 0000000..d20ba51
--- /dev/null
+++ b/lib/foo
@@ -0,0 +1,287 @@
+9c1dccaa (kent           2001-03-01 18:21:16 +0000   1) /* lineFile - stuff to rapidly read text files and parse them into
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700   2)  * lines.
+1ac42cff (kent           2002-09-02 04:07:51 +0000   3)  *
+1ac42cff (kent           2002-09-02 04:07:51 +0000   4)  * This file is copyright 2002 Jim Kent, but license is hereby
+1ac42cff (kent           2002-09-02 04:07:51 +0000   5)  * granted for all use - public, private or commercial. */
+1ac42cff (kent           2002-09-02 04:07:51 +0000   6) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000   7) #ifndef LINEFILE_H
+9c1dccaa (kent           2001-03-01 18:21:16 +0000   8) #define LINEFILE_H
+9c1dccaa (kent           2001-03-01 18:21:16 +0000   9) 
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700  10) #include "dystring.h"
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700  11) 
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800  12) #ifdef USE_TABIX
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800  13) #include "tabix.h"
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800  14) #endif
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800  15) 
+628e2c36 (galt           2005-05-17 23:40:23 +0000  16) enum nlType {
+628e2c36 (galt           2005-05-17 23:40:23 +0000  17)  nlt_undet, /* undetermined */
+628e2c36 (galt           2005-05-17 23:40:23 +0000  18)  nlt_unix,  /* lf   */
+628e2c36 (galt           2005-05-17 23:40:23 +0000  19)  nlt_dos,   /* crlf */
+91bc56fa (galt           2005-08-11 18:05:08 +0000  20)  nlt_mac    /* cr   */
+628e2c36 (galt           2005-05-17 23:40:23 +0000  21) };
+628e2c36 (galt           2005-05-17 23:40:23 +0000  22) 
+b472c1b9 (baertsch       2005-08-18 07:16:11 +0000  23) struct metaOutput
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700  24) /* struct to store list of file handles to output meta data to
+b472c1b9 (baertsch       2005-08-18 07:16:11 +0000  25)  * meta data is text after # */
+b472c1b9 (baertsch       2005-08-18 07:16:11 +0000  26)     {
+b472c1b9 (baertsch       2005-08-18 07:16:11 +0000  27)     struct metaOutput *next;    /* next file handle */
+b472c1b9 (baertsch       2005-08-18 07:16:11 +0000  28)     FILE *metaFile;             /* file to write metadata to */
+b472c1b9 (baertsch       2005-08-18 07:16:11 +0000  29)     };
+b472c1b9 (baertsch       2005-08-18 07:16:11 +0000  30) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  31) struct lineFile
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  32) /* Structure to handle fast, line oriented
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  33)  * fileIo. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  34)     {
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  35)     struct lineFile *next;	/* Might need to be on a list. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  36)     char *fileName;		/* Name of file. */
+6581afbc (kent           2004-04-15 07:28:29 +0000  37)     int fd;			/* File handle.  -1 for 'memory' files. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  38)     int bufSize;		/* Size of buffer. */
+b868b7db (markd          2002-12-08 17:09:36 +0000  39)     off_t bufOffsetInFile;	/* Offset in file of first buffer byte. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  40)     int bytesInBuf;		/* Bytes read into buffer. */
+6581afbc (kent           2004-04-15 07:28:29 +0000  41)     int reserved;		/* Reserved (zero for now). */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  42)     int lineIx;			/* Current line. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  43)     int lineStart;		/* Offset of line in buffer. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  44)     int lineEnd;		/* End of line in buffer. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  45)     bool zTerm;			/* Replace '\n' with zero? */
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700  46)     enum nlType nlType;         /* type of line endings: dos, unix, mac or undet */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  47)     bool reuse;			/* Set if reusing input. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  48)     char *buf;			/* Buffer. */
+303319a1 (markd          2004-08-09 17:08:17 +0000  49)     struct pipeline *pl;        /* pipeline if reading compressed */
+b472c1b9 (baertsch       2005-08-18 07:16:11 +0000  50)     struct metaOutput *metaOutput;   /* list of FILE handles to write metaData to */
+8fc35c67 (kate           2006-06-18 23:07:43 +0000  51)     bool isMetaUnique;          /* if set, do not repeat comments in output */
+8fc35c67 (kate           2006-06-18 23:07:43 +0000  52)     struct hash *metaLines;     /* save lines to suppress repetition */
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800  53) #ifdef USE_TABIX
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800  54)     tabix_t *tabix;		/* A tabix-compressed file and its binary index file (.tbi) */
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800  55)     ti_iter_t tabixIter;	/* An iterator to get decompressed indexed lines of text */
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800  56) #endif
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700  57)     struct dyString *fullLine;  // Filled with full line when a lineFileNextFull is called
+13f82230 (Tim Dreszer    2011-04-18 14:12:51 -0700  58)     struct dyString *rawLines;  // Filled with raw lines used to create the full line
+8cec4ba1 (Tim Dreszer    2011-04-15 22:52:50 -0700  59)     boolean fullLineReuse;      // If TRUE, next call to lineFileNextFull will get already built fullLine
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700  60) 
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700  61)     struct bbiFile *bbiHandle;                            // BigBed handle
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700  62)     struct bbiChromInfo *bbiChrom, *bbiChromList;         // BigBed chrom info
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700  63)     struct lm *bbiLm;                                     // BigBed local memory
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700  64)     struct bigBedInterval *bbiInterval, *bbiIntervalList; // BigBed intervals
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  65)     };
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  66) 
+d22435c7 (galt           2005-10-10 20:18:36 +0000  67) char *getFileNameFromHdrSig(char *m);
+d22435c7 (galt           2005-10-10 20:18:36 +0000  68) /* Check if header has signature of supported compression stream,
+d22435c7 (galt           2005-10-10 20:18:36 +0000  69)    and return a phoney filename for it, or NULL if no sig found. */
+d22435c7 (galt           2005-10-10 20:18:36 +0000  70) 
+d22435c7 (galt           2005-10-10 20:18:36 +0000  71) struct lineFile *lineFileDecompressFd(char *name, bool zTerm, int fd);
+d36fc7ed (galt           2005-09-30 20:59:20 +0000  72) /* open a linefile with decompression from a file or socket descriptor */
+d36fc7ed (galt           2005-09-30 20:59:20 +0000  73) 
+d22435c7 (galt           2005-10-10 20:18:36 +0000  74) struct lineFile *lineFileDecompressMem(bool zTerm, char *mem, long size);
+d22435c7 (galt           2005-10-10 20:18:36 +0000  75) /* open a linefile with decompression from a memory stream */
+d22435c7 (galt           2005-10-10 20:18:36 +0000  76) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  77) struct lineFile *lineFileMayOpen(char *fileName, bool zTerm);
+303319a1 (markd          2004-08-09 17:08:17 +0000  78) /* Try and open up a lineFile. If fileName ends in .gz, .Z, or .bz2,
+303319a1 (markd          2004-08-09 17:08:17 +0000  79)  * it will be read from a decompress pipeline. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  80) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  81) struct lineFile *lineFileOpen(char *fileName, bool zTerm);
+303319a1 (markd          2004-08-09 17:08:17 +0000  82) /* Open up a lineFile or die trying If fileName ends in .gz, .Z, or .bz2,
+303319a1 (markd          2004-08-09 17:08:17 +0000  83)  * it will be read from a decompress pipeline.. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  84) 
+7c0c46b2 (galt           2005-08-17 03:01:30 +0000  85) struct lineFile *lineFileAttach(char *fileName, bool zTerm, int fd);
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  86) /* Wrap a line file around an open'd file. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  87) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  88) struct lineFile *lineFileStdin(bool zTerm);
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  89) /* Wrap a line file around stdin. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  90) 
+6581afbc (kent           2004-04-15 07:28:29 +0000  91) struct lineFile *lineFileOnString(char *name, bool zTerm, char *s);
+6581afbc (kent           2004-04-15 07:28:29 +0000  92) /* Wrap a line file object around string in memory. This buffer
+6581afbc (kent           2004-04-15 07:28:29 +0000  93)  * have zeroes written into it if zTerm is non-zero.  It will
+6581afbc (kent           2004-04-15 07:28:29 +0000  94)  * be freed when the line file is closed. */
+6581afbc (kent           2004-04-15 07:28:29 +0000  95) 
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700  96) struct lineFile *lineFileOnBigBed(char *bigBedFileName);
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700  97) /* Wrap a line file object around a BigBed. */
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700  98) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000  99) void lineFileClose(struct lineFile **pLf);
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 100) /* Close up a line file. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 101) 
+31ad0dd6 (kent           2006-07-26 06:03:00 +0000 102) void lineFileCloseList(struct lineFile **pList);
+31ad0dd6 (kent           2006-07-26 06:03:00 +0000 103) /* Close up a list of line files. */
+31ad0dd6 (kent           2006-07-26 06:03:00 +0000 104) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 105) boolean lineFileNext(struct lineFile *lf, char **retStart, int *retSize);
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 106) /* Fetch next line from file. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 107) 
+13f82230 (Tim Dreszer    2011-04-18 14:12:51 -0700 108) boolean lineFileNextFull(struct lineFile *lf, char **retFull, int *retFullSize,
+13f82230 (Tim Dreszer    2011-04-18 14:12:51 -0700 109)                         char **retRaw, int *retRawSize);
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 110) // Fetch next line from file joining up any that are continued by ending '\'
+13f82230 (Tim Dreszer    2011-04-18 14:12:51 -0700 111) // If requested, and was joined, the unjoined raw lines are also returned
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 112) // NOTE: comment lines can't be continued!  ("# comment \ \n more comment" is 2 lines.)
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 113) 
+0899b85e (kent           2002-11-27 05:07:56 +0000 114) boolean lineFileNextReal(struct lineFile *lf, char **retStart);
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 115) /* Fetch next line from file that is not blank and
+0899b85e (kent           2002-11-27 05:07:56 +0000 116)  * does not start with a '#'. */
+0899b85e (kent           2002-11-27 05:07:56 +0000 117) 
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 118) boolean lineFileNextFullReal(struct lineFile *lf, char **retStart);
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 119) // Fetch next line from file that is not blank and does not start with a '#'.
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 120) // Continuation lines (ending in '\') are joined into a single line.
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 121) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 122) void lineFileNeedNext(struct lineFile *lf, char **retStart, int *retSize);
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 123) /* Fetch next line from file.  Squawk and die if it's not there. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 124) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 125) void lineFileReuse(struct lineFile *lf);
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 126) /* Reuse current line. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 127) 
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 128) void lineFileReuseFull(struct lineFile *lf);
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 129) // Reuse last full line read.  Unlike lineFileReuse,
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 130) // lineFileReuseFull only works with previous lineFileNextFull call
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 131) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 132) #define lineFileString(lf) ((lf)->buf + (lf)->lineStart)
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 133) /* Current string in line file. */
+5d795f18 (kent           2002-05-31 05:32:44 +0000 134) 
+5d795f18 (kent           2002-05-31 05:32:44 +0000 135) #define lineFileTell(lf) ((lf)->bufOffsetInFile + (lf)->lineStart)
+5d795f18 (kent           2002-05-31 05:32:44 +0000 136) /* Current offset (of string start) in file. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 137) 
+7f5b93f3 (kent           2002-09-21 01:33:06 +0000 138) void lineFileSeek(struct lineFile *lf, off_t offset, int whence);
+7f5b93f3 (kent           2002-09-21 01:33:06 +0000 139) /* Seek to read next line from given position. */
+de97fc85 (kent           2006-08-07 15:48:05 +0000 140) 
+c338ba5f (kent           2009-06-23 23:39:10 +0000 141) void lineFileRewind(struct lineFile *lf);
+c338ba5f (kent           2009-06-23 23:39:10 +0000 142) /* Return lineFile to start. */
+c338ba5f (kent           2009-06-23 23:39:10 +0000 143) 
+18c663e6 (kent           2006-08-07 15:57:47 +0000 144) void lineFileAbort(struct lineFile *lf, char *format, ...)
+de97fc85 (kent           2006-08-07 15:48:05 +0000 145) /* Print file name, line number, and error message, and abort. */
+251ee519 (markd          2008-02-21 02:13:26 +0000 146) #if defined(__GNUC__)
+d660d0ab (kent           2006-08-07 15:55:04 +0000 147) __attribute__((format(printf, 2, 3)))
+d660d0ab (kent           2006-08-07 15:55:04 +0000 148) #endif
+d660d0ab (kent           2006-08-07 15:55:04 +0000 149) ;
+de97fc85 (kent           2006-08-07 15:48:05 +0000 150) 
+18c663e6 (kent           2006-08-07 15:57:47 +0000 151) void lineFileVaAbort(struct lineFile *lf, char *format, va_list args);
+de97fc85 (kent           2006-08-07 15:48:05 +0000 152) /* Print file name, line number, and error message, and abort. */
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 153) 
+d8f1c532 (kent           2004-03-11 07:03:07 +0000 154) void lineFileUnexpectedEnd(struct lineFile *lf);
+d8f1c532 (kent           2004-03-11 07:03:07 +0000 155) /* Complain about unexpected end of file. */
+d8f1c532 (kent           2004-03-11 07:03:07 +0000 156) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 157) void lineFileExpectWords(struct lineFile *lf, int expecting, int got);
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 158) /* Check line has right number of words. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 159) 
+0899b85e (kent           2002-11-27 05:07:56 +0000 160) void lineFileExpectAtLeast(struct lineFile *lf, int expecting, int got);
+0899b85e (kent           2002-11-27 05:07:56 +0000 161) /* Check line has right number of words. */
+0899b85e (kent           2002-11-27 05:07:56 +0000 162) 
+ef5728a9 (kent           2003-10-01 23:12:53 +0000 163) void lineFileShort(struct lineFile *lf);
+ef5728a9 (kent           2003-10-01 23:12:53 +0000 164) /* Complain that line is too short. */
+ef5728a9 (kent           2003-10-01 23:12:53 +0000 165) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 166) boolean lineFileNextRow(struct lineFile *lf, char *words[], int wordCount);
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 167) /* Return next non-blank line that doesn't start with '#' chopped into words.
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 168)  * Returns FALSE at EOF.  Aborts on error. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 169) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 170) #define lineFileRow(lf, words) lineFileNextRow(lf, words, ArraySize(words))
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 171) /* Read in line chopped into fixed size word array. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 172) 
+c0ce3b27 (sugnet         2003-04-29 17:39:17 +0000 173) boolean lineFileNextCharRow(struct lineFile *lf, char sep, char *words[], int wordCount);
+c0ce3b27 (sugnet         2003-04-29 17:39:17 +0000 174) /* Return next non-blank line that doesn't start with '#' chopped into words
+c0ce3b27 (sugnet         2003-04-29 17:39:17 +0000 175)  * delimited by sep. Returns FALSE at EOF.  Aborts on error. */
+c0ce3b27 (sugnet         2003-04-29 17:39:17 +0000 176) 
+b868b7db (markd          2002-12-08 17:09:36 +0000 177) boolean lineFileNextRowTab(struct lineFile *lf, char *words[], int wordCount);
+b868b7db (markd          2002-12-08 17:09:36 +0000 178) /* Return next non-blank line that doesn't start with '#' chopped into words
+b868b7db (markd          2002-12-08 17:09:36 +0000 179)  * at tabs. Returns FALSE at EOF.  Aborts on error. */
+b868b7db (markd          2002-12-08 17:09:36 +0000 180) 
+f7358a0d (kent           2003-12-01 20:09:31 +0000 181) #define lineFileRowTab(lf, words) \
+f7358a0d (kent           2003-12-01 20:09:31 +0000 182) 	lineFileNextRowTab(lf, words, ArraySize(words))
+f7358a0d (kent           2003-12-01 20:09:31 +0000 183) /* Read in line chopped by tab into fixed size word array. */
+f7358a0d (kent           2003-12-01 20:09:31 +0000 184) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 185) int lineFileChopNext(struct lineFile *lf, char *words[], int maxWords);
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 186) /* Return next non-blank line that doesn't start with '#' chopped into words. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 187) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 188) #define lineFileChop(lf, words) lineFileChopNext(lf, words, ArraySize(words))
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 189) /* Ease-of-usef macro for lineFileChopNext above. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 190) 
+1ebd589d (hartera        2005-04-14 21:20:48 +0000 191) int lineFileChopCharNext(struct lineFile *lf, char sep, char *words[], int maxWords);
+72f32693 (hartera        2005-04-14 21:17:52 +0000 192) /* Return next non-blank line that doesn't start with '#' chopped into
+72f32693 (hartera        2005-04-14 21:17:52 +0000 193)    words delimited by sep. */
+72f32693 (hartera        2005-04-14 21:17:52 +0000 194) 
+b868b7db (markd          2002-12-08 17:09:36 +0000 195) int lineFileChopNextTab(struct lineFile *lf, char *words[], int maxWords);
+b868b7db (markd          2002-12-08 17:09:36 +0000 196) /* Return next non-blank line that doesn't start with '#' chopped into words
+b868b7db (markd          2002-12-08 17:09:36 +0000 197)  * on tabs */
+b868b7db (markd          2002-12-08 17:09:36 +0000 198) 
+5260dc3e (kent           2004-01-31 02:59:17 +0000 199) #define lineFileChopTab(lf, words) lineFileChopNextTab(lf, words, ArraySize(words))
+5260dc3e (kent           2004-01-31 02:59:17 +0000 200) /* Ease-of-usef macro for lineFileChopNext above. */
+5260dc3e (kent           2004-01-31 02:59:17 +0000 201) 
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 202) int lineFileCheckAllIntsNoAbort(char *s, void *val, 
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 203)     boolean isSigned, int byteCount, char *typeString, boolean noNeg, 
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 204)     char *errMsg, int errMsgSize);
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 205) /* Convert string to (signed) integer of the size specified.  
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 206)  * Unlike atol assumes all of string is number, no trailing trash allowed.
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 207)  * Returns 0 if conversion possible, and value is returned in 'val'
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 208)  * Otherwise 1 for empty string or trailing chars, and 2 for numeric overflow,
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 209)  * and 3 for (-) sign in unsigned number.
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 210)  * Error messages if any are written into the provided buffer.
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 211)  * Pass NULL val if you only want validation.
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 212)  * Use noNeg if negative values are not allowed despite the type being signed,
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 213)  * returns 4. */
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 214) 
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 215) void lineFileAllInts(struct lineFile *lf, char *words[], int wordIx, void *val,
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 216)   boolean isSigned,  int byteCount, char *typeString, boolean noNeg);
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 217) /* Returns long long integer from converting the input string. Aborts on error. */
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 218) 
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 219) int lineFileAllIntsArray(struct lineFile *lf, char *words[], int wordIx, void *array, int arraySize,
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 220)   boolean isSigned,  int byteCount, char *typeString, boolean noNeg);
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 221) /* Convert comma separated list of numbers to an array.  Pass in
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 222)  * array and max size of array. Aborts on error. Returns number of elements in parsed array. */
+2866dd07 (Galt Barber    2012-04-13 17:08:01 -0700 223) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 224) int lineFileNeedNum(struct lineFile *lf, char *words[], int wordIx);
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 225) /* Make sure that words[wordIx] is an ascii integer, and return
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 226)  * binary representation of it. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 227) 
+5df439c5 (kate           2004-04-22 16:35:21 +0000 228) int lineFileNeedFullNum(struct lineFile *lf, char *words[], int wordIx);
+5df439c5 (kate           2004-04-22 16:35:21 +0000 229) /* Make sure that words[wordIx] is an ascii integer, and return
+5df439c5 (kate           2004-04-22 16:35:21 +0000 230)  * binary representation of it. Require all chars in word to be digits.*/
+5df439c5 (kate           2004-04-22 16:35:21 +0000 231) 
+9b941573 (hiram          2003-12-10 00:26:33 +0000 232) double lineFileNeedDouble(struct lineFile *lf, char *words[], int wordIx);
+9b941573 (hiram          2003-12-10 00:26:33 +0000 233) /* Make sure that words[wordIx] is an ascii double value, and return
+9b941573 (hiram          2003-12-10 00:26:33 +0000 234)  * binary representation of it. */
+9b941573 (hiram          2003-12-10 00:26:33 +0000 235) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 236) void lineFileSkip(struct lineFile *lf, int lineCount);
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 237) /* Skip a number of lines. */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 238) 
+a043bcae (kent           2007-03-23 08:12:42 +0000 239) char *lineFileSkipToLineStartingWith(struct lineFile *lf, char *start, int maxCount);
+a043bcae (kent           2007-03-23 08:12:42 +0000 240) /* Skip to next line that starts with given string.  Return NULL
+a043bcae (kent           2007-03-23 08:12:42 +0000 241)  * if no such line found, otherwise return the line. */
+a043bcae (kent           2007-03-23 08:12:42 +0000 242) 
+1f1ad773 (Jim Kent       2011-02-01 12:38:07 -0800 243) char *lineFileReadAll(struct lineFile *lf);
+1f1ad773 (Jim Kent       2011-02-01 12:38:07 -0800 244) /* Read remainder of lineFile and return it as a string. */
+1f1ad773 (Jim Kent       2011-02-01 12:38:07 -0800 245) 
+542f0592 (angie          2002-06-29 00:30:15 +0000 246) boolean lineFileParseHttpHeader(struct lineFile *lf, char **hdr,
+542f0592 (angie          2002-06-29 00:30:15 +0000 247) 				boolean *chunked, int *contentLength);
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 248) /* Extract HTTP response header from lf into hdr, tell if it's
+542f0592 (angie          2002-06-29 00:30:15 +0000 249)  * "Transfer-Encoding: chunked" or if it has a contentLength. */
+542f0592 (angie          2002-06-29 00:30:15 +0000 250) 
+542f0592 (angie          2002-06-29 00:30:15 +0000 251) struct dyString *lineFileSlurpHttpBody(struct lineFile *lf,
+542f0592 (angie          2002-06-29 00:30:15 +0000 252) 				       boolean chunked, int contentLength);
+fcd12f2b (Tim Dreszer    2011-04-15 17:42:16 -0700 253) /* Return a dyString that contains the http response body in lf.  Handle
+542f0592 (angie          2002-06-29 00:30:15 +0000 254)  * chunk-encoding and content-length. */
+542f0592 (angie          2002-06-29 00:30:15 +0000 255) 
+b472c1b9 (baertsch       2005-08-18 07:16:11 +0000 256) void lineFileSetMetaDataOutput(struct lineFile *lf, FILE *f);
+b472c1b9 (baertsch       2005-08-18 07:16:11 +0000 257) /* set file to write meta data to,
+b472c1b9 (baertsch       2005-08-18 07:16:11 +0000 258)  * should be called before reading from input file */
+b472c1b9 (baertsch       2005-08-18 07:16:11 +0000 259) 
+8fc35c67 (kate           2006-06-18 23:07:43 +0000 260) void lineFileSetUniqueMetaData(struct lineFile *lf);
+8fc35c67 (kate           2006-06-18 23:07:43 +0000 261) /* suppress duplicate lines in metadata */
+8fc35c67 (kate           2006-06-18 23:07:43 +0000 262) 
+6a5809bc (braney         2010-06-10 20:12:00 +0000 263) 
+6a5809bc (braney         2010-06-10 20:12:00 +0000 264) void lineFileRemoveInitialCustomTrackLines(struct lineFile *lf);
+6a5809bc (braney         2010-06-10 20:12:00 +0000 265) /* remove initial browser and track lines */
+6a5809bc (braney         2010-06-10 20:12:00 +0000 266) 
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 267) /*----- Optionally-compiled wrapper on tabix (compression + indexing): -----*/
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 268) 
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 269) #define COMPILE_WITH_TABIX "%s: Sorry, this functionality is available only when\n" \
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 270)     "you have installed the tabix library from\n" \
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 271)      "http://samtools.sourceforge.net/ and rebuilt kent/src with USE_TABIX=1\n" \
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 272)      "(see http://genomewiki.ucsc.edu/index.php/Build_Environment_Variables)."
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 273) 
+84f9843f (Angie Hinrichs 2011-03-22 10:57:28 -0700 274) struct lineFile *lineFileTabixMayOpen(char *fileOrUrl, bool zTerm);
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 275) /* Wrap a line file around a data file that has been compressed and indexed
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 276)  * by the tabix command line program.  The index file <fileName>.tbi must be
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 277)  * readable in addition to fileName. If there's a problem, warn & return NULL.
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 278)  * This works only if kent/src has been compiled with USE_TABIX=1 and linked
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 279)  * with the tabix C library. */
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 280) 
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 281) boolean lineFileSetTabixRegion(struct lineFile *lf, char *seqName, int start, int end);
+84f9843f (Angie Hinrichs 2011-03-22 10:57:28 -0700 282) /* Assuming lf was created by lineFileTabixMayOpen, tell tabix to seek to the specified region
+19eaeb4d (Angie Hinrichs 2011-02-11 10:52:15 -0800 283)  * and return TRUE (or if there are no items in region, return FALSE). */
+16439684 (Angie Hinrichs 2011-02-22 11:36:43 -0800 284) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 285) #endif /* LINEFILE_H */
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 286) 
+9c1dccaa (kent           2001-03-01 18:21:16 +0000 287) 
diff --git a/lib/fuzzyShow.c b/lib/fuzzyShow.c
new file mode 100644
index 0000000..59e3851
--- /dev/null
+++ b/lib/fuzzyShow.c
@@ -0,0 +1,406 @@
+/* fuzzyShow - routines to show ffAli alignments in text
+ * or html. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "dnautil.h"
+#include "memgfx.h"
+#include "fuzzyFind.h"
+#include "htmshell.h"
+#include "cda.h"
+#include "seqOut.h"
+
+
+static void ffShNeedle(FILE *f, DNA *needle, int needleSize,
+		       int needleNumOffset, char *colorFlags,
+		       struct ffAli *aliList, boolean upcMatch,
+		       int cdsS, int cdsE,
+		       boolean accentRange, int accentStart, int accentEnd)
+/* Display the needle sequence with HTML highlighting. */
+{
+struct cfm *cfm = cfmNew(10, 50, TRUE, FALSE, f, needleNumOffset);
+char *n = cloneMem(needle, needleSize);
+char *accentFlags = needMem(needleSize);
+struct ffAli *leftAli = aliList;
+struct ffAli *ali;
+long i;
+
+zeroBytes(colorFlags, needleSize);
+zeroBytes(accentFlags, needleSize);
+fprintf(f, "<PRE><TT>\n");
+if (aliList != NULL)
+    {
+    for (leftAli = aliList; leftAli->left != NULL; leftAli = leftAli->left)
+	;
+    }
+for (ali = leftAli; ali != NULL; ali = ali->right)
+    {
+    boolean utr = FALSE;
+    int off = ali->nStart-needle;
+    int count = ali->nEnd - ali->nStart;
+    if ((cdsE > 0) && ((cdsS-off-1) > 0)) 
+	utr = TRUE;
+    for (i=0; i<count; ++i)
+	{
+	if (!utr && (i > (cdsE-off-1)) && (cdsE > 0))
+	    utr = TRUE;
+	if (utr && (i == (cdsS-off)))
+	    utr = FALSE;
+	if (toupper(ali->hStart[i]) == toupper(ali->nStart[i]))
+	    {
+	    if (utr)
+		colorFlags[off+i] = ((i == 0 || i == count-1) ? socOrange : socRed);
+	    else
+		colorFlags[off+i] = ((i == 0 || i == count-1) ? socBrightBlue : socBlue);
+	    if (upcMatch)
+		n[off+i] = toupper(n[off+i]);
+	    }
+	if (accentRange)
+	    {
+	    if (off+i >= accentStart && off+i < accentEnd)
+		accentFlags[off+i] = TRUE;
+	    }
+	}
+    }
+for (i=0; i<needleSize; ++i)
+    {
+    if (accentRange && i == accentStart)
+	fprintf(f, "<A NAME=cDNAStart></A>");
+    cfmOutExt(cfm, n[i], seqOutColorLookup[(int)colorFlags[i]],
+	      accentFlags[i], accentFlags[i], FALSE);
+    }
+cfmFree(&cfm);
+freeMem(n);
+freeMem(accentFlags);
+fprintf(f, "</TT></PRE>\n");
+htmHorizontalLine(f);
+}
+
+void ffShowSideBySide(FILE *f, struct ffAli *leftAli, DNA *needle, int needleNumOffset,
+		      DNA *haystack, int hayNumOffset, int haySize, int hayOffStart, int hayOffEnd,
+		      int blockMaxGap, boolean rcHaystack, boolean initialNewline)
+/* Print HTML side-by-side alignment of needle and haystack (no title or labels) to f.
+ * {hay,needle}NumOffset are the coords at which the DNA sequence begins.
+ * hayOff{Start,End} are the range of coords *relative to hayNumOffset* to which the 
+ * alignment display will be clipped -- pass in {0,haySize} for no clipping. */
+{
+fprintf(f, "<PRE><TT>%s", initialNewline ? "\n" : "");
+struct ffAli *ali, *lastAli = NULL;
+struct baf baf;
+/* NOTE: if rcHaystack, hayNumOffset changes here into the end, not start! */
+if (rcHaystack) 
+    hayNumOffset += haySize;
+bafInit(&baf, needle, needleNumOffset, FALSE, 
+    	haystack, hayNumOffset, rcHaystack, f, 50, FALSE);
+for (ali=leftAli; ali!=NULL; ali = ali->right)
+    {
+    int i;
+    boolean doBreak = TRUE;
+    if ((ali->hEnd - haystack) <= hayOffStart ||
+	(ali->hStart - haystack) >= hayOffEnd)
+	continue;
+
+    /* Decide whether to put in a line break and/or blank characters */
+    if (lastAli != NULL)
+	{
+	int nSkip = ali->nStart - lastAli->nEnd;
+	int hSkip = ali->hStart - lastAli->hEnd;
+	if (nSkip > 0 && nSkip <= blockMaxGap && hSkip == 0)
+	    {
+	    for (i=0; i<nSkip; ++i)
+		bafOut(&baf, lastAli->nEnd[i],'.');
+	    doBreak = FALSE; 
+	    }
+	else if (hSkip > 0 && hSkip <= blockMaxGap && nSkip == 0)
+	    {
+	    for (i=0; i<hSkip; ++i)
+		bafOut(&baf, '.', lastAli->hEnd[i]);
+	    doBreak = FALSE;
+	    }
+	else if (hSkip == nSkip && hSkip <= blockMaxGap)
+	    {
+	    for (i=0; i<hSkip; ++i)
+		bafOut(&baf, lastAli->nEnd[i], lastAli->hEnd[i]);
+	    doBreak = FALSE;
+	    }
+	}
+    else
+	{
+	doBreak = FALSE;
+	}
+    if (doBreak)
+	bafFlushLine(&baf);
+    int offset = max(0, (hayOffStart - (ali->hStart - haystack)));
+    int nStart = offset + ali->nStart - needle;
+    int hStart = offset + ali->hStart - haystack;
+    bafSetPos(&baf, nStart, hStart);
+    if (doBreak || lastAli == NULL)
+	bafStartLine(&baf);
+    int aliLen = ali->nEnd - ali->nStart;
+    for (i=0; i<aliLen; ++i)
+	{
+	int hayOff = i + (ali->hStart - haystack);
+	if (hayOff < hayOffStart)
+	    continue;
+	if (hayOff >= hayOffEnd)
+	    break;
+	bafOut(&baf, ali->nStart[i], ali->hStart[i]);
+	}
+    lastAli = ali;
+    }
+if (leftAli != NULL)
+    bafFlushLineNoHr(&baf);
+fprintf(f, "</TT></PRE>\n");
+}
+
+
+int ffShAliPart(FILE *f, struct ffAli *aliList, 
+    char *needleName, DNA *needle, int needleSize, int needleNumOffset,
+    char *haystackName, DNA *haystack, int haySize, int hayNumOffset,
+    int blockMaxGap, boolean rcNeedle, boolean rcHaystack,
+    boolean showJumpTable, 
+    boolean showNeedle, boolean showHaystack,
+    boolean showSideBySide, boolean upcMatch,
+    int cdsS, int cdsE, int hayPartS, int hayPartE)
+/* Display parts of alignment on html page.  If hayPartS..hayPartE is a 
+ * smaller subrange of the alignment, highlight that part of the alignment 
+ * in both needle and haystack with underline & bold, and show only that 
+ * part of the haystack (plus padding).  Returns number of blocks (after
+ * merging blocks separated by blockMaxGap or less). */
+{
+long i;
+struct ffAli *ali;
+struct ffAli *lastAli;
+struct ffAli *leftAli = aliList;
+struct ffAli *rightAli = aliList;
+int maxSize = (needleSize > haySize ? needleSize : haySize);
+char *colorFlags = needMem(maxSize);
+int anchorCount = 0;
+boolean restrictToWindow = FALSE;
+int hayOffStart = 0, hayOffEnd = haySize;
+int hayPaddedOffStart = 0, hayPaddedOffEnd = haySize;
+int hayExtremity = rcHaystack ? (hayNumOffset + haySize) : hayNumOffset;
+int nPartS=0, nPartE=0;
+
+if (aliList != NULL)
+    {
+    while (leftAli->left != NULL) leftAli = leftAli->left;
+    while (rightAli->right != NULL) rightAli = rightAli->right;
+    }
+
+/* If we are only showing part of the alignment, translate haystack window
+ * coords to needle window coords and haystack-offset window coords: */
+if (hayPartS > (hayNumOffset + (leftAli->hStart - haystack)) ||
+    (hayPartE > 0 && hayPartE < (hayNumOffset + (rightAli->hEnd - haystack))))
+    {
+    DNA *haystackPartS;
+    DNA *haystackPartE;
+    restrictToWindow = TRUE;
+    if (rcHaystack)
+	{
+	haystackPartS = haystack + (haySize - (hayPartE - hayNumOffset));
+	haystackPartE = haystack + (haySize - (hayPartS - hayNumOffset));
+	}
+    else
+	{
+	haystackPartS = haystack + hayPartS - hayNumOffset;
+	haystackPartE = haystack + hayPartE - hayNumOffset;
+	}
+    boolean foundStart = FALSE;
+    hayOffStart = haystackPartS - haystack;
+    hayOffEnd = haystackPartE - haystack;
+    for (ali = leftAli;  ali != NULL;  ali = ali->right)
+	{
+	if (haystackPartS < ali->hEnd && !foundStart)
+	    {
+	    int offset = haystackPartS - ali->hStart;
+	    if (offset < 0)
+		offset = 0;
+	    nPartS = offset + ali->nStart - needle;
+	    hayOffStart = offset + ali->hStart - haystack;
+	    foundStart = TRUE;
+	    }
+	if (haystackPartE > ali->hStart)
+	    {
+	    if (haystackPartE > ali->hEnd)
+		{
+		nPartE = ali->nEnd - needle;
+		hayOffEnd = ali->hEnd - haystack;
+		}
+	    else
+		{
+		nPartE = haystackPartE - ali->hStart + ali->nStart - needle;
+		hayOffEnd = haystackPartE - haystack;
+		}
+	    }
+	}
+    hayPaddedOffStart = max(0, (hayOffStart - 100));
+    hayPaddedOffEnd = min(haySize, (hayOffEnd + 100));
+    if (rcHaystack)
+	hayExtremity = hayNumOffset + haySize - hayPaddedOffStart;
+    else
+	hayExtremity = hayNumOffset + hayPaddedOffStart;
+    }
+
+if (showJumpTable)
+    {
+    fputs("<CENTER><P><TABLE BORDER=1 WIDTH=\"97%\"><TR>", f);
+    fputs("<TD WIDTH=\"23%\"><P ALIGN=CENTER><A HREF=\"#cDNA\">cDNA Sequence</A></TD>", f);
+    if (restrictToWindow)
+	fputs("<TD WIDTH=\"23%\"><P ALIGN=CENTER><A HREF=\"#cDNAStart\">cDNA Sequence in window</A></TD>", f);
+    fputs("<TD WIDTH=\"27%\"><P ALIGN=\"CENTER\"><A HREF=\"#genomic\">Genomic Sequence</A></TD>", f);
+    fputs("<TD WIDTH=\"29%\"><P ALIGN=\"CENTER\"><A HREF=\"#1\">cDNA in Genomic</A></TD>", f);
+    fputs("<TD WIDTH=\"21%\"><P ALIGN=\"CENTER\"><A HREF=\"#ali\">Side by Side</A></TD>", f);
+    fputs("</TR></TABLE>\n", f);
+    }
+if (cdsE > 0) 
+    {
+    fprintf(f, "Matching bases in coding regions of cDNA and genomic sequences are colored blue%s. ", 
+	    (upcMatch ? " and capitalized" : ""));
+    fprintf(f, "Matching bases in UTR regions of cDNA and genomic sequences are colored red%s. ", 
+	    (upcMatch ? " and capitalized" : ""));
+    fputs("Light blue (coding) or orange (UTR) bases mark the boundaries of gaps in either sequence "
+	  "(often splice sites).\n", f);
+    } 
+else 
+    {
+    fprintf(f, "Matching bases in cDNA and genomic sequences are colored blue%s. ", 
+	    (upcMatch ? " and capitalized" : ""));
+    fputs("Light blue bases mark the boundaries of gaps in either sequence "
+	  "(often splice sites).\n", f);
+    } 
+if (showNeedle && restrictToWindow)
+    fputs("Bases that were in the selected browser region are shown in bold "
+	  "and underlined, "
+	  "and only the alignment for these bases is displayed in the "
+	  "Genomic and Side by Side sections.\n", f);
+
+if (showJumpTable)
+    fputs("</P></CENTER>\n", f);
+htmHorizontalLine(f);
+
+fprintf(f, "<H4><A NAME=cDNA></A>cDNA %s%s</H4>\n", needleName, (rcNeedle ? " (reverse complemented)" : ""));
+
+if (rcNeedle)
+    reverseComplement(needle, needleSize);
+
+if (showNeedle)
+    {
+    ffShNeedle(f, needle, needleSize, needleNumOffset, colorFlags,
+	       aliList, upcMatch, cdsS, cdsE,
+	       restrictToWindow, nPartS, nPartE);
+    }
+
+if (showHaystack)
+    {
+    struct cfm *cfm = cfmNew(10, 50, TRUE, rcHaystack, f, hayExtremity);
+    char *h = cloneMem(haystack, haySize);
+    char *accentFlags = needMem(haySize);
+    zeroBytes(accentFlags, haySize);
+    fprintf(f, "<H4><A NAME=genomic></A>Genomic %s %s:</H4>\n", 
+    	haystackName,
+	(rcHaystack ? "(reverse strand)" : ""));
+    fprintf(f, "<PRE><TT>\n");
+    zeroBytes(colorFlags, haySize);
+    for (ali = leftAli; ali != NULL; ali = ali->right)
+	{
+	boolean utr = FALSE;
+	int i;
+	int off = ali->hStart-haystack;
+	int count = ali->hEnd - ali->hStart;
+	int offn = ali->nStart-needle;
+	if ((cdsE > 0) && ((cdsS-offn-1) > 0)) 
+	    utr = TRUE;
+	for (i=0; i<count; ++i)
+	    {
+	    if (!utr && (i > (cdsE-offn-1)) && (cdsE > 0))
+		utr = TRUE;
+	    if (utr && (i == (cdsS-offn)))
+		utr = FALSE;
+	    if (toupper(ali->hStart[i]) == toupper(ali->nStart[i]))
+		{
+		if (utr)
+		    colorFlags[off+i] = ((i == 0 || i == count-1) ? socOrange : socRed);
+		else
+		    colorFlags[off+i] = ((i == 0 || i == count-1) ? socBrightBlue : socBlue);
+		if (upcMatch)
+		    h[off+i] = toupper(h[off+i]);
+		}
+	    if (restrictToWindow && off+i >= hayOffStart && off+i < hayOffEnd)
+		accentFlags[off+i] = TRUE;
+	    }
+	}
+    ali = leftAli;
+    lastAli = NULL;
+    while (ali && (ali->hEnd - haystack) <= hayPaddedOffStart)
+	ali = ali->right;
+    for (i = hayPaddedOffStart; i < hayPaddedOffEnd; ++i)
+	{
+	/* Put down "anchor" on first match position in haystack
+	 * so user can hop here with a click on the needle. */
+	if (ali != NULL &&  i == ali->hStart - haystack)
+	    {
+	    if (lastAli == NULL || ali->hStart - lastAli->hEnd > blockMaxGap)
+		{
+		fprintf(f, "<A NAME=%d></A>", ++anchorCount);
+		}
+	    lastAli = ali;
+	    ali = ali->right;
+	    }
+	cfmOutExt(cfm, h[i], seqOutColorLookup[(int)colorFlags[i]],
+		  accentFlags[i], accentFlags[i], FALSE);
+	}
+    cfmFree(&cfm);
+    freeMem(h);
+    fprintf(f, "</TT></PRE>\n");
+    htmHorizontalLine(f);
+    }
+
+if (showSideBySide)
+    {
+    fprintf(f, "<H4><A NAME=ali></A>Side by Side Alignment</H4>\n");
+    ffShowSideBySide(f, leftAli, needle, needleNumOffset, haystack, hayNumOffset, haySize,
+		     hayOffStart, hayOffEnd, blockMaxGap, rcHaystack, TRUE);
+    fprintf(f, "<HR ALIGN=\"CENTER\">");
+    fprintf(f, "<EM>*Aligned Blocks with gaps <= %d bases are merged for "
+	    "this display when only one sequence has a gap, or when gaps in "
+	    "both sequences are of the same size.</EM>\n", blockMaxGap);
+    }
+if (rcNeedle)
+    reverseComplement(needle, needleSize);
+return anchorCount;
+}
+
+int ffShAli(FILE *f, struct ffAli *aliList, 
+    char *needleName, DNA *needle, int needleSize, int needleNumOffset,
+    char *haystackName, DNA *haystack, int haySize, int hayNumOffset,
+    int blockMaxGap, boolean rcNeedle)
+/* Display allignment on html page.  Returns number of blocks (after
+ * merging blocks separated by blockMaxGap or less). */
+{
+return ffShAliPart(f, aliList, needleName, needle, needleSize, needleNumOffset,
+    haystackName, haystack, haySize, hayNumOffset, blockMaxGap, rcNeedle, FALSE,
+    TRUE, TRUE, TRUE, TRUE, FALSE, 0, 0, 0, 0);
+}
+
+void ffShowAli(struct ffAli *aliList, char *needleName, DNA *needle, int needleNumOffset,
+    char *haystackName, DNA *haystack, int hayNumOffset, boolean rcNeedle)
+/* Display allignment on html page. */
+{
+ffShAli(stdout, aliList, needleName, needle, strlen(needle), needleNumOffset,
+    haystackName, haystack, strlen(haystack), hayNumOffset, 8, rcNeedle);
+}
+#if 0 /* not used */
+static struct cdaAli *makeBlocks(struct ffAli *aliList, 
+    DNA *needle, int needleSize, DNA *hay, int haySize, boolean isRc)
+/* Merge together blocks separated only by noise, and evaluate
+ * left, right, and middle of block for alignment strength. */
+{
+struct cdaAli *ca = cdaAliFromFfAli(aliList, 
+    needle, needleSize, hay, haySize, isRc);
+cdaCoalesceBlocks(ca);
+return ca;
+}
+#endif
diff --git a/lib/gapCalc.c b/lib/gapCalc.c
new file mode 100644
index 0000000..81a5114
--- /dev/null
+++ b/lib/gapCalc.c
@@ -0,0 +1,351 @@
+/* gapCalc - Stuff to calculate complex (but linear) gap costs quickly,
+ * and read specifications from a file. */
+
+#include "common.h"
+#include "linefile.h"
+#include "gapCalc.h"
+
+
+struct gapCalc
+/* A structure that bundles together stuff to help us
+ * calculate gap costs quickly. */
+    {
+    int smallSize; /* Size of tables for doing quick lookup of small gaps. */
+    int *qSmall;   /* Table for small gaps in q; */
+    int *tSmall;   /* Table for small gaps in t. */
+    int *bSmall;   /* Table for small gaps in either. */
+    int *longPos;/* Table of positions to interpolate between for larger gaps. */
+    double *qLong; /* Values to interpolate between for larger gaps in q. */
+    double *tLong; /* Values to interpolate between for larger gaps in t. */
+    double *bLong; /* Values to interpolate between for larger gaps in both. */
+    int longCount;	/* Number of long positions overall in longPos. */
+    int qPosCount;	/* Number of long positions in q. */
+    int tPosCount;	/* Number of long positions in t. */
+    int bPosCount;	/* Number of long positions in b. */
+    int qLastPos;	/* Maximum position we have data on in q. */
+    int tLastPos;	/* Maximum position we have data on in t. */
+    int bLastPos;	/* Maximum position we have data on in b. */
+    double qLastPosVal;	/* Value at max pos. */
+    double tLastPosVal;	/* Value at max pos. */
+    double bLastPosVal;	/* Value at max pos. */
+    double qLastSlope;	/* What to add for each base after last. */
+    double tLastSlope;	/* What to add for each base after last. */
+    double bLastSlope;	/* What to add for each base after last. */
+    };
+
+/* These are the gap costs used in the Evolution's Cauldron paper. */
+static char *originalGapCosts = 
+    "tableSize 11\n"
+    "smallSize 111\n"
+    "position 1 2 3 11 111 2111 12111 32111 72111 152111 252111\n"
+    "qGap 350 425 450 600 900 2900 22900 57900 117900 217900 317900\n"
+    "tGap 350 425 450 600 900 2900 22900 57900 117900 217900 317900\n"
+    "bothGap 750 825 850 1000 1300 3300 23300 58300 118300 218300 318300\n";
+
+/* These gap costs work well at chicken/human distances, and seem
+ * to do ok closer as well, so they are now the default. */
+static char *defaultGapCosts =
+"tablesize       11\n"
+"smallSize       111\n"
+"position        1       2       3       11      111     2111    12111   32111   72111   152111  252111\n"
+"qGap    325     360     400     450     600     1100    3600    7600    15600   31600   56600\n"
+"tGap    325     360     400     450     600     1100    3600    7600    15600   31600   56600\n"
+"bothGap 625     660     700     750     900     1400    4000    8000    16000   32000   57000\n";
+
+/* These gap costs are for query=mRNA, target=DNA. */
+static char *rnaDnaGapCosts = 
+"tablesize       12\n"
+"smallSize       111\n"
+"position        1       2       3       11     31   111   2111    12111   32111   72111   152111  252111\n"
+       "qGap    325     360     400     450     600  800   1100    3600    7600    15600   31600   56600\n"
+       "tGap    200     210     220     250     300  400   500      600     800    1200     2000   4000\n"
+"       bothGap 625     660     700     750     900  1100  1400    4000    8000    16000   32000   57000\n";
+
+static char *cheapGapCosts = 
+    "tableSize 3\n"
+    "smallSize 100\n"
+    "position 1 100 1000\n"
+    "qGap 0 30 300\n"
+    "tGap 0 30 300\n"
+    "bothGap 0 30 300\n";
+
+
+char *gapCalcSampleFileContents()
+/* Return contents of a sample linear gap file. */
+{
+return defaultGapCosts;
+}
+
+static int interpolate(int x, int *s, double *v, int sCount)
+/* Find closest value to x in s, and then lookup corresponding
+ * value in v.  Interpolate where necessary. */
+{
+int i, ds, ss;
+double dv;
+for (i=0; i<sCount; ++i)
+    {
+    ss = s[i];
+    if (x == ss)
+        return v[i];
+    else if (x < ss)
+        {
+	ds = ss - s[i-1];
+	dv = v[i] - v[i-1];
+	return v[i-1] + dv * (x - s[i-1]) / ds;
+	}
+    }
+/* If get to here extrapolate from last two values */
+ds = s[sCount-1] - s[sCount-2];
+dv = v[sCount-1] - v[sCount-2];
+return v[sCount-2] + dv * (x - s[sCount-2]) / ds;
+}
+
+static double calcSlope(double y2, double y1, double x2, double x1)
+/* Calculate slope of line from x1/y1 to x2/y2 */
+{
+return (y2-y1)/(x2-x1);
+}
+
+static void readTaggedNumLine(struct lineFile *lf, char *tag, 
+	int count, int *intOut,  double *floatOut)
+/* Read in a line that starts with tag and then has count numbers.
+ * Complain and die if tag is unexpected or other problem occurs. 
+ * Put output as integers and/or floating point into intOut and 
+ * floatOut. */
+{
+char *line;
+int i = 0;
+char *word;
+if (!lineFileNextReal(lf, &line))
+   lineFileUnexpectedEnd(lf);
+word = nextWord(&line);
+if (!sameWord(tag, word))
+    errAbort("Expecting %s got %s line %d of %s",
+             tag, word, lf->lineIx, lf->fileName);
+for (i = 0; i < count; ++i)
+    {
+    word = nextWord(&line);
+    if (word == NULL)
+        errAbort("Not enough numbers line %d of %s", lf->lineIx, lf->fileName);
+    if (!isdigit(word[0]))
+        errAbort("Expecting number got %s line %d of %s",
+	         word, lf->lineIx, lf->fileName);
+    if (intOut)
+	intOut[i] = atoi(word);
+    if (floatOut)
+        floatOut[i] = atof(word);
+    }
+word = nextWord(&line);
+if (word != NULL)
+        errAbort("Too many numbers line %d of %s", lf->lineIx, lf->fileName);
+}
+
+struct gapCalc *gapCalcRead(struct lineFile *lf)
+/* Create gapCalc from open file. */
+{
+int i, tableSize, startLong = -1;
+struct gapCalc *gapCalc;
+int *gapInitPos;  
+double *gapInitQGap;  
+double *gapInitTGap;  
+double *gapInitBothGap;
+
+AllocVar(gapCalc);
+
+/* Parse file. */
+readTaggedNumLine(lf, "tableSize", 1, &tableSize, NULL);
+readTaggedNumLine(lf, "smallSize", 1, &gapCalc->smallSize, NULL);
+AllocArray(gapInitPos,tableSize);
+AllocArray(gapInitQGap,tableSize);
+AllocArray(gapInitTGap,tableSize);
+AllocArray(gapInitBothGap,tableSize);
+readTaggedNumLine(lf, "position", tableSize, gapInitPos, NULL);
+readTaggedNumLine(lf, "qGap", tableSize, NULL, gapInitQGap);
+readTaggedNumLine(lf, "tGap", tableSize, NULL, gapInitTGap);
+readTaggedNumLine(lf, "bothGap", tableSize, NULL, gapInitBothGap);
+
+/* Set up precomputed interpolations for small gaps. */
+AllocArray(gapCalc->qSmall, gapCalc->smallSize);
+AllocArray(gapCalc->tSmall, gapCalc->smallSize);
+AllocArray(gapCalc->bSmall, gapCalc->smallSize);
+for (i=1; i<gapCalc->smallSize; ++i)
+    {
+    gapCalc->qSmall[i] = 
+	interpolate(i, gapInitPos, gapInitQGap, tableSize);
+    gapCalc->tSmall[i] = 
+	interpolate(i, gapInitPos, gapInitTGap, tableSize);
+    gapCalc->bSmall[i] = interpolate(i, gapInitPos, 
+	gapInitBothGap, tableSize);
+    }
+
+/* Set up to handle intermediate values. */
+for (i=0; i<tableSize; ++i)
+    {
+    if (gapCalc->smallSize == gapInitPos[i])
+	{
+	startLong = i;
+	break;
+	}
+    }
+if (startLong < 0)
+    errAbort("No position %d in gapCalcRead()\n", gapCalc->smallSize);
+gapCalc->longCount = tableSize - startLong;
+gapCalc->qPosCount = tableSize - startLong;
+gapCalc->tPosCount = tableSize - startLong;
+gapCalc->bPosCount = tableSize - startLong;
+gapCalc->longPos = cloneMem(gapInitPos + startLong, gapCalc->longCount * sizeof(int));
+gapCalc->qLong = cloneMem(gapInitQGap + startLong, gapCalc->qPosCount * sizeof(double));
+gapCalc->tLong = cloneMem(gapInitTGap + startLong, gapCalc->tPosCount * sizeof(double));
+gapCalc->bLong = cloneMem(gapInitBothGap + startLong, gapCalc->bPosCount * sizeof(double));
+
+/* Set up to handle huge values. */
+gapCalc->qLastPos = gapCalc->longPos[gapCalc->qPosCount-1];
+gapCalc->tLastPos = gapCalc->longPos[gapCalc->tPosCount-1];
+gapCalc->bLastPos = gapCalc->longPos[gapCalc->bPosCount-1];
+gapCalc->qLastPosVal = gapCalc->qLong[gapCalc->qPosCount-1];
+gapCalc->tLastPosVal = gapCalc->tLong[gapCalc->tPosCount-1];
+gapCalc->bLastPosVal = gapCalc->bLong[gapCalc->bPosCount-1];
+gapCalc->qLastSlope = calcSlope(gapCalc->qLastPosVal, gapCalc->qLong[gapCalc->qPosCount-2],
+			   gapCalc->qLastPos, gapCalc->longPos[gapCalc->qPosCount-2]);
+gapCalc->tLastSlope = calcSlope(gapCalc->tLastPosVal, gapCalc->tLong[gapCalc->tPosCount-2],
+			   gapCalc->tLastPos, gapCalc->longPos[gapCalc->tPosCount-2]);
+gapCalc->bLastSlope = calcSlope(gapCalc->bLastPosVal, gapCalc->bLong[gapCalc->bPosCount-2],
+			   gapCalc->bLastPos, gapCalc->longPos[gapCalc->bPosCount-2]);
+freez(&gapInitPos);
+freez(&gapInitQGap);
+freez(&gapInitTGap);
+freez(&gapInitBothGap);
+return gapCalc;
+}
+
+struct gapCalc *gapCalcFromString(char *s)
+/* Return gapCalc from description string. */
+{
+struct lineFile *lf = lineFileOnString("string", TRUE, cloneString(s));
+struct gapCalc *gapCalc = gapCalcRead(lf);
+lineFileClose(&lf);
+return gapCalc;
+}
+
+struct gapCalc *gapCalcFromFile(char *fileName)
+/* Return gapCalc from file. */
+{
+struct gapCalc *gapCalc = NULL;
+
+if (sameString(fileName, "loose"))
+    {
+    verbose(2, "using loose linear gap costs (chicken/human)\n");
+    gapCalc = gapCalcFromString(defaultGapCosts);
+    }
+else if (sameString(fileName, "medium"))
+    {
+    verbose(2, "using medium (original) linear gap costs (mouse/human)\n");
+    gapCalc = gapCalcFromString(originalGapCosts);
+    }
+else
+    {
+    struct lineFile *lf = lineFileOpen(fileName, TRUE);
+    gapCalc = gapCalcRead(lf);
+    lineFileClose(&lf);
+    }
+return gapCalc;
+}
+
+struct gapCalc *gapCalcDefault()
+/* Return default gapCalc. */
+{
+return gapCalcFromString(defaultGapCosts);
+}
+
+struct gapCalc *gapCalcRnaDna()
+/* Return gaps suitable for RNA queries vs. DNA targets */
+{
+return gapCalcFromString(rnaDnaGapCosts);
+}
+
+struct gapCalc *gapCalcCheap()
+/* Return cheap gap costs. */
+{
+return gapCalcFromString(cheapGapCosts);
+}
+
+struct gapCalc *gapCalcOriginal()
+/* Return gap costs from original paper. */
+{
+return gapCalcFromString(originalGapCosts);
+}
+
+void gapCalcFree(struct gapCalc **pGapCalc)
+/* Free up resources associated with gapCalc. */
+{
+struct gapCalc *gapCalc = *pGapCalc;
+if (gapCalc != NULL)
+    {
+    freeMem(gapCalc->qSmall);
+    freeMem(gapCalc->tSmall);
+    freeMem(gapCalc->bSmall);
+    freeMem(gapCalc->longPos);
+    freeMem(gapCalc->qLong);
+    freeMem(gapCalc->tLong);
+    freeMem(gapCalc->bLong);
+    freez(pGapCalc);
+    }
+}
+
+int gapCalcCost(struct gapCalc *gapCalc, int dq, int dt)
+/* Figure out gap costs. */
+{
+if (dt < 0) dt = 0;
+if (dq < 0) dq = 0;
+if (dt == 0)
+    { 
+    if (dq < gapCalc->smallSize)
+        return gapCalc->qSmall[dq];
+    else if (dq >= gapCalc->qLastPos)
+        return gapCalc->qLastPosVal + gapCalc->qLastSlope * (dq-gapCalc->qLastPos);
+    else
+        return interpolate(dq, gapCalc->longPos, gapCalc->qLong, gapCalc->qPosCount);
+    }
+else if (dq == 0)
+    {
+    if (dt < gapCalc->smallSize)
+        return gapCalc->tSmall[dt];
+    else if (dt >= gapCalc->tLastPos)
+        return gapCalc->tLastPosVal + gapCalc->tLastSlope * (dt-gapCalc->tLastPos);
+    else
+        return interpolate(dt, gapCalc->longPos, gapCalc->tLong, gapCalc->tPosCount);
+    }
+else
+    {
+    int both = dq + dt;
+    if (both < gapCalc->smallSize)
+        return gapCalc->bSmall[both];
+    else if (both >= gapCalc->bLastPos)
+        return gapCalc->bLastPosVal + gapCalc->bLastSlope * (both-gapCalc->bLastPos);
+    else
+        return interpolate(both, gapCalc->longPos, gapCalc->bLong, gapCalc->bPosCount);
+    }
+}
+
+void gapCalcTest(struct gapCalc *gapCalc)
+/* Print out gap cost info. */
+{
+int i;
+for (i=1; i<=10; i++)
+   {
+   verbose(1, "%d: %d %d %d\n", i, gapCalcCost(gapCalc, i, 0), 
+           gapCalcCost(gapCalc, 0, i), gapCalcCost(gapCalc, i/2, i-i/2));
+   }
+for (i=1; ; i *= 10)
+   {
+   verbose(1, "%d: %d %d %d\n", i, gapCalcCost(gapCalc, i, 0), gapCalcCost(gapCalc, 0, i), 
+           gapCalcCost(gapCalc, i/2, i-i/2));
+   if (i == 1000000000)
+       break;
+   }
+verbose(1, "%d %d cost %d\n", 6489540, 84240, gapCalcCost(gapCalc, 84240, 6489540));
+verbose(1, "%d %d cost %d\n", 2746361, 1075188, gapCalcCost(gapCalc, 1075188, 2746361));
+verbose(1, "%d %d cost %d\n", 6489540 + 2746361 + 72, 84240 + 1075188 + 72, gapCalcCost(gapCalc, 84240 + 1075188 + 72, 6489540 + 2746361 + 72));
+}
+
+
diff --git a/lib/gdf.c b/lib/gdf.c
new file mode 100644
index 0000000..df8e767
--- /dev/null
+++ b/lib/gdf.c
@@ -0,0 +1,153 @@
+/* gdf - Intronerator Gene Description File. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "gdf.h"
+
+
+struct gdfGene *newGdfGene(char *name, int nameSize, int exonCount, char strand, UBYTE chromIx)
+/* Return a new gene. */
+{
+struct gdfGene *gene = needMem(sizeof *gene);
+gene->name = cloneStringZ(name, nameSize);
+gene->dataCount = exonCount*2;
+if (exonCount > 0)
+    {
+    gene->dataPoints = 
+	    needMem(gene->dataCount * sizeof(gene->dataPoints[0]));
+    }
+gene->strand = strand;
+gene->chromIx = chromIx;
+return gene;
+}
+
+void gdfFreeGene(struct gdfGene *gene)
+/* Free a gene. */
+{
+if (gene != NULL)
+    {
+    freeMem(gene->name);
+    freeMem(gene->dataPoints);
+    freeMem(gene);
+    }
+}
+
+void gdfFreeGeneList(struct gdfGene **pList)
+/* Free a whole list of genes. */
+{
+struct gdfGene *gene, *next;
+gene = *pList;
+while (gene != NULL)
+    {
+    next = gene->next;
+    gdfFreeGene(gene);
+    gene = next;
+    }
+*pList = NULL;
+}
+
+struct gdfGene *gdfReadOneGene(FILE *f)
+/* Read one entry from a Gdf file.  Assumes that the file pointer
+ * is in the right place. */
+{
+short pointCount;
+char strand;
+UBYTE geneNameSize, chromIx;
+char geneNameBuf[128];
+struct gdfGene *gene;
+
+mustReadOne(f, geneNameSize);
+mustRead(f, geneNameBuf, geneNameSize);
+geneNameBuf[geneNameSize] = 0;
+mustReadOne(f, chromIx);
+mustReadOne(f, strand);
+mustReadOne(f, pointCount);
+gene = newGdfGene(geneNameBuf, geneNameSize, pointCount>>1, strand, chromIx);
+mustRead(f, gene->dataPoints, sizeof(gene->dataPoints[0]) * pointCount);
+return gene;
+}
+
+void gdfGeneExtents(struct gdfGene *gene, long *pMin, long *pMax)
+/* Figure out first and last base in gene. */
+{
+int i;
+long x;
+long min=0x7000000;
+long max = -min;
+
+for (i=0; i<gene->dataCount; i+=1)
+    {
+    x = gene->dataPoints[i].start;
+    if (x < min)
+	min = x;
+    if (x > max)
+	max = x;
+    }
+*pMin = min;
+*pMax = max;
+}
+
+void gdfOffsetGene(struct gdfGene *gene, int offset)
+/* Add offset to each point in gene */
+{
+struct gdfDataPoint *dp = gene->dataPoints;
+int count = gene->dataCount;
+int i;
+for (i=0; i<count; ++i)
+    dp[i].start += offset;
+}
+
+void gdfRcGene(struct gdfGene *gene, int size)
+/* Flip gene to other strand. Assumes dataPoints are already
+ * moved into range from 0-size */
+{
+struct gdfDataPoint *s = gene->dataPoints, *e, temp;
+int count = gene->dataCount;
+int i;
+int halfCount = count/2;
+
+
+for (i=0; i<count; ++i)
+    {
+    s->start = reverseOffset(s->start, size) + 1;
+    ++s;
+    }
+s = gene->dataPoints;
+e = s + gene->dataCount-1;
+for (i=0; i<halfCount; i += 1)
+    {
+    memcpy(&temp, s, sizeof(temp));
+    memcpy(s, e, sizeof(temp));
+    memcpy(e, &temp, sizeof(temp));
+    s += 1;
+    e -= 1;
+    }
+}
+
+
+void gdfUpcExons(struct gdfGene *gene, int geneOffset, DNA *dna, int dnaSize, int dnaOffset)
+/* Uppercase exons in DNA. */
+{
+struct gdfDataPoint *dp = gene->dataPoints;
+int count = gene->dataCount;
+int start, end;
+long gffStart, gffEnd;
+int combinedOffset;
+int i;
+
+gdfGeneExtents(gene, &gffStart, &gffEnd);
+combinedOffset = -gffStart + geneOffset - dnaOffset;
+for (i=0; i<count; i += 2)
+    {
+    start = dp[i].start + combinedOffset;
+    end = dp[i+1].start + combinedOffset;
+    if (end <= 0 || start >= dnaSize)
+        continue;
+    if (start < 0) start = 0;
+    if (end > dnaSize) end = dnaSize;
+    toUpperN(dna+start, end-start);
+    }
+}
+
diff --git a/lib/gemfont.c b/lib/gemfont.c
new file mode 100644
index 0000000..941b447
--- /dev/null
+++ b/lib/gemfont.c
@@ -0,0 +1,200 @@
+/* gemfont.c - Raster Font stuff, draws text based on a blit and a font
+   in a format that some day may approach Ventura Publisher, but currently
+   looks much more like GEM on the ST with some Mac-like mutations. */
+
+#include "common.h"
+#include "memgfx.h"
+#include "gemfont.h"
+
+
+typedef union
+    {
+    int  theInt;
+    char bytes[2];
+    } myInt;
+
+void gfText(struct memGfx *screen, struct font_hdr *f, char *text, 
+       int x, int y, Color color, TextBlit tblit, Color bcolor)
+{
+UBYTE *s = (UBYTE*)text;
+UBYTE *ss;
+int c, lo, hi;
+int sx, imageWid;
+WORD *off, wd, ht;
+UBYTE *data;
+myInt *OWtab, *iPtr;
+int missChar;
+int font_type;
+int extraWidth = f->lft_ofst + f->rgt_ofst;
+
+x += f->xOff;
+y += f->yOff;
+x += f->lft_ofst;
+lo = f->ADE_lo;
+hi = f->ADE_hi;
+off = f->ch_ofst;
+wd = f->frm_wdt;
+ht = f->frm_hgt,
+data = f->fnt_dta;
+OWtab= (myInt *)(f->hz_ofst);
+font_type = f->id;
+
+while ((c = *s++)!=0)
+    {
+    /* If we don't have the character, just turn it into a space. */
+    if (c > hi)
+	{
+	c = ' ';
+	}
+    c -= lo;
+    if (c < 0)
+	{
+	c = ' ' - lo;
+	}
+
+    /* Mac prop font && its a missing char */
+    if (font_type == MPROP && (*(OWtab+c)).theInt == -1) 
+	{            
+	c=hi-lo;                      /* last char is set */
+	missChar=1;
+	sx = off[c+1];
+	imageWid= f->frm_wdt*8 - sx;  /* sort of a kludge */
+	}
+    else 
+	{
+	missChar=0;
+	sx = off[c];
+	imageWid = off[c+1]-sx;
+	}
+    (*tblit)(imageWid, ht, sx, 0, data, wd, screen, x, y, color, bcolor);
+    switch (font_type)
+	{
+	case STPROP:
+	    x += imageWid + extraWidth;
+	    break;
+	case MFIXED:
+	    x += f->wchr_wdt + extraWidth;          
+	    break;
+	case MPROP:
+	    iPtr=OWtab+c;  
+	    if (!missChar)
+		    /* -1 means its a missing character */
+		{
+		x += (int)((*iPtr).bytes[1]);
+		ss=s;
+		if ((c=*(ss++)) != 0)
+			/* look to next char to determine amt to change x */
+		    {
+		    c-= lo;
+		    iPtr=OWtab+c;
+		    /* subtract kern Of Next char */
+		    /* f->rgt_ofst is neg of Mac maxKern value */
+		    if ((*iPtr).theInt!=-1)
+		       x += (int)((*iPtr).bytes[0])+ f->rgt_ofst;  
+		    }           
+		}
+	    else /* display the non print char */
+		x+=imageWid + extraWidth;
+	    break;
+	}
+    }
+}
+
+static int fchar_width(struct font_hdr *f,unsigned char *s)
+/* How wide is this character? */
+{
+int c;
+signed char *offsets;
+int width;
+int t;
+
+c = *s++;
+if (c > f->ADE_hi)
+    c = ' ';
+c -= f->ADE_lo;
+if (c < 0)
+    {
+    c = ' ' - f->ADE_lo;
+    }
+switch (f->id)
+    {
+    case MFIXED:
+	    return(f->wchr_wdt + f->lft_ofst + f->rgt_ofst);
+    case STPROP:
+	    return(f->ch_ofst[c+1] - f->ch_ofst[c] + f->lft_ofst + f->rgt_ofst);
+    case MPROP:
+	    offsets = f->hz_ofst+c*2;
+	    if (offsets[0] == -1 && offsets[1] == -1)	/* missing char */
+		{
+		t = f->ADE_hi - f->ADE_lo;
+		return( f->frm_wdt*8 - f->ch_ofst[t+1]);
+		}
+	    else
+		{
+		width = offsets[1];
+		if ((c = *s++) != 0)
+			{
+			c -= f->ADE_lo;
+			offsets = f->hz_ofst+c*2;
+			width += offsets[0] + f->rgt_ofst;
+			}
+		return(width);
+		}
+    default:
+         internalErr();
+	 return 0;
+    }
+}
+
+long fnstring_width(struct font_hdr *f, unsigned char *s, int n)
+{
+long acc = 0;
+
+while (--n >= 0)
+    {
+    acc += fchar_width(f, s);
+    s++;
+    }
+return(acc);
+}
+
+#if 0 /* unused */
+static long fstring_width(struct font_hdr *f, unsigned char *s)
+{
+return(fnstring_width(f, s, strlen((char *)s)));
+}
+#endif
+
+
+int fwidest_char(struct font_hdr *f)
+{
+unsigned char buf[2];
+int i;
+int c;
+int widest = 1;
+int w;
+
+c = f->ADE_lo;
+i = f->ADE_hi - c;
+buf[1] = 0;
+while (--i >= 0)
+	{
+	buf[0] = c++;
+	w = fchar_width(f, buf);
+	if (w > widest)
+		widest = w;
+	}
+return(widest);
+}
+
+int font_cel_height(struct font_hdr *f)
+/* How tall is font? */
+{
+return f->frm_hgt;
+}
+
+int font_line_height(struct font_hdr *f)
+/* How far to next line. */
+{
+return f->lineHeight;
+}
diff --git a/lib/gemfont.h b/lib/gemfont.h
new file mode 100644
index 0000000..ad67a04
--- /dev/null
+++ b/lib/gemfont.h
@@ -0,0 +1,69 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+#ifndef GEMFONT_H
+#define GEMFONT_H
+
+/* This file supports GEM style fonts.  They live on disk in three parts.
+   1st there's the header structure below, then a list of 'x' offsets into
+   the data - one 16-bit word for each offset, and 1 offset for each letter
+   in the font plus an extra offset at the end.
+
+   This is followed by the data which is a single bitmap.
+   */
+
+struct	font_hdr {
+WORD	id;			/* some random number, doesnt matter */
+WORD	size;		/* Size in points.  Somehow related to pixel height. */
+char	facename[32];	/* Give it a name, don't really matter. */
+WORD	ADE_lo;		/* Lowest ascii character in font */
+WORD	ADE_hi;		/* Highest ascii character in font */
+WORD	top_dist;
+WORD	asc_dist;	/* Ascender to baseline?? */
+WORD	hlf_dist;
+WORD	des_dist;	/* des for descender. */
+WORD	bot_dist;
+WORD	wchr_wdt;	/* Widest character width. */
+WORD	wcel_wdt;	/* Widest 'cell' width (includes distance to next character) */
+WORD	lft_ofst;
+WORD	rgt_ofst;
+WORD	thckning;
+WORD	undrline;
+WORD	lghtng_m;	/* Lightening mask.  Just use 0x55aa. */
+WORD	skewng_m;	/* Skewing mask for italics. If 1 bit rotate this line. 0xaaaa*/
+WORD	flags;		/* Just set to zero.  Half-assed intel swap if otherwise. */
+signed char *hz_ofst;  /* On disk byte offset from beginning of file to hor. offsets */
+WORD	*ch_ofst;	/* On disk byte offset to beginning of ?? kerning ?? data. */
+UBYTE	*fnt_dta;	/* On disk byte offset to beginning of bitmap. */
+WORD	frm_wdt;	/* Byte width of bitmap. */
+WORD	frm_hgt;	/* Pixel height of bitmap. */
+struct font_hdr	*nxt_fnt; /* Set to 0 */
+WORD    xOff;		/* X offset to add. */
+WORD    yOff;		/* Y offset to add. */
+WORD    lineHeight;     /* Distance to next line. */
+WORD	psHeight;	/* Height to set for equivalent postscript. */
+}; 
+
+#define STPROP 0
+#define MFIXED 1
+#define MPROP 2
+
+/* Write a line of graphics text. */
+void gfText(struct memGfx *screen, struct font_hdr *f, char *text, 
+       int x, int y, Color color, TextBlit tblit, Color bcolor);
+
+/* How tall is font? */
+int font_cel_height(struct font_hdr *f);
+
+/* How far to next line. */
+int font_line_height(struct font_hdr *f);
+
+/* How wide would this bunch of characters be? */
+long fnstring_width(struct font_hdr *f, unsigned char *s, int n);
+
+/* How wide is widest char in font? */
+int fwidest_char(struct font_hdr *f);
+
+#endif 
diff --git a/lib/genomeRangeTree.c b/lib/genomeRangeTree.c
new file mode 100644
index 0000000..de922b2
--- /dev/null
+++ b/lib/genomeRangeTree.c
@@ -0,0 +1,185 @@
+/* genomeRangeTree - This module is a way of keeping track of
+ * non-overlapping ranges (half-open intervals) across a whole
+ * genome (multiple chromosomes or scaffolds). 
+ * It is a hash table container mapping chrom to rangeTree.
+ * Most of the work is performed by rangeTree, this container
+ * enables local memory and stack to be shared by many rangeTrees
+ * so it should be able to handle genomes with a very large 
+ * number of scaffolds. See rangeTree for more information. */
+
+#include "common.h"
+#include "sig.h"
+#include "localmem.h"
+#include "rbTree.h"
+#include "hash.h"
+#include "rangeTree.h"
+#include "genomeRangeTree.h"
+#include "dystring.h"
+#include <limits.h>
+
+
+struct genomeRangeTree *genomeRangeTreeNewSize(int hashPowerOfTwoSize)
+/* Create a new, empty, genomeRangeTree. 
+ * Free with genomeRangeTreeFree. */
+{
+struct genomeRangeTree *t;
+AllocVar(t); 
+t->hash = newHash(hashPowerOfTwoSize);
+t->lm = lmInit(0);
+return t;
+}
+
+struct genomeRangeTree *genomeRangeTreeNew()
+/* Create a new, empty, genomeRangeTree. Uses the default hash size.
+ * Free with genomeRangeTreeFree. */
+{
+return genomeRangeTreeNewSize(0);
+}
+
+void genomeRangeTreeFree(struct genomeRangeTree **pTree)
+/* Free up genomeRangeTree.  */
+{
+/* need to manually free object due to thee way rbTreeNewDetailed is done */
+struct hashCookie hc = hashFirst((*pTree)->hash);
+struct hashEl *hel;
+while ((hel = hashNext(&hc)) != NULL)
+    freeMem(hel->val);
+
+lmCleanup(&((*pTree)->lm));  /* clean up all the memory for all nodes for all trees */
+freeHash(&((*pTree)->hash)); /* free the hash table including names (trees are freed by lmCleanup) */
+freez(pTree);                /* free this */
+}
+
+struct rbTree *genomeRangeTreeFindRangeTree(struct genomeRangeTree *tree, char *chrom)
+/* Find the rangeTree for this chromosome, if any. Returns NULL if chrom not found.
+ * Free with genomeRangeTreeFree. */
+{
+return hashFindVal(tree->hash, chrom);
+}
+
+struct rbTree *genomeRangeTreeFindOrAddRangeTree(struct genomeRangeTree *tree, char *chrom)
+/* Find the rangeTree for this chromosome, or add new chrom and empty rangeTree if not found.
+ * Free with genomeRangeTreeFree. */
+{
+struct hashEl *hel;
+hel = hashStore(tree->hash, chrom);
+if (hel->val == NULL) /* need to add a new rangeTree */
+    hel->val = rangeTreeNewDetailed(tree->lm, tree->stack);
+return hel->val;
+}
+
+struct range *genomeRangeTreeAdd(struct genomeRangeTree *tree, char *chrom, int start, int end)
+/* Add range to tree, merging with existing ranges if need be. 
+ * Adds new rangeTree if chrom not found. */
+{
+return rangeTreeAdd(genomeRangeTreeFindOrAddRangeTree(tree,chrom), start, end);
+}
+
+struct range *genomeRangeTreeAddVal(struct genomeRangeTree *tree, char *chrom, int start, int end, void *val, void *(*mergeVals)(void *existing, void*new))
+/* Add range to tree, merging with existing ranges if need be. 
+ * Adds new rangeTree if chrom not found. 
+ * If this is a new range, set the value to this val.
+ * If there are existing items for this range, and if mergeVals function is not null, 
+ * apply mergeVals to the existing values and this new val, storing the result as the val
+ * for this range (see rangeTreeAddValCount() and rangeTreeAddValList() below for examples). */
+{
+return rangeTreeAddVal(genomeRangeTreeFindOrAddRangeTree(tree,chrom), start, end, val, mergeVals);
+}
+
+struct range *genomeRangeTreeAddValCount(struct genomeRangeTree *tree, char *chrom, int start, int end)
+/* Add range to tree, merging with existing ranges if need be. 
+ * Adds new rangeTree if chrom not found. 
+ * Set range val to count of elements in the range. Counts are pointers to 
+ * ints allocated in tree localmem */
+{
+return rangeTreeAddValCount(genomeRangeTreeFindOrAddRangeTree(tree,chrom), start, end);
+}
+
+struct range *genomeRangeTreeAddValList(struct genomeRangeTree *tree, char *chrom, int start, int end, void *val)
+/* Add range to tree, merging with existing ranges if need be. 
+ * Adds new rangeTree if chrom not found. 
+ * Add val to the list of values (if any) in each range.
+ * val must be valid argument to slCat (ie, be a struct with a 'next' pointer as its first member) */
+{
+return rangeTreeAddValList(genomeRangeTreeFindOrAddRangeTree(tree,chrom), start, end, val);
+}
+
+boolean genomeRangeTreeOverlaps(struct genomeRangeTree *tree, char *chrom, int start, int end)
+/* Return TRUE if start-end overlaps anything in tree */
+{
+struct rbTree *t;
+return (t=genomeRangeTreeFindRangeTree(tree,chrom)) ? rangeTreeOverlaps(t, start, end) : FALSE;
+}
+
+int genomeRangeTreeOverlapSize(struct genomeRangeTree *tree, char *chrom, int start, int end)
+/* Return the total size of intersection between interval
+ * from start to end, and items in range tree. Sadly not
+ * thread-safe. */
+{
+struct rbTree *t;
+return (t=genomeRangeTreeFindRangeTree(tree,chrom)) ? rangeTreeOverlapSize(t, start, end) : 0;
+}
+
+struct range *genomeRangeTreeFindEnclosing(struct genomeRangeTree *tree, char *chrom, int start, int end)
+/* Find item in range tree that encloses range between start and end 
+ * if there is any such item. */
+{
+struct rbTree *t;
+return (t=genomeRangeTreeFindRangeTree(tree,chrom)) ? rangeTreeFindEnclosing(t, start, end) : NULL;
+}
+
+struct range *genomeRangeTreeAllOverlapping(struct genomeRangeTree *tree, char *chrom, int start, int end)
+/* Return list of all items in range tree that overlap interval start-end.
+ * Do not free this list, it is owned by tree.  However it is only good until
+ * next call to rangeTreeFindInRange or rangeTreeList. Not thread safe. */
+{
+struct rbTree *t;
+return (t=genomeRangeTreeFindRangeTree(tree,chrom)) ? rangeTreeAllOverlapping(t, start, end) : NULL;
+}
+
+struct range *genomeRangeTreeMaxOverlapping(struct genomeRangeTree *tree, char *chrom, int start, int end)
+/* Return item that overlaps most with start-end. Not thread safe.  Trashes list used
+ * by rangeTreeAllOverlapping. */
+{
+struct rbTree *t;
+return (t=genomeRangeTreeFindRangeTree(tree,chrom)) ? rangeTreeMaxOverlapping(t, start, end) : NULL;
+}
+
+struct range *genomeRangeTreeList(struct genomeRangeTree *tree, char *chrom)
+/* Return list of all ranges in single rangeTree in order.  Not thread safe. 
+ * No need to free this when done, memory is local to tree. */
+{
+struct rbTree *t;
+return (t=genomeRangeTreeFindRangeTree(tree,chrom)) ? rangeTreeList(t) : NULL;
+}
+
+/* globals used for genomeRangeTreeToString */
+struct dyString *tmpTreeToString = NULL;
+char *tmpTreeToStringCurChrom = NULL;
+void tmpNodeToString(void *item)
+{
+struct range *r = item;
+dyStringPrintf(tmpTreeToString, " (%d,%d)", r->start, r->end);
+}
+
+struct dyString *genomeRangeTreeToString(struct genomeRangeTree *tree)
+/* Return a string representation of the genomeRangeTree.
+ * Useful for testing.
+ * Not thread-safe; uses globals */
+{
+struct hashEl *chrom, *chromList = hashElListHash(tree->hash);
+slSort(&chromList, hashElCmp); /* alpha sort on chrom */
+dyStringFree(&tmpTreeToString);
+tmpTreeToString = newDyString(0);
+dyStringAppend(tmpTreeToString, "[tree");
+for (chrom = chromList ; chrom ; chrom = chrom->next)
+    {
+    dyStringPrintf(tmpTreeToString, " [%s:", chrom->name);
+    rbTreeTraverse(genomeRangeTreeFindRangeTree(tree, chrom->name), tmpNodeToString);
+    dyStringAppend(tmpTreeToString, "]");
+    }
+dyStringAppend(tmpTreeToString, "]");
+hashElFreeList(&chromList);
+return tmpTreeToString;
+}
+
diff --git a/lib/gfNet.c b/lib/gfNet.c
new file mode 100644
index 0000000..2c9e04f
--- /dev/null
+++ b/lib/gfNet.c
@@ -0,0 +1,21 @@
+/* gfNet.c - Network dependent stuff for blat server. */
+
+#include "common.h"
+#include "errabort.h"
+#include "genoFind.h"
+#include "net.h"
+
+
+int gfConnect(char *hostName, char *portName)
+/* Start connection with server. */
+{
+/* Connect to server. */
+int sd = netConnect(hostName, atoi(portName));
+if (sd < 0)
+    {
+    errnoAbort("Sorry, the BLAT/iPCR server seems to be down.  Please try "
+               "again later.");
+    }
+return sd;
+}
+
diff --git a/lib/gff.c b/lib/gff.c
new file mode 100644
index 0000000..14309e4
--- /dev/null
+++ b/lib/gff.c
@@ -0,0 +1,476 @@
+/* gff - routines to read many types of gff and gtf files
+ * and turn them into a relatively easy to deal with form
+ * in memory.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+#include "common.h"
+#include "hash.h"
+#include "linefile.h"
+#include "gff.h"
+#include "obscure.h"
+#include "dystring.h"
+
+
+void gffGroupFree(struct gffGroup **pGroup)
+/* Free up a gffGroup including lineList. */
+{
+struct gffGroup *group;
+if ((group = *pGroup) != NULL)
+    {
+    slFreeList(&group->lineList);
+    freez(pGroup);
+    }
+}
+
+void gffGroupFreeList(struct gffGroup **pList)
+/* Free up a list of gffGroups. */
+{
+struct gffGroup *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    gffGroupFree(&el);
+    }
+*pList = NULL;
+}
+
+
+void gffFileFree(struct gffFile **pGff)
+/* Free up a gff file. */
+{
+struct gffFile *gff;
+if ((gff = *pGff) != NULL)
+    {
+    freeMem(gff->fileName);
+    freeHash(&gff->seqHash);
+    freeHash(&gff->sourceHash);
+    freeHash(&gff->featureHash);
+    freeHash(&gff->groupHash);
+    freeHash(&gff->geneIdHash);
+    freeHash(&gff->strPool);
+    slFreeList(&gff->lineList);
+    slFreeList(&gff->seqList);
+    slFreeList(&gff->sourceList);
+    slFreeList(&gff->featureList);
+    slFreeList(&gff->geneIdList);
+    gffGroupFreeList(&gff->groupList);
+    freez(pGff);
+    }
+}
+
+static char *gffFileGetStr(struct gffFile *gff, char *str)
+/* get a string from the string pool */
+{
+return hashStore(gff->strPool,  str)->name;
+}
+
+int gffLineCmp(const void *va, const void *vb)
+/* Compare two gffLines. */
+{
+const struct gffLine *a = *((struct gffLine **)va);
+const struct gffLine *b = *((struct gffLine **)vb);
+int diff;
+
+/* for overlaping starts, sort by end, genePredFromGroupedGtf() depends on
+ * this */
+diff = strcmp(a->seq, b->seq);
+if (diff == 0)
+    diff = a->start - b->start;
+if (diff == 0)
+    diff = a->end - b->end;
+return diff;
+}
+
+
+static void gffSyntaxError(char *fileName, int line, char *msg)
+/* Complain about syntax error in GFF file. */
+{
+errAbort("%s Bad line %d of %s:\n", msg, line, fileName);
+}
+
+static char *gffTnName(char *seqName, char *groupName)
+/* Make name that encorperates seq and group names.... */
+{
+static struct dyString *nameBuf = NULL;
+if (nameBuf == NULL)
+    nameBuf = dyStringNew(0);
+dyStringClear(nameBuf);
+if (startsWith("gene-", groupName))
+    groupName += 5;
+if (startsWith("cc_", groupName))
+    groupName += 3;
+dyStringAppend(nameBuf, groupName);
+
+return nameBuf->string;
+}
+
+static boolean isGtfGroup(char *group)
+/* Return TRUE if group field looks like GTF */
+{
+if (strstr(group, "gene_id") == NULL)
+    return FALSE;
+if (countChars(group, '"') >= 2)
+    return TRUE;
+if (strstr(group, "transcript_id") != NULL)
+    return TRUE;
+return FALSE;
+}
+
+boolean gffHasGtfGroup(char *line)
+/* Return TRUE if line has a GTF group field */
+{
+char *words[10];
+char *dupe = cloneString(line);
+int wordCt = chopTabs(dupe, words);
+boolean isGtf = FALSE;
+if (wordCt >= 9) 
+    if (isGtfGroup(words[8]))
+        isGtf = TRUE;
+freeMem(dupe);
+return isGtf;
+}
+
+static void readQuotedString(char *fileName, int lineIx, char *in, char *out, char **retNext)
+/* Parse quoted string and abort on error. */
+{
+if (!parseQuotedString(in, out, retNext))
+    errAbort("Line %d of %s\n", lineIx, fileName);
+}
+
+static void parseGtfEnd(char *s, struct gffFile *gff, struct gffLine *gl, 
+    char *fileName, int lineIx)
+/* Read the semi-colon separated end bits of a GTF line into gl and
+ * hashes. */
+{
+char *type, *val;
+struct hashEl *hel;
+bool gotSemi;
+
+for (;;)
+   {
+   gotSemi = FALSE;
+   if ((type = nextWord(&s)) == NULL)
+       break;
+   s = skipLeadingSpaces(s);
+   if (NULL == s || s[0] == 0)
+       errAbort("Unpaired type(%s)/val on end of gtf line %d of %s", type, lineIx, fileName);
+   if (s[0] == '"' || s[0] == '\'')
+       {
+       val = s;
+       readQuotedString(fileName, lineIx, s, val, &s);
+       }
+   else
+       {
+       int len;
+       val = nextWord(&s);
+       len = strlen(val) - 1;
+       if (val[len] == ';')
+	   {
+	   val[len] = 0;
+	   len -= 1;
+           gotSemi = TRUE;
+	   }
+       if (len < 0)
+           errAbort("Empty value for %s line %d of %s", type, lineIx, fileName);
+       }
+   if (s != NULL && !gotSemi)
+      {
+      s = strchr(s, ';');
+      if (s != NULL)
+         ++s;
+      }
+   /* only use the first occurance of gene_id and transcript_id */
+   if (sameString("gene_id", type) && (gl->geneId == NULL))
+       {
+       struct gffGeneId *gg;
+       if ((hel = hashLookup(gff->geneIdHash, val)) == NULL)
+	   {
+	   AllocVar(gg);
+           hel = hashAdd(gff->geneIdHash, val, gg);
+	   gg->name = hel->name;
+	   slAddHead(&gff->geneIdList, gg);
+	   }
+	else
+	   {
+	   gg = hel->val;
+	   }
+       gl->geneId = gg->name;
+       }
+   else if (sameString("transcript_id", type) && (gl->group == NULL))
+       {
+       struct gffGroup *gg;
+       if ((hel = hashLookup(gff->groupHash, val)) == NULL)
+	   {
+	   AllocVar(gg);
+           hel = hashAdd(gff->groupHash, val, gg);
+	   gg->name = hel->name;
+	   gg->seq = gl->seq;
+	   gg->source = gl->source;
+	   slAddHead(&gff->groupList, gg);
+	   }
+	else
+	   {
+	   gg = hel->val;
+	   }
+       gl->group = gg->name;
+       }
+   else if (sameString("exon_id", type))
+       gl->exonId = gffFileGetStr(gff, val);
+   else if (sameString("exon_number", type))
+       {
+       if (!isdigit(val[0]))
+           errAbort("Expecting number after exon_number, got %s line %d of %s", val, lineIx, fileName);
+       gl->exonNumber = atoi(val);
+       }
+   else if (sameString("intron_id", type))
+       gl->intronId = gffFileGetStr(gff, val);
+   else if (sameString("intron_status", type))
+       gl->intronStatus = gffFileGetStr(gff, val);
+   else if (sameString("protein_id", type))
+       gl->proteinId = gffFileGetStr(gff, val);
+   else if (sameString("gene_name", type))
+       gl->geneName = gffFileGetStr(gff, val);
+   else if (sameString("transcript_name", type))
+       gl->transcriptName = gffFileGetStr(gff, val);
+   }
+if (gl->group == NULL)
+    {
+    if (gl->geneId == NULL)
+        warn("No gene_id or transcript_id line %d of %s", lineIx, fileName);
+    }
+}
+
+void gffFileAddRow(struct gffFile *gff, int baseOffset, char *words[], int wordCount, 
+    char *fileName, int lineIx)
+/* Process one row of GFF file (a non-comment line parsed by tabs normally). */
+{
+struct hashEl *hel;
+struct gffLine *gl;
+
+if (wordCount < 8)
+    gffSyntaxError(fileName, lineIx, "Word count less than 8 ");
+AllocVar(gl);
+
+if ((hel = hashLookup(gff->seqHash, words[0])) == NULL)
+    {
+    struct gffSeqName *el;
+    AllocVar(el);
+    hel = hashAdd(gff->seqHash, words[0], el);
+    el->name = hel->name;
+    slAddHead(&gff->seqList, el);
+    }
+gl->seq = hel->name;
+
+if ((hel = hashLookup(gff->sourceHash, words[1])) == NULL)
+    {
+    struct gffSource *el;
+    AllocVar(el);
+    hel = hashAdd(gff->sourceHash, words[1], el);
+    el->name = hel->name;
+    slAddHead(&gff->sourceList, el);
+    }
+gl->source = hel->name;
+
+if ((hel = hashLookup(gff->featureHash, words[2])) == NULL)
+    {
+    struct gffFeature *el;
+    AllocVar(el);
+    hel = hashAdd(gff->featureHash, words[2], el);
+    el->name = hel->name;
+    slAddHead(&gff->featureList, el);
+    }
+gl->feature = hel->name;
+
+if (!isdigit(words[3][0]) || !isdigit(words[4][0]))
+   gffSyntaxError(fileName, lineIx, "col 3 or 4 not a number ");	
+gl->start = atoi(words[3])-1 + baseOffset;
+gl->end = atoi(words[4]) + baseOffset;
+gl->score = atof(words[5]);
+gl->strand = words[6][0];
+gl->frame = words[7][0];
+
+if (wordCount >= 9)
+    {
+    if (!gff->typeKnown)
+	{
+	gff->typeKnown = TRUE;
+	gff->isGtf = isGtfGroup(words[8]);
+	}
+    if (gff->isGtf)
+	{
+	parseGtfEnd(words[8], gff, gl, fileName, lineIx);
+	}
+    else
+	{
+	char *tnName = gffTnName(gl->seq, trimSpaces(words[8]));
+	if ((hel = hashLookup(gff->groupHash, tnName)) == NULL)
+	    {
+	    struct gffGroup *group;
+	    AllocVar(group);
+	    hel = hashAdd(gff->groupHash, tnName, group);
+	    group->name = hel->name;
+	    group->seq = gl->seq;
+	    group->source = gl->source;
+	    slAddHead(&gff->groupList, group);
+	    }
+	gl->group = hel->name;
+	}
+    }
+slAddHead(&gff->lineList, gl);
+}
+
+
+void gffFileAdd(struct gffFile *gff, char *fileName, int baseOffset)
+/* Create a gffFile structure from a GFF file. */
+{
+/* Open file and do basic allocations. */
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *line, *words[9];
+int lineSize, wordCount;
+
+while (lineFileNext(lf, &line, &lineSize))
+    {
+    if (line[0] != '#')
+	{
+	wordCount = chopTabs(line, words);
+        if (wordCount > 0)
+            gffFileAddRow(gff, baseOffset, words, wordCount, lf->fileName, lf->lineIx);
+	}
+    }
+slReverse(&gff->lineList);
+slReverse(&gff->seqList);
+slReverse(&gff->sourceList);
+slReverse(&gff->featureList);
+slReverse(&gff->groupList);
+slReverse(&gff->geneIdList);
+lineFileClose(&lf);
+}
+
+struct gffFile *gffFileNew(char *fileName)
+/* Create a new gffFile structure. */
+{
+struct gffFile *gff;
+AllocVar(gff);
+gff->fileName = cloneString(fileName);
+gff->seqHash = newHash(18);
+gff->sourceHash = newHash(6);
+gff->featureHash = newHash(6);
+gff->groupHash = newHash(16);
+gff->geneIdHash = newHash(16);
+gff->strPool = newHash(20);
+return gff;
+}
+
+struct gffFile *gffRead(char *fileName)
+/* Create a gffFile structure from a GFF file. */
+{
+struct gffFile *gff = gffFileNew(fileName);
+gffFileAdd(gff, fileName, 0);
+return gff;
+}
+
+static void getGroupBoundaries(struct gffGroup *group)
+/* Fill in start, end, strand of group from lines. */
+{
+struct gffLine *line;
+int start = 0x3fffffff;
+int end = -start;
+line = group->lineList;
+group->strand = line->strand;
+for (; line != NULL; line = line->next)
+    {
+    if (start > line->start)
+	start = line->start;
+    if (end < line->end)
+	end = line->end;
+    }
+group->start = start;
+group->end = end;
+}
+
+void gffGroupLines(struct gffFile *gff)
+/* Group lines of gff file together, in process mofing
+ * gff->lineList to gffGroup->lineList. */
+{
+struct gffLine *line, *nextLine;
+struct hash *groupHash = gff->groupHash;
+char *groupName;
+struct gffGroup *group;
+struct gffLine *ungroupedLines = NULL;
+
+for (line = gff->lineList; line != NULL; line = nextLine)
+    {
+    nextLine = line->next;
+    if ((groupName = line->group) != NULL)
+	{
+	struct hashEl *hel = hashLookup(groupHash, groupName);
+	group = hel->val;
+	slAddHead(&group->lineList, line);
+	}
+    else
+	{
+	slAddHead(&ungroupedLines, line);
+	}
+    }
+
+/* Restore ungrouped lines to gff->lineList. */
+slReverse(&ungroupedLines);
+gff->lineList = ungroupedLines;
+
+/* Restore order of grouped lines and fill in start and end. */
+for (group = gff->groupList; group != NULL; group = group->next)
+    {
+    slSort(&group->lineList, gffLineCmp);
+    getGroupBoundaries(group);
+    }
+}
+
+void gffOutput(struct gffLine *el, FILE *f, char sep, char lastSep) 
+/* Print out GTF.  Separate fields with sep. Follow last field with lastSep. */
+{
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->seq);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->source);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->feature);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%u", el->start+1);
+fputc(sep,f);
+fprintf(f, "%u", el->end);
+fputc(sep,f);
+fprintf(f, "%f", el->score);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%c", el->strand);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%c", el->frame);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+if (el->geneId != NULL)
+    fprintf(f, "gene_id %s\"%s%s\"; ",
+	    (sep == ',') ? "\\" : "",
+	    el->geneId,
+	    (sep == ',') ? "\\" : "");
+fprintf(f, "transcript_id %s\"%s%s\"; ",
+	(sep == ',') ? "\\" : "",
+	el->group,
+	(sep == ',') ? "\\" : "");
+if (el->exonId != NULL)
+    fprintf(f, "exon_id %s\"%s%s\"; ",
+	    (sep == ',') ? "\\" : "",
+	    el->exonId,
+	    (sep == ',') ? "\\" : "");
+if (sep == ',') fputc('"',f);
+fputc(lastSep,f);
+}
+
diff --git a/lib/gff3.c b/lib/gff3.c
new file mode 100644
index 0000000..2aab05f
--- /dev/null
+++ b/lib/gff3.c
@@ -0,0 +1,1091 @@
+/*
+ * Object for accessing GFF3 files
+ * See GFF3 specification for details of file format:
+ *   http://www.sequenceontology.org/gff3.shtml
+ */
+#include "common.h"
+#include "gff3.h"
+#include <limits.h>
+#include "errabort.h"
+#include "localmem.h"
+#include "hash.h"
+#include "linefile.h"
+#include "dystring.h"
+#include "fa.h"
+
+// FIXME: spec unclear if attributes can be specified multiple times
+// FIXME: spec unclear on attribute of discontinuous features.
+// FIXME: should spaces be striped from attributes?
+
+/*
+ * Notes:
+ *   - a separate feature object that linked discontinuous feature annotations
+ *     was not used because it create more complexity with the linking of parents
+ *     and the fact that the restriction on discontinguous features attributes is
+ *     not clearly defined.
+ */
+
+static const int gffNumCols = 9;
+
+/* standard attribute names */
+char *gff3AttrID = "ID";
+char *gff3AttrName = "Name";
+char *gff3AttrAlias = "Alias";
+char *gff3AttrParent = "Parent";
+char *gff3AttrTarget = "Target";
+char *gff3AttrGap = "Gap";
+char *gff3AttrDerivesFrom = "Derives_from";
+char *gff3AttrNote = "Note";
+char *gff3AttrDbxref = "Dbxref";
+char *gff3AttrOntologyTerm = "Ontology_term";
+
+/* commonly used features names */
+char *gff3FeatGene = "gene";
+char *gff3FeatMRna = "mRNA";
+char *gff3FeatExon = "exon";
+char *gff3FeatCDS = "CDS";
+char *gff3FeatThreePrimeUTR = "three_prime_UTR";
+char *gff3FeatFivePrimeUTR = "five_prime_UTR";
+char *gff3FeatStartCodon = "start_codon";
+char *gff3FeatStopCodon = "stop_codon";
+
+static bool gff3FileStopDueToErrors(struct gff3File *g3f)
+/* determine if we should stop due to the number of errors */
+{
+return g3f->errCnt > g3f->maxErr;
+}
+
+static void gff3FileErr(struct gff3File *g3f, char *format, ...)
+#if defined(__GNUC__)
+__attribute__((format(printf, 2, 3)))
+#endif
+;
+
+static void gff3AnnErr(struct gff3Ann *g3a, char *format, ...)
+#if defined(__GNUC__)
+__attribute__((format(printf, 2, 3)))
+#endif
+;
+
+static void vaGff3FileErr(struct gff3File *g3f, char *format, va_list args)
+/* Print error message to error file, abort if max errors have been reached */
+{
+if (g3f->lf != NULL)
+    fprintf(g3f->errFh, "%s:%d: ", g3f->lf->fileName, g3f->lf->lineIx);
+vfprintf(g3f->errFh, format, args);
+fprintf(g3f->errFh, "\n");
+g3f->errCnt++;
+if (gff3FileStopDueToErrors(g3f))
+    errAbort("GFF3: %d parser errors", g3f->errCnt);
+}
+
+static void gff3FileErr(struct gff3File *g3f, char *format, ...)
+/* Print error message and abort */
+{
+va_list args;
+va_start(args, format);
+vaGff3FileErr(g3f, format, args);
+va_end(args);
+}
+
+static void gff3AnnErr(struct gff3Ann *g3a, char *format, ...)
+/* Print error message abort */
+{
+va_list args;
+va_start(args, format);
+vaGff3FileErr(g3a->file, format, args);
+va_end(args);
+}
+
+static int gff3FileStrToInt(struct gff3File *g3f, char *str)
+/* convert a string to an integer */
+{
+char *end;
+long val = strtol(str, &end, 0);
+if ((end == str) || (*end != '\0'))
+    gff3FileErr(g3f, "invalid integer: %s", str);
+return (int)val;
+}
+
+static float gff3FileStrToFloat(struct gff3File *g3f, char *str)
+/* convert a string to a float  */
+{
+char *end;
+double val = strtod(str, &end);
+if ((end == str) || (*end != '\0'))
+    gff3FileErr(g3f, "invalid float: %s", str);
+return (float)val;
+}
+
+static void *gff3FileAlloc(struct gff3File *g3f, size_t size)
+/* allocate memory from the memory pool */
+{
+return lmAlloc(g3f->pool->lm, size);
+}
+
+static char *gff3FileCloneStr(struct gff3File *g3f, char *str)
+/* allocate memory for a string and copy if */
+{
+return lmCloneString(g3f->pool->lm, str);
+}
+
+static char *gff3FilePooledStr(struct gff3File *g3f, char *str)
+/* allocate memory for a string from the shared string pool */
+{
+return hashStore(g3f->pool, str)->name;
+}
+
+static struct slName *gff3FileSlNameNew(struct gff3File *g3f, char *name)
+/* allocate slName from the memory pool */
+{
+return lmSlName(g3f->pool->lm, name);
+}
+
+
+static char **dynChopStringWhite(struct gff3File *g3f, char *str, int minWords, int maxWords, int *numWordsRet, char *desc)
+/* dynamic chop string without corrupting it, generate error if expected
+ * number of words not found. Free return when done. Returns NULL on
+ * error. */
+{
+int numWords = chopByWhite(str, NULL, 0);
+if ((numWords < minWords) || (numWords > maxWords))
+    {
+    gff3FileErr(g3f, "expected %s, got \"%s\"", desc, str);
+    return NULL;
+    }
+// allocate buffer for both array and string
+int wordsBytes = ((numWords+1)*sizeof(char**));
+char **words = needMem(wordsBytes+strlen(str)+1);
+char *strcp = ((char*)words)+wordsBytes;
+strcpy(strcp, str);
+chopByWhite(strcp, words, numWords);
+words[numWords] = NULL;
+if (numWordsRet != NULL)
+    *numWordsRet = numWords;
+return words;
+}
+
+struct gff3Attr *gff3AnnFindAttr(struct gff3Ann *g3a, char *tag)
+/* find a user attribute, or NULL */
+{
+struct gff3Attr *attr;
+for (attr = g3a->attrs; attr != NULL; attr = attr->next)
+    {
+    if (sameString(attr->tag, tag))
+        return attr;
+    }
+return NULL;
+}
+
+static struct gff3AnnRef *gff3AnnRefAlloc(struct gff3Ann *g3a)
+/* construct an annotation reference, allocated in the memory pool*/
+{
+struct gff3AnnRef *ref = gff3FileAlloc(g3a->file, sizeof(struct gff3AnnRef));
+ref->ann = g3a;
+return ref;
+}
+
+static void raiseInvalidEscape(struct gff3Ann *g3a, char *str)
+/* raise an error about an invalid escape in a string */
+{
+gff3AnnErr(g3a, "invalid GFF escape sequence in string: %s", str);
+}
+
+static char convertEscape(struct gff3Ann *g3a, char *esc, char *src)
+/* convert character at esc, which should start with a `%' and be a string
+ * in the form `%09' */
+{
+if (!(isxdigit(esc[1]) && isxdigit(esc[1])))
+    raiseInvalidEscape(g3a, src);
+char num[3], *end;
+strncpy(num, esc+1, 2);
+num[2] = '\0';
+long val = strtol(num, &end, 16);
+if ((end == num) || (*end != '\0'))
+    raiseInvalidEscape(g3a, src);
+return (char)val;
+}
+
+static void unescapeStr(struct gff3Ann *g3a, char *dest, char *src)
+/* remove URL-style escapes from a string. dest need only have enough
+ * memory to hold src, as unescaping will not grow the string */
+{
+char *s = src, *d = dest;
+while (*s != '\0')
+    {
+    if (*s == '%')
+        {
+        *d++ = convertEscape(g3a, s, src);
+        s += 3;
+        }
+    else
+        *d++ = *s++;
+    }
+*d = '\0';
+}
+
+static struct slName *unescapeSlName(struct gff3Ann *g3a, char *src)
+/* unescape the string and put in an slName object, storing it in memory
+ * allocated from localmem  */
+{
+struct slName *dest = gff3FileAlloc(g3a->file, sizeof(struct slName)+strlen(src));
+unescapeStr(g3a, dest->name, src);
+return dest;
+}
+
+static char *unescapeStrTmp(struct gff3Ann *g3a, char *src)
+/* unescape the string into a tmp buffer. WARNING: return is a static and
+ * maybe invalidated by calling another unescape function */
+{
+static struct dyString *buf = NULL;  // buffer for tmp copy of unescaped string
+if (buf == NULL)
+    buf = dyStringNew(256);
+dyStringBumpBufSize(buf, strlen(src)+1);
+unescapeStr(g3a, buf->string, src);
+return buf->string;
+}
+
+static char *unescapeStrPooled(struct gff3Ann *g3a, char *src)
+/* unescape the string and obtain it from localmem  */
+{
+return gff3FilePooledStr(g3a->file, unescapeStrTmp(g3a, src));
+}
+
+static char *escapeChar(char c)
+/* escape a character.  Warning: static return */
+{
+static char ec[4];
+safef(ec, sizeof(ec), "%%%02X", c);
+return ec;
+}
+
+static boolean isMetaChar(char c)
+/* determine if a character is a GFF3 meta character */
+{
+return ((c == '\t') || (c == '\n') || (c == '\r') || !isprint(c) || (c == ';') || (c == '=') || (c == '&') || (c == ','));
+}
+
+static void writeEscaped(char *str, FILE *fh)
+/* write a data string to a file, escaping as needed */
+{
+char *c;
+for (c = str; *c != '\0'; c++)
+    {
+    if (isMetaChar(*c))
+        fputs(escapeChar(*c), fh);
+    else
+        fputc(*c, fh);
+    }
+}
+
+static char *parseStrand(struct gff3Ann *g3a, char *strand)
+/* parse strand into static string, validating it */
+{
+if (sameString(strand, "."))
+    return NULL;
+else if (sameString(strand, "+"))
+    return "+";
+else if (sameString(strand, "-"))
+    return "-";
+else if (sameString(strand, "?"))
+    return "?";
+else
+    gff3AnnErr(g3a, "invalid strand: '%s'", strand);
+return NULL;
+}
+
+static int parsePhase(struct gff3Ann *g3a, char *str)
+/* parse phase into a number, validating it */
+{
+if (sameString(str, "."))
+    return -1;
+int phase = gff3FileStrToInt(g3a->file, str);
+if ((phase < 0) || (phase  > 2))
+    gff3AnnErr(g3a, "invalid phase: %d", phase);
+return phase;
+}
+
+static void parseFields(struct gff3Ann *g3a, char **words)
+/* parse the field in an annotation record */
+{
+g3a->seqid = unescapeStrPooled(g3a, words[0]);
+g3a->source = unescapeStrPooled(g3a, words[1]);
+g3a->type = unescapeStrPooled(g3a, words[2]);
+g3a->start = gff3FileStrToInt(g3a->file, words[3])-1;
+g3a->end = gff3FileStrToInt(g3a->file, words[4]);
+if (!sameString(words[5], "."))
+    {
+    g3a->score = gff3FileStrToFloat(g3a->file, words[5]);
+    g3a->haveScore = TRUE;
+    }
+g3a->strand = parseStrand(g3a, words[6]);
+g3a->phase = parsePhase(g3a, words[7]);
+if (sameString(g3a->type, "CDS"))
+    {
+    if (g3a->phase < 0)
+        gff3AnnErr(g3a, "CDS feature must have phase");
+    }
+else
+    {
+#if 0 // spec unclear; bug report filed
+    // spec currently doesn't restrict phase, unclear if it's allowed on start/stop codon features
+    if (g3a->phase >= 0)
+        gff3AnnErr(g3a, "phase only allowed on CDS features");
+#endif
+    }
+}
+
+/* check that an attribute tag name is valid. */
+static boolean checkAttrTag(struct gff3Ann *g3a, char *tag)
+{
+// FIXME: spec is not clear on what is a valid tag.
+char *tc = tag;
+boolean isOk = isalpha(*tc);
+for (tc++; isOk && (*tc != '\0'); tc++)
+    isOk = (*tc == '_') || isalnum(*tc);
+if (!isOk)
+    gff3AnnErr(g3a, "invalid attribute tag, must start with an alphabetic character and be composed of alphanumeric or underscore characters: %s", tag);
+return isOk;
+}
+
+static struct slName *parseAttrVals(struct gff3Ann *g3a, char *tag, char *valsStr)
+/* parse an attribute into its values */
+{
+int i, numVals = chopString(valsStr, ",", NULL, 0);
+char **vals = needMem((numVals+1)*sizeof(char**)); // +1 allows for no values
+chopString(valsStr, ",", vals, numVals);
+struct slName *unescVals = NULL;
+for (i = 0; i < numVals; i++)
+    slAddHead(&unescVals, unescapeSlName(g3a, vals[i]));
+if (unescVals == NULL)
+    slAddHead(&unescVals, slNameNew(""));  // empty value
+freeMem(vals);
+slReverse(&unescVals);
+return unescVals;
+}
+
+static void addAttr(struct gff3Ann *g3a, char *tag, char *valStr)
+/* Add an attribute to the list of attributes.  If attribute has already been
+ * specified, values are merged.  Attribute name must already be unescaped,
+ * attribute values will be split and then unescaped. */
+{
+struct gff3Attr *attr = gff3AnnFindAttr(g3a, tag);
+if (attr == NULL)
+    {
+    attr = gff3FileAlloc(g3a->file, sizeof(struct gff3Attr));
+    attr->tag = gff3FileCloneStr(g3a->file, tag);
+    slAddHead(&g3a->attrs, attr);
+    }
+attr->vals = slCat(attr->vals, parseAttrVals(g3a, tag, valStr));
+}
+
+static void parseAttr(struct gff3Ann *g3a, char *attrStr)
+/* parse one attribute from an annotation record */
+{
+char *eq = strchr(attrStr, '=');
+if ((eq == NULL) || (eq == attrStr))
+    gff3AnnErr(g3a, "expected name=value: %s", attrStr);
+else
+    {
+    char *tag = attrStr;
+    char *vals = eq+1;
+    *eq = '\0';
+    unescapeStr(g3a, tag, tag);
+    if (checkAttrTag(g3a, tag))
+        addAttr(g3a, tag, vals);
+    }
+}
+
+static void parseAttrs(struct gff3Ann *g3a, char *attrsCol)
+/* parse the attribute column in an annotation record */
+{
+int i, numAttrs = chopString(attrsCol, ";", NULL, 0);
+char **attrStrs = needMem(numAttrs*sizeof(char**));
+chopString(attrsCol, ";", attrStrs, numAttrs);
+for (i = 0; i < numAttrs; i++)
+    {
+    char *attrStr = trimSpaces(attrStrs[i]);
+    if (strlen(attrStr) > 0)
+        parseAttr(g3a, attrStr);
+    }
+freeMem(attrStrs);
+slReverse(&g3a->attrs);
+}
+
+static void checkSingleValAttr(struct gff3Ann *g3a, struct gff3Attr *attr)
+/* validate that an attribute has only one value */
+{
+if (attr->vals->next != NULL)
+    gff3AnnErr(g3a, "attribute %s must have a single value, found multiple comma-separated values", attr->tag);
+}
+
+static void parseIDAttr(struct gff3Ann *g3a, struct gff3Attr *attr)
+/* parse the ID attribute */
+{
+checkSingleValAttr(g3a, attr);
+g3a->id = attr->vals->name;
+// link into other parts of feature if discontinuous
+struct hashEl *hel = hashStore(g3a->file->byId, g3a->id);
+struct gff3Ann *head = hel->val;
+if (head != NULL)
+    head->prevPart = g3a;
+g3a->nextPart = head;
+hel->val = g3a;
+}
+
+static void parseNameAttr(struct gff3Ann *g3a, struct gff3Attr *attr)
+/* parse the Name attribute */
+{
+checkSingleValAttr(g3a, attr);
+g3a->name = attr->vals->name;
+}
+
+static void parseAliasAttr(struct gff3Ann *g3a, struct gff3Attr *attr)
+/* parse the Alias attribute */
+{
+g3a->aliases = attr->vals;
+}
+
+static void parseParentAttr(struct gff3Ann *g3a, struct gff3Attr *attr)
+/* parse the Parent attribute */
+{
+g3a->parentIds = attr->vals;
+}
+
+static void parseTargetAttr(struct gff3Ann *g3a, struct gff3Attr *attr)
+/* parse the Target attribute */
+{
+checkSingleValAttr(g3a, attr);
+
+// target_id start end [strand]
+int numWords;
+char **words = dynChopStringWhite(g3a->file, attr->vals->name, 3, 4, &numWords,
+                                  "Target attribute in the form \"target_id start end [strand]\"");
+if (words == NULL)
+    return;  // got an error
+g3a->targetId = gff3FileCloneStr(g3a->file, words[0]);
+g3a->targetStart = gff3FileStrToInt(g3a->file, words[1])-1;
+g3a->targetEnd = gff3FileStrToInt(g3a->file, words[2]);
+if (numWords > 3)
+    g3a->targetStrand = parseStrand(g3a, words[3]);
+freeMem(words);
+}
+
+static void parseGapAttr(struct gff3Ann *g3a, struct gff3Attr *attr)
+/* parse the Gap attribute */
+{
+checkSingleValAttr(g3a, attr);
+g3a->gap = attr->vals->name;
+}
+
+static void parseDerivesFromAttr(struct gff3Ann *g3a, struct gff3Attr *attr)
+/* parse the Derives_from attribute */
+{
+g3a->derivesFromId = attr->vals->name;
+}
+
+static void parseNoteAttr(struct gff3Ann *g3a, struct gff3Attr *attr)
+/* parse the Note attribute */
+{
+g3a->notes = attr->vals;
+}
+
+static void parseDbxrefAttr(struct gff3Ann *g3a, struct gff3Attr *attr)
+/* parse the Dbxref attribute */
+{
+g3a->dbxrefs = attr->vals;
+}
+
+static void parseOntologyTermAttr(struct gff3Ann *g3a, struct gff3Attr *attr)
+/* parse the Ontology_term attribute */
+{
+g3a->ontologyTerms = attr->vals;
+}
+
+static void parseStdAttr(struct gff3Ann *g3a, struct gff3Attr *attr)
+/* Parse one of the standard specified attributes (those starting with upper
+ * case) into fields. Multiple specifications of an attribute should have been
+ * merged before calling this function. */
+{
+if (sameString(attr->tag, gff3AttrID))
+    parseIDAttr(g3a, attr);
+else if (sameString(attr->tag, gff3AttrName))
+    parseNameAttr(g3a, attr);
+else if (sameString(attr->tag, gff3AttrAlias))
+    parseAliasAttr(g3a, attr);
+else if (sameString(attr->tag, gff3AttrParent))
+    parseParentAttr(g3a, attr);
+else if (sameString(attr->tag, gff3AttrTarget))
+    parseTargetAttr(g3a, attr);
+else if (sameString(attr->tag, gff3AttrGap))
+    parseGapAttr(g3a, attr);
+else if (sameString(attr->tag, gff3AttrDerivesFrom))
+    parseDerivesFromAttr(g3a, attr);
+else if (sameString(attr->tag, gff3AttrNote))
+    parseNoteAttr(g3a, attr);
+else if (sameString(attr->tag, gff3AttrDbxref))
+    parseDbxrefAttr(g3a, attr);
+else if (sameString(attr->tag, gff3AttrOntologyTerm))
+    parseOntologyTermAttr(g3a, attr);
+else
+    gff3AnnErr(g3a, "unknown standard attribute, user defined attributes must start with a lower-case letter: %s", attr->tag);
+}
+
+static void parseStdAttrs(struct gff3Ann *g3a)
+/* parse standard attributes (starting with upper case) into attributes
+ * have been parsed into attribute list, which would have  merged multiply
+ * specified attributes. */
+{
+struct gff3Attr *attr;
+for (attr = g3a->attrs; attr != NULL; attr = attr->next)
+    {
+    if (isupper(attr->tag[0]))
+        parseStdAttr(g3a, attr);
+    }
+}
+
+static void parseAnn(struct gff3File *g3f, char *line)
+/* parse an annotation line */
+{
+// extra column to check for too many
+char *words[gffNumCols+1];
+int numWords = chopString(line, "\t", words, gffNumCols+1);
+if (numWords != gffNumCols)
+    gff3FileErr(g3f, "expected %d tab-separated columns: %s", gffNumCols, line);
+
+struct gff3Ann *g3a = gff3FileAlloc(g3f, sizeof(struct gff3Ann));
+g3a->file = g3f;
+g3a->lineNum = g3f->lf->lineIx;
+parseFields(g3a, words);
+parseAttrs(g3a, words[8]);
+parseStdAttrs(g3a);
+slAddHead(&g3f->anns, gff3AnnRefNew(g3a));
+}
+
+static void writeAttr(struct gff3Attr *attr, FILE *fh)
+/* write one attribute and it's values */
+{
+writeEscaped(attr->tag, fh);
+fputc('=', fh);
+struct slName *val;
+for (val = attr->vals; val != NULL; val = val->next)
+    {
+    if (val != attr->vals)
+        fputc(',', fh);
+    writeEscaped(val->name, fh);
+    }
+}
+
+static void writeAttrs(struct gff3Ann *g3a, FILE *fh)
+/* write annotation record attributes */
+{
+struct gff3Attr *attr;
+for (attr = g3a->attrs; attr != NULL; attr = attr->next)
+    {
+    if (attr != g3a->attrs)
+        fputc(';', fh);
+    writeAttr(attr, fh);
+    }
+}
+
+static void writeFields(struct gff3Ann *g3a, FILE *fh)
+/* write an annotation record fields */
+{
+writeEscaped(g3a->seqid, fh);
+fputc('\t', fh);
+writeEscaped(g3a->source, fh);
+fputc('\t', fh);
+writeEscaped(g3a->type, fh);
+fprintf(fh, "\t%d\t%d", g3a->start+1, g3a->end);
+fputc('\t', fh);
+if (g3a->haveScore)
+    fprintf(fh, "%g", g3a->score);
+else
+    fputc('.', fh);
+fprintf(fh, "\t%c", (g3a->strand != NULL) ? g3a->strand[0] : '.');
+fputc('\t', fh);
+if (g3a->phase < 0)
+    fputc('.', fh);
+else
+    fprintf(fh, "%d", g3a->phase);
+}
+
+static void writeAnn(struct gff3Ann *g3a, FILE *fh)
+/* write an annotation record to the specified file */
+{
+writeFields(g3a, fh);
+fputc('\t', fh);
+writeAttrs(g3a, fh);
+fputc('\n', fh);
+}
+
+static void addFasta(struct gff3File *g3f, char *dna, int size, char *name)
+/* add one fasta record */
+{
+struct dnaSeq *dnaSeq = gff3FileAlloc(g3f, sizeof(struct dnaSeq));
+slAddHead(&g3f->seqs, dnaSeq);
+struct hashEl *hel = hashAdd(g3f->seqMap, name, dnaSeq);
+dnaSeq->name = hel->name;
+dnaSeq->dna = gff3FileCloneStr(g3f, dna);
+dnaSeq->size = size;
+}
+
+static void parseFasta(struct gff3File *g3f)
+/* parse fasta records in the file, consumes remainder of file */
+{
+char *dna, *name;
+int size;
+g3f->seqMap = hashNew(0);
+while (faMixedSpeedReadNext(g3f->lf, &dna, &size, &name))
+    addFasta(g3f, dna, size, name);
+}
+
+static void writeFastas(struct gff3File *g3f, FILE *fh)
+/* write fasta records fo the file */
+{
+if (g3f->seqs != NULL)
+    {
+    fputs("##FASTA\n", fh);
+    struct dnaSeq *seq;
+    for (seq = g3f->seqs; seq != NULL; seq = seq->next)
+        faWriteNext(fh, seq->name, seq->dna, seq->size);
+    }
+}
+
+static void parseSequenceRegion(struct gff3File *g3f, char *line)
+/* parse ##sequence-region seqid start end */
+{
+char **words = dynChopStringWhite(g3f, line, 4, 4, NULL,
+                                  "\"##sequence-region seqid start end\"");
+if (words == NULL)
+    return;  // got an error
+struct gff3SeqRegion *sr = gff3FileAlloc(g3f, sizeof(struct gff3SeqRegion));
+sr->seqid = gff3FileCloneStr(g3f, words[1]);
+sr->start = gff3FileStrToInt(g3f, words[2])-1;
+sr->end = gff3FileStrToInt(g3f, words[3]);
+if (g3f->seqRegionMap == NULL)
+    g3f->seqRegionMap = hashNew(0);
+struct hashEl *hel = hashStore(g3f->seqRegionMap, sr->seqid);
+if (hel->val != NULL)
+    gff3FileErr(g3f, "duplicate ##sequence-region for %s", sr->seqid);
+else
+    {
+    hel->val = sr;
+    slAddHead(&g3f->seqRegions, sr);
+    }
+freeMem(words);
+}
+
+static void writeSequenceRegions(struct gff3File *g3f, FILE *fh)
+/* parse ##sequence-region metadata */
+{
+struct gff3SeqRegion *sr;
+for (sr = g3f->seqRegions; sr != NULL; sr = sr->next)
+    fprintf(fh, "##sequence-region %s %d %d\n", sr->seqid, sr->start, sr->end);
+}
+
+static void writeSlNameMetas(char *metaName, struct slName *metas, FILE *fh)
+/* write meta records stores as slNames */
+{
+struct slName  *m;
+for (m = metas; m != NULL; m = m->next)
+    fprintf(fh, "%s %s\n", metaName, m->name);
+}
+
+static void parseFeatureOntology(struct gff3File *g3f, char *line)
+/* parse ##feature-ontology URI  */
+{
+char **words = dynChopStringWhite(g3f, line, 2, 2, NULL,
+                                  "\"##feature-ontology URI\"");
+if (words == NULL)
+    return;  // got an error
+slSafeAddHead(&g3f->featureOntologies, gff3FileSlNameNew(g3f, words[1]));
+freeMem(words);
+}
+
+static void writeFeatureOntologies(struct gff3File *g3f, FILE *fh)
+/* parse ##feature-ontology metas */
+{
+writeSlNameMetas("##feature-ontology", g3f->featureOntologies, fh);
+}
+
+static void parseAttributeOntology(struct gff3File *g3f, char *line)
+/* parse ##attribute-ontology URI */
+{
+char **words = dynChopStringWhite(g3f, line, 2, 2, NULL,
+                                  "\"##attribute-ontology URI\"");
+if (words == NULL)
+    return;  // got an error
+slSafeAddHead(&g3f->attributeOntologies, gff3FileSlNameNew(g3f, words[1]));
+freeMem(words);
+}
+
+static void writeAttributeOntologies(struct gff3File *g3f, FILE *fh)
+/* write ##attribute-ontology metas */
+{
+writeSlNameMetas("##attribute-ontology", g3f->attributeOntologies, fh);
+}
+
+static void parseSourceOntology(struct gff3File *g3f, char *line)
+/* parse ##source-ontology URI */
+{
+char **words = dynChopStringWhite(g3f, line, 2, 2, NULL,
+                                  "\"##source-ontology URI\"");
+if (words == NULL)
+    return;  // got an error
+slSafeAddHead(&g3f->sourceOntologies, gff3FileSlNameNew(g3f, words[1]));
+freeMem(words);
+}
+
+static void writeSourceOntologies(struct gff3File *g3f, FILE *fh)
+/* write ##source-ontology metas */
+{
+writeSlNameMetas("##source-ontology", g3f->sourceOntologies, fh);
+}
+
+static void parseSpecies(struct gff3File *g3f, char *line)
+/* parse ##species NCBI_Taxonomy_URI */
+{
+char **words = dynChopStringWhite(g3f, line, 2, 2, NULL,
+                                  "\"##species NCBI_Taxonomy_URI\"");
+if (words == NULL)
+    return;  // got an error
+slSafeAddHead(&g3f->species, gff3FileSlNameNew(g3f, words[1]));
+freeMem(words);
+}
+
+static void writeSpecies(struct gff3File *g3f, FILE *fh)
+/* write ##species NCBI_Taxonomy_URI */
+{
+writeSlNameMetas("##species", g3f->species, fh);
+}
+
+static void parseGenomeBuild(struct gff3File *g3f, char *line)
+/* parse ##genome-build source buildName */
+{
+if (g3f->genomeBuildSource != NULL)
+    gff3FileErr(g3f, "multiple ##genome-build records");
+char **words = dynChopStringWhite(g3f, line, 3, 3, NULL,
+                                  "\"##genome-build source buildName\"");
+if (words == NULL)
+    return;  // got an error
+g3f->genomeBuildSource = gff3FileCloneStr(g3f, words[1]);
+g3f->genomeBuildName = gff3FileCloneStr(g3f, words[2]);
+freeMem(words);
+}
+
+static void writeGenomeBuild(struct gff3File *g3f, FILE *fh)
+/* parse ##genome-build source buildName */
+{
+if (g3f->genomeBuildSource != NULL)
+    fprintf(fh, "##genome-build %s %s\n", g3f->genomeBuildSource, g3f->genomeBuildName);
+}
+
+static void parseMeta(struct gff3File *g3f, char *line)
+/* parse a meta line of a gff3 file */
+{
+eraseTrailingSpaces(line);
+if (sameString("###", line))
+    ; // ignore
+else if (sameString("##FASTA", line))
+    parseFasta(g3f);
+else if (startsWithWord("##sequence-region", line))
+    parseSequenceRegion(g3f, line);
+else if (startsWithWord("##feature-ontology", line))
+    parseFeatureOntology(g3f, line);
+else if (startsWithWord("##attribute-ontology", line))
+    parseAttributeOntology(g3f, line);
+else if (startsWithWord("##source-ontology", line))
+    parseSourceOntology(g3f, line);
+else if (startsWithWord("##species", line))
+    parseSpecies(g3f, line);
+else if (startsWithWord("##genome-build", line))
+    parseGenomeBuild(g3f, line);
+else if (startsWithWord("##gff-spec-version", line) ||
+         startsWithWord("##source-version", line) ||
+         startsWithWord("##date", line) ||
+         startsWithWord("##Type", line))
+    ;  /* FIXME: silently ignore these.  Mark says. */
+else
+    gff3FileErr(g3f, "invalid meta line: %s", line);
+}
+
+static void parseLine(struct gff3File *g3f, char *line)
+/* parse one line of a gff3 file */
+{
+if (startsWith("##", line))
+    parseMeta(g3f, line);
+else if (!startsWith("#", line) && (strlen(line) > 0))
+    parseAnn(g3f, line);
+}
+
+static void parseHeader(struct gff3File *g3f)
+/* parse and validate a GFF3 header */
+{
+char *line;
+if (!lineFileNext(g3f->lf, &line, NULL))
+    gff3FileErr(g3f, "empty GFF file, must have header");
+char *ver = skipToSpaces(line);
+if (*ver != '\0')
+    {
+    *ver++ = '\0';
+    ver = trimSpaces(ver);
+    }
+if (!(sameString(line, "##gff-version") && sameString(ver, "3")))
+    gff3FileErr(g3f, "invalid GFF3 header");
+}
+
+static void parseFile(struct gff3File *g3f)
+/* do parsing phase of reading a GFF3 file */
+{
+g3f->lf = lineFileOpen(g3f->fileName, TRUE);
+parseHeader(g3f);
+char *line;
+while (lineFileNext(g3f->lf, &line, NULL))
+    {
+    parseLine(g3f, line);
+    if (gff3FileStopDueToErrors(g3f))
+        break;
+    }
+lineFileClose(&g3f->lf);
+slReverse(&g3f->anns);
+}
+
+static int gff3AnnCount(struct gff3Ann *g3a)
+/* count the number of gff3Ann objects linked together in a feature */
+{
+int cnt = 0;
+for (; g3a != NULL; g3a = g3a->nextPart)
+    cnt++;
+return cnt;
+}
+
+static void discontinFeatureCheck(struct gff3Ann *g3a)
+/* sanity check linked gff3Ann discontinuous features */
+{
+struct gff3Ann *g3a2;
+for (g3a2 = g3a->nextPart; (g3a2 != NULL) && !gff3FileStopDueToErrors(g3a->file); g3a2 = g3a2->nextPart)
+    {
+    if (!sameString(g3a->type, g3a2->type))
+        gff3AnnErr(g3a, "Annotation records for discontinuous features with ID=\"%s\" do not have the same type, found \"%s\" and \"%s\"", g3a->id, g3a->type, g3a2->type);
+    }
+}
+
+static void discontinFeatureFillArray(struct gff3Ann *g3a, int numAnns, struct gff3Ann *featAnns[])
+/* convert list to array for sorting */
+{
+int i = 0;
+for (; g3a != NULL; g3a = g3a->nextPart)
+    featAnns[i++] = g3a;
+}
+
+static struct gff3Ann *discontinFeatureArrayLink(int numAnns, struct gff3Ann *featAnns[])
+/* convert sorted array to a list */
+{
+struct gff3Ann *g3aHead = NULL, *g3aPrev = NULL;
+int i;
+for (i = 0; i < numAnns; i++)
+    {
+    if (g3aHead == NULL)
+        g3aHead = featAnns[i];
+    if (g3aPrev != NULL)
+        g3aPrev->nextPart = featAnns[i];
+    featAnns[i]->prevPart = g3aPrev;
+    }
+return g3aHead;
+}
+
+static int discontigFeatureSortCmp(const void *p1, const void *p2)
+/* compare function for discontigFeatureSort */
+{
+struct gff3Ann *g3a1 = *((struct gff3Ann **)p1);
+struct gff3Ann *g3a2 = *((struct gff3Ann **)p2);
+int diff = g3a1->start - g3a2->start;
+if (diff == 0)
+    diff = g3a1->end - g3a2->end;
+return diff;
+}
+
+static struct gff3Ann *discontigFeatureSort(struct gff3Ann *g3a)
+/* sort a list of gff3Ann object representing discontinuous */
+{
+int numAnns = gff3AnnCount(g3a);
+struct gff3Ann *featAnns[numAnns];
+discontinFeatureFillArray(g3a, numAnns, featAnns);
+qsort(featAnns, numAnns, sizeof(struct gff3Ann*), discontigFeatureSortCmp);
+return discontinFeatureArrayLink(numAnns, featAnns);
+}
+
+static void discontigFeatureFinish(struct gff3File *g3f)
+/* finish up discontinuous features, sorting them into ascending order */
+{
+// only both sorting if more than one annotation
+struct hashCookie cookie = hashFirst(g3f->byId);
+struct hashEl *hel;
+while (((hel = hashNext(&cookie)) != NULL) && !gff3FileStopDueToErrors(g3f))
+    {
+    struct gff3Ann *g3a = hel->val;
+    if (g3a->nextPart != NULL)
+        {
+        discontinFeatureCheck(g3a);
+        hel->val = discontigFeatureSort(g3a);
+        }
+    }
+}
+
+static struct gff3Ann *resolveRef(struct gff3Ann *g3a, char *id, char *attr)
+/* resolve a link for an attribute */
+{
+struct gff3Ann *ann = gff3FileFindAnn(g3a->file, id);
+if (ann == NULL)
+    gff3AnnErr(g3a, "Can't find annotation record \"%s\" referenced by \"%s\" %s attribute", id, g3a->id, attr);
+return ann;
+}
+
+static struct gff3AnnRef *resolveRefs(struct gff3Ann *g3a, struct slName *ids, char *attr)
+/* resolve links for an attribute */
+{
+struct gff3AnnRef *refs = NULL;
+struct slName *id;
+for (id = ids; id != NULL; id = id->next)
+    {
+    struct gff3Ann *ann = resolveRef(g3a, id->name, attr);
+    if (ann != NULL)
+        slSafeAddHead(&refs, gff3AnnRefAlloc(ann));
+    }
+return refs;
+}
+
+static void resolveAnn(struct gff3Ann *g3a)
+/* resolve links for an gff3Ann */
+{
+g3a->parents = resolveRefs(g3a, g3a->parentIds, gff3AttrParent);
+if (g3a->parents == NULL)
+    slSafeAddHead(&g3a->file->roots, gff3AnnRefAlloc(g3a));
+else
+    {
+    struct gff3AnnRef *par;
+    for (par = g3a->parents; par != NULL; par = par->next)
+        slSafeAddHead(&par->ann->children, gff3AnnRefAlloc(g3a));
+    }
+if (g3a->derivesFromId != NULL)
+    g3a->derivesFrom = resolveRef(g3a, g3a->derivesFromId, gff3AttrDerivesFrom);
+}
+
+static void resolveAnns(struct gff3File *g3f)
+/* resolve links */
+{
+struct gff3AnnRef *g3aRef;
+for (g3aRef = g3f->anns; (g3aRef != NULL) && !gff3FileStopDueToErrors(g3f); g3aRef = g3aRef->next)
+    resolveAnn(g3aRef->ann);
+}
+
+static void resolveFile(struct gff3File *g3f)
+/* do resolution phase of reading a GFF3 file */
+{
+// must sort first, as links point to the first feature
+discontigFeatureFinish(g3f);
+resolveAnns(g3f);
+// reorder just for test reproducibility
+slReverse(&g3f->seqRegions);
+slReverse(&g3f->featureOntologies);
+slReverse(&g3f->attributeOntologies);
+slReverse(&g3f->sourceOntologies);
+slReverse(&g3f->species);
+slReverse(&g3f->seqs);
+}
+
+static struct gff3File *gff3FileNew()
+/* construct a new, empty gff3File object */
+{
+struct gff3File *g3f;
+AllocVar(g3f);
+g3f->byId = hashNew(0);
+g3f->pool = hashNew(0);
+return g3f;
+}
+
+struct gff3File *gff3FileOpen(char *fileName, int maxErr, FILE *errFh)
+/* Parse a GFF3 file into a gff3File object.  If maxErr not zero, then
+ * continue to parse until this number of error have been reached.  A maxErr
+ * less than zero does not stop reports all errors. Write errors to errFh,
+ * if NULL, use stderr. */
+{
+struct gff3File *g3f = gff3FileNew();
+g3f->fileName = gff3FileCloneStr(g3f, fileName);
+g3f->errFh = (errFh != NULL) ? errFh : stderr;
+g3f->maxErr = (maxErr < 0) ? INT_MAX : maxErr;
+parseFile(g3f);
+if (!gff3FileStopDueToErrors(g3f))
+    resolveFile(g3f);
+if (g3f->errCnt > 0)
+    errAbort("GFF3: %d parser errors", g3f->errCnt);
+return g3f;
+}
+
+void gff3FileFree(struct gff3File **g3fPtr)
+/* Free a gff3File object */
+{
+struct gff3File *g3f = *g3fPtr;
+if (g3f != NULL)
+    {
+    hashFree(&g3f->byId);
+    hashFree(&g3f->pool);
+    hashFree(&g3f->seqRegionMap);
+    freeMem(g3f);
+    *g3fPtr = NULL;
+    }
+}
+
+struct gff3Ann *gff3FileFindAnn(struct gff3File *g3f, char *id)
+/* find an annotation record by id, or NULL if not found. */
+{
+return hashFindVal(g3f->byId, id);
+}
+
+static void writeMeta(struct gff3File *g3f, FILE *fh)
+/* write meta data */
+{
+fputs("##gff-version 3\n", fh);
+writeSequenceRegions(g3f, fh);
+writeFeatureOntologies(g3f, fh);
+writeAttributeOntologies(g3f, fh);
+writeSourceOntologies(g3f, fh);
+writeSpecies(g3f, fh);
+writeGenomeBuild(g3f, fh);
+}
+
+void gff3FileWrite(struct gff3File *g3f, char *fileName)
+/* write contents of an GFF3File object to a file */
+{
+FILE *fh = mustOpen(fileName, "w");
+writeMeta(g3f, fh);
+struct gff3AnnRef *g3aRef;
+for (g3aRef = g3f->anns; g3aRef != NULL; g3aRef = g3aRef->next)
+    writeAnn(g3aRef->ann, fh);
+writeFastas(g3f, fh);
+carefulClose(&fh);
+}
+
+int gff3AnnRefLocCmp(const void *va, const void *vb)
+/* sort compare function for two gff3AnnRef objects */
+{
+const struct gff3Ann *a = (*((struct gff3AnnRef **)va))->ann;
+const struct gff3Ann *b = (*((struct gff3AnnRef **)vb))->ann;
+int diff = strcmp(a->seqid, b->seqid);
+if ((diff == 0) && (a->strand != b->strand))
+    {
+    // allow for various types of strand fields. above tests handles both null
+    if (a->strand == NULL)
+        diff = 1;
+    else if (b->strand == NULL)
+        diff = -1;
+    else
+        diff = strcmp(a->strand, b->strand);
+    }
+if (diff == 0)
+    diff = a->start - b->start;
+if (diff == 0)
+    diff = a->end - b->end;
+return diff;
+}
diff --git a/lib/gfxPoly.c b/lib/gfxPoly.c
new file mode 100644
index 0000000..48d5419
--- /dev/null
+++ b/lib/gfxPoly.c
@@ -0,0 +1,49 @@
+/* gfxPoly - two dimensional polygon. */
+#include "common.h"
+#include "gfxPoly.h"
+
+
+struct gfxPoly *gfxPolyNew()
+/* Create new (empty) polygon */
+{
+struct gfxPoly *poly;
+AllocVar(poly);
+return poly;
+}
+
+void gfxPolyFree(struct gfxPoly **pPoly)
+/* Free up resources associated with polygon */
+{
+struct gfxPoly *poly = *pPoly;
+if (poly != NULL)
+    {
+    if (poly->lastPoint != NULL)
+	{
+	poly->lastPoint->next = NULL;
+	slFreeList(&poly->ptList);
+	}
+    freez(pPoly);
+    }
+}
+
+void gfxPolyAddPoint(struct gfxPoly *poly, int x, int y)
+/* Add point to polygon. */
+{
+struct gfxPoint *pt;
+poly->ptCount += 1;
+AllocVar(pt);
+pt->x = x;
+pt->y = y;
+if (poly->ptList == NULL)
+    {
+    poly->ptList = poly->lastPoint = pt;
+    pt->next = pt;
+    }
+else
+    {
+    poly->lastPoint->next = pt;
+    pt->next = poly->ptList;
+    poly->lastPoint = pt;
+    }
+}
+
diff --git a/lib/gifLabel.c b/lib/gifLabel.c
new file mode 100644
index 0000000..63c8ea3
--- /dev/null
+++ b/lib/gifLabel.c
@@ -0,0 +1,101 @@
+/* gifLabel - create labels as GIF files. */
+
+#include "common.h"
+#include "memgfx.h"
+#include "portable.h"
+#include "gifLabel.h"
+
+
+int gifLabelMaxWidth(char **labels, int labelCount)
+/* Return maximum pixel width of labels.  It's ok to have
+ * NULLs in labels array. */
+{
+int width = 0, w, i;
+MgFont *font = mgMediumFont();
+for (i=0; i<labelCount; ++i)
+    {
+    char *label = labels[i];
+    if (label != NULL)
+	{
+	w = mgFontStringWidth(font, labels[i]);
+	if (w > width)
+	    width = w;
+	}
+    }
+width += 2;
+return width;
+}
+
+static struct memGfx *altColorLabels(char **labels, int labelCount, int width)
+/* Return a memory image with alternating colors. */
+{
+struct memGfx *mg = NULL;
+Color c1,c2;
+MgFont *font = mgMediumFont();
+int lineHeight = mgFontLineHeight(font)-1;
+int height = lineHeight * labelCount, i;
+int y = 0;
+
+/* Allocate picture and set up colors. */
+mg = mgNew(width, height);
+c1 = mgFindColor(mg, 0xE0, 0xE0, 0xFF);
+c2 = mgFindColor(mg, 0xFF, 0xC8, 0xC8);
+
+/* Draw text. */
+for (i=labelCount-1; i >= 0; --i)
+    {
+    Color c = ((i&1) ? c2 : c1);
+    mgDrawBox(mg, 0, y, width, lineHeight, c);
+    mgTextRight(mg, 0+1, y+1, width-1, lineHeight, MG_BLACK, font, labels[i]);
+    y += lineHeight;
+    }
+
+return mg;
+}
+
+
+boolean sameGifContents(struct memGfx *n1, struct memGfx *n2)
+/* compare two files and return true if their contents are identical using binary compare */
+{
+if (n1 == NULL) {  return FALSE; }
+if (n2 == NULL) { return FALSE; }
+if (n1->width != n2->width) { return FALSE; }
+if (n1->height != n2->height) { return FALSE; }
+if (n1->colorsUsed != n2->colorsUsed) { return FALSE; }
+if (memcmp(n1->colorMap, n2->colorMap, 256 * 3)!=0) { return FALSE; } /* gif colormaps differ */
+long bytes = (long)n1->width * n1->height;
+if (memcmp(n1->pixels, n2->pixels, bytes)!=0) { return FALSE; } /* gif contents differ */
+return TRUE;
+}
+
+void gifLabelVerticalText(char *fileName, char **labels, int labelCount, 
+	int height)
+/* Make a gif file with given labels.  This will check to see if fileName
+ * exists already and has not changed, and if so do nothing. */
+{
+struct memGfx *straight = altColorLabels(labels, labelCount, height);
+struct memGfx *rotated = mgRotate90(straight);
+struct memGfx *existing = NULL;
+struct tempName tn;
+makeTempName(&tn, "gifLabelVertTemp", ".png");
+mgSavePng(rotated, tn.forCgi, FALSE); 
+rename(tn.forCgi, fileName);
+mgFree(&straight);
+mgFree(&rotated);
+if (existing)
+    mgFree(&existing);
+}
+
+
+#ifdef DEBUG
+void gifTest()
+{
+static char *labels[] = {"cerebellum", "thymus", "breast", "heart",
+			 "stomach", "cartilage", "kidney", "liver",
+			 "lung", "testis", "black hole" };
+int size = gifLabelMaxWidth(labels, ArraySize(labels));
+int gifLabelMaxWidth(char **labels, int labelCount)
+gifLabelVerticalText("../trash/foo.gif", labels, ArraySize(labels), size);
+printf("<IMG SRC=\"../trash/foo.gif\">");
+}
+#endif /* DEBUG */
diff --git a/lib/gifcodes.h b/lib/gifcodes.h
new file mode 100644
index 0000000..480ab0d
--- /dev/null
+++ b/lib/gifcodes.h
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+struct gif_header
+	{
+	char giftype[6];
+	unsigned char wlo,whi;
+	unsigned char hlo,hhi;
+	unsigned char colpix;	/* flags */
+	unsigned char bgcolor;
+	unsigned char reserved;
+	};
+
+#define COLTAB	0x80
+#define COLMASK 0x70
+#define COLSHIFT 4
+#define PIXMASK 7
+#define COLPIXVGA13 (COLTAB | (5<<COLSHIFT) | 7)
+
+struct gif_image
+	{
+	unsigned char xlo,xhi;
+	unsigned char ylo,yhi;
+	unsigned char wlo,whi;
+	unsigned char hlo,hhi;
+	unsigned char flags;
+	};
+#define ITLV_BIT 0x40
+
+/* Various error codes used by decoder
+ * and my own routines...   It's okay
+ * for you to define whatever you want,
+ * as long as it's negative...  It will be
+ * returned intact up the various subroutine
+ * levels...
+ */
+#define OUT_OF_MEMORY -10
+#define BAD_CODE_SIZE -20
+#define READ_ERROR -1
+#define WRITE_ERROR -2
+#define OPEN_ERROR -3
+#define CREATE_ERROR -4
+#define TOO_HIGH	-5
+
+short gif_compress_data(int min_code_size, unsigned char *pt, long size, FILE *out);
+int gif_decoder(int linewidth);
diff --git a/lib/gifcomp.c b/lib/gifcomp.c
new file mode 100644
index 0000000..7aa88f3
--- /dev/null
+++ b/lib/gifcomp.c
@@ -0,0 +1,304 @@
+/* comprs.c - LZW compression code for GIF */
+
+/*
+ * ABSTRACT:
+ *	The compression algorithm builds a string translation table that maps
+ *	substrings from the input string into fixed-length codes.  These codes
+ *	are used by the expansion algorithm to rebuild the compressor's table
+ *	and reconstruct the original data stream.  In it's simplest form, the
+ *	algorithm can be stated as:
+ *
+ *		"if <w>k is in the table, then <w> is in the table"
+ *
+ *	<w> is a code which represents a string in the table.  When a new
+ *	character k is read in, the table is searched for <w>k.  If this
+ *	combination is found, <w> is set to the code for that combination
+ *	and the next character is read in.  Otherwise, this combination is
+ *	added to the table, the code <w> is written to the output stream and
+ *	<w> is set to k.
+ *
+ *	The expansion algorithm builds an identical table by parsing each
+ *	received code into a prefix string and suffix character.  The suffix
+ *	character is pushed onto the stack and the prefix string translated
+ *	again until it is a single character.  This completes the expansion.
+ *	The expanded code is then output by popping the stack and a new entry
+ *	is made in the table.
+ *
+ *	The algorithm used here has one additional feature.  The output codes
+ *	are variable length.  They start at a specified number of bits.  Once
+ *	the number of codes exceeds the current code size, the number of bits
+ *	in the code is incremented.  When the table is completely full, a
+ *	clear code is transmitted for the expander and the table is reset.
+ *	This program uses a maximum code size of 12 bits for a total of 4096
+ *	codes.
+ *
+ *	The expander realizes that the code size is changing when it's table
+ *	size reaches the maximum for the current code size.  At this point,
+ *	the code size in increased.  Remember that the expander's table is
+ *	identical to the compressor's table at any point in the original data
+ *	stream.
+ *
+ *	The compressed data stream is structured as follows:
+ *		first byte denoting the minimum code size
+ *		one or more counted byte strings. The first byte contains the
+ *		length of the string. A null string denotes "end of data"
+ *
+ *	This format permits a compressed data stream to be embedded within a
+ *	non-compressed context.
+ *
+ * AUTHOR: Steve Wilhite
+ *
+ * REVISION HISTORY:
+ *   Speed tweaked a bit by Jim Kent 8/29/88
+ *
+ */
+
+#include "common.h"
+#include <setjmp.h>
+
+
+#define UBYTE unsigned char
+
+
+#define LARGEST_CODE	4095
+#define TABLE_SIZE	(8*1024)
+
+static UBYTE gif_byte_buff[256+3];               /* Current block */
+static FILE *gif_file;
+
+static unsigned char *gif_wpt;
+static long gif_wcount;
+
+static jmp_buf recover;
+
+static short *prior_codes;
+static short *code_ids;
+static unsigned char *added_chars;
+
+static short code_size;
+static short clear_code;
+static short eof_code;
+static short bit_offset;
+static short max_code;
+static short free_code;
+
+
+static void init_table(short min_code_size)
+{
+code_size = min_code_size + 1;
+clear_code = 1 << min_code_size;
+eof_code = clear_code + 1;
+free_code = clear_code + 2;
+max_code = 1 << code_size;
+
+zeroBytes(code_ids, TABLE_SIZE*sizeof(code_ids[0]));
+}
+
+
+static void flush(size_t n)
+{
+if (fputc(n,gif_file) < 0)
+    {
+    longjmp(recover, -3);
+    }
+if (fwrite(gif_byte_buff, 1, n, gif_file) < n)
+    {
+    longjmp(recover, -3);
+    }
+}
+
+
+static void write_code(short code)
+{
+long temp;
+register short byte_offset; 
+register short bits_left;
+
+byte_offset = bit_offset >> 3;
+bits_left = bit_offset & 7;
+
+if (byte_offset >= 254)
+	{
+	flush(byte_offset);
+	gif_byte_buff[0] = gif_byte_buff[byte_offset];
+	bit_offset = bits_left;
+	byte_offset = 0;
+	}
+
+if (bits_left > 0)
+	{
+	temp = ((long) code << bits_left) | gif_byte_buff[byte_offset];
+	gif_byte_buff[byte_offset] = (UBYTE)temp;
+	gif_byte_buff[byte_offset + 1] = (UBYTE)(temp >> 8);
+	gif_byte_buff[byte_offset + 2] = (UBYTE)(temp >> 16);
+	}
+else
+	{
+	gif_byte_buff[byte_offset] = (UBYTE)code;
+	gif_byte_buff[byte_offset + 1] = (UBYTE)(code >> 8);
+	}
+bit_offset += code_size;
+}
+
+
+/*
+ * Function:
+ *	Compress a stream of data bytes using the LZW algorithm.
+ *
+ * Inputs:
+ *	min_code_size
+ *		the field size of an input value.  Should be in the range from
+ *		1 to 9.
+ *
+ * Returns:
+ *	 0	normal completion
+ *	-1	(not used)
+ *	-2	insufficient dynamic memory
+ *	-3	bad "min_code_size"
+ *	< -3	error status from either the get_byte or put_byte routine
+ */
+static short compress_data(int min_code_size)
+{
+short status;
+short prefix_code;
+short d;
+register int hx;
+register short suffix_char;
+
+status = setjmp(recover);
+
+if (status != 0)
+    {
+    return status;
+    }
+
+bit_offset = 0;
+init_table(min_code_size);
+write_code(clear_code);
+suffix_char = *gif_wpt++;
+gif_wcount -= 1;
+
+prefix_code = suffix_char;
+
+while (--gif_wcount >= 0)
+    {
+    suffix_char = *gif_wpt++;
+    hx = prefix_code ^ suffix_char << 5;
+    d = 1;
+
+    for (;;)
+	{
+	if (code_ids[hx] == 0)
+	    {
+	    write_code(prefix_code);
+
+	    d = free_code;
+
+	    if (free_code <= LARGEST_CODE)
+		{
+		prior_codes[hx] = prefix_code;
+		added_chars[hx] = (UBYTE)suffix_char;
+		code_ids[hx] = free_code;
+		free_code++;
+		}
+
+	    if (d == max_code)
+		{
+		if (code_size < 12)
+		    {
+		    code_size++;
+		    max_code <<= 1;
+		    }
+		else
+		    {
+		    write_code(clear_code);
+		    init_table(min_code_size);
+		    }
+	        }
+
+	    prefix_code = suffix_char;
+	    break;
+	    }
+
+	if (prior_codes[hx] == prefix_code &&
+		added_chars[hx] == suffix_char)
+	    {
+	    prefix_code = code_ids[hx];
+	    break;
+	    }
+
+	hx += d;
+	d += 2;
+	if (hx >= TABLE_SIZE)
+	    hx -= TABLE_SIZE;
+	}
+    }
+
+write_code(prefix_code);
+
+write_code(eof_code);
+
+
+/* Make sure the code buffer is flushed */
+
+if (bit_offset > 0)
+    {
+    int byte_offset = (bit_offset >> 3);
+    if (byte_offset == 255)	/* Make sure we don't write a zero by mistake. */
+        {
+	int bits_left = bit_offset & 7;
+	flush(255);
+	if (bits_left)
+	    {
+	    gif_byte_buff[0] = gif_byte_buff[byte_offset];
+	    flush(1);
+	    }
+	}
+    else
+	{
+	flush((bit_offset + 7)/8);
+	}
+    }
+
+flush(0);				/* end-of-data */
+return 0;
+}
+
+short gif_compress_data(int min_code_size, unsigned char *pt, long size, FILE *out)
+{
+int ret;
+
+/* Make sure min_code_size is reasonable. */
+if (min_code_size < 2 || min_code_size > 9)
+    {
+    if (min_code_size == 1)
+	min_code_size = 2;
+    else
+	return -3;
+    }
+
+/* Store input parameters where rest of routines can use. */
+gif_file = out;
+gif_wpt = pt;
+gif_wcount = size;
+
+ret = -2;	/* out of memory default */
+prior_codes = NULL;
+code_ids = NULL;
+added_chars = NULL;
+if ((prior_codes = (short*)needMem(TABLE_SIZE*sizeof(short))) == NULL)
+	goto OUT;
+if ((code_ids = (short*)needMem(TABLE_SIZE*sizeof(short))) == NULL)
+	goto OUT;
+if ((added_chars = (unsigned char*)needMem(TABLE_SIZE)) == NULL)
+	goto OUT;
+
+ret = compress_data(min_code_size);
+
+OUT:
+gentleFree(prior_codes);
+gentleFree(code_ids);
+gentleFree(added_chars);
+return(ret);
+}
+
diff --git a/lib/gifdecomp.c b/lib/gifdecomp.c
new file mode 100644
index 0000000..06c50f7
--- /dev/null
+++ b/lib/gifdecomp.c
@@ -0,0 +1,391 @@
+/* decode.c - An LZW decoder for GIF
+ * Copyright (C) 1987, by Steven A. Bennett
+ *
+ * Permission is given by the author to freely redistribute and include
+ * this code in any program as long as this credit is given where due.
+ *
+ * In accordance with the above, I want to credit Steve Wilhite who wrote
+ * the code which this is heavily inspired by...
+ *
+ * GIF and 'Graphics Interchange Format' are trademarks (tm) of
+ * Compuserve, Incorporated, an H&R Block Company.
+ *
+ * Release Notes: This file contains a decoder routine for GIF images
+ * which is similar, structurally, to the original routine by Steve Wilhite.
+ * It is, however, somewhat noticably faster in most cases.
+ *
+ */
+
+#include "common.h"
+#include "gifcodes.h"
+
+
+
+/* extern int gif_get_byte()
+ *
+ *   - This external (machine specific) function is expected to return
+ * either the next byte from the GIF file, or a negative number, as
+ * defined in gifcodes.h.
+ */
+extern int gif_get_byte();
+
+/* extern int gif_out_line(pixels, linelen)
+ *     UBYTE pixels[];
+ *     int linelen;
+ *
+ *   - This function takes a full line of pixels (one byte per pixel) and
+ * displays them (or does whatever your program wants with them...).  It
+ * should return zero, or negative if an error or some other event occurs
+ * which would require aborting the decode process...  Note that the length
+ * passed will almost always be equal to the line length passed to the
+ * decoder function, with the sole exception occurring when an ending code
+ * occurs in an odd place in the GIF file...  In any case, linelen will be
+ * equal to the number of pixels passed...
+ */
+extern int gif_out_line();
+
+/* extern int bad_code_count;
+ *
+ * This value is the only other global required by the using program, and
+ * is incremented each time an out of range code is read by the decoder.
+ * When this value is non-zero after a decode, your GIF file is probably
+ * corrupt in some way...
+ */
+int bad_code_count;
+
+#define MAX_CODES   4095
+
+/* Static variables */
+static WORD curr_size;                     /* The current code size */
+static WORD clear;                         /* Value for a clear code */
+static WORD ending;                        /* Value for a ending code */
+static WORD newcodes;                      /* First available code */
+static WORD top_slot;                      /* Highest code for current size */
+static WORD slot;                          /* Last read code */
+
+/* The following static variables are used
+ * for seperating out codes
+ */
+static WORD navail_bytes = 0;              /* # bytes left in block */
+static WORD nbits_left = 0;                /* # bits left in current byte */
+static UBYTE b1;                           /* Current byte */
+static UBYTE gif_byte_buff[256+3];               /* Current block */
+static UBYTE *pbytes;                      /* Pointer to next byte in block */
+
+static long code_mask[13] = {
+     0,
+     0x0001, 0x0003,
+     0x0007, 0x000F,
+     0x001F, 0x003F,
+     0x007F, 0x00FF,
+     0x01FF, 0x03FF,
+     0x07FF, 0x0FFF
+     };
+
+
+/* This function initializes the decoder for reading a new image.
+ */
+static WORD init_exp(size)
+   WORD size;
+   {
+   curr_size = size + 1;
+   top_slot = 1 << curr_size;
+   clear = 1 << size;
+   ending = clear + 1;
+   slot = newcodes = ending + 1;
+   navail_bytes = nbits_left = 0;
+   return(0);
+   }
+
+/* get_next_code()
+ * - gets the next code from the GIF file.  Returns the code, or else
+ * a negative number in case of file errors...
+ */
+static WORD get_next_code()
+   {
+   WORD i, x;
+   unsigned long ret;
+
+   if (nbits_left == 0)
+      {
+      if (navail_bytes <= 0)
+         {
+
+         /* Out of bytes in current block, so read next block
+          */
+         pbytes = gif_byte_buff;
+         if ((navail_bytes = gif_get_byte()) < 0)
+            return(navail_bytes);
+         else if (navail_bytes)
+            {
+            for (i = 0; i < navail_bytes; ++i)
+               {
+               if ((x = gif_get_byte()) < 0)
+                  return(x);
+               gif_byte_buff[i] = x;
+               }
+            }
+         }
+      b1 = *pbytes++;
+      nbits_left = 8;
+      --navail_bytes;
+      }
+
+   ret = b1 >> (8 - nbits_left);
+   while (curr_size > nbits_left)
+      {
+      if (navail_bytes <= 0)
+         {
+
+         /* Out of bytes in current block, so read next block
+          */
+         pbytes = gif_byte_buff;
+         if ((navail_bytes = gif_get_byte()) < 0)
+            return(navail_bytes);
+         else if (navail_bytes)
+            {
+            for (i = 0; i < navail_bytes; ++i)
+               {
+               if ((x = gif_get_byte()) < 0)
+                  return(x);
+               gif_byte_buff[i] = x;
+               }
+            }
+         }
+      b1 = *pbytes++;
+      ret |= b1 << nbits_left;
+      nbits_left += 8;
+      --navail_bytes;
+      }
+   nbits_left -= curr_size;
+   ret &= code_mask[curr_size];
+   return((WORD)(ret));
+   }
+
+
+
+/* WORD decoder(linewidth)
+ *    WORD linewidth;               * Pixels per line of image *
+ *
+ * - This function decodes an LZW image, according to the method used
+ * in the GIF spec.  Every *linewidth* 'characters' (ie. pixels) decoded
+ * will generate a call to gif_out_line(), which is a user specific function
+ * to display a line of pixels.  The function gets it's codes from
+ * get_next_code() which is responsible for reading blocks of data and
+ * seperating them into the proper size codes.  Finally, gif_get_byte() is
+ * the global routine to read the next byte from the GIF file.
+ *
+ * It is generally a good idea to have linewidth correspond to the actual
+ * width of a line (as specified in the Image header) to make your own
+ * code a bit simpler, but it isn't absolutely necessary.
+ *
+ * Returns: 0 if successful, else negative.  (See ERRS.H)
+ *
+ */
+
+static WORD decoder(linewidth,buf,stack,suffix,prefix)
+   WORD linewidth;
+   UBYTE *buf;		/* food for gif_line_out, where the pixels go */
+   UBYTE *stack;	/* Stack for storing pixels backwards */
+   UBYTE *suffix;	/* Suffix table */
+   UWORD *prefix;	/* Prefix linked list */
+   {
+   register UBYTE *sp, *bufptr;
+   register WORD code, fc, oc, bufcnt;
+   WORD c, size, ret;
+
+   /* Initialize for decoding a new image...
+    */
+   if ((size = gif_get_byte()) < 0)
+      return(size);
+   if (size < 2 || 9 < size)
+      return(BAD_CODE_SIZE);
+   init_exp(size);
+
+   /* Initialize in case they forgot to put in a clear code.
+    * (This shouldn't happen, but we'll try and decode it anyway...)
+    */
+   oc = fc = 0;
+
+
+   /* Set up the stack pointer and decode buffer pointer
+    */
+   sp = stack;
+   bufptr = buf;
+   bufcnt = linewidth;
+
+   /* This is the main loop.  For each code we get we pass through the
+    * linked list of prefix codes, pushing the corresponding 'character' for
+    * each code onto the stack.  When the list reaches a single 'character'
+    * we push that on the stack too, and then start unstacking each
+    * character for output in the correct order.  Special handling is
+    * included for the clear code, and the whole thing ends when we get
+    * an ending code.
+    */
+   while ((c = get_next_code()) != ending)
+      {
+
+      /* If we had a file error, return without completing the decode
+       */
+      if (c < 0)
+         {
+         return(c);
+         }
+
+      /* If the code is a clear code, reinitialize all necessary items.
+       */
+      if (c == clear)
+         {
+         curr_size = size + 1;
+         slot = newcodes;
+         top_slot = 1 << curr_size;
+
+         /* Continue reading codes until we get a non-clear code
+          * (Another unlikely, but possible case...)
+          */
+         while ((c = get_next_code()) == clear)
+            ;
+
+         /* If we get an ending code immediately after a clear code
+          * (Yet another unlikely case), then break out of the loop.
+          */
+         if (c == ending)
+            break;
+
+         /* Finally, if the code is beyond the range of already set codes,
+          * (This one had better NOT happen...  I have no idea what will
+          * result from this, but I doubt it will look good...) then set it
+          * to color zero.
+          */
+         if (c >= slot)
+            c = 0;
+
+         oc = fc = c;
+
+         /* And let us not forget to put the char into the buffer... And
+          * if, on the off chance, we were exactly one pixel from the end
+          * of the line, we have to send the buffer to the gif_out_line()
+          * routine...
+          */
+         *bufptr++ = c;
+         if (--bufcnt == 0)
+            {
+            if ((ret = gif_out_line(buf, linewidth)) < 0)
+               {
+               return(ret);
+               }
+            bufptr = buf;
+            bufcnt = linewidth;
+            }
+         }
+      else
+         {
+
+         /* In this case, it's not a clear code or an ending code, so
+          * it must be a code code...  So we can now decode the code into
+          * a stack of character codes. (Clear as mud, right?)
+          */
+         code = c;
+
+         /* Here we go again with one of those off chances...  If, on the
+          * off chance, the code we got is beyond the range of those already
+          * set up (Another thing which had better NOT happen...) we trick
+          * the decoder into thinking it actually got the last code read.
+          * (Hmmn... I'm not sure why this works...  But it does...)
+          */
+         if (code >= slot)
+            {
+            if (code > slot)
+               ++bad_code_count;
+            code = oc;
+            *sp++ = fc;
+            }
+
+         /* Here we scan back along the linked list of prefixes, pushing
+          * helpless characters (ie. suffixes) onto the stack as we do so.
+          */
+         while (code >= newcodes)
+            {
+            *sp++ = suffix[code];
+            code = prefix[code];
+            }
+
+         /* Push the last character on the stack, and set up the new
+          * prefix and suffix, and if the required slot number is greater
+          * than that allowed by the current bit size, increase the bit
+          * size.  (NOTE - If we are all full, we *don't* save the new
+          * suffix and prefix...  I'm not certain if this is correct...
+          * it might be more proper to overwrite the last code...
+          */
+         *sp++ = code;
+         if (slot < top_slot)
+            {
+            suffix[slot] = fc = code;
+            prefix[slot++] = oc;
+            oc = c;
+            }
+         if (slot >= top_slot)
+            if (curr_size < 12)
+               {
+               top_slot <<= 1;
+               ++curr_size;
+               } 
+
+         /* Now that we've pushed the decoded string (in reverse order)
+          * onto the stack, lets pop it off and put it into our decode
+          * buffer...  And when the decode buffer is full, write another
+          * line...
+          */
+         while (sp > stack)
+            {
+            *bufptr++ = *(--sp);
+            if (--bufcnt == 0)
+               {
+               if ((ret = gif_out_line(buf, linewidth)) < 0)
+                  {
+                  return(ret);
+                  }
+               bufptr = buf;
+               bufcnt = linewidth;
+               }
+            }
+         }
+      }
+   ret = 0;
+   if (bufcnt != linewidth)
+      ret = gif_out_line(buf, (linewidth - bufcnt));
+   return(ret);
+   }
+
+/* basically just allocate memory for buffers and tables, and then
+   call Steve B.'s decoder */
+int gif_decoder(int linewidth)
+{
+UBYTE *buf, *stack, *suffix;
+UWORD *prefix;
+int ret;
+
+ret = OUT_OF_MEMORY;
+stack = NULL;
+suffix = NULL;
+prefix = NULL;
+/* stack = suffix = (UBYTE *)prefix = NULL; */
+if ((buf = (UBYTE *)needMem(linewidth + 1)) == NULL)
+	goto OUT;
+if ((stack = (UBYTE *)needMem(MAX_CODES+1)) == NULL)
+	goto OUT;
+if ((suffix = (UBYTE *)needMem(MAX_CODES+1)) == NULL)
+	goto OUT;
+if ((prefix = (UWORD *)needMem((MAX_CODES+1)*sizeof(UWORD) )) == NULL)
+	goto OUT;
+ret = decoder(linewidth,buf,stack,suffix,prefix);
+OUT:
+freeMem(buf);
+freeMem(stack);
+freeMem(prefix);
+freeMem(suffix);
+return(ret);
+}
+
+
+
diff --git a/lib/gifread.c b/lib/gifread.c
new file mode 100644
index 0000000..bfa0803
--- /dev/null
+++ b/lib/gifread.c
@@ -0,0 +1,186 @@
+/* gifread.c - The high level GIF reading routines.  See writegif for the
+   write side.  Also gifdecode.c for lower level GIF reading code. */
+
+#include "common.h"
+#include "gifcodes.h"
+#include "memgfx.h"
+
+
+static struct gif_header gif;
+static struct gif_image gim;
+static int gif_line;
+static char iphase;
+static WORD iy;
+static UBYTE gif_cmap[256*3];
+static FILE *gif_file;
+static struct memGfx *gif_mg;
+static int gif_width, gif_height;
+
+int gif_get_byte()
+/* Get next byte from file for decoder.
+ * return -1 at end of file. */
+{
+return(fgetc(gif_file));
+}
+
+
+int gif_out_line(UBYTE *pixels, int linelen)
+/* Output a line of gif. */
+{
+int y;
+
+y = gif_line;
+if (gim.flags&ITLV_BIT)
+    {
+    y = iy;
+    switch (iphase)
+        {
+        case 0:
+        case 1:
+            iy+=8;
+            break;
+        case 2:
+            iy += 4;
+            break;
+        case 3:
+            iy += 2;
+            break;
+        }
+    if (iy >= gif_height)
+        {
+        switch (iphase)
+            {
+            case 0:
+                iy = 4;
+                break;
+            case 1:
+                iy = 2;
+                break;
+            case 2:
+                iy = 1;
+                break;
+            }
+        iphase++;
+        }
+    }
+gif_line++;
+memcpy(gif_mg->pixels + y*gif_mg->width, pixels, linelen);
+return(0);
+}
+
+
+
+struct memGfx *mgLoadGif(char *name)
+/* Create memory image based on gif file. 
+ * Note this is based on a very old gif reader
+ * that only handles the GIF87a version. 
+ * This is the same that mgSaveGif creates at
+ * least.  This version of gif was always
+ * color mapped. */
+{
+int c;
+char type[7];
+int gif_colors = 0;
+
+gif_line = 0;
+iphase = 0;
+iy = 0;
+gif_mg = NULL;
+gif_file = mustOpen(name, "rb");
+if (fread(&gif, 1, sizeof(gif), gif_file) < sizeof(gif))
+    {
+    goto TRUNCOUT;
+    }
+memcpy(type, gif.giftype, 6);
+type[6] = 0;
+if (!startsWith("GIF", type))
+    {
+    errAbort("Not a good GIF file");
+    goto BADOUT;
+    }
+if (!sameString("GIF87a", type))
+    {
+    errAbort("Gif is version %s, sadly load_gif only speaks version GIF87a", type);
+    goto BADOUT;
+    }
+gif_colors = (1<<((gif.colpix&PIXMASK)+1));
+if (gif.colpix&COLTAB)
+    {
+    int size = gif_colors*3;
+    if (fread(gif_cmap, 1, size, gif_file) < size)
+        goto TRUNCOUT;
+    }
+for (;;)    /* skip over extension blocks and other junk til get ',' */
+    {
+    if ((c = fgetc(gif_file)) == READ_ERROR)
+        goto TRUNCOUT;
+    if (c == ',')
+        break;
+    if (c == ';')    /* semi-colon is end of piccie */
+        goto TRUNCOUT;
+    if (c == '!')    /* extension block */
+        {
+        if ((c = fgetc(gif_file)) == READ_ERROR)    /* skip extension type */
+            goto TRUNCOUT;
+        for (;;)
+            {
+            if ((c = fgetc(gif_file)) == READ_ERROR)
+                goto TRUNCOUT;
+            if (c == 0)    /* zero 'count' means end of extension */
+                break;
+            while (--c >= 0)
+                {
+                if (fgetc(gif_file) == READ_ERROR)
+                    goto TRUNCOUT;
+                }
+            }
+        }
+    }
+if (fread(&gim, 1, sizeof(gim), gif_file) < sizeof(gim))
+    goto TRUNCOUT;
+gif_width = (gim.whi<<8) + gim.wlo;
+gif_height = (gim.hhi<<8) + gim.hlo;
+
+gif_mg = mgNew(gif_width, gif_height);
+
+/* Gif files can have color maps in two places.  Let
+ * the gim color map overwrite the one in the gif header
+ * here. */
+if (gim.flags&COLTAB)
+    {
+    int size;
+    gif_colors = (1<<((gim.flags&PIXMASK)+1));
+    size = gif_colors*3;
+    if (fread(gif_cmap, 1, size, gif_file) < size)
+        goto TRUNCOUT;
+    }
+if (gif_colors > 0)
+    {
+    if (gif_colors > 256)
+       errAbort("Too many colors in %s", name);
+    memcpy(gif_mg->colorMap, gif_cmap, 3*gif_colors);
+    }
+
+switch (gif_decoder(gif_width))
+    {
+    case READ_ERROR:
+    case BAD_CODE_SIZE:
+        goto TRUNCOUT;
+    case OUT_OF_MEMORY:
+	errAbort("out of memory");
+        goto BADOUT;
+    default:
+        break;
+    }
+carefulClose(&gif_file);
+return(gif_mg);
+
+TRUNCOUT:
+errAbort("%s is truncated", name);
+BADOUT:
+carefulClose(&gif_file);
+mgFree(&gif_mg);
+return(NULL);
+}
+
+
diff --git a/lib/gifwrite.c b/lib/gifwrite.c
new file mode 100644
index 0000000..76149a1
--- /dev/null
+++ b/lib/gifwrite.c
@@ -0,0 +1,98 @@
+/* writegif.c - stuff to write out a GIF file.  See also comprs.c */
+
+#ifndef USE_PNG
+#include "common.h"
+#include "memgfx.h"
+#include "gifcodes.h"
+
+
+static char gifsig[] = "GIF87a";
+
+// GIF Graphic Control Extension, for making the background color transparent:
+static struct gif_gce
+    {
+    unsigned char extensionIntroducer, graphicControlLabel, blockSize;
+    unsigned char flags;
+    unsigned char delayTimeLo,delayTimeHi;
+    unsigned char transparentColorIndex;
+    unsigned char blockTerminator;
+    } gce = {0x21, 0xF9, 0x04, // fixed bytes from spec
+	     0x01,             // transparency on (no user input or disposal options)
+	     0x00, 0x00,       // no animation delay time
+	     0x00,             // color index 0 (white) is transparent
+	     0x00};
+
+boolean mgSaveToGif(FILE *gif_file, struct memGfx *screen, boolean useTransparency)
+/* Save GIF to an already open file.
+ * If useTransparency, then the first color in memgfx's colormap/palette is
+ * assumed to be the image background color, and pixels of that color
+ * are made transparent. */
+{
+int i;
+struct gif_header gif;
+struct gif_image gim;
+long gif_wcount;
+
+gif_wcount = (long)screen->width * screen->height;
+zeroBytes(&gif, sizeof(gif));
+strncpy(gif.giftype, gifsig, sizeof(gif.giftype));
+gif.wlo = gim.wlo = ((screen->width)&0xff);
+gif.whi = gim.whi = ((screen->width>>8)&0xff);
+gif.hlo = gim.hlo = ((screen->height)&0xff);
+gif.hhi = gim.hhi = ((screen->height>>8)&0xff);
+gim.xlo = gim.xhi = gim.ylo = gim.yhi = gim.flags = 0;
+gif.colpix = COLPIXVGA13;
+if (fwrite(&gif, sizeof(gif), 1, gif_file ) < 1)
+    goto TRUNCOUT;
+/* write global color map */
+if (fwrite(screen->colorMap, 3, 256, gif_file) < 256)
+    goto TRUNCOUT;
+
+if (useTransparency)
+    if (fwrite(&gce, sizeof(gce), 1, gif_file ) < 1)
+	goto TRUNCOUT;
+
+if (fputc(',', gif_file) < 0) /* comma to start image */
+    goto TRUNCOUT;
+if (fwrite(&gim, sizeof(gim), 1, gif_file) < 1)
+    goto TRUNCOUT;
+fputc(8,gif_file);
+fflush(gif_file);
+i = gif_compress_data(8, (unsigned char*)screen->pixels, gif_wcount, gif_file);
+switch (i)
+    {
+    case 0:
+        break;
+    case -2:
+	warn("Out of memory writing GIF");
+	goto BADOUT;
+    case -3:
+	goto TRUNCOUT;
+    default:
+	warn("Error code %d writing gif", i);
+	goto BADOUT;
+    }
+fputc(';', gif_file); /* end of file for gif */
+return(TRUE);
+TRUNCOUT:
+warn("Disk full writing GIF");
+BADOUT:
+return(FALSE);
+}
+
+void mgSaveGif(struct memGfx *screen, char *name, boolean useTransparency)
+/* Save memory bitmap as a gif.
+ * If useTransparency, then the first color in memgfx's colormap/palette is
+ * assumed to be the image background color, and pixels of that color
+ * are made transparent. */
+{
+FILE *gifFile = mustOpen(name, "wb");
+if (!mgSaveToGif(gifFile, screen, useTransparency))
+    {
+    remove(name);
+    errAbort("Couldn't save %s", name);
+    }
+if (fclose(gifFile) != 0)
+    errnoAbort("fclose failed");
+}
+#endif
diff --git a/lib/hacTree.c b/lib/hacTree.c
new file mode 100644
index 0000000..c017520
--- /dev/null
+++ b/lib/hacTree.c
@@ -0,0 +1,276 @@
+/* hacTree - Hierarchical Agglomerative Clustering a list of inputs into a binary tree */
+
+#include "common.h"
+#include "hacTree.h"
+
+static struct hacTree *leafNodesFromItems(const struct slList *itemList, int itemCount,
+					  struct lm *localMem)
+/* Allocate & initialize leaf nodes that contain only items. */
+{
+struct hacTree *leafNodes = lmAlloc(localMem, itemCount * sizeof(struct hacTree));
+int i = 0;
+const struct slList *item = itemList;
+while (item != NULL && i < itemCount)
+    {
+    // needMem zeroes the memory, so initialize only non-NULL stuff.
+    struct hacTree *node = &(leafNodes[i]);
+    if (i < itemCount-1)
+	node->next = &(leafNodes[i+1]);
+    node->itemOrCluster = (struct slList *)item;
+    i++;
+    item = item->next;
+    }
+return leafNodes;
+}
+
+struct sortWrapper
+/* We need to compare nodes' itemOrClusters using cmpF and extraData;
+ * qsort's comparison function doesn't have a way to pass in extraData,
+ * so we need to point to it from each qsort element. */
+{
+    struct hacTree *node;  // contains itemOrCluster to be compared
+    hacCmpFunction *cmpF;  // user-provided itemOrCluster comparison function
+    void *extraData;       // user-provided aux data for cmpF
+};
+
+static int sortWrapCmp(const void *v1, const void *v2)
+/* Unpack sortWrappers and run cmpF on nodes' itemOrClusters with extraData. */
+{
+const struct sortWrapper *w1 = v1, *w2 = v2;
+return w1->cmpF(w1->node->itemOrCluster, w2->node->itemOrCluster, w1->extraData);
+}
+
+static struct sortWrapper *makeSortedWraps(struct hacTree *leafNodes, int itemCount,
+					   struct lm *localMem, hacCmpFunction cmpF,
+					   void *extraData)
+/* Use cmpF and extraData to sort wrapped leaves so that identical leaves will be adjacent. */
+{
+struct sortWrapper *leafWraps = lmAlloc(localMem, itemCount * sizeof(struct sortWrapper));
+int i;
+for (i=0;  i < itemCount;  i++)
+    {
+    leafWraps[i].node = &(leafNodes[i]);
+    leafWraps[i].cmpF = cmpF;
+    leafWraps[i].extraData = extraData;
+    }
+qsort(leafWraps, itemCount, sizeof(struct sortWrapper), sortWrapCmp);
+return leafWraps;
+}
+
+INLINE void initNode(struct hacTree *node, const struct hacTree *left, const struct hacTree *right,
+		     hacDistanceFunction *distF, hacMergeFunction *mergeF, void *extraData)
+/* Initialize node to have left and right as its children.  Leave parent pointers
+ * alone -- they would be unstable during tree construction. */
+{
+node->left = (struct hacTree *)left;
+node->right = (struct hacTree *)right;
+if (left != NULL && right != NULL)
+    {
+    node->childDistance = distF(left->itemOrCluster, right->itemOrCluster, extraData);
+    node->itemOrCluster = mergeF(left->itemOrCluster, right->itemOrCluster, extraData);
+    }
+}
+
+INLINE struct hacTree preClusterNodes(const struct sortWrapper *leafWraps, int i, int runLength,
+				      hacDistanceFunction *distF, hacMergeFunction *mergeF,
+				      void *extraData, struct lm *localMem)
+/* Caller has allocated a node, and this returns what to store there:
+ * a recursively constructed cluster of nodes extracted from wrapped
+ * leafNodes (leafWraps) starting at i, for runLength items. */
+{
+struct hacTree ret = {NULL, NULL, NULL, NULL, 0, NULL};
+if (runLength > 2)
+    {
+    struct hacTree *newClusters = lmAlloc(localMem, 2 * sizeof(struct hacTree));
+    int halfLength = runLength/2;
+    newClusters[0] = preClusterNodes(leafWraps, i, halfLength,
+				     distF, mergeF, extraData, localMem);
+    newClusters[1] = preClusterNodes(leafWraps, i+halfLength, runLength-halfLength,
+				     distF, mergeF, extraData, localMem);
+    initNode(&ret, &(newClusters[0]), &(newClusters[1]), distF, mergeF, extraData);
+    }
+else if (runLength == 2)
+    {
+    initNode(&ret, leafWraps[i].node, leafWraps[i+1].node, distF, mergeF, extraData);
+    }
+else
+    ret = *(leafWraps[i].node);
+return ret;
+}
+
+static struct hacTree *sortAndPreCluster(struct hacTree *leafNodes, int *retItemCount,
+					 struct lm *localMem, hacDistanceFunction *distF,
+					 hacMergeFunction *mergeF, hacCmpFunction *cmpF,
+					 void *extraData)
+/* Use cmpF and extraData to sort wrapped leaf nodes so that identical leaves will be adjacent,
+ * then replace leaves with clusters of identical leaves where possible.  Place new
+ * (hopefully smaller) item count in retItemCount. */
+{
+int itemCount = *retItemCount;
+struct sortWrapper *leafWraps = makeSortedWraps(leafNodes, itemCount, localMem, cmpF, extraData);
+struct hacTree *newLeaves = lmAlloc(localMem, itemCount * sizeof(struct hacTree));
+int i=0, newI=0;
+while (i < itemCount)
+    {
+    int nextRunStart;
+    for (nextRunStart = i+1;  nextRunStart < itemCount; nextRunStart++)
+	if (distF(leafWraps[i].node->itemOrCluster, leafWraps[nextRunStart].node->itemOrCluster,
+		  extraData) != 0)
+	    break;
+    int runLength = nextRunStart - i;
+    newLeaves[newI] = preClusterNodes(leafWraps, i, runLength, distF, mergeF, extraData, localMem);
+    i = nextRunStart;
+    newI++;
+    }
+*retItemCount = newI;
+return newLeaves;
+}
+
+static struct hacTree *pairUpItems(const struct slList *itemList, int itemCount,
+				   int *retPairCount, struct lm *localMem,
+				   hacDistanceFunction *distF, hacMergeFunction *mergeF,
+				   hacCmpFunction *cmpF, void *extraData)
+/* Allocate & initialize leaf nodes and all possible pairings of leaf nodes
+ * which will be our seed clusters.  If cmpF is given, pre-sort the leaf nodes
+ * and pre-cluster identical leaves before generating seed clusters. */
+{
+struct hacTree *leafNodes = leafNodesFromItems(itemList, itemCount, localMem);
+if (cmpF != NULL)
+    leafNodes = sortAndPreCluster(leafNodes, &itemCount, localMem,
+				  distF, mergeF, cmpF, extraData);
+int pairCount = (itemCount == 1) ? 1 : (itemCount * (itemCount-1) / 2);
+struct hacTree *pairPool = lmAlloc(localMem, pairCount * sizeof(struct hacTree));
+if (itemCount == 1)
+    initNode(pairPool, leafNodes, NULL, distF, mergeF, extraData);
+else
+    {
+    int i, j, pairIx;
+    for (i=0, pairIx=0;  i < itemCount-1;  i++)
+	for (j=i+1;  j < itemCount;  j++, pairIx++)
+	    initNode(&(pairPool[pairIx]), &(leafNodes[i]), &(leafNodes[j]), distF, mergeF,
+		     extraData);
+    }
+*retPairCount = pairCount;
+return pairPool;
+}
+
+struct hacTree *hacTreeFromItems(const struct slList *itemList, struct lm *localMem,
+				 hacDistanceFunction *distF, hacMergeFunction *mergeF,
+				 hacCmpFunction *cmpF, void *extraData)
+/* Using distF, mergeF, optionally cmpF and binary tree operations,
+ * perform a hierarchical agglomerative (bottom-up) clustering of
+ * items.  To free the resulting tree, lmCleanup(&localMem). */
+//
+// Implementation:
+//
+// Create a pool containing all pairs of items (N*(N-1)/2), and build
+// a hierarchical binary tree of items from the bottom up.  In each
+// iteration, first we find the closest pair and swap it into the head
+// of the pool; then we advance the head pointer, so the closest pair
+// now has a stable location in memory.  Next, for all pairs still in
+// the pool, we replace references to the elements of the closest pair
+// with the closest pair itself, but delete half of such pairs because
+// they would be duplicates.  Specifically, we keep pairs that had the
+// left element of the closest pair, and delete pairs that had the
+// right element of the closest pair.  We rescore the pairs that have
+// the closest pair swapped in for an element.  The code to do all
+// this is surprisingly simple -- in the second for loop below.  Note
+// that with each iteration, the pool will reduce in size, by N-2 the
+// first iteration, N-3 the second, and so forth.
+//
+// An example may help: say we start with items A, B, C and D.  Initially
+// the pool contains all pairs:
+//    (A, B)   (A, C)   (A, D)   (B, C)   (B, D)   (C, D)
+//
+// If (A, B) is the closest pair, we pop it from the pool and the pool
+// becomes
+//    (A, C)   (A, D)   (B, C)   (B, D)   (C, D)
+//
+// Now we substitute (A, B) for pool pairs containing A, and delete pool
+// pairs contining B because they would be duplicates of those containing
+// A.  [X] shows where a pair was deleted:
+//
+//    ((A, B), C)  ((A, B), D)  [X]   [X]  (C, D)
+//
+// Now say ((A, B), D) is the closest remaining pair, and is popped from
+// the head of the pool.  We substitute into pairs containing (A, B) and
+// delete pairs containing D.  After the replacement step, the pool is
+// down to a single element:
+//
+//    (((A, B), D), C)   [X]
+{
+if (itemList == NULL)
+    return NULL;
+struct hacTree *root = NULL;
+int itemCount = slCount(itemList);
+int pairCount = 0;
+struct hacTree *leafPairs = pairUpItems(itemList, itemCount, &pairCount, localMem,
+					distF, mergeF, cmpF, extraData);
+int *nodesToDelete = needMem(pairCount * sizeof(int));
+struct hacTree *poolHead = leafPairs;
+int poolLength = pairCount;
+while (poolLength > 0)
+    {
+    // Scan pool for node with lowest childDistance; swap that node w/head
+    int bestIx = 0;
+    double minScore = poolHead[0].childDistance;
+    int i;
+    for (i=1;  i < poolLength;  i++)
+	if (poolHead[i].childDistance < minScore)
+	    {
+	    minScore = poolHead[i].childDistance;
+	    bestIx = i;
+	    }
+    if (bestIx != 0)
+	swapBytes((char *)&(poolHead[0]), (char *)&(poolHead[bestIx]), sizeof(struct hacTree));
+    // Pop the best (lowest-distance) node from poolHead, make it root (for now).
+    root = poolHead;
+    poolHead = &(poolHead[1]);
+    poolLength--;
+    // Where root->left is found in the pool, replace it with root.
+    // Where root->right is found, drop that node so it doesn't become
+    // a duplicate of the replacement cases.
+    int numNodesToDelete = 0;
+    for (i=0;  i < poolLength;  i++)
+	{
+	struct hacTree *node = &(poolHead[i]);
+	if (node->left == root->left)
+	    // found root->left; replace node->left with root (merge root with node->right):
+	    initNode(node, root, node->right, distF, mergeF, extraData);
+	else if (node->right == root->left)
+	    // found root->left; replace node->right with root (merge root with node->left):
+	    initNode(node, node->left, root, distF, mergeF, extraData);
+	else if (node->left == root->right || node->right == root->right)
+	    // found root->right; mark this node for deletion:
+	    nodesToDelete[numNodesToDelete++] = i;
+	}
+    if (numNodesToDelete > 0)
+	{
+	int newPoolLen = nodesToDelete[0];
+	// This will be "next node to delete" for the last marked node:
+	nodesToDelete[numNodesToDelete] = poolLength;
+	for (i = 0;  i < numNodesToDelete;  i++)
+	    {
+	    int nodeToDel = nodesToDelete[i];
+	    int nextNodeToDel = nodesToDelete[i+1];
+	    int blkSize = nextNodeToDel - (nodeToDel+1);
+	    if (blkSize == 0)
+		continue;
+	    struct hacTree *fromNode = &(poolHead[nodeToDel+1]);
+	    struct hacTree *toNode = &(poolHead[newPoolLen]);
+	    memmove(toNode, fromNode, blkSize * sizeof(struct hacTree));
+	    newPoolLen += blkSize;
+	    }
+	poolLength = newPoolLen;
+	}
+    // root now has a stable address, unlike nodes still in the pool, so set parents here:
+    if (root->left != NULL)
+	root->left->parent = root;
+    if (root->right != NULL)
+	root->right->parent = root;
+    }
+// This shouldn't be necessary as long as initNode leaves parent pointers alone,
+// but just in case that changes:
+root->parent = NULL;
+return root;
+}
diff --git a/lib/hash.c b/lib/hash.c
new file mode 100644
index 0000000..320b360
--- /dev/null
+++ b/lib/hash.c
@@ -0,0 +1,717 @@
+/* Hash.c - implements hashing.  See hash.h for usage comments.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "localmem.h"
+#include "hash.h"
+#include "obscure.h"
+#include "dystring.h"
+
+
+/*
+ * Hash a string key.  This code is taken from Tcl interpreter. I was borrowed
+ * after discovering a lot of collisions and poor utilization of the table
+ * when hashing accessions.
+ *
+ * This function was compared to Bob Jenkins' lookup2 hash function and
+ * (http://burtleburtle.net/bob/hash/) and Paul Hsieh's SuperFast
+ * hash function (http://www.azillionmonkeys.com/qed/hash.html).
+ * Both of those functions provided better utilization of the table,
+ * but were also more expensive, so the Tcl function was used.
+ * If hashing of binary keys is implemented, SuperFast hash should
+ * be considered.
+ *
+ * for an explanation of this function, see HashStringKey() in the
+ * Tcl source file, generic/tclHash.c, available from
+ * http://tcl.sourceforge.net/.
+ *
+ * The Tcl code is:
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" (in the Tcl distribution) for complete
+ * license (which is a BSD-style license).
+ *
+ * Since hashCrc() is in use elsewhere, 
+ * a new function hashString() was created for use in hash table.
+ * -- markd
+ */
+bits32 hashString(char *string)
+/* Compute a hash value of a string. */
+{
+char *keyStr = string;
+unsigned int result = 0;
+int c;
+
+while ((c = *keyStr++) != '\0')
+    {
+    result += (result<<3) + c;
+    }
+return result;
+}
+
+bits32 hashCrc(char *string)
+/* Returns a CRC value on string. */
+{
+unsigned char *us = (unsigned char *)string;
+unsigned char c;
+bits32 shiftAcc = 0;
+bits32 addAcc = 0;
+
+while ((c = *us++) != 0)
+    {
+    shiftAcc <<= 2;
+    shiftAcc += c;
+    addAcc += c;
+    }
+return shiftAcc + addAcc;
+}
+
+struct hashEl *hashLookup(struct hash *hash, char *name)
+/* Looks for name in hash table. Returns associated element,
+ * if found, or NULL if not.  If there are multiple entries
+ * for name, the last one added is returned (LIFO behavior).
+ */
+{
+struct hashEl *el = hash->table[hashString(name)&hash->mask];
+while (el != NULL)
+    {
+    if (strcmp(el->name, name) == 0)
+        break;
+    el = el->next;
+    }
+return el;
+}
+
+struct hashEl *hashLookupUpperCase(struct hash *hash, char *name)
+/* Lookup upper cased name in hash. (Assumes all elements of hash
+ * are themselves already in upper case.) */
+{
+char s[256];
+safef(s, sizeof(s), "%s", name);
+touppers(s);
+return hashLookup(hash, s);
+}
+
+
+struct hashEl *hashLookupNext(struct hashEl *hashEl)
+/* Find the next occurance of name that may occur in the table multiple times,
+ * or NULL if not found.  Use hashLookup to find the first occurrence.  Elements
+ * are returned in LIFO order.
+ */
+{
+struct hashEl *el = hashEl->next;
+while (el != NULL)
+    {
+    if (strcmp(el->name, hashEl->name) == 0)
+        break;
+    el = el->next;
+    }
+return el;
+}
+
+struct hashEl *hashAddN(struct hash *hash, char *name, int nameSize, void *val)
+/* Add name of given size to hash (no need to be zero terminated) */
+{
+struct hashEl *el;
+if (hash->lm) 
+    el = lmAlloc(hash->lm, sizeof(*el));
+else
+    AllocVar(el);
+el->hashVal = hashString(name);
+int hashVal = el->hashVal & hash->mask;
+if (hash->lm)
+    {
+    el->name = lmAlloc(hash->lm, nameSize+1);
+    memcpy(el->name, name, nameSize);
+    }
+else
+    el->name = cloneStringZ(name, nameSize);
+el->val = val;
+el->next = hash->table[hashVal];
+hash->table[hashVal] = el;
+hash->elCount += 1;
+if (hash->autoExpand && hash->elCount > (int)(hash->size * hash->expansionFactor))
+    {
+    /* double the size */
+    hashResize(hash, digitsBaseTwo(hash->size));
+    }
+return el;
+}
+
+struct hashEl *hashAdd(struct hash *hash, char *name, void *val)
+/* Add new element to hash table.  If an item with name, already exists, a new
+ * item is added in a LIFO manner.  The last item added for a given name is
+ * the one returned by the hashLookup functions.  hashLookupNext must be used
+ * to find the preceding entries for a name.
+ */
+{
+return hashAddN(hash, name, strlen(name), val);
+}
+
+boolean hashMayRemove(struct hash *hash, char *name)
+/* Remove item of the given name from hash table, if present.
+ * Return true if it was present */
+{
+return (hashRemove(hash, name) != NULL);
+}
+
+void hashMustRemove(struct hash *hash, char *name)
+/* Remove item of the given name from hash table, or error
+ * if not present */
+{
+if (hashRemove(hash, name) == NULL)
+    errAbort("attempt to remove non-existant %s from hash", name);
+}
+
+void freeHashEl(struct hashEl *hel)
+/* Free hash element. Use only on non-local memory version. */
+{
+freeMem(hel->name);
+freeMem(hel);
+}
+
+void *hashRemove(struct hash *hash, char *name)
+/* Remove item of the given name from hash table. 
+ * Returns value of removed item, or NULL if not in the table.
+ * If their are multiple entries for name, the last one added
+ * is removed (LIFO behavior).
+ */
+{
+struct hashEl *hel;
+void *ret;
+struct hashEl **pBucket = &hash->table[hashString(name)&hash->mask];
+for (hel = *pBucket; hel != NULL; hel = hel->next)
+    if (sameString(hel->name, name))
+        break;
+if (hel == NULL)
+    return NULL;
+ret = hel->val;
+if (slRemoveEl(pBucket, hel))
+    {
+    hash->elCount -= 1;
+    if (!hash->lm)
+	freeHashEl(hel);
+    }
+return ret;
+}
+
+struct hashEl *hashAddUnique(struct hash *hash, char *name, void *val)
+/* Add new element to hash table. Squawk and die if not unique */
+{
+if (hashLookup(hash, name) != NULL)
+    errAbort("%s duplicated, aborting", name);
+return hashAdd(hash, name, val);
+}
+
+struct hashEl *hashAddSaveName(struct hash *hash, char *name, void *val, char **saveName)
+/* Add new element to hash table.  Save the name of the element, which is now
+ * allocated in the hash table, to *saveName.  A typical usage would be:
+ *    AllocVar(el);
+ *    hashAddSaveName(hash, name, el, &el->name);
+ */
+{
+struct hashEl *hel = hashAdd(hash, name, val);
+*saveName = hel->name;
+return hel;
+}
+
+struct hashEl *hashStore(struct hash *hash, char *name)
+/* If element in hash already return it, otherwise add it
+ * and return it. */
+{
+struct hashEl *hel;
+if ((hel = hashLookup(hash, name)) != NULL)
+    return hel;
+return hashAdd(hash, name, NULL);
+}
+
+char  *hashStoreName(struct hash *hash, char *name)
+/* If element in hash already return it, otherwise add it
+ * and return it. */
+{
+struct hashEl *hel;
+if (name == NULL)
+    return NULL;
+if ((hel = hashLookup(hash, name)) != NULL)
+    return hel->name;
+return hashAdd(hash, name, NULL)->name;
+}
+
+int hashIntVal(struct hash *hash, char *name)
+/* Find size of name in hash or die trying. */
+{
+void *val = hashMustFindVal(hash, name);
+return ptToInt(val);
+}
+
+int hashIntValDefault(struct hash *hash, char *name, int defaultInt)
+/* Return integer value associated with name in a simple 
+ * hash of ints or defaultInt if not found. */
+{
+struct hashEl *hel = hashLookup(hash, name);
+if(hel == NULL)
+    return defaultInt;
+return ptToInt(hel->val);
+}
+
+void *hashMustFindVal(struct hash *hash, char *name)
+/* Lookup name in hash and return val.  Abort if not found. */
+{
+struct hashEl *hel = hashLookup(hash, name);
+if (hel == NULL)
+    errAbort("hashMustFindVal: '%s' not found", name);
+return hel->val;
+}
+
+void *hashFindVal(struct hash *hash, char *name)
+/* Look up name in hash and return val or NULL if not found. */
+{
+struct hashEl *hel = hashLookup(hash, name);
+if (hel == NULL)
+    return NULL;
+return hel->val;
+}
+
+void *hashOptionalVal(struct hash *hash, char *name, void *usual)
+/* Look up name in hash and return val, or usual if not found. */
+{
+struct hashEl *hel = hashLookup(hash, name);
+if (hel == NULL)
+    return usual;
+else
+    return hel->val;
+}
+
+void *hashFindValUpperCase(struct hash *hash, char *name)
+/* Lookup upper cased name in hash and return val or return NULL if not found.
+ * (Assumes all elements of hash are themselves already in upper case.) */
+{
+struct hashEl *hel = hashLookupUpperCase(hash, name);
+if (hel == NULL)
+    return NULL;
+return hel->val;
+}
+
+char *hashMustFindName(struct hash *hash, char *name)
+/* Return name as stored in hash table (in hel->name). 
+ * Abort if not found. */
+{
+struct hashEl *hel = hashLookup(hash, name);
+if (hel == NULL)
+    errAbort("hashMustFindName: '%s' not found", name);
+return hel->name;
+}
+
+struct hashEl *hashAddInt(struct hash *hash, char *name, int val)
+/* Store integer value in hash */
+{
+char *pt = NULL;
+return hashAdd(hash, name, pt + val);
+}
+
+
+void hashIncInt(struct hash *hash, char *name)
+/* Increment integer value in hash */
+{
+struct hashEl *hel = hashLookup(hash, name);
+if (hel == NULL)
+  {
+  hashAddInt(hash, name, 1);
+  }
+else
+  {
+  hel->val = ((char *)hel->val)+1;
+  /* The much simpler ++hel->val works for gnu C, but really adding one to a void pointer
+   * I think is not well defined. */
+  }
+}
+
+long long hashIntSum(struct hash *hash)
+/* Return sum of all the ints in a hash of ints. */
+{
+long long sum = 0;
+int i;
+struct hashEl *hel;
+for (i=0; i<hash->size; ++i)
+    {
+    for (hel = hash->table[i]; hel != NULL; hel = hel->next)
+	{
+	int num = ptToInt(hel->val);
+	sum += (long long)num;
+	}
+    }
+return sum;
+}
+
+struct hash *newHashExt(int powerOfTwoSize, boolean useLocalMem)
+/* Returns new hash table. Uses local memory optionally. */
+{
+struct hash *hash = needMem(sizeof(*hash));
+int memBlockPower = 16;
+if (powerOfTwoSize == 0)
+    powerOfTwoSize = 12;
+assert(powerOfTwoSize <= hashMaxSize && powerOfTwoSize > 0);
+hash->powerOfTwoSize = powerOfTwoSize;
+hash->size = (1<<powerOfTwoSize);
+/* Make size of memory block for allocator vary between
+ * 256 bytes and 64k depending on size of table. */
+if (powerOfTwoSize < 8)
+    memBlockPower = 8;
+else if (powerOfTwoSize < 16)
+    memBlockPower = powerOfTwoSize;
+if (useLocalMem) 
+    hash->lm = lmInit(1<<memBlockPower);
+hash->mask = hash->size-1;
+AllocArray(hash->table, hash->size);
+hash->autoExpand = TRUE;
+hash->expansionFactor = defaultExpansionFactor;   /* Expand when elCount > size*expansionFactor */
+return hash;
+}
+
+void hashResize(struct hash *hash, int powerOfTwoSize)
+/* Resize the hash to a new size */
+{
+int oldHashSize = hash->size;
+struct hashEl **oldTable = hash->table;
+
+if (powerOfTwoSize == 0)
+    powerOfTwoSize = 12;
+assert(powerOfTwoSize <= hashMaxSize && powerOfTwoSize > 0);
+hash->powerOfTwoSize = powerOfTwoSize;
+hash->size = (1<<powerOfTwoSize);
+hash->mask = hash->size-1;
+
+AllocArray(hash->table, hash->size);
+
+int i;
+struct hashEl *hel, *next;
+for (i=0; i<oldHashSize; ++i)
+    {
+    for (hel = oldTable[i]; hel != NULL; hel = next)
+	{
+	next = hel->next;
+	int hashVal = hel->hashVal & hash->mask;
+	hel->next = hash->table[hashVal];
+	hash->table[hashVal] = hel;
+	}
+    }
+/* restore original list order */
+for (i=0; i<hash->size; ++i)
+    {
+    struct hashEl *hel = hash->table[i];
+    if (hel != NULL && hel->next != NULL)	    
+	slReverse(&hash->table[i]);
+    }
+freeMem(oldTable);
+hash->numResizes++;
+}
+
+
+struct hash *hashFromSlNameList(void *list)
+/* Create a hash out of a list of slNames or any kind of list where the */
+/* first field is the next pointer and the second is the name. */
+{
+struct hash *hash = NULL;
+struct slName *namedList = list, *item;
+if (!list)
+    return NULL;
+hash = newHash(0);
+for (item = namedList; item != NULL; item = item->next)
+    hashAdd(hash, item->name, item);
+return hash;
+}
+
+void hashTraverseEls(struct hash *hash, void (*func)(struct hashEl *hel))
+/* Apply func to every element of hash with hashEl as parameter. */
+{
+int i;
+struct hashEl *hel;
+for (i=0; i<hash->size; ++i)
+    {
+    for (hel = hash->table[i]; hel != NULL; hel = hel->next)
+	func(hel);
+    }
+}
+
+void hashTraverseVals(struct hash *hash, void (*func)(void *val))
+/* Apply func to every element of hash with hashEl->val as parameter. */
+{
+int i;
+struct hashEl *hel;
+for (i=0; i<hash->size; ++i)
+    {
+    for (hel = hash->table[i]; hel != NULL; hel = hel->next)
+	func(hel->val);
+    }
+}
+
+int hashElCmp(const void *va, const void *vb)
+/* Compare two hashEl by name. */
+{
+const struct hashEl *a = *((struct hashEl **)va);
+const struct hashEl *b = *((struct hashEl **)vb);
+return strcmp(a->name, b->name);
+}
+
+int hashElCmpWithEmbeddedNumbers(const void *va, const void *vb)
+/* Compare two hashEl by name sorting including numbers within name,
+ * suitable for chromosomes, genes, etc. */
+{
+const struct hashEl *a = *((struct hashEl **)va);
+const struct hashEl *b = *((struct hashEl **)vb);
+return cmpStringsWithEmbeddedNumbers(a->name, b->name);
+}
+
+void *hashElFindVal(struct hashEl *list, char *name)
+/* Look up name in hashEl list and return val or NULL if not found. */
+{
+struct hashEl *el;
+for (el = list; el != NULL; el = el->next)
+    {
+    if (strcmp(el->name, name) == 0)
+        return el->val;
+    }
+return NULL;
+}
+
+struct hashEl *hashElListHash(struct hash *hash)
+/* Return a list of all elements of hash.   Free return with hashElFreeList. */
+{
+int i;
+struct hashEl *hel, *dupe, *list = NULL;
+for (i=0; i<hash->size; ++i)
+    {
+    for (hel = hash->table[i]; hel != NULL; hel = hel->next)
+	{
+	dupe = CloneVar(hel);
+	slAddHead(&list, dupe);
+	}
+    }
+return list;
+}
+
+
+void hashElFree(struct hashEl **pEl)
+/* Free hash el list returned from hashListAll.  (Don't use
+ * this internally.) */
+{
+freez(pEl);
+}
+
+void hashElFreeList(struct hashEl **pList)
+/* Free hash el list returned from hashListAll.  (Don't use
+ * this internally. */
+{
+slFreeList(pList);
+}
+
+struct hashCookie hashFirst(struct hash *hash)
+/* Return an object to use by hashNext() to traverse the hash table.
+ * The first call to hashNext will return the first entry in the table. */
+{
+struct hashCookie cookie;
+cookie.hash = hash;
+cookie.idx = 0;
+cookie.nextEl = NULL;
+
+/* find first entry */
+for (cookie.idx = 0;
+     (cookie.idx < hash->size) && (hash->table[cookie.idx] == NULL);
+     cookie.idx++)
+    continue;  /* empty body */
+if (cookie.idx < hash->size)
+    cookie.nextEl = hash->table[cookie.idx];
+return cookie;
+}
+
+struct hashEl* hashNext(struct hashCookie *cookie)
+/* Return the next entry in the hash table, or NULL if no more. Do not modify
+ * hash table while this is being used. */
+{
+/* NOTE: if hashRemove were coded to track the previous entry during the
+ * search and then use it to do the remove, it would be possible to
+ * remove the entry returned by this method */
+struct hashEl *retEl = cookie->nextEl;
+if (retEl == NULL)
+    return NULL;  /* no more */
+
+/* find next entry */
+cookie->nextEl = retEl->next;
+if (cookie->nextEl == NULL)
+    {
+    for (cookie->idx++; (cookie->idx < cookie->hash->size)
+             && (cookie->hash->table[cookie->idx] == NULL); cookie->idx++)
+        continue;  /* empty body */
+    if (cookie->idx < cookie->hash->size)
+        cookie->nextEl = cookie->hash->table[cookie->idx];
+    }
+return retEl;
+}
+
+void* hashNextVal(struct hashCookie *cookie)
+/* Return the next value in the hash table, or NULL if no more. Do not modify
+ * hash table while this is being used. */
+{
+struct hashEl *hel = hashNext(cookie);
+if (hel == NULL)
+    return NULL;
+else
+    return hel->val;
+}
+
+char *hashNextName(struct hashCookie *cookie)
+/* Return the next name in the hash table, or NULL if no more. Do not modify
+ * hash table while this is being used. */
+{
+struct hashEl *hel = hashNext(cookie);
+if (hel == NULL)
+    return NULL;
+else
+    return hel->name;
+}
+
+void freeHash(struct hash **pHash)
+/* Free up hash table. */
+{
+struct hash *hash = *pHash;
+if (hash == NULL)
+    return;
+if (hash->lm)
+    lmCleanup(&hash->lm);
+else
+    {
+    int i;
+    struct hashEl *hel, *next;
+    for (i=0; i<hash->size; ++i)
+	{
+	for (hel = hash->table[i]; hel != NULL; hel = next)
+	    {
+	    next = hel->next;
+	    freeHashEl(hel);
+	    }
+	}
+    }
+freeMem(hash->table);
+freez(pHash);
+}
+
+
+void freeHashAndVals(struct hash **pHash)
+/* Free up hash table and all values associated with it.
+ * (Just calls freeMem on each hel->val) */
+{
+struct hash *hash;
+if ((hash = *pHash) != NULL)
+    {
+    hashTraverseVals(hash, freeMem);
+    freeHash(pHash);
+    }
+}
+
+void hashFreeWithVals(struct hash **pHash, void (freeFunc)())
+/* Free up hash table and all values associated with it. freeFunc is a
+ * function to free an entry, should take a pointer to a pointer to an
+ * entry. */
+{
+struct hash *hash = *pHash;
+if (hash != NULL)
+    {
+    struct hashCookie cookie = hashFirst(hash);
+    struct hashEl *hel;
+    while ((hel = hashNext(&cookie)) != NULL)
+        freeFunc(&hel->val);
+    hashFree(pHash);
+    }
+}
+
+void hashFreeList(struct hash **pList)
+/* Free up a list of hashes. */
+{
+struct hash *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    hashFree(&el);
+    }
+*pList = NULL;
+}
+
+static int bucketLen(struct hashEl *hel)
+/* determine how many elements are in a hash bucket */
+{
+int nel = 0;
+for (; hel != NULL; hel = hel->next)
+    nel++;
+return nel;
+}
+
+void hashHisto(struct hash *hash, char *fname)
+/* Output bucket usage counts to a file for producing a histogram  */
+{
+FILE* fh = mustOpen(fname, "w");
+int i;
+
+for (i=0; i<hash->size; ++i)
+    fprintf(fh, "%d\n", bucketLen(hash->table[i]));
+carefulClose(&fh);
+}
+
+void hashPrintStats(struct hash *hash, char *label, FILE *fh)
+/* print statistic about a hash table */
+{
+// count up usage
+int i, occupiedCnt = 0, maxBucket = 0;
+for (i=0; i<hash->size; ++i)
+    {
+    if (hash->table[i] != NULL)
+        occupiedCnt++;
+    int sz = bucketLen(hash->table[i]);
+    maxBucket = max(maxBucket, sz);
+    }
+
+fprintf(fh, "hashTable\t%s\n", label);
+fprintf(fh, "tableSize\t%d\t%d\n", hash->size, hash->powerOfTwoSize);
+fprintf(fh, "numElements\t%d\n", hash->elCount);
+fprintf(fh, "occupied\t%d\t%0.4f\n", occupiedCnt, ((hash->size == 0) ? 0.0 : ((float)occupiedCnt)/hash->size));
+fprintf(fh, "maxBucket\t%d\n", maxBucket);
+fprintf(fh, "numResizes\t%d\n", hash->numResizes);
+fprintf(fh, "\n");
+}
+
+struct hashEl *hashReplace(struct hash *hash, char *name, void *val)
+/* Replace an existing element in hash table, or add it if not present. */
+{
+if (hashLookup(hash, name))
+    hashRemove(hash, name);
+return hashAdd(hash, name, val);
+}
+
+char *hashToRaString(struct hash *hash)
+/* Convert hash to string in ra format. */
+{
+struct hashEl *el, *list = hashElListHash(hash);
+struct dyString *dy = dyStringNew(0);
+slSort(&list, hashElCmp);
+for (el = list; el != NULL; el = el->next)
+   {
+   dyStringAppend(dy, el->name);
+   dyStringAppendC(dy, ' ');
+   dyStringAppend(dy, el->val);
+   dyStringAppendC(dy, '\n');
+   }
+hashElFreeList(&list);
+return dyStringCannibalize(&dy);
+}
+
+int hashNumEntries(struct hash *hash)
+/* count the number of entries in a hash */
+{
+int n = 0, i;
+for (i=0; i<hash->size; ++i)
+    n += bucketLen(hash->table[i]);
+return n;
+}
diff --git a/lib/histogram.c b/lib/histogram.c
new file mode 100644
index 0000000..0da3f19
--- /dev/null
+++ b/lib/histogram.c
@@ -0,0 +1,267 @@
+/* histogram function for data array in memory	*/
+
+#include "common.h"
+#include "histogram.h"
+
+
+static unsigned autoScale(float *values, size_t N, float *binSize,
+	unsigned *binCount, float *minValue, float *min, float *max)
+/*	determine binSize, binCount, minValue for values[N]
+ *	If any of those are given, use them instead of calculating.
+ *	A given minValue means ignore data below that.
+ *	NAN's for binSize or minValue are the signals to not use them.
+ *	non-zero for binCount to use it.  NOTE: binCount is actually one
+ *	too high to get the minimum and maximum values in the first and
+ *	last (binCount-1) bins correctly.
+ */
+{
+float minFound = INFINITY;
+float maxFound = -1.0 * INFINITY;
+float range = 0.0;
+unsigned count = 0;
+unsigned bins = DEFAULT_BIN_COUNT;
+size_t i;
+boolean findMinMax = FALSE;
+
+if ( (*min == 0.0) && (*max == 0.0) )
+    findMinMax = TRUE;
+else
+    {
+    minFound = *min;
+    maxFound = *max;
+    }
+
+if (isnan(*minValue))
+    {				/*	minValue is not specified	*/
+    for (i = 0; i < N; ++i)
+	{
+	if (!isnan(values[i]))
+	    {
+	    if (findMinMax)
+		{
+		++count;
+		if (values[i] < minFound) minFound = values[i];
+		if (values[i] > maxFound) maxFound = values[i];
+		}
+	    else
+		{
+		if ( (values[i] < *max) && (values[i] > *min) ) ++count;
+		}
+	    }
+	}
+    }
+else
+    {
+    minFound = *minValue;		/*	use given minValue	*/
+    for (i = 0; i < N; ++i)
+	{
+	if ((!isnan(values[i])) && (values[i] >= minFound))
+	    {
+	    if (findMinMax)
+		{
+		++count;
+		if (values[i] > maxFound) maxFound = values[i];
+		}
+	    else
+		{
+		if ( (values[i] < *max) && (values[i] > *min) ) ++count;
+		}
+	    }
+
+	}
+    }
+
+if (count > 0)
+    {
+    /*	if the caller asked us to find min,max, return them	*/
+    if (findMinMax)
+	{
+	*min = minFound;
+	*max = maxFound;
+	}
+
+    /*	If the caller did not specify a minValue, return it	*/
+    if (isnan(*minValue))
+	*minValue = minFound;
+
+    range = maxFound - minFound;
+
+    /*	if they gave us a binCount, use it	*/
+    if (*binCount > 0)
+	bins = *binCount;
+    else
+	*binCount = bins;
+
+    if ( (range > 0.0) && (bins > 1))
+	{
+	/*  binSize is calculated on (bins - 1) to allow the minimum value
+	 *  to be in the middle of the first bin, and the highest value to be
+	 *	in the middle of the last bin
+	 */
+	if (isnan(*binSize))
+	    *binSize = range / (bins - 1);
+
+	if (*binSize > 0.0)
+	    return count;
+	else
+	    return 0;	/*	did not work	*/
+	}
+    }
+return 0;	/*	did not work	*/
+}	/*	static unsigned autoScale()	*/
+
+void freeHistoGram(struct histoResult **histoResults)
+/*      free the histoResults list	*/
+{
+if (histoResults && *histoResults)
+    {
+    struct histoResult *hr, *next;
+
+    for (hr = *histoResults; hr; hr = next)
+        {
+        next = hr->next;
+        freeMem(hr->binCounts);
+        freeMem(hr->pValues);
+        freeMem(hr);
+        }
+    *histoResults = NULL;
+    }
+}
+
+struct histoResult *histoGram(float *values, size_t N, float binSize,
+	unsigned binCount, float minValue, float min, float max,
+	struct histoResult *accumHisto)
+/*	construct histogram of data in values[N] array.  The extra
+ *	options of binSize, binCount, minValue, min, max are optional.
+ *	Run autoScaling when min == max == 0.0
+ *	Defaults for binSize, binCount and minValue can be given even
+ *	when auto-scaling, or NAN's for the floats, or 0 for the
+ *	binCount to determine them too.
+ *	When they are specified they will be used in place of auto
+ *	scaled determined values.  If the min and max of the data is
+ *	known, pass those in on min,max to aid the calculation of auto
+ *	scaled values.  NAN's can be in the values[N] array and will be
+ *	ignored.
+ *	NOTE: when giving a binCount, it is actually one
+ *	higher to get the minimum and maximum values in the first and
+ *	last (binCount-1) bins correctly.  The resulting histogram will
+ *	appear to be (binCount-1) number of bins.
+ *	When given a pointer to accumHisto, use that existing histo gram
+ *	and continue accumulations in it.
+ */
+{
+float autoBinSize = NAN;	/*	pass NAN's to cause auto scaling */
+float autoMinValue = NAN;
+float range = 0.0;
+unsigned autoBinCount = 0;
+unsigned autoValueCount = 0;
+boolean autoScaling = FALSE;
+unsigned valueCount = 0;
+unsigned i;			/*	array index	*/
+struct histoResult *hr;
+unsigned missed = 0;
+
+if (N == 0)
+    return NULL;	/*	we don't work on zero number of values	*/
+
+if (accumHisto)		/*	if accumulating in existing histogram	*/
+    {			/*	use its parameters as the scaling values */
+    autoBinCount = accumHisto->binCount;
+    autoBinSize = accumHisto->binSize;
+    autoMinValue = accumHisto->binZero;
+    autoScaling = FALSE;
+    range = autoBinSize * (autoBinCount - 1);
+    valueCount = accumHisto->count;
+    }
+else
+    {
+/*	Caller may give us a range to work within	*/
+if ( (0.0 == min) && (0.0 == max) )
+    autoScaling = TRUE;
+else
+    {
+    range = max - min;
+    if (range == 0.0)
+	return NULL;	/*	caller gave us equal min, max !	*/
+    }
+
+/*	Caller may give us any of the binCount, binSize, minValue */
+if (binCount > 1)
+    autoBinCount = binCount;
+else if (!autoScaling)
+    autoBinCount = DEFAULT_BIN_COUNT;
+
+if (!isnan(binSize))
+    autoBinSize = binSize;
+else if (!autoScaling)
+    autoBinSize = range / (autoBinCount - 1);
+
+if (!isnan(minValue))
+    autoMinValue = minValue;
+else if (!autoScaling)
+    autoMinValue = min;
+
+if (autoScaling)
+    {
+    autoValueCount = autoScale(values, N, &autoBinSize,
+			&autoBinCount, &autoMinValue, &min, &max);
+    if (autoValueCount == 0)
+	return NULL;	/*	no result !	*/
+    }
+else
+    autoValueCount = N;
+    }
+
+if (accumHisto)		/*	if accumulating in existing histogram	*/
+    hr = accumHisto;
+else
+    {
+    AllocVar(hr);
+    AllocArray(hr->binCounts,autoBinCount);
+    AllocArray(hr->pValues,autoBinCount);
+    }
+
+for (i = 0; i < N; ++i)
+    {
+    if (!isnan(values[i]) && (values[i] >= autoMinValue))
+	{
+	if ( (values[i] <= max) && (values[i] >= min) )
+	    {
+	    float f = values[i] - autoMinValue;
+	    int inx = (int) floor(f / autoBinSize);
+
+	    if ( (inx >= 0) && (inx < autoBinCount))
+		{
+		++valueCount;
+		++hr->binCounts[inx];
+		}
+	    else
+		++missed;
+	    }
+	    else
+		++missed;
+	}
+	else
+	    ++missed;
+    }	/*	for (i = 0; i < N; ++i)	*/
+
+if (accumHisto)		/*	if accumulating in existing histogram	*/
+    hr->count = valueCount;	/*	only this is new	*/
+else
+    {
+    hr->binSize = autoBinSize;
+    hr->binCount = autoBinCount;
+    hr->count = valueCount;
+    hr->binZero = autoMinValue;
+    }
+
+for (i = 0; i < autoBinCount; ++i)
+    {
+    if (hr->binCounts[i] > 0)
+	hr->pValues[i] = (float) hr->binCounts[i] / (float) valueCount;
+    else
+	hr->pValues[i] = 0.0;
+    }
+
+return hr;
+}
diff --git a/lib/hmmPfamParse.c b/lib/hmmPfamParse.c
new file mode 100644
index 0000000..6e85e92
--- /dev/null
+++ b/lib/hmmPfamParse.c
@@ -0,0 +1,191 @@
+/* hmmpfamParse - Parse hmmpfam files.. */
+
+#include "common.h"
+#include "linefile.h"
+#include "errabort.h"
+#include "spacedColumn.h"
+#include "hmmPfamParse.h"
+
+
+void hpfModelFree(struct hpfModel **pMod)
+/* Free memory associated with hpfModel */
+{
+struct hpfModel *mod = *pMod;
+if (mod != NULL)
+    {
+    freeMem(mod->name);
+    freeMem(mod->description);
+    slFreeList(&mod->domainList);
+    freez(pMod);
+    }
+}
+
+void hpfModelFreeList(struct hpfModel **pList)
+/* Free a list of dynamically allocated hpfModel's */
+{
+struct hpfModel *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    hpfModelFree(&el);
+    }
+*pList = NULL;
+}
+
+
+void hpfResultFree(struct hpfResult **pHr)
+/* Free memory associated with hpfResult */
+{
+struct hpfResult *hr = *pHr;
+if (hr != NULL)
+    {
+    freeMem(hr->name);
+    hpfModelFreeList(&hr->modelList);
+    freez(pHr);
+    }
+}
+
+void hpfResultFreeList(struct hpfResult **pList)
+/* Free a list of dynamically allocated hpfResult's */
+{
+struct hpfResult *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    hpfResultFree(&el);
+    }
+*pList = NULL;
+}
+
+void parseErr(struct lineFile *lf, char *format, ...)
+/* Print out a parse error message. */
+{
+va_list args;
+va_start(args, format);
+vaWarn(format, args);
+va_end(args);
+errAbort("line %d of %s", lf->lineIx, lf->fileName);
+}
+
+char *needLineStartingWith(struct lineFile *lf, char *start, int maxCount)
+/* Get next line that starts as so */
+{
+char *line = lineFileSkipToLineStartingWith(lf, start, maxCount);
+if (line == NULL)
+     parseErr(lf, "Missing line starting with \"%s\"", start);
+return line;
+}
+
+void spacedColumnFatten(struct spacedColumn *colList)
+/* Make columns extend all the way to the next column. */
+{
+struct spacedColumn *col, *nextCol;
+for (col = colList; col != NULL; col = nextCol)
+    {
+    nextCol = col->next;
+    if (nextCol == NULL)
+        break;
+    col->size = nextCol->start - col->start - 1;
+    }
+}
+
+struct hpfModel *hpfFindResultInModel(struct hpfResult *hr, char *modName)
+/* Look for named result in model. */
+{
+struct hpfModel *mod;
+for (mod = hr->modelList; mod != NULL; mod = mod->next)
+    if (sameString(mod->name, modName))
+	break;
+return mod;
+}
+
+struct hpfResult *hpfNext(struct lineFile *lf)
+/* Parse out next record in hmmpfam result file. */
+{
+/* Seek to first line that starts with "Query sequence:" and parse name out of it. */
+char *queryPat = "Query sequence: ";
+char *line = lineFileSkipToLineStartingWith(lf, queryPat, 100);
+if (line == NULL)
+    return NULL;
+line += strlen(queryPat);
+char *query = cloneString(nextWord(&line));
+if (query == NULL)
+    parseErr(lf, "Missing sequence name");
+
+/* Seek to start of model list, figuring out width of fields we need in the process. */
+needLineStartingWith(lf, "Scores for sequence family", 10);
+needLineStartingWith(lf, "Model ", 2);
+char *template = needLineStartingWith(lf, "----", 1);
+struct spacedColumn *colList = spacedColumnFromSample(template);
+spacedColumnFatten(colList);
+int colCount = slCount(colList);
+if (colCount < 5)
+    parseErr(lf, "Expecting at least 5 columns");
+
+/* Parse out all the models. */
+struct hpfResult *hr;
+AllocVar(hr);
+hr->name = query;
+for (;;)
+    {
+    lineFileNeedNext(lf, &line, NULL);
+    line = skipLeadingSpaces(line);
+    if (line[0] == 0)
+        break;
+    if (startsWith("[no hits above thresholds]", line))
+        break;
+    char *row[colCount];
+    if (!spacedColumnParseLine(colList, line, row))
+        parseErr(lf, "short line");
+    struct hpfModel *mod;
+    AllocVar(mod);
+    mod->name = cloneString(row[0]);
+    mod->description = cloneString(row[1]);
+    mod->score = lineFileNeedDouble(lf, row, 2);
+    mod->eVal = lineFileNeedDouble(lf, row, 3);
+    slAddTail(&hr->modelList, mod);
+    }
+slFreeList(&colList);
+
+/* Skip over to the section on domains, figuriong out column widths while we're at it. */
+needLineStartingWith(lf, "Parsed for domains:", 10);
+needLineStartingWith(lf, "Model ", 2);
+template = needLineStartingWith(lf, "----", 1);
+colList = spacedColumnFromSample(template);
+colCount = slCount(colList);
+if (colCount < 8)
+    parseErr(lf, "Expecting at least 8 columns.");
+struct spacedColumn *col2 = colList->next;
+colList->size = col2->start - 1;
+
+/* Parse out all the domains. */
+for (;;)
+    {
+    lineFileNeedNext(lf, &line, NULL);
+    line = skipLeadingSpaces(line);
+    if (line[0] == 0)
+        break;
+    if (startsWith("[no hits above thresholds]", line))
+        break;
+    char *row[colCount];
+    if (!spacedColumnParseLine(colList, line, row))
+        parseErr(lf, "short line");
+    struct hpfModel *mod = hpfFindResultInModel(hr, row[0]);
+    if (mod == NULL)
+        parseErr(lf, "Model %s in domain section but not model section", row[0]);
+    struct hpfDomain *dom;
+    AllocVar(dom);
+    dom->qStart = lineFileNeedNum(lf, row, 2) - 1;
+    dom->qEnd = lineFileNeedNum(lf, row, 3);
+    dom->hmmStart = lineFileNeedNum(lf, row, 4) - 1;
+    dom->hmmEnd = lineFileNeedNum(lf, row, 5);
+    dom->score = lineFileNeedDouble(lf, row, 6);
+    dom->eVal = lineFileNeedDouble(lf, row, 7);
+    slAddTail(&mod->domainList, dom);
+    }
+slFreeList(&colList);
+if (!lineFileSkipToLineStartingWith(lf, "//", 10000000))
+    parseErr(lf, "Expecting //");
+return hr;
+}
+
diff --git a/lib/hmmstats.c b/lib/hmmstats.c
new file mode 100644
index 0000000..412ebc9
--- /dev/null
+++ b/lib/hmmstats.c
@@ -0,0 +1,48 @@
+/* hmmstats.c - Stuff for doing statistical analysis in general and 
+ * hidden Markov models in particular. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "hmmstats.h"
+
+
+int scaledLog(double val)
+/* Return scaled log of val. */
+{
+return round(logScaleFactor * log(val));
+}
+
+double oneOverSqrtTwoPi = 0.39894228;
+
+double simpleGaussean(double x)
+/* Gaussean distribution with standard deviation 1 and mean 0. */
+{
+return oneOverSqrtTwoPi * exp(-0.5*x*x );
+}
+
+double gaussean(double x, double mean, double sd)
+/* Gaussean distribution with mean and standard deviation at point x  */
+{
+x -= mean;
+x /= sd;
+return oneOverSqrtTwoPi * exp(-0.5*x*x) / sd;
+}
+
+double calcVarianceFromSums(double sum, double sumSquares, bits64 n)
+/* Calculate variance. */
+{
+double var = sumSquares - sum*sum/n;
+if (n > 1)
+    var /= n-1;
+return var;
+}
+
+double calcStdFromSums(double sum, double sumSquares, bits64 n)
+/* Calculate standard deviation. */
+{
+return sqrt(calcVarianceFromSums(sum, sumSquares, n));
+}
+
+
diff --git a/lib/htmlPage.c b/lib/htmlPage.c
new file mode 100644
index 0000000..cb8b01b
--- /dev/null
+++ b/lib/htmlPage.c
@@ -0,0 +1,1820 @@
+/* htmlPage - stuff to read, parse, and submit  htmlPages and forms. 
+ *
+ * typical usage is:
+ *   struct htmlPage *page = htmlPageGet(url);
+ *   htmlPageValidateOrAbort(page);
+ *   var = htmlPageGetVar(page, page->forms, "org");
+ *   if (var != NULL)
+ *      printf("Organism = var->org);
+ *   htmlPageSetVar(page, page->forms, "org", "Human");
+ *   newPage = htmlPageFromForm(page, page->forms, "submit", "Go");
+ */
+
+#include "common.h"
+#include "errabort.h"
+#include "errCatch.h"
+#include "memalloc.h"
+#include "linefile.h"
+#include "hash.h"
+#include "dystring.h"
+#include "cheapcgi.h"
+#include "obscure.h"
+#include "filePath.h"
+#include "net.h"
+#include "htmlPage.h"
+
+
+void htmlStatusFree(struct htmlStatus **pStatus)
+/* Free up resources associated with status */
+{
+struct htmlStatus *status = *pStatus;
+if (status != NULL)
+    {
+    freeMem(status->version);
+    freez(pStatus);
+    }
+}
+
+void htmlStatusFreeList(struct htmlStatus **pList)
+/* Free a list of dynamically allocated htmlStatus's */
+{
+struct htmlStatus *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    htmlStatusFree(&el);
+    }
+*pList = NULL;
+}
+
+void htmlCookieFree(struct htmlCookie **pCookie)
+/* Free memory associated with cookie. */
+{
+struct htmlCookie *cookie = *pCookie;
+if (cookie != NULL)
+    {
+    freeMem(cookie->name);
+    freeMem(cookie->value);
+    freeMem(cookie->domain);
+    freeMem(cookie->path);
+    freeMem(cookie->expires);
+    freez(pCookie);
+    }
+}
+
+void htmlCookieFreeList(struct htmlCookie **pList)
+/* Free a list of dynamically allocated htmlCookie's */
+{
+struct htmlCookie *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    htmlCookieFree(&el);
+    }
+*pList = NULL;
+}
+
+struct htmlCookie *htmlCookieFileRead(char *fileName)
+/* Read cookies from a line oriented file.  First word in line
+ * is the cookie name, the rest of the line the cookie value. */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+struct htmlCookie *list = NULL, *cookie;
+char *line, *word;
+while (lineFileNextReal(lf, &line))
+    {
+    word = nextWord(&line);
+    line = skipLeadingSpaces(line);
+    if (line == NULL)
+        errAbort("Missing cookie value line %d of %s", lf->lineIx, lf->fileName);
+    AllocVar(cookie);
+    cookie->name = cloneString(word);
+    cookie->value = cloneString(line);
+    slAddHead(&list, cookie);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+static void cookieOutput(struct dyString *dy, struct htmlCookie *cookieList)
+/* Write cookies to dy. */
+{
+struct htmlCookie *cookie;
+if (cookieList != NULL)
+    {
+    dyStringAppend(dy, "Cookie:");
+    for (cookie = cookieList; cookie != NULL; cookie = cookie->next)
+	{
+	if (cookie != cookieList)
+	    dyStringAppendC(dy, ';');
+	dyStringAppendC(dy, ' ');
+	dyStringAppend(dy, cookie->name);
+	dyStringAppendC(dy, '=');
+	dyStringAppend(dy, cookie->value);
+	}
+    dyStringAppend(dy, "\r\n");
+    }
+}
+
+
+void htmlAttributeFree(struct htmlAttribute **pAttribute)
+/* Free up resources associated with attribute. */
+{
+struct htmlAttribute *att = *pAttribute;
+if (att != NULL)
+    {
+    freeMem(att->name);
+    freeMem(att->val);
+    freez(pAttribute);
+    }
+}
+
+void htmlAttributeFreeList(struct htmlAttribute **pList)
+/* Free a list of dynamically allocated htmlAttribute's */
+{
+struct htmlAttribute *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    htmlAttributeFree(&el);
+    }
+*pList = NULL;
+}
+
+void htmlTagFree(struct htmlTag **pTag)
+/* Free up resources associated with tag. */
+{
+struct htmlTag *tag = *pTag;
+if (tag != NULL)
+    {
+    htmlAttributeFreeList(&tag->attributes);
+    freeMem(tag->name);
+    freez(pTag);
+    }
+}
+
+void htmlTagFreeList(struct htmlTag **pList)
+/* Free a list of dynamically allocated htmlTag's */
+{
+struct htmlTag *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    htmlTagFree(&el);
+    }
+*pList = NULL;
+}
+
+void htmlFormVarFree(struct htmlFormVar **pVar)
+/* Free up resources associated with form variable. */
+{
+struct htmlFormVar *var = *pVar;
+if (var != NULL)
+    {
+    freeMem(var->curVal);
+    slFreeList(&var->values);
+    slFreeList(&var->tags);
+    freez(pVar);
+    }
+}
+
+void htmlFormVarFreeList(struct htmlFormVar **pList)
+/* Free a list of dynamically allocated htmlFormVar's */
+{
+struct htmlFormVar *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    htmlFormVarFree(&el);
+    }
+*pList = NULL;
+}
+
+
+void htmlFormFree(struct htmlForm **pForm)
+/* Free up resources associated with form variable. */
+{
+struct htmlForm *form = *pForm;
+if (form != NULL)
+    {
+    htmlFormVarFreeList(&form->vars);
+    freez(pForm);
+    }
+}
+
+void htmlFormFreeList(struct htmlForm **pList)
+/* Free a list of dynamically allocated htmlForm's */
+{
+struct htmlForm *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    htmlFormFree(&el);
+    }
+*pList = NULL;
+}
+
+void htmlPageFree(struct htmlPage **pPage)
+/* Free up resources associated with htmlPage. */
+{
+struct htmlPage *page = *pPage;
+if (page != NULL)
+    {
+    freez(&page->url);
+    htmlStatusFree(&page->status);
+    freeHashAndVals(&page->header);
+    htmlCookieFreeList(&page->cookies);
+    freez(&page->fullText);
+    htmlTagFreeList(&page->tags);
+    htmlFormFreeList(&page->forms);
+    freez(pPage);
+    }
+}
+
+void htmlPageFreeList(struct htmlPage **pList)
+/* Free a list of dynamically allocated htmlPage's */
+{
+struct htmlPage *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    htmlPageFree(&el);
+    }
+*pList = NULL;
+}
+
+static int findLineNumber(char *start, char *pos)
+/* Figure out line number of given position relative to start. */
+{
+char *s;
+int line = 1;
+for (s = start; s <= pos; ++s)
+    {
+    if (s[0] == '\n')
+       ++line;
+    }
+return line;
+}
+
+static void tagVaWarn(struct htmlPage *page, struct htmlTag *tag, char *format, 
+	va_list args)
+/* Print warning message and some context of tag. */
+{
+char context[80];
+strncpy(context, tag->start, sizeof(context));
+context[sizeof(context)-1] = 0;
+warn("Error near line %d of %s:\n %s", findLineNumber(page->htmlText, tag->start), 
+	page->url, context);
+vaWarn(format, args);
+}
+
+static void tagWarn(struct htmlPage *page, struct htmlTag *tag, char *format, ...)
+/* Print warning message and some context of tag. */
+{
+va_list args;
+va_start(args, format);
+tagVaWarn(page, tag, format, args);
+va_end(args);
+}
+
+static void tagAbort(struct htmlPage *page, struct htmlTag *tag, char *format, ...)
+/* Print abort message and some context of tag. */
+{
+va_list args;
+va_start(args, format);
+tagVaWarn(page, tag, format, args);
+va_end(args);
+noWarnAbort();
+}
+
+struct htmlStatus *htmlStatusParse(char **pText)
+/* Read in status from first line.  Update pText to point to next line. 
+ * Note unlike many routines here, this does not insert zeros into text. */
+{
+char *text = *pText;
+char *end = strchr(text, '\n');
+struct htmlStatus *status;
+if (end != NULL)
+   *pText = end+1;
+else
+   *pText = text + strlen(text);
+end = skipToSpaces(text);
+if (end == NULL)
+    {
+    warn("Short status line.");
+    return NULL;
+    }
+AllocVar(status);
+status->version = cloneStringZ(text, end-text);
+end = skipLeadingSpaces(end);
+if (!isdigit(end[0]))
+    {
+    warn("Not a number in status field");
+    return NULL;
+    }
+status->status = atoi(end);
+return status;
+}
+
+char *htmlNextCrLfLine(char **pS)
+/* Return zero-terminated line and advance *pS to start of
+ * next line.  Return NULL at end of file.  Warn if there is
+ * no <CR>. */
+{
+char *s = *pS, *e;
+if (s == NULL || s[0] == 0)
+    return NULL;
+e = strchr(s, '\n');
+if (e == NULL)
+    verbose(1, "End of file in header\n");
+else 
+    {
+    *e = 0;
+    if (e == s || e[-1] != '\r')
+	verbose(1, "Missing <CR> in header line\n");
+    else
+       e[-1] = 0;
+    e += 1;
+    }
+*pS = e;
+return s;
+}
+
+static void cookieParseNameValuePair(char *s, char **retName, char **retVal)
+/* Parse out name/value pair. Warn and return FALSE if there's a problem. */
+{
+char *val = strchr(s, '=');
+if (val == NULL)
+    {
+    val = s + strlen(s);
+    }
+*val++ = 0;
+*retName = s;
+*retVal = val;
+}
+
+static struct htmlCookie *parseCookie(char *s)
+/* Parse out cookie line to the right of Set-Cookie. */
+{
+char *e, *name, *val;
+struct htmlCookie *cookie;
+
+/* Grab up to semicolon, which is the cookie name/value pair. */
+e = strchr(s, ';');
+if (e == NULL)
+    {
+    warn("Missing ';' in cookie");
+    return NULL;
+    }
+*e++ = 0;
+
+/* Allocate cookie and fill out name/value pair. */
+AllocVar(cookie);
+cookieParseNameValuePair(s, &name, &val);
+cookie->name = cloneString(name);
+cookie->value = cloneString(val);
+
+/* Loop through to grab the other info - domain and so forth. */
+s = e;
+for (;;)
+    {
+    /* Find next semicolon and zero-terminate it. */
+    s = skipLeadingSpaces(s);
+    e = strchr(s, ';');
+    if (e == NULL)
+        break;
+    *e++ = 0;
+
+    /* Parse out name/value pairs and save it away if it's one we know about. */
+    cookieParseNameValuePair(s, &name, &val);
+    if (sameString(name, "domain"))
+        cookie->domain = cloneString(val);
+    else if (sameString(name, "path"))
+        cookie->path = cloneString(val);
+    else if (sameString(name, "expires"))
+        cookie->expires = cloneString(val);
+    else if (sameString(name, "secure"))
+        cookie->secure = TRUE;
+
+    s = e;
+    }
+return cookie;
+}
+
+static struct hash *htmlHeaderRead(char **pHtml, struct htmlCookie **pCookies)
+/* Read in from second line through first blank line and
+ * save in hash.  These lines are in the form name: value. */
+{
+struct hash *hash = hashNew(6);
+for (;;)
+    {
+    char *line = htmlNextCrLfLine(pHtml);
+    char *word;
+    if (line == NULL)
+	{
+        warn("End of file in header");
+	break;
+	}
+    word = nextWord(&line);
+    if (word == NULL)
+        break;
+    line = skipLeadingSpaces(line);
+    hashAdd(hash, word, cloneString(line));
+    if (sameString(word, "Set-Cookie:"))
+	{
+	struct htmlCookie *cookie = parseCookie(line);
+	if (cookie != NULL)
+	    slAddTail(pCookies, cookie);
+	}
+    }
+return hash;
+}
+
+static char *htmlAttributeFindVal(struct htmlAttribute *list, char *name)
+/* Find named attribute or return NULL. */
+{
+struct htmlAttribute *att;
+for (att = list; att != NULL; att = att->next)
+    {
+    if (sameWord(att->name, name))
+        return att->val;
+    }
+return NULL;
+}
+
+
+char *htmlTagAttributeVal(struct htmlPage *page, struct htmlTag *tag, 
+	char *name, char *defaultVal)
+/* Return value of named attribute, or defaultVal if attribute doesn't exist. */
+{
+char *val = htmlAttributeFindVal(tag->attributes, name);
+if (val == NULL)
+    val = defaultVal;
+return val;
+}
+
+char *htmlTagAttributeNeeded(struct htmlPage *page, struct htmlTag *tag, char *name)
+/* Return named tag attribute.  Complain and return "n/a" if it
+ * doesn't exist. */
+{
+char *val = htmlTagAttributeVal(page, tag, name, NULL);
+if (val == NULL)
+    {
+    tagWarn(page, tag, "Missing %s attribute", name);
+    val = "n/a";
+    }
+return val;
+}
+
+static struct htmlTag *htmlTagScan(char *html, char *dupe)
+/* Scan HTML for tags and return a list of them. 
+ * Html is the text to scan, and dupe is a copy of it
+ * which this routine will insert 0's in in the course of
+ * parsing.*/
+{
+char *s = dupe, c, *e, *tagName;
+struct htmlTag *tagList = NULL, *tag;
+struct htmlAttribute *att;
+int pos;
+
+for (;;)
+    {
+    c = *s++;
+    if (c == 0)
+        break;
+    if (c == '<')
+        {
+	if (*s == '!')	/* HTML comment. */
+	    {
+	    s += 1;
+	    if (s[0] == '-' && s[1] == '-')
+	        s = stringIn("-->", s);
+	    else
+		s = strchr(s, '>');
+	    if (s == NULL)
+		{
+	        warn("End of file in comment");
+		break;
+		}
+	    }
+	else
+	    {
+	    /* Grab first word into tagName. */
+	    e = s;
+	    for (;;)
+	        {
+		c = *e;
+		if (c == '>' || c == 0 || isspace(c))
+		    break;
+		e += 1;
+		}
+	    if (c != 0)
+	       *e++ = 0;
+	    tagName = s;
+	    s = e;
+	    
+	    /* Allocate tag, fill in name, and stick it on list. */
+	    AllocVar(tag);
+	    tag->name = cloneString(tagName);
+	    slAddHead(&tagList, tag);
+	    pos = tagName - dupe - 1;
+	    tag->start = html+pos;
+
+	    /* If already got end tag (or EOF) stop processing tag. */
+	    if (c == '>' || c == 0)
+		{
+		tag->end = html + (e - dupe);
+	        continue;
+		}
+
+	    /* Process name/value pairs until get end tag. */
+	    for (;;)
+		{
+		char *name, *val;
+		boolean gotEnd = FALSE;
+
+		/* Check for end tag. */
+		s = skipLeadingSpaces(s);
+		if (s[0] == '>' || s[0] == 0)
+		    {
+		    tag->end = html + (s - dupe);
+		    if (s[0] == '>')
+			tag->end += 1;
+		    break;
+		    }
+
+		/* Get name - everything up to equals. */
+		e = s;
+		for (;;)
+		    {
+		    c = *e;
+		    if (c == '=')
+		        break;
+		    else if (c == '>')
+		        break;
+		    else if (c == 0)
+		        break;
+		    else if (isspace(c))
+		        break;
+		    e += 1;
+		    }
+		if (c == 0)
+		    {
+		    warn("End of file in tag");
+		    break;
+		    }
+		name = s;
+		*e++ = 0;
+		eraseTrailingSpaces(name);
+		if (c == '>')
+		    {
+		    val = "";
+		    gotEnd = TRUE;
+		    tag->end = html + (e - dupe);
+		    }
+		else if (isspace(c))
+		    {
+		    val = "";
+		    }
+		else
+		    {
+		    val = e = skipLeadingSpaces(e);
+		    if (e[0] == '"' || e[0] == '\'')
+			{
+			if (!parseQuotedStringNoEscapes(val, val, &e))
+			    break;
+			}
+		    else
+			{
+			for (;;)
+			    {
+			    c = *e;
+			    if (c == '>')
+				{
+				gotEnd = TRUE;
+				*e++ = 0;
+				tag->end = html + (e - dupe);
+				break;
+				}
+			    else if (isspace(c))
+				{
+				*e++ = 0;
+				break;
+				}
+			    else if (c == 0)
+				break;
+			    ++e;
+			    }
+			}
+		    }
+		AllocVar(att);
+		att->name = cloneString(name);
+		att->val = cloneString(val);
+		slAddTail(&tag->attributes, att);
+		s = e;
+		if (gotEnd)
+		    break;
+		}
+	    }
+	}
+    }
+slReverse(&tagList);
+return tagList;
+}
+
+static struct htmlFormVar *findOrMakeVar(struct htmlPage *page, char *name, 
+	struct hash *hash, struct htmlTag *tag, struct htmlFormVar **pVarList)
+/* Find variable of existing name if it exists,  otherwise
+ * make a new one and add to hash and list.  Add reference
+ * to this tag to var. */
+{
+struct htmlFormVar *var = hashFindVal(hash, name);
+if (var == NULL)
+    {
+    AllocVar(var);
+    var->name = name;
+    var->tagName = tag->name;
+    hashAdd(hash, name, var);
+    slAddHead(pVarList, var);
+    }
+else
+    {
+    if (!sameWord(var->tagName, tag->name))
+        {
+	tagWarn(page, tag, "Mixing FORM variable tag types %s and %s", 
+		var->tagName, tag->name);
+	var->tagName = tag->name;
+	}
+    }
+refAdd(&var->tags, tag);
+return var;
+}
+
+static boolean isMixableInputType(char *type)
+/* Return TRUE if it's a type you can mix with others ok, like
+ * button, submit, and image. */
+{
+return sameWord(type, "BUTTON") || sameWord(type, "SUBMIT") 
+	|| sameWord(type, "IMAGE");
+}
+
+static void htmlFormVarAddValue(struct htmlFormVar *var, char *value)
+/* Add value to list of predefined values for var. */
+{
+struct slName *name = slNameNew(value);
+slAddTail(&var->values, name);
+}
+
+
+static struct htmlFormVar *formParseVars(struct htmlPage *page, struct htmlForm *form)
+/* Return a list of variables parsed out of form.  
+ * A form variable is something that may appear in the name
+ * side of the name=value pairs that serves as input to a CGI
+ * script.  The variables may be constructed from buttons, 
+ * INPUT tags, OPTION lists, or TEXTAREAs. */
+{
+struct htmlTag *tag;
+struct htmlFormVar *varList = NULL, *var;
+struct hash *hash = newHash(0);
+for (tag = form->startTag->next; tag != form->endTag; tag = tag->next)
+    {
+    if (sameWord(tag->name, "INPUT"))
+        {
+	char *type = htmlTagAttributeVal(page, tag, "TYPE", NULL);
+	char *varName = htmlTagAttributeVal(page, tag, "NAME", NULL);
+	char *value = htmlTagAttributeVal(page, tag, "VALUE", NULL);
+
+	if (type == NULL)
+	    type = "TEXT";
+	if (varName == NULL)
+	    {
+	    if (!sameWord(type, "SUBMIT") && !sameWord(type, "CLEAR")
+	    	&& !sameWord(type, "BUTTON") && !sameWord(type, "RESET")
+		&& !sameWord(type, "IMAGE"))
+		tagWarn(page, tag, "Missing NAME attribute");
+	    varName = "n/a";
+	    }
+	var = findOrMakeVar(page, varName, hash, tag, &varList); 
+	if (var->type != NULL && !sameWord(var->type, type))
+	    {
+	    if (!isMixableInputType(var->type) || !isMixableInputType(type))
+		tagWarn(page, tag, "Mixing input types %s and %s", var->type, type);
+	    }
+	var->type = type;
+	if (sameWord(type, "TEXT") || sameWord(type, "PASSWORD") 
+		|| sameWord(type, "FILE") || sameWord(type, "HIDDEN")
+		|| sameWord(type, "IMAGE"))
+	    {
+	    var->curVal = cloneString(value);
+	    }
+	else if (sameWord(type, "CHECKBOX"))
+	    {
+	    if (htmlTagAttributeVal(page, tag, "CHECKED", NULL) != NULL)
+	        var->curVal = cloneString("on");
+	    }
+	else if (sameWord(type, "RADIO"))
+	    {
+	    if (htmlTagAttributeVal(page, tag, "CHECKED", NULL) != NULL)
+	        var->curVal = cloneString(value);
+	    htmlFormVarAddValue(var, value);
+	    }
+	else if ( sameWord(type, "RESET") || sameWord(type, "BUTTON") ||
+		sameWord(type, "SUBMIT") || sameWord(type, "IMAGE") ||
+		sameWord(type, "n/a"))
+	    {
+	    /* Do nothing. */
+	    }
+	else
+	    {
+	    tagWarn(page, tag, "Unrecognized INPUT TYPE %s", type);
+	    }
+	}
+    else if (sameWord(tag->name, "SELECT"))
+        {
+	char *varName = htmlTagAttributeNeeded(page, tag, "NAME");
+	struct htmlTag *subTag;
+	var = findOrMakeVar(page, varName, hash, tag, &varList); 
+	for (subTag = tag->next; subTag != form->endTag; subTag = subTag->next)
+	    {
+	    if (sameWord(subTag->name, "/SELECT"))
+		{
+		if (var->curVal == NULL && var->values != NULL)
+		    {
+		    var->curVal = cloneString(var->values->name);
+		    }
+		break;
+		}
+	    else if (sameWord(subTag->name, "OPTION"))
+	        {
+		char *val = cloneString(htmlTagAttributeVal(page, subTag, "VALUE", NULL));
+		if (val == NULL)
+		    {
+		    char *e = strchr(subTag->end, '<');
+		    if (e != NULL)
+			val = cloneStringZ(subTag->end, e - subTag->end);
+		    }
+		if (val != NULL)
+		    htmlFormVarAddValue(var, val);
+		if (htmlTagAttributeVal(page, subTag, "SELECTED", NULL) != NULL)
+		    {
+		    if (val != NULL)
+			var->curVal = cloneString(val);
+		    }
+		freez(&val);
+		}
+	    }
+	}
+    else if (sameWord(tag->name, "TEXTAREA"))
+        {
+	char *varName = htmlTagAttributeNeeded(page, tag, "NAME");
+	char *e = strchr(tag->end, '<');
+	var = findOrMakeVar(page, varName, hash, tag, &varList); 
+	if (e != NULL)
+	    var->curVal = cloneStringZ(tag->end, e - tag->end);
+	}
+    }
+freeHash(&hash);    
+slReverse(&varList);
+for (var = varList; var != NULL; var = var->next)
+    {
+    slReverse(&var->tags);
+    }
+return varList;
+}
+
+static struct htmlForm *htmlParseForms(struct htmlPage *page,
+	struct htmlTag *startTag, struct htmlTag *endTag)
+/* Parse out list of forms from tag stream. */
+{
+struct htmlForm *formList = NULL, *form = NULL;
+struct htmlTag *tag;
+for (tag = startTag; tag != endTag; tag = tag->next)
+    {
+    if (sameWord(tag->name, "FORM"))
+        {
+	if (form != NULL)
+	    tagWarn(page, tag, "FORM inside of FORM");
+	AllocVar(form);
+	form->startTag = tag;
+	slAddHead(&formList, form);
+	form->name = htmlTagAttributeVal(page, tag, "name", "n/a");
+	form->action = htmlTagAttributeNeeded(page, tag, "action");
+	form->method = htmlTagAttributeVal(page, tag, "method", "GET");
+	}
+    else if (sameWord(tag->name, "/FORM"))
+        {
+	if (form == NULL)
+	    tagWarn(page, tag, "/FORM outside of FORM");
+	else
+	    {
+	    form->endTag = tag->next;
+	    form = NULL;
+	    }
+	}
+    }
+slReverse(&formList);
+for (form = formList; form != NULL; form = form->next)
+    {
+    form->vars = formParseVars(page, form);
+    }
+return formList;
+}
+
+struct htmlPage *htmlPageParse(char *url, char *fullText)
+/* Parse out page and return. */
+{
+struct htmlPage *page;
+char *dupe = cloneLongString(fullText);
+char *s = dupe;
+struct htmlStatus *status = htmlStatusParse(&s);
+char *contentType;
+
+if (status == NULL)
+    return NULL;
+
+AllocVar(page);
+page->url = cloneString(url);
+page->fullText = fullText;
+page->status = status;
+page->header = htmlHeaderRead(&s, &page->cookies);
+contentType = hashFindVal(page->header, "Content-Type:");
+if (contentType == NULL)	
+    {
+    warn("No contentType, assuming text/html");
+    contentType = cloneString("text/html");
+    hashAdd(page->header, "Content-Type:", contentType);
+    }
+page->htmlText = fullText + (s - dupe);
+if (startsWith("text/html", contentType))
+    {
+    page->tags = htmlTagScan(page->htmlText, s);
+    page->forms = htmlParseForms(page, page->tags, NULL);
+    }
+freez(&dupe);
+return page;
+}
+
+struct htmlPage *htmlPageParseNoHead(char *url, char *htmlText)
+/* Parse out page in memory (past http header if any) and return. */
+{
+char *dupe = cloneString(htmlText);
+struct htmlPage *page;
+AllocVar(page);
+page->url = cloneString(url);
+page->fullText = page->htmlText = htmlText;
+page->tags = htmlTagScan(page->htmlText, dupe);
+page->forms = htmlParseForms(page, page->tags, NULL);
+freez(&dupe);
+return page;
+}
+
+struct htmlPage *htmlPageParseOk(char *url, char *fullText)
+/* Parse out page and return only if status ok. */
+{
+struct htmlPage *page = htmlPageParse(url, fullText);
+if (page == NULL)
+   noWarnAbort();
+if (page->status->status != 200)
+   errAbort("%s returned with status code %d", url, page->status->status);
+return page;
+}
+
+char *htmlSlurpWithCookies(char *url, struct htmlCookie *cookies)
+/* Send get message to url with cookies, and return full response as
+ * a dyString.  This is not parsed or validated, and includes http
+ * header lines.  Typically you'd pass this to htmlPageParse() to
+ * get an actual page. */
+{
+struct dyString *dyHeader = dyStringNew(0);
+struct dyString *dyText;
+int sd;
+
+cookieOutput(dyHeader, cookies);
+sd = netOpenHttpExt(url, "GET", dyHeader->string);
+dyText = netSlurpFile(sd);
+close(sd);
+dyStringFree(&dyHeader);
+return dyStringCannibalize(&dyText);
+}
+
+struct htmlPage *htmlPageGetWithCookies(char *url, struct htmlCookie *cookies)
+/* Get page from URL giving server the given cookies.   Note only the
+ * name and value parts of the cookies need to be filled in. */
+{
+char *buf = htmlSlurpWithCookies(url, cookies);
+return htmlPageParse(url, buf);
+}
+
+struct htmlPage *htmlPageForwarded(char *url, struct htmlCookie *cookies)
+/* Get html page.  If it's just a forwarding link then get do the
+ * forwarding.  Cookies is a possibly empty list of cookies with
+ * name and value parts filled in. */
+{
+struct htmlPage *page = htmlPageGetWithCookies(url, cookies);
+int level, maxLevels = 7;
+for (level = 0; level < maxLevels; ++level)
+    {
+    struct htmlPage *newPage;
+    char *newUrl = hashFindVal(page->header, "Location:");
+    if (newUrl == NULL)
+        break;
+    newPage = htmlPageGetWithCookies(newUrl, cookies);
+    htmlPageFree(&page);
+    page = newPage;
+    }
+return page;
+}
+
+struct htmlPage *htmlPageForwardedNoAbort(char *url, struct htmlCookie *cookies)
+/* Try and get an HTML page.  Print warning and return NULL if there's a problem. */
+{
+struct errCatch *errCatch = errCatchNew();
+struct htmlPage *page = NULL;
+if (errCatchStart(errCatch))
+    page = htmlPageForwarded(url, cookies);
+errCatchEnd(errCatch);
+if (errCatch->gotError)
+    warn("%s", errCatch->message->string);
+errCatchFree(&errCatch);
+return page;
+}
+
+
+struct htmlPage *htmlPageGet(char *url)
+/* Get page from URL (may be a file). */
+{
+if (fileExists(url))
+    {
+    char *buf;
+    readInGulp(url, &buf, NULL);
+    return htmlPageParseNoHead(url, buf);
+    }
+else
+    return htmlPageGetWithCookies(url, NULL);
+}
+
+void htmlFormVarPrint(struct htmlFormVar *var, FILE *f, char *prefix)
+/* Print out variable to file, prepending prefix. */
+{
+struct slName *val;
+fprintf(f, "%s%s\t%s\t%s\t%s\n", prefix, var->name, var->tagName, 
+	naForNull(var->type), 
+	naForNull(var->curVal));
+for (val = var->values; val != NULL; val = val->next)
+     fprintf(f, "%s\t%s\n", prefix, val->name);
+}
+
+void htmlFormPrint(struct htmlForm *form, FILE *f)
+/* Print out form structure. */
+{
+struct htmlFormVar *var;
+fprintf(f, "%s\t%s\t%s\n", form->name, form->method, form->action);
+for (var = form->vars; var != NULL; var = var->next)
+    htmlFormVarPrint(var, f, "\t");
+}
+
+struct htmlForm *htmlFormGet(struct htmlPage *page, char *name)
+/* Get named form. */
+{
+struct htmlForm *form;
+for (form = page->forms; form != NULL; form = form->next)
+    if (sameWord(form->name, name))
+        break;
+return form;
+}
+
+struct htmlFormVar *htmlFormVarGet(struct htmlForm *form, char *name)
+/* Get named variable. */
+{
+struct htmlFormVar *var;
+if (form == NULL)
+    errAbort("Null form passed to htmlFormVarGet");
+for (var = form->vars; var != NULL; var = var->next)
+    if (sameWord(var->name, name))
+	break;
+return var;
+}
+
+void htmlFormVarSet(struct htmlForm *form, char *name, char *val)
+/* Set variable to given value. Create it if it doesn't exist*/
+{
+struct htmlFormVar *var;
+if (form == NULL)
+    errAbort("Null form passed to htmlFormVarSet");
+var = htmlFormVarGet(form, name);
+if (var == NULL)
+    {
+    AllocVar(var);
+    var->type = "TEXT";
+    var->tagName = "INPUT";
+    var->name = name;
+    slAddHead(&form->vars, var);
+    }
+freez(&var->curVal);
+var->curVal = cloneString(val);
+}
+
+
+struct htmlFormVar *htmlPageGetVar(struct htmlPage *page, struct htmlForm *form, char *name)
+/* Get named variable.  If form is NULL, first form in page is used. */
+{
+if (form == NULL)
+    form = page->forms;
+return htmlFormVarGet(form, name);
+}
+
+void htmlPageSetVar(struct htmlPage *page, struct htmlForm *form, char *name, char *val)
+/* Set variable to given value.  If form is NULL, first form in page is used. */
+{
+if (page == NULL)
+    errAbort("Null page passed to htmlPageSetVar");
+if (form == NULL)
+    form = page->forms;
+if (form == NULL)
+    errAbort("Null form in htmlPageSetVar");
+htmlFormVarSet(form, name, val);
+}
+
+static void asciiEntityDecode(char *in, char *out, int inLength)
+/* Decode from SGML Character Entity &# format to normal. 
+ * Out will be a little shorter than in typically, and
+ * can be the same buffer. Only supports ASCII charset. */
+{
+char c;
+int i;
+char *e;
+for (i=0; i<inLength;++i)
+    {
+    c = *in++;
+    if ((c == '&') && (*in == '#'))
+	{
+	in++;
+	if ((e = strchr(in,';')) == NULL  || (e - in) > 5)
+	    { /* probably a badly formatted string, just recover and continue */
+	    *out++ = '&';
+	    *out++ = '#';
+	    }
+	else
+	    {
+	    int code;
+	    if (sscanf(in, "%d", &code) != 1)
+		{
+		code = '?';
+		}
+	    if (code > 255) 
+		{
+		code = '?';
+		}
+	    in = e;
+	    in++;
+	    *out++ = code;
+	    }
+	}
+    else
+	*out++ = c;
+    }
+*out++ = 0;
+}
+
+
+char *htmlExpandUrl(char *base, char *url)
+/* Expand URL that is relative to base to stand on its own. 
+ * Return NULL if it's not http or https. */
+{
+struct dyString *dy = NULL;
+char *hostName, *pastHostName;
+
+/* some mailto: have SGML char encoding, e.g a to hide from spambots */
+url = cloneString(url);	/* Clone because asciiEntityDecode may modify it. */
+asciiEntityDecode(url, url, strlen(url));
+
+/* In easiest case URL is actually absolute and begins with
+ * protocol.  Just return clone of url. */
+if (startsWith("http:", url) || startsWith("https:", url))
+    return url;
+
+/* If it's got a colon, but no http or https, then it's some
+ * protocol we don't understand, like a mailto.  Just return NULL. */
+if (strchr(url, ':') != NULL)
+    {
+    freez(&url);
+    return NULL;
+    }
+
+/* Figure out first character past host name. Load up
+ * return string with protocol (if any) and host name. */
+dy = dyStringNew(256);
+if (startsWith("http:", base) || startsWith("https:", base))
+    hostName = (strchr(base, ':') + 3);
+else
+    hostName = base;
+pastHostName = strchr(hostName, '/');
+if (pastHostName == NULL)
+    pastHostName = hostName + strlen(hostName);
+dyStringAppendN(dy, base, pastHostName - base);
+
+/* Add url to return string after host name. */
+if (startsWith("/", url))	/* New URL is absolute, just append to hostName */
+    {
+    dyStringAppend(dy, url);
+    }
+else
+    {
+    char *curDir = pastHostName;
+    char *endDir;
+    if (curDir[0] == '/')
+        curDir += 1;
+    dyStringAppendC(dy, '/');
+    endDir = strrchr(curDir, '/');
+    if (endDir == NULL)
+	endDir = curDir;
+    if (startsWith("../", url))
+	{
+	char *dir = cloneStringZ(curDir, endDir-curDir);
+	char *path = expandRelativePath(dir, url);
+	if (path != NULL)
+	     {
+	     dyStringAppend(dy, path);
+	     }
+	freez(&dir);
+	freez(&path);
+	}
+    else
+	{
+	dyStringAppendN(dy, curDir, endDir-curDir);
+	if (lastChar(dy->string) != '/')
+	    dyStringAppendC(dy, '/');
+	dyStringAppend(dy, url);
+	}
+    }
+freez(&url);
+return dyStringCannibalize(&dy);
+}
+
+static void appendCgiVar(struct dyString *dy, char *name, char *value)
+/* Append cgiVar with cgi-encoded value to dy. */
+{
+char *enc = NULL;
+if (value == NULL)
+    value = "";
+enc = cgiEncode(value);
+if (dy->stringSize != 0)
+    dyStringAppendC(dy, '&');
+dyStringAppend(dy, name);
+dyStringAppendC(dy, '=');
+dyStringAppend(dy, enc);
+freez(&enc);
+}
+
+#define MIMEBUFSIZE 4096
+
+static void appendMimeVar(struct dyString *dy, char *name, char *value, char *varType, char *boundary)
+/* Append cgiVar with cgi-encoded value to dy. */
+{
+char *fileName = NULL;
+
+if (value == NULL)
+    value = "";
+dyStringAppend(dy, "\r\n--");
+dyStringAppend(dy, boundary);
+dyStringAppend(dy, "\r\n");
+dyStringAppend(dy, "content-disposition: form-data; name=\"");
+dyStringAppend(dy, name);
+dyStringAppend(dy, "\"");
+
+if (varType && sameWord(varType, "FILE"))
+    {
+    fileName = strrchr(value,'/'); 
+    if (fileName)
+	++fileName;
+    else
+	fileName = value;
+    dyStringAppend(dy, "; filename=\"");
+    dyStringAppend(dy, fileName);
+    dyStringAppend(dy, "\"");
+    }
+dyStringAppend(dy, "\r\n");
+dyStringAppend(dy, "\r\n");
+if (varType && sameWord(varType, "FILE") && !sameWord(value,""))
+    {
+    FILE *f = mustOpen(value, "r");
+    char buf[MIMEBUFSIZE];
+    int bytesRead = 0;
+    do
+	{
+	bytesRead = fread(buf,1,MIMEBUFSIZE,f);
+	if (bytesRead < 0)
+	    errnoAbort("error reading file to upload %s",value);
+    	dyStringAppendN(dy, buf, bytesRead);
+	}
+    while(bytesRead > 0);
+    carefulClose(&f);
+    }
+else    
+    dyStringAppend(dy, value);
+}
+
+static void appendMimeTerminus(struct dyString *dy, char *boundary)
+/* Append MIME boundary terminator to dy. */
+{
+dyStringAppend(dy, "\r\n--");
+dyStringAppend(dy, boundary);
+dyStringAppend(dy, "--\r\n");
+}
+
+
+static int countOccurrences(char *needle, int nLen, char *haystack, int hLen)
+/* count # of occurrences of needle in haystack */
+{
+int count = 0;
+char *match=NULL;
+while((match=memMatch(needle, nLen, haystack, hLen)) != NULL)
+    {
+    ++count;
+    hLen -= (match - haystack) + nLen;
+    if (hLen < 1)
+	break;
+    haystack=match+nLen;
+    }
+return count;
+}
+
+static boolean isMimeEncoded(struct htmlForm *form)
+/* determine if the form is using MIME encoding */
+{
+struct htmlAttribute *a;
+for(a = form->startTag->attributes;a;a = a->next)
+    if (sameWord(a->name,"ENCTYPE") && sameWord(a->val,"multipart/form-data"))
+	return TRUE;
+return FALSE;
+}
+
+char *htmlFormCgiVars(struct htmlPage *page, struct htmlForm *form, 
+	char *buttonName, char *buttonVal, struct dyString *dyHeader)
+/* Return cgi vars in name=val format from use having pressed
+ * submit button of given name and value. */
+{
+struct dyString *dy = newDyString(0);
+struct htmlFormVar *var;
+boolean isMime = isMimeEncoded(form);
+int mimeParts = 0;
+char boundary[256];
+
+while(TRUE)
+    {
+    if (isMime)
+	{
+	/* choose a new string for the boundary */
+	/* Set initial seed */
+	int i = 0;
+    	safef(boundary,sizeof(boundary),"%s", "---------");
+	srand( (unsigned)time( NULL ) );
+	for(i=strlen(boundary);i<41;++i)
+	    {
+    	    int r = (int) 26 * (rand() / (RAND_MAX + 1.0));
+	    boundary[i] = r+'A';
+	    }
+	boundary[i] = 0;
+	}
+
+    if (form == NULL)
+	form = page->forms;
+    if (buttonName != NULL && !isMime)
+	appendCgiVar(dy, buttonName, buttonVal);
+    for (var = form->vars; var != NULL; var = var->next)
+	{
+	if (sameWord(var->tagName, "SELECT") || 
+	    sameWord(var->tagName, "TEXTAREA") || 
+	    (var->type != NULL &&
+	    ((sameWord(var->type, "RADIO") || sameWord(var->type, "TEXTBOX")
+	    || sameWord(var->type, "PASSWORD") || sameWord(var->type, "HIDDEN")
+	    || sameWord(var->type, "TEXT") || sameWord(var->type, "FILE")))))
+	    {
+	    char *val = var->curVal;
+	    if (val == NULL)
+		val = "";
+	    if (isMime)
+		{
+		++mimeParts;
+		appendMimeVar(dy, var->name, val, var->type, boundary);
+		}
+	    else	    
+		appendCgiVar(dy, var->name, val);
+	    }
+	else if (var->type != NULL && sameWord(var->type, "CHECKBOX"))
+	    {
+	    if (var->curVal != NULL)
+		{
+		if (isMime)	    
+		    {
+		    ++mimeParts;
+		    appendMimeVar(dy, var->name, var->curVal, var->type, boundary);
+		    }
+		else	    
+		    appendCgiVar(dy, var->name, var->curVal);
+		}
+	    }
+	else if (isMime && buttonName && sameWord(buttonName,var->name))
+	    {
+	    ++mimeParts;
+	    appendMimeVar(dy, buttonName, buttonVal, NULL, boundary);
+	    }
+	}
+    if (isMime) 
+	{
+	++mimeParts;
+	appendMimeTerminus(dy,boundary);
+	if (countOccurrences(boundary,strlen(boundary),dy->string,dy->stringSize) != mimeParts)
+	    { /* boundary was found in input! # occurrences not as expected */
+	    dyStringClear(dy);
+    	    continue;  /* if at first you don't succeed, try another boundary string */
+	    }
+    	dyStringPrintf(dyHeader, "Content-type: multipart/form-data, boundary=%s\r\n",boundary);
+	if (isMime && verboseLevel() == 2)
+	    {
+    	    mustWrite(stderr, dyHeader->string, dyHeader->stringSize);
+	    mustWrite(stderr, dy->string, dy->stringSize);
+	    }
+	}
+    break;
+    }   
+    
+return dyStringCannibalize(&dy);
+
+}
+
+struct htmlPage *htmlPageFromForm(struct htmlPage *origPage, struct htmlForm *form, 
+	char *buttonName, char *buttonVal)
+/* Return a new htmlPage based on response to pressing indicated button
+ * on indicated form in origPage. */
+{
+struct htmlPage *newPage = NULL;
+struct dyString *dyUrl = dyStringNew(0);
+struct dyString *dyHeader = dyStringNew(0);
+struct dyString *dyText = NULL;
+char *url = htmlExpandUrl(origPage->url, form->action);
+char *cgiVars = NULL;
+int contentLength = 0;
+int sd = -1;
+
+dyStringAppend(dyUrl, url);
+cookieOutput(dyHeader, origPage->cookies);
+if (sameWord(form->method, "GET"))
+    {
+    cgiVars = htmlFormCgiVars(origPage, form, buttonName, buttonVal, dyHeader);
+    dyStringAppend(dyUrl, "?");
+    dyStringAppend(dyUrl, cgiVars);
+    verbose(3, "GET %s\n", dyUrl->string);
+    sd = netOpenHttpExt(dyUrl->string, form->method, dyHeader->string);
+    }
+else if (sameWord(form->method, "POST"))
+    {
+    cgiVars = htmlFormCgiVars(origPage, form, buttonName, buttonVal, dyHeader);
+    contentLength = strlen(cgiVars);
+    verbose(3, "POST %s\n", dyUrl->string);
+    dyStringPrintf(dyHeader, "Content-length: %d\r\n", contentLength);
+    sd = netOpenHttpExt(dyUrl->string, form->method, dyHeader->string);
+    mustWriteFd(sd, cgiVars, contentLength);
+    }
+dyText = netSlurpFile(sd);
+close(sd);
+newPage = htmlPageParse(url, dyStringCannibalize(&dyText));
+freez(&url);
+dyStringFree(&dyUrl);
+dyStringFree(&dyHeader);
+freez(&cgiVars);
+return newPage;
+}
+
+struct slName *htmlPageScanAttribute(struct htmlPage *page, 
+	char *tagName, char *attribute)
+/* Scan page for values of particular attribute in particular tag.
+ * if tag is NULL then scans in all tags. */
+{
+struct htmlTag *tag;
+struct htmlAttribute *att;
+struct slName *list = NULL, *el;
+
+for (tag = page->tags; tag != NULL; tag = tag->next)
+    {
+    if (tagName == NULL || sameWord(tagName, tag->name))
+        {
+	for (att = tag->attributes; att != NULL; att = att->next)
+	    {
+	    if (sameWord(attribute, att->name))
+	        {
+		el = slNameNew(att->val);
+		slAddHead(&list, el);
+		}
+	    }
+	}
+    }
+slReverse(&list);
+return list;
+}
+
+struct slName *htmlPageLinks(struct htmlPage *page)
+/* Scan through tags list and pull out HREF attributes. */
+{
+return htmlPageScanAttribute(page, NULL, "HREF");
+}
+
+struct htmlTableRow
+/* Data on a row */
+    {
+    struct htmlTableRow *next;
+    int tdCount;
+    int inTd;
+    };
+
+struct htmlTable 
+/* Data on a table. */
+    {
+    struct htmlTable *next;
+    struct htmlTableRow *row;
+    int rowCount;
+    };
+
+static void validateTables(struct htmlPage *page, 
+	struct htmlTag *startTag, struct htmlTag *endTag)
+/* Validate <TABLE><TR><TD> are all properly nested, and that there
+ * are no empty rows. */
+{
+struct htmlTable *tableStack = NULL, *table;
+struct htmlTableRow *row;
+struct htmlTag *tag;
+
+for (tag = startTag; tag != endTag; tag = tag->next)
+    {
+    if (sameWord(tag->name, "TABLE"))
+        {
+	if (tableStack != NULL)
+	    {
+	    if (tableStack->row == NULL || !tableStack->row->inTd)
+	    tagAbort(page, tag, "TABLE inside of another table, but not inside of <TR><TD>\n");
+	    }
+	AllocVar(table);
+	slAddHead(&tableStack, table);
+	}
+    else if (sameWord(tag->name, "/TABLE"))
+        {
+	if ((table = tableStack) == NULL)
+	    tagAbort(page, tag, "Extra </TABLE> tag");
+	if (table->rowCount == 0)
+	    tagAbort(page, tag, "<TABLE> with no <TR>'s");
+	if (table->row != NULL)
+	    tagAbort(page, tag, "</TABLE> inside of a row");
+	tableStack = table->next;
+	freez(&table);
+	}
+    else if (sameWord(tag->name, "TR"))
+        {
+	if ((table = tableStack) == NULL)
+	    tagAbort(page, tag, "<TR> outside of TABLE");
+	if (table->row != NULL)
+	    tagAbort(page, tag, "<TR>...<TR> with no </TR> in between");
+	AllocVar(table->row);
+	table->rowCount += 1;
+	}
+    else if (sameWord(tag->name, "/TR"))
+        {
+	if ((table = tableStack) == NULL)
+	    tagAbort(page, tag, "</TR> outside of TABLE");
+	if (table->row == NULL)
+	    tagAbort(page, tag, "</TR> with no <TR>");
+#ifdef LEGAL_ACTUALLY
+	if (table->row->inTd)
+	    {
+	    tagAbort(page, tag, "</TR> while <TD> is open");
+	    }
+#endif /* LEGAL_ACTUALLY */
+	if (table->row->tdCount == 0)
+	    tagAbort(page, tag, "Empty row in <TABLE>");
+	freez(&table->row);
+	}
+    else if (sameWord(tag->name, "TD") || sameWord(tag->name, "TH"))
+        {
+	if ((table = tableStack) == NULL)
+	    tagAbort(page, tag, "<%s> outside of <TABLE>", tag->name);
+	if ((row = table->row) == NULL)
+	    tagAbort(page, tag, "<%s> outside of <TR>", tag->name);
+#ifdef LEGAL_ACTUALLY
+	if (row->inTd)
+	    {
+	    tagAbort(page, tag, "<%s>...<%s> with no </%s> in between", 
+	    	tag->name, tag->name, tag->name);
+	    }
+#endif /* LEGAL_ACTUALLY */
+	row->inTd = TRUE;
+	row->tdCount += 1;
+	}
+    else if (sameWord(tag->name, "/TD") || sameWord(tag->name, "/TH"))
+        {
+	if ((table = tableStack) == NULL)
+	    tagAbort(page, tag, "<%s> outside of <TABLE>", tag->name);
+	if ((row = table->row) == NULL)
+	    tagAbort(page, tag, "<%s> outside of <TR>", tag->name);
+	if (!row->inTd)
+	    tagAbort(page, tag, "<%s> with no <%s>", tag->name, tag->name+1);
+	row->inTd = FALSE;
+	}
+    }
+if (tableStack != NULL)
+    tagAbort(page, tag, "Missing </TABLE>");
+}
+
+static void checkTagIsInside(struct htmlPage *page, char *outsiders, char *insiders,  
+	struct htmlTag *startTag, struct htmlTag *endTag)
+/* Check that insiders are all bracketed by outsiders. */
+{
+char *outDupe = cloneString(outsiders);
+char *inDupe = cloneString(insiders);
+char *line, *word;
+int depth = 0;
+struct htmlTag *tag;
+struct hash *outOpen = newHash(8);
+struct hash *outClose = newHash(8);
+struct hash *inHash = newHash(8);
+char buf[256];
+
+/* Create hashes of all insiders */
+line = inDupe;
+while ((word = nextWord(&line)) != NULL)
+    {
+    touppers(word);
+    hashAdd(inHash, word, NULL);
+    }
+
+/* Create hash of open and close outsiders. */
+line = outDupe;
+while ((word = nextWord(&line)) != NULL)
+    {
+    touppers(word);
+    hashAdd(outOpen, word, NULL);
+    safef(buf, sizeof(buf), "/%s", word);
+    hashAdd(outClose, buf, NULL);
+    }
+
+/* Stream through tags making sure that insiders are
+ * at least one deep inside of outsiders. */
+for (tag = startTag; tag != NULL; tag = tag->next)
+    {
+    char *type = tag->name;
+    if (hashLookup(outOpen, type ))
+        ++depth;
+    else if (hashLookup(outClose, type))
+        --depth;
+    else if (hashLookup(inHash, type))
+        {
+	if (depth <= 0)
+	    {
+	    if (!startsWith("<INPUT TYPE=HIDDEN NAME=", tag->start))  // one exception hardwired
+		tagAbort(page, tag, "%s outside of any of %s", type, outsiders);
+	    }
+	}
+    }
+freeHash(&inHash);
+freeHash(&outOpen);
+freeHash(&outClose);
+freeMem(outDupe);
+freeMem(inDupe);
+}
+
+static void checkNest(struct htmlPage *page,
+	char *type, struct htmlTag *startTag, struct htmlTag *endTag)
+/* Check that <type> and </type> tags are properly nested. */
+{
+struct htmlTag *tag;
+int depth = 0;
+char endType[256];
+safef(endType, sizeof(endType), "/%s", type);
+for (tag = startTag; tag != endTag; tag = tag->next)
+    {
+    if (sameWord(tag->name, type))
+	++depth;
+    else if (sameWord(tag->name, endType))
+        {
+	--depth;
+	if (depth < 0)
+	   tagAbort(page, tag, "<%s> without preceding <%s>", endType, type);
+	}
+    }
+if (depth != 0)
+    errAbort("Missing <%s> tag", endType);
+}
+
+static void validateNestingTags(struct htmlPage *page,
+	struct htmlTag *startTag, struct htmlTag *endTag,
+	char *nesters[], int nesterCount)
+/* Validate many tags that do need to nest. */
+{
+int i;
+for (i=0; i<nesterCount; ++i)
+    checkNest(page, nesters[i], startTag, endTag);
+}
+
+static char *bodyNesters[] = 
+/* Nesting tags that appear in body. */
+{
+    "ADDRESS", "DIV", "H1", "H2", "H3", "H4", "H5", "H6",
+    "ACRONYM", "BLOCKQUOTE", "CITE", "CODE", "DEL", "DFN"
+    "DIR", "DL", "MENU", "OL", "UL", "CAPTION", "TABLE", 
+    "A", "MAP", "OBJECT", "FORM"
+};
+
+static char *headNesters[] =
+/* Nesting tags that appear in header. */
+{
+    "TITLE",
+};
+
+static struct htmlTag *validateBody(struct htmlPage *page, struct htmlTag *startTag)
+/* Go through tags from current position (just past <BODY>)
+ * up to and including </BODY> and check some things. */
+{
+struct htmlTag *tag, *endTag = NULL;
+
+/* First search for end tag. */
+for (tag = startTag; tag != NULL; tag = tag->next)
+    {
+    if (sameWord(tag->name, "/BODY"))
+        {
+	endTag = tag;
+	break;
+	}
+    }
+if (endTag == NULL)
+    errAbort("Missing </BODY>");
+validateTables(page, startTag, endTag);
+checkTagIsInside(page, "DIR MENU OL UL", "LI", startTag, endTag);
+checkTagIsInside(page, "DL", "DD DT", startTag, endTag);
+checkTagIsInside(page, "COLGROUP TABLE", "COL", startTag, endTag);
+checkTagIsInside(page, "MAP", "AREA", startTag, endTag);
+checkTagIsInside(page, "FORM SCRIPT", 
+	"INPUT BUTTON /BUTTON OPTION SELECT /SELECT TEXTAREA /TEXTAREA"
+	"FIELDSET /FIELDSET"
+	, 
+	startTag, endTag);
+validateNestingTags(page, startTag, endTag, bodyNesters, ArraySize(bodyNesters));
+return endTag->next;
+}
+
+static char *urlOkChars()
+/* Return array character indexed array that has
+ * 1 for characters that are ok in URLs and 0
+ * elsewhere. */
+{
+char *okChars;
+int c;
+AllocArray(okChars, 256);
+for (c=0; c<256; ++c)
+    if (isalnum(c))
+        okChars[c] = 1;
+/* This list is a little more inclusive than W3's. */
+okChars['='] = 1;
+okChars['-'] = 1;
+okChars['/'] = 1;
+okChars['%'] = 1;
+okChars['.'] = 1;
+okChars[';'] = 1;
+okChars[':'] = 1;
+okChars['_'] = 1;
+okChars['&'] = 1;
+okChars['+'] = 1;
+okChars['('] = 1;
+okChars[')'] = 1;
+okChars['$'] = 1;
+okChars['!'] = 1;
+okChars['*'] = 1;
+okChars['@'] = 1;
+okChars['\''] = 1;  // apparently the apostrophe itself is ok
+return okChars;
+}
+
+static void validateCgiUrl(char *url)
+/* Make sure URL follows basic CGI encoding rules. */
+{
+if (startsWith("http:", url) || startsWith("https:", url))
+    {
+    static char *okChars = NULL;
+    UBYTE c, *s;
+    if (okChars == NULL)
+	okChars = urlOkChars();
+    url = strchr(url, '?');
+    if (url != NULL)
+	{
+	s = (UBYTE*)url+1;
+	while ((c = *s++) != 0)
+	    {
+	    if (!okChars[c])
+		{
+		errAbort("Character %c not allowed in URL %s", c, url);
+		}
+	    }
+	}
+    }
+}
+
+static void validateCgiUrls(struct htmlPage *page)
+/* Make sure URLs in page follow basic CGI encoding rules. */
+{
+struct htmlForm *form;
+struct slName *linkList = htmlPageLinks(page), *link;
+
+for (form = page->forms; form != NULL; form = form->next)
+    validateCgiUrl(form->action);
+for (link = linkList; link != NULL; link = link->next)
+    validateCgiUrl(link->name);
+slFreeList(&linkList);
+}
+
+static int countTagsOfType(struct htmlTag *tagList, char *type)
+/* Count number of tags of given type. */
+{
+struct htmlTag *tag;
+int count = 0;
+for (tag = tagList; tag != NULL; tag = tag->next)
+    if (sameString(tag->name, type))
+        ++count;
+return count;
+}
+
+static void checkExactlyOne(struct htmlTag *tagList, char *type)
+/* Check there is exactly one of tag in list. */
+{
+int count = countTagsOfType(tagList, type);
+if (count != 1)
+    errAbort("Expecting exactly 1 <%s>, got %d", type, count);
+}
+
+
+void htmlPageFormOrAbort(struct htmlPage *page)
+/* Aborts if no FORM found */
+{
+if (page == NULL)
+    errAbort("Can't validate NULL page");
+if (page->forms == NULL)
+    errAbort("No form found");
+}
+
+void htmlPageValidateOrAbort(struct htmlPage *page)
+/* Do some basic validations.  Aborts if there is a problem. */
+{
+struct htmlTag *tag;
+boolean gotTitle = FALSE;
+char *contentType = NULL;
+
+if (page == NULL)
+    errAbort("Can't validate NULL page");
+if (page->header != NULL)
+    contentType = hashFindVal(page->header, "Content-Type:");
+if (contentType == NULL || startsWith("text/html", contentType))
+    {
+    /* To simplify things upper case all tag names. */
+    for (tag = page->tags; tag != NULL; tag = tag->next)
+	touppers(tag->name);
+
+    checkExactlyOne(page->tags, "BODY");
+
+    /* Validate header, and make a suggestion or two */
+    if ((tag = page->tags) == NULL)
+	errAbort("No tags");
+    if (!sameWord(tag->name, "HTML"))
+	errAbort("Doesn't start with <HTML> tag");
+    tag = tag->next;
+    if (tag == NULL || !sameWord(tag->name, "HEAD"))
+	warn("<HEAD> tag does not follow <HTML> tag");
+    else
+	{
+	for (;;)
+	    {
+	    tag = tag->next;
+	    if (tag == NULL)
+		errAbort("Missing </HEAD>");
+	    if (sameWord(tag->name, "TITLE"))
+		gotTitle = TRUE;
+	    if (sameWord(tag->name, "/HEAD"))
+		break;
+	    }
+	if (!gotTitle)
+	    warn("No title in <HEAD>");
+	validateNestingTags(page, page->tags, tag, headNesters, ArraySize(headNesters));
+	tag = tag->next;
+	}
+    if (tag == NULL || !sameWord(tag->name, "BODY"))
+	errAbort("<BODY> tag does not follow <HTML> tag");
+    tag = validateBody(page, tag->next);
+    if (tag == NULL || !sameWord(tag->name, "/HTML"))
+	errAbort("Missing </HTML>");
+    validateCgiUrls(page);
+    }
+}
+
diff --git a/lib/htmshell.c b/lib/htmshell.c
new file mode 100644
index 0000000..0ee49bf
--- /dev/null
+++ b/lib/htmshell.c
@@ -0,0 +1,668 @@
+/* htmshell - a shell to wrap around programs that generate
+ * html files.  Write the html initial stuff (<head>, <body>, etc.)
+ * and the final stuff too.  Also catch errors here so that
+ * the html final stuff is written even if the program has
+ * to abort.
+ *
+ * This also includes a few routines to write commonly used
+ * html constructs such as images, horizontal lines. etc.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "obscure.h"
+#include "cheapcgi.h"
+#include "htmshell.h"
+#include "errabort.h"
+#include "dnautil.h"
+
+
+jmp_buf htmlRecover;
+
+static bool NoEscape = FALSE;
+
+void htmlNoEscape()
+{
+NoEscape = TRUE;
+}
+
+void htmlDoEscape()
+{
+NoEscape = FALSE;
+}
+
+void htmlVaParagraph(char *line, va_list args)
+/* Print a line in it's own paragraph. */
+{
+fputs("<P>", stdout);
+vfprintf(stdout, line, args);
+fputs("</P>\n", stdout);
+}
+
+void htmlParagraph(char *line, ...)
+{
+va_list args;
+va_start(args, line);
+htmlVaParagraph(line, args);
+va_end(args);
+}
+
+void htmlVaCenterParagraph(char *line, va_list args)
+/* Center a line in it's own paragraph. */
+{
+fputs("<P ALIGN=\"CENTER\">", stdout);
+vfprintf(stdout, line, args);
+fputs("</P>\n", stdout);
+}
+
+void htmlCenterParagraph(char *line, ...)
+{
+va_list args;
+va_start(args, line);
+htmlVaCenterParagraph(line, args);
+va_end(args);
+}
+
+void htmlHorizontalLine()
+/* Print a horizontal line. */
+{
+printf("<HR ALIGN=\"CENTER\">");
+}
+
+void htmHorizontalLine(FILE *f)
+/* Print a horizontal line. */
+{
+fprintf(f, "<HR ALIGN=\"CENTER\">");
+}
+
+void htmlNbSpaces(int count)
+/* Print a number of non-breaking spaces. */
+{
+int i;
+for (i=0; i<count; ++i)
+    printf(" ");
+}
+
+void htmTextOut(FILE *f, char *s)
+/* Print out string to file, if necessary replacing > with > and the like */
+{
+char c;
+if (NoEscape)
+    {
+    fputs(s, f);
+    return;
+    }
+
+while ((c = *s++) != 0)
+    {
+    switch (c)
+        {
+	case '>':
+	    fputs(">", f);
+	    break;
+	case '<':
+	    fputs("<", f);
+	    break;
+	case '&':
+	    fputs("&", f);
+	    break;
+	case '"':
+	    fputs(""", f);
+	    break;
+	default:
+	    fputc(c, f);
+	    break;
+	}
+    }
+}
+
+void htmlTextOut(char *s)
+/* Print out string, if necessary replacing > with > and the like */
+{
+htmTextOut(stdout, s);
+}
+
+char *htmlTextStripTags(char *s)
+/* Returns a cloned string with all html tags stripped out */
+{
+if (s == NULL)
+    return NULL;
+char *scrubbed = needMem(strlen(s));
+char *from=s;
+char *to=scrubbed;
+while (*from!='\0')
+    {
+    if (*from == '<')
+        {
+        from++;
+        while (*from!='\0' && *from != '>')
+            from++;
+        if (*from == '\0')  // The last open tag was never closed!
+            break;
+        from++;
+        }
+    else
+        *to++ = *from++;
+    }
+return scrubbed;
+}
+
+char *htmlTextReplaceTagsWithChar(char *s, char ch)
+/* Returns a cloned string with all html tags replaced with given char (useful for tokenizing) */
+{
+if (s == NULL)
+    return NULL;
+char *scrubbed = needMem(strlen(s) + 1);
+char *from=s;
+char *to=scrubbed;
+while(*from!='\0')
+    {
+    if (*from == '<')
+        {
+        from++;
+        *to++ = ch;
+        while (*from!='\0' && *from != '>')
+            from++;
+        if (*from == '\0')  // The last open tag was never closed!
+            break;
+        from++;
+        }
+    else
+        *to++ = *from++;
+    }
+*to = '\0';
+return scrubbed;
+}
+
+char *htmlEncodeText(char *s,boolean tagsOkay)
+/* Returns a cloned string with quotes replaced by html codes.
+   Changes ',",\n and if not tagsOkay >,<,& to code equivalents.
+   This differs from cgiEncode as it handles text that will
+   be displayed in an html page or tooltip style title.  */
+{
+int size = strlen(s) + 3; // Add some slop
+if (tagsOkay)
+    size += countChars(s,'\n') * 4;
+else
+    {
+    size += countChars(s,'>' ) * 4;
+    size += countChars(s,'<' ) * 4;
+    size += countChars(s,'&' ) * 5;
+    size += countChars(s,'\n') * 6;
+    }
+size += countChars(s,'"' ) * 6;
+size += countChars(s,'\'') * 5;
+char *cleanQuote = needMem(size);
+safecpy(cleanQuote,size,s);
+
+// NOTE: While some internal HTML should work, a single quote (') will will screw it up!
+if (tagsOkay)
+    strSwapStrs(cleanQuote, size,"\n","<BR>" ); // new lines also break the html
+else
+    {
+    strSwapStrs(cleanQuote, size,"&","&" );  // '&' is not the start of a control char
+    strSwapStrs(cleanQuote, size,">",">"  );  // '>' is not the close of a tag
+    strSwapStrs(cleanQuote, size,"<","<"  );  // '<' is not the open of a tag
+    if (cgiClientBrowser(NULL,NULL,NULL) == btFF)
+        strSwapStrs(cleanQuote, size,"\n","|"); // FF does not support!  Use "|" for '|'
+                                                     // instead
+    else
+        strSwapStrs(cleanQuote, size,"\n","&#x0A;"); // '\n' is supported on some browsers
+    }
+strSwapStrs(cleanQuote, size,"\"","""); // Shield double quotes
+strSwapStrs(cleanQuote, size,"'" ,"'" ); // Shield single quotes
+
+return cleanQuote;
+}
+
+char *attributeEncode(char *str)
+{
+// encode double and single quotes in a string to be used as an element attribute
+return replaceChars(replaceChars(str, "\"", """), "'", "'");
+}
+
+char *htmlWarnStartPattern()
+/* Return starting pattern for warning message. */
+{
+return "<!-- HGERROR-START -->\n";
+}
+
+char *htmlWarnEndPattern()
+/* Return ending pattern for warning message. */
+{
+return "<!-- HGERROR-END -->\n";
+}
+
+void htmlWarnBoxSetup(FILE *f)
+/* Creates an invisible, empty warning box than can be filled with errors
+ * and then made visible. */
+{
+// Only set this up once per page
+static boolean htmlWarnBoxSetUpAlready=FALSE;
+if (htmlWarnBoxSetUpAlready)
+    return;
+htmlWarnBoxSetUpAlready=TRUE;
+
+// NOTE: Making both IE and FF work is almost impossible.  Currently, in IE, if the message
+// is forced to the top (calling this routine after <BODY> then the box is not resizable
+// (dynamically adjusting to its contents). But if this setup is done later in the page
+// (at first warning), then IE does resize it.  Why?
+// FF3.0 (but not FF2.0) was resizable with the following, but it took some experimentation.
+// Remember what worked nicely on FF3.0:
+//      "var app=navigator.appName.substr(0,9); "
+//      "if(app == 'Microsoft') {warnBox.style.display='';} 
+//       else {warnBox.style.display=''; warnBox.style.width='auto';}"
+fprintf(f, "<script type='text/javascript'>\n");
+fprintf(f, "document.write(\"<center>"
+            "<div id='warnBox' style='display:none;'>"
+            "<CENTER><B id='warnHead'></B></CENTER>"
+            "<UL id='warnList'></UL>"
+            "<CENTER><button id='warnOK' onclick='hideWarnBox();return false;'></button></CENTER>"
+            "</div></center>\");\n");
+fprintf(f,"function showWarnBox() {"
+            "document.getElementById('warnOK').innerHTML=' OK ';"
+            "var warnBox=document.getElementById('warnBox');"
+            "warnBox.style.display=''; warnBox.style.width='65%%';"
+            "document.getElementById('warnHead').innerHTML='Warning/Error(s):';"
+            "window.scrollTo(0, 0);"
+          "}\n");
+fprintf(f,"function hideWarnBox() {"
+            "var warnBox=document.getElementById('warnBox');"
+            "warnBox.style.display='none';warnBox.innerHTML='';"
+            "var endOfPage = document.body.innerHTML.substr(document.body.innerHTML.length-20);"
+            "if(endOfPage.lastIndexOf('-- ERROR --') > 0) { history.back(); }"
+          "}\n"); // Note OK button goes to prev page when this page is interrupted by the error.
+fprintf(f,"window.onunload = function(){}; // Trick to avoid FF back button issue.\n");
+fprintf(f,"</script>\n");
+}
+
+void htmlVaWarn(char *format, va_list args)
+/* Write an error message. */
+{
+va_list argscp;
+va_copy(argscp, args);
+htmlWarnBoxSetup(stdout); // sets up the warnBox if it hasn't already been done.
+char warning[1024];
+vsnprintf(warning,sizeof(warning),format, args);
+char *encodedMessage = htmlEncodeText(warning,TRUE); // NOTE: While some internal HTML should work,
+                                                     // a single quote (') will will screw it up!
+printf("<script type='text/javascript'>{showWarnBox();"
+        "var warnList=document.getElementById('warnList');"
+        "warnList.innerHTML += '<li>%s</li>';}</script><!-- ERROR -->\n",encodedMessage); 
+                                     // NOTE that "--ERROR --" is needed at the end of this print!!
+freeMem(encodedMessage);
+
+/* Log useful CGI info to stderr */
+logCgiToStderr();
+
+/* write warning/error message to stderr so they get logged. */
+vfprintf(stderr, format, argscp);
+va_end(argscp);
+fflush(stderr);
+}
+
+void htmlAbort()
+/* Terminate HTML file. */
+{
+longjmp(htmlRecover, -1);
+}
+
+void htmlMemDeath()
+{
+errAbort("Out of memory.");
+}
+
+static void earlyWarningHandler(char *format, va_list args)
+/* Write an error message so user can see it before page is really started. */
+{
+static boolean initted = FALSE;
+if (!initted)
+    {
+    htmlStart("Very Early Error");
+    initted = TRUE;
+    }
+printf("%s", htmlWarnStartPattern());
+htmlVaParagraph(format,args);
+printf("%s", htmlWarnEndPattern());
+}
+
+static void earlyAbortHandler()
+/* Exit close web page during early abort. */
+{
+printf("</BODY></HTML>");
+exit(0);
+}
+
+void htmlPushEarlyHandlers()
+/* Push stuff to close out web page to make sensible error
+ * message during initialization. */
+{
+pushWarnHandler(earlyWarningHandler);
+pushAbortHandler(earlyAbortHandler);
+}
+
+
+static char *htmlStyle =
+    "<STYLE TYPE=\"text/css\">"
+    ".hiddenText {background-color: silver}"
+    ".normalText {background-color: white}"
+    "</STYLE>\n";
+
+char *htmlStyleUndecoratedLink =
+/* Style that gets rid of underline of links. */
+   "<STYLE TYPE=\"text/css\"> "
+   "<!-- "
+   "A {text-decoration: none} "
+   "-->"
+   "</STYLE>\n";
+
+// optional style set by theme, added after main style and thus
+// can overwrite main style settings
+static char *htmlStyleTheme = NULL;
+
+void htmlSetStyle(char *style)
+/* Set document wide style. A favorite style to
+ * use for many purposes is htmlStyleUndecoratedLink
+ * which will remove underlines from links.
+ * Needs to be called before htmlStart or htmShell. */
+{
+htmlStyle = style;
+}
+
+static char *htmlStyleSheet = NULL;
+void htmlSetStyleSheet(char *styleSheet)
+/* Set document wide style sheet by adding css name to HEAD part.
+ * Needs to be called before htmlStart or htmShell. */
+{
+htmlStyleSheet = styleSheet;
+}
+
+static char *htmlFormClass = NULL;
+void htmlSetFormClass(char *formClass)
+/* Set class in the BODY part. */
+{
+htmlFormClass = formClass;
+}
+
+void htmlSetStyleTheme(char *style)
+/* Set theme style. Needs to be called before htmlStart or htmShell. */
+{
+htmlStyleTheme = style;
+}
+
+static char *htmlBackground = NULL;
+
+void htmlSetBackground(char *imageFile)
+/* Set background - needs to be called before htmlStart
+ * or htmShell. */
+{
+htmlBackground = imageFile;
+}
+
+static int htmlBgColor = 0xFFFFFF;
+boolean gotBgColor = FALSE;
+
+void htmlSetBgColor(int color)
+/* Set background color - needs to be called before htmlStart
+ * or htmShell. */
+{
+htmlBgColor = color;
+gotBgColor = TRUE;
+}
+
+void htmlSetCookie(char* name, char* value, char* expires, char* path, char* domain, boolean isSecure)
+/* create a cookie with the given stats */
+{
+char* encoded_name;
+char* encoded_value;
+char* encoded_path = NULL;
+
+encoded_name = cgiEncode(name);
+encoded_value = cgiEncode(value);
+if(path != NULL)
+	encoded_path = cgiEncode(path);
+
+printf("Set-Cookie: %s=%s; ", encoded_name, encoded_value);
+
+if(expires != NULL)
+    printf("expires=%s; ", expires);
+
+if(path != NULL)
+    printf("path=%s; ", encoded_path);
+
+if(domain != NULL)
+    printf("domain=%s; ", domain);
+
+if(isSecure == TRUE)
+    printf("secure");
+
+printf("\n");
+}
+
+void printBodyTag(FILE *f)
+{
+// print starting BODY tag, including any appropriate attributes (class, background and bgcolor). 
+fprintf(f, "<BODY");
+struct slName *classes = NULL;
+
+slNameAddHead(&classes, "cgi");
+char *scriptName = cgiScriptName();
+if(isNotEmpty(scriptName))
+    {
+    char buf[FILENAME_LEN];
+    splitPath(scriptName, NULL, buf, NULL);
+    slNameAddHead(&classes, cloneString(buf));
+}
+if (htmlFormClass != NULL )
+    slNameAddHead(&classes, htmlFormClass);
+fprintf(f, " CLASS=\"%s\"", slNameListToString(classes, ' '));
+
+if (htmlBackground != NULL )
+    fprintf(f, " BACKGROUND=\"%s\"", htmlBackground);
+if (gotBgColor)
+    fprintf(f, " BGCOLOR=\"#%X\"", htmlBgColor);
+fputs(">\n",f);
+}
+
+void _htmStartWithHead(FILE *f, char *head, char *title, boolean printDocType, int dirDepth)
+/* Write out bits of header that both stand-alone .htmls
+ * and CGI returned .htmls need, including optional head info */
+{
+if (printDocType)
+    {
+//#define TOO_TIMID_FOR_CURRENT_HTML_STANDARDS
+#ifdef TOO_TIMID_FOR_CURRENT_HTML_STANDARDS
+    fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n", f);
+#else///ifndef TOO_TIMID_FOR_CURRENT_HTML_STANDARDS
+    char *browserVersion;
+    if (btIE == cgiClientBrowser(&browserVersion, NULL, NULL) && *browserVersion < '8')
+        fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n", f);
+    else
+        fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" "
+              "\"http://www.w3.org/TR/html4/loose.dtd\">",f);
+    // Strict would be nice since it fixes atleast one IE problem (use of :hover CSS pseudoclass)
+#endif///ndef TOO_TIMID_FOR_CURRENT_HTML_STANDARDS
+    }
+fputs("<HTML>", f);
+fprintf(f,"<HEAD>\n%s<TITLE>%s</TITLE>\n", head, title);
+fprintf(f, "\t<META http-equiv=\"Content-Script-Type\" content=\"text/javascript\">\n");
+if (htmlStyle != NULL)
+    fputs(htmlStyle, f);
+if (htmlStyleSheet != NULL)
+    fprintf(f,"<link href=\"%s\" rel=\"stylesheet\" type=\"text/css\">\n", htmlStyleSheet);
+if (htmlStyleTheme != NULL)
+    fputs(htmlStyleTheme, f);
+
+fputs("</HEAD>\n\n",f);
+printBodyTag(f);
+htmlWarnBoxSetup(f);
+}
+
+
+void htmlStart(char *title)
+/* Write the start of an html from CGI */
+{
+puts("Content-Type:text/html");
+puts("\n");
+_htmStartWithHead(stdout, "", title, TRUE, 1);
+}
+
+void htmStartWithHead(FILE *f, char *head, char *title)
+/* Write the start of a stand alone .html file, plus head info */
+{
+_htmStartWithHead(f, head, title, TRUE, 1);
+}
+
+void htmStart(FILE *f, char *title)
+/* Write the start of a stand alone .html file. */
+{
+htmStartWithHead(f, "", title);
+}
+
+void htmStartDirDepth(FILE *f, char *title, int dirDepth)
+/* Write the start of a stand alone .html file.  dirDepth is the number of levels
+ * beneath apache root that caller's HTML will appear to the web client.
+ * E.g. if writing HTML from cgi-bin, dirDepth is 1; if trash/body/, 2. */
+{
+_htmStartWithHead(f, "", title, TRUE, dirDepth);
+}
+
+/* Write the end of an html file */
+void htmEnd(FILE *f)
+{
+fputs("\n</BODY>\n</HTML>\n", f);
+}
+
+/* Write the end of a stand-alone html file */
+void htmlEnd()
+{
+htmEnd(stdout);
+}
+
+void htmlBadVar(char *varName)
+{
+cgiBadVar(varName);
+}
+
+/* Display centered image file. */
+void htmlImage(char *fileName, int width, int height)
+{
+printf("<P ALIGN=\"CENTER\"><IMG SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\" ALIGN=\"BOTTOM\" BORDER=\"0\"></P>", fileName, width, height);
+}
+
+
+void htmErrOnlyShell(void (*doMiddle)())
+/* Wrap error recovery around call to doMiddle. */
+{
+int status;
+
+/* Set up error recovery. */
+status = setjmp(htmlRecover);
+
+/* Do your main thing. */
+if (status == 0)
+    {
+    doMiddle();
+    }
+}
+
+void htmEmptyShell(void (*doMiddle)(), char *method)
+/* Wrap error recovery and and input processing around call to doMiddle. */
+{
+int status;
+
+/* Set up error recovery (for out of memory and the like)
+ * so that we finish web page regardless of problems. */
+pushAbortHandler(htmlAbort);
+pushWarnHandler(htmlVaWarn);
+status = setjmp(htmlRecover);
+
+/* Do your main thing. */
+if (status == 0)
+    {
+    doMiddle();
+    }
+
+popWarnHandler();
+popAbortHandler();
+}
+
+
+/* Wrap an html file around the passed in function.
+ * The passed in function is already in the body. It
+ * should just make paragraphs and return.
+ */
+void htmShell(char *title, void (*doMiddle)(), char *method)
+{
+/* Preamble. */
+dnaUtilOpen();
+htmlStart(title);
+
+/* Call wrapper for error handling. */
+htmEmptyShell(doMiddle, method);
+
+/* Post-script. */
+htmlEnd();
+}
+
+/* Wrap an html file around the passed in function.
+ * The passed in function is already in the body. It
+ * should just make paragraphs and return.
+ * Method should be "query" or "get" or "post".
+param title - The HTML page title
+param head - The head text: can be a refresh directive or javascript
+param method - The function pointer to execute in the middle
+param method - The browser request method to use
+ */
+void htmShellWithHead( char *title, char *head, void (*doMiddle)(), char *method)
+{
+/* Preamble. */
+dnaUtilOpen();
+
+puts("Content-Type:text/html");
+puts("\n");
+
+puts("<HTML>");
+printf("<HEAD>%s<TITLE>%s</TITLE>\n</HEAD>\n\n", head, title);
+printBodyTag(stdout);
+
+htmlWarnBoxSetup(stdout);// Sets up a warning box which can be filled with errors as they occur
+
+/* Call wrapper for error handling. */
+htmEmptyShell(doMiddle, method);
+
+/* Post-script. */
+htmlEnd();
+}
+
+/* Include an HTML file in a CGI */
+void htmlIncludeFile(char *path)
+{
+char *str = NULL;
+size_t len = 0;
+
+if (path == NULL)
+    errAbort("Program error: including null file");
+if (!fileExists(path))
+    errAbort("Missing file %s", path);
+readInGulp(path, &str, &len);
+
+if (len <= 0)
+    errAbort("Error reading included file: %s", path);
+
+puts(str);
+freeMem(str);
+}
+
+/* Include an HTML file in a CGI.
+ *   The file path is relative to the web server document root */
+void htmlIncludeWebFile(char *file)
+{
+char path[256];
+char *docRoot = "/usr/local/apache/htdocs";
+
+safef(path, sizeof path, "%s/%s", docRoot, file);
+htmlIncludeFile(path);
+}
+
diff --git a/lib/https.c b/lib/https.c
new file mode 100644
index 0000000..3c6cc8b
--- /dev/null
+++ b/lib/https.c
@@ -0,0 +1,385 @@
+/* Connect via https. */
+
+#ifdef USE_SSL
+
+#include "openssl/ssl.h"
+#include "openssl/err.h"
+
+#include <sys/socket.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include "common.h"
+#include "errabort.h"
+
+
+static pthread_mutex_t *mutexes = NULL;
+ 
+static unsigned long openssl_id_callback(void)
+{
+return ((unsigned long)pthread_self());
+}
+ 
+static void openssl_locking_callback(int mode, int n, const char * file, int line)
+{
+if (mode & CRYPTO_LOCK)
+    pthread_mutex_lock(&mutexes[n]);
+else
+    pthread_mutex_unlock(&mutexes[n]);
+}
+ 
+void openssl_pthread_setup(void)
+{
+int i;
+int numLocks = CRYPTO_num_locks();
+AllocArray(mutexes, numLocks);
+for (i = 0;  i < numLocks;  i++)
+    pthread_mutex_init(&mutexes[i], NULL);
+CRYPTO_set_id_callback(openssl_id_callback);
+CRYPTO_set_locking_callback(openssl_locking_callback);
+}
+ 
+
+struct netConnectHttpsParams
+/* params to pass to thread */
+{
+pthread_t thread;
+char *hostName;
+int port;
+int sv[2]; /* the pair of socket descriptors */
+};
+
+static void xerrno(char *msg)
+{
+fprintf(stderr, "%s : %s\n", strerror(errno), msg); fflush(stderr);
+}
+
+static void xerr(char *msg)
+{
+fprintf(stderr, "%s\n", msg); fflush(stderr);
+}
+
+void openSslInit()
+/* do only once */
+{
+static boolean done = FALSE;
+static pthread_mutex_t osiMutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_lock( &osiMutex );
+if (!done)
+    {
+    SSL_library_init();
+    ERR_load_crypto_strings();
+    ERR_load_SSL_strings();
+    OpenSSL_add_all_algorithms();
+    openssl_pthread_setup();
+    done = TRUE;
+    }
+pthread_mutex_unlock( &osiMutex );
+}
+
+
+void *netConnectHttpsThread(void *threadParam)
+/* use a thread to run socket back to user */
+{
+/* child */
+
+struct netConnectHttpsParams *params = threadParam;
+
+pthread_detach(params->thread);  // this thread will never join back with it's progenitor
+
+int fd=0;
+
+char hostnameProto[256];
+
+BIO *sbio;
+SSL_CTX *ctx;
+SSL *ssl;
+
+openSslInit();
+
+ctx = SSL_CTX_new(SSLv23_client_method());
+
+fd_set readfds;
+fd_set writefds;
+int err;
+struct timeval tv;
+
+
+/* TODO checking certificates 
+
+char *certFile = NULL;
+char *certPath = NULL;
+if (certFile || certPath)
+    {
+    SSL_CTX_load_verify_locations(ctx,certFile,certPath);
+#if (OPENSSL_VERSION_NUMBER < 0x0090600fL)
+    SSL_CTX_set_verify_depth(ctx,1);
+#endif
+    }
+
+// verify paths and mode.
+
+*/
+
+
+sbio = BIO_new_ssl_connect(ctx);
+
+BIO_get_ssl(sbio, &ssl);
+if(!ssl) 
+    {
+    xerr("Can't locate SSL pointer");
+    goto cleanup;
+    }
+
+/* Don't want any retries since we are non-blocking bio now */
+//SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+
+
+safef(hostnameProto,sizeof(hostnameProto),"%s:%d",params->hostName,params->port);
+BIO_set_conn_hostname(sbio, hostnameProto);
+
+BIO_set_nbio(sbio, 1);     /* non-blocking mode */
+
+while (1) 
+    {
+    if (BIO_do_connect(sbio) == 1) 
+	{
+	break;  /* Connected */
+	}
+    if (! BIO_should_retry(sbio)) 
+	{
+	xerr("BIO_do_connect() failed");
+	char s[256];	
+	safef(s, sizeof s, "SSL error: %s", ERR_reason_error_string(ERR_get_error()));
+	xerr(s);
+	goto cleanup;
+	}
+
+    fd = BIO_get_fd(sbio, NULL);
+    if (fd == -1) 
+	{
+	xerr("unable to get BIO descriptor");
+	goto cleanup;
+	}
+    FD_ZERO(&readfds);
+    FD_ZERO(&writefds);
+    if (BIO_should_read(sbio)) 
+	{
+	FD_SET(fd, &readfds);
+	}
+    else if (BIO_should_write(sbio)) 
+	{
+	FD_SET(fd, &writefds);
+	}
+    else 
+	{  /* BIO_should_io_special() */
+	FD_SET(fd, &readfds);
+	FD_SET(fd, &writefds);
+	}
+    tv.tv_sec = 10;  // timeout
+    tv.tv_usec = 0;
+
+    err = select(fd + 1, &readfds, &writefds, NULL, &tv);
+    if (err < 0) 
+	{
+	xerr("select() error");
+	goto cleanup;
+	}
+
+    if (err == 0) 
+	{
+	char s[256];	
+	safef(s, sizeof s, "connection timeout to %s", params->hostName);
+	xerr(s);
+	goto cleanup;
+	}
+    }
+
+
+/* TODO checking certificates 
+
+if (certFile || certPath)
+    if (!check_cert(ssl, host))
+	return -1;
+
+*/
+
+/* we need to wait on both the user's socket and the BIO SSL socket 
+ * to see if we need to ferry data from one to the other */
+
+
+char sbuf[32768];  // socket buffer sv[1] to user
+char bbuf[32768];  // bio buffer
+int srd = 0;
+int swt = 0;
+int brd = 0;
+int bwt = 0;
+while (1) 
+    {
+
+    // Do NOT move this outside the while loop. 
+    /* Get underlying file descriptor, needed for select call */
+    fd = BIO_get_fd(sbio, NULL);
+    if (fd == -1) 
+	{
+	xerr("BIO doesn't seem to be initialized in https, unable to get descriptor.");
+	goto cleanup;
+	}
+
+
+    FD_ZERO(&readfds);
+    FD_ZERO(&writefds);
+
+    if (brd == 0)
+	FD_SET(fd, &readfds);
+    if (swt < srd)
+	FD_SET(fd, &writefds);
+    if (srd == 0)
+	FD_SET(params->sv[1], &readfds);
+
+    tv.tv_sec = 10;   // timeout
+    tv.tv_usec = 0;
+
+    err = select(max(fd,params->sv[1]) + 1, &readfds, &writefds, NULL, &tv);
+
+    /* Evaluate select() return code */
+    if (err < 0) 
+	{
+	xerr("error during select()");
+	goto cleanup;
+	}
+    else if (err == 0) 
+	{
+	/* Timed out - just quit */
+	xerr("https timeout expired");
+	goto cleanup;
+	}
+
+    else 
+	{
+	if (FD_ISSET(params->sv[1], &readfds))
+	    {
+	    swt = 0;
+	    srd = read(params->sv[1], sbuf, 32768);
+	    if (srd == -1)
+		{
+		if (errno != 104) // udcCache often closes causing "Connection reset by peer"
+		    xerrno("error reading https socket");
+		goto cleanup;
+		}
+	    if (srd == 0) 
+		break;  // user closed socket, we are done
+	    }
+
+	if (FD_ISSET(fd, &writefds))
+	    {
+	    int swtx = BIO_write(sbio, sbuf+swt, srd-swt);
+	    if (swtx <= 0)
+		{
+		if (!BIO_should_write(sbio))
+		    {
+		    ERR_print_errors_fp(stderr);
+		    xerr("Error writing SSL connection");
+		    goto cleanup;
+		    }
+		}
+	    else
+		{
+		swt += swtx;
+		if (swt >= srd)
+		    {
+		    swt = 0;
+		    srd = 0;
+		    }
+		}
+	    }
+
+	if (FD_ISSET(fd, &readfds))
+	    {
+	    bwt = 0;
+	    brd = BIO_read(sbio, bbuf, 32768);
+
+	    if (brd <= 0)
+		{
+		if (BIO_should_read(sbio))
+		    {
+		    brd = 0;
+		    continue;
+		    }
+		else
+		    {
+		    if (brd == 0) break;
+		    ERR_print_errors_fp(stderr);
+		    xerr("Error reading SSL connection");
+		    goto cleanup;
+		    }
+		}
+	    // write the https data received immediately back on socket to user, and it's ok if it blocks.
+	    while(bwt < brd)
+		{
+		int bwtx = write(params->sv[1], bbuf+bwt, brd-bwt);
+		if (bwtx == -1)
+		    {
+		    if ((errno != 104)  // udcCache often closes causing "Connection reset by peer"
+		     && (errno !=  32)) // udcCache often closes causing "Broken pipe"
+			xerrno("error writing https data back to user socket");
+		    goto cleanup;
+		    }
+		bwt += bwtx;
+		}
+	    brd = 0;
+	    bwt = 0;
+	    }
+	}
+    }
+
+cleanup:
+
+BIO_free_all(sbio);
+close(params->sv[1]);  /* we are done with it */
+
+return NULL;
+}
+
+int netConnectHttps(char *hostName, int port)
+/* Return socket for https connection with server or -1 if error. */
+{
+
+fflush(stdin);
+fflush(stdout);
+fflush(stderr);
+
+struct netConnectHttpsParams *params;
+AllocVar(params);
+params->hostName = cloneString(hostName);
+params->port = port;
+
+socketpair(AF_UNIX, SOCK_STREAM, 0, params->sv);
+
+int rc;
+rc = pthread_create(&params->thread, NULL, netConnectHttpsThread, (void *)params);
+if (rc)
+    {
+    errAbort("Unexpected error %d from pthread_create(): %s",rc,strerror(rc));
+    }
+
+/* parent */
+
+return params->sv[0];
+
+}
+
+#else
+
+#include <stdarg.h>
+#include "common.h"
+#include "errabort.h"
+
+int netConnectHttps(char *hostName, int port)
+/* Start https connection with server or die. */
+{
+errAbort("No openssl available in netConnectHttps for %s : %d", hostName, port);
+return -1;   /* will never get to here, make compiler happy */
+}
+
+#endif
diff --git a/lib/i386/placeHolder.c b/lib/i386/placeHolder.c
new file mode 100755
index 0000000..e69de29
diff --git a/lib/i686/placeHolder.c b/lib/i686/placeHolder.c
new file mode 100644
index 0000000..e69de29
diff --git a/lib/intExp.c b/lib/intExp.c
new file mode 100644
index 0000000..67c3d2c
--- /dev/null
+++ b/lib/intExp.c
@@ -0,0 +1,153 @@
+/* Below is the worlds sleaziest little numerical expression
+ * evaluator. Used to do only ints, now does doubles as well. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "kxTok.h"
+
+
+static struct kxTok *tok;
+
+#define nextTok() (tok = tok->next) 
+
+#ifdef DEBUG
+static void nextTok()
+/* Advance to next token. */
+{
+if (tok == NULL)
+    printf("(null)");
+else
+    {
+    printf("'%s' -> ", tok->string);
+    if (tok->next == NULL)
+        printf("(null)\n");
+    else
+        printf("'%s'\n", tok->next->string);
+    }
+tok = tok->next;
+}
+#endif /* DEBUG */
+
+
+static double expression();
+/* Forward declaration of main expression handler. */
+
+static double number()
+/* Return number. */
+{
+double val;
+if (tok == NULL)
+    errAbort("Parse error in numerical expression");
+if (!isdigit(tok->string[0]))
+    errAbort("Expecting number, got %s", tok->string);
+val = atof(tok->string);
+nextTok();
+return val;
+}
+
+static double atom()
+/* Return parenthetical expression or number. */
+{
+double val;
+if (tok->type == kxtOpenParen)
+    {
+    nextTok();
+    val = expression();
+    if (tok->type == kxtCloseParen)
+	{
+        nextTok();
+	return val;
+	}
+    else
+	{
+        errAbort("Unmatched parenthesis");
+	return 0;
+	}
+    }
+else
+    return number();
+}
+
+
+static double uMinus()
+/* Unary minus. */
+{
+double val;
+if (tok->type == kxtSub)
+    {
+    nextTok();
+    val = -atom();
+    return val;
+    }
+else
+    return atom();
+}
+
+static double mulDiv()
+/* Multiplication or division. */
+{
+double val = uMinus();
+for (;;)
+    {
+    if (tok->type == kxtMul)
+	{
+	nextTok();
+	val *= uMinus();
+	}
+    else if (tok->type == kxtDiv)
+	{
+	nextTok();
+	val /= uMinus();
+	}
+    else
+        break;
+    }
+return val;
+}
+
+static double addSub()
+/* Addition or subtraction. */
+{
+double val;
+val = mulDiv();
+for (;;)
+    {
+    if (tok->type == kxtAdd)
+	{
+	nextTok();
+	val += mulDiv();
+	}
+    else if (tok->type == kxtSub)
+	{
+	nextTok();
+	val -= mulDiv();
+	}
+    else
+        break;
+    }
+return val;
+}
+
+static double expression()
+/* Wraps around lowest level of expression. */
+{
+return addSub();
+}
+
+double doubleExp(char *text)
+/* Convert text to double expression and evaluate. */
+{
+double val;
+struct kxTok *tokList = tok = kxTokenize(text, FALSE);
+val = expression();
+slFreeList(&tokList);
+return val;
+}
+
+int intExp(char *text)
+/* Convert text to int expression and evaluate. */
+{
+return round(doubleExp(text));
+}
diff --git a/lib/intValTree.c b/lib/intValTree.c
new file mode 100644
index 0000000..d0868d5
--- /dev/null
+++ b/lib/intValTree.c
@@ -0,0 +1,102 @@
+/* intValTree - a binary tree with integer keys and void values.  This is based on the 
+ * red/black self-balancing binary tree algorithm in the rbTree module. */
+
+#include "common.h"
+#include "localmem.h"
+#include "rbTree.h"
+#include "intValTree.h"
+
+int intValCmp(void *va, void *vb)
+/* Return -1 if a before b,  0 if a and b overlap,
+ * and 1 if a after b. */
+{
+struct intVal *a = va;
+struct intVal *b = vb;
+return a->key - b->key;
+}
+
+struct rbTree *intValTreeNew()
+/* Create a new, empty, tree with integer keys and void values. */
+{
+return rbTreeNew(intValCmp);
+}
+
+struct intVal *intValTreeAdd(struct rbTree *tree, int key, void *val)
+/* Add to binary tree.  Will abort if key is already in tree. */
+{
+struct intVal *iv;
+lmAllocVar(tree->lm, iv);
+iv->key = key;
+iv->val = val;
+if (rbTreeAdd(tree, iv) != NULL)
+    errAbort("Key %d already exists in tree", key);
+return iv;
+}
+
+struct intVal *intValTreeUpdate(struct rbTree *tree, int key, void *val)
+/* Add to binary tree. If key is already in tree just updates it with val. */
+{
+struct intVal *iv = intValTreeLookup(tree, key);
+if (iv != NULL)
+    iv->val = val;
+else
+    iv = intValTreeAdd(tree, key, val);
+return iv;
+}
+
+struct intVal *intValTreeRemove(struct rbTree *tree, int key)
+/* Removes given tree from key. */
+{
+struct intVal fullKey;
+fullKey.key = key;
+return rbTreeRemove(tree, &fullKey);
+}
+
+struct intVal *intValTreeLookup(struct rbTree *tree, int key)
+/* Returns intVal associated with given key, or NULL if none exists. */
+{
+struct intVal fullKey;
+fullKey.key = key;
+return rbTreeFind(tree, &fullKey);
+}
+
+
+void *intValTreeFind(struct rbTree *tree, int key)
+/* Returns value associated with given key, or NULL if none exists. */
+{
+struct intVal fullKey;
+fullKey.key = key;
+struct intVal *iv = rbTreeFind(tree, &fullKey);
+if (iv == NULL)
+    return NULL;
+return iv->val;
+}
+
+void *intValTreeMustFind(struct rbTree *tree, int key)
+/* Return value associated with given key. Aborts if none exists. */
+{
+struct intVal fullKey;
+fullKey.key = key;
+struct intVal *iv = rbTreeFind(tree, &fullKey);
+if (iv == NULL)
+    errAbort("%d is not in tree", key);
+return iv->val;
+}
+
+void doAllKeys(void *item, void *context)
+/* Callback function for tree traversal. */
+{
+int **pPt = context;
+struct intVal *iv = item;
+**pPt = iv->key;
+*pPt += 1;
+}
+
+int *intValTreeKeys(struct rbTree *tree)
+/* Returns array of keys (size is tree->n).  You freeMem this when done. */
+{
+int *results, *pt;
+pt = AllocArray(results, tree->n);
+rbTreeTraverseWithContext(tree, doAllKeys, &pt);
+return results;
+}
diff --git a/lib/internet.c b/lib/internet.c
new file mode 100644
index 0000000..e753510
--- /dev/null
+++ b/lib/internet.c
@@ -0,0 +1,159 @@
+/* internet - some stuff to make it easier to use
+ * internet sockets and the like. */
+#include "common.h"
+#include "internet.h"
+
+
+boolean internetIsDottedQuad(char *s)
+/* Returns TRUE if it looks like s is a dotted quad. */
+{
+int i;
+if (!isdigit(s[0]))
+    return FALSE;
+for (i=0; i<3; ++i)
+    {
+    s = strchr(s, '.');
+    if (s == NULL)
+        return FALSE;
+    s += 1;
+    if (!isdigit(s[0]))
+        return FALSE;
+    }
+return TRUE;
+}
+
+bits32 internetHostIp(char *hostName)
+/* Get IP v4 address (in host byte order) for hostName.
+ * Warn and return 0 if there's a problem. */
+{
+bits32 ret;
+if (internetIsDottedQuad(hostName))
+    {
+    internetDottedQuadToIp(hostName, &ret);
+    }
+else
+    {
+    /* getaddrinfo is thread-safe and widely supported */
+    struct addrinfo hints, *res;
+    struct in_addr addr;
+    int err;
+
+    zeroBytes(&hints, sizeof(hints));
+    hints.ai_family = AF_INET;
+
+    if ((err = getaddrinfo(hostName, NULL, &hints, &res)) != 0) 
+	{
+	warn("getaddrinfo() error on hostName=%s: %s\n", hostName, gai_strerror(err));
+	return 0;
+	}
+
+    addr = ((struct sockaddr_in *)(res->ai_addr))->sin_addr;
+
+    ret = ntohl((uint32_t)addr.s_addr);
+
+    freeaddrinfo(res);
+
+    }
+return ret;
+}
+
+boolean internetFillInAddress(char *hostName, int port, struct sockaddr_in *address)
+/* Fill in address. Return FALSE if can't.  */
+{
+ZeroVar(address);
+address->sin_family = AF_INET;
+address->sin_port = htons(port);
+if (hostName == NULL)
+    address->sin_addr.s_addr = INADDR_ANY;
+else
+    {
+    if ((address->sin_addr.s_addr = htonl(internetHostIp(hostName))) == 0)
+	return FALSE;
+    }
+return TRUE;
+}
+
+boolean internetIpToDottedQuad(bits32 ip, char dottedQuad[17])
+/* Convert IP4 address in host byte order to dotted quad 
+ * notation.  Warn and return FALSE if there's a 
+ * problem. */
+{
+#ifndef __CYGWIN32__
+struct in_addr ia;
+zeroBytes(dottedQuad, 17);
+ZeroVar(&ia);
+ia.s_addr = htonl(ip);
+if (inet_ntop(AF_INET, &ia, dottedQuad, 16) == NULL)
+    {
+    warn("conversion problem on 0x%x in internetIpToDottedQuad: %s", 
+    	ip, strerror(errno));
+    return FALSE;
+    }
+return TRUE;
+#else
+warn("Sorry, internetIpToDottedQuad not supported in Windows.");
+return FALSE;
+#endif
+}
+
+boolean internetDottedQuadToIp(char *dottedQuad, bits32 *retIp)
+/* Convert dotted quad format address to IP4 address in
+ * host byte order.  Warn and return FALSE if there's a 
+ * problem. */
+{
+#ifndef __CYGWIN32__
+struct in_addr ia;
+if (inet_pton(AF_INET, dottedQuad, &ia) < 0)
+    {
+    warn("internetDottedQuadToIp problem on %s: %s", dottedQuad, strerror(errno));
+    return FALSE;
+    }
+*retIp = ntohl(ia.s_addr);
+return TRUE;
+#else
+warn("Sorry, internetDottedQuadToIp not supported in Windows.");
+return FALSE;
+#endif
+}
+
+void internetParseDottedQuad(char *dottedQuad, unsigned char quad[4])
+/* Parse dotted quads into quad */
+{
+char *s = dottedQuad;
+int i;
+if (!internetIsDottedQuad(s))
+    errAbort("%s is not a dotted quad", s);
+for (i=0; i<4; ++i)
+    {
+    quad[i] = atoi(s);
+    s = strchr(s, '.') + 1;
+    }
+}
+
+void internetUnpackIp(bits32 packed, unsigned char unpacked[4])
+/* Convert from 32 bit to 4-byte format with most significant
+ * byte first. */
+{
+int i;
+for (i=3; i>=0; --i)
+    {
+    unpacked[i] = (packed&0xff);
+    packed >>= 8;
+    }
+}
+
+boolean internetIpInSubnet(unsigned char unpackedIp[4], unsigned char subnet[4])
+/* Return true if unpacked IP address is in subnet. */
+{
+int i;
+for (i=0; i<4; ++i)
+    {
+    unsigned char c = subnet[i];
+    if (c == 255)
+        return TRUE;
+    if (c != unpackedIp[i])
+        return FALSE;
+    }
+return TRUE;
+}
+
diff --git a/lib/itsa.c b/lib/itsa.c
new file mode 100644
index 0000000..083ab5e
--- /dev/null
+++ b/lib/itsa.c
@@ -0,0 +1,187 @@
+/* itsa - indexed traversable suffix array.  Used for doing quick genomic searches.
+ * Use itsaMake utility to create one of these files , and the routines here to access it.  
+ * See comment by itsaFileHeader for file format. See src/shortReads/itsaMake/itsa.doc as well 
+ * for an explanation of the data structures, particularly the traverse array. */
+/* This file is copyright 2008 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include <sys/mman.h>
+#include "net.h"
+#include "itsa.h"
+
+/* Hex conversions to assist debugging:
+ * 0=AA 1=AC 2=AG 3=AT 4=CA 5=CC 6=CG 7=CT
+ * 8=GA 9=GC A=GG B=GT C=TA D=TC E=TG F=TT
+ */
+
+/* Table to convert letters to one of the above values. */
+int itsaBaseToVal[256];
+
+void itsaBaseToValInit()
+/* Initialize itsaBaseToVal array */
+{
+/* Fill out itsaBaseToVal array - A is already done. */
+itsaBaseToVal[(int)'C'] = itsaBaseToVal[(int)'c'] = ITSA_C;
+itsaBaseToVal[(int)'G'] = itsaBaseToVal[(int)'g'] = ITSA_G;
+itsaBaseToVal[(int)'T'] = itsaBaseToVal[(int)'t'] = ITSA_T;
+}
+
+int itsaDnaToBinary(char *dna, int size)
+/* Convert dna to binary representation. */
+{
+int i;
+int val = 0;
+for (i=0; i<size; ++i)
+    {
+    val <<= 2;
+    val += itsaBaseToVal[(int)dna[i]];
+    }
+return val;
+}
+
+
+static void *pointerOffset(void *pt, bits64 offset)
+/* A little wrapper around pointer arithmetic in terms of bytes. */
+{
+char *s = pt;
+return s + offset;
+}
+
+struct itsa *itsaRead(char *fileName, boolean memoryMap)
+/* Read in a itsa from a file.  Does this via memory mapping if you like,
+ * which will be faster typically for about 100 reads, and slower for more
+ * than that (_much_ slower for thousands of reads and more). */
+{
+/* Open file (low level), read in header, and check it. */
+int fd = open(fileName, O_RDONLY);
+if (fd < 0)
+    errnoAbort("Can't open %s", fileName);
+struct itsaFileHeader h;
+if (netReadAll(fd, &h, sizeof(h)) < sizeof(h))
+    errnoAbort("Couldn't read header of file %s", fileName);
+if (h.magic != ITSA_MAGIC)
+    errAbort("%s does not seem to be a itsa file.", fileName);
+if (h.majorVersion > ITSA_MAJOR_VERSION)
+    errAbort("%s is a newer, incompatible version of itsa format. "
+             "This program works on version %d and below. "
+	     "%s is version %d.",  fileName, ITSA_MAJOR_VERSION, fileName, h.majorVersion);
+
+struct itsa *itsa;
+verbose(2, "itsa file %s size %lld\n", fileName, h.size);
+
+/* Get a pointer to data in memory, via memory map, or allocation and read. */
+struct itsaFileHeader *header ;
+if (memoryMap)
+    {
+#ifdef MACHTYPE_sparc
+    header = (struct itsaFileHeader *)mmap(NULL, h.size, PROT_READ, MAP_SHARED, fd, 0);
+#else
+    header = mmap(NULL, h.size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0);
+#endif
+    if (header == (void*)(-1))
+	errnoAbort("Couldn't mmap %s, sorry", fileName);
+    }
+else
+    {
+    header = needHugeMem(h.size);
+    if (lseek(fd, 0, SEEK_SET) < 0)
+	errnoAbort("Couldn't seek back to start of itsa file %s.  "
+		   "Splix files must be random access files, not pipes and the like"
+		   , fileName);
+    if (netReadAll(fd, header, h.size) < h.size)
+        errnoAbort("Couldn't read all of itsa file %s.", fileName);
+    }
+
+/* Allocate wrapper structure and fill it in. */
+AllocVar(itsa);
+itsa->header = header;
+itsa->isMapped = memoryMap;
+
+/* Make an array for easy access to chromosome names. */
+int chromCount = header->chromCount;
+char **chromNames = AllocArray(itsa->chromNames, chromCount);
+char *s = pointerOffset(header, sizeof(*header) );
+int i;
+for (i=0; i<chromCount; ++i)
+    {
+    chromNames[i] = s;
+    s += strlen(s)+1;
+    }
+
+/* Keep track of where we are in memmap. */
+bits64 mapOffset = sizeof(*header) + header->chromNamesSize;
+
+/* Point into chromSizes array. */
+bits32 *chromSizes = itsa->chromSizes 
+	= pointerOffset(header, mapOffset);
+mapOffset += sizeof(bits32) * chromCount;
+
+verbose(2, "total dna size %lld in %d chromosomes\n", (long long)header->dnaDiskSize, header->chromCount);
+itsa->allDna = pointerOffset(header, mapOffset);
+mapOffset += header->dnaDiskSize;
+
+/* Calculate chromOffset array. */
+bits32 offset = 0;
+bits32 *chromOffsets = AllocArray(itsa->chromOffsets, chromCount);
+for (i=0; i<chromCount; ++i)
+    {
+    chromOffsets[i] = offset;
+    offset += chromSizes[i] + 1;
+    verbose(2, "itsa contains %s,  %d bases, %d offset\n", 
+    	itsa->chromNames[i], (int)itsa->chromSizes[i], (int)chromOffsets[i]);
+    }
+
+/* Point to the suffix array. */
+itsa->array = pointerOffset(header, mapOffset);
+mapOffset += header->arraySize * sizeof(bits32);
+
+/* Point to the traverse array. */
+itsa->traverse = pointerOffset(header, mapOffset);
+mapOffset += header->arraySize * sizeof(bits32);
+
+/* Point to the 13-mer index. */
+itsa->index13 = pointerOffset(header, mapOffset);
+mapOffset += itsaSlotCount * sizeof(bits32);
+
+/* Make cursors array (faster to calculate than to load, and doesn't depend on data). */
+itsa->cursors13 = pointerOffset(header, mapOffset);
+mapOffset += itsaSlotCount * sizeof(UBYTE);
+
+assert(mapOffset == header->size);	/* Sanity check */
+return itsa;
+}
+
+void itsaFree(struct itsa **pItsa)
+/* Free up resources associated with index. */
+{
+struct itsa *itsa = *pItsa;
+if (itsa != NULL)
+    {
+    freeMem(itsa->chromNames);
+    freeMem(itsa->chromOffsets);
+    if (itsa->isMapped)
+	munmap((void *)itsa->header, itsa->header->size);
+    else
+	freeMem(itsa->header);
+    freez(pItsa);
+    }
+}
+
+int itsaOffsetToChromIx(struct itsa *itsa, bits32 tOffset)
+/* Figure out index of chromosome containing tOffset */
+{
+int i;
+int chromCount = itsa->header->chromCount;
+/* TODO - convert to binary search - at least chrom list is sorted in itsas. */
+for (i=0; i<chromCount; ++i)
+    {
+    int chromStart = itsa->chromOffsets[i];
+    int chromEnd = chromStart + itsa->chromSizes[i];
+    if (tOffset >= chromStart && tOffset < chromEnd)
+        return i;
+    }
+errAbort("tOffset %d out of range\n", tOffset);
+return -1;
+}
+
diff --git a/lib/iupac.c b/lib/iupac.c
new file mode 100644
index 0000000..6dd4402
--- /dev/null
+++ b/lib/iupac.c
@@ -0,0 +1,213 @@
+/* iupac - routines to help cope with IUPAC ambiguity codes in DNA sequence. */
+
+#include "common.h"
+#include "dnautil.h"
+#include "iupac.h"
+
+boolean iupacMatchLower(char iupac, char dna)
+/* See if iupac ambiguity code matches dna character where
+ * both are lower case */
+{
+switch (iupac)
+    {
+    case 'a':
+        return dna == 'a';
+    case 'c':
+        return dna == 'c';
+    case 'g':
+        return dna == 'g';
+    case 't':
+    case 'u':
+        return dna == 't';
+    case 'r':
+        return dna == 'a' || dna == 'g';
+    case 'y':
+        return dna == 'c' || dna == 't';
+    case 's':
+        return dna == 'g' || dna == 'c';
+    case 'w':
+        return dna == 'a' || dna == 't';
+    case 'k':
+        return dna == 'g' || dna == 't';
+    case 'm':
+        return dna == 'a' || dna == 'c';
+    case 'b':
+        return dna == 'c' || dna == 'g' || dna == 't';
+    case 'd':
+        return dna == 'a' || dna == 'g' || dna == 't';
+    case 'h':
+        return dna == 'a' || dna == 'c' || dna == 't';
+    case 'v':
+        return dna == 'a' || dna == 'c' || dna == 'g';
+    case 'n':
+        return TRUE;
+    default:
+        errAbort("Unrecognized IUPAC code '%c'", iupac);
+	return FALSE;   // Not actually used but prevent compiler complaints
+    }
+}
+
+boolean iupacMatch(char iupac, char dna)
+/* See if iupac ambiguity code matches dna character */
+{
+return iupacMatchLower(tolower(iupac), tolower(dna));
+}
+
+boolean isIupacLower(char c)
+/* See if iupac c is a legal (lower case) iupac char */
+{
+switch (c)
+    {
+    case 'a':
+    case 'c':
+    case 'g':
+    case 't':
+    case 'u':
+    case 'r':
+    case 'y':
+    case 's':
+    case 'w':
+    case 'k':
+    case 'm':
+    case 'b':
+    case 'd':
+    case 'h':
+    case 'v':
+    case 'n':
+        return TRUE;
+    default:
+	return FALSE;
+    }
+}
+
+boolean isIupac(char c)
+/* See if iupac c is a legal iupac char */
+{
+return isIupacLower(tolower(c));
+}
+
+void iupacFilter(char *in, char *out)
+/* Filter out non-DNA non-UIPAC ambiguity code characters and change to lower case. */
+{
+char c;
+while ((c = *in++) != 0)
+    {
+    c = tolower(c);
+    if (isIupacLower(c))
+       *out++ = c;
+    }
+*out++ = 0;
+}
+
+boolean anyIupac(char *s)
+/* Return TRUE if there are any IUPAC ambiguity codes in s */
+{
+dnaUtilOpen();
+int c;
+while ((c = *s++) != 0)
+    {
+    switch (c)
+	{
+	case 'r':
+	case 'y':
+	case 's':
+	case 'w':
+	case 'k':
+	case 'm':
+	case 'b':
+	case 'd':
+	case 'h':
+	case 'v':
+	case 'n':
+	    return TRUE;
+	}
+    }
+return FALSE;
+}
+
+char iupacComplementBaseLower(char iupac)
+/* Return IUPAC complement for a single base */
+{
+switch (iupac)
+    {
+    case 'a':
+        return 't';
+    case 'c':
+        return 'g';
+    case 'g':
+        return 'c';
+    case 't':
+    case 'u':
+        return 'a';
+    case 'r':
+	return 'y';
+    case 'y':
+	return 'r';
+    case 's':
+	return 's';
+    case 'w':
+	return 'w';
+    case 'k':
+	return 'm';
+    case 'm':
+	return 'k';
+    case 'b':
+	return 'v';
+    case 'd':
+	return 'h';
+    case 'h':
+	return 'd';
+    case 'v':
+	return 'b';
+    case 'n':
+	return 'n';
+    default:
+        errAbort("Unrecognized IUPAC code '%c'", iupac);
+	return 0;   // Just to keep compiler from complaining, control won't reach here.
+    }
+}
+
+void iupacComplementLower(char *iupac, int iuSize)
+/* Return IUPAC complement many bases. Assumes iupac is lower case. */
+{
+int i;
+for (i=0; i<iuSize; ++i)
+    iupac[i] = iupacComplementBaseLower(iupac[i]);
+}
+
+void iupacReverseComplement(char *iu, int iuSize)
+/* Reverse complement a string containing DNA and IUPAC codes. Result will be always
+ * lower case. */
+{
+toLowerN(iu, iuSize);
+reverseBytes(iu, iuSize);
+iupacComplementLower(iu, iuSize);
+}
+
+boolean iupacMatchStart(char *iupacPrefix, char *dnaString)
+/* Return TRUE if start of DNA is compatible with iupac */
+{
+char iupac;
+while ((iupac = *iupacPrefix++) != 0)
+    {
+    if (!iupacMatch(iupac, *dnaString++))
+        return FALSE;
+    }
+return TRUE;
+}
+
+char *iupacIn(char *needle, char *haystack)
+/* Return first place in haystack (DNA) that matches needle that may contain IUPAC codes. */
+{
+int needleSize = strlen(needle);
+int haySize = strlen(haystack);
+char *endOfHay = haystack + haySize - needleSize;
+char *h;
+for (h = haystack; h<=endOfHay; ++h)
+    {
+    if (iupacMatchStart(needle, h))
+        return h;
+    }
+return NULL;
+}
+
diff --git a/lib/jointalign.c b/lib/jointalign.c
new file mode 100644
index 0000000..c95b83e
--- /dev/null
+++ b/lib/jointalign.c
@@ -0,0 +1,74 @@
+/* jointalign.c - routines for printing a joint alignment in html. 
+ *
+ * This file is copyright 2002 Ryan Weber, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "errabort.h"
+#include "jointalign.h"
+
+
+
+void htmlPrintJointAlignment( char *seq1, char *seq2, int columnNum, 
+        int start, int end, char *strand )
+/* Print sequences 1 and 2 (assumed to be a joint alignment),
+ * formatted for html output. Coordinates are printed based on
+ * the start and end positions and oriented according to the
+ * strand the sequences are on (+ or -). (NO COORDINATES YET)*/
+{
+int i;
+validateSeqs( seq1, seq2 );
+
+/*print the sequences with lines connecting identical residues
+ *in columns of size columnNum*/
+for( i=0; i<strlen(seq1); i += columnNum )
+    htmlPrintJointAlignmentLine(seq1, seq2, i, min(i+columnNum, strlen(seq1)));
+
+/*printf( "<tt><hr><br>%s<br>%s<br></tt>", seq1, seq2 );*/
+
+}
+
+void htmlPrintJointAlignmentLine( char *seq1, char *seq2, int start, int end)
+/* Prints one line of the joint alignment between seq1 and seq2,
+ * from seq[start] to seq[end-1].*/
+{
+
+int i;
+printf("<tt>");
+for( i=start; i<end; i++ )
+    printf("%c",seq1[i]);
+printf("<br>");
+for( i=start; i<end; i++ )
+    {
+    if(ucaseMatch( seq1[i], seq2[i] ))
+        printf("|");
+    else
+        printf(" ");
+    }
+printf("<br>");
+for( i=start; i<end; i++ )
+    printf("%c",seq2[i]);
+printf("</tt>");
+printf("<br><br>");
+   
+
+}
+
+boolean ucaseMatch( char a, char b )
+/* Case insensitive character matching */
+{
+if( toupper( a ) == toupper( b ) )
+    return( TRUE );
+else 
+    return( FALSE );
+}
+
+void validateSeqs( char *seq1, char *seq2 )
+/*Make sure sequences are the same length*/
+{
+if( strlen(seq1) != strlen(seq2) )
+    {
+    printf("%s<br>%s<br>", seq1, seq2 );
+    errAbort("The sequences are not properly aligned (different lengths)<br>\n"); 
+    }
+}
diff --git a/lib/jpegSize.c b/lib/jpegSize.c
new file mode 100644
index 0000000..95b6f8f
--- /dev/null
+++ b/lib/jpegSize.c
@@ -0,0 +1,136 @@
+/* jpegSize - read a jpeg header and figure out dimensions of image.
+ * Adapted by Galt Barber from Matthias Wandel's jhead program */
+#include "common.h"
+#include "jpegSize.h"
+
+
+/* sections containing width and height     */
+#define M_SOF0  0xC0            /* Start Of Frame N                        */
+#define M_SOF1  0xC1            /* N indicates which compression process   */
+#define M_SOF2  0xC2            /* Only SOF0-SOF2 are now in common use    */
+#define M_SOF3  0xC3
+#define M_SOF5  0xC5            /* NB: codes C4 and CC are NOT SOF markers */
+#define M_SOF6  0xC6
+#define M_SOF7  0xC7
+#define M_SOF9  0xC9
+#define M_SOF10 0xCA
+#define M_SOF11 0xCB
+#define M_SOF13 0xCD
+#define M_SOF14 0xCE
+#define M_SOF15 0xCF
+
+#define M_SOI   0xD8            /* Start Of Image (beginning of datastream)*/
+#define M_EOI   0xD9            /* End Of Image (end of datastream)        */
+#define M_SOS   0xDA            /* Start Of Scan (begins compressed data)  */
+#define M_JFIF  0xE0            /* Jfif marker                             */
+#define M_EXIF  0xE1            /* Exif marker                             */
+
+#define MAX_SECTIONS 40
+
+typedef unsigned char uchar;
+
+void jpegSize(char *fileName, int *width, int *height)
+/* Read image width and height.
+ * Parse marker stream until SOS or EOI; */
+{
+FILE * infile = mustOpen(fileName, "r"); 
+int sectionsRead = 0;
+boolean done = FALSE;
+boolean foundJFIF = FALSE;
+/* Scan the JPEG headers. */
+if (fgetc(infile) != 0xff || fgetc(infile) != M_SOI)
+    errAbort("error reading jpg header: %s",fileName);
+while(!done)
+    {
+    int itemlen;
+    int marker = 0;
+    int ll,lh, got;
+    int a=0;
+    uchar * data;
+
+    if (sectionsRead >= MAX_SECTIONS)
+	errAbort("Too many sections in jpg file: %s",fileName);
+
+    for (a=0;a<7;a++)
+	{
+	marker = fgetc(infile);
+	if (marker != 0xff) 
+	    break;
+	if (a >= 6)
+	    errAbort("too many padding bytes: %s",fileName);
+	}
+
+    /* 0xff is legal padding, but if we get that many, something's wrong. */
+    if (marker == 0xff)
+	errAbort("too many padding bytes: %s",fileName);
+
+    /* Read the length of the section. */
+    lh = fgetc(infile);
+    ll = fgetc(infile);
+
+    itemlen = (lh << 8) | ll;
+
+    if (itemlen < 2)
+	errAbort("invalid jpeg marker: %s",fileName);
+
+    data = (uchar *)needMem(itemlen);
+    if (data == NULL)
+	errAbort("Could not allocate %d bytes memory", itemlen);
+
+    /* Store first two pre-read bytes. */
+    data[0] = (uchar)lh;
+    data[1] = (uchar)ll;
+
+    got = fread(data+2, 1, itemlen-2, infile); /* Read the whole section. */
+    if (got != itemlen-2)
+	errAbort("Premature end of file?: %s",fileName);
+    
+    ++sectionsRead;
+
+    switch(marker)
+	{
+	case M_SOS:   /* stop before hitting compressed data */
+	    done = TRUE;
+	    break;
+	case M_EOI:   /* in case it's a tables-only JPEG stream */
+	    errAbort("No image in jpeg!: %s",fileName);
+	case M_JFIF:
+	    /* Regular jpegs always have this tag, 
+	       exif images have the exif marker instead or in addition 
+	       - could add check to make sure this is present
+	    */
+	    foundJFIF = TRUE;
+	    break;
+
+	case M_SOF0:
+	case M_SOF1:
+	case M_SOF2:
+	case M_SOF3:
+	case M_SOF5:
+	case M_SOF6:
+	case M_SOF7:
+	case M_SOF9:
+	case M_SOF10:
+	case M_SOF11:
+	case M_SOF13:
+	case M_SOF14:	    
+	case M_SOF15:
+	    *height = data[3]*256+data[4];
+	    *width  = data[5]*256+data[6];
+	    done = TRUE;
+	    break;
+	default:
+	    /* Skip any other sections. */
+	    break;
+	}
+	
+    freez(&data);
+    
+    }
+fclose(infile);
+if (!foundJFIF)
+    errAbort("JFIF marker not found jpeg: %s",fileName);
+return;
+}
+
+
diff --git a/lib/keys.c b/lib/keys.c
new file mode 100644
index 0000000..a9e14a1
--- /dev/null
+++ b/lib/keys.c
@@ -0,0 +1,558 @@
+/* keys.c - Stuff to manage a little key/value pair table and
+ * evaluate expressions on it. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "keys.h"
+#include "kxTok.h"
+
+
+struct kvt
+/* Key/value table. */
+    {
+    int used;             /* Number of keys used in table. */
+    int alloced;          /* Number allocated in table. */
+    struct keyVal *table; /* The table itself. */
+    };
+
+struct kvt *newKvt(int size)
+/* Get a new key value table. */
+{
+struct kvt *kvt;
+AllocVar(kvt);
+kvt->alloced = size;
+kvt->table = needMem(size * sizeof(kvt->table[0]));
+return kvt;
+}
+
+
+void freeKvt(struct kvt **pKvt)
+/* Free up key value table. */
+{
+struct kvt *kvt;
+if ((kvt = *pKvt) != NULL)
+    {
+    freeMem(kvt->table);
+    freez(pKvt);
+    }
+}
+
+void kvtClear(struct kvt *kvt)
+/* Clear the keys table. */
+{
+kvt->used = 0;
+}
+
+struct keyVal *kvtAdd(struct kvt *kvt, char *key, char *val)
+/* Add in new key. */
+{
+struct keyVal *kv;
+if (kvt->used == kvt->alloced)
+    errAbort("Too many keys in keyVal(%s %s)", key, val);
+kv = &kvt->table[kvt->used++];
+kv->key = key;
+kv->val = val;
+return kv;
+}
+
+void kvtParseAdd(struct kvt *kvt, char *text)
+/* Add in keys from text.  Text is in format:
+ *     key val
+ * for each line of text. Text gets many of it's
+ * space characters and newlines replaced by 0's
+ * and should persist until call to keysClear(). */
+{
+char *lines[256];
+int lineCount;
+int i;
+char *k, *v;
+
+lineCount = chopString(text, "\n\r", lines, ArraySize(lines));
+for (i=0; i<lineCount; ++i)
+    {
+    k = lines[i];
+    if ((v = strchr(k, ' ')) != NULL)
+        {
+        *v++ = 0;
+        kvtAdd(kvt, k, v);
+        }
+    }
+}
+
+struct keyVal* kvtGet(struct kvt *kvt, char *key)
+/* get the keyVal for the specified key, of NULL if not found. */
+{
+int i;
+struct keyVal *keyTable = kvt->table;
+int keysUsed = kvt->used;
+
+for (i=0; i<keysUsed; ++i)
+    {
+    if (sameString(key, keyTable[i].key))
+        return &keyTable[i];
+    }
+return NULL;
+}
+
+char *kvtLookup(struct kvt *kvt, char *key)
+/* Search table for key.  Return key value, or NULL if
+ * key not found. */
+{
+struct keyVal *keyVal = kvtGet(kvt, key);
+if (keyVal == NULL)
+    return NULL;
+else
+    return keyVal->val;
+}
+
+void kvtWriteAll(struct kvt *kvt, FILE *f, struct slName *hideList)
+/* Write all keys to file except the ones in hideList */
+{
+int i;
+static char lf = '\n';
+struct keyVal *kv = kvt->table;
+int keyCount = kvt->used;
+
+for (i=0; i<keyCount; ++i)
+    {
+    char *key = kv->key;
+    if (kv->val != NULL && !slNameInList(hideList, key))
+        fprintf(f, "%s %s\n", key, kv->val);
+    ++kv;
+    }
+mustWrite(f, &lf, 1);   /* Instead of fputc for error checking. */
+}
+
+
+/* Expression evaluator - evaluates a parsed tree. */
+enum keyExpType
+    {
+    kxMatch,
+    kxWildMatch,
+    kxGT,      /* Greater Than */
+    kxGE,      /* Greater Than or Equal */
+    kxLT,      /* Less Than */
+    kxLE,      /* Less Than or Equal */
+    kxAnd,
+    kxOr,
+    kxNot,
+    kxXor,
+    };
+
+struct exp
+    {
+    void *left;
+    void *right;
+    enum keyExpType type;
+    };
+
+static void getIntVals(struct kvt *kvt, struct exp *exp, int *retLeft, int *retRight)
+/* Look up value for key on left hand side of expression and
+ * literal string from right hand side.  Convert both to ints. */
+{
+char *rightString = exp->right;
+char *leftKey = exp->left;
+char *leftString = kvtLookup(kvt, leftKey);
+
+if (leftString == NULL)
+    *retLeft = 0;
+else
+    *retLeft = atoi(leftString);
+if (rightString == NULL)
+    *retRight = 0;
+else
+    *retRight = atoi(rightString);
+}
+
+#if 0 /* unused */
+static void dumpExp(struct kvt *kvt, struct exp *exp)
+/* Print out expression. */
+{
+switch (exp->type)
+    {
+    case kxMatch:
+        {
+        char *key = exp->left;
+        char *matcher = exp->right;
+        char *val = kvtLookup(kvt, key);
+	printf("%s(%s) match %s\n", key, val, matcher);
+	break;
+        }
+    case kxWildMatch:
+        {
+        char *key = exp->left;
+        char *matcher = exp->right;
+        char *val = kvtLookup(kvt, key);
+	printf("%s(%s) wildMatch %s\n", key, val, matcher);
+	break;
+        }
+    case kxGT:
+        {
+        int left, right;
+        getIntVals(kvt, exp, &left, &right);
+	printf("%d > %d\n", left, right);
+	break;
+        }
+    case kxGE:
+        {
+        int left, right;
+        getIntVals(kvt, exp, &left, &right);
+	printf("%d >= %d\n", left, right);
+	break;
+        }
+    case kxLT:
+        {
+        int left, right;
+        getIntVals(kvt, exp, &left, &right);
+	printf("%d < %d\n", left, right);
+	break;
+        }
+    case kxLE:
+        {
+        int left, right;
+        getIntVals(kvt, exp, &left, &right);
+	printf("%d <= %d\n", left, right);
+	break;
+        }
+    
+    case kxNot:
+        {
+	printf("!\n");
+	break;
+        }
+    case kxAnd:
+        {
+	printf("&\n");
+	break;
+        }
+    case kxOr:
+        {
+	printf("|\n");
+	break;
+        }
+    case kxXor:
+        {
+	printf("^\n");
+	break;
+        }
+    }
+}
+#endif
+
+static boolean rkeyEval(struct kvt *kvt, struct exp *exp)
+/* Recursively evaluate expression. */
+{
+if (exp == NULL)
+    return TRUE;
+switch (exp->type)
+    {
+    case kxMatch:
+        {
+        char *key = exp->left;
+        char *matcher = exp->right;
+        char *val = kvtLookup(kvt, key);
+        if (val == NULL)
+            return sameWord(matcher, "null");
+        else
+            return sameWord(matcher, val);
+        }
+    case kxWildMatch:
+        {
+        char *key = exp->left;
+        char *matcher = exp->right;
+        char *val = kvtLookup(kvt, key);
+        if (val == NULL)
+            return sameString(matcher, "*");
+        else
+            return wildMatch(matcher, val);
+        }
+    case kxGT:
+        {
+        int left, right;
+        getIntVals(kvt, exp, &left, &right);
+        return left > right;
+        }
+    case kxGE:
+        {
+        int left, right;
+        getIntVals(kvt, exp, &left, &right);
+        return left >= right;
+        }
+    case kxLT:
+        {
+        int left, right;
+        getIntVals(kvt, exp, &left, &right);
+        return left < right;
+        }
+    case kxLE:
+        {
+        int left, right;
+        getIntVals(kvt, exp, &left, &right);
+        return left <= right;
+        }
+    
+    case kxNot:
+        {
+        return !rkeyEval(kvt, exp->right);
+        }
+    case kxAnd:
+        {
+        return rkeyEval(kvt, exp->left) && rkeyEval(kvt, exp->right);
+        }
+    case kxOr:
+        {
+        return rkeyEval(kvt, exp->left) || rkeyEval(kvt, exp->right);
+        }
+    case kxXor:
+        {
+        return rkeyEval(kvt, exp->left) ^ rkeyEval(kvt, exp->right);
+        }
+    default:
+        {
+	errAbort("unknown expression type %d", exp->type);
+	return 0;
+	}
+    }
+}
+
+boolean keyExpEval(struct keyExp *keyExp, struct kvt *kvt)
+/* Evaluate key expression. */
+{
+return rkeyEval(kvt, keyExp->rootExp);
+}
+
+/***** A little recursive descent parser. *****/
+
+static struct kxTok *token;      /* Next token for parser. */
+
+static void advanceToken()
+/* Move to next token. */
+{
+token = token->next;
+}
+
+static struct exp *nextExp();       /* Get next expression. */
+
+static struct exp *parseRelation()
+/* Parse key=wildcard. */
+{
+struct kxTok *key, *match;
+
+if (token == NULL)
+    return NULL;
+if (token->type != kxtString)
+    errAbort("Expecting key got %s", token->string);
+key = token;
+advanceToken();
+if (token->type == kxtEquals)
+    {
+    advanceToken();
+    if (token->type == kxtString || token->type == kxtWildString)
+        {
+        struct exp *exp;
+        match = token;
+        advanceToken();
+        AllocVar(exp);
+        exp->left = key->string;
+        exp->right = match->string;
+        exp->type = (match->type == kxtString ? kxMatch : kxWildMatch);
+        return exp;
+        }
+    else
+        {
+        errAbort("Expecting string to match in key=match expression,\ngot %s", token->string);
+        }
+    }
+else if (token->type == kxtGT || token->type == kxtGE || token->type == kxtLT || token->type == kxtLE)
+    {
+    enum kxTokType relation = token->type;
+    advanceToken();
+    if (isdigit(token->string[0]))
+        {
+        struct exp *exp;
+        match = token;
+        advanceToken();
+        AllocVar(exp);
+        exp->left = key->string;
+        exp->right = match->string;
+        if (relation == kxtGT) exp->type = kxGT;
+        else if (relation == kxtGE) exp->type = kxGE;
+        else if (relation == kxtLT) exp->type = kxLT;
+        else if (relation == kxtLE) exp->type = kxLE;
+        return exp;
+        }
+    else
+        {
+        errAbort("Expecting number got %s", token->string);
+        }
+    }
+else
+    errAbort("Expecting = got %s", token->string);
+return NULL;
+}
+
+static struct exp *parseParenthesized()
+/* Parse parenthesized expressions. */
+{
+struct exp *exp;
+if (token == NULL)
+    return NULL;
+if (token->type == kxtOpenParen)
+    {
+    advanceToken();
+    exp = nextExp();
+    if (token->type != kxtCloseParen)
+        errAbort("Unmatched parenthesis");
+    advanceToken();
+    return exp;
+    }
+else
+    {
+    return parseRelation();
+    }            
+}
+
+static struct exp *parseNot()
+/* Parse not */
+{
+struct exp *exp;
+struct exp *right;
+
+if (token == NULL)
+    return NULL;
+if (token->type == kxtNot)
+    {
+    advanceToken();
+    right = nextExp();
+    AllocVar(exp);
+    exp->right = right;
+    exp->type = kxNot;
+    return exp;
+    }
+else
+    return parseParenthesized();
+}
+
+static struct exp *parseAndExp()
+/* Parse and level expressions. */
+{
+struct exp *left;
+struct exp *right, *exp;
+struct kxTok *tok;
+enum kxTokType type;
+
+if ((left = parseNot()) == NULL)
+    return NULL;
+if ((tok = token) == NULL)
+    return left;
+type = token->type;
+if (type == kxtAnd)
+    {
+    advanceToken();
+    right = nextExp();
+    if (right == NULL)
+        errAbort("Expecting expression on the other side of %s", tok->string);
+    AllocVar(exp);
+    exp->left = left;
+    exp->right = right;
+    exp->type = kxAnd;
+    return exp;
+    }
+else
+    return left;    
+}
+
+static struct exp *parseOrExp()
+/* Parse lowest level of precedent expressions - or and xor. */
+{
+struct exp *left;
+struct exp *right, *exp;
+struct kxTok *tok;
+enum kxTokType type;
+
+if ((left = parseAndExp()) == NULL)
+    return NULL;
+if ((tok = token) == NULL)
+    return left;
+type = token->type;
+if (type == kxtOr || type == kxtXor)
+    {
+    advanceToken();
+    right = nextExp();
+    if (right == NULL)
+        errAbort("Expecting expression on the other side of %s", tok->string);
+    AllocVar(exp);
+    exp->left = left;
+    exp->right = right;
+    if (type == kxtOr)
+        exp->type = kxOr;
+    else
+        exp->type = kxXor;
+    return exp;
+    }
+else
+    return left;    
+}
+
+static struct exp *nextExp()
+/* Get another expression. */
+{
+return parseOrExp();
+}
+
+static struct exp *parseExp(struct kxTok *tokList)
+/* Convert key expression from token stream to parse tree. */
+{
+struct exp *exp;
+token = tokList;
+exp =  nextExp();
+if (token->type != kxtEnd)
+    {
+    errAbort("Extra tokens past end of expression.  Missing &?");
+    }
+return exp;
+}
+
+struct keyExp *keyExpParse(char *text)
+/* Parse text into key expression.  Squawk and die if it
+ * fails. */
+{
+struct keyExp *ke;
+struct kxTok *tok;
+AllocVar(ke);
+ke->tokenList = tok = kxTokenize(text, TRUE);
+ke->rootExp = parseExp(tok);
+
+return ke;
+}
+
+
+
+boolean keyTextScan(char *text, char *key, char *valBuf, int valBufSize)
+/* Get value of key. Return FALSE if key doesn't exist. */
+{
+int keySize = strlen(key);
+char *s, *nl;
+boolean ok = FALSE;
+
+for (s = text; !isspace(s[0]); s = nl+1)
+    {
+    nl = strchr(s, '\n');
+    assert(nl != NULL);
+    if (s[keySize] == ' ' && memcmp(s, key, keySize) == 0)
+        {
+        char *val = s + keySize + 1;
+        int valSize = nl - val;
+        if (valSize >= valBufSize)
+            valSize = valBufSize-1;
+        memcpy(valBuf, val, valSize);
+        valBuf[valSize] = 0;
+        ok = TRUE;
+        break;
+        }
+    }
+return ok;
+}
+
diff --git a/lib/knetUdc.c b/lib/knetUdc.c
new file mode 100644
index 0000000..fdba740
--- /dev/null
+++ b/lib/knetUdc.c
@@ -0,0 +1,86 @@
+/* knetUdc -- install udc i/o functions in knetfile interface in samtools. */
+/* As of 2/23/10, the KNETFILE_HOOKS extension is a UCSC-local modification of samtools. */
+
+#if ((defined USE_BAM || defined USE_TABIX) && defined KNETFILE_HOOKS)
+
+#include "common.h"
+#include "udc.h"
+#include "knetUdc.h"
+#include "knetfile.h"
+
+
+struct knetFile_s {
+    struct udcFile *udcf;
+}; // typedef'd to knetFile in knetfile.h
+
+static char *udcCacheDir = NULL;
+
+static knetFile *kuOpen(const char *filename, const char *mode)
+/* Open the given filename with mode which must be "r". */
+{
+if (!sameOk((char *)mode, "r"))
+    errAbort("mode passed to kuOpen must be 'r' not '%s'", mode);
+struct udcFile *udcf = udcFileMayOpen((char *)filename, udcCacheDir);
+if (udcf == NULL)
+    return NULL;
+knetFile *kf = NULL;
+AllocVar(kf);
+kf->udcf = udcf;
+verbose(2, "kuOpen: returning %lu\n", (unsigned long)(kf->udcf));
+return kf;
+}
+
+static knetFile *kuDopen(int fd, const char *mode)
+/* Open from a file descriptor -- not necessary for our use of samtools. */
+{
+errAbort("kuDopen not implemented");
+return NULL;
+}
+
+static off_t kuRead(knetFile *fp, void *buf, off_t len)
+/* Read len bytes into buf, return amount actually read. */
+{
+verbose(2, "udcRead(%lu, buf, %lld)\n", (unsigned long)(fp->udcf), (long long)len);
+return (off_t)udcRead(fp->udcf, buf, (int)len);
+}
+
+static off_t kuSeek(knetFile *fp, int64_t off, int whence)
+/* Seek to off according to whence (but don't waste time with samtools' SEEK_END to
+ * check empty record at end of file.  Don't be fooled by the off_t return type --
+ * it's 0 for OK, non-0 for fail. */
+{
+bits64 offset;
+if (whence == SEEK_SET)
+    offset = off;
+else if (whence == SEEK_CUR)
+    offset = off+ udcTell(fp->udcf);
+else
+    return -1;
+verbose(2, "udcSeek(%lu, %lld)\n", (unsigned long)(fp->udcf), offset);
+udcSeek(fp->udcf, offset);
+return 0;
+}
+
+static off_t kuTell(knetFile *fp)
+/* Tell current offset in file. */
+{
+verbose(2, "udcTell(%lu)\n", (unsigned long)(fp->udcf));
+return udcTell(fp->udcf);
+}
+
+static int kuClose(knetFile *fp)
+/* Close and free fp->udcf. */
+{
+verbose(2, "udcClose(%lu)\n", (unsigned long)(fp->udcf));
+udcFileClose(&(fp->udcf));
+return 0;
+}
+
+void knetUdcInstall()
+/* install udc i/o functions in knetfile interface in Heng Li's samtools lib. */
+{
+// maybe init udcCacheDir from hg.conf?
+knet_init_alt(kuOpen, kuDopen, kuRead, kuSeek, kuTell, kuClose);
+}
+
+#endif//def (USE_BAM || USE_TABIX) && KNETFILE_HOOKS
diff --git a/lib/kxTok.c b/lib/kxTok.c
new file mode 100644
index 0000000..a9801e0
--- /dev/null
+++ b/lib/kxTok.c
@@ -0,0 +1,239 @@
+/* kxTok - quick little tokenizer for stuff first
+ * loaded into memory.  Originally developed for
+ * "Key eXpression" evaluator. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "kxTok.h"
+
+
+boolean includeQuotes = FALSE;
+
+static struct kxTok *kxTokNew(enum kxTokType type, char *string, int stringSize,
+	boolean spaceBefore)
+/* Allocate and initialize a new token. */
+{
+struct kxTok *tok;
+int totalSize = stringSize + sizeof(*tok);
+tok = needMem(totalSize);
+tok->type = type;
+tok->spaceBefore = spaceBefore;
+memcpy(tok->string, string, stringSize);
+return tok;
+}
+
+struct kxTok *kxTokenizeFancy(char *text, boolean wildAst,
+			      boolean wildPercent, boolean includeHyphen)
+/* Convert text to stream of tokens. If 'wildAst' is
+ * TRUE then '*' character will be treated as wildcard
+ * rather than multiplication sign.  
+ * If wildPercent is TRUE then the '%' character will be treated as a 
+ * wildcard (as in SQL) rather than a modulo (kxtMod) or percent sign.
+ * If includeHyphen is TRUE then a '-' character in the middle of a String 
+ * token will be treated as a hyphen (part of the String token) instead of 
+ * a new kxtSub token. */
+{
+struct kxTok *tokList = NULL, *tok;
+char c, *s, *start = NULL, *end = NULL;
+enum kxTokType type = 0;
+boolean spaceBefore = FALSE;
+
+s = text;
+for (;;)
+    {
+    if ((c = *s) == 0)
+        break;
+    start = s++;
+    if (isspace(c))
+        {
+	spaceBefore = TRUE;
+        continue;
+        }
+    else if (isalnum(c) || c == '?' || (wildAst && c == '*') ||
+	     (wildPercent && c == '%'))
+        {
+        if (c == '?')
+            type = kxtWildString;
+	else if (wildAst && c == '*')
+            type = kxtWildString;
+	else if (wildPercent && c == '%')
+            type = kxtWildString;
+        else
+            type = kxtString;
+        for (;;)
+            {
+            c = *s;
+            if (isalnum(c) || c == ':' || c == '_' || c == '.' ||
+		(includeHyphen && c == '-'))
+                ++s;
+            else if (c == '?' || (wildAst && c == '*') ||
+		     (wildPercent && c == '%'))
+                {
+                type = kxtWildString;
+                ++s;
+                }
+            else
+                break;
+            }
+        end = s;
+        }
+    else if (c == '"')
+        {
+        type = kxtString;
+        if (! includeQuotes)
+	    start = s;
+        for (;;)
+            {
+            c = *s++;
+            if (c == '"')
+                break;
+            if (c == '*' || c == '?' || (wildPercent && c == '%'))
+                type = kxtWildString;
+            }
+	if (! includeQuotes)
+	    end = s-1;
+	else
+	    end = s;
+        }
+    else if (c == '\'')
+        {
+        type = kxtString;
+        if (! includeQuotes)
+	    start = s;
+        for (;;)
+            {
+            c = *s++;
+            if (c == '\'')
+                break;
+            if (c == '*' || c == '?' || (wildPercent && c == '%'))
+                type = kxtWildString;
+            }
+	if (! includeQuotes)
+	    end = s-1;
+	else
+	    end = s;
+        } 
+    else if (c == '=')
+        {
+        type = kxtEquals;
+        end = s;
+        }
+    else if (c == '&')
+        {
+        type = kxtAnd;
+        end = s;
+        }
+    else if (c == '|')
+        {
+        type = kxtOr;
+        end = s;
+        }
+    else if (c == '^')
+        {
+        type = kxtXor;
+        end = s;
+        }
+    else if (c == '+')
+        {
+	type = kxtAdd;
+	end = s;
+	}
+    else if (c == '-')
+        {
+	type = kxtSub;
+	end = s;
+	}
+    else if (c == '*')
+        {
+	type = kxtMul;
+	end = s;
+	}
+    else if (c == '/')
+        {
+	type = kxtDiv;
+	end = s;
+	}
+    else if (c == '(')
+        {
+        type = kxtOpenParen;
+        end = s;
+        }
+    else if (c == ')')
+        {
+        type = kxtCloseParen;
+        end = s;
+        }
+    else if (c == '!')
+        {
+        type = kxtNot;
+        end = s;
+        }
+    else if (c == '>')
+        {
+        if (*s == '=')
+            {
+            ++s;
+            type = kxtGE;
+            }
+        else
+            type = kxtGT;
+        end = s;
+        }
+    else if (c == '<')
+        {
+        if (*s == '=')
+            {
+            ++s;
+            type = kxtLE;
+            }
+        else
+            type = kxtLT;
+        end = s;
+        }
+    else if (c == '.')
+        {
+        type = kxtDot;
+        end = s;
+	}
+    else if (c == '%')
+        {
+        type = kxtMod;
+        end = s;
+	}
+    else if (ispunct(c))
+        {
+        type = kxtPunct;
+        end = s;
+	}
+    else
+        {
+        errAbort("Unrecognized character %c", c);
+        }
+    tok = kxTokNew(type, start, end-start, spaceBefore);
+    slAddHead(&tokList, tok);
+    spaceBefore = FALSE;
+    }
+tok = kxTokNew(kxtEnd, "end", 3, spaceBefore);
+slAddHead(&tokList, tok);
+slReverse(&tokList);
+return tokList;
+}
+
+
+struct kxTok *kxTokenize(char *text, boolean wildAst)
+/* Convert text to stream of tokens. If 'wildAst' is
+ * TRUE then '*' character will be treated as wildcard
+ * rather than multiplication sign. */
+{
+return kxTokenizeFancy(text, wildAst, FALSE, FALSE);
+}
+
+void kxTokIncludeQuotes(boolean val)
+/* Pass in TRUE if kxTok should include quote characters in string tokens. */
+{
+includeQuotes = val;
+}
+
+
diff --git a/lib/lineFileOnBigBed.c b/lib/lineFileOnBigBed.c
new file mode 100644
index 0000000..eec1035
--- /dev/null
+++ b/lib/lineFileOnBigBed.c
@@ -0,0 +1,111 @@
+/* lineFileOnBigBed - set up lineFile support on a BigBed
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "linefile.h"
+#include "localmem.h"
+#include "bigBed.h"
+
+struct lfBigBedData
+/* data used during callbacks */
+    {	
+    struct bbiFile *bbiHandle;                            // BigBed handle
+    struct bbiChromInfo *bbiChrom, *bbiChromList;         // BigBed chrom info
+    struct lm *bbiLm;                                     // BigBed local memory
+    struct bigBedInterval *bbiInterval, *bbiIntervalList; // BigBed intervals
+    };
+
+void checkBigBedSupport(struct lineFile *lf, char *where)
+/* abort if not supported by bigBed */
+{
+if (sameString(where,"lineFileSeek"))
+    lineFileAbort(lf, "%s: not supported for lineFile on BigBed.", where);
+}
+
+boolean lineFileNextBigBed(struct lineFile *lf, char **retStart, int *retSize)
+/* skip to the next line */
+{
+struct lfBigBedData *lfBigBedData = lf->dataForCallBack;
+int lineSize = 0;
+if (!lfBigBedData->bbiChrom)
+    return FALSE;
+if (!lfBigBedData->bbiInterval)
+    return FALSE;
+lineSize = 1024; // some extra room
+lineSize += strlen(lfBigBedData->bbiChrom->name);
+if (lfBigBedData->bbiInterval->rest)
+    lineSize += strlen(lfBigBedData->bbiInterval->rest);
+
+if (lineSize > lf->bufSize)
+    lineFileExpandBuf(lf, lineSize * 2);
+safef(lf->buf, lf->bufSize, "%s\t%u\t%u", lfBigBedData->bbiChrom->name, lfBigBedData->bbiInterval->start, lfBigBedData->bbiInterval->end);
+if (lfBigBedData->bbiInterval->rest)
+    {
+    safecat(lf->buf, lf->bufSize, "\t");
+    safecat(lf->buf, lf->bufSize, lfBigBedData->bbiInterval->rest);
+    }
+lf->bufOffsetInFile = -1;
+lf->bytesInBuf = strlen(lf->buf);
+lf->lineIx++;
+lf->lineStart = 0;
+lf->lineEnd = lineSize;
+*retStart = lf->buf;
+if (retSize != NULL)
+    *retSize = lineSize;
+
+lfBigBedData->bbiInterval = lfBigBedData->bbiInterval->next;
+if (!lfBigBedData->bbiInterval)
+    {
+    lmCleanup(&lfBigBedData->bbiLm);
+    lfBigBedData->bbiLm = lmInit(0);
+    lfBigBedData->bbiChrom = lfBigBedData->bbiChrom->next;
+    if(lfBigBedData->bbiChrom)
+	lfBigBedData->bbiIntervalList = bigBedIntervalQuery(
+	    lfBigBedData->bbiHandle, lfBigBedData->bbiChrom->name, 0, lfBigBedData->bbiChrom->size, 0, lfBigBedData->bbiLm);
+    }
+
+return TRUE;
+}
+
+void lineFileCloseBigBed(struct lineFile *lf)
+/* release bigBed resources */
+{
+struct lfBigBedData *lfBigBedData = lf->dataForCallBack;
+lmCleanup(&lfBigBedData->bbiLm);
+bbiChromInfoFreeList(&lfBigBedData->bbiChromList);
+bbiFileClose(&lfBigBedData->bbiHandle);
+freez(&lf->dataForCallBack);
+}
+
+
+struct lineFile *lineFileOnBigBed(char *bigBedFileName)
+/* Wrap a line file object around a BigBed. */
+{
+struct lineFile *lf;
+AllocVar(lf);
+lf->fileName = cloneString(bigBedFileName);
+struct lfBigBedData *lfBigBedData;
+AllocVar(lfBigBedData);
+lf->dataForCallBack = lfBigBedData;
+lfBigBedData->bbiHandle = bigBedFileOpen(lf->fileName);
+lfBigBedData->bbiChromList = bbiChromList(lfBigBedData->bbiHandle);
+lfBigBedData->bbiChrom = lfBigBedData->bbiChromList;
+lfBigBedData->bbiLm = lmInit(0);
+if (lfBigBedData->bbiChrom)
+    {
+    lfBigBedData->bbiIntervalList = bigBedIntervalQuery(
+	lfBigBedData->bbiHandle, lfBigBedData->bbiChrom->name, 0, lfBigBedData->bbiChrom->size, 0, lfBigBedData->bbiLm);
+    lfBigBedData->bbiInterval = lfBigBedData->bbiIntervalList;
+    }
+lf->checkSupport = checkBigBedSupport;
+lf->nextCallBack = lineFileNextBigBed;
+lf->closeCallBack = lineFileCloseBigBed;
+lf->fd = -1;
+lf->lineIx = 0;
+lf->bufSize = 64 * 1024;
+lf->buf = needMem(lf->bufSize);
+return lf;
+}
+
diff --git a/lib/linefile.c b/lib/linefile.c
new file mode 100644
index 0000000..91720c8
--- /dev/null
+++ b/lib/linefile.c
@@ -0,0 +1,1396 @@
+/* lineFile - stuff to rapidly read text files and parse them into
+ * lines.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "hash.h"
+#include <fcntl.h>
+#include <signal.h>
+#include "dystring.h"
+#include "errabort.h"
+#include "linefile.h"
+#include "pipeline.h"
+#include "localmem.h"
+
+char *getFileNameFromHdrSig(char *m)
+/* Check if header has signature of supported compression stream,
+   and return a phoney filename for it, or NULL if no sig found. */
+{
+char buf[20];
+char *ext=NULL;
+if (startsWith("\x1f\x8b",m)) ext = "gz";
+else if (startsWith("\x1f\x9d\x90",m)) ext = "Z";
+else if (startsWith("BZ",m)) ext = "bz2";
+else if (startsWith("PK\x03\x04",m)) ext = "zip";
+if (ext==NULL)
+    return NULL;
+safef(buf, sizeof(buf), "somefile.%s", ext);
+return cloneString(buf);
+}
+
+static char **getDecompressor(char *fileName)
+/* if a file is compressed, return the command to decompress the
+ * approriate format, otherwise return NULL */
+{
+static char *GZ_READ[] = {"gzip", "-dc", NULL};
+static char *Z_READ[] = {"gzip", "-dc", NULL};
+static char *BZ2_READ[] = {"bzip2", "-dc", NULL};
+static char *ZIP_READ[] = {"gzip", "-dc", NULL};
+
+if (endsWith(fileName, ".gz"))
+    return GZ_READ;
+else if (endsWith(fileName, ".Z"))
+    return Z_READ;
+else if (endsWith(fileName, ".bz2"))
+    return BZ2_READ;
+else if (endsWith(fileName, ".zip"))
+    return ZIP_READ;
+else
+    return NULL;
+}
+
+static void metaDataAdd(struct lineFile *lf, char *line)
+/* write a line of metaData to output file
+ * internal function called by lineFileNext */
+{
+struct metaOutput *meta = NULL;
+
+if (lf->isMetaUnique)
+    {
+    /* suppress repetition of comments */
+    if (hashLookup(lf->metaLines, line))
+        {
+        return;
+        }
+    hashAdd(lf->metaLines, line, NULL);
+    }
+for (meta = lf->metaOutput ; meta != NULL ; meta = meta->next)
+    if (line != NULL && meta->metaFile != NULL)
+        fprintf(meta->metaFile,"%s\n", line);
+}
+
+static void metaDataFree(struct lineFile *lf)
+/* free saved comments */
+{
+if (lf->isMetaUnique && lf->metaLines)
+    freeHash(&lf->metaLines);
+}
+
+void lineFileSetMetaDataOutput(struct lineFile *lf, FILE *f)
+/* set file to write meta data to,
+ * should be called before reading from input file */
+{
+struct metaOutput *meta = NULL;
+if (lf == NULL)
+    return;
+AllocVar(meta);
+meta->next = NULL;
+meta->metaFile = f;
+slAddHead(&lf->metaOutput, meta);
+}
+
+void lineFileSetUniqueMetaData(struct lineFile *lf)
+/* suppress duplicate lines in metadata */
+{
+lf->isMetaUnique = TRUE;
+lf->metaLines = hashNew(8);
+}
+
+static char * headerBytes(char *fileName, int numbytes)
+/* Return specified number of header bytes from file
+ * if file exists as a string which should be freed. */
+{
+int fd,bytesread=0;
+char *result = NULL;
+if ((fd = open(fileName, O_RDONLY)) >= 0)
+    {
+    result=needMem(numbytes+1);
+    if ((bytesread=read(fd,result,numbytes)) < numbytes)
+	freez(&result);  /* file too short? can read numbytes */
+    else
+	result[numbytes]=0;
+    close(fd);
+    }
+return result;
+}
+
+
+struct lineFile *lineFileDecompress(char *fileName, bool zTerm)
+/* open a linefile with decompression */
+{
+struct pipeline *pl;
+struct lineFile *lf;
+char *testName = NULL;
+char *testbytes = NULL;    /* the header signatures for .gz, .bz2, .Z,
+			    * .zip are all 2-4 bytes only */
+if (fileName==NULL)
+  return NULL;
+testbytes=headerBytes(fileName,4);
+if (!testbytes)
+    return NULL;  /* avoid error from pipeline */
+testName=getFileNameFromHdrSig(testbytes);
+freez(&testbytes);
+if (!testName)
+    return NULL;  /* avoid error from pipeline */
+pl = pipelineOpen1(getDecompressor(fileName), pipelineRead, fileName, NULL);
+lf = lineFileAttach(fileName, zTerm, pipelineFd(pl));
+lf->pl = pl;
+return lf;
+}
+
+struct lineFile *lineFileDecompressFd(char *name, bool zTerm, int fd)
+/* open a linefile with decompression from a file or socket descriptor */
+{
+struct pipeline *pl;
+struct lineFile *lf;
+pl = pipelineOpenFd1(getDecompressor(name), pipelineRead, fd, STDERR_FILENO);
+lf = lineFileAttach(name, zTerm, pipelineFd(pl));
+lf->pl = pl;
+return lf;
+}
+
+
+
+struct lineFile *lineFileDecompressMem(bool zTerm, char *mem, long size)
+/* open a linefile with decompression from a memory stream */
+{
+struct pipeline *pl;
+struct lineFile *lf;
+char *fileName = getFileNameFromHdrSig(mem);
+if (fileName==NULL)
+  return NULL;
+pl = pipelineOpenMem1(getDecompressor(fileName), pipelineRead, mem, size, STDERR_FILENO);
+lf = lineFileAttach(fileName, zTerm, pipelineFd(pl));
+lf->pl = pl;
+return lf;
+}
+
+
+
+struct lineFile *lineFileAttach(char *fileName, bool zTerm, int fd)
+/* Wrap a line file around an open'd file. */
+{
+struct lineFile *lf;
+AllocVar(lf);
+lf->fileName = cloneString(fileName);
+lf->fd = fd;
+lf->bufSize = 64*1024;
+lf->zTerm = zTerm;
+lf->buf = needMem(lf->bufSize+1);
+return lf;
+}
+
+struct lineFile *lineFileOnString(char *name, bool zTerm, char *s)
+/* Wrap a line file object around string in memory. This buffer
+ * have zeroes written into it and be freed when the line file
+ * is closed. */
+{
+struct lineFile *lf;
+AllocVar(lf);
+lf->fileName = cloneString(name);
+lf->fd = -1;
+lf->bufSize = lf->bytesInBuf = strlen(s);
+lf->zTerm = zTerm;
+lf->buf = s;
+return lf;
+}
+
+struct lineFile *lineFileTabixMayOpen(char *fileOrUrl, bool zTerm)
+/* Wrap a line file around a data file that has been compressed and indexed
+ * by the tabix command line program.  The index file <fileOrUrl>.tbi must be
+ * readable in addition to fileOrUrl. If there's a problem, warn & return NULL.
+ * This works only if kent/src has been compiled with USE_TABIX=1 and linked
+ * with the tabix C library. */
+{
+#ifdef USE_TABIX
+int tbiNameSize = strlen(fileOrUrl) + strlen(".tbi") + 1;
+char *tbiName = needMem(tbiNameSize);
+safef(tbiName, tbiNameSize, "%s.tbi", fileOrUrl);
+tabix_t *tabix = ti_open(fileOrUrl, tbiName);
+if (tabix == NULL)
+    {
+    warn("Unable to open \"%s\"", fileOrUrl);
+    freez(&tbiName);
+    return NULL;
+    }
+if ((tabix->idx = ti_index_load(tbiName)) == NULL)
+    {
+    warn("Unable to load tabix index from \"%s\"", tbiName);
+    ti_close(tabix);
+    tabix = NULL;
+    freez(&tbiName);
+    return NULL;
+    }
+struct lineFile *lf = needMem(sizeof(struct lineFile));
+lf->fileName = cloneString(fileOrUrl);
+lf->fd = -1;
+lf->bufSize = 64 * 1024;
+lf->buf = needMem(lf->bufSize);
+lf->zTerm = zTerm;
+lf->tabix = tabix;
+lf->tabixIter = ti_iter_first();
+freez(&tbiName);
+return lf;
+#else // no USE_TABIX
+warn(COMPILE_WITH_TABIX, "lineFileTabixMayOpen");
+return NULL;
+#endif // no USE_TABIX
+}
+
+boolean lineFileSetTabixRegion(struct lineFile *lf, char *seqName, int start, int end)
+/* Assuming lf was created by lineFileTabixMayOpen, tell tabix to seek to the specified region
+ * and return TRUE (or if there are no items in region, return FALSE). */
+{
+#ifdef USE_TABIX
+if (lf->tabix == NULL)
+    errAbort("lineFileSetTabixRegion: lf->tabix is NULL.  Did you open lf with lineFileTabixMayOpen?");
+if (seqName == NULL)
+    return FALSE;
+int tabixSeqId = ti_get_tid(lf->tabix->idx, seqName);
+if (tabixSeqId < 0 && startsWith("chr", seqName))
+    // We will get some files that have chr-less Ensembl chromosome names:
+    tabixSeqId = ti_get_tid(lf->tabix->idx, seqName+strlen("chr"));
+if (tabixSeqId < 0)
+    return FALSE;
+ti_iter_t iter = ti_queryi(lf->tabix, tabixSeqId, start, end);
+if (iter == NULL)
+    return FALSE;
+if (lf->tabixIter != NULL)
+    ti_iter_destroy(lf->tabixIter);
+lf->tabixIter = iter;
+lf->bufOffsetInFile = ti_bgzf_tell(lf->tabix->fp);
+lf->bytesInBuf = 0;
+lf->lineIx = -1;
+lf->lineStart = 0;
+lf->lineEnd = 0;
+return TRUE;
+#else // no USE_TABIX
+warn(COMPILE_WITH_TABIX, "lineFileSetTabixRegion");
+return FALSE;
+#endif // no USE_TABIX
+}
+
+
+void lineFileExpandBuf(struct lineFile *lf, int newSize)
+/* Expand line file buffer. */
+{
+assert(newSize > lf->bufSize);
+lf->buf = needMoreMem(lf->buf, lf->bytesInBuf, newSize);
+lf->bufSize = newSize;
+}
+
+
+struct lineFile *lineFileStdin(bool zTerm)
+/* Wrap a line file around stdin. */
+{
+return lineFileAttach("stdin", zTerm, fileno(stdin));
+}
+
+struct lineFile *lineFileMayOpen(char *fileName, bool zTerm)
+/* Try and open up a lineFile. */
+{
+if (sameString(fileName, "stdin"))
+    return lineFileStdin(zTerm);
+else if (getDecompressor(fileName) != NULL)
+    return lineFileDecompress(fileName, zTerm);
+else
+    {
+    int fd = open(fileName, O_RDONLY);
+    if (fd == -1)
+        return NULL;
+    return lineFileAttach(fileName, zTerm, fd);
+    }
+}
+
+struct lineFile *lineFileOpen(char *fileName, bool zTerm)
+/* Open up a lineFile or die trying. */
+{
+struct lineFile *lf = lineFileMayOpen(fileName, zTerm);
+if (lf == NULL)
+    errAbort("Couldn't open %s , %s", fileName, strerror(errno));
+return lf;
+}
+
+void lineFileReuse(struct lineFile *lf)
+/* Reuse current line. */
+{
+lf->reuse = TRUE;
+}
+
+
+INLINE void noTabixSupport(struct lineFile *lf, char *where)
+{
+#ifdef USE_TABIX
+if (lf->tabix != NULL)
+    lineFileAbort(lf, "%s: not implemented for lineFile opened with lineFileTabixMayOpen.", where);
+#endif // USE_TABIX
+}
+
+void lineFileSeek(struct lineFile *lf, off_t offset, int whence)
+/* Seek to read next line from given position. */
+{
+noTabixSupport(lf, "lineFileSeek");
+if (lf->checkSupport)
+    lf->checkSupport(lf, "lineFileSeek");
+if (lf->pl != NULL)
+    errnoAbort("Can't lineFileSeek on a compressed file: %s", lf->fileName);
+lf->reuse = FALSE;
+if (whence == SEEK_SET && offset >= lf->bufOffsetInFile
+	&& offset < lf->bufOffsetInFile + lf->bytesInBuf)
+    {
+    lf->lineStart = lf->lineEnd = offset - lf->bufOffsetInFile;
+    }
+else
+    {
+    lf->lineStart = lf->lineEnd = lf->bytesInBuf = 0;
+    if ((lf->bufOffsetInFile = lseek(lf->fd, offset, whence)) == -1)
+	errnoAbort("Couldn't lineFileSeek %s", lf->fileName);
+    }
+}
+
+void lineFileRewind(struct lineFile *lf)
+/* Return lineFile to start. */
+{
+lineFileSeek(lf, 0, SEEK_SET);
+lf->lineIx = 0;
+}
+
+int lineFileLongNetRead(int fd, char *buf, int size)
+/* Keep reading until either get no new characters or
+ * have read size */
+{
+int oneSize, totalRead = 0;
+
+while (size > 0)
+    {
+    oneSize = read(fd, buf, size);
+    if (oneSize <= 0)
+        break;
+    totalRead += oneSize;
+    buf += oneSize;
+    size -= oneSize;
+    }
+return totalRead;
+}
+
+static void determineNlType(struct lineFile *lf, char *buf, int bufSize)
+/* determine type of newline used for the file, assumes buffer not empty */
+{
+char *c = buf;
+if (bufSize==0) return;
+if (lf->nlType != nlt_undet) return;  /* if already determined just exit */
+lf->nlType = nlt_unix;  /* start with default of unix lf type */
+while (c < buf+bufSize)
+    {
+    if (*c=='\r')
+	{
+    	lf->nlType = nlt_mac;
+	if (++c < buf+bufSize)
+    	    if (*c == '\n')
+    		lf->nlType = nlt_dos;
+	return;
+	}
+    if (*(c++) == '\n')
+	{
+	return;
+	}
+    }
+}
+
+boolean lineFileNext(struct lineFile *lf, char **retStart, int *retSize)
+/* Fetch next line from file. */
+{
+char *buf = lf->buf;
+int bytesInBuf = lf->bytesInBuf;
+int endIx = lf->lineEnd;
+boolean gotLf = FALSE;
+int newStart;
+
+if (lf->reuse)
+    {
+    lf->reuse = FALSE;
+    if (retSize != NULL)
+	*retSize = lf->lineEnd - lf->lineStart;
+    *retStart = buf + lf->lineStart;
+    if (lf->metaOutput && *retStart[0] == '#')
+        metaDataAdd(lf, *retStart);
+    return TRUE;
+    }
+
+if (lf->nextCallBack)
+    return lf->nextCallBack(lf, retStart, retSize);
+
+
+#ifdef USE_TABIX
+if (lf->tabix != NULL && lf->tabixIter != NULL)
+    {
+    // Just use line-oriented ti_read:
+    int lineSize = 0;
+    const char *line = ti_read(lf->tabix, lf->tabixIter, &lineSize);
+    if (line == NULL)
+	return FALSE;
+    lf->bufOffsetInFile = -1;
+    lf->bytesInBuf = lineSize;
+    lf->lineIx = -1;
+    lf->lineStart = 0;
+    lf->lineEnd = lineSize;
+    if (lineSize > lf->bufSize)
+	// shouldn't be!  but just in case:
+	lineFileExpandBuf(lf, lineSize * 2);
+    safecpy(lf->buf, lf->bufSize, line);
+    *retStart = lf->buf;
+    if (retSize != NULL)
+	*retSize = lineSize;
+    return TRUE;
+    }
+#endif // USE_TABIX
+
+determineNlType(lf, buf+endIx, bytesInBuf);
+
+/* Find next end of line in buffer. */
+switch(lf->nlType)
+    {
+    case nlt_unix:
+    case nlt_dos:
+	for (endIx = lf->lineEnd; endIx < bytesInBuf; ++endIx)
+	    {
+	    if (buf[endIx] == '\n')
+		{
+		gotLf = TRUE;
+		endIx += 1;
+		break;
+		}
+	    }
+	break;
+    case nlt_mac:
+	for (endIx = lf->lineEnd; endIx < bytesInBuf; ++endIx)
+	    {
+	    if (buf[endIx] == '\r')
+		{
+		gotLf = TRUE;
+		endIx += 1;
+		break;
+		}
+	    }
+	break;
+    case nlt_undet:
+	break;
+    }
+
+/* If not in buffer read in a new buffer's worth. */
+while (!gotLf)
+    {
+    int oldEnd = lf->lineEnd;
+    int sizeLeft = bytesInBuf - oldEnd;
+    int bufSize = lf->bufSize;
+    int readSize = bufSize - sizeLeft;
+
+    if (oldEnd > 0 && sizeLeft > 0)
+	{
+	memmove(buf, buf+oldEnd, sizeLeft);
+	}
+    lf->bufOffsetInFile += oldEnd;
+    if (lf->fd >= 0)
+	readSize = lineFileLongNetRead(lf->fd, buf+sizeLeft, readSize);
+#ifdef USE_TABIX
+    else if (lf->tabix != NULL && readSize > 0)
+	{
+	readSize = ti_bgzf_read(lf->tabix->fp, buf+sizeLeft, readSize);
+	if (readSize < 1)
+	    return FALSE;
+	}
+#endif // USE_TABIX
+    else
+        readSize = 0;
+
+    if ((readSize == 0) && (endIx > oldEnd))
+	{
+	endIx = sizeLeft;
+	buf[endIx] = 0;
+	lf->bytesInBuf = newStart = lf->lineStart = 0;
+	lf->lineEnd = endIx;
+	++lf->lineIx;
+	if (retSize != NULL)
+	    *retSize = endIx - newStart;
+	*retStart = buf + newStart;
+        if (*retStart[0] == '#')
+            metaDataAdd(lf, *retStart);
+	return TRUE;
+	}
+    else if (readSize <= 0)
+	{
+	lf->bytesInBuf = lf->lineStart = lf->lineEnd = 0;
+	return FALSE;
+	}
+    bytesInBuf = lf->bytesInBuf = readSize + sizeLeft;
+    lf->lineEnd = 0;
+
+    determineNlType(lf, buf+endIx, bytesInBuf);
+
+    /* Look for next end of line.  */
+    switch(lf->nlType)
+	{
+    	case nlt_unix:
+	case nlt_dos:
+	    for (endIx = sizeLeft; endIx <bytesInBuf; ++endIx)
+		{
+		if (buf[endIx] == '\n')
+		    {
+		    endIx += 1;
+		    gotLf = TRUE;
+		    break;
+		    }
+		}
+	    break;
+	case nlt_mac:
+	    for (endIx = sizeLeft; endIx <bytesInBuf; ++endIx)
+		{
+		if (buf[endIx] == '\r')
+		    {
+		    endIx += 1;
+		    gotLf = TRUE;
+		    break;
+		    }
+		}
+	    break;
+	case nlt_undet:
+	    break;
+	}
+    if (!gotLf && bytesInBuf == lf->bufSize)
+        {
+	if (bufSize >= 512*1024*1024)
+	    {
+	    errAbort("Line too long (more than %d chars) line %d of %s",
+		lf->bufSize, lf->lineIx+1, lf->fileName);
+	    }
+	else
+	    {
+	    lineFileExpandBuf(lf, bufSize*2);
+	    buf = lf->buf;
+	    }
+	}
+    }
+
+if (lf->zTerm)
+    {
+    buf[endIx-1] = 0;
+    if ((lf->nlType == nlt_dos) && (buf[endIx-2]=='\r'))
+	{
+	buf[endIx-2] = 0;
+	}
+    }
+
+lf->lineStart = newStart = lf->lineEnd;
+lf->lineEnd = endIx;
+++lf->lineIx;
+if (retSize != NULL)
+    *retSize = endIx - newStart;
+*retStart = buf + newStart;
+if (*retStart[0] == '#')
+    metaDataAdd(lf, *retStart);
+return TRUE;
+}
+
+void lineFileVaAbort(struct lineFile *lf, char *format, va_list args)
+/* Print file name, line number, and error message, and abort. */
+{
+struct dyString *dy = dyStringNew(0);
+dyStringPrintf(dy,  "Error line %d of %s: ", lf->lineIx, lf->fileName);
+dyStringVaPrintf(dy, format, args);
+errAbort("%s", dy->string);
+dyStringFree(&dy);
+}
+
+void lineFileAbort(struct lineFile *lf, char *format, ...)
+/* Print file name, line number, and error message, and abort. */
+{
+va_list args;
+va_start(args, format);
+lineFileVaAbort(lf, format, args);
+va_end(args);
+}
+
+void lineFileUnexpectedEnd(struct lineFile *lf)
+/* Complain about unexpected end of file. */
+{
+errAbort("Unexpected end of file in %s", lf->fileName);
+}
+
+void lineFileNeedNext(struct lineFile *lf, char **retStart, int *retSize)
+/* Fetch next line from file.  Squawk and die if it's not there. */
+{
+if (!lineFileNext(lf, retStart, retSize))
+    lineFileUnexpectedEnd(lf);
+}
+
+void lineFileClose(struct lineFile **pLf)
+/* Close up a line file. */
+{
+struct lineFile *lf;
+if ((lf = *pLf) != NULL)
+    {
+    if (lf->pl != NULL)
+        {
+        pipelineWait(lf->pl);
+        pipelineFree(&lf->pl);
+        }
+    else if (lf->fd > 0 && lf->fd != fileno(stdin))
+	{
+	close(lf->fd);
+	freeMem(lf->buf);
+	}
+#ifdef USE_TABIX
+    else if (lf->tabix != NULL)
+	{
+	if (lf->tabixIter != NULL)
+	    ti_iter_destroy(lf->tabixIter);
+	ti_close(lf->tabix);
+	}
+#endif // USE_TABIX
+    if (lf->closeCallBack)
+        lf->closeCallBack(lf);
+    freeMem(lf->fileName);
+    metaDataFree(lf);
+    freez(pLf);
+    }
+}
+
+void lineFileCloseList(struct lineFile **pList)
+/* Close up a list of line files. */
+{
+struct lineFile *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    lineFileClose(&el);
+    }
+*pList = NULL;
+}
+
+void lineFileExpectWords(struct lineFile *lf, int expecting, int got)
+/* Check line has right number of words. */
+{
+if (expecting != got)
+    errAbort("Expecting %d words line %d of %s got %d",
+	    expecting, lf->lineIx, lf->fileName, got);
+}
+
+void lineFileExpectAtLeast(struct lineFile *lf, int expecting, int got)
+/* Check line has right number of words. */
+{
+if (got < expecting)
+    errAbort("Expecting at least %d words line %d of %s got %d",
+	    expecting, lf->lineIx, lf->fileName, got);
+}
+
+void lineFileShort(struct lineFile *lf)
+/* Complain that line is too short. */
+{
+errAbort("Short line %d of %s", lf->lineIx, lf->fileName);
+}
+
+void lineFileReuseFull(struct lineFile *lf)
+// Reuse last full line read.  Unlike lineFileReuse,
+// lineFileReuseFull only works with previous lineFileNextFull call
+{
+assert(lf->fullLine != NULL);
+lf->fullLineReuse = TRUE;
+}
+
+
+boolean lineFileNextFull(struct lineFile *lf, char **retFull, int *retFullSize,
+                        char **retRaw, int *retRawSize)
+// Fetch next line from file joining up any that are continued by ending '\'
+// If requested, and was joined, the unjoined raw lines are also returned
+// NOTE: comment lines can't be continued!  ("# comment \ \n more comment" is 2 lines.)
+{
+// May have requested reusing the last full line.
+if (lf->fullLineReuse)
+    {
+    lf->fullLineReuse = FALSE;
+    assert(lf->fullLine != NULL);
+    *retFull = dyStringContents(lf->fullLine);
+    if (retFullSize)
+        *retFullSize = dyStringLen(lf->fullLine);
+    if (retRaw != NULL)
+        {
+        assert(lf->rawLines != NULL);
+        *retRaw = dyStringContents(lf->rawLines);
+        if (retRawSize)
+            *retRawSize = dyStringLen(lf->rawLines);
+        }
+    return TRUE;
+    }
+
+// Empty pointers
+*retFull = NULL;
+if (retRaw != NULL)
+    *retRaw = NULL;
+
+// Prepare lf buffers
+if (lf->fullLine == NULL)
+    {
+    lf->fullLine = dyStringNew(1024);
+    lf->rawLines = dyStringNew(1024); // Better to always create it than test every time
+    }
+else
+    {
+    dyStringClear(lf->fullLine);
+    dyStringClear(lf->rawLines);
+    }
+
+char *line;
+while (lineFileNext(lf, &line, NULL))
+    {
+    char *start = skipLeadingSpaces(line);
+
+    // Will the next line continue this one?
+    char *end = start;
+    if (*start == '#')  // Comment lines can't be continued!
+        end = start + strlen(start);
+    else
+        {
+        while (*end != '\0')  // walking forward for efficiency (avoid strlens())
+            {
+            for (;*end != '\0' && *end != '\\'; end++) ; // Tight loop to find '\'
+            if (*end == '\0')
+                break;
+
+            // This could be a continuation
+            char *slash = end;
+            if (*(++end) == '\\')  // escaped
+                continue;
+            end = skipLeadingSpaces(end);
+
+            if (*end == '\0') // Just whitespace after '\', so true continuation mark
+                {
+                if (retRaw != NULL) // Only if actually requested.
+                    {
+                    dyStringAppendN(lf->rawLines,line,(end - line));
+                    dyStringAppendC(lf->rawLines,'\n'); // New lines delimit raw lines.
+                    }
+                end = slash; // Don't need to zero, because of appending by length
+                break;
+                }
+            }
+        }
+
+    // Stitch together full lines
+    if (dyStringLen(lf->fullLine) == 0)
+        dyStringAppendN(lf->fullLine,line,(end - line)); // includes first line's whitespace
+    else if (start < end)             // don't include continued line's leading spaces
+        dyStringAppendN(lf->fullLine,start,(end - start));
+
+    if (*end == '\\')
+        continue;
+
+    // Got a full line now!
+    *retFull = dyStringContents(lf->fullLine);
+    if (retFullSize)
+        *retFullSize = dyStringLen(lf->fullLine);
+
+    if (retRaw != NULL && dyStringLen(lf->rawLines) > 0) // Only if actually requested & continued
+        {
+        // This is the final line which doesn't have a continuation char
+        dyStringAppendN(lf->rawLines,line,(end - line));
+        *retRaw = dyStringContents(lf->rawLines);
+        if (retRawSize)
+            *retRawSize = dyStringLen(lf->rawLines);
+        }
+    return TRUE;
+    }
+return FALSE;
+}
+
+boolean lineFileNextReal(struct lineFile *lf, char **retStart)
+/* Fetch next line from file that is not blank and
+ * does not start with a '#'. */
+{
+char *s, c;
+while (lineFileNext(lf, retStart, NULL))
+    {
+    s = skipLeadingSpaces(*retStart);
+    c = s[0];
+    if (c != 0 && c != '#')
+        return TRUE;
+    }
+return FALSE;
+}
+
+boolean lineFileNextFullReal(struct lineFile *lf, char **retStart)
+// Fetch next line from file that is not blank and does not start with a '#'.
+// Continuation lines (ending in '\') are joined into a single line.
+{
+while (lineFileNextFull(lf, retStart, NULL, NULL, NULL))
+    {
+    char *clippedText = skipLeadingSpaces(*retStart);
+    if (clippedText[0] != '\0' && clippedText[0] != '#')
+        return TRUE;
+    }
+return FALSE;
+}
+
+
+int lineFileChopNext(struct lineFile *lf, char *words[], int maxWords)
+/* Return next non-blank line that doesn't start with '#' chopped into words. */
+{
+int lineSize, wordCount;
+char *line;
+
+while (lineFileNext(lf, &line, &lineSize))
+    {
+    if (line[0] == '#')
+        continue;
+    wordCount = chopByWhite(line, words, maxWords);
+    if (wordCount != 0)
+        return wordCount;
+    }
+return 0;
+}
+
+int lineFileChopCharNext(struct lineFile *lf, char sep, char *words[], int maxWords)
+/* Return next non-blank line that doesn't start with '#' chopped into
+   words delimited by sep. */
+{
+int lineSize, wordCount;
+char *line;
+
+while (lineFileNext(lf, &line, &lineSize))
+    {
+    if (line[0] == '#')
+        continue;
+    wordCount = chopByChar(line, sep, words, maxWords);
+    if (wordCount != 0)
+        return wordCount;
+    }
+return 0;
+}
+
+int lineFileChopNextTab(struct lineFile *lf, char *words[], int maxWords)
+/* Return next non-blank line that doesn't start with '#' chopped into words
+ * on tabs */
+{
+int lineSize, wordCount;
+char *line;
+
+while (lineFileNext(lf, &line, &lineSize))
+    {
+    if (line[0] == '#')
+        continue;
+    wordCount = chopByChar(line, '\t', words, maxWords);
+    if (wordCount != 0)
+        return wordCount;
+    }
+return 0;
+}
+
+boolean lineFileNextCharRow(struct lineFile *lf, char sep, char *words[], int wordCount)
+/* Return next non-blank line that doesn't start with '#' chopped into words
+ * delimited by sep. Returns FALSE at EOF.  Aborts on error. */
+{
+int wordsRead;
+wordsRead = lineFileChopCharNext(lf, sep, words, wordCount);
+if (wordsRead == 0)
+    return FALSE;
+if (wordsRead < wordCount)
+    lineFileExpectWords(lf, wordCount, wordsRead);
+return TRUE;
+}
+
+boolean lineFileNextRow(struct lineFile *lf, char *words[], int wordCount)
+/* Return next non-blank line that doesn't start with '#' chopped into words.
+ * Returns FALSE at EOF.  Aborts on error. */
+{
+int wordsRead;
+wordsRead = lineFileChopNext(lf, words, wordCount);
+if (wordsRead == 0)
+    return FALSE;
+if (wordsRead < wordCount)
+    lineFileExpectWords(lf, wordCount, wordsRead);
+return TRUE;
+}
+
+boolean lineFileNextRowTab(struct lineFile *lf, char *words[], int wordCount)
+/* Return next non-blank line that doesn't start with '#' chopped into words
+ * at tabs. Returns FALSE at EOF.  Aborts on error. */
+{
+int wordsRead;
+wordsRead = lineFileChopNextTab(lf, words, wordCount);
+if (wordsRead == 0)
+    return FALSE;
+if (wordsRead < wordCount)
+    lineFileExpectWords(lf, wordCount, wordsRead);
+return TRUE;
+}
+
+int lineFileNeedFullNum(struct lineFile *lf, char *words[], int wordIx)
+/* Make sure that words[wordIx] is an ascii integer, and return
+ * binary representation of it. Require all chars in word to be digits.*/
+{
+char *c;
+for (c = words[wordIx]; *c; c++)
+    {
+    if (*c == '-' || isdigit(*c))
+        /* NOTE: embedded '-' will be caught by lineFileNeedNum */
+        continue;
+    errAbort("Expecting integer field %d line %d of %s, got %s",
+            wordIx+1, lf->lineIx, lf->fileName, words[wordIx]);
+    }
+return lineFileNeedNum(lf, words, wordIx);
+}
+
+int lineFileNeedNum(struct lineFile *lf, char *words[], int wordIx)
+/* Make sure that words[wordIx] is an ascii integer, and return
+ * binary representation of it. Conversion stops at first non-digit char. */
+{
+char *ascii = words[wordIx];
+char c = ascii[0];
+if (c != '-' && !isdigit(c))
+    errAbort("Expecting number field %d line %d of %s, got %s",
+    	wordIx+1, lf->lineIx, lf->fileName, ascii);
+return atoi(ascii);
+}
+
+int lineFileCheckAllIntsNoAbort(char *s, void *val, 
+    boolean isSigned, int byteCount, char *typeString, boolean noNeg, 
+    char *errMsg, int errMsgSize)
+/* Convert string to (signed) integer of the size specified.  
+ * Unlike atol assumes all of string is number, no trailing trash allowed.
+ * Returns 0 if conversion possible, and value is returned in 'val'
+ * Otherwise 1 for empty string or trailing chars, and 2 for numeric overflow,
+ * and 3 for (-) sign in unsigned number.
+ * Error messages if any are written into the provided buffer.
+ * Pass NULL val if you only want validation.
+ * Use noNeg if negative values are not allowed despite the type being signed,
+ * returns 4. */
+{
+unsigned long long res = 0, oldRes = 0;
+boolean isMinus = FALSE;
+
+if ((byteCount != 1) 
+ && (byteCount != 2)
+ && (byteCount != 4)
+ && (byteCount != 8))
+    errAbort("Unexpected error: Invalid byte count for integer size in lineFileCheckAllIntsNoAbort, expected 1 2 4 or 8, got %d.", byteCount);
+
+unsigned long long limit = 0xFFFFFFFFFFFFFFFFULL >> (8*(8-byteCount));
+
+if (isSigned) 
+    limit >>= 1;
+
+char *p, *p0 = s;
+
+if (*p0 == '-')
+    {
+    if (isSigned)
+	{
+	if (noNeg)
+	    {
+	    safef(errMsg, errMsgSize, "Negative value not allowed");
+	    return 4; 
+	    }
+	p0++;
+	++limit;
+	isMinus = TRUE;
+	}
+    else
+	{
+	safef(errMsg, errMsgSize, "Unsigned %s may not begin with minus sign (-)", typeString);
+	return 3; 
+	}
+    }
+p = p0;
+while ((*p >= '0') && (*p <= '9'))
+    {
+    res *= 10;
+    if (res < oldRes)
+	{
+	safef(errMsg, errMsgSize, "%s%s overflowed", isSigned ? "signed ":"", typeString);
+	return 2; 
+	}
+    oldRes = res;
+    res += *p - '0';
+    if (res < oldRes)
+	{
+	safef(errMsg, errMsgSize, "%s%s overflowed", isSigned ? "signed ":"", typeString);
+	return 2; 
+	}
+    if (res > limit)
+	{
+	safef(errMsg, errMsgSize, "%s%s overflowed, limit=%s%llu", isSigned ? "signed ":"", typeString, isMinus ? "-" : "", limit);
+	return 2; 
+	}
+    oldRes = res;
+    p++;
+    }
+/* test for invalid character, empty, or just a minus */
+if (*p != '\0')
+    {
+    safef(errMsg, errMsgSize, "Trailing characters parsing %s%s", isSigned ? "signed ":"", typeString);
+    return 1;
+    }
+if (p == p0)
+    {
+    safef(errMsg, errMsgSize, "Empty string parsing %s%s", isSigned ? "signed ":"", typeString);
+    return 1;
+    }
+
+if (!val)
+    return 0;  // only validation required
+
+switch (byteCount)
+    {
+    case 1:
+	if (isSigned)
+	    {
+	    if (isMinus)
+		*(char *)val = -res;
+	    else
+		*(char *)val = res;
+	    }
+	else
+	    *(unsigned char *)val = res;
+	break;
+    case 2:
+	if (isSigned)
+	    {
+	    if (isMinus)
+		*(short *)val = -res;
+	    else
+		*(short *)val = res;
+	    }
+	else
+	    *(unsigned short *)val = res;
+	break;
+    case 4:
+	if (isSigned)
+	    {
+	    if (isMinus)
+		*(int *)val = -res;
+	    else
+		*(int *)val = res;
+	    }
+	else
+	    *(unsigned *)val = res;
+	break;
+    case 8:
+	if (isSigned)
+	    {
+	    if (isMinus)
+		*(long long *)val = -res;
+	    else
+		*(long long *) val =res;
+	    }
+	else
+	    *(unsigned long long *)val = res;
+	break;
+    }
+
+
+return 0;
+}
+
+void lineFileAllInts(struct lineFile *lf, char *words[], int wordIx, void *val,
+  boolean isSigned,  int byteCount, char *typeString, boolean noNeg)
+/* Returns long long integer from converting the input string. Aborts on error. */
+{
+char *s = words[wordIx];
+char errMsg[256];
+int res = lineFileCheckAllIntsNoAbort(s, val, isSigned, byteCount, typeString, noNeg, errMsg, sizeof errMsg);
+if (res > 0)
+    {
+    errAbort("%s in field %d line %d of %s, got %s",
+	errMsg, wordIx+1, lf->lineIx, lf->fileName, s);
+    }
+}
+
+int lineFileAllIntsArray(struct lineFile *lf, char *words[], int wordIx, void *array, int arraySize,
+  boolean isSigned,  int byteCount, char *typeString, boolean noNeg)
+/* Convert comma separated list of numbers to an array.  Pass in
+ * array and max size of array. Aborts on error. Returns number of elements in parsed array. */
+{
+char *s = words[wordIx];
+char errMsg[256];
+unsigned count = 0;
+char *cArray = array;
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0 || count == arraySize)
+        break;
+    e = strchr(s, ',');
+    if (e)
+        *e = 0;
+    int res = lineFileCheckAllIntsNoAbort(s, cArray, isSigned, byteCount, typeString, noNeg, errMsg, sizeof errMsg);
+    if (res > 0)
+	{
+	errAbort("%s in column %d of array field %d line %d of %s, got %s",
+	    errMsg, count, wordIx+1, lf->lineIx, lf->fileName, s);
+	}
+    if (cArray) // NULL means validation only.
+	cArray += byteCount;  
+    count++;
+    if (e)  // restore input string
+        *e++ = ',';
+    s = e;
+    }
+return count;
+}
+
+
+double lineFileNeedDouble(struct lineFile *lf, char *words[], int wordIx)
+/* Make sure that words[wordIx] is an ascii double value, and return
+ * binary representation of it. */
+{
+char *valEnd;
+char *val = words[wordIx];
+double doubleValue;
+
+doubleValue = strtod(val, &valEnd);
+if ((*val == '\0') || (*valEnd != '\0'))
+    errAbort("Expecting double field %d line %d of %s, got %s",
+    	wordIx+1, lf->lineIx, lf->fileName, val);
+return doubleValue;
+}
+
+void lineFileSkip(struct lineFile *lf, int lineCount)
+/* Skip a number of lines. */
+{
+int i, lineSize;
+char *line;
+
+for (i=0; i<lineCount; ++i)
+    {
+    if (!lineFileNext(lf, &line, &lineSize))
+        errAbort("Premature end of file in %s", lf->fileName);
+    }
+}
+
+char *lineFileSkipToLineStartingWith(struct lineFile *lf, char *start, int maxCount)
+/* Skip to next line that starts with given string.  Return NULL
+ * if no such line found, otherwise return the line. */
+{
+char *line;
+while (lineFileNext(lf, &line, NULL) && --maxCount >= 0)
+    {
+    if (startsWith(start, line))
+        return line;
+    }
+return NULL;
+}
+
+char *lineFileReadAll(struct lineFile *lf)
+/* Read remainder of lineFile and return it as a string. */
+{
+struct dyString *dy = dyStringNew(1024*4);
+lf->zTerm = 0;
+int size;
+char *line;
+while (lineFileNext(lf, &line, &size))
+    dyStringAppendN(dy, line, size);
+return dyStringCannibalize(&dy);
+}
+
+boolean lineFileParseHttpHeader(struct lineFile *lf, char **hdr,
+				boolean *chunked, int *contentLength)
+/* Extract HTTP response header from lf into hdr, tell if it's
+ * "Transfer-Encoding: chunked" or if it has a contentLength. */
+{
+  struct dyString *header = newDyString(1024);
+  char *line;
+  int lineSize;
+
+  if (chunked != NULL)
+    *chunked = FALSE;
+  if (contentLength != NULL)
+    *contentLength = -1;
+  dyStringClear(header);
+  if (lineFileNext(lf, &line, &lineSize))
+    {
+      if (startsWith("HTTP/", line))
+	{
+	char *version, *code;
+	dyStringAppendN(header, line, lineSize-1);
+	dyStringAppendC(header, '\n');
+	version = nextWord(&line);
+	code = nextWord(&line);
+	if (code == NULL)
+	    {
+	    warn("%s: Expecting HTTP/<version> <code> header line, got this: %s\n", lf->fileName, header->string);
+	    *hdr = cloneString(header->string);
+	    dyStringFree(&header);
+	    return FALSE;
+	    }
+	if (!sameString(code, "200"))
+	    {
+	    warn("%s: Errored HTTP response header: %s %s %s\n", lf->fileName, version, code, line);
+	    *hdr = cloneString(header->string);
+	    dyStringFree(&header);
+	    return FALSE;
+	    }
+	while (lineFileNext(lf, &line, &lineSize))
+	    {
+	    /* blank line means end of HTTP header */
+	    if ((line[0] == '\r' && line[1] == 0) || line[0] == 0)
+	        break;
+	    if (strstr(line, "Transfer-Encoding: chunked") && chunked != NULL)
+	        *chunked = TRUE;
+	    dyStringAppendN(header, line, lineSize-1);
+	    dyStringAppendC(header, '\n');
+	    if (strstr(line, "Content-Length:"))
+	      {
+		code = nextWord(&line);
+		code = nextWord(&line);
+		if (contentLength != NULL)
+		    *contentLength = atoi(code);
+	      }
+	    }
+	}
+      else
+	{
+	  /* put the line back, don't put it in header/hdr */
+	  lineFileReuse(lf);
+	  warn("%s: Expecting HTTP/<version> <code> header line, got this: %s\n", lf->fileName, header->string);
+	  *hdr = cloneString(header->string);
+	  dyStringFree(&header);
+	  return FALSE;
+	}
+    }
+  else
+    {
+      *hdr = cloneString(header->string);
+      dyStringFree(&header);
+      return FALSE;
+    }
+
+  *hdr = cloneString(header->string);
+  dyStringFree(&header);
+  return TRUE;
+} /* lineFileParseHttpHeader */
+
+struct dyString *lineFileSlurpHttpBody(struct lineFile *lf,
+				       boolean chunked, int contentLength)
+/* Return a dyString that contains the http response body in lf.  Handle
+ * chunk-encoding and content-length. */
+{
+  struct dyString *body = newDyString(64*1024);
+  char *line;
+  int lineSize;
+
+  dyStringClear(body);
+  if (chunked)
+    {
+      /* Handle "Transfer-Encoding: chunked" body */
+      /* Procedure from RFC2068 section 19.4.6 */
+      char *csword;
+      unsigned chunkSize = 0;
+      unsigned size;
+      do
+	{
+	  /* Read line that has chunk size (in hex) as first word. */
+	  if (lineFileNext(lf, &line, NULL))
+	    csword = nextWord(&line);
+	  else break;
+	  if (sscanf(csword, "%x", &chunkSize) < 1)
+	    {
+	      warn("%s: chunked transfer-encoding chunk size parse error.\n",
+		   lf->fileName);
+	      break;
+	    }
+	  /* If chunk size is 0, read in a blank line & then we're done. */
+	  if (chunkSize == 0)
+	    {
+	      lineFileNext(lf, &line, NULL);
+	      if (line == NULL || (line[0] != '\r' && line[0] != 0))
+		warn("%s: chunked transfer-encoding: expected blank line, got %s\n",
+		     lf->fileName, line);
+
+	      break;
+	    }
+	  /* Read (and save) lines until we have read in chunk. */
+	  for (size = 0;  size < chunkSize;  size += lineSize)
+	    {
+	      if (! lineFileNext(lf, &line, &lineSize))
+		break;
+	      dyStringAppendN(body, line, lineSize-1);
+	      dyStringAppendC(body, '\n');
+	    }
+	  /* Read blank line - or extra CRLF inserted in the middle of the
+	   * current line, in which case we need to trim it. */
+	  if (size > chunkSize)
+	    {
+	      body->stringSize -= (size - chunkSize);
+	      body->string[body->stringSize] = 0;
+	    }
+	  else if (size == chunkSize)
+	    {
+	      lineFileNext(lf, &line, NULL);
+	      if (line == NULL || (line[0] != '\r' && line[0] != 0))
+		warn("%s: chunked transfer-encoding: expected blank line, got %s\n",
+		     lf->fileName, line);
+	    }
+	} while (chunkSize > 0);
+      /* Try to read in next line.  If it's an HTTP header, put it back. */
+      /* If there is a next line but it's not an HTTP header, it's a footer. */
+      if (lineFileNext(lf, &line, NULL))
+	{
+	  if (startsWith("HTTP/", line))
+	    lineFileReuse(lf);
+	  else
+	    {
+	      /* Got a footer -- keep reading until blank line */
+	      warn("%s: chunked transfer-encoding: got footer %s, discarding it.\n",
+		   lf->fileName, line);
+	      while (lineFileNext(lf, &line, NULL))
+		{
+		  if ((line[0] == '\r' && line[1] == 0) || line[0] == 0)
+		    break;
+		  warn("discarding footer line: %s\n", line);
+		}
+	    }
+	}
+    }
+  else if (contentLength >= 0)
+    {
+      /* Read in known length */
+      int size;
+      for (size = 0;  size < contentLength;  size += lineSize)
+	{
+	  if (! lineFileNext(lf, &line, &lineSize))
+	    break;
+	  dyStringAppendN(body, line, lineSize-1);
+	  dyStringAppendC(body, '\n');
+	}
+    }
+  else
+    {
+      /* Read in to end of file (assume it's not a persistent connection) */
+      while (lineFileNext(lf, &line, &lineSize))
+	{
+	  dyStringAppendN(body, line, lineSize-1);
+	  dyStringAppendC(body, '\n');
+	}
+    }
+
+  return(body);
+} /* lineFileSlurpHttpBody */
+
+void lineFileRemoveInitialCustomTrackLines(struct lineFile *lf)
+/* remove initial browser and track lines */
+{
+char *line;
+while (lineFileNextReal(lf, &line))
+    {
+    if (!(startsWith("browser", line) || startsWith("track", line) ))
+        {
+        verbose(2, "found line not browser or track: %s\n", line);
+        lineFileReuse(lf);
+        break;
+        }
+    verbose(2, "skipping %s\n", line);
+    }
+}
+
diff --git a/lib/localmem.c b/lib/localmem.c
new file mode 100644
index 0000000..e364a66
--- /dev/null
+++ b/lib/localmem.c
@@ -0,0 +1,162 @@
+/* LocalMem.c - local memory routines. 
+ * 
+ * These routines are meant for the sort of scenario where
+ * a lot of little to medium size pieces of memory are
+ * allocated, and then disposed of all at once.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+
+#include "common.h"
+#include "localmem.h"
+
+
+struct lm
+    {
+    struct lmBlock *blocks;
+    size_t blockSize;
+    size_t allignMask;
+    size_t allignAdd;
+    };
+
+struct lmBlock
+    {
+    struct lmBlock *next;
+    char *free;
+    char *end;
+    char *extra;
+    };
+
+static struct lmBlock *newBlock(struct lm *lm, size_t reqSize)
+/* Allocate a new block of at least reqSize */
+{
+size_t size = (reqSize > lm->blockSize ? reqSize : lm->blockSize);
+size_t fullSize = size + sizeof(struct lmBlock);
+struct lmBlock *mb = needLargeZeroedMem(fullSize);
+if (mb == NULL)
+    errAbort("Couldn't allocate %lld bytes", (long long)fullSize);
+mb->free = (char *)(mb+1);
+mb->end = ((char *)mb) + fullSize;
+mb->next = lm->blocks;
+lm->blocks = mb;
+return mb;
+}
+
+struct lm *lmInit(int blockSize)
+/* Create a local memory pool. */
+{
+struct lm *lm;
+int aliSize = sizeof(long);
+if (aliSize < sizeof(double))
+    aliSize = sizeof(double);
+if (aliSize < sizeof(void *))
+    aliSize = sizeof(void *);
+lm = needMem(sizeof(*lm));
+lm->blocks = NULL;
+if (blockSize <= 0)
+    blockSize = (1<<14);    /* 16k default. */
+lm->blockSize = blockSize;
+lm->allignAdd = (aliSize-1);
+lm->allignMask = ~lm->allignAdd;
+newBlock(lm, blockSize);
+return lm;
+}
+
+void lmCleanup(struct lm **pLm)
+/* Clean up a local memory pool. */
+{
+    struct lm *lm = *pLm;
+    if (lm == NULL)
+        return;
+    slFreeList(&lm->blocks);
+    freeMem(lm);
+    *pLm = NULL;
+}
+
+void *lmAlloc(struct lm *lm, size_t size)
+/* Allocate memory from local pool. */
+{
+struct lmBlock *mb = lm->blocks;
+void *ret;
+size_t memLeft = mb->end - mb->free;
+if (memLeft < size)
+    mb = newBlock(lm, size);
+ret = mb->free;
+mb->free += ((size+lm->allignAdd)&lm->allignMask);
+if (mb->free > mb->end)
+    mb->free = mb->end;
+return ret;
+}
+
+void *lmCloneMem(struct lm *lm, void *pt, size_t size)
+/* Return a local mem copy of memory block. */
+{
+void *d = lmAlloc(lm, size);
+memcpy(d, pt, size);
+return d;
+}
+
+char *lmCloneStringZ(struct lm *lm, char *string, int size)
+/* Return local mem copy of string. */
+{
+if (string == NULL)
+    return NULL;
+else
+    {
+    char *s = lmAlloc(lm, size+1);
+    memcpy(s, string, size);
+    return s;
+    }
+}
+
+char *lmCloneString(struct lm *lm, char *string)
+/* Return local mem copy of string. */
+{
+if (string == NULL)
+    return NULL;
+else
+    return lmCloneStringZ(lm, string, strlen(string));
+}
+
+char *lmCloneFirstWord(struct lm *lm, char *line)
+/* Clone first word in line */
+{
+char *startFirstWord = skipLeadingSpaces(line);
+if (startFirstWord == NULL)
+    return NULL;
+char *endFirstWord = skipToSpaces(startFirstWord);
+if (endFirstWord == NULL)
+    return lmCloneString(lm, startFirstWord);
+else
+    return lmCloneStringZ(lm, startFirstWord, endFirstWord - startFirstWord);
+}
+    
+char *lmCloneSomeWord(struct lm *lm, char *line, int wordIx)
+/* Return a clone of the given space-delimited word within line.  Returns NULL if
+ * not that many words in line. */
+{
+if (wordIx < 0)
+    return NULL;
+int i;
+for (i=0; i<wordIx; ++i)
+    {
+    line = skipLeadingSpaces(line);
+    line = skipToSpaces(line);
+    if (line == NULL)
+        return NULL;
+    }
+return lmCloneFirstWord(lm, line);
+}
+
+
+struct slName *lmSlName(struct lm *lm, char *name)
+/* Return slName in memory. */
+{
+struct slName *n;
+int size = sizeof(*n) + strlen(name) + 1;
+n = lmAlloc(lm, size);
+strcpy(n->name, name);
+return n;
+}
+
diff --git a/lib/log.c b/lib/log.c
new file mode 100644
index 0000000..0ad9b32
--- /dev/null
+++ b/lib/log.c
@@ -0,0 +1,343 @@
+/* log.c - logging for servers, can log to a file and/or syslog.  Compile with
+ * -DNO_SYSLOG for systems without syslog. */
+
+#include "common.h"
+#include "log.h"
+#include "errabort.h"
+#include "dystring.h"
+#include "options.h"
+#include "portable.h"
+
+#ifndef NO_SYSLOG
+#include <syslog.h>
+#endif
+#include <time.h>
+
+
+static char *gProgram = "unknown";  /* name of program */
+static boolean gSysLogOn = FALSE;   /* syslog logging enabled? */
+static FILE *gLogFh = NULL;         /* logging file */
+
+struct nameVal
+/* pair of string name and integer value */
+{
+    char *name;
+    int val;
+};
+
+#ifndef NO_SYSLOG
+
+static struct nameVal facilityNameTbl[] =
+/* not all version of syslog have the facilitynames table, so  define our own */
+{
+    {"auth",         LOG_AUTH},
+#ifdef LOG_AUTHPRIV
+    {"authpriv",     LOG_AUTHPRIV},
+#endif
+    {"cron",         LOG_CRON},
+    {"daemon",       LOG_DAEMON},
+#ifdef LOG_FTP
+    {"ftp",          LOG_FTP},
+#endif
+    {"kern",         LOG_KERN},
+    {"lpr",          LOG_LPR},
+    {"mail",         LOG_MAIL},
+    {"news",         LOG_NEWS},
+    {"syslog",       LOG_SYSLOG},
+    {"user",         LOG_USER},
+#ifdef LOG_UUCP
+    {"uucp",         LOG_UUCP},
+#endif
+    {"local0",       LOG_LOCAL0},
+    {"local1",       LOG_LOCAL1},
+    {"local2",       LOG_LOCAL2},
+    {"local3",       LOG_LOCAL3},
+    {"local4",       LOG_LOCAL4},
+    {"local5",       LOG_LOCAL5},
+    {"local6",       LOG_LOCAL6},
+    {"local7",       LOG_LOCAL7},
+    {NULL,           0}
+};
+#endif
+
+/* Priority numbers and names used for setting minimum priority to log.  This
+ * is kept independent of syslog, so it works on file logging too.  */
+#define	PRI_EMERG	0
+#define	PRI_ALERT	1
+#define	PRI_CRIT	2
+#define	PRI_ERR		3
+#define	PRI_WARNING	4
+#define	PRI_NOTICE	5
+#define	PRI_INFO	6
+#define	PRI_DEBUG	7
+
+static struct nameVal priorityNameTbl[] = {
+    {"panic", PRI_EMERG},
+    {"emerg", PRI_EMERG},
+    {"alert", PRI_ALERT},
+    {"crit", PRI_CRIT},
+    {"err", PRI_ERR},
+    {"error", PRI_ERR},
+    {"warn", PRI_WARNING},
+    {"warning", PRI_WARNING},
+    {"notice", PRI_NOTICE},
+    {"info", PRI_INFO},
+    {"debug", PRI_DEBUG},
+    {NULL, -1}
+    };
+
+static int gMinPriority = PRI_INFO;  // minimum priority to log (reverse numbering)
+
+static int nameValTblFind(struct nameVal *tbl, char *name)
+/* search a nameVal table, return -1 if not found */
+{
+int i;
+for (i = 0; tbl[i].name != NULL; i++)
+    {
+    if (sameString(tbl[i].name, name))
+        return tbl[i].val;
+    }
+return -1;
+}
+
+static char *nameValTblMsg(struct nameVal *tbl)
+/* generate a message for values in table */
+{
+struct dyString *msg = dyStringNew(256);
+int i;
+for (i = 0; tbl[i].name != NULL; i++)
+    {
+    if (i > 0)
+        dyStringAppend(msg, ", ");
+    dyStringAppend(msg, tbl[i].name);
+    }
+return dyStringCannibalize(&msg);
+}
+
+static void logWarnHandler(char *format, va_list args)
+/* Warn handler that logs message. */
+{
+if (isErrAbortInProgress())
+    logErrorVa(format, args);
+else
+    logWarnVa(format, args);
+}
+
+static void logAbortHandler()
+/* abort handler that logs this fact and exits. */
+{
+logError("%s aborted", gProgram);
+fprintf(stderr, "aborted");
+exit(1);
+}
+
+static void setProgram(char* program)
+/* set the program name, removing leading directories from file */
+{
+char name[128], ext[64];
+int len;
+splitPath(program, NULL, name, ext);
+len = strlen(name) + strlen(ext) + 1;
+gProgram = needMem(len);
+strcpy(gProgram, name);
+if (ext[0] != '\0')
+    strcat(gProgram, ext); /* includes dot */
+}
+
+#ifndef NO_SYSLOG
+static int parseFacility(char *facility)
+/* parse a facility name into a number, or use default if NULL. */
+{
+if (facility == NULL)
+    return LOG_LOCAL0;
+int val = nameValTblFind(facilityNameTbl, facility);
+if (val < 0)
+    errAbort("invalid log facility: %s, expected one of: %s", facility, nameValTblMsg(facilityNameTbl));
+return val;
+}
+#endif
+
+static int parsePriority(char *pri)
+/* parse a priority name into a number, or use default if NULL. */
+{
+if (pri == NULL)
+    return PRI_INFO;
+int val = nameValTblFind(priorityNameTbl, pri);
+if (val < 0)
+    errAbort("invalid log priority: %s, expected one of: %s", pri, nameValTblMsg(priorityNameTbl));
+return val;
+}
+
+void logOpenSyslog(char* program, char *facility)
+/* Initialize syslog using the specified facility.  Facility is the syslog
+ * facility as specified in syslog.conf.  If facility is NULL, local0 is used.
+ * This adds a warn and errAbort handlers that do logging.  If custom handlers
+ * are added, they should call logErrorVa().
+ */
+{
+#ifndef NO_SYSLOG
+setProgram(program);
+openlog(program, LOG_PID, parseFacility(facility));
+pushWarnHandler(logWarnHandler);
+pushAbortHandler(logAbortHandler);
+gSysLogOn = TRUE;
+#else
+errAbort("syslog support was not compiled into %s", __FILE__);
+#endif
+}
+
+void logOpenFile(char* program, char *logFile)
+/* Initialize logging to the specified file.  Append to the file if it exists.
+ * This adds a warn and errAbort handlers that do logging.  If custom handlers
+ * are added, they should call logErrorVa().
+ */
+{
+setProgram(program);
+gLogFh = mustOpen(logFile, "a");
+pushWarnHandler(logWarnHandler);
+pushAbortHandler(logAbortHandler);
+}
+
+void logSetMinPriority(char *minPriority)
+/* set minimum priority to log, which is one of the syslog priority names,
+ * even when logging to a file */
+{
+gMinPriority = parsePriority(minPriority);
+}
+
+FILE *logGetFile()
+/* Returns the log FILE object if file logging is enabled, or NULL if it
+ * isn't. This is useful for logging debugging data that doesn't fit the log
+ * message paradigm, For example, logging fasta records. */
+{
+return gLogFh;
+}
+
+static void logFilePrint(char* level, char *format, va_list args)
+/* write a message to the log file */
+{
+static char *timeFmt = "%Y/%m/%d %H:%M:%S";
+char timeBuf[128];
+time_t curTime = time(NULL);
+strftime(timeBuf, sizeof(timeBuf), timeFmt, localtime(&curTime));
+fprintf(gLogFh, "%s: %s: ", timeBuf, level);
+vfprintf(gLogFh, format, args);
+fputc('\n', gLogFh);
+fflush(gLogFh);
+}
+
+void logErrorVa(char *format, va_list args)
+/* Variable args logError. */
+{
+if (gMinPriority >= PRI_ERR)
+    {
+#ifndef NO_SYSLOG
+    if (gSysLogOn)
+        vsyslog(LOG_ERR, format, args);
+#endif
+    if (gLogFh != NULL)
+        logFilePrint("error", format, args);
+    }
+}
+
+void logError(char *format, ...)
+/* Log an error message. */
+{
+va_list args;
+va_start(args, format);
+logErrorVa(format, args);
+va_end(args);
+}
+
+void logWarnVa(char *format, va_list args)
+/* Variable args logWarn. */
+{
+if (gMinPriority >= PRI_WARNING)
+    {
+#ifndef NO_SYSLOG
+    if (gSysLogOn)
+        vsyslog(LOG_WARNING, format, args);
+#endif
+    if (gLogFh != NULL)
+        logFilePrint("warn", format, args);
+    }
+}
+
+void logWarn(char *format, ...)
+/* Log a warn message. */
+{
+va_list args;
+va_start(args, format);
+logWarnVa(format, args);
+va_end(args);
+}
+
+void logInfoVa(char *format, va_list args)
+/* Variable args logInfo. */
+{
+if (gMinPriority >= PRI_INFO)
+    {
+#ifndef NO_SYSLOG
+    if (gSysLogOn)
+        vsyslog(LOG_INFO, format, args);
+#endif
+    if (gLogFh != NULL)
+        logFilePrint("info", format, args);
+    }
+}
+
+void logInfo(char *format, ...)
+/* Log an info message. */
+{
+va_list args;
+va_start(args, format);
+logInfoVa(format, args);
+va_end(args);
+}
+
+void logDebugVa(char *format, va_list args)
+/* Variable args logDebug. */
+{
+if (gMinPriority >= PRI_DEBUG)
+    {
+#ifndef NO_SYSLOG
+    if (gSysLogOn)
+        vsyslog(LOG_DEBUG, format, args);
+#endif
+    if (gLogFh != NULL)
+        logFilePrint("debug", format, args);
+    }
+}
+
+void logDebug(char *format, ...)
+/* Log a debug message. */
+{
+va_list args;
+va_start(args, format);
+logDebugVa(format, args);
+va_end(args);
+}
+
+void logDaemonize(char *progName)
+/* daemonize parasol server process, closing open file descriptors and
+ * starting logging based on the -logFacility and -log command line options .
+ * if -debug is supplied , don't fork. */
+{
+if (!optionExists("debug"))
+    {
+    int i, maxFiles = getdtablesize();
+    if (mustFork() != 0)
+        exit(0);  /* parent goes away */
+
+    /* Close all open files first (before logging) */
+    for (i = 0; i < maxFiles; i++)
+        close(i);
+    }
+
+/* Set up log handler. */
+if (optionExists("log"))
+    logOpenFile(progName, optionVal("log", NULL));
+else    
+    logOpenSyslog(progName, optionVal("logFacility", NULL));
+}
+
diff --git a/lib/maf.c b/lib/maf.c
new file mode 100644
index 0000000..5f5dd0d
--- /dev/null
+++ b/lib/maf.c
@@ -0,0 +1,888 @@
+/* maf.c - Read/write maf format. */
+#include "common.h"
+#include "linefile.h"
+#include "errabort.h"
+#include "obscure.h"
+#include "dnautil.h"
+#include "axt.h"
+#include "maf.h"
+#include "hash.h"
+#include <fcntl.h>
+
+
+char *mafRegDefTxUpstream = "txupstream";  // transcription start size upstream region
+
+struct mafFile *mafMayOpen(char *fileName)
+/* Open up a maf file and verify header. */
+{
+struct mafFile *mf;
+struct lineFile *lf;
+char *line, *word;
+char *sig = "##maf";
+
+if ((lf = lineFileMayOpen(fileName, TRUE)) == NULL)
+    return NULL;
+AllocVar(mf);
+mf->lf = lf;
+
+lineFileNeedNext(lf, &line, NULL);
+if (!startsWith(sig, line))
+    {
+    errAbort("%s does not start with %s", fileName, sig);
+    }
+line += strlen(sig);
+
+while ((word = nextWord(&line)) != NULL)
+    {
+    /* Parse name=val. */
+    char *name = word;
+    char *val = strchr(word, '=');
+    if (val == NULL)
+       errAbort("Missing = after %s line 1 of %s\n", name, fileName);
+    *val++ = 0;
+
+    if (sameString(name, "version"))
+        mf->version = atoi(val);
+    else if (sameString(name, "scoring"))
+        mf->scoring = cloneString(val);
+    }
+if (mf->version == 0)
+    errAbort("No version line 1 of %s\n", fileName);
+return mf;
+}
+
+struct mafFile *mafOpen(char *fileName)
+/* Open up a maf file.  Squawk and die if there's a problem. */
+{
+struct mafFile *mf = mafMayOpen(fileName);
+if (mf == NULL)
+    errnoAbort("Couldn't open %s\n", fileName);
+return mf;
+}
+
+void mafRewind(struct mafFile *mf)
+/* Seek to beginning of open maf file */
+{
+if (mf == NULL)
+    errAbort("maf file rewind failed -- file not open");
+lineFileSeek(mf->lf, 0, SEEK_SET);
+}
+
+static boolean nextLine(struct lineFile *lf, char **pLine)
+/* Get next line that is not a comment. */
+{
+for (;;)
+    {
+    if (!lineFileNext(lf, pLine, NULL))
+        return FALSE;
+    if (**pLine != '#')
+        return TRUE;
+    }
+}
+
+static void mafRegDefParse(struct mafFile *mf, struct mafAli *ali, char *line)
+/* parse a 'r' line of an 'a' paragraph. */
+{
+if (ali->regDef != NULL)
+    errAbort("multiple 'r' lines in an alignment paragraph: %d of %s", mf->lf->lineIx, mf->lf->fileName);
+char *row[3];
+int wordCount = chopByWhite(line, row, ArraySize(row));
+if (wordCount != 3)
+    lineFileExpectWords(mf->lf, 3+1, wordCount+1); // +1 for 'r'
+ali->regDef = mafRegDefNew(row[0], lineFileNeedFullNum(mf->lf, row, 1),
+                           row[2]);
+}
+
+struct mafAli *mafNextWithPos(struct mafFile *mf, off_t *retOffset)
+/* Return next alignment in FILE or NULL if at end.  If retOffset is
+ * nonNULL, return start offset of record in file. */
+{
+struct lineFile *lf = mf->lf;
+struct mafAli *ali;
+char *line, *word;
+
+/* Loop until get an alignment paragraph or reach end of file. */
+for (;;)
+    {
+    /* Get alignment header line.  If it's not there assume end of file. */
+    if (!nextLine(lf, &line))
+	{
+	lineFileClose(&mf->lf);
+	return NULL;
+	}
+
+    /* Parse alignment header line. */
+    word = nextWord(&line);
+    if (word == NULL)
+	continue;	/* Ignore blank lines. */
+	
+    if (sameString(word, "a"))
+	{
+	if (retOffset != NULL)
+	    *retOffset = lineFileTell(mf->lf);
+	AllocVar(ali);
+	while ((word = nextWord(&line)) != NULL)
+	    {
+	    /* Parse name=val. */
+	    char *name = word;
+	    char *val = strchr(word, '=');
+	    if (val == NULL)
+	       errAbort("Missing = after %s line 1 of %s", name, lf->fileName);
+	    *val++ = 0;
+
+	    if (sameString(name, "score"))
+		ali->score = atof(val);
+	    }
+
+	/* Parse alignment components until blank line. */
+	for (;;)
+	    {
+	    if (!nextLine(lf, &line))
+		break;
+	    word = nextWord(&line);
+	    if (word == NULL)
+		break;
+	    if (sameString(word, "s") || sameString(word, "e"))
+		{
+		struct mafComp *comp;
+		int wordCount;
+		char *row[7];
+		int textSize;
+
+		/* Chop line up by white space.  This involves a few +-1's because
+		 * have already chopped out first word. */
+		row[0] = word;
+		wordCount = chopByWhite(line, row+1, ArraySize(row)-1) + 1; /* +-1 because of "s" */
+		lineFileExpectWords(lf, ArraySize(row), wordCount);
+		AllocVar(comp);
+
+		/* Convert ascii text representation to mafComp structure. */
+		comp->src = cloneString(row[1]);
+		comp->srcSize = lineFileNeedNum(lf, row, 5);
+		comp->strand = row[4][0];
+		comp->start = lineFileNeedNum(lf, row, 2);
+
+		if (sameString(word, "e"))
+		    {
+		    comp->size = 0;
+		    comp->rightLen = comp->leftLen = lineFileNeedNum(lf, row, 3);
+		    comp->rightStatus = comp->leftStatus = *row[6];
+		    }
+		else
+		    {
+		    comp->size = lineFileNeedNum(lf, row, 3);
+		    comp->text = cloneString(row[6]);
+		    textSize = strlen(comp->text);
+
+		    /* Fill in ali->text size. */
+		    if (ali->textSize == 0)
+			ali->textSize = textSize;
+		    else if (ali->textSize != textSize)
+			errAbort("Text size inconsistent (%d vs %d) line %d of %s",
+			    textSize, ali->textSize, lf->lineIx, lf->fileName);
+		    }
+
+		/* Do some sanity checking. */
+		if (comp->srcSize < 0 || comp->size < 0)
+		     errAbort("Got a negative size line %d of %s", lf->lineIx, lf->fileName);
+		if (comp->start < 0 || comp->start + comp->size > comp->srcSize)
+		     errAbort("Coordinates out of range line %d of %s", lf->lineIx, lf->fileName);
+		  
+		/* Add component to head of list. */
+		slAddHead(&ali->components, comp);
+		}
+	    if (sameString(word, "i"))
+		{
+		struct mafComp *comp;
+		int wordCount;
+		char *row[6];
+
+		/* Chop line up by white space.  This involves a few +-1's because
+		 * have already chopped out first word. */
+		row[0] = word;
+		wordCount = chopByWhite(line, row+1, ArraySize(row)-1) + 1; /* +-1 because of "s" */
+		lineFileExpectWords(lf, ArraySize(row), wordCount);
+		if (!sameString(row[1],ali->components->src))
+		    errAbort("i line src mismatch: i is %s :: s is %s\n", row[1], ali->components->src);
+
+		comp = ali->components;
+		comp->leftStatus = *row[2];
+		comp->leftLen = atoi(row[3]);
+		comp->rightStatus = *row[4];
+		comp->rightLen = atoi(row[5]);
+		}
+            if (sameString(word, "q"))
+		{
+		struct mafComp *comp;
+		int wordCount;
+		char *row[3];
+
+		/* Chop line up by white space.  This involves a few +-1's because
+		 * have already chopped out first word. */
+		row[0] = word;
+		wordCount = chopByWhite(line, row+1, ArraySize(row)-1) + 1; /* +-1 because of "s" */
+		lineFileExpectWords(lf, ArraySize(row), wordCount);
+		if (!sameString(row[1],ali->components->src))
+		    errAbort("q line src mismatch: q is %s :: s is %s\n", row[1], ali->components->src);
+
+			comp = ali->components;
+			comp->quality = cloneString(row[2]);
+		}
+	    if (sameString(word, "r"))
+                mafRegDefParse(mf, ali, line);
+	    }
+	slReverse(&ali->components);
+	return ali;
+	}
+    else  /* Skip over paragraph we don't understand. */
+	{
+	for (;;)
+	    {
+	    if (!nextLine(lf, &line))
+		return NULL;
+            if (nextWord(&line) == NULL)
+		break;
+	    }
+	}
+    }
+}
+
+
+struct mafAli *mafNext(struct mafFile *mf)
+/* Return next alignment in FILE or NULL if at end. */
+{
+return mafNextWithPos(mf, NULL);
+}
+
+
+struct mafFile *mafReadAll(char *fileName)
+/* Read all elements in a maf file */
+{
+struct mafFile *mf = mafOpen(fileName);
+struct mafAli *ali;
+while ((ali = mafNext(mf)) != NULL)
+    {
+    slAddHead(&mf->alignments, ali);
+    }
+slReverse(&mf->alignments);
+return mf;
+}
+
+void mafWriteStart(FILE *f, char *scoring)
+/* Write maf header and scoring scheme name (may be null) */
+{
+fprintf(f, "##maf version=1");
+if (scoring != NULL)
+    fprintf(f, " scoring=%s", scoring);
+fprintf(f, "\n");
+}
+
+
+void mafWrite(FILE *f, struct mafAli *ali)
+/* Write next alignment to file. */
+{
+struct mafComp *comp;
+int srcChars = 0, startChars = 0, sizeChars = 0, srcSizeChars = 0;
+
+/* Write out alignment header */
+fprintf(f, "a score=%f\n", ali->score);
+
+/* include region definition */
+if (ali->regDef != NULL)
+    fprintf(f, "r %s %d %s\n", ali->regDef->type, ali->regDef->size, ali->regDef->id);
+
+/* Figure out length of each field. */
+for (comp = ali->components; comp != NULL; comp = comp->next)
+    {
+    int len = 0;
+    /* a name like '.' will break some tools, so replace it
+    * with a generic name */
+    if (sameString(comp->src,"."))
+	comp->src=cloneString("defaultName");
+    len = strlen(comp->src);
+    if (srcChars < len)
+        srcChars = len;
+    len = digitsBaseTen(comp->start);
+    if (startChars < len)
+        startChars = len;
+    len = digitsBaseTen(comp->size);
+    if (sizeChars < len)
+        sizeChars = len;
+    len = digitsBaseTen(comp->srcSize);
+    if (srcSizeChars < len)
+        srcSizeChars = len;
+    }
+
+/* Write out each component. */
+for (comp = ali->components; comp != NULL; comp = comp->next)
+    {
+    if ((comp->size == 0) && (comp->leftStatus))
+	fprintf(f, "e %-*s %*d %*d %c %*d %c\n", 
+	    srcChars, comp->src, startChars, comp->start, 
+	    sizeChars, comp->leftLen, comp->strand, 
+	    srcSizeChars, comp->srcSize, comp->leftStatus);
+    else
+	{
+	fprintf(f, "s %-*s %*d %*d %c %*d %s\n", 
+	    srcChars, comp->src, startChars, comp->start, 
+	    sizeChars, comp->size, comp->strand, 
+	    srcSizeChars, comp->srcSize, comp->text);
+
+	if (comp->quality)
+		fprintf(f, "q %-*s %s\n",
+		srcChars + startChars + sizeChars + srcSizeChars + 5,
+		comp->src, comp->quality);
+
+	if (comp->leftStatus)
+	    fprintf(f,"i %-*s %c %d %c %d\n",srcChars,comp->src,
+		comp->leftStatus,comp->leftLen,comp->rightStatus,comp->rightLen);
+	}
+
+    }
+
+/* Write out blank separator line. */
+fprintf(f, "\n");
+}
+
+void mafWriteEnd(FILE *f)
+/* Write maf footer. In this case nothing */
+{
+}
+
+void mafWriteAll(struct mafFile *mf, char *fileName)
+/* Write out full mafFile. */
+{
+FILE *f = mustOpen(fileName, "w");
+struct mafAli *ali;
+mafWriteStart(f, mf->scoring);
+for (ali = mf->alignments; ali != NULL; ali = ali->next)
+    mafWrite(f, ali);
+mafWriteEnd(f);
+carefulClose(&f);
+}
+
+void mafCompFree(struct mafComp **pObj)
+/* Free up a maf component. */
+{
+struct mafComp *obj = *pObj;
+if (obj == NULL)
+    return;
+freeMem(obj->src);
+freeMem(obj->text);
+freeMem(obj->quality);
+freez(pObj);
+}
+
+void mafCompFreeList(struct mafComp **pList)
+/* Free up a list of maf components. */
+{
+struct mafComp *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    mafCompFree(&el);
+    }
+*pList = NULL;
+}
+
+char *mafCompGetSrcDb(struct mafComp *mc, char *buf, int bufSize)
+/* parse the srcDb name from the mafComp src name, return NULL if no srcDb */
+{
+char *e = strchr(mc->src, '.');
+if (e == NULL)
+    return NULL;
+int len = e - mc->src;
+if (len >= bufSize-1)
+    errAbort("srcDb name in \"%s\" overflows buffer length of %d", mc->src, bufSize);
+strncpy(buf, mc->src, len);
+buf[len] = '\0';
+return buf;
+}
+
+char *mafCompGetSrcName(struct mafComp *mc)
+/* parse the src sequence name from the mafComp src name */
+{
+char *e = strchr(mc->src, '.');
+if (e == NULL)
+    return mc->src;
+else
+    return e+1;
+}
+
+int mafPlusStart(struct mafComp *comp)
+/* Return start relative to plus strand of src. */
+{
+if (comp->strand == '-') 
+    return comp->srcSize - (comp->start + comp->size);
+else
+    return comp->start;
+}
+
+void mafAliFree(struct mafAli **pObj)
+/* Free up a maf alignment. */
+{
+struct mafAli *obj = *pObj;
+if (obj == NULL)
+    return;
+mafCompFreeList(&obj->components);
+mafRegDefFree(&obj->regDef);
+freez(pObj);
+}
+
+void mafAliFreeList(struct mafAli **pList)
+/* Free up a list of maf alignmentx. */
+{
+struct mafAli *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    mafAliFree(&el);
+    }
+*pList = NULL;
+}
+
+void mafFileFree(struct mafFile **pObj)
+/* Free up a maf file. */
+{
+struct mafFile *obj = *pObj;
+if (obj == NULL)
+    return;
+lineFileClose(&obj->lf);
+freeMem(obj->scoring);
+mafAliFreeList(&obj->alignments);
+freez(pObj);
+}
+
+void mafFileFreeList(struct mafFile **pList)
+/* Free up a list of maf files. */
+{
+struct mafFile *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    mafFileFree(&el);
+    }
+*pList = NULL;
+}
+
+struct mafComp *mafMayFindComponent(struct mafAli *maf, char *src)
+/* Find component of given source. Return NULL if not found. */
+{
+struct mafComp *mc;
+for (mc = maf->components; mc != NULL; mc = mc->next)
+    {
+    if (sameString(mc->src, src))
+        return mc;
+    }
+return NULL;
+}
+
+struct mafComp *mafMayFindComponentDb(struct mafAli *maf, char *db)
+/* Find component of given database, allowing component to be 
+ * labeled "db", or "db.chrom" . Return NULL if not found. */
+{
+struct mafComp *mc;
+char *p, *q;
+for (mc = maf->components; mc != NULL; mc = mc->next)
+    {
+    for (p = mc->src, q = db; *p && *q; p++, q++)
+        {
+        if (*p != *q)
+            break;
+        }
+    if (*p == '.' && *q == 0)
+        return mc;
+    if (*p == *q)
+        return mc;
+    }
+return NULL;
+}
+
+struct mafComp *mafFindComponent(struct mafAli *maf, char *src)
+/* Find component of given source or die trying. */
+{
+struct mafComp *mc = mafMayFindComponent(maf, src);
+if (mc == NULL)
+    errAbort("Couldn't find %s in maf", src);
+return mc;
+}
+
+struct mafComp *mafMayFindCompSpecies(struct mafAli *maf, char *species, char sepChar)
+/* Find component of given source that starts with species possibly followed by sepChar or \0 .
+   Return NULL if not found. */
+{
+struct mafComp *mc;
+int speciesLen = strlen(species);
+
+for (mc = maf->components; mc != NULL; mc = mc->next)
+    {
+    if (startsWith(species, mc->src) )
+	{
+	char endChar = mc->src[speciesLen];
+
+	if ((endChar == '\0') || (endChar == sepChar))
+	    return mc;
+	}
+    }
+return NULL;
+}
+
+
+struct mafComp *mafFindCompSpecies(struct mafAli *maf, char *species, char sepChar)
+/* Find component of given source that starts with species followed by sepChar
+   or die trying. */
+{
+struct mafComp *mc = mafMayFindCompSpecies(maf, species, sepChar);
+if (mc == NULL)
+    errAbort("Couldn't find %s%c or just %s... in maf", species,sepChar,species);
+return mc;
+}
+
+struct mafComp *mafMayFindCompPrefix(struct mafAli *maf, char *pre, char *sep)
+/* Find component of given source that starts with pre followed by sep.
+   Return NULL if not found. */
+{
+struct mafComp *mc;
+char prefix[256];
+
+if (sep == NULL)
+    sep = "";
+snprintf(prefix, 256, "%s%s", pre, sep);
+
+for (mc = maf->components; mc != NULL; mc = mc->next)
+    {
+    if (startsWith(prefix, mc->src))
+        return mc;
+    }
+return NULL;
+}
+
+struct mafComp *mafFindCompPrefix(struct mafAli *maf, char *pre, char *sep)
+/* Find component of given source that starts with pre followed by sep
+   or die trying. */
+{
+struct mafComp *mc = mafMayFindCompPrefix(maf, pre, sep);
+if (mc == NULL)
+    errAbort("Couldn't find %s%s... in maf", pre,sep);
+return mc;
+}
+
+struct mafComp *mafMayFindComponentInHash(struct mafAli *maf, struct hash *cHash) 
+/* Find arbitrary component of given source that matches any string in the cHash.
+   Return NULL if not found. */
+{
+struct mafComp *mc;
+
+for (mc = maf->components; mc != NULL; mc = mc->next)
+    {
+    if (hashFindVal(cHash, mc->src))
+        return mc;
+    }
+return NULL;
+}
+
+struct mafComp *mafMayFindSpeciesInHash(struct mafAli *maf, struct hash *cHash, char sepChar) 
+/* Find arbitrary component of given who's source prefix (ended by sep)
+   matches matches any string in the cHash.  Return NULL if not found. */
+{
+struct mafComp *mc;
+
+for (mc = maf->components; mc != NULL; mc = mc->next)
+    {
+    char *sep = strchr(mc->src, sepChar);
+    if (sep != NULL)
+        *sep = '\0';
+    boolean hit = hashFindVal(cHash, mc->src) != NULL;
+    if (sep != NULL)
+        *sep = sepChar;
+    if (hit)
+        return mc;
+    }
+return NULL;
+}
+
+boolean mafMayFindAllComponents(struct mafAli *maf, struct hash *cHash) 
+/* Find component of given source that starts matches any string in the cHash.
+   Return NULL if not found. */
+{
+struct hashCookie cookie = hashFirst(cHash);
+struct hashEl *el;
+
+while ((el = hashNext(&cookie)) != NULL)
+    if (mafMayFindComponent(maf, el->name) == NULL)
+	return FALSE;
+return TRUE;
+}
+
+struct mafAli *mafSubset(struct mafAli *maf, char *componentSource,
+	int newStart, int newEnd)
+{
+return mafSubsetE(maf, componentSource, newStart, newEnd, FALSE);
+}
+
+struct mafAli *mafSubsetE(struct mafAli *maf, char *componentSource,
+	int newStart, int newEnd, bool getInitialDashes)
+/* Extract subset of maf that intersects a given range
+ * in a component sequence.  The newStart and newEnd
+ * are given in the forward strand coordinates of the
+ * component sequence.  The componentSource is typically
+ * something like 'mm3.chr1'.  This will return NULL
+ * if maf does not intersect range.  The score field
+ * in the returned maf will not be filled in (since
+ * we don't know which scoring scheme to use). */
+{
+struct mafComp *mcMaster = mafFindComponent(maf, componentSource);
+struct mafAli *subset;
+struct mafComp *mc, *subMc;
+char *s, *e;
+int textStart, textSize;
+
+/* Reverse complement input range if necessary. */
+if (mcMaster->strand == '-')
+    reverseIntRange(&newStart, &newEnd, mcMaster->srcSize);
+
+/* Check if any real intersection and return NULL if not. */
+if (newStart >= newEnd)
+    return NULL;
+if (newStart >= mcMaster->start + mcMaster->size)
+    return NULL;
+if (newEnd <= mcMaster->start)
+    return NULL;
+
+/* Clip to bounds of actual data. */
+if (newStart < mcMaster->start)
+    newStart = mcMaster->start;
+if (newEnd > mcMaster->start + mcMaster->size)
+    newEnd = mcMaster->start + mcMaster->size;
+
+/* Translate position in master sequence to position in
+ * multiple alignment. */
+s = skipIgnoringDash(mcMaster->text, newStart - mcMaster->start, TRUE);
+e = skipIgnoringDash(s, newEnd - newStart, TRUE);
+textStart = s - mcMaster->text;
+textSize = e - s;
+
+if (getInitialDashes && (newStart == mcMaster->start))
+    {
+    textStart = 0;
+    textSize += s - mcMaster->text;
+    }
+
+/* Allocate subset structure and fill it in */
+AllocVar(subset);
+subset->textSize = textSize;
+for (mc = maf->components; mc != NULL; mc = mc->next)
+    {
+    AllocVar(subMc);
+    subMc->src = cloneString(mc->src);
+    subMc->srcSize = mc->srcSize;
+    subMc->strand = mc->strand;
+    if (mc->size != 0)
+        {
+        subMc->start = mc->start + countNonDash(mc->text, textStart);
+        subMc->size = countNonDash(mc->text+textStart, textSize);
+        subMc->text = cloneStringZ(mc->text + textStart, textSize);
+        if (mc->quality != NULL)
+            subMc->quality = cloneStringZ(mc->quality + textStart, textSize);
+        }
+    else
+	{
+        /* empty row annotation */
+        subMc->size = 0;
+        subMc->start = mc->start;
+	}
+
+    subMc->leftStatus = mc->leftStatus;
+    subMc->leftLen = mc->leftLen;
+    subMc->rightStatus = mc->rightStatus;
+    subMc->rightLen = mc->rightLen;
+
+    slAddHead(&subset->components, subMc);
+    }
+slReverse(&subset->components);
+return subset;
+}
+
+void mafMoveComponentToTop(struct mafAli *maf, char *componentSource)
+/* Move given component to head of component list. */
+{
+struct mafComp *mcMaster = mafFindComponent(maf, componentSource);
+slRemoveEl(&maf->components, mcMaster);
+slAddHead(&maf->components, mcMaster);
+}
+
+boolean mafNeedSubset(struct mafAli *maf, char *componentSource,
+	int newStart, int newEnd)
+/* Return TRUE if maf only partially fits between newStart/newEnd
+ * in given component. */
+{
+struct mafComp *mcMaster = mafFindComponent(maf, componentSource);
+
+/* Reverse complement input range if necessary. */
+if (mcMaster->strand == '-')
+    reverseIntRange(&newStart, &newEnd, mcMaster->srcSize);
+
+return newStart > mcMaster->start || newEnd < mcMaster->start + mcMaster->size;
+}
+
+void mafFlipStrand(struct mafAli *maf)
+/* Reverse complement maf. */
+{
+struct mafComp *mc;
+for (mc = maf->components; mc != NULL; mc = mc->next)
+    {
+    int e = mc->start + mc->size;
+    reverseIntRange(&mc->start, &e, mc->srcSize);
+    if (mc->text != NULL)
+        reverseComplement(mc->text, maf->textSize);
+	if (mc->quality != NULL)
+		reverseBytes(mc->quality, maf->textSize);
+    if (mc->strand == '-')
+        mc->strand = '+';
+    else
+        mc->strand = '-';
+    char holdStatus = mc->leftStatus;
+    mc->leftStatus = mc->rightStatus;
+    mc->rightStatus = holdStatus;
+    int holdLen = mc->leftLen;
+    mc->leftLen = mc->rightLen;
+    mc->rightLen = holdLen;
+    }
+}
+
+void mafSrcDb(char *name, char *retDb, int retDbSize)
+/* Parse out just database part of name (up to but not including
+ * first dot). If dot found, return entire name */
+{
+int len;
+char *e = strchr(name, '.');
+/* Put prefix up to dot into buf. */
+len = (e == NULL ? strlen(name) : e - name);
+if (len >= retDbSize)
+     len = retDbSize-1;
+memcpy(retDb, name, len);
+retDb[len] = 0;
+}
+
+boolean mafColumnEmpty(struct mafAli *maf, int col)
+/* Return TRUE if the column is all '-' or '.' */
+{
+assert(col < maf->textSize);
+struct mafComp *comp;
+for (comp = maf->components; comp != NULL; comp = comp->next)
+    if (comp->text != NULL)
+        {
+        char c = comp->text[col];
+        if (c != '.' && c != '-')
+            return FALSE;
+        }
+return TRUE;
+}
+
+void mafStripEmptyColumns(struct mafAli *maf)
+/* Remove columns that are all '-' or '.' from  maf. */
+{
+/* Selectively copy over non-empty columns. */
+int readIx=0, writeIx = 0;
+struct mafComp *comp;
+for (readIx=0; readIx < maf->textSize; ++readIx)
+    {
+    if (!mafColumnEmpty(maf, readIx))
+        {
+        for (comp = maf->components; comp != NULL; comp = comp->next) 
+            {
+            if(comp->text != NULL)
+                comp->text[writeIx] = comp->text[readIx];
+            if (comp->quality != NULL)
+                comp->quality[writeIx] = comp->quality[readIx];
+            }
+        ++writeIx;
+        }
+    }
+/* Zero terminate text, and update textSize. */
+for (comp = maf->components; comp != NULL; comp = comp->next)
+    {
+    if (comp->text != NULL)
+        comp->text[writeIx] = 0;
+    if (comp->quality != NULL)
+        comp->quality[writeIx] = 0;
+    }
+maf->textSize = writeIx;
+}
+
+struct mafRegDef *mafRegDefNew(char *type, int size, char *id)
+/* construct a new mafRegDef object */
+{
+struct mafRegDef *mrd;
+AllocVar(mrd);
+if (sameString(type, mafRegDefTxUpstream))
+    mrd->type = mafRegDefTxUpstream;
+else
+    errAbort("invalid mafRefDef type: %s", type);
+mrd->size = size;
+mrd->id = cloneString(id);
+return mrd;
+}
+
+void mafRegDefFree(struct mafRegDef **mrdPtr)
+/* Free a mafRegDef object */
+{
+struct mafRegDef *mrd = *mrdPtr;
+if (mrd != NULL)
+    {
+    freeMem(mrd->id);
+    freeMem(mrd);
+    *mrdPtr = NULL;
+    }
+}
+
+boolean isContigOrTandem(char status)
+/* is status MAF_CONTIG_STATUS or MAF_TANDEM_STATUS */
+{
+return ((status == MAF_CONTIG_STATUS) ||
+	(status == MAF_TANDEM_STATUS));
+}
+
+struct mafComp *mafCompClone(struct mafComp *srcComp)
+/* clone a mafComp */
+{
+struct mafComp *comp;
+AllocVar(comp);
+comp->src = cloneString(srcComp->src);
+comp->srcSize = srcComp->srcSize;
+comp->strand = srcComp->strand;
+comp->start = srcComp->start;
+comp->size = srcComp->size;
+comp->text = cloneString(srcComp->text);
+comp->quality = cloneString(srcComp->quality);
+comp->leftStatus = srcComp->leftStatus;
+comp->leftLen = srcComp->leftLen;
+comp->rightStatus = srcComp->rightStatus;
+comp->rightLen = srcComp->rightLen;
+return comp;
+}
+
+static struct mafRegDef *mafRegDefClone(struct mafRegDef *srcRegDef)
+/* clone a srcRegDef */
+{
+return mafRegDefNew(srcRegDef->type, srcRegDef->size, srcRegDef->id);
+}
+
+struct mafAli *mafAliClone(struct mafAli *srcAli)
+/* clone a mafAli */
+{
+struct mafAli *ali;
+AllocVar(ali);
+ali->score = srcAli->score;
+struct mafComp *srcComp;
+for (srcComp = srcAli->components; srcComp != NULL; srcComp = srcComp->next)
+    slAddHead(&ali->components, mafCompClone(srcComp));
+slReverse(&ali->components);
+ali->textSize = srcAli->textSize;
+if (srcAli->regDef != NULL)
+    ali->regDef = mafRegDefClone(srcAli->regDef);
+return ali;
+}
diff --git a/lib/maf.doc b/lib/maf.doc
new file mode 100644
index 0000000..4cf7eb1
--- /dev/null
+++ b/lib/maf.doc
@@ -0,0 +1,222 @@
+Specification of the Multiple Alignment Format (.maf) v1
+
+Introduction
+
+The multiple alignment format stores a series of multiple
+alignments in a format that is easy to parse and relatively
+easy to read.  We apologize for creating yet another
+multiple alignment format.  We realize that there are
+many in existence.  What motivates this format is
+to store multiple alignments at the dna level between
+entire genomes. The existing formats we are aware of
+are geared towards multiple alignments of single proteins,
+and would require considerable extension at the least to
+cope with genomic issues such as forward and reverse
+strand directions,  multiple pieces to the alignment,
+and so forth.
+
+A Simple Example
+
+Here is a simple example of a file with two alignments
+with three sequences each:
+
+##maf version=1 scoring=probability
+#mblastz 8.91 02-Jan-2005
+
+a score=0.128
+s human_hoxa 100  9 + 100257 ACA-TTACTA
+s horse_hoxa 120 10 -  98892 ACAATTGCTA
+s fugu_hoxa   88  8  + 90788 ACA--TGCTA
+
+a score=0.071
+s human_unc 9077 8 + 10998 ACAGTATT
+s horse_unc 4555 6 -  5099 ACA--ATT
+s fugu_unc  4000 4 +  4038 AC----TT
+
+
+General Structure
+
+The .maf format is line oriented. Multiple alignments each
+end with a blank line.  Each sequence in an alignment 
+is on a single line, which can get quite long. Words in
+a line are delimited by any white space. Lines 
+starting with # are considered comments.  Lines starting 
+with ## can be ignored by most programs, but contain 
+meta-data of one form or another.  
+
+The file is broken into paragraphs that terminate in a
+blank line.  Within a paragraph the first word of a line
+indicates it's type.  Each multiple alignment is in 
+a paragraph by itself that begins with an 'a' line and
+which contains an 's' line for each sequence in the
+multiple alignment.  Parsers for now should ignore
+other types of paragraphs, and other types of lines within
+an alignment paragraph. Parsers should also ignore extra
+blank lines before paragraphs.
+
+
+The First Line
+
+The first line of a .maf file begins with ##maf.  This
+word is followed by whitespace separated variable=value pairs.  
+There must *not* be white space surrounding the =.
+The currently defined variables are:
+   version - Required.  Currently set to one.
+   scoring - Optional. A name for the scoring scheme used for the
+             alignments.  The current scoring schemes are:
+	bit - roughly corresponds to blast bit values - roughly
+	      2 points per aligning base minus penalties for mismatches
+	      and inserts.
+	blastz - blastz scoring scheme - roughly 100 points per aligning
+	      base.
+	probability - some score normalized between 0 and 1.
+   program - Optional. Name of program generating alignment.
+Parsers ignore variables they do not understand.
+
+'a' Lines
+
+Each alignment begins with an 'a' line.  The 'a' is followed
+by name=value pairs.   There are no required name=value pairs.
+The currently defined variables are:
+    score - Optional. Floating point score. If this is present
+            it is good practice to also define scoring in the first 
+	    line.
+    pass - Optional.  Positive integer value.  For programs that
+           do multiple pass alignments such as blastz,
+	   this shows which pass this alignment came from.
+	   Typically the pass 1 will find the strongest alignments
+	   genome-wide,  and pass 2 will find weaker alignments
+	   between two first pass alignments.
+
+
+'s' Lines    
+
+The s lines together with the a lines define a multiple alignment.
+The s lines have the following fields which are defined by 
+position rather than name=value pairs. 
+
+  src - The name of one of the source sequences for the alignment.
+        Typically this will be the first word following the '>' in
+	a fasta file that was input to the multiple aligner.
+  start - The start of the aligning region in the source sequence.
+        This is a zero based number. If the strand field below is
+	'-' then this is the start relative to the reverse-complemented
+	source sequence.
+  size - The size of the aligning region in the source sequence.  This
+         number is equal to the number of non-dash characters in the
+	 alignment text field below.
+  strand - Either '+' or '-'.  If '-' then the alignment is to the
+         reverse complemented source.
+  srcSize - The size of the entire source sequence, not just the parts
+         involved in the alignment.
+  text - The bases (or amino acids) in the alignment and any dashes
+         as well.
+
+
+'i' Lines
+
+The i lines are optional.  They are used by the browser to display synteny
+breaks. An i line must immediately follow the s line that it describes
+(unless there is no s line for that species in the current block).
+The i lines have the following fields which are defined by 
+position rather than name=value pairs. 
+    src - The name of one of the source sequences for the alignment.
+	    This should match the s line above the i line.
+    leftStatus - the syntenic status of the alignment before us vis a vis ourselves.  
+	    Possible Values:
+	    MAF_INVERSE_STATUS		'V'
+	    MAF_INSERT_STATUS		'I'
+	    MAF_DUP_STATUS		'D'
+	    MAF_NEW_STATUS		'N'
+	    MAF_NEW_NESTED_STATUS	'n'
+	    MAF_CONTIG_STATUS		'C'
+	    MAF_TANDEM_STATUS		'T'
+            
+    leftLen - length related information for the previous alignment for the species
+    rightStatus - the syntenic status of the alignment after us vis a vis ourselves 
+	     Possible values are same as leftStatus.
+    rightLen - length related information for the following alignment for the species 
+
+'q' Lines
+
+The q lines are optional.  They are used to display quality data for a
+sequence.  Like the i lines, q lines follow the s line that it describes.
+The q lines contain the following fields:
+    src - The name of one of the source sequences for the alignment.
+          This should match the s line above the q line.
+    quality - The quality data for corresponding to the sequence on the s line.
+
+As we are generally interested in bases with low quality, the quality
+data in the maf is a compressed version of the actual quality data.
+The quality data in the maf is:
+
+    min( floor(actualy quality value/5), 9)
+
+This allows us to show more of the low-quality values.  The relationship
+between quality characters in the maf and the actualy quality value are
+summarized in the following table:
+
+    .: In Gap Q == FAKE_GAP_QUAL
+    0: 0 <= Q < 5 || Q == 98
+    1: 5 <= Q < 10
+    2: 10 <= Q < 15
+    3: 15 <= Q < 20
+    4: 20 <= Q < 25
+    5: 25 <= Q < 30
+    6: 30 <= Q < 35
+    7: 35 <= Q < 40
+    8: 40 <= Q < 45
+    9: 45 <= Q < 98
+    F: Q == 99
+
+'e' Lines
+
+The 'e' lines are optional and indicate that there isn't aligning 
+DNA for a species but that the current block is bridged by a chain 
+that connects blocks before and after this block.
+
+  src -- The name of one of the source sequences for the alignment. 
+  start -- The start of the non-aligning region in the source sequence. 
+      This is a zero-based number. If the strand field is '-' then this is 
+      the start relative to the reverse-complemented source sequence. 
+  size -- The size in base pairs of the non-aligning region in the 
+      source sequence. 
+  strand -- Either '+' or '-'. If '-', then the alignment is to the 
+      reverse-complemented source. 
+  srcSize -- The size of the entire source sequence, not just the parts 
+      involved in the alignment. alignment and any insertions (dashes) 
+      as well. 
+  status -- A character that specifies the relationship between the 
+      non-aligning sequence in this block and the sequence that appears 
+      in the previous and subsequent blocks. 
+
+The status character can be one of the following values: 
+
+  C -- the sequence before and after is contiguous implying that this 
+      region was either deleted in the source or inserted in the 
+      reference sequence. The browser draws a single line or a '-' 
+      in base mode in these blocks. 
+  I -- there are non-aligning bases in the source species between 
+      chained alignment blocks before and after this block. The 
+      browser shows a double line or '=' in base mode. 
+  M -- there are non-aligning bases in the source and more than 95% 
+      of them are Ns in the source. The browser shows a pale yellow bar. 
+  n -- there are non-aligning bases in the source and the next aligning 
+      block starts in a new chromosome or scaffold that is bridged by 
+      a chain between still other blocks. The browser shows either a 
+      single line or a double line based on how many bases are in the 
+      gap between the bridging alignments. 
+
+'r' Lines
+
+The r lines are optional.  They specify how this region of the
+MAF was defined.  A paragraph can only have one r line.  The
+first word defines the source type, with the remanded of the
+words specific to the source type.  The following source types
+are defined:
+
+   txupstream - Gene transcription start upstream regions:
+           r txupstream size geneId
+       size - is the number of bases in the region
+       geneId - gene identifier for the gene
+
diff --git a/lib/mafFromAxt.c b/lib/mafFromAxt.c
new file mode 100644
index 0000000..3841e0e
--- /dev/null
+++ b/lib/mafFromAxt.c
@@ -0,0 +1,77 @@
+/* mafFromAxt - convert a axt into maf. */
+#include "common.h"
+#include "axt.h"
+#include "maf.h"
+
+
+void mafFromAxtTemp(struct axt *axt, int tSize, int qSize,
+	struct mafAli *temp)
+/* Make a maf out of axt,  parasiting on the memory in axt.
+ * Do *not* mafFree this temp.  The memory it has in pointers
+ * is still owned by the axt.  Furthermore the next call to
+ * this function will invalidate the previous temp value.
+ * It's sort of a kludge, but quick to run and easy to implement. */
+{
+static struct mafComp qComp, tComp;
+ZeroVar(temp);
+ZeroVar(&qComp);
+ZeroVar(&tComp);
+temp->score = axt->score;
+temp->textSize = axt->symCount;
+qComp.src = axt->qName;
+qComp.srcSize = qSize;
+qComp.strand = axt->qStrand;
+qComp.start = axt->qStart;
+qComp.size = axt->qEnd - axt->qStart;
+qComp.text = axt->qSym;
+slAddHead(&temp->components, &qComp);
+tComp.src = axt->tName;
+tComp.srcSize = tSize;
+tComp.strand = axt->tStrand;
+tComp.start = axt->tStart;
+tComp.size = axt->tEnd - axt->tStart;
+tComp.text = axt->tSym;
+slAddHead(&temp->components, &tComp);
+}
+
+struct mafAli *mafFromAxt(struct axt *axt, int tSize, 
+	char *tPrefix, int qSize, char *qPrefix)
+/* Make up a maf file from axt.  Slower than mafFromAxtTemp,
+ * but the axt and maf are independent afterwards. */
+{
+struct mafAli *maf;
+struct mafComp *mc;
+char name[256];
+AllocVar(maf);
+maf->score = axt->score;
+maf->textSize = axt->symCount;
+AllocVar(mc);
+if (qPrefix == NULL)
+    mc->src = cloneString(axt->qName);
+else
+    {
+    safef(name, sizeof(name), "%s.%s", qPrefix, axt->qName);
+    mc->src = cloneString(name);
+    }
+mc->srcSize = qSize;
+mc->strand = axt->qStrand;
+mc->start = axt->qStart;
+mc->size = axt->qEnd - axt->qStart;
+mc->text = cloneStringZ(axt->qSym, axt->symCount);
+slAddHead(&maf->components, mc);
+AllocVar(mc);
+if (tPrefix == NULL)
+    mc->src = cloneString(axt->tName);
+else
+    {
+    safef(name, sizeof(name), "%s.%s", tPrefix, axt->tName);
+    mc->src = cloneString(name);
+    }
+mc->srcSize = tSize;
+mc->strand = axt->tStrand;
+mc->start = axt->tStart;
+mc->size = axt->tEnd - axt->tStart;
+mc->text = cloneStringZ(axt->tSym, axt->symCount);
+slAddHead(&maf->components, mc);
+return maf;
+}
diff --git a/lib/mafScore.c b/lib/mafScore.c
new file mode 100644
index 0000000..6c83023
--- /dev/null
+++ b/lib/mafScore.c
@@ -0,0 +1,152 @@
+/* Score mafs and subsets of maf. 
+ * This module is from Webb Miller at PSU. 
+ * Some description of maf scoring is included in hgLoadMaf.c comments*/
+
+#include "common.h"
+#include "maf.h"
+
+
+
+typedef struct gap_scores {
+	int E;
+	int O;
+} gap_scores_t;
+
+#define CLEN(s) (sizeof((s))-1)
+#define NACHARS 128
+#define SS(c,d) ss[(uchar)c][(uchar)d]
+#define GAP(w,x,y,z) gop[(gtype[w]<<6)+(gtype[x]<<4)+(gtype[y]<<2)+gtype[z]]
+#define DASH '-'
+
+typedef int ss_t[NACHARS][NACHARS];
+typedef unsigned char uchar;
+
+static ss_t ss;
+static gap_scores_t ds;
+static int gop[256], gtype[128];
+
+static const uchar nchars[] = "ACGT";
+static const int HOXD70_sym[4][4] = {
+  {  91, -114,  -31, -123 },
+  {-114,  100, -125,  -31 },
+  { -31, -125,  100, -114 },
+  {-123,  -31, -114,   91 },
+};
+
+/* DNA_scores --------------------------  substitution scoring matrix for DNA */
+static void DNA_scores(ss_t ss)
+{
+	int i, j, bad, a, b, A, B;
+
+	for (i = 0; i < NACHARS; ++i)
+		for (j = 0; j < NACHARS; ++j)
+			ss[i][j] = -100;
+	for (i = 0; i < (signed)CLEN(nchars); ++i) {
+		A = nchars[i];
+		a = tolower(A);
+		for (j = 0; j < (signed)CLEN(nchars); ++j) {
+			B = nchars[j];
+			b = tolower(B);
+			ss[A][B] = ss[a][B] = ss[A][b] = ss[a][b] =
+				HOXD70_sym[i][j];
+		}
+	}
+	bad = -1000;
+	for (i = 0; i < NACHARS; ++i)
+		ss['X'][i] = ss[i]['X'] = ss['x'][i] = ss[i]['x'] = bad;
+}
+
+
+static void gap_costs(int *gop, int *gtype, int gap_open)
+{
+	int i, X, D;
+
+	for (i = 0; i < 128; ++i)
+		gtype[i] = 0;
+	D = DASH;
+	gtype[D] = 1;
+
+	for (i = 0; i < 256; ++i)
+		gop[i] = 0;
+	X = (uchar)'A';
+	GAP(X,X,X,D) = gap_open;
+	GAP(X,X,D,X) = gap_open;
+	GAP(X,D,D,X) = gap_open;
+	GAP(D,X,X,D) = gap_open;
+	GAP(D,D,X,D) = gap_open;
+	GAP(D,D,D,X) = gap_open;
+}
+
+double mafScoreRangeMultiz(struct mafAli *maf, int start, int size)
+/* Return score of a subset of an alignment.  Parameters are:
+ *    maf - the alignment
+ *    start - the (zero based) offset to start calculating score
+ *    size - the size of the subset
+ * The following relationship should hold:
+ *   scoreRange(maf,start,size) =
+ *	scoreRange(maf,0,start+size) - scoreRange(maf,0,start)
+ */
+{
+uchar ai, ar, bi, br;
+int i;
+double score;
+struct mafComp *c1, *c2;
+
+if (start < 0 || size <= 0 || 
+    start+size > maf->textSize) {
+	errAbort( "mafScoreRange: start = %d, size = %d, textSize = %d\n",
+		start, size, maf->textSize);
+}
+if (ss['A']['A'] != HOXD70_sym[0][0]) {
+	DNA_scores(ss);
+	ds.E = 30;
+	ds.O = 400;
+	for (i = 0; i < 128; ++i)
+		ss[i][DASH] = ss[DASH][i] = -ds.E;
+	ss[DASH][DASH] = 0;
+	gap_costs(gop, gtype, ds.O);   /* quasi-natural gap costs */
+}
+score = 0.0;
+for (i = start; i < start+size; ++i) {
+	for (c1 = maf->components; c1 != NULL; c1 = c1->next) {
+		if (c1->size == 0) continue;
+		br = c1->text[i];
+		for (c2 = c1->next; c2 != NULL; c2 = c2->next) {
+			if (c2->size == 0) continue;
+			bi = c2->text[i];
+			score += SS(br, bi);
+			if (i > 0) {
+				ar = c1->text[i-1];
+				ai = c2->text[i-1];
+				score -= GAP(ar,ai,br,bi);
+			}
+		}
+	}
+}
+return score;
+}
+
+double mafScoreMultiz(struct mafAli *maf)
+/* Return score of a maf (calculated rather than what is
+ * stored in the structure. */
+{
+return mafScoreRangeMultiz(maf, 0, maf->textSize);
+}
+
+double mafScoreMultizMaxCol(int species)
+/* Return maximum possible score for a column. */
+{
+int i, count = 0;
+for (i=1; i<species; ++i)
+    count += i;
+return 100.0*count; 
+}
+
+void mafColMinMaxScore(struct mafAli *maf, 
+	double *retMin, double *retMax)
+/* Get min/max maf scores for a column. */
+{
+*retMax = mafScoreMultizMaxCol(slCount(maf->components));
+*retMin = -*retMax;
+}
+
diff --git a/lib/makefile b/lib/makefile
new file mode 100644
index 0000000..c5957c8
--- /dev/null
+++ b/lib/makefile
@@ -0,0 +1,61 @@
+include ../inc/common.mk
+
+
+O = aliType.o annoColumn.o annoFilter.o annoFormatter.o annoFormatTab.o \
+    annoGrator.o annoGratorQuery.o annoOption.o annoRow.o annoStreamer.o annoStreamVcf.o \
+    apacheLog.o asParse.o axt.o axtAffine.o bamFile.o base64.o \
+    basicBed.o bbiRead.o bbiWrite.o bigBed.o binRange.o bits.o \
+    blastOut.o blastParse.o boxClump.o boxLump.o bPlusTree.o \
+    bwgCreate.o bwgQuery.o bwgValsOnChrom.o \
+    cda.o chain.o chainBlock.o chainConnect.o chainToAxt.o chainToPsl.o \
+    cheapcgi.o cirTree.o codebias.o colHash.o common.o correlate.o crTree.o \
+    dgRange.o diGraph.o dlist.o dnaLoad.o dnaMarkov.o dnaMotif.o dnaseq.o \
+    dnautil.o dsPrint.o dtdParse.o dystring.o \
+    emblParse.o errCatch.o errabort.o \
+    fa.o ffAli.o ffScore.o filePath.o fixColor.o flydna.o fof.o \
+    font/mgCourier10.o font/mgCourier12.o font/mgCourier14.o font/mgCourier18.o \
+    font/mgCourier24.o font/mgCourier34.o font/mgCourier8.o font/mgHelvetica10.o \
+    font/mgHelvetica12.o font/mgHelvetica14.o font/mgHelvetica18.o font/mgHelvetica24.o \
+    font/mgHelvetica34.o font/mgHelvetica8.o font/mgHelveticaBold10.o font/mgHelveticaBold12.o \
+    font/mgHelveticaBold14.o font/mgHelveticaBold18.o font/mgHelveticaBold24.o \
+    font/mgHelveticaBold34.o font/mgHelveticaBold8.o font/mgSixhi6.o font/mgSail8.o \
+    font/mgTimes10.o font/mgTimes12.o font/mgTimes14.o font/mgTimes18.o \
+    font/mgTimes24.o font/mgTimes34.o font/mgTimes8.o font/mgMenlo12.o \
+    fuzzyShow.o \
+    gapCalc.o gdf.o gemfont.o genomeRangeTree.o \
+    gfNet.o gff.o gff3.o gfxPoly.o gifLabel.o \
+    hacTree.o hash.o histogram.o hmmPfamParse.o hmmstats.o htmlPage.o htmshell.o \
+    https.o intExp.o intValTree.o internet.o itsa.o iupac.o \
+    jointalign.o jpegSize.o keys.o knetUdc.o kxTok.o linefile.o lineFileOnBigBed.o localmem.o log.o \
+    maf.o mafFromAxt.o mafScore.o md5.o memalloc.o memgfx.o metaWig.o mgCircle.o \
+    mgPolygon.o mime.o net.o nib.o nibTwo.o nt4.o numObscure.o \
+    obscure.o oldGff.o oligoTm.o options.o osunix.o pairHmm.o peakCluster.o \
+    phyloTree.o pipeline.o portimpl.o pngwrite.o psGfx.o psPoly.o pscmGfx.o \
+    psl.o pslGenoShow.o pslShow.o pslTbl.o pslTransMap.o pthreadWrap.o \
+    qa.o quickHeap.o quotedP.o \
+    ra.o rainbow.o rbTree.o rangeTree.o regexHelper.o repMask.o \
+    rle.o rnautil.o rqlEval.o rqlParse.o rudp.o \
+    scoreWindow.o seg.o seqOut.o seqStats.o servBrcMcw.o servCrunx.o \
+    servcis.o servcl.o servmsII.o servpws.o shaRes.o slog.o snof.o \
+    snofmake.o snofsig.o spaceSaver.o spacedColumn.o spacedSeed.o \
+    splatAli.o sqlList.o sqlNum.o subText.o sufa.o sufx.o synQueue.o \
+    tabRow.o textOut.o tokenizer.o trix.o twoBit.o \
+    udc.o vcf.o vGfx.o vPng.o verbose.o \
+    wildcmp.o wormdna.o \
+    xAli.o xa.o xap.o xenshow.o xmlEscape.o xp.o zlibFace.o
+
+$(MACHTYPE)/jkweb.a: $(O) $(MACHTYPE)
+	ar rcus $(MACHTYPE)/jkweb.a $(O)
+
+$(MACHTYPE):
+	mkdir $(MACHTYPE)
+
+test:
+	cd tests && ${MAKE} test
+
+clean:
+	rm -f ${O} $(MACHTYPE)/jkweb.a
+	cd tests && ${MAKE} clean
+
+tags:
+	etags ../inc/*.h ../lib/*.h ../lib/*.c  ../hg/inc/*.h ../hg/lib/*.h ../hg/lib/*.c ../hg/hgTracks/*.c ../hg/hgc/*.c ../hg/hgTrackUi/*.c
diff --git a/lib/md5.c b/lib/md5.c
new file mode 100644
index 0000000..4db7435
--- /dev/null
+++ b/lib/md5.c
@@ -0,0 +1,287 @@
+/*
+ * RFC 1321 compliant MD5 implementation,
+ * by Christophe Devine <devine at cr0.net>;
+ * this program is licensed under the GPL.
+ */
+
+#include "common.h"
+#include "md5.h"
+
+
+#define GET_UINT32(n,b,i)					\
+{								\
+    (n) = (uint32) ((uint8 *) b)[(i)]				\
+      | (((uint32) ((uint8 *) b)[(i)+1]) <<  8)			\
+      | (((uint32) ((uint8 *) b)[(i)+2]) << 16)			\
+      | (((uint32) ((uint8 *) b)[(i)+3]) << 24);		\
+}
+
+#define PUT_UINT32(n,b,i)					\
+{								\
+    (((uint8 *) b)[(i)]  ) = (uint8) (((n)      ) & 0xFF);	\
+    (((uint8 *) b)[(i)+1]) = (uint8) (((n) >>  8) & 0xFF);	\
+    (((uint8 *) b)[(i)+2]) = (uint8) (((n) >> 16) & 0xFF);	\
+    (((uint8 *) b)[(i)+3]) = (uint8) (((n) >> 24) & 0xFF);	\
+}
+
+void md5_starts( struct md5_context *ctx )
+{
+    ctx->total = 0;
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+}
+
+void md5_process( struct md5_context *ctx, uint8 data[64] )
+{
+    uint32 A, B, C, D, X[16];
+
+    GET_UINT32( X[0],  data,  0 );
+    GET_UINT32( X[1],  data,  4 );
+    GET_UINT32( X[2],  data,  8 );
+    GET_UINT32( X[3],  data, 12 );
+    GET_UINT32( X[4],  data, 16 );
+    GET_UINT32( X[5],  data, 20 );
+    GET_UINT32( X[6],  data, 24 );
+    GET_UINT32( X[7],  data, 28 );
+    GET_UINT32( X[8],  data, 32 );
+    GET_UINT32( X[9],  data, 36 );
+    GET_UINT32( X[10], data, 40 );
+    GET_UINT32( X[11], data, 44 );
+    GET_UINT32( X[12], data, 48 );
+    GET_UINT32( X[13], data, 52 );
+    GET_UINT32( X[14], data, 56 );
+    GET_UINT32( X[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define P(a,b,c,d,k,s,t)				\
+{							\
+    a += F(b,c,d) + X[k] + t; a = S(a,s) + b;		\
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+
+    P( A, B, C, D,  0,  7, 0xD76AA478 );
+    P( D, A, B, C,  1, 12, 0xE8C7B756 );
+    P( C, D, A, B,  2, 17, 0x242070DB );
+    P( B, C, D, A,  3, 22, 0xC1BDCEEE );
+    P( A, B, C, D,  4,  7, 0xF57C0FAF );
+    P( D, A, B, C,  5, 12, 0x4787C62A );
+    P( C, D, A, B,  6, 17, 0xA8304613 );
+    P( B, C, D, A,  7, 22, 0xFD469501 );
+    P( A, B, C, D,  8,  7, 0x698098D8 );
+    P( D, A, B, C,  9, 12, 0x8B44F7AF );
+    P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
+    P( B, C, D, A, 11, 22, 0x895CD7BE );
+    P( A, B, C, D, 12,  7, 0x6B901122 );
+    P( D, A, B, C, 13, 12, 0xFD987193 );
+    P( C, D, A, B, 14, 17, 0xA679438E );
+    P( B, C, D, A, 15, 22, 0x49B40821 );
+
+#undef F
+
+#define F(x,y,z) (y ^ (z & (x ^ y)))
+
+    P( A, B, C, D,  1,  5, 0xF61E2562 );
+    P( D, A, B, C,  6,  9, 0xC040B340 );
+    P( C, D, A, B, 11, 14, 0x265E5A51 );
+    P( B, C, D, A,  0, 20, 0xE9B6C7AA );
+    P( A, B, C, D,  5,  5, 0xD62F105D );
+    P( D, A, B, C, 10,  9, 0x02441453 );
+    P( C, D, A, B, 15, 14, 0xD8A1E681 );
+    P( B, C, D, A,  4, 20, 0xE7D3FBC8 );
+    P( A, B, C, D,  9,  5, 0x21E1CDE6 );
+    P( D, A, B, C, 14,  9, 0xC33707D6 );
+    P( C, D, A, B,  3, 14, 0xF4D50D87 );
+    P( B, C, D, A,  8, 20, 0x455A14ED );
+    P( A, B, C, D, 13,  5, 0xA9E3E905 );
+    P( D, A, B, C,  2,  9, 0xFCEFA3F8 );
+    P( C, D, A, B,  7, 14, 0x676F02D9 );
+    P( B, C, D, A, 12, 20, 0x8D2A4C8A );
+
+#undef F
+    
+#define F(x,y,z) (x ^ y ^ z)
+
+    P( A, B, C, D,  5,  4, 0xFFFA3942 );
+    P( D, A, B, C,  8, 11, 0x8771F681 );
+    P( C, D, A, B, 11, 16, 0x6D9D6122 );
+    P( B, C, D, A, 14, 23, 0xFDE5380C );
+    P( A, B, C, D,  1,  4, 0xA4BEEA44 );
+    P( D, A, B, C,  4, 11, 0x4BDECFA9 );
+    P( C, D, A, B,  7, 16, 0xF6BB4B60 );
+    P( B, C, D, A, 10, 23, 0xBEBFBC70 );
+    P( A, B, C, D, 13,  4, 0x289B7EC6 );
+    P( D, A, B, C,  0, 11, 0xEAA127FA );
+    P( C, D, A, B,  3, 16, 0xD4EF3085 );
+    P( B, C, D, A,  6, 23, 0x04881D05 );
+    P( A, B, C, D,  9,  4, 0xD9D4D039 );
+    P( D, A, B, C, 12, 11, 0xE6DB99E5 );
+    P( C, D, A, B, 15, 16, 0x1FA27CF8 );
+    P( B, C, D, A,  2, 23, 0xC4AC5665 );
+
+#undef F
+
+#define F(x,y,z) (y ^ (x | ~z))
+
+    P( A, B, C, D,  0,  6, 0xF4292244 );
+    P( D, A, B, C,  7, 10, 0x432AFF97 );
+    P( C, D, A, B, 14, 15, 0xAB9423A7 );
+    P( B, C, D, A,  5, 21, 0xFC93A039 );
+    P( A, B, C, D, 12,  6, 0x655B59C3 );
+    P( D, A, B, C,  3, 10, 0x8F0CCC92 );
+    P( C, D, A, B, 10, 15, 0xFFEFF47D );
+    P( B, C, D, A,  1, 21, 0x85845DD1 );
+    P( A, B, C, D,  8,  6, 0x6FA87E4F );
+    P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
+    P( C, D, A, B,  6, 15, 0xA3014314 );
+    P( B, C, D, A, 13, 21, 0x4E0811A1 );
+    P( A, B, C, D,  4,  6, 0xF7537E82 );
+    P( D, A, B, C, 11, 10, 0xBD3AF235 );
+    P( C, D, A, B,  2, 15, 0x2AD7D2BB );
+    P( B, C, D, A,  9, 21, 0xEB86D391 );
+
+#undef F
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+}
+
+void md5_update( struct md5_context *ctx, uint8 *input, uint32 length )
+{
+    uint32 left, fill;
+
+    if( ! length ) return;
+
+    left = (uint32) (ctx->total & 0x3F);
+    fill = 64 - left;
+
+    ctx->total += length;
+
+    if( left && length >= fill )
+    {
+	memcpy( (void *) (ctx->buffer + left), (void *) input, fill );
+	md5_process( ctx, ctx->buffer );
+	length -= fill;
+	input  += fill;
+	left = 0;
+    }
+
+    while( length >= 64 )
+    {
+        md5_process( ctx, input );
+	length -= 64;
+	input  += 64;
+    }
+
+    if( length )
+    {
+        memcpy( (void *) (ctx->buffer + left), (void *) input, length );
+    }
+}
+
+static uint8 md5_padding[64] =
+{
+ 0x80, 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
+};
+
+void md5_finish( struct md5_context *ctx, uint8 digest[16] )
+{
+    uint32 last, padn;
+    uint8 msglen[8];
+
+    PUT_UINT32( (uint32) ((ctx->total <<  3) & 0xFFFFFFFF), msglen, 0 );
+    PUT_UINT32( (uint32) ((ctx->total >> 29) & 0xFFFFFFFF), msglen, 4 );
+
+    last = (uint32) (ctx->total & 0x3F);
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    md5_update( ctx, md5_padding, padn );
+    md5_update( ctx, msglen, 8 );
+
+    PUT_UINT32( ctx->state[0], digest,  0 );
+    PUT_UINT32( ctx->state[1], digest,  4 );
+    PUT_UINT32( ctx->state[2], digest,  8 );
+    PUT_UINT32( ctx->state[3], digest, 12 );
+}
+
+#ifdef TEST
+
+#include <stdio.h>
+
+/*
+ * those are the standard RFC 1321 test vectors
+ */
+
+static char *msg[] =
+{
+    "",
+    "a",
+    "abc",
+    "message digest",
+    "abcdefghijklmnopqrstuvwxyz",
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+    "12345678901234567890123456789012345678901234567890123456789012" \
+	"345678901234567890"
+};
+
+static char *val[] =
+{
+    "d41d8cd98f00b204e9800998ecf8427e",
+    "0cc175b9c0f1b6a831c399e269772661",
+    "900150983cd24fb0d6963f7d28e17f72",
+    "f96b697d7cb7938d525a2f31aaf161d0",
+    "c3fcd3d76192e4007dfb496cca67e13b",
+    "d174ab98d277d9f5a5611c2c9f419d9f",
+    "57edf4a22be3c955ac49da2e2107b67a"
+};
+
+int main( void )
+{
+    int i, j;
+    char output[33];
+    struct md5_context ctx;
+    unsigned char md5sum[16];
+
+    for( i = 0; i < 7; i++ )
+    {
+	md5_starts( &ctx );
+	md5_update( &ctx, (uint8 *) msg[i], strlen( msg[i] ) );
+	md5_finish( &ctx, md5sum );
+
+	for( j = 0; j < 16; j++ )
+	{
+	    sprintf( output + j * 2, "%02x", md5sum[j] );
+	}
+
+	printf( "test %d ", i + 1 );
+
+	if( ! memcmp( output, val[i], 32 ) )
+	{
+	    printf( "passed\n" );
+	}
+	else
+	{
+	    printf( "failed\n" );
+	    return( 1 );
+	}
+    }
+
+    return( 0 );
+}
+
+#endif
+
+
diff --git a/lib/memalloc.c b/lib/memalloc.c
new file mode 100644
index 0000000..45d8567
--- /dev/null
+++ b/lib/memalloc.c
@@ -0,0 +1,481 @@
+/* memalloc.c - Routines to allocate and deallocate dynamic memory. 
+ * This lets you have a stack of memory handlers.  The default
+ * memory handler is a thin shell around malloc/free.  You can
+ * substitute routines that do more integrety checking with
+ * pushCarefulMem(), or routines of your own devising with
+ * pushMemHandler(). 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "obscure.h"
+#include "memalloc.h"
+#include "dlist.h"
+
+
+static void *defaultAlloc(size_t size)
+/* Default allocator. */
+{
+return malloc(size);
+}
+
+static void defaultFree(void *vpt)
+/* Default deallocator. */
+{
+free(vpt);
+}
+
+static void *defaultRealloc(void *vpt, size_t size)
+/* Default deallocator. */
+{
+return realloc(vpt, size);
+}
+
+static struct memHandler defaultMemHandler = 
+/* Default memory handler. */
+    {
+    NULL,
+    defaultAlloc,
+    defaultFree,
+    defaultRealloc,
+    };
+
+static struct memHandler *mhStack = &defaultMemHandler;
+
+struct memHandler *pushMemHandler(struct memHandler *newHandler)
+/* Use newHandler for memory requests until matching popMemHandler.
+ * Returns previous top of memory handler stack. */
+{
+struct memHandler *oldHandler = mhStack;
+slAddHead(&mhStack, newHandler);
+return oldHandler;
+}
+
+
+struct memHandler *popMemHandler()
+/* Removes top element from memHandler stack and returns it. */
+{
+struct memHandler *oldHandler = mhStack;
+if (mhStack == &defaultMemHandler)
+    errAbort("Too many popMemHandlers()");
+mhStack = mhStack->next;
+return oldHandler;
+}
+
+
+void setDefaultMemHandler()
+/* Sets memHandler to the default. */
+{
+mhStack = &defaultMemHandler;
+}
+
+/* 128*8*1024*1024 == 1073741824 == 2^30 on 32 bit machines,size_t == 4 bytes*/
+/* on 64 bit machines, size_t = 8 bytes, 2^30 * 2 * 2 * 2 * 2 = 2^34 == 16 Gb */
+static size_t maxAlloc = (size_t)128*8*1024*1024*(sizeof(size_t)/4)*(sizeof(size_t)/4)*(sizeof(size_t)/4*(sizeof(size_t)/4));
+
+void setMaxAlloc(size_t s)
+/* Set large allocation limit. */
+{
+maxAlloc = s;
+}
+
+void *needLargeMem(size_t size)
+/* This calls abort if the memory allocation fails. The memory is
+ * not initialized to zero. */
+{
+void *pt;
+if (size == 0 || size >= maxAlloc)
+    errAbort("needLargeMem: trying to allocate %llu bytes (limit: %llu)",
+         (unsigned long long)size, (unsigned long long)maxAlloc);
+if ((pt = mhStack->alloc(size)) == NULL)
+    errAbort("needLargeMem: Out of memory - request size %llu bytes, errno: %d\n",
+             (unsigned long long)size, errno);
+return pt;
+}
+
+void *needLargeZeroedMem(size_t size)
+/* Request a large block of memory and zero it. */
+{
+void *v;
+v = needLargeMem(size);
+memset(v, 0, size);
+return v;
+}
+
+void *needLargeMemResize(void* vp, size_t size)
+/* Adjust memory size on a block, possibly relocating it.  If vp is NULL,
+ * a new memory block is allocated.  Memory not initted. */
+{
+void *pt;
+if (size == 0 || size >= maxAlloc)
+    errAbort("needLargeMemResize: trying to allocate %llu bytes (limit: %llu)",
+         (unsigned long long)size, (unsigned long long)maxAlloc);
+if ((pt = mhStack->realloc(vp, size)) == NULL)
+    errAbort("needLargeMemResize: Out of memory - request size %llu bytes, errno: %d\n",
+             (unsigned long long)size, errno);
+return pt;
+}
+
+void *needLargeZeroedMemResize(void* vp, size_t oldSize, size_t newSize)
+/* Adjust memory size on a block, possibly relocating it.  If vp is NULL, a
+ * new memory block is allocated.  If block is grown, new memory is zeroed. */
+{
+void *v = needLargeMemResize(vp, newSize);
+if (newSize > oldSize)
+    memset(((char*)v)+oldSize, 0, newSize-oldSize);
+return v;
+}
+
+void *needHugeMem(size_t size)
+/* No checking on size.  Memory not initted. */
+{
+void *pt;
+if (size == 0)
+    errAbort("needHugeMem: trying to allocate 0 bytes");
+if ((pt = mhStack->alloc(size)) == NULL)
+    errAbort("needHugeMem: Out of huge memory - request size %llu bytes, errno: %d\n",
+             (unsigned long long)size, errno);
+return pt;
+}
+
+
+void *needHugeZeroedMem(size_t size)
+/* Request a large block of memory and zero it. */
+{
+void *v;
+v = needHugeMem(size);
+memset(v, 0, size);
+return v;
+}
+
+void *needHugeMemResize(void* vp, size_t size)
+/* Adjust memory size on a block, possibly relocating it.  If vp is NULL,
+ * a new memory block is allocated.  No checking on size.  Memory not
+ * initted. */
+{
+void *pt;
+if ((pt = mhStack->realloc(vp, size)) == NULL)
+    errAbort("needHugeMemResize: Out of memory - request resize %llu bytes, errno: %d\n",
+	(unsigned long long)size, errno);
+return pt;
+}
+
+
+void *needHugeZeroedMemResize(void* vp, size_t oldSize, size_t newSize)
+/* Adjust memory size on a block, possibly relocating it.  If vp is NULL, a
+ * new memory block is allocated.  No checking on size.  If block is grown,
+ * new memory is zeroed. */
+{
+void *v;
+v = needHugeMemResize(vp, newSize);
+if (newSize > oldSize)
+    memset(((char*)v)+oldSize, 0, newSize-oldSize);
+return v;
+}
+
+#define NEEDMEM_LIMIT 500000000
+
+void *needMem(size_t size)
+/* Need mem calls abort if the memory allocation fails. The memory
+ * is initialized to zero. */
+{
+void *pt;
+if (size == 0 || size > NEEDMEM_LIMIT)
+    errAbort("needMem: trying to allocate %llu bytes (limit: %llu)",
+         (unsigned long long)size, (unsigned long long)NEEDMEM_LIMIT);
+if ((pt = mhStack->alloc(size)) == NULL)
+    errAbort("needMem: Out of memory - request size %llu bytes, errno: %d\n",
+             (unsigned long long)size, errno);
+memset(pt, 0, size);
+return pt;
+}
+
+void *needMoreMem(void *old, size_t oldSize, size_t newSize)
+/* Adjust memory size on a block, possibly relocating it.  If vp is NULL, a
+ * new memory block is allocated.  No checking on size.  If block is grown,
+ * new memory is zeroed. */
+{
+return needLargeZeroedMemResize(old, oldSize, newSize);
+}
+
+void *wantMem(size_t size)
+/* Want mem just calls malloc - no zeroing of memory, no
+ * aborting if request fails. */
+{
+return mhStack->alloc(size);
+}
+
+void freeMem(void *pt)
+/* Free memory will check for null before freeing. */
+{
+if (pt != NULL)
+    mhStack->free(pt);
+}
+
+void freez(void *vpt)
+/* Pass address of pointer.  Will free pointer and set it 
+ * to NULL. */
+{
+void **ppt = (void **)vpt;
+void *pt = *ppt;
+*ppt = NULL;
+freeMem(pt);
+}
+
+static int carefulAlignSize;    /* Alignment size for machine - 8 bytes for DEC alpha, 4 for Sparc. */
+static int carefulAlignAdd;     /* Do aliSize = *(unaliSize+carefulAlignAdd)&carefulAlignMask); */
+
+#if __WORDSIZE == 64
+static bits64 carefulAlignMask;    /* to make sure requests are aligned. */
+#elif __WORDSIZE == 32
+static bits32 carefulAlignMask;    /* to make sure requests are aligned. */
+#else
+static bits32 carefulAlignMask;    /* to make sure requests are aligned. */
+#endif
+
+static struct memHandler *carefulParent;
+
+static size_t carefulMaxToAlloc;
+static size_t carefulAlloced;
+
+struct carefulMemBlock
+/* Keep one of these for each outstanding memory block.   It's a doubly linked list. */
+    {
+    struct carefulMemBlock *next;
+    struct carefulMemBlock *prev;
+    int size;
+    int startCookie;
+    };
+
+int cmbStartCookie = 0x78753421;
+
+char cmbEndCookie[4] = {0x44, 0x33, 0x7F, 0x42};
+
+struct dlList *cmbAllocedList;
+
+static void carefulMemInit(size_t maxToAlloc)
+/* Initialize careful memory system */
+{
+carefulMaxToAlloc = maxToAlloc;
+cmbAllocedList = newDlList();
+carefulAlignSize = sizeof(double);
+if (sizeof(void *) > carefulAlignSize)
+    carefulAlignSize = sizeof(void *);
+if (sizeof(long) > carefulAlignSize)
+    carefulAlignSize = sizeof(long);
+if (sizeof(off_t) > carefulAlignSize)
+    carefulAlignSize = sizeof(off_t);
+if (sizeof(long long) > carefulAlignSize)
+    carefulAlignSize = sizeof(long long);
+carefulAlignAdd = carefulAlignSize-1;
+carefulAlignMask = ~carefulAlignAdd;
+}
+
+
+static void *carefulAlloc(size_t size)
+/* Allocate extra memory for cookies and list node, and then
+ * return memory block. */
+{
+struct carefulMemBlock *cmb;
+char *pEndCookie;
+size_t newAlloced = size + carefulAlloced;
+size_t aliSize;
+
+if (newAlloced > carefulMaxToAlloc)
+    {
+    char maxAlloc[32];
+    char allocRequest[32];
+    sprintLongWithCommas(maxAlloc, (long long)carefulMaxToAlloc);
+    sprintLongWithCommas(allocRequest, (long long)newAlloced);
+    errAbort("carefulAlloc: Allocated too much memory - more than %s bytes (%s)",
+	maxAlloc, allocRequest);
+    }
+carefulAlloced = newAlloced;
+aliSize = ((size + sizeof(*cmb) + 4 + carefulAlignAdd)&carefulAlignMask);
+cmb = carefulParent->alloc(aliSize);
+cmb->size = size;
+cmb->startCookie = cmbStartCookie;
+pEndCookie = (char *)(cmb+1);
+pEndCookie += size;
+memcpy(pEndCookie, cmbEndCookie, sizeof(cmbEndCookie));
+dlAddHead(cmbAllocedList, (struct dlNode *)cmb);
+return (void *)(cmb+1);
+}
+
+static void carefulFree(void *vpt)
+/* Check cookies and free. */
+{
+struct carefulMemBlock *cmb = ((struct carefulMemBlock *)vpt)-1;
+size_t size = cmb->size;
+char *pEndCookie;
+
+carefulAlloced -= size;
+pEndCookie = (((char *)(cmb+1)) + size);
+if (cmb->startCookie != cmbStartCookie)
+    errAbort("Bad start cookie %x freeing %llx\n", cmb->startCookie,
+             ptrToLL(vpt));
+if (memcmp(pEndCookie, cmbEndCookie, sizeof(cmbEndCookie)) != 0)
+    errAbort("Bad end cookie %x%x%x%x freeing %llx\n", 
+        pEndCookie[0], pEndCookie[1], pEndCookie[2], pEndCookie[3],
+             ptrToLL(vpt));
+dlRemove((struct dlNode *)cmb);
+carefulParent->free(cmb);
+}
+
+
+static void *carefulRealloc(void *vpt, size_t size)
+/* realloc a careful memblock block. */
+{
+unsigned char* newBlk = carefulAlloc(size);
+if (vpt != NULL)
+    {
+    struct carefulMemBlock *cmb = ((struct carefulMemBlock *)vpt)-1;
+    memcpy(newBlk, vpt, cmb->size);
+    carefulFree(vpt);
+    }
+return newBlk;
+}
+
+
+void carefulCheckHeap()
+/* Walk through allocated memory and make sure that all cookies are
+ * in place. */
+{
+int maxPieces = 10000000;    /* Assume no more than this many pieces allocated. */
+struct carefulMemBlock *cmb;
+char *pEndCookie;
+size_t size;
+
+if (carefulParent == NULL)
+    return;
+
+for (cmb = (struct carefulMemBlock *)(cmbAllocedList->head); cmb->next != NULL; cmb = cmb->next)
+    {
+    size = cmb->size;
+    pEndCookie = (((char *)(cmb+1)) + size);
+    if (cmb->startCookie != cmbStartCookie)
+        errAbort("Bad start cookie %x checking %llx\n", cmb->startCookie,
+                 ptrToLL(cmb+1));
+    if (memcmp(pEndCookie, cmbEndCookie, sizeof(cmbEndCookie)) != 0)
+        errAbort("Bad end cookie %x%x%x%x checking %llx\n", 
+                 pEndCookie[0], pEndCookie[1], pEndCookie[2], pEndCookie[3],
+                 ptrToLL(cmb+1));
+    if (--maxPieces == 0)
+        errAbort("Loop or more than 10000000 pieces in memory list");
+    }
+}
+
+int carefulCountBlocksAllocated()
+/* How many memory items are allocated? */
+{
+return dlCount(cmbAllocedList);
+}
+
+long carefulTotalAllocated()
+/* Return total bases allocated */
+{
+return carefulAlloced;
+}
+
+static struct memHandler carefulMemHandler = 
+/* Default memory handler. */
+    {
+    NULL,
+    carefulAlloc,
+    carefulFree,
+    carefulRealloc,
+    };
+
+void pushCarefulMemHandler(size_t maxAlloc)
+/* Push the careful (paranoid, conservative, checks everything)
+ * memory handler  top of the memHandler stack and use it. */
+{
+carefulMemInit(maxAlloc);
+carefulParent = pushMemHandler(&carefulMemHandler);
+}
+
+struct memTracker
+/* A structure to keep track of memory. */
+    {
+    struct memTracker *next;	 /* Next in list. */
+    struct dlList *list;	 /* List of allocated blocks. */
+    struct memHandler *parent;   /* Underlying memory handler. */
+    struct memHandler *handler;  /* Memory handler. */
+    };
+
+static struct memTracker *memTracker = NULL;	/* Head in memTracker list. */
+
+static void *memTrackerAlloc(size_t size)
+/* Allocate extra memory for cookies and list node, and then
+ * return memory block. */
+{
+struct dlNode *node;
+
+size += sizeof (*node);
+node = memTracker->parent->alloc(size);
+if (node == NULL)
+    return node;
+dlAddTail(memTracker->list, node);
+return (void*)(node+1);
+}
+
+static void memTrackerFree(void *vpt)
+/* Check cookies and free. */
+{
+struct dlNode *node = vpt;
+node -= 1;
+dlRemove(node);
+memTracker->parent->free(node);
+}
+
+static void *memTrackerRealloc(void *vpt, size_t size)
+/* Resize a memory block from memTrackerAlloc. */
+{
+if (vpt == NULL)
+    return memTrackerAlloc(size);
+else
+    {
+    struct dlNode *node = ((struct dlNode *)vpt)-1;
+    size += sizeof(*node);
+    dlRemove(node);
+    node = memTracker->parent->realloc(node, size);
+    if (node == NULL)
+        return node;
+    dlAddTail(memTracker->list, node);
+    return (void*)(node+1);
+    }
+}
+
+void memTrackerStart()
+/* Push memory handler that will track blocks allocated so that
+ * they can be automatically released with memTrackerEnd().  You
+ * can have memTrackerStart one after the other, but memTrackerStart/End
+ * need to nest. */
+{
+struct memTracker *mt;
+
+if (memTracker != NULL)
+     errAbort("multiple memTrackerStart calls");
+AllocVar(mt);
+AllocVar(mt->handler);
+mt->handler->alloc = memTrackerAlloc;
+mt->handler->free = memTrackerFree;
+mt->handler->realloc = memTrackerRealloc;
+mt->list = dlListNew();
+mt->parent = pushMemHandler(mt->handler);
+memTracker = mt;
+}
+
+void memTrackerEnd()
+/* Free any remaining blocks and pop tracker memory handler. */
+{
+struct memTracker *mt = memTracker;
+if (mt == NULL)
+    errAbort("memTrackerEnd without memTrackerStart");
+memTracker = NULL;
+popMemHandler();
+dlListFree(&mt->list);
+freeMem(mt->handler);
+freeMem(mt);
+}
diff --git a/lib/memgfx.c b/lib/memgfx.c
new file mode 100644
index 0000000..62e2e6b
--- /dev/null
+++ b/lib/memgfx.c
@@ -0,0 +1,1187 @@
+/* memgfx - routines for drawing on bitmaps in memory.
+ * Currently limited to 256 color bitmaps. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "memgfx.h"
+#include "gemfont.h"
+#include "localmem.h"
+#include "vGfx.h"
+#include "vGfxPrivate.h"
+#include "colHash.h"
+
+
+
+Color multiply(Color src, Color new)
+{
+#ifdef COLOR32
+unsigned char rs = (src >> 0) & 0xff;
+unsigned char gs = (src >> 8) & 0xff;
+unsigned char bs = (src >> 16) & 0xff;
+unsigned char rn = (new >> 0) & 0xff;
+unsigned char gn = (new >> 8) & 0xff;
+unsigned char bn = (new >> 16) & 0xff;
+
+unsigned char ro = ((unsigned) rn * rs) / 255;
+unsigned char go = ((unsigned) gn * gs) / 255;
+unsigned char bo = ((unsigned) bn * bs) / 255;
+return MAKECOLOR_32(ro, go, bo);
+#else
+/* no multiply write mode in 8 bit */
+return new;
+#endif /* COLOR32 */
+}
+
+
+#ifndef min3
+#define min3(x,y,z) (min(x,min(y,z)))
+/* Return min of x,y, and z. */
+#endif
+
+#ifndef max3
+#define max3(x,y,z) (max(x,max(y,z)))
+/* Return max of x,y, and z. */
+#endif
+
+void _mgPutDotMultiply(struct memGfx *mg, int x, int y,Color color)
+{
+Color src = *_mgPixAdr(mg,x,y);
+*_mgPixAdr(mg,x,y) = multiply(src, color);
+}
+
+
+static void mgSetDefaultColorMap(struct memGfx *mg)
+/* Set up default color map for a memGfx. */
+{
+#ifdef COLOR32
+    return;
+#else
+
+/* Note dependency in order here and in MG_WHITE, MG_BLACK, etc. */
+int i;
+for (i=0; i<ArraySize(mgFixedColors); ++i)
+    {
+    struct rgbColor *c = &mgFixedColors[i];
+    mgAddColor(mg, c->r, c->g, c->b);
+    }
+#endif
+}
+
+
+
+void mgSetWriteMode(struct memGfx *mg, unsigned int writeMode)
+/* Set write mode */
+{
+mg->writeMode = writeMode;
+}
+
+void mgSetClip(struct memGfx *mg, int x, int y, int width, int height)
+/* Set clipping rectangle. */
+{
+int x2, y2;
+if (x < 0)
+    x = 0;
+if (y < 0)
+    y = 0;
+x2 = x + width;
+if (x2 > mg->width)
+    x2 = mg->width;
+y2 = y + height;
+if (y2 > mg->height)
+    y2 = mg->height;
+mg->clipMinX = x;
+mg->clipMaxX = x2;
+mg->clipMinY = y;
+mg->clipMaxY = y2;
+}
+
+void mgUnclip(struct memGfx *mg)
+/* Set clipping rect cover full thing. */
+{
+mgSetClip(mg, 0,0,mg->width, mg->height);
+}
+
+struct memGfx *mgNew(int width, int height)
+/* Return new memGfx. Note new pixel memory is uninitialized */
+{
+struct memGfx *mg;
+
+mg = needMem(sizeof(*mg));
+mg->width = width;
+mg->height = height;
+mg->pixels = needLargeMem(width*height*sizeof(Color));
+#ifndef COLOR32
+mg->colorHash = colHashNew();
+#endif
+mgSetDefaultColorMap(mg);
+mgUnclip(mg);
+return mg;
+}
+
+void mgClearPixels(struct memGfx *mg)
+/* Set all pixels to background. */
+{
+#ifdef COLOR32
+memset((unsigned char *)mg->pixels, 0xff, mg->width*mg->height*sizeof(unsigned int));
+#else
+zeroBytes(mg->pixels, mg->width*mg->height);
+#endif
+}
+
+void mgClearPixelsTrans(struct memGfx *mg)
+/* Set all pixels to transparent. */
+{
+#ifdef COLOR32
+unsigned int *ptr = mg->pixels;
+unsigned int *lastPtr = &mg->pixels[mg->width * mg->height];
+for(; ptr < lastPtr; ptr++)
+#ifdef MEMGFX_BIGENDIAN
+    *ptr = 0xffffff00;
+#else
+    *ptr = 0x00ffffff;  // transparent white
+#endif
+
+#else
+zeroBytes(mg->pixels, mg->width*mg->height);
+#endif
+}
+
+Color mgFindColor(struct memGfx *mg, unsigned char r, unsigned char g, unsigned char b)
+/* Returns closest color in color map to rgb values.  If it doesn't
+ * already exist in color map and there's room, it will create
+ * exact color in map. */
+{
+#ifdef COLOR32
+return MAKECOLOR_32(r,g,b);
+#else
+struct colHashEl *che;
+if ((che = colHashLookup(mg->colorHash, r, g, b)) != NULL)
+    return che->ix;
+if (mgColorsFree(mg))
+    return mgAddColor(mg, r, g, b);
+return mgClosestColor(mg, r, g, b);
+#endif
+}
+
+
+struct rgbColor mgColorIxToRgb(struct memGfx *mg, int colorIx)
+/* Return rgb value at color index. */
+{
+#ifdef COLOR32
+static struct rgbColor rgb;
+#ifdef MEMGFX_BIGENDIAN
+rgb.r = (colorIx >> 24) & 0xff;
+rgb.g = (colorIx >> 16) & 0xff;
+rgb.b = (colorIx >> 8) & 0xff;
+#else
+rgb.r = (colorIx >> 0) & 0xff;
+rgb.g = (colorIx >> 8) & 0xff;
+rgb.b = (colorIx >> 16) & 0xff;
+#endif
+
+return rgb;
+#else
+return mg->colorMap[colorIx];
+#endif
+}
+
+Color mgClosestColor(struct memGfx *mg, unsigned char r, unsigned char g, unsigned char b)
+/* Returns closest color in color map to r,g,b */
+{
+#ifdef COLOR32
+return MAKECOLOR_32(r,g,b);
+#else
+struct rgbColor *c = mg->colorMap;
+int closestDist = 0x7fffffff;
+int closestIx = -1;
+int dist, dif;
+int i;
+for (i=0; i<mg->colorsUsed; ++i)
+    {
+    dif = c->r - r;
+    dist = dif*dif;
+    dif = c->g - g;
+    dist += dif*dif;
+    dif = c->b - b;
+    dist += dif*dif;
+    if (dist < closestDist)
+        {
+        closestDist = dist;
+        closestIx = i;
+        }
+    ++c;
+    }
+return closestIx;
+#endif
+}
+
+
+Color mgAddColor(struct memGfx *mg, unsigned char r, unsigned char g, unsigned char b)
+/* Adds color to end of color map if there's room. */
+{
+#ifdef COLOR32
+return MAKECOLOR_32(r,g,b);
+#else
+int colIx = mg->colorsUsed;
+if (colIx < 256)
+    {
+    struct rgbColor *c = mg->colorMap + mg->colorsUsed;
+    c->r = r;
+    c->g = g;
+    c->b = b;
+    mg->colorsUsed += 1;
+    colHashAdd(mg->colorHash, r, g, b, colIx);
+    }
+return (Color)colIx;
+#endif
+}
+
+int mgColorsFree(struct memGfx *mg)
+/* Returns # of unused colors in color map. */
+{
+#ifdef COLOR32
+return 1 << 23;
+#else
+return 256-mg->colorsUsed;
+#endif
+}
+
+void mgFree(struct memGfx **pmg)
+{
+struct memGfx *mg = *pmg;
+if (mg != NULL)
+    {
+    if (mg->pixels != NULL)
+	freeMem(mg->pixels);
+    if (mg->colorHash)
+        colHashFree(&mg->colorHash);
+    zeroBytes(mg, sizeof(*mg));
+    freeMem(mg);
+    }
+*pmg = NULL;
+}
+
+static void nonZeroCopy(Color *d, Color *s, int width)
+/* Copy non-zero colors. */
+{
+Color c;
+int i;
+for (i=0; i<width; ++i)
+    {
+    if ((c = s[i]) != MG_WHITE)
+        d[i] = c;
+    }
+}
+
+static void mgPutSegMaybeZeroClear(struct memGfx *mg, int x, int y, int width, Color *dots, boolean zeroClear)
+/* Put a series of dots starting at x, y and going to right width pixels.
+ * Possibly don't put zero dots though. */
+{
+int x2;
+Color *pt;
+if (y < mg->clipMinY || y > mg->clipMaxY)
+    return;
+x2 = x + width;
+if (x2 > mg->clipMaxX)
+    x2 = mg->clipMaxX;
+if (x < mg->clipMinX)
+    {
+    dots += mg->clipMinX - x;
+    x = mg->clipMinX;
+    }
+width = x2 - x;
+if (width > 0)
+    {
+    pt = _mgPixAdr(mg, x, y);
+    if (zeroClear)
+        nonZeroCopy(pt, dots, width);
+    else
+        {
+        width *= sizeof(Color);
+        memcpy(pt, dots, width * sizeof(Color));
+        }
+    }
+}
+
+void mgVerticalSmear(struct memGfx *mg,
+	int xOff, int yOff, int width, int height, 
+	Color *dots, boolean zeroClear)
+/* Put a series of one 'pixel' width vertical lines. */
+{
+while (--height >= 0)
+    {
+    mgPutSegMaybeZeroClear(mg, xOff, yOff, width, dots, zeroClear);
+    ++yOff;
+    }
+}
+
+
+void mgDrawBoxNormal(struct memGfx *mg, int x, int y, int width, int height, Color color)
+{
+int i;
+Color *pt;
+int x2 = x + width;
+int y2 = y + height;
+int wrapCount;
+
+if (x < mg->clipMinX)
+    x = mg->clipMinX;
+if (y < mg->clipMinY)
+    y = mg->clipMinY;
+if (x2 > mg->clipMaxX)
+    x2 = mg->clipMaxX;
+if (y2 > mg->clipMaxY)
+    y2 = mg->clipMaxY;
+width = x2-x;
+height = y2-y;
+if (width > 0 && height > 0)
+    {
+    pt = _mgPixAdr(mg,x,y);
+    /*colorBin[x][color]++;  increment color count for this pixel */
+    wrapCount = _mgBpr(mg) - width;
+    while (--height >= 0)
+	{
+        //Color src = *pt;
+	i = width;
+	while (--i >= 0)
+	    *pt++ = color;
+	pt += wrapCount;
+	}
+    }
+}
+
+void mgDrawBoxMultiply(struct memGfx *mg, int x, int y, int width, int height, Color color)
+{
+int i;
+Color *pt;
+int x2 = x + width;
+int y2 = y + height;
+int wrapCount;
+
+if (x < mg->clipMinX)
+    x = mg->clipMinX;
+if (y < mg->clipMinY)
+    y = mg->clipMinY;
+if (x2 > mg->clipMaxX)
+    x2 = mg->clipMaxX;
+if (y2 > mg->clipMaxY)
+    y2 = mg->clipMaxY;
+width = x2-x;
+height = y2-y;
+if (width > 0 && height > 0)
+    {
+    pt = _mgPixAdr(mg,x,y);
+    wrapCount = _mgBpr(mg) - width;
+    while (--height >= 0)
+	{
+        Color src = *pt;
+	i = width;
+	while (--i >= 0)
+	    *pt++ = multiply(src, color);
+	pt += wrapCount;
+	}
+    }
+}
+
+void mgDrawBox(struct memGfx *mg, int x, int y, int width, int height, Color color)
+{
+switch(mg->writeMode)
+    {
+    case MG_WRITE_MODE_NORMAL:
+        {
+        mgDrawBoxNormal(mg,x,y, width, height, color);
+        }
+        break;
+    case MG_WRITE_MODE_MULTIPLY:
+        {
+        mgDrawBoxMultiply(mg,x,y, width, height, color);
+        }
+        break;
+    }
+}
+
+void mgBrezy(struct memGfx *mg, int x1, int y1, int x2, int y2, Color color,
+	int yBase, boolean fillFromBase)
+/* Brezenham line algorithm.  Optionally fill in under line. */
+{
+if (x1 == x2)
+    {
+    int y,height;
+    if (y1 > y2)
+	{
+	y = y2;
+	height = y1-y2+1;
+	}
+    else
+        {
+	y = y1;
+	height = y2-y1+1;
+	}
+    if (fillFromBase)
+        {
+	if (y < yBase)
+	    mgDrawBox(mg, x1, y, 1, yBase-y, color);
+	}
+    else
+        mgDrawBox(mg, x1, y, 1, height, color);
+    }
+else if (y1 == y2)
+    {
+    int x,width;
+    if (x1 > x2)
+        {
+	x = x2;
+	width = x1-x2+1;
+	}
+    else
+        {
+	x = x1;
+	width = x2-x1+1;
+	}
+    if (fillFromBase)
+        {
+	if (y1 < yBase)
+	    mgDrawBox(mg, x, y1, width, yBase - y1, color);
+	}
+    else
+        {
+	mgDrawBox(mg, x, y1, width, 1, color);
+	}
+    }
+else
+    {
+    int duty_cycle;
+    int incy;
+    int delta_x, delta_y;
+    int dots;
+    delta_y = y2-y1;
+    delta_x = x2-x1;
+    if (delta_y < 0) 
+	{
+	delta_y = -delta_y;
+	incy = -1;
+	}
+    else
+	{
+	incy = 1;
+	}
+    if (delta_x < 0) 
+	{
+	delta_x = -delta_x;
+	incy = -incy;
+	x1 = x2;
+	y1 = y2;
+	}
+    duty_cycle = (delta_x - delta_y)/2;
+    if (delta_x >= delta_y)
+	{
+	dots = delta_x+1;
+	while (--dots >= 0)
+	    {
+	    if (fillFromBase)
+		{
+		if (y1 < yBase)
+		    mgDrawBox(mg,x1,y1,1,yBase-y1,color);
+		}
+	    else
+		mgPutDot(mg,x1,y1,color);
+	    duty_cycle -= delta_y;
+	    x1 += 1;
+	    if (duty_cycle < 0)
+		{
+		duty_cycle += delta_x;	  /* update duty cycle */
+		y1+=incy;
+		}
+	    }
+	}
+    else
+	{
+	dots = delta_y+1;
+	while (--dots >= 0)
+	    {
+	    if (fillFromBase)
+		{
+		if (y1 < yBase)
+		    mgDrawBox(mg,x1,y1,1,yBase-y1,color);
+		}
+	    else
+		mgPutDot(mg,x1,y1,color);
+	    duty_cycle += delta_x;
+	    y1+=incy;
+	    if (duty_cycle > 0)
+		{
+		duty_cycle -= delta_y;	  /* update duty cycle */
+		x1 += 1;
+		}
+	    }
+	}
+    }
+}
+
+void mgDrawLine(struct memGfx *mg, int x1, int y1, int x2, int y2, Color color)
+/* Draw a line from one point to another. */
+{
+mgBrezy(mg, x1, y1, x2, y2, color, 0, FALSE);
+}
+
+void mgFillUnder(struct memGfx *mg, int x1, int y1, int x2, int y2, 
+	int bottom, Color color)
+/* Draw a 4 sided filled figure that has line x1/y1 to x2/y2 at
+ * it's top, a horizontal line at bottom as it's bottom, and
+ * vertical lines from the bottom to y1 on the left and bottom to
+ * y2 on the right. */
+{
+mgBrezy(mg, x1, y1, x2, y2, color, bottom, TRUE);
+}
+
+void mgPutSeg(struct memGfx *mg, int x, int y, int width, Color *dots)
+/* Put a series of dots starting at x, y and going to right width pixels. */
+{
+mgPutSegMaybeZeroClear(mg, x, y, width, dots, FALSE);
+}
+
+void mgPutSegZeroClear(struct memGfx *mg, int x, int y, int width, Color *dots)
+/* Put a series of dots starting at x, y and going to right width pixels.
+ * Don't put zero dots though. */
+{
+mgPutSegMaybeZeroClear(mg, x, y, width, dots, TRUE);
+}
+
+
+void mgDrawHorizontalLine(struct memGfx *mg, int y1, Color color)
+/*special case of mgDrawLine, for horizontal line across entire window 
+  at y-value y1.*/
+{
+mgDrawLine( mg, mg->clipMinX, y1, mg->clipMaxX, y1, color);
+}
+
+void mgLineH(struct memGfx *mg, int y, int x1, int x2, Color color)
+/* Draw horizizontal line width pixels long starting at x/y in color */
+{
+if (y >= mg->clipMinY && y < mg->clipMaxY)
+    {
+    int w;
+    if (x1 < mg->clipMinX)
+        x1 = mg->clipMinX;
+    if (x2 > mg->clipMaxX)
+        x2 = mg->clipMaxX;
+    w = x2 - x1;
+    if (w > 0)
+        {
+	Color *pt = _mgPixAdr(mg,x1,y);
+	while (--w >= 0)
+	    *pt++ = color;
+	}
+    }
+}
+
+
+boolean mgClipForBlit(int *w, int *h, int *sx, int *sy,
+	struct memGfx *dest, int *dx, int *dy)
+{
+/* Make sure we don't overwrite destination. */
+int over;
+
+if ((over = dest->clipMinX - *dx) > 0)
+    {
+    *w -= over;
+    *sx += over;
+    *dx = dest->clipMinX;
+    }
+if ((over = dest->clipMinY - *dy) > 0)
+    {
+    *h -= over;
+    *sy += over;
+    *dy = dest->clipMinY;
+    }
+if ((over = *w + *dx - dest->clipMaxX) > 0)
+    *w -= over; 
+if ((over = *h + *dy - dest->clipMaxY) > 0)
+    *h -= over;
+return (*h > 0 && *w > 0);
+}
+
+void mgTextBlit(int width, int height, int bitX, int bitY,
+	unsigned char *bitData, int bitDataRowBytes, 
+	struct memGfx *dest, int destX, int destY, 
+	Color color, Color backgroundColor)
+{
+UBYTE *inLine;
+Color *outLine;
+UBYTE inLineBit;
+
+if (!mgClipForBlit(&width, &height, &bitX, &bitY, dest, &destX, &destY))
+    return;
+
+inLine = bitData + (bitX>>3) + bitY * bitDataRowBytes;
+inLineBit = (0x80 >> (bitX&7));
+outLine = _mgPixAdr(dest,destX,destY);
+while (--height >= 0)
+    {
+    UBYTE *in = inLine;
+    Color *out = outLine;
+    UBYTE inBit = inLineBit;
+    UBYTE inByte = *in++;
+    int i = width;
+    while (--i >= 0)
+	{
+	if (inBit & inByte)
+	    *out = color;
+	++out;
+	if ((inBit >>= 1) == 0)
+	    {
+	    inByte = *in++;
+	    inBit = 0x80;
+	    }
+	}
+    inLine += bitDataRowBytes;
+    outLine += _mgBpr(dest);
+    }
+}
+
+void mgTextBlitSolid(int width, int height, int bitX, int bitY,
+	unsigned char *bitData, int bitDataRowBytes, 
+	struct memGfx *dest, int destX, int destY, 
+	Color color, Color backgroundColor)
+{
+UBYTE *inLine;
+Color *outLine;
+UBYTE inLineBit;
+
+if (!mgClipForBlit(&width, &height, &bitX, &bitY, dest, &destX, &destY))
+    return;
+inLine = bitData + (bitX>>3) + bitY * bitDataRowBytes;
+inLineBit = (0x80 >> (bitX&7));
+outLine = _mgPixAdr(dest,destX,destY);
+while (--height >= 0)
+    {
+    UBYTE *in = inLine;
+    Color *out = outLine;
+    UBYTE inBit = inLineBit;
+    UBYTE inByte = *in++;
+    int i = width;
+    while (--i >= 0)
+	{
+	*out++ = ((inBit & inByte) ? color : backgroundColor);
+	if ((inBit >>= 1) == 0)
+	    {
+	    inByte = *in++;
+	    inBit = 0x80;
+	    }
+	}
+    inLine += bitDataRowBytes;
+    outLine += _mgBpr(dest);
+    }
+}
+
+
+void mgText(struct memGfx *mg, int x, int y, Color color, 
+	MgFont *font, char *text)
+/* Draw a line of text with upper left corner x,y. */
+{
+gfText(mg, font, text, x, y, color, mgTextBlit, MG_WHITE);
+}
+
+void mgTextCentered(struct memGfx *mg, int x, int y, int width, int height, 
+	Color color, MgFont *font, char *text)
+/* Draw a line of text centered in box defined by x/y/width/height */
+{
+int fWidth, fHeight;
+int xoff, yoff;
+fWidth = mgFontStringWidth(font, text);
+fHeight = mgFontPixelHeight(font);
+xoff = x + (width - fWidth)/2;
+yoff = y + (height - fHeight)/2;
+if (font == mgSmallFont())
+    {
+    xoff += 1;
+    yoff += 1;
+    }
+mgText(mg, xoff, yoff, color, font, text);
+}
+
+void mgTextRight(struct memGfx *mg, int x, int y, int width, int height, 
+	Color color, MgFont *font, char *text)
+/* Draw a line of text right justified in box defined by x/y/width/height */
+{
+int fWidth, fHeight;
+int xoff, yoff;
+fWidth = mgFontStringWidth(font, text);
+fHeight = mgFontPixelHeight(font);
+xoff = x + width - fWidth - 1;
+yoff = y + (height - fHeight)/2;
+if (font == mgSmallFont())
+    {
+    xoff += 1;
+    yoff += 1;
+    }
+mgText(mg, xoff, yoff, color, font, text);
+}
+
+int mgFontPixelHeight(MgFont *font)
+/* How high in pixels is font? */
+{
+return font_cel_height(font);
+}
+
+int mgGetFontPixelHeight(struct memGfx *mg, MgFont *font)
+/* How high in pixels is font? */
+{
+return mgFontPixelHeight(font);
+}
+
+int mgFontLineHeight(MgFont *font)
+/* How many pixels to next line ideally? */
+{
+return font_line_height(font);
+}
+
+int mgFontWidth(MgFont *font, char *chars, int charCount)
+/* How wide are a couple of letters? */
+{
+return fnstring_width(font, (unsigned char *)chars, charCount);
+}
+
+int mgFontStringWidth(MgFont *font, char *string)
+/* How wide is a string? */
+{
+return mgFontWidth(font, string, strlen(string));
+}
+
+int mgGetFontStringWidth(struct memGfx *mg, MgFont *font, char *string)
+/* How wide is a string? */
+{
+return mgFontStringWidth(font, string);
+}
+
+int mgFontCharWidth(MgFont *font, char c)
+/* How wide is a character? */
+{
+return mgFontWidth(font, &c, 1);
+}
+
+char *mgFontSizeBackwardsCompatible(char *size)
+/* Given "size" argument that may be in old tiny/small/medium/big/huge format,
+ * return it in new numerical string format. Do NOT free the return string*/
+{
+if (isdigit(size[0]))
+    return size;
+else if (sameWord(size, "tiny"))
+    return "6";
+else if (sameWord(size, "small"))
+    return "8";
+else if (sameWord(size, "medium"))
+    return "14";
+else if (sameWord(size, "large"))
+    return "18";
+else if (sameWord(size, "huge"))
+    return "34";
+else
+    {
+    errAbort("unknown font size %s", size);
+    return NULL;
+    }
+}
+
+MgFont *mgFontForSizeAndStyle(char *textSize, char *fontType)
+/* Get a font of given size and style.  Abort with error message if not found.
+ * The textSize should be 6,8,10,12,14,18,24 or 34.  For backwards compatibility
+ * textSizes of "tiny" "small", "medium", "large" and "huge" are also ok.
+ * The fontType should be "medium", "bold", or "fixed" */
+{
+textSize = mgFontSizeBackwardsCompatible(textSize);
+MgFont *font = NULL;
+if (sameString(fontType,"bold"))
+    {
+    if (sameString(textSize, "6"))
+	 font = mgTinyBoldFont();
+    else if (sameString(textSize, "8"))
+	 font = mgHelveticaBold8Font();
+    else if (sameString(textSize, "10"))
+	 font = mgHelveticaBold10Font();
+    else if (sameString(textSize, "12"))
+	 font = mgHelveticaBold12Font();
+    else if (sameString(textSize, "14"))
+	 font = mgHelveticaBold14Font();
+    else if (sameString(textSize, "18"))
+	 font = mgHelveticaBold18Font();
+    else if (sameString(textSize, "24"))
+	 font = mgHelveticaBold24Font();
+    else if (sameString(textSize, "34"))
+	 font = mgHelveticaBold34Font();
+    else
+	 errAbort("unknown textSize %s", textSize);
+    }
+else if (sameString(fontType,"fixed"))
+    {
+    if (sameString(textSize, "6"))
+	 font = mgTinyFixedFont();
+    else if (sameString(textSize, "8"))
+	 font = mgCourier8Font();
+    else if (sameString(textSize, "10"))
+	 font = mgCourier10Font();
+    else if (sameString(textSize, "12"))
+	 font = mgCourier12Font();
+    else if (sameString(textSize, "14"))
+	 font = mgCourier14Font();
+    else if (sameString(textSize, "18"))
+	 font = mgCourier18Font();
+    else if (sameString(textSize, "24"))
+	 font = mgCourier24Font();
+    else if (sameString(textSize, "34"))
+	 font = mgCourier34Font();
+    else
+	 errAbort("unknown textSize %s", textSize);
+    }
+else
+    {
+    if (sameString(textSize, "6"))
+	 font = mgTinyFont();
+    else if (sameString(textSize, "8"))
+	 font = mgSmallFont();
+    else if (sameString(textSize, "10"))
+	 font = mgHelvetica10Font();
+    else if (sameString(textSize, "12"))
+	 font = mgHelvetica12Font();
+    else if (sameString(textSize, "14"))
+	 font = mgHelvetica14Font();
+    else if (sameString(textSize, "18"))
+	 font = mgHelvetica18Font();
+    else if (sameString(textSize, "24"))
+	 font = mgHelvetica24Font();
+    else if (sameString(textSize, "34"))
+	 font = mgHelvetica34Font();
+    else
+	 errAbort("unknown textSize %s", textSize);
+    }
+return font;
+}
+
+MgFont *mgFontForSize(char *textSize)
+/* Get a font of given size and style.  Abort with error message if not found.
+ * The textSize should be 6,8,10,12,14,18,24 or 34.  For backwards compatibility
+ * textSizes of "tiny" "small", "medium", "large" and "huge" are also ok. */
+{
+return mgFontForSizeAndStyle(textSize, "medium");
+}
+
+
+void mgSlowDot(struct memGfx *mg, int x, int y, int colorIx)
+/* Draw a dot when a macro won't do. */
+{
+mgPutDot(mg, x, y, colorIx);
+}
+
+int mgSlowGetDot(struct memGfx *mg, int x, int y)
+/* Fetch a dot when a macro won't do. */
+{
+return mgGetDot(mg, x, y);
+}
+
+struct memGfx *mgRotate90(struct memGfx *in)
+/* Create a copy of input that is rotated 90 degrees clockwise. */
+{
+int iWidth = in->width, iHeight = in->height;
+struct memGfx *out = mgNew(iHeight, iWidth);
+Color *inCol, *outRow, *outRowStart;
+int i,j;
+
+memcpy(out->colorMap, in->colorMap, sizeof(out->colorMap));
+outRowStart = out->pixels;
+for (i=0; i<iWidth; ++i)
+    {
+    inCol = in->pixels + i;
+    outRow = outRowStart;
+    outRowStart += _mgBpr(out);
+    j = iHeight;
+    while (--j >= 0)
+        {
+	outRow[j] = *inCol;
+	inCol += _mgBpr(in);
+	}
+    }
+return out;
+}
+
+void mgSetHint(char *hint)
+/* dummy function */
+{
+return;
+}
+
+char *mgGetHint(char *hint)
+/* dummy function */
+{
+return "";
+}
+
+void vgMgMethods(struct vGfx *vg)
+/* Fill in virtual graphics methods for memory based drawing. */
+{
+vg->pixelBased = TRUE;
+vg->close = (vg_close)mgFree;
+vg->dot = (vg_dot)mgSlowDot;
+vg->getDot = (vg_getDot)mgSlowGetDot;
+vg->box = (vg_box)mgDrawBox;
+vg->line = (vg_line)mgDrawLine;
+vg->text = (vg_text)mgText;
+vg->textRight = (vg_textRight)mgTextRight;
+vg->textCentered = (vg_textCentered)mgTextCentered;
+vg->findColorIx = (vg_findColorIx)mgFindColor;
+vg->colorIxToRgb = (vg_colorIxToRgb)mgColorIxToRgb;
+vg->setWriteMode = (vg_setWriteMode)mgSetWriteMode;
+vg->setClip = (vg_setClip)mgSetClip;
+vg->unclip = (vg_unclip)mgUnclip;
+vg->verticalSmear = (vg_verticalSmear)mgVerticalSmear;
+vg->fillUnder = (vg_fillUnder)mgFillUnder;
+vg->drawPoly = (vg_drawPoly)mgDrawPoly;
+vg->setHint = (vg_setHint)mgSetHint;
+vg->getHint = (vg_getHint)mgGetHint;
+vg->getFontPixelHeight = (vg_getFontPixelHeight)mgGetFontPixelHeight;
+vg->getFontStringWidth = (vg_getFontStringWidth)mgGetFontStringWidth;
+}
+
+
+struct hslColor mgRgbToHsl(struct rgbColor rgb)
+/* Convert RGB to HSL colorspace (see http://en.wikipedia.org/wiki/HSL_and_HSV)
+ * In HSL, Hue is the color in the range [0,360) with 0=red 120=green 240=blue,
+ * Saturation goes from a shade of grey (0) to fully saturated color (1000), and
+ * Lightness goes from black (0) through the hue (500) to white (1000). */
+{
+unsigned char rgbMax = max3(rgb.r, rgb.g, rgb.b);
+unsigned char rgbMin = min3(rgb.r, rgb.g, rgb.b);
+unsigned char delta = rgbMax - rgbMin;
+unsigned short minMax = rgbMax + rgbMin;
+int divisor;
+struct hslColor hsl = { 0.0, 0, (1000*minMax+255)/(2*255) }; // round up
+
+// if max=min then no saturation, and this is gray
+if (rgbMax == rgbMin)
+    return hsl;
+else if (hsl.l <= 500)
+    divisor = minMax;
+else
+    divisor = (2*255-minMax);
+hsl.s = (1000*delta + divisor/2)/divisor; // round up
+
+// Saturation so compute hue 0..360 degrees (same as for HSV)
+if (rgbMax == rgb.r) // red is 0 +/- offset in blue or green direction
+    {
+    hsl.h = 0 + 60.0*(rgb.g - rgb.b)/delta;
+    }
+else if (rgbMax == rgb.g) // green is 120 +/- offset in blue or red direction
+    {
+    hsl.h = 120 + 60.0*(rgb.b - rgb.r)/delta;
+    }
+else // rgb_max == rgb.b // blue is 240 +/- offset in red or green direction
+    {
+    hsl.h = 240 + 60.0*(rgb.r - rgb.g)/delta;
+    }
+// normalize to [0,360)
+if (hsl.h < 0.0)
+    hsl.h += 360.0;
+else if (hsl.h >= 360.0)
+    hsl.h -= 360.0;
+return hsl;
+}
+
+
+struct hsvColor mgRgbToHsv(struct rgbColor rgb) 
+/* Convert RGB to HSV colorspace (see http://en.wikipedia.org/wiki/HSL_and_HSV)
+ * In HSV, Hue is the color in the range [0,360) with 0=red 120=green 240=blue,
+ * Saturation goes from white (0) to fully saturated color (1000), and
+ * Value goes from black (0) through to the hue (1000). */
+{
+unsigned char rgbMax = max3(rgb.r, rgb.g, rgb.b);
+unsigned char rgbMin = min3(rgb.r, rgb.g, rgb.b);
+unsigned char delta = rgbMax - rgbMin;
+struct hsvColor hsv = {0.0, 0, 1000*rgbMax/255};
+
+if (hsv.v == 0) 
+    return hsv;
+hsv.s = 1000*delta/rgbMax;
+// if no saturation, then this is gray
+if (hsv.s == 0) 
+    return hsv;
+// Saturation so compute hue 0..360 degrees (same as for HSL)
+if (rgbMax == rgb.r) // red is 0 +/- offset in blue or green direction
+    {
+    hsv.h = 0 + 60.0*(rgb.g - rgb.b)/delta;
+    } 
+else if (rgbMax == rgb.g) // green is 120 +/- offset in blue or red direction
+    {
+    hsv.h = 120 + 60.0*(rgb.b - rgb.r)/delta;
+    } 
+else // rgb_max == rgb.b // blue is 240 +/- offset in red or green direction
+    {
+    hsv.h = 240 + 60.0*(rgb.r - rgb.g)/delta;
+    }
+// normalize to [0,360)
+if (hsv.h < 0.0)
+    hsv.h += 360.0;
+else if (hsv.h >= 360.0)
+    hsv.h -= 360.0;
+return hsv;
+}
+
+
+struct rgbColor mgHslToRgb(struct hslColor hsl)
+/* Convert HSL to RGB colorspace http://en.wikipedia.org/wiki/HSL_and_HSV */
+{
+int p, q;
+double r, g, b;
+//unsigned short p, q, r, g, b;
+double tR, tG, tB;
+
+if( hsl.s == 0 ) // achromatic (grey)
+    return (struct rgbColor) {(255*hsl.l+500)/1000, (255*hsl.l+500)/1000, (255*hsl.l+500)/1000};
+if (hsl.l <= 500)
+    q = hsl.l + (hsl.l*hsl.s+500)/1000;
+else
+    q = hsl.l + hsl.s - (hsl.l*hsl.s+500)/1000;
+p = 2 * hsl.l - q;
+hsl.h /= 360.0; // normalize h to 0..1
+tR = hsl.h + 1/3.0;
+tG = hsl.h;
+tB = hsl.h - 1/3.0;
+if (tR < 0.0)
+    tR += 1.0;
+else if (tR > 1.0)
+    tR -= 1.0;
+if (tG < 0.0)
+    tG += 1.0;
+else if (tG > 1.0)
+    tG -= 1.0;
+if (tB < 0.0)
+    tB += 1.0;
+else if (tB > 1.0)
+    tB -= 1.0;
+// Red
+if (tR < 1/6.0)
+    r = p + (q-p)*6*tR;
+else if (tR < 0.5)
+    r = q;
+else if (tR < 2/3.0)
+    r = p + (q-p)*6*(2/3.0 - tR);
+else
+    r = p;
+// Green
+if (tG < 1/6.0)
+    g = p + (q-p)*6*tG;
+else if (tG < 0.5)
+    g = q;
+else if (tG < 2/3.0)
+    g = p + (q-p)*6*(2/3.0 - tG);
+else
+    g = p;
+// Blue
+if (tB < 1/6.0)
+    b = p + (q-p)*6*tB;
+else if (tB < 0.5)
+    b = q;
+else if (tB < 2/3.0)
+    b = p + (q-p)*6*(2/3.0 - tB);
+else
+    b = p;
+return (struct rgbColor) {(255*r+500)/1000, (255*g+500)/1000, (255*b+500)/1000}; // round up
+}
+
+
+struct rgbColor mgHsvToRgb(struct hsvColor hsv)
+/* Convert HSV to RGB colorspace http://en.wikipedia.org/wiki/HSL_and_HSV */
+{
+int i;
+double f;
+unsigned short low, q, t, r, g, b;
+
+if( hsv.s == 0 ) // achromatic (grey)
+    return (struct rgbColor) {(255*hsv.v+500)/1000, (255*hsv.v+500)/1000, (255*hsv.v+500)/1000};
+hsv.h /= 60.0; 
+i = (int) hsv.h;                     // floor the floating point value, sector 0 to 5
+f = hsv.h - i;                       // fractional part (distance) from hue 
+// hsv.v is highest r,g, or b value
+// low value is related to saturation
+low = hsv.v - (hsv.v * hsv.s / 1000); // lowest r,g, or b value
+t = low + (hsv.v - low) * f;         // scaled value from low..high
+q = low + (hsv.v - low) * (1.0-f);   // scaled value from low..high
+
+switch( i )
+    {
+    case 0:
+	r = hsv.v;
+        g = t;
+        b = low;
+        break;
+    case 1:
+        r = q;
+        g = hsv.v;
+        b = low;
+        break;
+    case 2:
+        r = low;
+        g = hsv.v;
+        b = t;
+        break;
+    case 3:
+        r = low;
+        g = q;
+        b = hsv.v;
+        break;
+    case 4:
+        r = t;
+        g = low;
+        b = hsv.v;
+        break;
+    default:                // case 5:
+        r = hsv.v;
+        g = low;
+        b = q;
+        break;
+    }
+return (struct rgbColor) {(255*r+500)/1000, (255*g+500)/1000, (255*b+500)/1000};
+}
+
+
+struct rgbColor mgRgbTransformHsl(struct rgbColor in, double h, double s, double l)
+/* Transform rgb 'in' value using
+ *   hue shift 'h' (0..360 degrees), 
+ *   saturation scale 's', and 
+ *   lightness scale 'l'
+ * Returns the transformed rgb value 
+ * Use H=0, S=L=1 for identity transformation
+ */
+{
+struct hslColor hsl = mgRgbToHsl(in);
+hsl.h += h;
+while (hsl.h < 0.0)
+    hsl.h += 360.0;
+while (hsl.h > 360.0)
+    hsl.h -= 360.0;
+hsl.s = min(max(hsl.s * s, 0), 1000);
+hsl.l = min(max(hsl.l * l, 0), 1000);
+return mgHslToRgb(hsl);
+}
+
+
+struct rgbColor mgRgbTransformHsv(struct rgbColor in, double h, double s, double v)
+/* Transform rgb 'in' value using
+ *   hue shift 'h' (0..360 degrees), 
+ *   saturation scale 's', and 
+ *   value scale 'v'
+ * Returns the transformed rgb value 
+ * Use H=0, S=V=1 for identity transformation
+ */
+{
+struct hsvColor hsv = mgRgbToHsv(in);
+hsv.h += h;
+while (hsv.h < 0.0)
+    hsv.h += 360.0;
+while (hsv.h > 360.0)
+    hsv.h -= 360.0;
+hsv.s = min(max(hsv.s * s, 0), 1000);
+hsv.v = min(max(hsv.v * v, 0), 1000);
+return mgHsvToRgb(hsv);
+}
+
diff --git a/lib/metaWig.c b/lib/metaWig.c
new file mode 100644
index 0000000..a9358ce
--- /dev/null
+++ b/lib/metaWig.c
@@ -0,0 +1,185 @@
+#include "common.h"
+#include "hash.h"
+#include "linefile.h"
+#include "localmem.h"
+#include "bigWig.h"
+#include "bwgInternal.h"
+#include "metaWig.h"
+
+static struct hash *hashSectionChroms(struct bwgSection *sectionList)
+/* Return hash keyed by chromosome name with values that are the
+ * first section in the chromosome. */
+{
+struct hash *hash = hashNew(0);
+struct bwgSection *section;
+for (section = sectionList; section != NULL; section = section->next)
+    {
+    if (!hashLookup(hash, section->chrom))
+        hashAdd(hash, section->chrom, section);
+    }
+return hash;
+}
+
+struct metaWig *metaWigOpen(char *fileName)
+/* Wrap self around file.  Read all of it if it's wig, just header if bigWig. */
+{
+struct metaWig *mw;
+AllocVar(mw);
+if (isBigWig(fileName))
+    {
+    mw->type = mwtBigWig;
+    mw->bwf = bigWigFileOpen(fileName);
+    }
+else
+    {
+    mw->lm = lmInit(0);
+    mw->sectionList = bwgParseWig(fileName, FALSE, NULL, 512, mw->lm);
+    mw->chromHash = hashSectionChroms(mw->sectionList);
+    mw->type = mwtSections;
+    }
+return mw;
+}
+
+void metaWigClose(struct metaWig **pMw)
+/* Close up metaWig file */
+{
+struct metaWig *mw = *pMw;
+if (mw != NULL)
+    {
+    bigWigFileClose(&mw->bwf);
+    lmCleanup(&mw->lm);
+    freez(pMw);
+    }
+}
+
+struct slName *metaWigChromList(struct metaWig *mw)
+/* Return list of chromosomes covered in wig. */
+{
+struct slName *list = NULL;
+switch (mw->type)
+    {
+    case mwtSections:
+        {
+	struct hashEl *chrom, *chromList = hashElListHash(mw->chromHash);
+	for (chrom = chromList; chrom != NULL; chrom = chrom->next)
+	    slNameAddHead(&list, chrom->name);
+	hashElFreeList(&chromList);
+	break;
+	}
+    case mwtBigWig:
+        {
+	struct bbiChromInfo *chrom, *chromList = bbiChromList(mw->bwf);
+	for (chrom = chromList; chrom != NULL; chrom = chrom->next)
+	    slNameAddHead(&list, chrom->name);
+	bbiChromInfoFreeList(&chromList);
+	break;
+	}
+    }
+slSort(&list, slNameCmpStringsWithEmbeddedNumbers);
+return list;
+}
+
+static void bedGraphSectionToIntervals(struct bwgSection *section, struct lm *lm,
+	struct bbiInterval **pList)
+/* Convert bedGraph section to interval format. */
+{
+struct bwgBedGraphItem *item;
+for (item = section->items.bedGraphList; item != NULL; item = item->next)
+    {
+    struct bbiInterval *el;
+    lmAllocVar(lm, el);
+    el->start = item->start;
+    el->end = item->end;
+    el->val = item->val;
+    slAddHead(pList, el);
+    }
+}
+
+static void varStepSectionToIntervals(struct bwgSection *section, struct lm *lm,
+	struct bbiInterval **pList)
+/* Convert bedGraph section to interval format. */
+{
+struct bwgVariableStepPacked *array = section->items.variableStepPacked;
+int i, count = section->itemCount;
+bits32 span = section->itemSpan;
+for (i=0; i<count; ++i)
+    {
+    struct bwgVariableStepPacked *item = &array[i];
+    struct bbiInterval *el;
+    lmAllocVar(lm, el);
+    el->start = item->start;
+    el->end = item->start + span;
+    el->val = item->val;
+    slAddHead(pList, el);
+    }
+}
+
+static void fixedStepSectionToIntervals(struct bwgSection *section, struct lm *lm,
+	struct bbiInterval **pList)
+/* Convert bedGraph section to interval format. */
+{
+struct bwgFixedStepPacked *array = section->items.fixedStepPacked;
+int i, count = section->itemCount;
+bits32 span = section->itemSpan;
+bits32 step = section->itemStep;
+bits32 start = section->start;
+for (i=0; i<count; ++i)
+    {
+    struct bwgFixedStepPacked *item = &array[i];
+    struct bbiInterval *el;
+    lmAllocVar(lm, el);
+    el->start = start;
+    el->end = start + span;
+    el->val = item->val;
+    start += step;
+    slAddHead(pList, el);
+    }
+}
+
+static void addIntervals(struct bwgSection *section, struct lm *lm, struct bbiInterval **pList)
+/* Convert section to list of allocated in lm */
+{
+switch (section->type)
+    {
+    case bwgTypeBedGraph:
+        bedGraphSectionToIntervals(section, lm, pList);
+        break;
+    case bwgTypeVariableStep:
+	varStepSectionToIntervals(section, lm, pList);
+        break;
+    case bwgTypeFixedStep:
+	fixedStepSectionToIntervals(section, lm, pList);
+	break;
+    default:
+        errAbort("unknown section type %d in addIntervals", section->type);
+	break;
+    }
+}
+
+struct bbiInterval *metaIntervalsForChrom(struct metaWig *mw, char *chrom, struct lm *lm)
+/* Get sorted list of all intervals with data on chromosome. */
+{
+struct bbiInterval *list = NULL;
+switch (mw->type)
+    {
+    case mwtSections:
+        {
+	struct bwgSection *section, *sectionList = hashFindVal(mw->chromHash, chrom);
+	for (section = sectionList; section != NULL; section = section->next)
+	   {
+	   if (!sameString(section->chrom, chrom))
+	       break;
+	   addIntervals(section, lm, &list);
+	   }
+	slReverse(&list);
+	break;
+	}
+    case mwtBigWig:
+        {
+	list = bigWigIntervalQuery(mw->bwf, chrom, 0, bbiChromSize(mw->bwf, chrom), lm);
+	break;
+	}
+    }
+return list;
+}
+
diff --git a/lib/mgCircle.c b/lib/mgCircle.c
new file mode 100644
index 0000000..4507afe
--- /dev/null
+++ b/lib/mgCircle.c
@@ -0,0 +1,79 @@
+/* mgCircle.c - Simple stepping draw a circle algorithm.  
+	Don't even correct aspect ratio. */
+
+#include "common.h"
+#include "memgfx.h"
+
+
+void mgCircle(struct memGfx *mg, int xCen, int yCen, int rad, 
+	Color color, boolean filled)
+/* Draw a circle using a stepping algorithm.  Doesn't correct
+ * for non-square pixels. */
+{
+int err;
+int derr, yerr, xerr;
+int aderr, ayerr, axerr;
+register int x,y;
+int lasty;
+
+if (rad <= 0)
+    {
+    mgPutDot(mg, xCen, yCen, color);
+    return;
+    }
+err = 0;
+x = rad;
+lasty = y = 0;
+for (;;)
+    {
+    if (filled)
+	{
+	if (y == 0)
+	    mgLineH(mg, yCen, xCen-x, xCen+x, color);
+	else
+	    {
+	    if (lasty != y)
+		{
+		mgLineH(mg, yCen-y, xCen-x, xCen+x, color);
+		mgLineH(mg, yCen+y, xCen-x, xCen+x, color);
+		lasty = y;
+		}
+	    }
+	}
+    else
+	{
+	/* draw 4 quadrandts of a circle */
+	mgPutDot(mg, xCen+x, yCen+y, color);
+	mgPutDot(mg, xCen+x, yCen-y, color);
+	mgPutDot(mg, xCen-x, yCen+y, color);
+	mgPutDot(mg, xCen-x, yCen-y, color);
+	}
+    axerr = xerr = err -x-x+1;
+    ayerr = yerr = err +y+y+1;
+    aderr = derr = yerr+xerr-err;
+    if (aderr < 0)
+	aderr = -aderr;
+    if (ayerr < 0)
+	ayerr = -ayerr;
+    if (axerr < 0)
+	axerr = -axerr;
+    if (aderr <= ayerr && aderr <= axerr)
+	{
+	err = derr;
+	x -= 1;
+	y += 1;
+	}
+    else if (ayerr <= axerr)
+	{
+	err = yerr;
+	y += 1;
+	}
+    else
+	{
+	err = xerr;
+	x -= 1;
+	}
+    if (x < 0)
+	break;
+    }
+}
diff --git a/lib/mgPolygon.c b/lib/mgPolygon.c
new file mode 100644
index 0000000..ce31e44
--- /dev/null
+++ b/lib/mgPolygon.c
@@ -0,0 +1,436 @@
+/* mgPolygon - stuff to draw polygons in memory.  This code dates
+ * back to 1984, was used in the Aegis Animator for the Atari ST. 
+ * It was an exceedingly speed critical routine for that program.
+ * For us it may be overkill, but the major speed tweak - the special
+ * case for convex polygons - is only 1/3 of the module, so I'm leaving
+ * it in.  I've lightly adapted the code to current conventions, but
+ * you can still see some relics in the local and static variable names of 
+ * other coding conventions.  */
+
+#include "common.h"
+#include "bits.h"
+#include "memgfx.h"
+#include "gfxPoly.h"
+
+
+void mgDrawPolyOutline(struct memGfx *mg, struct gfxPoly *poly, Color color)
+/* Draw a singe pixel line around polygon. */
+{
+struct gfxPoint *a, *b, *end;
+
+a = end = poly->ptList;
+b = a->next;
+for (;;)
+    {
+    mgDrawLine(mg, a->x, a->y, b->x, b->y, color);
+    a = b;
+    b = b->next;
+    if (a == end)
+        break;
+    }
+}
+
+/* ----- Stuff for convex polygons that may contain crossing lines ----- 
+ * This code works by allocating a bitmap big enough to hold the polygon
+ * and drawing lines on the bitmap in a special fashion, and then
+ * scanning the bitmap to connect together the dots with horizontal lines. */
+
+#define UPDIR 1
+#define DOWNDIR 0
+
+static UBYTE *on_off_buf;	/* Our bitplane. */
+
+static int pxmin, pxmax, pymin, pymax;	/* Bounds of polygon. */
+
+static void find_pminmax(struct gfxPoly *poly)
+{
+struct gfxPoint *pointpt;
+int i;
+
+pointpt = poly->ptList;
+pxmin = pxmax = pointpt->x;
+pymin = pymax = pointpt->y;
+pointpt = pointpt->next;
+
+i = poly->ptCount;
+while (--i > 0)
+   {
+   if (pxmin > pointpt->x) pxmin = pointpt->x;
+   if (pxmax < pointpt->x) pxmax = pointpt->x;
+   if (pymin > pointpt->y) pymin = pointpt->y;
+   if (pymax < pointpt->y) pymax = pointpt->y;
+   pointpt = pointpt->next;
+   }
+}
+
+static void xor_pt(int bpr, int x, int y)
+/* Xor in a bit at given location. */
+{
+UBYTE rot;
+
+rot = ((unsigned)0x80) >> (x&7);
+on_off_buf[ bpr*y + (x>>3) ] ^= rot;
+}
+
+
+static void y_xor_line(int bpr, int x1, int y1, int x2, int y2)
+/* Xor in a line onto on_off_buf, only plotting when we hit a new y-value. */
+{
+UBYTE *imagept = on_off_buf;
+UBYTE rot;
+int   duty_cycle;
+int   delta_x, delta_y;
+int dots;
+int swap;
+
+if (x1 > x2)
+    {
+    swap = x1;
+    x1 = x2;
+    x2 = swap;
+    swap = y1;
+    y1 = y2;
+    y2 = swap;
+    }
+delta_y = y2-y1;
+delta_x = x2-x1;
+rot = ((unsigned)0x80) >> (x1&7);
+imagept += bpr*y1 + (x1>>3);
+
+
+if (delta_y < 0) 
+    {
+    delta_y = -delta_y;
+    bpr = -bpr;
+    }
+duty_cycle = (delta_x - delta_y)/2;
+*(imagept) ^= rot;
+if (delta_x < delta_y)
+    {
+    dots = delta_y;
+    while (--dots >= 0)
+	{
+	*(imagept) ^= rot;
+	duty_cycle += delta_x;	  /* update duty cycle */
+	imagept += bpr;
+	if (duty_cycle > 0)
+	    {
+	    duty_cycle -= delta_y;
+	    rot >>= 1;
+	    if (rot == 0)
+		{
+		imagept++;
+		rot = 0x80;
+		}
+	    }
+	}
+    }
+else
+    {
+    dots = delta_x;
+    while (--dots >= 0)
+	{
+	duty_cycle -= delta_y;	  /* update duty cycle */
+	if (duty_cycle < 0)
+	    {
+	    *(imagept) ^= rot;
+	    duty_cycle += delta_x;
+	    imagept += bpr;
+	    }
+	rot >>= 1;
+	if (rot == 0)
+	    {
+	    imagept++;
+	    rot = 0x80;
+	    }
+	}
+    }
+}
+
+ 
+static void drawAfterOnOff(struct memGfx *mg, Color color, int bpr, int width, 
+	int height)
+/* Examine bitmap and draw horizontal lines between set bits. */
+{
+UBYTE *linept = on_off_buf;
+int y;
+
+for (y=0; y<height; ++y)
+	{
+	int start = 0;
+	int end;
+	for (;;)
+	    {
+	    start = bitFindSet(linept, start, width);
+	    if (start >= width)
+	        break;
+	    end = bitFindSet(linept, start+1, width);
+	    mgLineH(mg, y+pymin, start+pxmin, end+pxmin, color);
+	    start = end+1;
+	    }
+	linept += bpr;
+	}
+}
+
+static void fillConcave(struct memGfx *mg, struct gfxPoly *poly, Color color)
+/* Draw concave polygon */
+{
+struct gfxPoint *pointpt;
+int x,y;
+int ox,oy;
+int lastdir;
+int i;
+int bpr;	/* Bytes per row */
+int width, height;
+long size;
+
+find_pminmax(poly);
+if (pymin==pymax)  /*Complex code can't cope with trivial case*/
+    {
+    mgLineH(mg, pymin, pxmin, pxmax,color);
+    return;
+    }
+width = pxmax - pxmin + 1;
+height = pymax - pymin + 1;
+bpr = ((width+7)>>3);
+size = (long)bpr*height;
+if ((on_off_buf = needMem(size)) == NULL)	
+    return;
+pointpt = poly->ptList;
+x = pointpt->x;
+y = pointpt->y;
+
+do
+	{
+	pointpt = pointpt->next;
+	ox = pointpt->x;
+	oy = pointpt->y;
+	}
+while (oy == y);
+
+if (oy>y)
+	lastdir = UPDIR;
+else
+	lastdir = DOWNDIR;
+
+i = poly->ptCount;
+while (--i >= 0)
+   {
+   pointpt = pointpt->next;
+   x = pointpt->x;
+   y = pointpt->y;
+   if (y!=oy)
+	  {
+	  y_xor_line(bpr,ox-pxmin,oy-pymin,x-pxmin,y-pymin);
+	  if (y>oy)
+		 if (lastdir == UPDIR)
+			xor_pt(bpr,ox-pxmin,oy-pymin);
+		 else
+			lastdir = UPDIR;
+	  else
+		 if (lastdir == DOWNDIR)
+			xor_pt(bpr,ox-pxmin,oy-pymin);
+		 else
+			lastdir = DOWNDIR;
+	  }
+   ox = x;
+   oy = y;
+   }
+
+drawAfterOnOff(mg, color, bpr, width, height);
+freez(&on_off_buf);
+return;
+}
+
+/*  ---- This section of code is for convex, polygons.  It's faster. ---- */
+
+#ifdef SOME_OFF_BY_ONE_PROBLEMS
+static int *xdda_ebuf(int *ebuf, int x1, int y1, int x2, int y2)
+/* Calculate the x-positions of a line from x1,y1  to x2/y2  */
+{
+int incx, incy;
+int x;
+int duty_cycle;
+int delta_x, delta_y;
+int dots;
+
+delta_y = y2-y1;
+delta_x = x2-x1;
+incx =  incy = 1;
+x = x1;
+if (delta_y < 0) 
+   {
+   delta_y = -delta_y;
+   incy = -1;
+   }
+
+if (delta_x < 0) 
+   {
+   delta_x = -delta_x;
+   incx = -1;
+   }
+
+duty_cycle = (delta_x - delta_y)/2;
+if (delta_x >= delta_y)
+    {
+    int lasty = y1-1;
+    dots = delta_x+1;
+    while (--dots >= 0)
+	{
+	if (lasty != y1)
+	    {
+	    *ebuf++ = x1;
+	    lasty = y1;
+	    }
+	duty_cycle -= delta_y;
+	x1 += incx;
+	if (duty_cycle < 0)
+	    {
+	    duty_cycle += delta_x;	  /* update duty cycle */
+	    y1+=incy;
+	    }
+	}
+    }
+else
+    {
+    dots = delta_y+1;
+    while (--dots >= 0)
+	{
+	*ebuf++ = x1;
+	duty_cycle += delta_x;
+	y1+=incy;
+	if (duty_cycle > 0)
+	    {
+	    duty_cycle -= delta_y;	  /* update duty cycle */
+	    x1 += incx;
+	    }
+	}
+    }
+return(ebuf);
+}
+#endif /* SOME_OFF_BY_ONE_PROBLEMS */
+
+
+#ifdef CONVEX_OPTIMIZATION
+int *fill_ebuf(struct gfxPoint *thread, int count, int *ebuf)
+/* Make list of x coordinates for a couple of lines.  Assumes that
+ * the y coordinates are monotonic.  Ebuf needs to be as big as the
+ * total height of thread.  Returns next free space in ebuf. */
+{
+int x, y, ox, oy;
+int i;
+
+ox = thread->x;
+oy = thread->y;
+
+for (i=0; i<count; ++i)
+   {
+   thread = thread->next;
+   x = thread->x;
+   y = thread->y;
+   if (y!=oy)
+      ebuf = xdda_ebuf(ebuf,ox,oy,x,y) - 1;
+   ox = x;
+   oy = y;
+   }
+return(ebuf+1);
+}
+
+static void blast_hlines(struct memGfx *mg, 
+	int *thread1, 	/* List of start X positions. */
+	int *thread2, 	/* Backwards list of end positions. */
+	int y, 		/* Y position. */
+	int count, 	/* Number of horizontal lines to draw. */
+	Color color)	/* Color. */
+/* Draw a whole bunch of horizontal lines. */
+{
+int x1, x2;
+thread2 += count;
+while (--count >= 0)
+    {
+    x1 = *thread1++;
+    x2 = *(--thread2);
+    if (x1 > x2)
+	mgLineH(mg, y, x2, x1, color);
+    else
+	mgLineH(mg, y, x1, x2, color);
+    y += 1;
+    }
+}
+
+void mgDrawPolyFilled(struct memGfx *mg, struct gfxPoly *poly, Color color)
+/* Draw filled polygon, possibly with outline in a seperate color. */
+{
+struct gfxPoint *p;
+struct gfxPoint *np;
+struct gfxPoint *peak;
+struct gfxPoint *valley;
+int highy;
+int i;
+int pcount;
+int lasty;
+
+peak = p = poly->ptList;
+i = poly->ptCount;
+highy = p->y;
+pcount = 0;
+while (--i > 0)
+    {
+    p = p->next;
+    if (p->y <= highy)
+	{
+	peak = p;
+	highy = p->y;
+	}
+    }
+p = peak;
+np = p->next;
+i = poly->ptCount;
+while (--i >= 0)
+    {
+    if (np->y < p->y)
+	{
+	int totalHeight;
+	int *thread1, *thread2;
+	valley = p;
+	p = np;
+	np = np->next;
+	while (--i >= 0)
+	    {
+	    if (np->y > p->y)
+		{
+		fillConcave(mg, poly, color);
+		return;	/*sorry its concave*/
+		}
+	    p = np;
+	    np = np->next;		
+	    }
+	totalHeight = valley->y - highy + 1;
+	AllocArray(thread1, totalHeight);
+	AllocArray(thread2, totalHeight);
+	fill_ebuf(peak, pcount, thread1);
+	pcount = fill_ebuf(valley, poly->ptCount - pcount, thread2)
+		- thread2;
+	blast_hlines(mg, thread1, thread2, highy, pcount, color);
+	freeMem(thread1);
+	freeMem(thread2);
+	return;
+	}
+    pcount++;
+    p = np;
+    np = np->next;
+    }	
+return;	/*all points of poly have same y value */
+}
+#endif /* CONVEX_OPTIMIZATION */
+
+void mgDrawPoly(struct memGfx *mg, struct gfxPoly *poly, Color color,
+	boolean filled)
+/* Draw polygon, possibly filled in color. */
+{
+if (filled)
+    fillConcave(mg, poly, color);
+    // mgDrawPolyFilled(mg, poly, color);
+mgDrawPolyOutline(mg, poly, color);
+}
+
diff --git a/lib/mime.c b/lib/mime.c
new file mode 100644
index 0000000..2914167
--- /dev/null
+++ b/lib/mime.c
@@ -0,0 +1,687 @@
+/* Routines for processing MIME from a descriptor.
+ *   For cgi post, the MIME descriptor is stdin.
+ *   We want to parse it as it comes in so that 
+ *   we can handle very large files if needed.
+ *   Large data are saved to tempfiles.
+ *   Small data stays as ptr+size in memory.
+ *
+ * This file is copyright 2005 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "hash.h"
+#include "linefile.h"
+#include "cheapcgi.h"
+#include "portable.h"
+#include "errabort.h"
+#include "mime.h"
+
+/* 
+ * Note: MIME is a nested structure that makes a tree that streams in depth-first.
+ */
+
+#define MAXPARTSIZE 64LL*1024*1024*1024  /* max size before gets put in a tempfile to save memory. It currently has been set so large that it will not be triggered. */
+#define MAXPARTLINESIZE 1024 /* header lines should be small, so bad if bigger than this */
+#define MAXDATASIZE 64LL*1024*1024*1024 /* max size allowable for large uploads */
+#define MAXBOUNDARY 72+5     /* max size of buffer for boundary 72+--""0 */
+
+enum nlType nlType = nlt_undet;
+
+static void setEopMB(struct mimeBuf *b)
+/* do a search for boundary, set eop End Of Part if found */
+{
+if (b->blen > 0)
+    b->eop = memMatch(b->boundary, b->blen, b->i, b->eoi - b->i);
+else
+    b->eop = NULL;
+}
+
+static void setEodMB(struct mimeBuf *b)
+/* set end of data - eoi minus (boundary-size -1) */
+{
+if (b->blen > 1 && b->eoi == b->eom) 
+    {
+    b->eod = b->eoi - (b->blen-1);
+    }
+else
+    {
+    b->eod = b->eoi;
+    }
+}
+
+static void setBoundaryMB(struct mimeBuf *b, char *boundary)
+/* set boundary in b */
+{
+b->boundary = boundary;
+b->blen = boundary ? strlen(b->boundary) : 0;
+setEopMB(b);
+setEodMB(b);
+}
+
+#ifdef DEBUG
+static void dumpMB(struct mimeBuf *b)
+/* debug dump */
+{
+int i=0;
+
+fprintf(stderr,"b->i  =%lu "
+      "b->eop=%lu "
+      "b->eod=%lu "
+      "b->eoi=%lu "
+      "b->eom=%lu "
+      "%s "
+      "%d "
+      "\n", 
+    (unsigned long) b->i,
+    (unsigned long) b->eop,
+    (unsigned long) b->eod,
+    (unsigned long) b->eoi,
+    (unsigned long) b->eom,
+    b->boundary,
+    b->blen
+    );
+fprintf(stderr,"*");    
+for(i=0;i<MIMEBUFSIZE;++i)
+    {
+    fprintf(stderr,"%c", (b->buf[i] < 31 || (unsigned) b->buf[i] > 127) ? '.' : b->buf[i] );
+    }
+fprintf(stderr,"\n\n");    
+}
+#endif
+
+static void moreMimeBuf(struct mimeBuf *b)
+{
+int bytesRead = 0, bytesToRead = 0;
+if (b->blen > 1)
+    {
+    int r = b->eoi - b->i;
+    memmove(b->buf, b->i, r);
+    b->eoi = b->buf+r;
+    }
+else
+    {
+    b->eoi = b->buf;
+    }
+b->i = b->buf+0;
+bytesToRead = b->eom - b->eoi;
+while (bytesToRead > 0)
+    {
+    bytesRead = read(b->d, b->eoi, bytesToRead);
+    if (bytesRead < 0)
+        errnoAbort("moreMimeBuf: error reading MIME input descriptor");
+    b->eoi += bytesRead;
+    if (bytesRead == 0)
+        break;
+    bytesToRead = bytesToRead - bytesRead;
+    }
+setEopMB(b);
+setEodMB(b);
+//debug
+//fprintf(stderr,"post-moreMime dumpMB: ");
+//dumpMB(b);  //debug
+}
+
+static char getcMB(struct mimeBuf *b)
+/* read just one char from MIME buffer */
+{
+if (b->i >= b->eoi && b->eoi < b->eom)  /* at end of input */
+    errAbort("getcMB error - requested input beyond end of MIME input.");
+if (b->i >= b->eod && b->eoi == b->eom) /* at end of buffer */
+    moreMimeBuf(b);
+    
+//fprintf(stderr,"b->buf:%lu b->i:%lu %c \n",
+//    (unsigned long) b->buf,
+//    (unsigned long) b->i,
+//    *b->i
+//    );
+//fprintf(stderr,"%c",*b->i);
+//fflush(stderr); 
+return *b->i++;    
+}
+
+static void putBackMB(struct mimeBuf *b)
+/* Rewind just one char back in MIME buffer.
+ * Do not use except for distinguishing line type initially */
+{
+if (b->i == b->buf)  /* at beginning of buffer */
+    errAbort("putBackMB error - requested pushback beyond beginning buffer.");
+b->i--;    
+}
+
+static char *getLineMB(struct mimeBuf *b)
+/* Reads one line up to CRLF, returned string does not include CRLF however. 
+   Use freeMem when done with string. */
+{
+char line[MAXPARTLINESIZE];
+int i = 0;
+char c = 0;
+line[0]=0;
+while(TRUE)
+    {
+    c =getcMB(b);
+    if ((c == 0x0d) || (c == 0x0a))  /* CR or LF is end of line */
+	break;
+    line[i++] = c;
+    if (i >= MAXPARTLINESIZE)
+	errAbort("getLineMB error - MIME input header too long, "
+		    "greater than %d chars",MAXPARTLINESIZE);
+    }
+line[i] = 0; /* terminate string */ 
+if (nlType == nlt_undet)  /* determine newline type */
+    {
+    if (c == 0x0d)
+	{
+	nlType = nlt_mac;
+	c = getcMB(b);
+	if (c == 0x0a)
+	    nlType = nlt_dos;
+	else
+    	    putBackMB(b);
+	}
+    else
+	{
+	nlType = nlt_unix;
+	}
+    }
+else if (nlType == nlt_dos)
+    {
+    if (c == 0x0d)
+    	getcMB(b); /* just waste the LF */
+    else
+	nlType = nlt_unix;
+    }
+return cloneString(line);
+}
+
+
+static void getChunkMB(struct mimeBuf *b, char **address, int *size, boolean *hasZeros)
+/* Pass back address and size of chunk, and whether it contains embedded zeros.
+   The chunk is the largest piece of data left in the buffer up to the eod or eop. */
+{
+char *eoc = b->eop ? b->eop : b->eod; /* end of chunk */
+//debug
+//fprintf(stderr,"pre-getChunkMB dumpMB: ");
+//dumpMB(b);  //debug
+*address=b->i;
+*size=eoc - b->i;
+*hasZeros = (memMatch("", 1,*address, *size) != NULL);
+b->i = eoc;
+}
+
+static void readPartHeaderMB(struct mimeBuf *b, struct mimePart *p, char *altHeader)
+/* Reads the header lines of the mimePart,
+   saves the header settings in a hash.  */
+{
+struct dyString *fullLine = dyStringNew(0);
+char *key=NULL, *val=NULL;
+struct lineFile *lf = NULL;
+char *line = NULL;
+char *lineAhead = NULL;
+int size = 0;
+p->hdr = newHash(3);
+	//debug
+    	//fprintf(stderr,"headers dumpMB: ");
+	//dumpMB(b);  //debug
+if (altHeader)
+    {
+    lf = lineFileOnString("MIME Header", TRUE, altHeader);
+    }
+/* read ahead one line, skipping any leading blanks lines */   
+do
+    {
+    if (altHeader)
+	lineFileNext(lf, &lineAhead, &size);
+    else
+	lineAhead = getLineMB(b);
+    } 
+    while (sameString(lineAhead,""));
+
+do
+    {
+    /* accumulate a full header line - some emailers split into mpl lines */
+    dyStringClear(fullLine);
+    do 
+	{
+	line = lineAhead;
+	if (altHeader)
+	    lineFileNext(lf, &lineAhead, &size);
+	else
+	    lineAhead = getLineMB(b);
+	dyStringAppend(fullLine,line);    
+	if (!altHeader) 
+	    freez(&line);
+	} while (isspace(lineAhead[0]));
+    line = fullLine->string;
+    //fprintf(stderr,"found a line! [%s]\n",line);  //debug
+    key = line;
+    val = strchr(line,':');
+    if (!val)
+	errAbort("readPartHeaderMB error - header-line colon not found, line=[%s]",line);
+    *val = 0;
+    val++;
+    key=trimSpaces(key);
+    // since the hash is case-sensitive, convert to lower case for ease of matching
+    tolowers(key);  
+    val=trimSpaces(val);
+    hashAdd(p->hdr,key,cloneString(val));
+    
+    //debug
+    //fprintf(stderr,"MIME header: key=[%s], val=[%s]\n",key,val);
+    //fflush(stderr); 
+    
+    } while (!sameString(lineAhead,""));
+if (altHeader)
+    {
+    if (nlType == nlt_undet)
+	nlType = lf->nlType;
+    lineFileClose(&lf);
+    }
+else
+    {
+    freez(&lineAhead);
+    }
+dyStringFree(&fullLine);
+    
+}
+
+
+struct mimeBuf * initMimeBuf(int d)
+/* d is a descriptor for a file or socket or some other descriptor 
+   that the MIME input can be read from. 
+   Initializes the mimeBuf structure. */
+{
+struct mimeBuf *b=AllocA(*b);
+b->d = d;
+b->boundary = NULL;
+b->blen = 0;
+b->eom = b->buf+MIMEBUFSIZE;
+b->eoi = b->eom;
+b->eod = b->eom;
+b->i = b->eom;
+moreMimeBuf(b);
+return b;
+}
+
+char *getMimeHeaderMainVal(char *header)
+/* Parse a typical mime header line returning the first
+ * main value up to whitespace, punctuation, or end. 
+ * freeMem the returned string when done */
+{
+char value[1024]; 
+char *h = header;
+int i = 0;
+char *puncChars = ",;: \t\r\n"; /* punctuation chars */
+i=0;
+/* The header should have already been trimmed of leading and trailing spaces */
+while(TRUE)
+    {
+    char c = *h++;
+    if (c==0 || strchr(puncChars,c))
+	break;
+    value[i++] = c;
+    if (i >= sizeof(value))
+	errAbort("error: main value too long (>%lu) in MIME header Content-type:%s",(unsigned long)sizeof(value),header);
+    }
+value[i] = 0;    
+
+return cloneString(value);
+
+}
+
+
+char *getMimeHeaderFieldVal(char *header, char *field)
+/* Parse a typical mime header line looking for field=
+ * and return the value which may be quoted.
+ * freeMem the returned string when done */
+{
+char value[1024]; 
+char *fld = header;
+int i = 0;
+char *puncChars = ",;: \t\r\n"; /* punctuation chars */
+while (TRUE)
+    {
+    fld = strstr(fld,field);
+    if (!fld)
+	return NULL;
+    if (fld > header && strchr(puncChars,fld[-1]))
+	{
+	fld+=strlen(field);
+	if (*fld == '=')
+	    {
+	    ++fld;
+	    break;
+	    }
+	}    
+    else
+	{
+	++fld;
+	}
+    }	
+if (*fld == '"')
+    {
+    puncChars = "\"";  /* quoted */
+    ++fld;
+    }
+i=0;
+while(TRUE)
+    {
+    char c = *fld++;
+    if (c==0 || strchr(puncChars,c))
+	break;
+    value[i++] = c;
+    if (i >= sizeof(value))
+	errAbort("error: %s= value too long (>%lu) in MIME header Content-type:%s",field,(unsigned long)sizeof(value),header);
+    }
+value[i] = 0;    
+
+return cloneString(value);
+
+}
+
+char *getNewLineByType()
+/* just use global nlType setting */
+{
+switch (nlType)
+    {
+    case nlt_dos:
+	//debug
+    	//fprintf(stderr,"nlType=nlt_dos\n");
+	return "\x0d\x0a";
+    case nlt_mac:
+	//debug
+    	//fprintf(stderr,"nlType=nlt_mac\n");
+	return "\x0d";
+    case nlt_unix:
+    default:
+	//debug
+    	//fprintf(stderr,"nlType=nlt_unix\n");
+	return "\x0a";
+    }
+}
+
+struct mimePart *parseMultiParts(struct mimeBuf *b, char *altHeader)
+/* This is a recursive function.  It parses multipart MIME messages.
+   Data that are binary or too large will be saved in mimePart->filename
+   otherwise saved as a c-string in mimePart->data.  If multipart,
+   then first child is mimePart->child, subsequent sibs are in child->next.
+   altHeader is a string of headers that can be fed in if the headers have
+   already been read off the stream by an earlier process, i.e. apache.
+ */
+{ 
+struct mimePart *p=AllocA(*p);
+char *parentboundary = NULL, *boundary = NULL;
+char *ct = NULL;
+boolean autoBoundary = FALSE;
+
+
+//debug
+//fprintf(stderr,"altHeader=[%s]\n",altHeader);
+
+if (sameOk(altHeader, "autoBoundary"))
+    { /* process things with no explicit header.
+       *  look for *MIME* \n\n-- */
+    struct dyString *dy = dyStringNew(0);
+    char *prevPrevLine = NULL;
+    char *prevLine = NULL;
+    char *line = NULL;
+    boolean found = FALSE;
+    autoBoundary = TRUE;
+    while (TRUE)
+	{
+	if (b->i >= b->eoi && b->eoi < b->eom)  /* at end of input */
+	    break;
+	line = getLineMB(b);
+	if (line && startsWith("--",line) // && 
+	    //sameString(prevLine,"") && 
+	    //prevPrevLine &&
+	    //stringIn("MULTI",prevPrevLine) && 
+	    //stringIn("MIME",prevPrevLine) 
+	    )
+	    {
+	    found = TRUE;
+	    break;
+	    }
+	freez(&prevPrevLine);
+	prevPrevLine = prevLine;
+	prevLine = line;
+	if (prevPrevLine)
+	    touppers(prevPrevLine);
+	}
+    if (!found)
+	errAbort("autoBoundary: No initial boundary found.");
+
+    dyStringPrintf(dy, "CONTENT-TYPE:multipart/form-data; boundary=%s%s%s", 
+	line+2, getNewLineByType(), getNewLineByType() );
+    altHeader = dyStringCannibalize(&dy); 
+    
+    //debug
+    //fprintf(stderr,"autoBoundary altHeader = [%s]\n",altHeader);
+    //fflush(stderr); 
+
+    freez(&prevPrevLine);	    
+    freez(&prevLine);	    
+    freez(&line);	    
+    }
+
+//debug
+//fprintf(stderr,"\n");
+readPartHeaderMB(b,p,altHeader);
+
+ct = hashFindVal(p->hdr,"content-type");  /* use lowercase key */
+//debug
+//fprintf(stderr,"ct from hash:%s\n",ct);
+//fflush(stderr); 
+
+if (ct && startsWith("multipart/",ct))
+    {
+    char bound[MAXBOUNDARY]; 
+    char *bnd = NULL;
+    struct mimePart *child = NULL;
+
+    /* these 3 vars just for processing epilog chunk: */
+    char *bp=NULL;
+    int size=0;
+    boolean hasZeros=FALSE;
+
+    /* save */
+    parentboundary = b->boundary;
+
+    boundary = getMimeHeaderFieldVal(ct,"boundary");
+    if (strlen(boundary) >= MAXBOUNDARY)
+	errAbort("error: boundary= value too long in MIME header Content-type:%s",ct);
+    safef(bound, sizeof(bound), "--%s",boundary);  /* do not prepend CRLF to boundary yet */
+    freez(&boundary);
+    boundary = cloneString(bound);
+    //debug
+    //fprintf(stderr,"initial boundary parsed:%s\n",boundary);
+    //fflush(stderr); 
+
+    if (!autoBoundary)
+	{
+	/* skip any extra "prolog" before the initial boundary marker */
+	while (TRUE)
+	    {
+	    bnd = getLineMB(b);
+	    if (sameString(bnd,boundary)) 
+	       break;
+	    freez(&bnd);
+	    }
+	    //debug
+	    //fprintf(stderr,"initial boundary found:%s\n",bnd);
+	    //fflush(stderr); 
+	freez(&bnd);
+	}
+
+    /* include crlf in the boundary so bodies won't have trailing a CRLF
+     * this is done here so that in case there's no extra CRLF
+     * between the header and the boundary, it will still work,
+     * so we only prepend the CRLF to the boundary after initial found */
+    safef(bound,sizeof(bound),"%s%s", getNewLineByType(), boundary);
+    freez(&boundary);
+    boundary=cloneString(bound);
+    
+    setBoundaryMB(b, boundary);
+
+    while(TRUE)
+	{
+	int i = 0;
+	char c1 = ' ', c2 = ' ';
+    	child = parseMultiParts(b,NULL);
+	slAddHead(&p->multi,child);
+	//call getLine, compare to boundary 
+	/* skip extra initial boundary marker - it's moot anyway */
+	freez(&bnd);
+	    //debug
+	    //fprintf(stderr,"post-parse pre-getLineMB dumpMB: ");
+	    //dumpMB(b);  //debug
+	for (i=0;i<strlen(boundary);++i)
+	    bound[i] = getcMB(b);
+	bound[i] = 0;    
+	if (!sameString(bound,boundary))
+	    errAbort("expected boundary %s, but found %s in MIME",boundary,bound);
+	//debug
+    	//fprintf(stderr,"\nfound boundary:%s\n",bound);
+	//fflush(stderr); 
+    	c1 = getcMB(b);
+	if (c1 == '-')
+	    {
+	    c2 = getcMB(b);
+	    if (c2 == '-')
+    		break;  /* last boundary found */
+	    else		    
+	    	errAbort("expected -- after boundary %s, but found %c%c in MIME",boundary,c1,c2);
+	    }
+	if (nlType == nlt_dos)
+	    c2 = getcMB(b);
+	switch (nlType)
+	    {
+	    case nlt_dos:
+		if (c1 == 0x0d && c2 == 0x0a)
+		    break;
+		else		    
+		    errAbort("expected CRLF after boundary %s, but found %c%c in MIME",boundary,c1,c2);
+	    case nlt_unix:
+		if (c1 == 0x0a)
+		    break;
+		else		    
+		    errAbort("expected LF after boundary %s, but found %c in MIME",boundary,c1);
+	    case nlt_mac:
+		if (c1 == 0x0d)
+		    break;
+		else		    
+		    errAbort("expected CR after boundary %s, but found %c in MIME",boundary,c1);
+	    default:
+		    errAbort("unexpected nlType %d after boundary %s",nlType,boundary);
+	    }
+	setEopMB(b);
+	}	
+    freez(&bnd);
+    slReverse(&p->multi);
+    /* restore */
+    freez(&boundary);
+    boundary = parentboundary;
+	//debug
+    	//fprintf(stderr,"restoring parent boundary = %s\n",boundary);
+    setBoundaryMB(b, boundary);
+
+    /* dump any "epilog" that may be between the 
+     * end of the child boundary and the parent boundary */
+    getChunkMB(b, &bp, &size, &hasZeros);
+    //debug
+    //fprintf(stderr,"epilog size=%d\n",size);
+    	   
+    
+    }
+else
+    {
+    char *bp=NULL;
+    int size=0;
+    boolean hasZeros=FALSE;
+    boolean toobig=FALSE;
+    boolean asFile=FALSE;
+    boolean convert=FALSE;
+    FILE *f = NULL;
+    struct dyString *dy=newDyString(1024);
+    //debug
+    //fprintf(stderr,"starting new part (non-multi), dumpMB: \n");
+    //dumpMB(b);  //debug
+    
+    //debug
+    //ct = hashFindVal(p->hdr,"content-transfer-encoding");  /* use lowercase key */
+    //fprintf(stderr,"cte from hash:%s\n",ct);
+	
+    while(TRUE)
+	{
+	// break if eop, eod, eoi
+    	getChunkMB(b, &bp, &size, &hasZeros);
+	//debug
+    	//fprintf(stderr,"bp=%lu size=%d, hasZeros=%d \n", 
+	//    (unsigned long) bp,
+	//    size,
+	//    hasZeros);
+	if (hasZeros)
+	    {
+	    p->binary=TRUE;
+	    }
+	//if (hasZeros && !asFile)
+	//    {
+	//    convert=TRUE;
+	//    }
+	if (!asFile && p->size+size > MAXPARTSIZE)
+	    {
+	    toobig = TRUE;
+	    convert=TRUE;
+	    }
+	if (convert)
+	    {
+	    struct tempName uploadedData;
+	    convert=FALSE;
+	    asFile = TRUE;
+	    makeTempName(&uploadedData, "hgSs", ".cgi");
+	    p->fileName=cloneString(uploadedData.forCgi);
+	    f = mustOpen(p->fileName,"w");
+	    mustWrite(f,dy->string,dy->stringSize);
+	    freeDyString(&dy);
+	    }
+	if (asFile)
+	    {
+	    mustWrite(f,bp,size);
+	    }
+	else
+	    {
+    	    dyStringAppendN(dy,bp,size);
+	    }
+	p->size+=size;
+	if (p->size > MAXDATASIZE)
+	    errAbort("max data size allowable for upload in MIME exceeded %llu",(unsigned long long)MAXDATASIZE);
+	    
+	
+	if (b->eop && b->i == b->eop)  /* end of part */
+	    {
+	    break;
+	    }
+	if (b->i == b->eoi && b->eoi < b->eom) /* end of data */
+	    {
+	    break;
+	    }
+	moreMimeBuf(b);
+	}
+    if (dy)
+	{
+	p->data=needLargeMem(dy->stringSize+1);
+	memcpy(p->data,dy->string,dy->stringSize);
+	p->data[dy->stringSize] = 0;
+    	freeDyString(&dy);
+	}
+    if (f)
+	carefulClose(&f);
+
+    //debug
+    //fprintf(stderr,"p->fileName=%s p->data=[%s]\n",p->fileName,p->data);
+
+    }
+
+return p;
+}
+
+
diff --git a/lib/net.c b/lib/net.c
new file mode 100644
index 0000000..03fb764
--- /dev/null
+++ b/lib/net.c
@@ -0,0 +1,2594 @@
+/* net.c some stuff to wrap around net communications. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+#include <utime.h>
+#include <pthread.h>
+#include "internet.h"
+#include "errabort.h"
+#include "hash.h"
+#include "net.h"
+#include "linefile.h"
+#include "base64.h"
+#include "cheapcgi.h"
+#include "https.h"
+#include "sqlNum.h"
+#include "obscure.h"
+
+
+/* Brought errno in to get more useful error messages */
+
+extern int errno;
+
+static int netStreamSocket()
+/* Create a TCP/IP streaming socket.  Complain and return something
+ * negative if can't */
+{
+int sd = socket(AF_INET, SOCK_STREAM, 0);
+if (sd < 0)
+    warn("Couldn't make AF_INET socket.");
+return sd;
+}
+
+static int netConnectWithTimeout(char *hostName, int port, long msTimeout)
+/* In order to avoid a very long default timeout (several minutes) for hosts that will
+ * not answer the port, we are forced to connect non-blocking.
+ * After the connection has been established, we return to blocking mode. */
+{
+int sd;
+struct sockaddr_in sai;		/* Some system socket info. */
+int res;
+fd_set mySet;
+struct timeval lTime;
+long fcntlFlags;
+
+if (hostName == NULL)
+    {
+    warn("NULL hostName in netConnect");
+    return -1;
+    }
+if (!internetFillInAddress(hostName, port, &sai))
+    return -1;
+if ((sd = netStreamSocket()) < 0)
+    return sd;
+
+// Set non-blocking
+if ((fcntlFlags = fcntl(sd, F_GETFL, NULL)) < 0) 
+    {
+    warn("Error fcntl(..., F_GETFL) (%s)", strerror(errno));
+    close(sd);
+    return -1;
+    }
+fcntlFlags |= O_NONBLOCK;
+if (fcntl(sd, F_SETFL, fcntlFlags) < 0) 
+    {
+    warn("Error fcntl(..., F_SETFL) (%s)", strerror(errno));
+    close(sd);
+    return -1;
+    }
+
+// Trying to connect with timeout
+res = connect(sd, (struct sockaddr*) &sai, sizeof(sai));
+if (res < 0)
+    {
+    if (errno == EINPROGRESS)
+	{
+	while (1) 
+	    {
+	    lTime.tv_sec = (long) (msTimeout/1000);
+	    lTime.tv_usec = (long) (((msTimeout/1000)-lTime.tv_sec)*1000000);
+	    FD_ZERO(&mySet);
+	    FD_SET(sd, &mySet);
+	    res = select(sd+1, NULL, &mySet, &mySet, &lTime);
+	    if (res < 0) 
+		{
+		if (errno != EINTR) 
+		    {
+		    warn("Error in select() during TCP non-blocking connect %d - %s", errno, strerror(errno));
+		    close(sd);
+		    return -1;
+		    }
+		}
+	    else if (res > 0)
+		{
+		// Socket selected for write when it is ready
+		int valOpt;
+		socklen_t lon;
+                // But check the socket for any errors
+                lon = sizeof(valOpt);
+                if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (void*) (&valOpt), &lon) < 0)
+                    {
+                    warn("Error in getsockopt() %d - %s", errno, strerror(errno));
+                    close(sd);
+                    return -1;
+                    }
+                // Check the value returned...
+                if (valOpt)
+                    {
+                    warn("Error in TCP non-blocking connect() %d - %s", valOpt, strerror(valOpt));
+                    close(sd);
+                    return -1;
+                    }
+		break;
+		}
+	    else
+		{
+		warn("TCP non-blocking connect() to %s timed-out in select() after %ld milliseconds - Cancelling!", hostName, msTimeout);
+		close(sd);
+		return -1;
+		}
+	    }
+	}
+    else
+	{
+	warn("TCP non-blocking connect() error %d - %s", errno, strerror(errno));
+	close(sd);
+	return -1;
+	}
+    }
+
+// Set to blocking mode again
+if ((fcntlFlags = fcntl(sd, F_GETFL, NULL)) < 0)
+    {
+    warn("Error fcntl(..., F_GETFL) (%s)", strerror(errno));
+    close(sd);
+    return -1;
+    }
+fcntlFlags &= (~O_NONBLOCK);
+if (fcntl(sd, F_SETFL, fcntlFlags) < 0)
+    {
+    warn("Error fcntl(..., F_SETFL) (%s)", strerror(errno));
+    close(sd);
+    return -1;
+    }
+
+return sd;
+
+}
+
+
+int netConnect(char *hostName, int port)
+/* Start connection with a server. */
+{
+return netConnectWithTimeout(hostName, port, 10000); // 10 seconds connect timeout
+}
+
+int netMustConnect(char *hostName, int port)
+/* Start connection with server or die. */
+{
+int sd = netConnect(hostName, port);
+if (sd < 0)
+   noWarnAbort();
+return sd;
+}
+
+int netMustConnectTo(char *hostName, char *portName)
+/* Start connection with a server and a port that needs to be converted to integer */
+{
+if (!isdigit(portName[0]))
+    errAbort("netConnectTo: ports must be numerical, not %s", portName);
+return netMustConnect(hostName, atoi(portName));
+}
+
+
+int netAcceptingSocketFrom(int port, int queueSize, char *host)
+/* Create a socket that can accept connections from a 
+ * IP address on the current machine if the current machine
+ * has multiple IP addresses. */
+{
+struct sockaddr_in sai;
+int sd;
+int flag = 1;
+
+netBlockBrokenPipes();
+if ((sd = netStreamSocket()) < 0)
+    return sd;
+if (!internetFillInAddress(host, port, &sai))
+    return -1;
+if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)))
+    return -1;
+if (bind(sd, (struct sockaddr*)&sai, sizeof(sai)) == -1)
+    {
+    warn("Couldn't bind socket to %d: %s", port, strerror(errno));
+    close(sd);
+    return -1;
+    }
+listen(sd, queueSize);
+return sd;
+}
+
+int netAcceptingSocket(int port, int queueSize)
+/* Create a socket that can accept connections from
+ * anywhere. */
+{
+return netAcceptingSocketFrom(port, queueSize, NULL);
+}
+
+int netAccept(int sd)
+/* Accept incoming connection from socket descriptor. */
+{
+socklen_t fromLen;
+return accept(sd, NULL, &fromLen);
+}
+
+int netAcceptFrom(int acceptor, unsigned char subnet[4])
+/* Wait for incoming connection from socket descriptor
+ * from IP address in subnet.  Subnet is something
+ * returned from netParseSubnet or internetParseDottedQuad. 
+ * Subnet may be NULL. */
+{
+struct sockaddr_in sai;		/* Some system socket info. */
+ZeroVar(&sai);
+sai.sin_family = AF_INET;
+for (;;)
+    {
+    socklen_t addrSize = sizeof(sai);
+    int sd = accept(acceptor, (struct sockaddr *)&sai, &addrSize);
+    if (sd >= 0)
+	{
+	if (subnet == NULL)
+	    return sd;
+	else
+	    {
+	    unsigned char unpacked[4]; 
+	    internetUnpackIp(ntohl(sai.sin_addr.s_addr), unpacked);
+	    if (internetIpInSubnet(unpacked, subnet))
+		{
+		return sd;
+		}
+	    else
+		{
+		close(sd);
+		}
+	    }
+	}
+    }
+}
+
+FILE *netFileFromSocket(int socket)
+/* Wrap a FILE around socket.  This should be fclose'd
+ * and separately the socket close'd. */
+{
+FILE *f;
+if ((socket = dup(socket)) < 0)
+   errnoAbort("Couldn't dupe socket in netFileFromSocket");
+f = fdopen(socket, "r+");
+if (f == NULL)
+   errnoAbort("Couldn't fdopen socket in netFileFromSocket");
+return f;
+}
+
+static boolean plumberInstalled = FALSE;
+
+void netBlockBrokenPipes()
+/* Make it so a broken pipe doesn't kill us. */
+{
+if (!plumberInstalled)
+    {
+    signal(SIGPIPE, SIG_IGN);       /* Block broken pipe signals. */
+    plumberInstalled = TRUE;
+    }
+}
+
+size_t netReadAll(int sd, void *vBuf, size_t size)
+/* Read given number of bytes into buffer.
+ * Don't give up on first read! */
+{
+char *buf = vBuf;
+size_t totalRead = 0;
+int oneRead;
+
+if (!plumberInstalled)
+    netBlockBrokenPipes();
+while (totalRead < size)
+    {
+    oneRead = read(sd, buf + totalRead, size - totalRead);
+    if (oneRead < 0)
+	return oneRead;
+    if (oneRead == 0)
+        break;
+    totalRead += oneRead;
+    }
+return totalRead;
+}
+
+int netMustReadAll(int sd, void *vBuf, size_t size)
+/* Read given number of bytes into buffer or die.
+ * Don't give up if first read is short! */
+{
+int ret = netReadAll(sd, vBuf, size);
+if (ret < 0)
+    errnoAbort("Couldn't finish netReadAll");
+return ret;
+}
+
+static void notGoodSubnet(char *sns)
+/* Complain about subnet format. */
+{
+errAbort("'%s' is not a properly formatted subnet.  Subnets must consist of\n"
+         "one to three dot-separated numbers between 0 and 255", sns);
+}
+
+void netParseSubnet(char *in, unsigned char out[4])
+/* Parse subnet, which is a prefix of a normal dotted quad form.
+ * Out will contain 255's for the don't care bits. */
+{
+out[0] = out[1] = out[2] = out[3] = 255;
+if (in != NULL)
+    {
+    char *snsCopy = strdup(in);
+    char *words[5];
+    int wordCount, i;
+    wordCount = chopString(snsCopy, ".", words, ArraySize(words));
+    if (wordCount > 3 || wordCount < 1)
+        notGoodSubnet(in);
+    for (i=0; i<wordCount; ++i)
+	{
+	char *s = words[i];
+	int x;
+	if (!isdigit(s[0]))
+	    notGoodSubnet(in);
+	x = atoi(s);
+	if (x > 255)
+	    notGoodSubnet(in);
+	out[i] = x;
+	}
+    freez(&snsCopy);
+    }
+}
+
+static void parseByteRange(char *url, ssize_t *rangeStart, ssize_t *rangeEnd, boolean terminateAtByteRange)
+/* parse the byte range information from url */
+{
+char *x;
+/* default to no byte range specified */
+*rangeStart = -1;
+*rangeEnd = -1;
+x = strrchr(url, ';');
+if (x)
+    {
+    if (startsWith(";byterange=", x))
+	{
+	char *y=strchr(x, '=');
+	++y;
+	char *z=strchr(y, '-');
+	if (z)
+	    {
+	    ++z;
+	    if (terminateAtByteRange)
+		*x = 0;
+	    // TODO: use something better than atoll() ?
+	    *rangeStart = atoll(y); 
+	    if (z[0] != '\0')
+		*rangeEnd = atoll(z);
+	    }    
+	}
+    }
+
+}
+
+void netParseUrl(char *url, struct netParsedUrl *parsed)
+/* Parse a URL into components.   A full URL is made up as so:
+ *   http://user:password@hostName:port/file;byterange=0-499
+ * User and password may be cgi-encoded.
+ * This is set up so that the http:// and the port are optional. 
+ */
+{
+char *s, *t, *u, *v, *w;
+char buf[1024];
+
+/* Make local copy of URL. */
+if (strlen(url) >= sizeof(buf))
+    errAbort("Url too long: '%s'", url);
+strcpy(buf, url);
+url = buf;
+
+/* Find out protocol - default to http. */
+s = trimSpaces(url);
+s = stringIn("://", url);
+if (s == NULL)
+    {
+    strcpy(parsed->protocol, "http");
+    s = url;
+    }
+else
+    {
+    *s = 0;
+    tolowers(url);
+    safecpy(parsed->protocol, sizeof(parsed->protocol), url);
+    s += 3;
+    }
+
+/* Split off file part. */
+parsed->byteRangeStart = -1;  /* default to no byte range specified */
+parsed->byteRangeEnd = -1;
+u = strchr(s, '/');
+if (u == NULL)
+    strcpy(parsed->file, "/");
+else
+    {
+    parseByteRange(u, &parsed->byteRangeStart, &parsed->byteRangeEnd, TRUE);
+
+    /* need to encode spaces, but not ! other characters */
+    char *t=replaceChars(u," ","%20");
+    safecpy(parsed->file, sizeof(parsed->file), t);
+    freeMem(t);
+    *u = 0;
+    }
+
+/* Split off user part */
+v = strchr(s, '@');
+if (v == NULL)
+    {
+    if (sameWord(parsed->protocol,"http") ||
+        sameWord(parsed->protocol,"https"))
+	{
+	strcpy(parsed->user, "");
+	strcpy(parsed->password, "");
+	}
+    if (sameWord(parsed->protocol,"ftp"))
+	{
+	strcpy(parsed->user, "anonymous");
+	strcpy(parsed->password, "x at genome.ucsc.edu");
+	}
+    }
+else
+    {
+    *v = 0;
+    /* split off password part */
+    w = strchr(s, ':');
+    if (w == NULL)
+	{
+	safecpy(parsed->user, sizeof(parsed->user), s);
+	strcpy(parsed->password, "");
+	}
+    else
+	{
+	*w = 0;
+	safecpy(parsed->user, sizeof(parsed->user), s);
+	safecpy(parsed->password, sizeof(parsed->password), w+1);
+	}
+    
+    cgiDecode(parsed->user,parsed->user,strlen(parsed->user));
+    cgiDecode(parsed->password,parsed->password,strlen(parsed->password));
+    s = v+1;
+    }
+
+
+/* Save port if it's there.  If not default to 80. */
+t = strchr(s, ':');
+if (t == NULL)
+    {
+    if (sameWord(parsed->protocol,"http"))
+	strcpy(parsed->port, "80");
+    if (sameWord(parsed->protocol,"https"))
+	strcpy(parsed->port, "443");
+    if (sameWord(parsed->protocol,"ftp"))
+	strcpy(parsed->port, "21");
+    }
+else
+    {
+    *t++ = 0;
+    if (!isdigit(t[0]))
+	errAbort("Non-numeric port name %s", t);
+    safecpy(parsed->port, sizeof(parsed->port), t);
+    }
+
+/* What's left is the host. */
+safecpy(parsed->host, sizeof(parsed->host), s);
+}
+
+char *urlFromNetParsedUrl(struct netParsedUrl *npu)
+/* Build URL from netParsedUrl structure */
+{
+struct dyString *dy = newDyString(512);
+
+dyStringAppend(dy, npu->protocol);
+dyStringAppend(dy, "://");
+if (npu->user[0] != 0)
+    {
+    char *encUser = cgiEncode(npu->user);
+    dyStringAppend(dy, encUser);
+    freeMem(encUser);
+    if (npu->password[0] != 0)
+	{
+	dyStringAppend(dy, ":");
+	char *encPassword = cgiEncode(npu->password);
+	dyStringAppend(dy, encPassword);
+	freeMem(encPassword);
+	}
+    dyStringAppend(dy, "@");
+    }
+dyStringAppend(dy, npu->host);
+/* do not include port if it is the default */
+if (!(
+ (sameString(npu->protocol, "ftp"  ) && sameString("21", npu->port)) ||
+ (sameString(npu->protocol, "http" ) && sameString("80", npu->port)) ||
+ (sameString(npu->protocol, "https") && sameString("443",npu->port))
+    ))
+    {
+    dyStringAppend(dy, ":");
+    dyStringAppend(dy, npu->port);
+    }
+dyStringAppend(dy, npu->file);
+if (npu->byteRangeStart != -1)
+    {
+    dyStringPrintf(dy, ";byterange=%lld-", (long long)npu->byteRangeStart);
+    if (npu->byteRangeEnd != -1)
+	dyStringPrintf(dy, "%lld", (long long)npu->byteRangeEnd);
+    }
+
+/* Clean up and return handle. */
+return dyStringCannibalize(&dy);
+}
+
+/* this was cloned from rudp.c - move it later for sharing */
+static boolean readReadyWait(int sd, int microseconds)
+/* Wait for descriptor to have some data to read, up to
+ * given number of microseconds. */
+{
+struct timeval tv;
+fd_set set;
+int readyCount;
+
+for (;;)
+    {
+    if (microseconds >= 1000000)
+	{
+	tv.tv_sec = microseconds/1000000;
+	tv.tv_usec = microseconds%1000000;
+	}
+    else
+	{
+	tv.tv_sec = 0;
+	tv.tv_usec = microseconds;
+	}
+    FD_ZERO(&set);
+    FD_SET(sd, &set);
+    readyCount = select(sd+1, &set, NULL, NULL, &tv);
+    if (readyCount < 0) 
+	{
+	if (errno == EINTR)	/* Select interrupted, not timed out. */
+	    continue;
+    	else 
+    	    warn("select failure in rudp: %s", strerror(errno));
+    	}
+    else
+	{
+    	return readyCount > 0;	/* Zero readyCount indicates time out */
+	}
+    }
+}
+
+static void sendFtpCommandOnly(int sd, char *cmd)
+/* send command to ftp server */
+{   
+mustWriteFd(sd, cmd, strlen(cmd));
+}
+
+#define NET_FTP_TIMEOUT 1000000
+
+static boolean receiveFtpReply(int sd, char *cmd, struct dyString **retReply, int *retCode)
+/* send command to ftp server and check resulting reply code, 
+ * warn and return FALSE if not desired reply.  If retReply is non-NULL, store reply text there. */
+{
+char *startLastLine = NULL;
+struct dyString *rs = newDyString(4*1024);
+while (1)
+    {
+    int readSize = 0;
+    while (1)
+	{
+	char buf[4*1024];
+	if (!readReadyWait(sd, NET_FTP_TIMEOUT))
+	    {
+	    warn("ftp server response timed out > %d microsec", NET_FTP_TIMEOUT);
+	    return FALSE;
+	    }
+	if ((readSize = read(sd, buf, sizeof(buf))) == 0)
+	    break;
+
+	dyStringAppendN(rs, buf, readSize);
+	if (endsWith(rs->string,"\n"))
+	    break;
+	}
+	
+    /* find the start of the last line in the buffer */
+    startLastLine = rs->string+strlen(rs->string)-1;
+    if (startLastLine >= rs->string)
+	if (*startLastLine == '\n') 
+	    --startLastLine;
+    while ((startLastLine >= rs->string) && (*startLastLine != '\n'))
+	--startLastLine;
+    ++startLastLine;
+	
+    if (strlen(startLastLine)>4)
+      if (
+	isdigit(startLastLine[0]) &&
+	isdigit(startLastLine[1]) &&
+	isdigit(startLastLine[2]) &&
+	startLastLine[3]==' ')
+	break;
+	
+    if (readSize == 0)
+	break;  // EOF
+    /* must be some text info we can't use, ignore it till we get status code */
+    }
+
+int reply = atoi(startLastLine);
+if ((reply < 200) || (reply > 399))
+    {
+    warn("ftp server error on cmd=[%s] response=[%s]",cmd,rs->string);
+    return FALSE;
+    }
+    
+if (retReply)
+    *retReply = rs;
+else
+    dyStringFree(&rs);
+if (retCode)
+    *retCode = reply;
+return TRUE;
+}
+
+static boolean sendFtpCommand(int sd, char *cmd, struct dyString **retReply, int *retCode)
+/* send command to ftp server and check resulting reply code, 
+ * warn and return FALSE if not desired reply.  If retReply is non-NULL, store reply text there. */
+{   
+sendFtpCommandOnly(sd, cmd);
+return receiveFtpReply(sd, cmd, retReply, retCode);
+}
+
+static int parsePasvPort(char *rs)
+/* parse PASV reply to get the port and return it */
+{
+char *words[7];
+int wordCount;
+char *rsStart = strchr(rs,'(');
+char *rsEnd = strchr(rs,')');
+int result = 0;
+rsStart++;
+*rsEnd=0;
+wordCount = chopString(rsStart, ",", words, ArraySize(words));
+if (wordCount != 6)
+    errAbort("PASV reply does not parse correctly");
+result = atoi(words[4])*256+atoi(words[5]);    
+return result;
+}    
+
+
+static long long parseFtpSIZE(char *rs)
+/* parse reply to SIZE and return it */
+{
+char *words[3];
+int wordCount;
+char *rsStart = rs;
+long long result = 0;
+wordCount = chopString(rsStart, " ", words, ArraySize(words));
+if (wordCount != 2)
+    errAbort("SIZE reply does not parse correctly");
+result = atoll(words[1]);    
+return result;
+}    
+
+
+static time_t parseFtpMDTM(char *rs)
+/* parse reply to MDTM and return it
+ * 200 YYYYMMDDhhmmss */
+{
+char *words[3];
+int wordCount = chopString(rs, " ", words, ArraySize(words));
+if (wordCount != 2)
+    errAbort("MDTM reply should have 2 words but has %d", wordCount);
+#define EXPECTED_MDTM_FORMAT "YYYYmmddHHMMSS"
+if (strlen(words[1]) < strlen(EXPECTED_MDTM_FORMAT))
+    errAbort("MDTM reply word [%s] shorter than " EXPECTED_MDTM_FORMAT, words[1]);
+// man strptime ->
+// "There should be whitespace or other alphanumeric characters between any two field descriptors."
+// There are no separators in the MDTM timestamp, so make a spread-out version for strptime:
+char spread[] = "YYYY mm dd HH MM SS";
+char *from = words[1];
+char *to = spread;
+*to++ = *from++;
+*to++ = *from++;
+*to++ = *from++;
+*to++ = *from++;
+*to++ = '-';
+*to++ = *from++;
+*to++ = *from++;
+*to++ = '-';
+*to++ = *from++;
+*to++ = *from++;
+*to++ = ' ';
+*to++ = *from++;
+*to++ = *from++;
+*to++ = ':';
+*to++ = *from++;
+*to++ = *from++;
+*to++ = ':';
+*to++ = *from++;
+*to++ = *from++;
+*to++ = 0;
+struct tm tm;
+if (strptime(spread, "%Y-%m-%d %H:%M:%S", &tm) == NULL)
+    errAbort("unable to parse MDTM string [%s]", spread);
+// Not set by strptime(); tells mktime() to determine whether daylight saving time is in effect:
+tm.tm_isdst = -1;
+time_t t = mktime(&tm);
+if (t == -1)
+    errAbort("mktime failed while parsing strptime'd MDTM string [%s]", words[1]);
+return t;
+}    
+
+
+static int openFtpControlSocket(char *host, int port, char *user, char *password)
+/* Open a socket to host,port; authenticate anonymous ftp; set type to I; 
+ * return socket desc or -1 if there was an error. */
+{
+int sd = netConnect(host, port);
+if (sd < 0)
+    return -1;
+
+/* First read the welcome msg */
+if (readReadyWait(sd, NET_FTP_TIMEOUT))
+    sendFtpCommand(sd, "", NULL, NULL);
+
+char cmd[256];
+int retCode = 0;
+safef(cmd,sizeof(cmd),"USER %s\r\n", user);
+if (!sendFtpCommand(sd, cmd, NULL, &retCode))
+    {
+    close(sd);
+    return -1;
+    }
+
+if (retCode == 331)
+    {
+    safef(cmd,sizeof(cmd),"PASS %s\r\n", password);
+    if (!sendFtpCommand(sd, cmd, NULL, NULL))
+	{
+	close(sd);
+	return -1;
+	}
+    }
+
+if (!sendFtpCommand(sd, "TYPE I\r\n", NULL, NULL))
+    {
+    close(sd);
+    return -1;
+    }
+/* 200 Type set to I */
+/* (send the data as binary, so can support compressed files) */
+return sd;
+}
+
+boolean netGetFtpInfo(char *url, long long *retSize, time_t *retTime)
+/* Return date in UTC and size of ftp url file */
+{
+/* Parse the URL and connect. */
+struct netParsedUrl npu;
+netParseUrl(url, &npu);
+if (!sameString(npu.protocol, "ftp"))
+    errAbort("netGetFtpInfo: url (%s) is not for ftp.", url);
+
+// TODO maybe remove this workaround where udc cache wants info on URL "/" ?
+if (sameString(npu.file,"/"))
+    {
+    *retSize = 0;
+    *retTime = time(NULL);
+    return TRUE;
+    }
+
+int sd = openFtpControlSocket(npu.host, atoi(npu.port), npu.user, npu.password);
+if (sd < 0)
+    return FALSE;
+char cmd[256];
+safef(cmd,sizeof(cmd),"SIZE %s\r\n", npu.file);
+struct dyString *rs = NULL;
+if (!sendFtpCommand(sd, cmd, &rs, NULL))
+    {
+    close(sd);
+    return FALSE;
+    }
+*retSize = parseFtpSIZE(rs->string);
+/* 200 12345 */
+dyStringFree(&rs);
+
+safef(cmd,sizeof(cmd),"MDTM %s\r\n", npu.file);
+if (!sendFtpCommand(sd, cmd, &rs, NULL))
+    {
+    close(sd);
+    return FALSE;
+    }
+*retTime = parseFtpMDTM(rs->string);
+/* 200 YYYYMMDDhhmmss */
+dyStringFree(&rs);
+close(sd);   
+return TRUE;
+}
+
+struct netConnectFtpParams
+/* params to pass to thread */
+{
+pthread_t thread;
+int pipefd[2];
+int sd;
+int sdata; 
+struct netParsedUrl npu;
+};
+
+static void *sendFtpDataToPipeThread(void *threadParams)
+/* This is to be executed by the child process after the fork in netGetOpenFtpSockets.
+ * It keeps the ftp control socket alive while reading from the ftp data socket
+ * and writing to the pipe to the parent process, which closes the ftp sockets
+ * and reads from the pipe. */
+{
+
+struct netConnectFtpParams *params = threadParams;
+
+pthread_detach(params->thread);  // this thread will never join back with it's progenitor
+
+char buf[32768];
+int rd = 0;
+long long dataPos = 0; 
+if (params->npu.byteRangeStart != -1)
+    dataPos = params->npu.byteRangeStart;
+while((rd = read(params->sdata, buf, 32768)) > 0) 
+    {
+    if (params->npu.byteRangeEnd != -1 && (dataPos + rd) > params->npu.byteRangeEnd)
+	rd = params->npu.byteRangeEnd - dataPos + 1;
+    int wt = write(params->pipefd[1], buf, rd);
+    if (wt == -1 && params->npu.byteRangeEnd != -1)
+	{
+	// errAbort in child process is messy; let reader complain if
+	// trouble.  If byterange was open-ended, we will hit this point
+	// when the parent stops reading and closes the pipe.
+	errnoWarn("error writing ftp data to pipe");
+	break;
+	}
+    dataPos += rd;
+    if (params->npu.byteRangeEnd != -1 && dataPos >= params->npu.byteRangeEnd)
+	break;	    
+    }
+if (rd == -1)
+    // Again, avoid abort in child process.
+    errnoWarn("error reading ftp socket");
+close(params->pipefd[1]);  /* we are done with it */
+close(params->sd);
+close(params->sdata);
+return NULL;
+}
+
+static int netGetOpenFtpSockets(char *url, int *retCtrlSd)
+/* Return a socket descriptor for url data (url can end in ";byterange:start-end",
+ * or -1 if error.
+ * If retCtrlSd is non-null, keep the control socket alive and set *retCtrlSd.
+ * Otherwise, create a pipe and fork to keep control socket alive in the child 
+ * process until we are done fetching data. */
+{
+char cmd[256];
+
+/* Parse the URL and connect. */
+struct netParsedUrl npu;
+netParseUrl(url, &npu);
+if (!sameString(npu.protocol, "ftp"))
+    errAbort("netGetOpenFtpSockets: url (%s) is not for ftp.", url);
+int sd = openFtpControlSocket(npu.host, atoi(npu.port), npu.user, npu.password);
+if (sd == -1)
+    return -1;
+
+struct dyString *rs = NULL;
+if (!sendFtpCommand(sd, "PASV\r\n", &rs, NULL))
+    {
+    close(sd);
+    return -1;
+    }
+/* 227 Entering Passive Mode (128,231,210,81,222,250) */
+
+if (npu.byteRangeStart != -1)
+    {
+    safef(cmd,sizeof(cmd),"REST %lld\r\n", (long long) npu.byteRangeStart);
+    if (!sendFtpCommand(sd, cmd, NULL, NULL))
+	{
+	close(sd);
+	return -1;
+	}
+    }
+
+/* RETR for files, LIST for directories ending in / */
+safef(cmd,sizeof(cmd),"%s %s\r\n",((npu.file[strlen(npu.file)-1]) == '/') ? "LIST" : "RETR", npu.file);
+sendFtpCommandOnly(sd, cmd);
+
+int sdata = netConnect(npu.host, parsePasvPort(rs->string));
+dyStringFree(&rs);
+if (sdata < 0)
+    {
+    close(sd);
+    return -1;
+    }
+
+int secondsWaited = 0;
+while (TRUE)
+    {
+    if (secondsWaited >= 10)
+	{
+	warn("ftp server error on cmd=[%s] timed-out waiting for data or error", cmd);
+	close(sd);
+	close(sdata);
+	return -1;
+	}
+    if (readReadyWait(sdata, NET_FTP_TIMEOUT))
+	break;   // we have some data
+    if (readReadyWait(sd, 0)) /* wait in microsec */
+	{
+	// this can see an error like bad filename
+	if (!receiveFtpReply(sd, cmd, NULL, NULL))
+	    {
+	    close(sd);
+	    close(sdata);
+	    return -1;
+	    }
+	}
+    ++secondsWaited;
+    }
+
+if (retCtrlSd != NULL)
+    {
+    *retCtrlSd = sd;
+    return sdata;
+    }
+else
+    {
+    /* Because some FTP servers will kill the data connection
+     * as soon as the control connection closes,
+     * we have to develop a workaround using a partner process. */
+    fflush(stdin);
+    fflush(stdout);
+    fflush(stderr);
+
+    struct netConnectFtpParams *params;
+    AllocVar(params);
+    params->sd = sd;
+    params->sdata = sdata;
+    params->npu = npu;
+    /* make a pipe (fds go in pipefd[0] and pipefd[1])  */
+    if (pipe(params->pipefd) != 0)
+	errAbort("netGetOpenFtpSockets: failed to create pipe: %s", strerror(errno));
+    int rc;
+    rc = pthread_create(&params->thread, NULL, sendFtpDataToPipeThread, (void *)params);
+    if (rc)
+	{
+	errAbort("Unexpected error %d from pthread_create(): %s",rc,strerror(rc));
+	}
+
+    return params->pipefd[0];
+    }
+}
+
+
+int connectNpu(struct netParsedUrl npu, char *url)
+/* Connect using NetParsedUrl. */
+{
+int sd = -1;
+if (sameString(npu.protocol, "http"))
+    {
+    sd = netConnect(npu.host, atoi(npu.port));
+    }
+else if (sameString(npu.protocol, "https"))
+    {
+    sd = netConnectHttps(npu.host, atoi(npu.port));
+    }
+else
+    {
+    errAbort("netHttpConnect: url (%s) is not for http.", url);
+    return -1;  /* never gets here, fixes compiler complaint */
+    }
+return sd;
+}
+
+void setAuthorization(struct netParsedUrl npu, char *authHeader, struct dyString *dy)
+/* Set the specified authorization header with BASIC auth base64-encoded user and password */
+{
+if (!sameString(npu.user,""))
+    {
+    char up[256];
+    char *b64up = NULL;
+    safef(up, sizeof(up), "%s:%s", npu.user, npu.password);
+    b64up = base64Encode(up, strlen(up));
+    dyStringPrintf(dy, "%s: Basic %s\r\n", authHeader, b64up);
+    freez(&b64up);
+    }
+}
+
+int netHttpConnect(char *url, char *method, char *protocol, char *agent, char *optionalHeader)
+/* Parse URL, connect to associated server on port, and send most of
+ * the request to the server.  If specified in the url send user name
+ * and password too.  Typically the "method" will be "GET" or "POST"
+ * and the agent will be the name of your program or
+ * library. optionalHeader may be NULL or contain additional header
+ * lines such as cookie info. 
+ * Proxy support via hg.conf httpProxy or env var http_proxy
+ * Return data socket, or -1 if error.*/
+{
+struct netParsedUrl npu;
+struct netParsedUrl pxy;
+struct dyString *dy = newDyString(512);
+int sd = -1;
+/* Parse the URL and connect. */
+netParseUrl(url, &npu);
+
+char *proxyUrl = getenv("http_proxy");
+
+if (proxyUrl)
+    {
+    netParseUrl(proxyUrl, &pxy);
+    sd = connectNpu(pxy, url);
+    }
+else
+    {
+    sd = connectNpu(npu, url);
+    }
+if (sd < 0)
+    return -1;
+
+/* Ask remote server for a file. */
+char *urlForProxy = NULL;
+if (proxyUrl)
+    {
+    /* trim off the byterange part at the end of url because proxy does not understand it. */
+    urlForProxy = cloneString(url);
+    char *x = strrchr(urlForProxy, ';');
+    if (x && startsWith(";byterange=", x))
+	*x = 0;
+    }
+dyStringPrintf(dy, "%s %s %s\r\n", method, proxyUrl ? urlForProxy : npu.file, protocol);
+freeMem(urlForProxy);
+dyStringPrintf(dy, "User-Agent: %s\r\n", agent);
+/* do not need the 80 since it is the default */
+if ((sameString(npu.protocol, "http" ) && sameString("80", npu.port)) ||
+    (sameString(npu.protocol, "https") && sameString("443",npu.port)))
+    dyStringPrintf(dy, "Host: %s\r\n", npu.host);
+else
+    dyStringPrintf(dy, "Host: %s:%s\r\n", npu.host, npu.port);
+setAuthorization(npu, "Authorization", dy);
+if (proxyUrl)
+    setAuthorization(pxy, "Proxy-Authorization", dy);
+dyStringAppend(dy, "Accept: */*\r\n");
+if (npu.byteRangeStart != -1)
+    {
+    if (npu.byteRangeEnd != -1)
+	dyStringPrintf(dy, "Range: bytes=%lld-%lld\r\n"
+		       , (long long)npu.byteRangeStart
+		       , (long long)npu.byteRangeEnd);
+    else
+	dyStringPrintf(dy, "Range: bytes=%lld-\r\n"
+		       , (long long)npu.byteRangeStart);
+    }
+
+if (optionalHeader)
+    dyStringAppend(dy, optionalHeader);
+
+/* finish off the header with final blank line */
+dyStringAppend(dy, "\r\n");
+
+mustWriteFd(sd, dy->string, dy->stringSize);
+
+/* Clean up and return handle. */
+dyStringFree(&dy);
+return sd;
+}
+
+
+int netOpenHttpExt(char *url, char *method, char *optionalHeader)
+/* Return a file handle that will read the url.  optionalHeader
+ * may by NULL or may contain cookies and other info.  */
+{
+return netHttpConnect(url, method, "HTTP/1.0", "genome.ucsc.edu/net.c", optionalHeader);
+}
+
+static int netGetOpenHttp(char *url)
+/* Return a file handle that will read the url.  */
+{
+return netOpenHttpExt(url, "GET", NULL);
+}
+
+int netUrlHeadExt(char *url, char *method, struct hash *hash)
+/* Go get head and return status.  Return negative number if
+ * can't get head. If hash is non-null, fill it with header
+ * lines with upper cased keywords for case-insensitive lookup, 
+ * including hopefully CONTENT-TYPE: . */
+{
+int sd = netOpenHttpExt(url, method, NULL);
+int status = EIO;
+if (sd >= 0)
+    {
+    char *line, *word;
+    struct lineFile *lf = lineFileAttach(url, TRUE, sd);
+
+    if (lineFileNext(lf, &line, NULL))
+	{
+	if (startsWith("HTTP/", line))
+	    {
+	    word = nextWord(&line);
+	    word = nextWord(&line);
+	    if (word != NULL && isdigit(word[0]))
+	        {
+		status = atoi(word);
+		if (hash != NULL)
+		    {
+		    while (lineFileNext(lf, &line, NULL))
+		        {
+			word = nextWord(&line);
+			if (word == NULL)
+			    break;
+			hashAdd(hash, strUpper(word), cloneString(skipLeadingSpaces(line)));
+			}
+		    }
+		}
+	    }
+	}
+    lineFileClose(&lf);
+    }
+else
+    status = errno;
+return status;
+}
+
+
+int netUrlHead(char *url, struct hash *hash)
+/* Go get head and return status.  Return negative number if
+ * can't get head. If hash is non-null, fill it with header
+ * lines with upper cased keywords for case-insensitive lookup, 
+ * including hopefully CONTENT-TYPE: . */
+{
+return netUrlHeadExt(url, "HEAD", hash);
+}
+
+
+long long netUrlSizeByRangeResponse(char *url)
+/* Use byteRange as a work-around alternate method to get file size (content-length).  
+ * Return negative number if can't get. */
+{
+long long retVal = -1;
+char rangeUrl[2048];
+safef(rangeUrl, sizeof(rangeUrl), "%s;byterange=0-0", url);
+struct hash *hash = newHash(0);
+int status = netUrlHeadExt(rangeUrl, "GET", hash);
+if (status == 206)
+    { 
+    char *rangeString = hashFindValUpperCase(hash, "Content-Range:");
+    if (rangeString)
+	{
+ 	/* input pattern: Content-Range: bytes 0-99/2738262 */
+	char *slash = strchr(rangeString,'/');
+	if (slash)
+	    {
+	    retVal = atoll(slash+1);
+	    }
+	}
+    }
+hashFree(&hash);
+return retVal;
+}
+
+
+int netUrlOpenSockets(char *url, int *retCtrlSocket)
+/* Return socket descriptor (low-level file handle) for read()ing url data,
+ * or -1 if error. 
+ * If retCtrlSocket is non-NULL and url is FTP, set *retCtrlSocket
+ * to the FTP control socket which is left open for a persistent connection.
+ * close(result) (and close(*retCtrlSocket) if applicable) when done. 
+ * If url is missing :// then it's just treated as a file. */
+{
+if (stringIn("://", url) == NULL)
+    return open(url, O_RDONLY);
+else
+    {
+    if (startsWith("http://",url) || startsWith("https://",url))
+	return netGetOpenHttp(url);
+    else if (startsWith("ftp://",url))
+	return netGetOpenFtpSockets(url, retCtrlSocket);
+    else    
+	errAbort("Sorry, can only netUrlOpen http, https and ftp currently, not '%s'", url);
+    }
+return -1;    
+}
+
+int netUrlOpen(char *url)
+/* Return socket descriptor (low-level file handle) for read()ing url data,
+ * or -1 if error.  Just close(result) when done. */
+{
+return netUrlOpenSockets(url, NULL);
+}
+
+struct dyString *netSlurpFile(int sd)
+/* Slurp file into dynamic string and return. */
+{
+char buf[4*1024];
+int readSize;
+struct dyString *dy = newDyString(4*1024);
+
+/* Slurp file into dy and return. */
+while ((readSize = read(sd, buf, sizeof(buf))) > 0)
+    dyStringAppendN(dy, buf, readSize);
+return dy;
+}
+
+struct dyString *netSlurpUrl(char *url)
+/* Go grab all of URL and return it as dynamic string. */
+{
+int sd = netUrlOpen(url);
+if (sd < 0)
+    errAbort("netSlurpUrl: failed to open socket for [%s]", url);
+struct dyString *dy = netSlurpFile(sd);
+close(sd);
+return dy;
+}
+
+static void parseContentRange(char *x, ssize_t *rangeStart, ssize_t *rangeEnd)
+/* parse the content range information from response header value 
+	"bytes 763400000-763400112/763400113"
+ */
+{
+/* default to no byte range specified */
+*rangeStart = -1;
+*rangeEnd = -1;
+if (startsWith("bytes ", x))
+    {
+    char *y=strchr(x, ' ');
+    ++y;
+    char *z=strchr(y, '-');
+    if (z)
+	{
+	++z;
+	// TODO: use something better than atoll() ?
+	*rangeStart = atoll(y); 
+	if (z[0] != '\0')
+	    *rangeEnd = atoll(z);
+	}    
+    }
+
+}
+
+
+boolean netSkipHttpHeaderLinesWithRedirect(int sd, char *url, char **redirectedUrl)
+/* Skip http header lines. Return FALSE if there's a problem.
+ * The input is a standard sd or fd descriptor.
+ * This is meant to be able work even with a re-passable stream handle,
+ * e.g. can pass it to the pipes routines, which means we can't
+ * attach a linefile since filling its buffer reads in more than just the http header.
+ * Handles 300, 301, 302, 303, 307 http redirects by setting *redirectedUrl to
+ * the new location. */
+{
+char buf[2000];
+char *line = buf;
+int maxbuf = sizeof(buf);
+int i=0;
+char c = ' ';
+int nread = 0;
+char *sep = NULL;
+char *headerName = NULL;
+char *headerVal = NULL;
+boolean redirect = FALSE;
+boolean byteRangeUsed = (strstr(url,";byterange=") != NULL);
+ssize_t byteRangeStart = -1;
+ssize_t byteRangeEnd = -1;
+boolean foundContentRange = FALSE;
+ssize_t contentRangeStart = -1;
+ssize_t contentRangeEnd = -1;
+
+boolean mustUseProxy = FALSE;  /* User must use proxy 305 error*/
+char *proxyLocation = NULL;
+boolean mustUseProxyAuth = FALSE;  /* User must use proxy authentication 407 error*/
+
+if (byteRangeUsed)
+    {
+    parseByteRange(url, &byteRangeStart, &byteRangeEnd, FALSE);
+    }
+
+while(TRUE)
+    {
+    i = 0;
+    while (TRUE)
+	{
+	nread = read(sd, &c, 1);  /* one char at a time, but http headers are small */
+	if (nread != 1)
+	    {
+	    if (nread == -1)
+    		warn("Error (%s) reading http header on %s", strerror(errno), url);
+	    else if (nread == 0)
+    		warn("Error unexpected end of input reading http header on %s", url);
+	    else
+    		warn("Error reading http header on %s", url);
+	    return FALSE;  /* err reading descriptor */
+	    }
+	if (c == 10)
+	    break;
+	if (c != 13)
+    	    buf[i++] = c;
+	if (i >= maxbuf)
+	    {
+	    warn("http header line too long > %d chars.",maxbuf);
+	    return FALSE;
+	    }
+	}
+    buf[i] = 0;  /* add string terminator */
+
+    if (sameString(line,""))
+	{
+	break; /* End of Header found */
+	}
+    if (startsWith("HTTP/", line))
+        {
+	char *version, *code;
+	version = nextWord(&line);
+	code = nextWord(&line);
+	if (code == NULL)
+	    {
+	    warn("Strange http header on %s", url);
+	    return FALSE;
+	    }
+	if (startsWith("30", code) && isdigit(code[2])
+	    && ((code[2] >= '0' && code[2] <= '3') || code[2] == '7') && code[3] == 0)
+	    {
+	    redirect = TRUE;
+	    }
+	else if (sameString(code, "305"))
+	    {
+	    mustUseProxy = TRUE;
+	    }
+	else if (sameString(code, "407"))
+	    {
+	    mustUseProxyAuth = TRUE;
+	    }
+	else if (byteRangeUsed 
+	    /* hack for Apache bug 2.2.20 and 2.2.21 2011-10-21 should be OK to remove after one year. */
+		&& !(sameString(code, "200") && byteRangeStart == 0 && byteRangeEnd == -1))  
+	    {
+	    if (!sameString(code, "206"))
+		{
+		if (sameString(code, "200"))
+		    warn("Byte-range request was ignored by server. ");
+		warn("Expected Partial Content 206. %s: %s %s", url, code, line);
+		return FALSE;
+		}
+	    }
+	else if (!sameString(code, "200"))
+	    {
+	    warn("Expected 200 %s: %s %s", url, code, line);
+	    return FALSE;
+	    }
+	line = buf;  /* restore it */
+	}
+    headerName = line;
+    sep = strchr(line,':');
+    if (sep)
+	{
+	*sep = 0;
+	headerVal = skipLeadingSpaces(++sep);
+	}
+    else
+	{
+	headerVal = NULL;
+	}
+    if (sameWord(headerName,"Location"))
+	{
+	if (redirect)
+	    *redirectedUrl = cloneString(headerVal);
+	if (mustUseProxy)
+	    proxyLocation = cloneString(headerVal);
+	}
+    if (sameWord(headerName,"Content-Range"))
+	{
+	if (byteRangeUsed)
+	    {
+	    foundContentRange = TRUE;
+	    parseContentRange(headerVal, &contentRangeStart, &contentRangeEnd);	
+    	    if ((contentRangeStart != byteRangeStart) ||
+		(byteRangeEnd != -1 && (contentRangeEnd != byteRangeEnd)))
+		{
+		char bre[256];
+		safef(bre, sizeof bre, "%lld", (long long)byteRangeEnd);
+		if (byteRangeEnd == -1)
+		    bre[0] = 0;
+		warn("Found Content-Range: %s. Expected bytes %lld-%s. Improper caching of 206 reponse byte-ranges?",
+		    headerVal, (long long) byteRangeStart, bre);
+    		return FALSE;
+		}
+	    }
+	}
+    }
+if (mustUseProxy ||  mustUseProxyAuth)
+    {
+    warn("%s: %s error. Use Proxy%s. Location = %s", url, 
+	mustUseProxy ? "" : " Authentication", 
+	mustUseProxy ? "305" : "407", 
+	proxyLocation ? proxyLocation : "not given");
+    return FALSE;
+    }
+if (byteRangeUsed && !foundContentRange
+	    /* hack for Apache bug 2.2.20 and 2.2.21 2011-10-21 should be OK to remove after one year. */
+		&& !(byteRangeStart == 0 && byteRangeEnd == -1))  
+    {
+    char bre[256];
+    safef(bre, sizeof bre, "%lld", (long long)byteRangeEnd);
+    if (byteRangeEnd == -1)
+	bre[0] = 0;
+    warn("Expected response header Content-Range: %lld-%s", (long long) byteRangeStart, bre);
+    return FALSE;
+    }
+
+return TRUE;
+}
+
+
+boolean netSkipHttpHeaderLinesHandlingRedirect(int sd, char *url, int *redirectedSd, char **redirectedUrl)
+/* Skip http headers lines, returning FALSE if there is a problem.  Generally called as
+ *    netSkipHttpHeaderLine(sd, url, &sd, &url);
+ * where sd is a socket (file) opened with netUrlOpen(url), and url is in dynamic memory.
+ * If the http header indicates that the file has moved, then it will update the *redirectedSd and
+ * *redirectedUrl with the new socket and URL, first closing sd.
+ * If for some reason you want to detect whether the forwarding has occurred you could
+ * call this as:
+ *    char *newUrl = NULL;
+ *    int newSd = 0;
+ *    netSkipHttpHeaderLine(sd, url, &newSd, &newUrl);
+ *    if (newUrl != NULL)
+ *          // Update sd with newSd, free url if appropriate and replace it with newUrl, etc.
+ *          //  free newUrl when finished.
+ * This routine handles up to 5 steps of redirection.
+ * The logic to this routine is also complicated a little to make it work in a pipe, which means we
+ * can't attach a lineFile since filling the lineFile buffer reads in more than just the http header. */
+{
+int redirectCount = 0;
+while (TRUE)
+    {
+    /* url needed for err msgs, and to return redirect location */
+    char *newUrl = NULL;
+    boolean success = netSkipHttpHeaderLinesWithRedirect(sd, url, &newUrl);
+    if (success && !newUrl) /* success after 0 to 5 redirects */
+        {
+	if (redirectCount > 0)
+	    {
+	    *redirectedSd = sd;
+	    *redirectedUrl = url;
+	    }
+	else
+	    {
+	    *redirectedSd = -1;
+	    *redirectedUrl = NULL;
+	    }
+	return TRUE;
+	}
+    close(sd);
+    if (redirectCount > 0)
+	freeMem(url);
+    if (success)
+	{
+	/* we have a new url to try */
+	++redirectCount;
+	if (redirectCount > 5)
+	    {
+	    warn("code 30x redirects: exceeded limit of 5 redirects, %s", newUrl);
+	    success = FALSE;
+	    }
+	else if (!startsWith("http://",newUrl) 
+              && !startsWith("https://",newUrl))
+	    {
+	    warn("redirected to non-http(s): %s", newUrl);
+	    success = FALSE;
+	    }
+	else 
+	    {
+	    struct netParsedUrl npu, newNpu;
+	    /* Parse the old URL to make parts available for graft onto the redirected url. */
+	    /* This makes redirection work with byterange urls and user:password@ */
+	    netParseUrl(url, &npu);
+	    netParseUrl(newUrl, &newNpu);
+	    boolean updated = FALSE;
+	    if (npu.byteRangeStart != -1)
+		{
+		newNpu.byteRangeStart = npu.byteRangeStart;
+		newNpu.byteRangeEnd = npu.byteRangeEnd;
+		updated = TRUE;
+		}
+	    if ((npu.user[0] != 0) && (newNpu.user[0] == 0))
+		{
+		safecpy(newNpu.user,     sizeof newNpu.user,     npu.user);
+		safecpy(newNpu.password, sizeof newNpu.password, npu.password);
+		updated = TRUE;
+		}
+	    if (updated)
+		{
+		freeMem(newUrl);
+		newUrl = urlFromNetParsedUrl(&newNpu);
+		}
+	    sd = netUrlOpen(newUrl);
+	    if (sd < 0)
+		{
+		warn("Couldn't open %s", newUrl);
+		success = FALSE;
+		}
+	    }
+	}
+    if (!success)
+	{  /* failure after 0 to 5 redirects */
+	if (redirectCount > 0)
+	    freeMem(newUrl);
+	return FALSE;
+	}
+    url = newUrl;
+    }
+return FALSE;
+}
+
+struct lineFile *netLineFileMayOpen(char *url)
+/* Return a lineFile attached to url. http skips header.
+ * Supports some compression formats.  Prints warning message, but
+ * does not abort, just returning NULL if there's a problem. */
+{
+int sd = netUrlOpen(url);
+if (sd < 0)
+    {
+    warn("Couldn't open %s", url);
+    return NULL;
+    }
+else
+    {
+    struct lineFile *lf = NULL;
+    char *newUrl = NULL;
+    int newSd = 0;
+    if (startsWith("http://",url) || startsWith("https://",url))
+	{  
+	if (!netSkipHttpHeaderLinesHandlingRedirect(sd, url, &newSd, &newUrl))
+	    {
+	    return NULL;
+	    }
+	if (newUrl != NULL)
+	    {
+    	    /*  Update sd with newSd, replace it with newUrl, etc. */
+	    sd = newSd;
+	    url = newUrl;
+	    }
+	}
+    if (endsWith(url, ".gz") ||
+	endsWith(url, ".Z")  ||
+    	endsWith(url, ".bz2"))
+	{
+	lf = lineFileDecompressFd(url, TRUE, sd);
+           /* url needed only for compress type determination */
+	}
+    else
+	{
+	lf = lineFileAttach(url, TRUE, sd);
+	}
+    if (newUrl) 
+	freeMem(newUrl); 
+    return lf;
+    }
+}
+
+struct lineFile *netLineFileSilentOpen(char *url)
+/* Open a lineFile on a URL.  Just return NULL without any user
+ * visible warning message if there's a problem. */
+{
+pushSilentWarnHandler();
+struct lineFile *lf = netLineFileMayOpen(url);
+popWarnHandler();
+return lf;
+}
+
+char *netReadTextFileIfExists(char *url)
+/* Read entire URL and return it as a string.  URL should be text (embedded zeros will be
+ * interpreted as end of string).  If the url doesn't exist or has other problems,
+ * returns NULL. */
+{
+struct lineFile *lf = netLineFileSilentOpen(url);
+if (lf == NULL)
+    return NULL;
+char *text = lineFileReadAll(lf);
+lineFileClose(&lf);
+return text;
+}
+
+
+struct parallelConn
+/* struct to information on a parallel connection */
+    {
+    struct parallelConn *next;  /* next connection */
+    int sd;                     /* socket descriptor */
+    off_t rangeStart;           /* where does the range start */
+    off_t partSize;             /* range size */
+    off_t received;             /* bytes received */
+    };
+
+void writeParaFetchStatus(char *origPath, struct parallelConn *pcList, char *url, off_t fileSize, char *dateString, boolean isFinal)
+/* Write a status file.
+ * This has two purposes.
+ * First, we can use it to resume a failed transfer.
+ * Second, we can use it to follow progress */
+{
+char outTempX[1024];
+char outTemp[1024];
+safef(outTempX, sizeof(outTempX), "%s.paraFetchStatusX", origPath);
+safef(outTemp, sizeof(outTemp), "%s.paraFetchStatus", origPath);
+struct parallelConn *pc = NULL;
+
+FILE *f = mustOpen(outTempX, "w");
+int part = 0;
+fprintf(f, "%s\n", url);
+fprintf(f, "%lld\n", (long long)fileSize);
+fprintf(f, "%s\n", dateString);
+for(pc = pcList; pc; pc = pc->next)
+    {
+    fprintf(f, "part%d %lld %lld %lld\n", part
+	, (long long)pc->rangeStart
+	, (long long)pc->partSize
+	, (long long)pc->received);
+    ++part;
+    }
+
+carefulClose(&f);
+
+/* rename the successful status to the original name */
+rename(outTempX, outTemp);
+
+if (isFinal)  /* We are done and just looking to get rid of the file. */
+    unlink(outTemp);
+}
+
+
+boolean readParaFetchStatus(char *origPath, 
+    struct parallelConn **pPcList, char **pUrl, off_t *pFileSize, char **pDateString, off_t *pTotalDownloaded)
+/* Write a status file.
+ * This has two purposes.
+ * First, we can use it to resume a failed transfer.
+ * Second, we can use it to follow progress */
+{
+char outTemp[1024];
+char outStat[1024];
+safef(outStat, sizeof(outStat), "%s.paraFetchStatus", origPath);
+safef(outTemp, sizeof(outTemp), "%s.paraFetch", origPath);
+struct parallelConn *pcList = NULL, *pc = NULL;
+off_t totalDownloaded = 0;
+
+if (!fileExists(outStat))
+    {
+    unlink(outTemp);
+    return FALSE;
+    }
+
+if (!fileExists(outTemp))
+    {
+    unlink(outStat);
+    return FALSE;
+    }
+
+char *line, *word;
+struct lineFile *lf = lineFileOpen(outStat, TRUE);
+if (!lineFileNext(lf, &line, NULL))
+    {
+    unlink(outTemp);
+    unlink(outStat);
+    return FALSE;
+    }
+char *url = cloneString(line);
+if (!lineFileNext(lf, &line, NULL))
+    {
+    unlink(outTemp);
+    unlink(outStat);
+    return FALSE;
+    }
+off_t fileSize = sqlLongLong(line);
+if (!lineFileNext(lf, &line, NULL))
+    {
+    unlink(outTemp);
+    unlink(outStat);
+    return FALSE;
+    }
+char *dateString = cloneString(line);
+while (lineFileNext(lf, &line, NULL))
+    {
+    word = nextWord(&line);
+    AllocVar(pc);
+    pc->next = NULL;
+    pc->sd = -4;  /* no connection tried yet */
+    word = nextWord(&line);
+    pc->rangeStart = sqlLongLong(word);
+    word = nextWord(&line);
+    pc->partSize = sqlLongLong(word);
+    word = nextWord(&line);
+    pc->received = sqlLongLong(word);
+    if (pc->received == pc->partSize)
+	pc->sd = -1;  /* part all done already */
+    totalDownloaded += pc->received;
+    slAddHead(&pcList, pc);
+    }
+slReverse(&pcList);
+
+lineFileClose(&lf);
+
+if (slCount(pcList) < 1)
+    {
+    unlink(outTemp);
+    unlink(outStat);
+    return FALSE;
+    }
+
+*pPcList = pcList;
+*pUrl = url;
+*pFileSize = fileSize;
+*pDateString = dateString;
+*pTotalDownloaded = totalDownloaded;
+
+return TRUE;
+
+}
+
+
+boolean parallelFetch(char *url, char *outPath, int numConnections, int numRetries, boolean newer, boolean progress)
+/* Open multiple parallel connections to URL to speed downloading */
+{
+char *origPath = outPath;
+char outTemp[1024];
+safef(outTemp, sizeof(outTemp), "%s.paraFetch", outPath);
+outPath = outTemp;
+/* get the size of the file to be downloaded */
+off_t fileSize = 0;
+off_t totalDownloaded = 0;
+ssize_t sinceLastStatus = 0;
+char *dateString = "";
+int star = 1;  
+int starMax = 20;  
+int starStep = 1;
+// TODO handle case-sensitivity of protocols input
+if (startsWith("http://",url) || startsWith("https://",url))
+    {
+    struct hash *hash = newHash(0);
+    int status = netUrlHead(url, hash);
+    if (status != 200) // && status != 302 && status != 301)
+	{
+	warn("Error code: %d, expected 200 for %s, can't proceed, sorry", status, url);
+	return FALSE;
+	}
+    char *sizeString = hashFindValUpperCase(hash, "Content-Length:");
+    if (sizeString)
+	{
+	fileSize = atoll(sizeString);
+	}
+    else
+	{
+	warn("No Content-Length: returned in header for %s, must limit to a single connection, will not know if data is complete", url);
+	numConnections = 1;
+	fileSize = -1;
+	}
+    char *ds = hashFindValUpperCase(hash, "Last-Modified:");
+    if (ds)
+	dateString = cloneString(ds);
+    hashFree(&hash);
+    }
+else if (startsWith("ftp://",url))
+    {
+    long long size = 0;
+    time_t t;
+    boolean ok = netGetFtpInfo(url, &size, &t);
+    if (!ok)
+	{
+	warn("Unable to get size info from FTP for %s, can't proceed, sorry", url);
+	return FALSE;
+	}
+    fileSize = size;
+
+    struct tm  *ts;
+    char ftpTime[80];
+ 
+    /* Format the time "Tue, 15 Jun 2010 06:45:08 GMT" */
+    ts = localtime(&t);
+    strftime(ftpTime, sizeof(ftpTime), "%a, %d %b %Y %H:%M:%S %Z", ts);
+    dateString = cloneString(ftpTime);
+
+    }
+else
+    {
+    warn("unrecognized protocol: %s", url);
+    return FALSE;
+    }
+
+
+verbose(2,"fileSize=%lld\n", (long long) fileSize);
+
+if (fileSize < 65536)    /* special case small file */
+    numConnections = 1;
+
+if (numConnections > 50)    /* ignore high values for numConnections */
+    {
+    warn("Currently maximum number of connections is 50. You requested %d. Will proceed with 50 on %s", numConnections, url);
+    numConnections = 50;
+    }
+
+verbose(2,"numConnections=%d\n", numConnections); //debug
+
+if (numConnections < 1)
+    {
+    warn("number of connections must be greater than 0 for %s, can't proceed, sorry", url);
+    return FALSE;
+    }
+
+if (numRetries < 0)
+    numRetries = 0;
+
+/* what is the size of each part */
+off_t partSize = (fileSize + numConnections -1) / numConnections;
+if (fileSize == -1) 
+    partSize = -1;
+off_t base = 0;
+int c;
+
+verbose(2,"partSize=%lld\n", (long long) partSize); //debug
+
+
+/* n is the highest-numbered descriptor */
+int n = 0;
+int connOpen = 0;
+int reOpen = 0;
+
+
+struct parallelConn *restartPcList = NULL;
+char *restartUrl = NULL;
+off_t restartFileSize = 0;
+char *restartDateString = "";
+off_t restartTotalDownloaded = 0;
+boolean restartable = readParaFetchStatus(origPath, &restartPcList, &restartUrl, &restartFileSize, &restartDateString, &restartTotalDownloaded);
+if (fileSize == -1)
+    restartable = FALSE;
+
+struct parallelConn *pcList = NULL, *pc;
+
+if (restartable 
+ && sameString(url, restartUrl)
+ && fileSize == restartFileSize
+ && sameString(dateString, restartDateString))
+    {
+    pcList = restartPcList;
+    totalDownloaded = restartTotalDownloaded;
+    }
+else
+    {
+
+    if (newer) // only download it if it is newer than what we already have
+	{
+	/* datestamp mtime from last-modified header */
+	struct tm tm;
+	// Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
+	// These strings are always GMT
+	if (strptime(dateString, "%a, %d %b %Y %H:%M:%S %Z", &tm) == NULL)
+	    {
+	    warn("unable to parse last-modified string [%s]", dateString);
+	    }
+	else
+	    {
+	    time_t t;
+	    // convert to UTC (GMT) time
+	    t = mktimeFromUtc(&tm);
+	    if (t == -1)
+		{
+		warn("mktimeFromUtc failed while converting last-modified string to UTC [%s]", dateString);
+		}
+	    else
+		{
+		// get the file mtime
+		struct stat mystat;
+		ZeroVar(&mystat);
+		if (stat(origPath,&mystat)==0)
+		    {
+		    if (t <= mystat.st_mtime)
+			{
+			verbose(2,"Since nothing newer was found, skipping %s\n", origPath);
+			verbose(3,"t from last-modified = %ld; st_mtime = %ld\n", (long) t, (long)mystat.st_mtime);
+			return TRUE;
+			}
+		    }
+		}
+	    }
+	}
+
+    /* make a list of connections */
+    for (c = 0; c < numConnections; ++c)
+	{
+	AllocVar(pc);
+	pc->next = NULL;
+	pc->rangeStart = base;
+	base += partSize;
+	pc->partSize = partSize;
+	if (fileSize != -1 && pc->rangeStart+pc->partSize >= fileSize)
+	    pc->partSize = fileSize - pc->rangeStart;
+	pc->received = 0;
+	pc->sd = -4;  /* no connection tried yet */
+	slAddHead(&pcList, pc);
+	}
+    slReverse(&pcList);
+    }
+
+if (progress)
+    {
+    char nicenumber[1024]="";
+    sprintWithGreekByte(nicenumber, sizeof(nicenumber), fileSize);
+    printf("downloading %s ", nicenumber); fflush(stdout);
+    starStep = fileSize/starMax;
+    if (starStep < 1)
+	starStep = 1;
+    }
+
+int out = open(outPath, O_CREAT|O_WRONLY, 0664);
+if (out < 0)
+    {
+    warn("Unable to open %s for write while downloading %s, can't proceed, sorry", url, outPath);
+    return FALSE;
+    }
+
+
+/* descriptors for select() */
+fd_set rfds;
+struct timeval tv;
+int retval;
+
+ssize_t readCount = 0;
+#define BUFSIZE 65536 * 4
+char buf[BUFSIZE];
+
+/* create paraFetchStatus right away for monitoring programs */
+writeParaFetchStatus(origPath, pcList, url, fileSize, dateString, FALSE);
+sinceLastStatus = 0;
+
+int retryCount = 0;
+
+time_t startTime = time(NULL);
+
+#define SELTIMEOUT 5
+#define RETRYSLEEPTIME 30    
+while (TRUE)
+    {
+
+    verbose(2,"Top of big loop\n");
+
+    if (progress)
+	{
+	while (totalDownloaded >= star * starStep)
+	    {
+	    printf("*");fflush(stdout);
+	    ++star;
+	    }
+	}
+
+    /* are we done? */
+    if (connOpen == 0)
+	{
+	boolean done = TRUE;
+	for(pc = pcList; pc; pc = pc->next)
+	    if (pc->sd != -1)
+		done = FALSE;
+	if (done) break;
+	}
+
+    /* See if we need to open any connections, either new or retries */
+    for(pc = pcList; pc; pc = pc->next)
+	{
+	if ((pc->sd == -4)  /* never even tried to open yet */
+	 || ((reOpen>0)      /* some connections have been released */
+	    && (pc->sd == -2  /* started but not finished */
+	    ||  pc->sd == -3)))  /* not even started */
+	    {
+	    char urlExt[1024];
+	    safef(urlExt, sizeof(urlExt), "%s;byterange=%llu-%llu"
+	    , url
+	    , (unsigned long long) (pc->rangeStart + pc->received)
+	    , (unsigned long long) (pc->rangeStart + pc->partSize - 1) );
+
+
+	    int oldSd = pc->sd;  /* in case we need to remember where we were */
+	    if (oldSd != -4)      /* decrement whether we succeed or not */
+		--reOpen;
+	    if (oldSd == -4) 
+		oldSd = -3;       /* ok this one just changes */
+	    if (fileSize == -1)
+		{
+		verbose(2,"opening url %s\n", url);
+		pc->sd = netUrlOpen(url);
+		}
+	    else
+		{
+		verbose(2,"opening url %s\n", urlExt);
+		pc->sd = netUrlOpen(urlExt);
+		}
+	    if (pc->sd < 0)
+		{
+		pc->sd = oldSd;  /* failed to open, can retry later */
+		}
+	    else
+		{
+		char *newUrl = NULL;
+		int newSd = 0;
+		if (startsWith("http://",url) || startsWith("https://",url))
+		    {
+		    if (!netSkipHttpHeaderLinesHandlingRedirect(pc->sd, urlExt, &newSd, &newUrl))
+			{
+			warn("Error processing http response for %s", url);
+			return FALSE;
+			}
+		    if (newUrl) 
+			{
+			/*  Update sd with newSd, replace it with newUrl, etc. */
+			pc->sd = newSd;
+			}
+		    }
+		++connOpen;
+		}
+	    }
+	}
+
+
+    if (connOpen == 0)
+	{
+	warn("Unable to open any connections to download %s, can't proceed, sorry", url);
+	return FALSE;
+	}
+
+
+    FD_ZERO(&rfds);
+    n = 0;
+    for(pc = pcList; pc; pc = pc->next)
+	{
+	if (pc->sd >= 0)
+	    {
+	    FD_SET(pc->sd, &rfds);    /* reset descriptor in readfds for select() */
+	    if (pc->sd > n)
+		n = pc->sd;
+	    }
+	}
+
+
+    /* Wait up to SELTIMEOUT seconds. */
+    tv.tv_sec = SELTIMEOUT;
+    tv.tv_usec = 0;
+    retval = select(n+1, &rfds, NULL, NULL, &tv);
+    /* Don't rely on the value of tv now! */
+
+    if (retval < 0)
+	{
+	perror("select retval < 0");
+	return FALSE;
+	}
+    else if (retval)
+	{
+
+	verbose(2,"returned from select, retval=%d\n", retval);
+
+	for(pc = pcList; pc; pc = pc->next)
+	    {
+	    if ((pc->sd >= 0) && FD_ISSET(pc->sd, &rfds))
+		{
+
+		verbose(2,"found a descriptor with data: %d\n", pc->sd);
+
+		readCount = read(pc->sd, buf, BUFSIZE);
+
+		verbose(2,"readCount = %lld\n", (long long) readCount);
+
+		if (readCount == 0)
+		    {
+		    close(pc->sd);
+
+		    verbose(2,"closing descriptor: %d\n", pc->sd);
+		    pc->sd = -1;
+
+		    if (fileSize != -1 && pc->received != pc->partSize)	
+			{
+			pc->sd = -2;  /* conn was closed before all data was sent, can retry later */
+			return FALSE;
+			}
+		    --connOpen;
+		    ++reOpen;
+		    writeParaFetchStatus(origPath, pcList, url, fileSize, dateString, FALSE);
+		    sinceLastStatus = 0;
+		    continue; 
+		    }
+		if (readCount < 0)
+		    {
+		    warn("error reading from socket for url %s", url);
+		    return FALSE;
+		    }
+
+		verbose(2,"rangeStart %llu  received %llu\n"
+			, (unsigned long long) pc->rangeStart
+			, (unsigned long long) pc->received );
+
+		verbose(2,"seeking to %llu\n", (unsigned long long) (pc->rangeStart + pc->received));
+
+		if (lseek(out, pc->rangeStart + pc->received, SEEK_SET) == -1)
+		    {
+		    perror("error seeking output file");
+		    warn("error seeking output file %s: rangeStart %llu  received %llu for url %s"
+			, outPath
+			, (unsigned long long) pc->rangeStart
+			, (unsigned long long) pc->received
+			, url);
+		    return FALSE;
+		    }
+		int writeCount = write(out, buf, readCount);
+		if (writeCount < 0)
+		    {
+		    warn("error writing output file %s", outPath);
+		    return FALSE;
+		    }
+		pc->received += readCount;
+		totalDownloaded += readCount;
+		sinceLastStatus += readCount;
+		if (sinceLastStatus >= 100*1024*1024)
+		    {
+		    writeParaFetchStatus(origPath, pcList, url, fileSize, dateString, FALSE);
+		    sinceLastStatus = 0;
+		    }
+		}
+	    }
+	}
+    else
+	{
+	warn("No data within %d seconds for %s", SELTIMEOUT, url);
+	/* Retry ? */
+	if (retryCount >= numRetries)
+	    {
+    	    return FALSE;
+	    }
+	else
+	    {
+	    ++retryCount;
+	    /* close any open connections */
+	    for(pc = pcList; pc; pc = pc->next)
+		{
+		if (pc->sd >= 0) 
+		    {
+		    close(pc->sd);
+		    verbose(2,"closing descriptor: %d\n", pc->sd);
+		    }
+		if (pc->sd != -1) 
+		    pc->sd = -4;
+		}
+	    connOpen = 0;
+	    reOpen = 0;
+	    /* sleep for a while, maybe the server will recover */
+	    sleep(RETRYSLEEPTIME);
+	    }
+	}
+
+    }
+
+close(out);
+
+/* delete the status file - by passing TRUE */
+writeParaFetchStatus(origPath, pcList, url, fileSize, dateString, TRUE); 
+
+/* restore original file datestamp mtime from last-modified header */
+struct tm tm;
+// Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
+// These strings are always GMT
+if (strptime(dateString, "%a, %d %b %Y %H:%M:%S %Z", &tm) == NULL)
+    {
+    warn("unable to parse last-modified string [%s]", dateString);
+    }
+else
+    {
+    time_t t;
+    // convert to UTC (GMT) time
+    t = mktimeFromUtc(&tm);
+    if (t == -1)
+	{
+	warn("mktimeFromUtc failed while converting last-modified string to UTC [%s]", dateString);
+	}
+    else
+	{
+	// update the file mtime
+	struct utimbuf ut;
+	struct stat mystat;
+	ZeroVar(&mystat);
+	if (stat(outTemp,&mystat)==0)
+	    {
+	    ut.actime = mystat.st_atime;
+	    ut.modtime = t;
+	    if (utime(outTemp, &ut)==-1)
+		{
+		char errMsg[256];
+                safef(errMsg, sizeof(errMsg), "paraFetch: error setting modification time of %s to %s\n", outTemp, dateString);
+		perror(errMsg);
+		}
+	    }
+	}
+    }
+
+/* rename the successful download to the original name */
+rename(outTemp, origPath);
+
+
+
+if (progress)
+    {
+    while (star <= starMax)
+	{
+	printf("*");fflush(stdout);
+	++star;
+	}
+    long timeDiff = (long)(time(NULL) - startTime);
+    if (timeDiff > 0)
+	{
+	printf(" %ld seconds", timeDiff);
+	float mbpersec =  ((totalDownloaded - restartTotalDownloaded)/1000000) / timeDiff;
+	printf(" %0.1f MB/sec", mbpersec);
+	}
+    printf("\n");fflush(stdout);
+    }
+
+if (fileSize != -1 && totalDownloaded != fileSize)
+    {
+    warn("Unexpected result: Total downloaded bytes %lld is not equal to fileSize %lld"
+	, (long long) totalDownloaded
+	, (long long) fileSize);
+    return FALSE;
+    }
+return TRUE;
+}
+
+
+struct lineFile *netLineFileOpen(char *url)
+/* Return a lineFile attached to url.  This one
+ * will skip any headers.   Free this with
+ * lineFileClose(). */
+{
+struct lineFile *lf = netLineFileMayOpen(url);
+if (lf == NULL)
+    noWarnAbort();
+return lf;
+}
+
+boolean netSendString(int sd, char *s)
+/* Send a string down a socket - length byte first. */
+{
+int length = strlen(s);
+UBYTE len;
+
+if (length > 255)
+    errAbort("Trying to send a string longer than 255 bytes (%d bytes)", length);
+len = length;
+if (write(sd, &len, 1)<0)
+    {
+    warn("Couldn't send string to socket");
+    return FALSE;
+    }
+if (write(sd, s, length)<0)
+    {
+    warn("Couldn't send string to socket");
+    return FALSE;
+    }
+return TRUE;
+}
+
+boolean netSendLongString(int sd, char *s)
+/* Send a long string down socket: two bytes for length. */
+{
+unsigned length = strlen(s);
+UBYTE b[2];
+
+if (length >= 64*1024)
+    {
+    warn("Trying to send a string longer than 64k bytes (%d bytes)", length);
+    return FALSE;
+    }
+b[0] = (length>>8);
+b[1] = (length&0xff);
+if (write(sd, b, 2) < 0)
+    {
+    warn("Couldn't send long string to socket");
+    return FALSE;
+    }
+if (write(sd, s, length)<0)
+    {
+    warn("Couldn't send long string to socket");
+    return FALSE;
+    }
+return TRUE;
+}
+
+boolean netSendHugeString(int sd, char *s)
+/* Send a long string down socket: four bytes for length. */
+{
+unsigned long length = strlen(s);
+unsigned long l = length;
+UBYTE b[4];
+int i;
+for (i=3; i>=0; --i)
+    {
+    b[i] = l & 0xff;
+    l >>= 8;
+    }
+if (write(sd, b, 4) < 0)
+    {
+    warn("Couldn't send huge string to socket");
+    return FALSE;
+    }
+if (write(sd, s, length) < 0)
+    {
+    warn("Couldn't send huge string to socket");
+    return FALSE;
+    }
+return TRUE;
+}
+
+
+char *netGetString(int sd, char buf[256])
+/* Read string into buf and return it.  If buf is NULL
+ * an internal buffer will be used. Print warning message
+ * and return NULL if any problem. */
+{
+static char sbuf[256];
+UBYTE len = 0;
+int length;
+int sz;
+if (buf == NULL) buf = sbuf;
+sz = netReadAll(sd, &len, 1);
+if (sz == 0)
+    return NULL;
+if (sz < 0)
+    {
+    warn("Couldn't read string length");
+    return NULL;
+    }
+length = len;
+if (length > 0)
+    if (netReadAll(sd, buf, length) < 0)
+	{
+	warn("Couldn't read string body");
+	return NULL;
+	}
+buf[length] = 0;
+return buf;
+}
+
+char *netGetLongString(int sd)
+/* Read string and return it.  freeMem
+ * the result when done. */
+{
+UBYTE b[2];
+char *s = NULL;
+int length = 0;
+int sz;
+b[0] = b[1] = 0;
+sz = netReadAll(sd, b, 2);
+if (sz == 0)
+    return NULL;
+if (sz < 0)
+    {
+    warn("Couldn't read long string length");
+    return NULL;
+    }
+length = (b[0]<<8) + b[1];
+s = needMem(length+1);
+if (length > 0)
+    if (netReadAll(sd, s, length) < 0)
+	{
+	warn("Couldn't read long string body");
+	return NULL;
+	}
+s[length] = 0;
+return s;
+}
+
+char *netGetHugeString(int sd)
+/* Read string and return it.  freeMem
+ * the result when done. */
+{
+UBYTE b[4];
+char *s = NULL;
+unsigned long length = 0;
+int sz, i;
+sz = netReadAll(sd, b, 4);
+if (sz == 0)
+    return NULL;
+if (sz < 4)
+    {
+    warn("Couldn't read huge string length");
+    return NULL;
+    }
+for (i=0; i<4; ++i)
+    {
+    length <<= 8;
+    length += b[i];
+    }
+s = needMem(length+1);
+if (length > 0)
+    {
+    if (netReadAll(sd, s, length) < 0)
+	{
+	warn("Couldn't read huge string body");
+	return NULL;
+	}
+    }
+s[length] = 0;
+return s;
+}
+
+
+char *netRecieveString(int sd, char buf[256])
+/* Read string into buf and return it.  If buf is NULL
+ * an internal buffer will be used. Abort if any problem. */
+{
+char *s = netGetString(sd, buf);
+if (s == NULL)
+     noWarnAbort();   
+return s;
+}
+
+char *netRecieveLongString(int sd)
+/* Read string and return it.  freeMem
+ * the result when done. Abort if any problem*/
+{
+char *s = netGetLongString(sd);
+if (s == NULL)
+     noWarnAbort();   
+return s;
+}
+
+char *netRecieveHugeString(int sd)
+/* Read string and return it.  freeMem
+ * the result when done. Abort if any problem*/
+{
+char *s = netGetHugeString(sd);
+if (s == NULL)
+     noWarnAbort();   
+return s;
+}
+
+
+struct lineFile *netHttpLineFileMayOpen(char *url, struct netParsedUrl **npu)
+/* Parse URL and open an HTTP socket for it but don't send a request yet. */
+{
+int sd;
+struct lineFile *lf;
+
+/* Parse the URL and try to connect. */
+AllocVar(*npu);
+netParseUrl(url, *npu);
+if (!sameString((*npu)->protocol, "http"))
+    errAbort("netHttpLineFileMayOpen: url (%s) is not for http.", url);
+sd = netConnect((*npu)->host, atoi((*npu)->port));
+if (sd < 0)
+    return NULL;
+
+/* Return handle. */
+lf = lineFileAttach(url, TRUE, sd);
+return lf;
+} /* netHttpLineFileMayOpen */
+
+
+void netHttpGet(struct lineFile *lf, struct netParsedUrl *npu,
+		boolean keepAlive)
+/* Send a GET request, possibly with Keep-Alive. */
+{
+struct dyString *dy = newDyString(512);
+
+/* Ask remote server for the file/query. */
+dyStringPrintf(dy, "GET %s HTTP/1.1\r\n", npu->file);
+dyStringPrintf(dy, "User-Agent: genome.ucsc.edu/net.c\r\n");
+dyStringPrintf(dy, "Host: %s:%s\r\n", npu->host, npu->port);
+if (!sameString(npu->user,""))
+    {
+    char up[256];
+    char *b64up = NULL;
+    safef(up,sizeof(up), "%s:%s", npu->user, npu->password);
+    b64up = base64Encode(up, strlen(up));
+    dyStringPrintf(dy, "Authorization: Basic %s\r\n", b64up);
+    freez(&b64up);
+    }
+dyStringAppend(dy, "Accept: */*\r\n");
+if (keepAlive)
+  {
+    dyStringAppend(dy, "Connection: Keep-Alive\r\n");
+    dyStringAppend(dy, "Connection: Persist\r\n");
+  }
+else
+    dyStringAppend(dy, "Connection: close\r\n");
+dyStringAppend(dy, "\r\n");
+mustWriteFd(lf->fd, dy->string, dy->stringSize);
+/* Clean up. */
+dyStringFree(&dy);
+} /* netHttpGet */
+
+int netHttpGetMultiple(char *url, struct slName *queries, void *userData,
+		       void (*responseCB)(void *userData, char *req,
+					  char *hdr, struct dyString *body))
+/* Given an URL which is the base of all requests to be made, and a 
+ * linked list of queries to be appended to that base and sent in as 
+ * requests, send the requests as a batch and read the HTTP response 
+ * headers and bodies.  If not all the requests get responses (i.e. if 
+ * the server is ignoring Keep-Alive or is imposing a limit), try again 
+ * until we can't connect or until all requests have been served. 
+ * For each HTTP response, do a callback. */
+{
+  struct slName *qStart;
+  struct slName *qPtr;
+  struct lineFile *lf;
+  struct netParsedUrl *npu;
+  struct dyString *dyQ    = newDyString(512);
+  struct dyString *body;
+  char *base;
+  char *hdr;
+  int qCount;
+  int qTotal;
+  int numParseFailures;
+  int contentLength;
+  boolean chunked;
+  boolean done;
+  boolean keepAlive;
+
+  /* Find out how many queries we'll need to do so we know how many times 
+   * it's OK to run into end of file in case server ignores Keep-Alive. */
+  qTotal = 0;
+  for (qPtr = queries;  qPtr != NULL;  qPtr = qPtr->next)
+    {
+      qTotal++;
+    }
+
+  done = FALSE;
+  qCount = 0;
+  numParseFailures = 0;
+  qStart = queries;
+  while ((! done) && (qStart != NULL))
+    {
+      lf = netHttpLineFileMayOpen(url, &npu);
+      if (lf == NULL)
+	{
+	  done = TRUE;
+	  break;
+	}
+      base = cloneString(npu->file);
+      /* Send all remaining requests with keep-alive. */
+      for (qPtr = qStart;  qPtr != NULL;  qPtr = qPtr->next)
+	{
+	  dyStringClear(dyQ);
+	  dyStringAppend(dyQ, base);
+	  dyStringAppend(dyQ, qPtr->name);
+	  strcpy(npu->file, dyQ->string);
+	  keepAlive = (qPtr->next == NULL) ? FALSE : TRUE;
+	  netHttpGet(lf, npu, keepAlive);
+	}
+      /* Get as many responses as we can; call responseCB() and 
+       * advance qStart for each. */
+      for (qPtr = qStart;  qPtr != NULL;  qPtr = qPtr->next)
+        {
+	  if (lineFileParseHttpHeader(lf, &hdr, &chunked, &contentLength))
+	    {
+	      body = lineFileSlurpHttpBody(lf, chunked, contentLength);
+	      dyStringClear(dyQ);
+	      dyStringAppend(dyQ, base);
+	      dyStringAppend(dyQ, qPtr->name);
+	      responseCB(userData, dyQ->string, hdr, body);
+	      qStart = qStart->next;
+	      qCount++;
+	    }
+	  else
+	    {
+	      if (numParseFailures++ > qTotal) {
+		done = TRUE;
+	      }
+	      break;
+	    }
+	}
+    }
+
+  return qCount;
+} /* netHttpMultipleQueries */
+
+
diff --git a/lib/nib.c b/lib/nib.c
new file mode 100644
index 0000000..d885513
--- /dev/null
+++ b/lib/nib.c
@@ -0,0 +1,516 @@
+/* Nib - nibble (4 bit) representation of nucleotide sequences. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "hash.h"
+#include "dnautil.h"
+#include "dnaseq.h"
+#include "nib.h"
+#include "sig.h"
+
+
+static char *findNibSubrange(char *fileName)
+/* find the colon starting a nib seq name/subrange in a nib file name, or NULL
+ * if none */
+{
+char *baseName = strrchr(fileName, '/');
+baseName = (baseName == NULL) ? fileName : baseName+1;
+return strchr(baseName, ':');
+}
+
+static void parseSubrange(char *subrange, char *name, 
+	unsigned *start, unsigned *end)
+/* parse the subrange specification */
+{
+char *rangePart = strchr(subrange+1, ':');
+if (rangePart != NULL)
+    {
+    /* :seqId:start-end form */
+    *rangePart = '\0';
+    strcpy(name, subrange+1);
+    *rangePart = ':';
+    rangePart++;
+    }
+else
+    {
+    /* :start-end form */
+    rangePart = subrange+1;
+    strcpy(name, ""); 
+    }
+if ((sscanf(rangePart, "%u-%u", start, end) != 2) || (*start > *end))
+    errAbort("can't parse nib file subsequence specification: %s",
+             subrange);
+}
+
+void nibParseName(unsigned options, char *fileSpec, char *filePath,
+                         char *name, unsigned *start, unsigned *end)
+/* Parse the nib name, getting the file name, seq name to use, and
+ * optionally the start and end positions. Zero is return for start
+ * and end if they are not specified. Return the path to the file
+ * and the name to use for the sequence. */
+{
+char *subrange = findNibSubrange(fileSpec);
+if (subrange != NULL)
+    {
+    *subrange = '\0';
+    parseSubrange(subrange, name, start, end);
+    strcpy(filePath, fileSpec);
+    *subrange = ':';
+    if (strlen(name) == 0)
+        {
+        /* no name in spec, generate one */
+        if (options & NIB_BASE_NAME)
+            splitPath(filePath, NULL, name, NULL);
+        else
+            strcpy(name, filePath);
+        sprintf(name+strlen(name), ":%u-%u", *start, *end);
+        }
+    }
+else
+    {
+    *start = 0;
+    *end = 0;
+    strcpy(filePath, fileSpec);
+    if (options & NIB_BASE_NAME)
+        splitPath(fileSpec, NULL, name, NULL);
+    else
+        strcpy(name, fileSpec);
+    }
+}
+
+void nibOpenVerify(char *fileName, FILE **retFile, int *retSize)
+/* Open file and verify it's in good nibble format. */
+{
+bits32 size;
+bits32 sig;
+FILE *f = fopen(fileName, "rb");
+char buffer[512];
+char buffer2[512];
+char buffer3[512];
+
+if (f == NULL)
+    {
+    /* see if nib is down a few directories ala faSplit -outDirDepth */
+    char *ptr = NULL;
+    char *dir, *file;
+    struct stat statBuf;
+
+    /* divide fileName into file and directory components */
+    safef(buffer, sizeof(buffer), "%s", fileName);
+    if ((ptr = strrchr(buffer, '/')) != NULL)
+	{
+	*ptr++ = 0;
+	dir = buffer;
+	file = ptr;
+	}
+    else
+	{
+	dir = "";
+	file = buffer;
+	}
+    
+    buffer3[0] = 0;
+    /* start at the end of the fileName (minus .nib) */
+    for(ptr = &file[strlen(file) - 5]; ; )
+	{
+	strcpy(buffer2, buffer3);
+	if (isdigit(*ptr))
+	    {
+	    /* if we have a digit in the fileName, see if there is a directory with this name */
+	    safef(buffer3, sizeof(buffer3), "%c/%s",*ptr,buffer2);
+	    ptr--;
+	    }
+	else
+	    /* we've run out of digits in the fileName, just add 0's */
+	    safef(buffer3, sizeof(buffer3), "0/%s",buffer2);
+
+	/* check to see if this directory exists */
+	safef(buffer2, sizeof(buffer2), "%s/%s", dir, buffer3);
+	if (stat(buffer2, &statBuf) < 0)
+	    break;
+
+	/* directory exists, see if our file is down there */
+	safef(buffer2, sizeof(buffer2), "%s/%s/%s", dir, buffer3, file);
+	if  ((f = fopen(buffer2, "rb")) != NULL)
+	    break;
+	}
+    if (f == NULL)
+	errAbort("Can't open %s to read: %s", fileName,  strerror(errno));
+    }
+dnaUtilOpen();
+mustReadOne(f, sig);
+mustReadOne(f, size);
+if (sig != nibSig)
+    {
+    sig = byteSwap32(sig);
+    size = byteSwap32(size);
+    if (sig != nibSig)
+	errAbort("%s is not a good .nib file.",  fileName);
+    }
+*retSize = size;
+*retFile = f;
+}
+
+static struct dnaSeq *nibInput(int options, char *fileName, char *seqName,
+                               FILE *f, int seqSize, int start, int size)
+/* Load part of an open .nib file. */
+{
+int end;
+DNA *d;
+int bVal;
+DNA *valToNtTbl = ((options &  NIB_MASK_MIXED) ? valToNtMasked : valToNt);
+struct dnaSeq *seq;
+Bits* mask = NULL;
+int bytePos, byteSize;
+int maskIdx = 0;
+
+assert(start >= 0);
+assert(size >= 0);
+
+end = start+size;
+if (end > seqSize)
+    errAbort("nib read past end of file (%d %d) in file: %s", 
+	     end, seqSize, (fileName != NULL ? fileName : "(NULL)"));
+
+AllocVar(seq);
+seq->size = size;
+seq->name = cloneString(seqName);
+seq->dna = d = needLargeMem(size+1);
+if (options & NIB_MASK_MIXED)
+    seq->mask = mask = bitAlloc(size);
+
+bytePos = (start>>1);
+fseek(f, bytePos + 2*sizeof(bits32), SEEK_SET);
+if (start & 1)
+    {
+    bVal = getc_unlocked(f);
+    if (bVal < 0)
+	{
+	errAbort("Read error 1 in %s", fileName);
+	}
+    *d++ = valToNtTbl[(bVal&0xf)];
+    size -= 1;
+    if (mask != NULL)
+        {
+        if ((bVal&0xf&MASKED_BASE_BIT) == 0)
+            bitSetOne(mask, maskIdx);
+        maskIdx++;
+        }
+    }
+byteSize = (size>>1);
+while (--byteSize >= 0)
+    {
+    bVal = getc_unlocked(f);
+    if (bVal < 0)
+	errAbort("Read error 2 in %s", fileName);
+    d[0] = valToNtTbl[(bVal>>4)];
+    d[1] = valToNtTbl[(bVal&0xf)];
+    d += 2;
+    if (mask != NULL)
+        {
+        if (((bVal>>4)&0xf) == 0)
+            bitSetOne(mask, maskIdx);
+        if ((bVal&0xf) == 0)
+            bitSetOne(mask, maskIdx+1);
+        maskIdx += 2;
+        }
+    }
+if (size&1)
+    {
+    bVal = getc_unlocked(f);
+    if (bVal < 0)
+	errAbort("Read error 3 in %s", fileName);
+    *d++ = valToNtTbl[(bVal>>4)];
+    if (mask != NULL)
+        {
+        if ((bVal>>4) == 0)
+            bitSetOne(mask, maskIdx);
+        maskIdx++;
+        }
+    }
+*d = 0;
+return seq;
+}
+
+static void nibOutput(int options, struct dnaSeq *seq, char *fileName)
+/* Write out file in format of four bits per nucleotide, with control over
+ * handling of masked positions. */
+{
+UBYTE byte;
+DNA *dna = seq->dna;
+int dVal1, dVal2;
+bits32 size = seq->size;
+int byteCount = (size>>1);
+bits32 sig = nibSig;
+int *ntValTbl = ((options & NIB_MASK_MIXED) ? ntValMasked : ntVal5);
+Bits* mask = ((options & NIB_MASK_MAP) ? seq->mask : NULL);
+int maskIdx = 0;
+FILE *f = mustOpen(fileName, "w");
+
+assert(sizeof(bits32) == 4);
+
+writeOne(f, sig);
+writeOne(f, seq->size);
+
+printf("Writing %d bases in %d bytes\n", seq->size, ((seq->size+1)/2) + 8);
+while (--byteCount >= 0)
+    {
+    dVal1 = ntValTbl[(int)dna[0]];
+    dVal2 = ntValTbl[(int)dna[1]];
+    /* Set from mask, remember bit in character is opposite sense of bit
+     * in mask. */
+    if (mask != NULL)
+        {
+        if (!bitReadOne(mask, maskIdx))
+            dVal1 |= MASKED_BASE_BIT;
+        if (!bitReadOne(mask, maskIdx+1))
+            dVal2 |= MASKED_BASE_BIT;
+        maskIdx += 2;
+        }
+    byte = (dVal1<<4) | dVal2;
+    if (putc(byte, f) < 0)
+	{
+	perror("");
+	errAbort("Couldn't write all of %s", fileName);
+	}
+    dna += 2;
+    }
+if (size & 1)
+    {
+    dVal1 = ntValTbl[(int)dna[0]];
+    if ((mask != NULL) && !bitReadOne(mask, maskIdx))
+        dVal1 |= MASKED_BASE_BIT;
+    byte = (dVal1<<4);
+    putc(byte, f);
+    }
+carefulClose(&f);
+}
+
+struct dnaSeq *nibLdPartMasked(int options, char *fileName, FILE *f, int seqSize, int start, int size)
+/* Load part of an open .nib file, with control over handling of masked
+ * positions. */
+{
+char nameBuf[512];
+safef(nameBuf, sizeof(nameBuf), "%s:%d-%d", fileName, start, start+size);
+return nibInput(options, fileName, nameBuf, f, seqSize, start, size);
+}
+
+struct dnaSeq *nibLdPart(char *fileName, FILE *f, int seqSize, int start, int size)
+/* Load part of an open .nib file. */
+{
+return nibLdPartMasked(0, fileName, f, seqSize, start, size);
+}
+
+struct dnaSeq *nibLoadPartMasked(int options, char *fileName, int start, int size)
+/* Load part of an .nib file, with control over handling of masked positions */
+{
+struct dnaSeq *seq;
+FILE *f;
+int seqSize;
+nibOpenVerify(fileName, &f, &seqSize);
+seq = nibLdPartMasked(options, fileName, f, seqSize, start, size);
+fclose(f);
+return seq;
+}
+
+struct dnaSeq *nibLoadPart(char *fileName, int start, int size)
+/* Load part of an .nib file. */
+{
+return nibLoadPartMasked(0, fileName, start, size);
+}
+
+struct dnaSeq *nibLoadAllMasked(int options, char *fileName)
+/* Load part of a .nib file, with control over handling of masked
+ * positions. Subranges of nib files may specified in the file name
+ * using the syntax:
+ *    /path/file.nib:seqid:start-end
+ * or\n"
+ *    /path/file.nib:start-end
+ * With the first form, seqid becomes the id of the subrange, with the second
+ * form, a sequence id of file:start-end will be used.
+ */
+{
+struct dnaSeq *seq;
+FILE *f;
+int seqSize;
+char filePath[PATH_LEN];
+char name[PATH_LEN];
+unsigned start, end;
+
+nibParseName(options, fileName, filePath, name, &start, &end);
+nibOpenVerify(filePath, &f, &seqSize);
+if (end == 0)
+    end = seqSize;
+seq = nibInput(options, fileName, name, f, seqSize, start, end-start);
+fclose(f);
+return seq;
+}
+
+struct dnaSeq *nibLoadAll(char *fileName)
+/* Load part of an .nib file. */
+{
+return nibLoadAllMasked(0, fileName);
+}
+
+void nibWriteMasked(int options, struct dnaSeq *seq, char *fileName)
+/* Write out file in format of four bits per nucleotide, with control over
+ * handling of masked positions. */
+{
+    nibOutput(options, seq, fileName);
+}
+
+void nibWrite(struct dnaSeq *seq, char *fileName)
+/* Write out file in format of four bits per nucleotide. */
+{
+    nibWriteMasked(0, seq, fileName);
+}
+
+struct nibStream
+/* Struct to help write a nib file one base at a time. 
+ * The routines that do this aren't very fast, but they
+ * aren't used much currently. */
+    {
+    struct nibStream *next;
+    char *fileName;	/* Name of file - allocated here. */
+    FILE *f;		/* File handle. */
+    bits32 size;	/* Current size. */
+    UBYTE byte;		/* Two nibble's worth of data. */
+    };
+
+struct nibStream *nibStreamOpen(char *fileName)
+/* Create a new nib stream.  Open file and stuff. */
+{
+struct nibStream *ns;
+FILE *f;
+
+dnaUtilOpen();
+AllocVar(ns);
+ns->f = f = mustOpen(fileName, "wb");
+ns->fileName = cloneString(fileName);
+
+/* Write header - initially zero.  Will fix it up when we close. */
+writeOne(f, ns->size);
+writeOne(f, ns->size);
+
+return ns;
+}
+
+void nibStreamClose(struct nibStream **pNs)
+/* Close a nib stream.  Flush last nibble if need be.  Fix up header. */
+{
+struct nibStream *ns = *pNs;
+FILE *f;
+bits32 sig = nibSig;
+if (ns == NULL)
+    return;
+f = ns->f;
+if (ns->size&1)
+    writeOne(f, ns->byte);
+fseek(f,  0L, SEEK_SET);
+writeOne(f, sig);
+writeOne(f, ns->size);
+fclose(f);
+freeMem(ns->fileName);
+freez(pNs);
+}
+
+void nibStreamOne(struct nibStream *ns, DNA base)
+/* Write out one base to nibStream. */
+{
+UBYTE ub = ntVal5[(int)base];
+
+if ((++ns->size&1) == 0)
+    {
+    ub += ns->byte;
+    writeOne(ns->f, ub);
+    }
+else
+    {
+    ns->byte = (ub<<4);
+    }
+}
+
+void nibStreamMany(struct nibStream *ns, DNA *dna, int size)
+/* Write many bases to nibStream. */
+{
+int i;
+for (i=0; i<size; ++i)
+    nibStreamOne(ns, *dna++);
+}
+
+boolean nibIsFile(char *fileName)
+/* Return TRUE if file is a nib file. */
+{
+boolean isANib;
+char *subrange = findNibSubrange(fileName);
+if (subrange != NULL)
+    *subrange = '\0';
+isANib = endsWith(fileName, ".nib") || endsWith(fileName, ".NIB");
+if (subrange != NULL)
+    *subrange = ':';
+return isANib;
+}
+
+boolean nibIsRange(char *fileName)
+/* Return TRUE if file specifies a subrange of a nib file. */
+{
+boolean isANib;
+char *subrange = findNibSubrange(fileName);;
+if (subrange == NULL)
+    return FALSE;
+*subrange = '\0';
+isANib = endsWith(fileName, ".nib") || endsWith(fileName, ".NIB");
+*subrange = ':';
+return isANib;
+}
+
+struct nibInfo *nibInfoNew(char *path)
+/* Make a new nibInfo with open nib file. */
+{
+struct nibInfo *nib;
+AllocVar(nib);
+nib->fileName = cloneString(path);
+nibOpenVerify(path, &nib->f, &nib->size);
+return nib;
+}
+
+void nibInfoFree(struct nibInfo **pNib)
+/* Free up nib info and close file if open. */
+{
+struct nibInfo *nib = *pNib;
+if (nib != NULL)
+    {
+    carefulClose(&nib->f);
+    freeMem(nib->fileName);
+    freez(pNib);
+    }
+}
+
+struct nibInfo *nibInfoFromCache(struct hash *hash, char *nibDir, char *nibName)
+/* Get nibInfo on nibDir/nibName.nib from cache, filling cache if need be. */
+{
+struct nibInfo *nib;
+char path[PATH_LEN];
+safef(path, sizeof(path), "%s/%s.nib", nibDir, nibName);
+nib = hashFindVal(hash, path);
+if (nib == NULL)
+    {
+    nib = nibInfoNew(path);
+    hashAdd(hash, path, nib);
+    }
+return nib;
+}
+
+int nibGetSize(char* nibFile)
+/* Get the sequence length of a nib */
+{
+FILE* fh;
+int size;
+
+nibOpenVerify(nibFile, &fh, &size);
+carefulClose(&fh);
+return size;
+}
+
diff --git a/lib/nibTwo.c b/lib/nibTwo.c
new file mode 100644
index 0000000..1d918f5
--- /dev/null
+++ b/lib/nibTwo.c
@@ -0,0 +1,122 @@
+/* nibTwo - Something to let you transparently access either
+ * .2bit or .nib files. */
+
+#include "common.h"
+#include "hash.h"
+#include "dnaseq.h"
+#include "nib.h"
+#include "twoBit.h"
+#include "nibTwo.h"
+
+
+struct nibTwoCache *nibTwoCacheNew(char *pathName)
+/* Get something that will more or less transparently get sequence from 
+ * nib files or .2bit. */ 
+{
+struct nibTwoCache *ntc;
+AllocVar(ntc);
+ntc->pathName = cloneString(pathName);
+ntc->isTwoBit = twoBitIsFile(pathName);
+if (ntc->isTwoBit)
+    ntc->tbf = twoBitOpen(pathName);
+else
+    ntc->nibHash = newHash(10);
+return ntc;
+}
+
+void nibTwoCacheFree(struct nibTwoCache **pNtc)
+/* Free up resources associated with nibTwoCache. */
+{
+struct nibTwoCache *ntc = *pNtc;
+if (ntc != NULL)
+    {
+    freez(&ntc->pathName);
+    if (ntc->isTwoBit)
+        twoBitClose(&ntc->tbf);
+    else
+        {
+	struct hashEl *el, *list = hashElListHash(ntc->nibHash);
+	struct nibInfo *nib;
+	for (el = list; el != NULL; el = el->next)
+	     {
+	     nib = el->val;
+	     nibInfoFree(&nib);
+	     }
+	hashElFreeList(&list);
+	hashFree(&ntc->nibHash);
+	}
+    freez(pNtc);
+    }
+}
+
+struct dnaSeq *nibTwoCacheSeq(struct nibTwoCache *ntc, char *seqName)
+/* Return all of sequence. This will have repeats in lower case. */
+{
+if (ntc->isTwoBit)
+    return twoBitReadSeqFrag(ntc->tbf, seqName, 0, 0);
+else
+    {
+    struct nibInfo *nib = nibInfoFromCache(ntc->nibHash, ntc->pathName, seqName);
+    return nibLdPart(nib->fileName, nib->f, nib->size, 0, nib->size);
+    }
+}
+
+struct dnaSeq *nibTwoCacheSeqPartExt(struct nibTwoCache *ntc, char *seqName, int start, int size,
+                                     boolean doMask, int *retFullSeqSize)
+/* Return part of sequence. If *retFullSeqSize is non-null then return full
+ * size of sequence (not just loaded part) there.   Sequence will be lower
+ * case if doMask is false, mixed case (repeats in lower)
+ * if doMask is true. */
+{
+if (ntc->isTwoBit)
+    {
+    return twoBitReadSeqFragExt(ntc->tbf, seqName, start, start+size,
+                                doMask, retFullSeqSize);
+    }
+else
+    {
+    struct nibInfo *nib = nibInfoFromCache(ntc->nibHash, ntc->pathName, seqName);
+    int opts = (doMask ? NIB_MASK_MIXED : 0);
+    if (retFullSeqSize != NULL)
+        *retFullSeqSize = nib->size;
+    return nibLdPartMasked(opts, nib->fileName, nib->f, nib->size, start, size);
+    }
+}
+
+struct dnaSeq *nibTwoCacheSeqPart(struct nibTwoCache *ntc, char *seqName, int start, int size,
+	int *retFullSeqSize)
+/* Return part of sequence. If *retFullSeqSize is non-null then return full size of
+ * sequence (not just loaded part) there. This will have repeats in lower case. */
+{
+return nibTwoCacheSeqPartExt(ntc, seqName, start, size, TRUE, retFullSeqSize);
+}
+
+struct dnaSeq *nibTwoLoadOne(char *pathName, char *seqName)
+/* Return sequence from a directory full of nibs or a .2bit file. 
+ * The sequence will have repeats in lower case. */
+{
+struct dnaSeq *seq;
+if (twoBitIsFile(pathName))
+    {
+    struct twoBitFile *tbf = twoBitOpen(pathName);
+    seq = twoBitReadSeqFrag(tbf, seqName, 0, 0);
+    twoBitClose(&tbf);
+    }
+else
+    {
+    char path[512];
+    safef(path, sizeof(path), "%s/%s.nib", pathName, seqName);
+    seq = nibLoadAllMasked(NIB_MASK_MIXED, path);
+    }
+return seq;
+}
+
+int nibTwoGetSize(struct nibTwoCache *ntc, char *seqName)
+/* Return size of sequence. */
+{
+if (ntc->isTwoBit)
+    return twoBitSeqSize(ntc->tbf, seqName);
+else
+    return nibInfoFromCache(ntc->nibHash, ntc->pathName, seqName)->size;
+}
+
diff --git a/lib/nt4.c b/lib/nt4.c
new file mode 100644
index 0000000..f291066
--- /dev/null
+++ b/lib/nt4.c
@@ -0,0 +1,260 @@
+/* nt4 - stuff to handle 2-bit-a-base representation of DNA.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "dnautil.h"
+#include "shaRes.h"
+#include "dnaseq.h"
+#include "nt4.h"
+#include "sig.h"
+
+
+static size_t bits32PaddedSize(size_t size)
+{
+    return (((size+15)>>4)<<2);
+}
+
+static struct nt4Seq *allocNt4(size_t baseCount, char *name)
+/* Create a new nt4Seq struct with memory for bases. */
+{
+size_t memSize = bits32PaddedSize(baseCount);
+struct nt4Seq *seq = needMem(sizeof(*seq));
+seq->baseCount = baseCount;
+seq->bases = needLargeMem(memSize);
+seq->name = cloneString(name);
+return seq;
+}
+
+
+struct nt4Seq *newNt4(DNA *dna, int size, char *name)
+/* Create a new DNA seq with 2 bits per base pair. */
+{
+bits32 *packed;
+DNA *unpacked;
+char last[16];
+struct nt4Seq *seq = allocNt4(size, name);
+packed = seq->bases;
+unpacked = dna;
+while (size > 16)
+    {
+    *packed++ = packDna16(dna);
+    dna += 16;
+    size -= 16;
+    }
+if (size > 0)
+    {
+    memcpy(last, dna, size);
+    *packed++ = packDna16(dna);
+    }
+return seq;
+}
+
+void freeNt4(struct nt4Seq **pSeq)
+/* Free up DNA seq with 2 bits per base pair */
+{
+struct nt4Seq *seq = *pSeq;
+if (seq == NULL)
+    return;
+freeMem(seq->bases);
+freeMem(seq->name);
+freez(pSeq);
+}
+
+static FILE *nt4OpenVerify(char *fileName)
+/* Open up an nt4 file and verify signature.
+ * Abort if any problem. */
+{
+FILE *f = mustOpen(fileName, "rb");
+bits32 signature;
+mustReadOne(f, signature);
+if (signature != nt4Signature)
+    errAbort("%s is not a good Nt4 file", fileName);
+return f;
+}
+
+struct nt4Seq *loadNt4(char *fileName, char *seqName)
+/* Load up an nt4 sequence from a file. */
+{
+bits32 size;
+struct nt4Seq *seq;
+FILE *f = nt4OpenVerify(fileName);
+
+mustReadOne(f, size);
+if (seqName == NULL)
+    seqName = fileName;
+seq = allocNt4(size, seqName);
+mustRead(f, seq->bases, bits32PaddedSize(size));
+carefulClose(&f);
+return seq;
+}
+
+void  saveNt4(char *fileName, DNA *dna, bits32 dnaSize)
+/* Save dna in an NT4 file. */
+{
+FILE *f = mustOpen(fileName, "wb");
+bits32 signature = nt4Signature;
+bits32 bases;
+char last[16];
+
+writeOne(f, signature);
+writeOne(f, dnaSize);
+while (dnaSize >= 16)
+    {
+    bases = packDna16(dna);
+    writeOne(f, bases);
+    dna += 16;
+    dnaSize -= 16;
+    }
+if (dnaSize > 0)
+    {
+    zeroBytes(last, sizeof(last));
+    memcpy(last, dna, dnaSize);
+    bases = packDna16(last);
+    writeOne(f, bases);
+    }
+fclose(f);
+}
+
+int nt4BaseCount(char *fileName)
+/* Return number of bases in NT4 file. */
+{
+bits32 size;
+FILE *f = nt4OpenVerify(fileName);
+
+mustReadOne(f, size);
+fclose(f);
+return (int)size;
+}
+
+static void unpackRightSide(bits32 tile, int baseCount, DNA *out)
+/* Unpack last part of tile into DNA. */
+{
+int j;
+
+for (j=baseCount; --j>=0; )
+    {
+    out[j] = valToNt[tile & 0x3];
+    tile >>= 2;
+    }
+}
+
+static void unpackLeftSide(bits32 tile, int baseCount, DNA *out)
+/* Unpack first part of tile into DNA. */
+{
+int bitsToDump = ((16-baseCount)<<1);
+tile >>= bitsToDump;
+out += baseCount;
+while (--baseCount >= 0)
+    {
+    *--out = valToNt[tile&0x3];
+    tile >>= 2;
+    }
+}
+
+static void unpackMidWord(bits32 tile, int startBase, int baseCount, DNA *out)
+/* Unpack part of a single word. */
+{
+tile >>= ((16-startBase-baseCount)<<1);
+out += baseCount;
+while (--baseCount >= 0)
+    {
+    *--out = valToNt[tile&0x3];
+    tile >>= 2;
+    }
+}
+
+void unalignedUnpackDna(bits32 *tiles, int start, int size, DNA *unpacked)
+/* Unpack into out, even though not starting/stopping on tile 
+ * boundaries. */
+{
+DNA *pt = unpacked;
+int sizeLeft = size;
+int firstBases, middleBases;
+bits32 *startTile, *endTile;
+
+dnaUtilOpen();
+
+/* See if all data is in a single word. */
+startTile = tiles + (start>>4);
+endTile = tiles + ((start + size - 1)>>4);
+if (startTile == endTile)
+    {
+    unpackMidWord(*startTile, start&0xf, size, unpacked);
+    return;
+    }
+
+/* Skip over initial stuff. */
+tiles = startTile;
+
+/* See if just have one tile to 
+ * Unpack the right hand side of the first tile. */
+firstBases = (16 - (start&0xf));
+unpackRightSide(*tiles, firstBases, pt);
+pt += firstBases;
+sizeLeft -= firstBases;
+tiles += 1;
+
+/* Unpack all of the middle tiles. */
+middleBases = (sizeLeft&0x7ffffff0);
+unpackDna(tiles, middleBases>>4, pt);
+pt += middleBases;
+sizeLeft -= middleBases;
+tiles += (middleBases>>4);
+
+/* Unpack the left side of last tile. */
+if (sizeLeft > 0)
+    unpackLeftSide(*tiles, sizeLeft, pt);
+pt += sizeLeft;
+
+/* Add trailing zero to make it a DNA string. */
+assert(pt == unpacked+size);
+*pt = 0;
+}
+
+DNA *nt4Unpack(struct nt4Seq *n, int start, int size)
+/* Create an unpacked section of nt4 sequence.  */
+{
+DNA *unpacked = needLargeMem(size+1);
+unalignedUnpackDna(n->bases, start, size, unpacked);
+return unpacked;
+}
+
+
+DNA *nt4LoadPart(char *fileName, int start, int size)
+/* Load part of an nt4 file. */
+{
+bits32 basesInFile;
+int tStart, tEnd, tSize;
+int end;
+FILE *f;
+DNA *unpacked;
+bits32 *tiles;
+
+/* Open file, and make sure request is covered by file. */
+f = nt4OpenVerify(fileName);
+mustReadOne(f, basesInFile);
+
+assert(start >= 0);
+end = start + size;
+assert(end <= (int)basesInFile);
+
+/* Figure out tiles to load */
+tStart = (start>>4);
+tEnd = ((end+15)>>4);
+tSize = tEnd - tStart;
+
+/* Allocate tile array and read it from disk. */
+tiles = needLargeMem(tSize * sizeof(*tiles));
+fseek(f, tStart * sizeof(*tiles), SEEK_CUR);
+mustRead(f, tiles, tSize * sizeof(*tiles) );
+
+/* Allocate and unpack array. */
+unpacked = needLargeMem(size+1);
+unalignedUnpackDna(tiles, start - (tStart<<4), size, unpacked);
+
+freeMem(tiles);
+fclose(f);
+return unpacked;
+}
diff --git a/lib/numObscure.c b/lib/numObscure.c
new file mode 100644
index 0000000..f99aab4
--- /dev/null
+++ b/lib/numObscure.c
@@ -0,0 +1,103 @@
+/* numObscure - obscure but sometimes useful numerical functions. */
+#include "common.h"
+#include "obscure.h"
+
+static void rangeIncludingZero(double start, double end, double *retStart, double *retEnd)
+/* If start == end, then make range go from zero to the start/end value. */
+{
+if (start < 0.0)
+    {
+    *retStart = start;
+    *retEnd = 0;
+    }
+else if (start > 0.0)
+    {
+    *retStart = 0;
+    *retEnd = end;
+    }
+else
+    {
+    *retStart = 0;
+    *retEnd = 1;
+    }
+return;
+}
+
+void rangeRoundUp(double start, double end, double *retStart, double *retEnd)
+/* Round start and end so that they cover a slightly bigger range, but with more round
+ * numbers.  For instance 0.23:9.89 becomes 0:10 */
+{
+double size = end - start;
+if (size < 0)
+    errAbort("start (%g) after end (%g) in rangeRoundUp", start, end);
+
+/* Flat ranges get moved to include zero for scale. */
+if (size == 0.0)
+    {
+    rangeIncludingZero(start, end, &start, &end);
+    size = end - start;
+    }
+
+/* Figure out "increment", which will be 1, 2, 5, or 10, or a multiple of 10 of these 
+ * Want to have at least two increments in range. */
+double exponent = 1;
+double scaledSize = size;
+double increment = 0;
+while (scaledSize < 100)
+    {
+    scaledSize *= 10;
+    exponent /= 10;
+    }
+while (scaledSize >= 100)
+    {
+    scaledSize /= 10;
+    exponent *= 10;
+    }
+/* At this point have a number between 10 and 100 */
+if (scaledSize < 12)
+    increment = 1;
+else if (scaledSize < 20)
+    increment = 2;
+else if (scaledSize < 75)
+    increment = 5;
+else
+    increment = 10;
+increment *= exponent;
+
+int startInIncrements = floor(start/increment);
+int endInIncrements = ceil(end/increment);
+*retStart = startInIncrements * increment;
+*retEnd = endInIncrements * increment;
+}
+
+void rangeFromMinMaxMeanStd(double minVal, double maxVal, double mean, double std,
+	double *retStart, double *retEnd)
+/* Given some basic statistical properties, set a range that will be good on a wide
+ * range of biological data. */
+{
+double start,end;
+if (isnan(std))
+    {
+    /* Handle a case that occurred in version 1 bigWigs and bigBeds due to fault in
+     * sumSquares calculation. */
+    start = mean-5;
+    end = mean+5;
+    if (start < minVal) start = minVal;
+    if (end > maxVal) end = maxVal;
+    }
+else if (std == 0)
+    {
+    start = end = mean;
+    rangeIncludingZero(start, end, &start, &end);
+    }
+else
+    {
+    start = mean - 5*std;
+    end = mean + 5*std;
+    if (start < minVal) start = minVal;
+    if (end > maxVal) end = maxVal;
+    }
+*retStart = start;
+*retEnd = end;
+}
+
diff --git a/lib/obscure.c b/lib/obscure.c
new file mode 100644
index 0000000..09f00b6
--- /dev/null
+++ b/lib/obscure.c
@@ -0,0 +1,737 @@
+/* Obscure stuff that is handy every now and again. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include <unistd.h>
+#include "portable.h"
+#include "localmem.h"
+#include "hash.h"
+#include "obscure.h"
+#include "linefile.h"
+
+static int _dotForUserMod = 100; /* How often does dotForUser() output a dot. */
+
+long incCounterFile(char *fileName)
+/* Increment a 32 bit value on disk. */
+{
+long val = 0;
+FILE *f = fopen(fileName, "r+b");
+if (f != NULL)
+    {
+    mustReadOne(f, val);
+    rewind(f);
+    }
+else
+    {
+    f = fopen(fileName, "wb");
+    }
+++val;
+if (f != NULL)
+    {
+    fwrite(&val, sizeof(val), 1, f);
+    if (fclose(f) != 0)
+        errnoAbort("fclose failed");
+    }
+return val;
+}
+
+int digitsBaseTwo(unsigned long x)
+/* Return base two # of digits. */
+{
+int digits = 0;
+while (x)
+    {
+    digits += 1;
+    x >>= 1;
+    }
+return digits;
+}
+
+int digitsBaseTen(int x)
+/* Return number of digits base 10. */
+{
+int digCount = 1;
+if (x < 0)
+    {
+    digCount = 2;
+    x = -x;
+    }
+while (x >= 10)
+    {
+    digCount += 1;
+    x /= 10;
+    }
+return digCount;
+}
+
+void writeGulp(char *file, char *buf, int size)
+/* Write out a bunch of memory. */
+{
+FILE *f = mustOpen(file, "w");
+mustWrite(f, buf, size);
+carefulClose(&f);
+}
+
+void readInGulp(char *fileName, char **retBuf, size_t *retSize)
+/* Read whole file in one big gulp. */
+{
+size_t size = (size_t)fileSize(fileName);
+char *buf;
+FILE *f = mustOpen(fileName, "rb");
+*retBuf = buf = needLargeMem(size+1);
+mustRead(f, buf, size);
+buf[size] = 0;      /* Just in case it needs zero termination. */
+fclose(f);
+if (retSize != NULL)
+    *retSize = size;
+}
+
+void readAllWords(char *fileName, char ***retWords, int *retWordCount, char **retBuf)
+/* Read in whole file and break it into words. You need to freeMem both
+ * *retWordCount and *retBuf when done. */
+{
+int wordCount;
+char *buf = NULL;
+char **words = NULL;
+size_t bufSize;
+
+readInGulp(fileName, &buf, &bufSize);
+wordCount = chopByWhite(buf, NULL, 0);
+if (wordCount != 0)
+    {
+    words = needMem(wordCount * sizeof(words[0]));
+    chopByWhite(buf, words, wordCount);
+    }
+*retWords = words;
+*retWordCount = wordCount;
+*retBuf = buf;
+}
+
+int countWordsInFile(char *fileName)
+/* Count number of words in file. */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *line;
+int wordCount = 0;
+while (lineFileNext(lf, &line, NULL))
+    wordCount += chopByWhite(line, NULL, 0);
+lineFileClose(&lf);
+return wordCount;
+}
+
+struct hash *hashWordsInFile(char *fileName, int hashSize)
+/* Create a hash of space delimited words in file. */
+{
+struct hash *hash = newHash(hashSize);
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *line, *word;
+while (lineFileNext(lf, &line, NULL))
+    {
+    while ((word = nextWord(&line)) != NULL)
+        hashAdd(hash, word, NULL);
+    }
+lineFileClose(&lf);
+return hash;
+}
+
+struct hash *hashNameIntFile(char *fileName)
+/* Given a two column file (name, integer value) return a
+ * hash keyed by name with integer values */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[2];
+struct hash *hash = hashNew(16);
+while (lineFileRow(lf, row))
+    hashAddInt(hash, row[0], lineFileNeedNum(lf, row, 1));
+lineFileClose(&lf);
+return hash;
+}
+
+struct hash *hashTwoColumnFile(char *fileName)
+/* Given a two column file (key, value) return a hash. */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[2];
+struct hash *hash = hashNew(16);
+while (lineFileRow(lf, row))
+    {
+    char *name = row[0];
+    char *value = lmCloneString(hash->lm, row[1]);
+    hashAdd(hash, name, value);
+    }
+lineFileClose(&lf);
+return hash;
+}
+
+struct slName *readAllLines(char *fileName)
+/* Read all lines of file into a list.  (Removes trailing carriage return.) */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+struct slName *list = NULL, *el;
+char *line;
+
+while (lineFileNext(lf, &line, NULL))
+     {
+     el = newSlName(line);
+     slAddHead(&list, el);
+     }
+slReverse(&list);
+return list;
+}
+
+void copyFile(char *source, char *dest)
+/* Copy file from source to dest. */
+{
+int bufSize = 64*1024;
+char *buf = needMem(bufSize);
+int bytesRead;
+int s, d;
+
+s = open(source, O_RDONLY);
+if (s < 0)
+    errAbort("Couldn't open %s. %s\n", source, strerror(errno));
+d = creat(dest, 0777);
+if (d < 0)
+    {
+    close(s);
+    errAbort("Couldn't open %s. %s\n", dest, strerror(errno));
+    }
+while ((bytesRead = read(s, buf, bufSize)) > 0)
+    {
+    if (write(d, buf, bytesRead) < 0)
+        errAbort("Write error on %s. %s\n", dest, strerror(errno));
+    }
+close(s);
+if (close(d) != 0)
+    errnoAbort("close failed");
+freeMem(buf);
+}
+
+void copyOpenFile(FILE *inFh, FILE *outFh)
+/* copy an open stdio file */
+{
+int c;
+while ((c = fgetc(inFh)) != EOF)
+    fputc(c, outFh);
+if (ferror(inFh))
+    errnoAbort("file read failed");
+if (ferror(outFh))
+    errnoAbort("file write failed");
+}
+
+void cpFile(int s, int d)
+/* Copy from source file to dest until reach end of file. */
+{
+int bufSize = 64*1024, readSize;
+char *buf = needMem(bufSize);
+
+for (;;)
+    {
+    readSize = read(s, buf, bufSize);
+    if (readSize > 0)
+        mustWriteFd(d, buf, readSize);
+    if (readSize <= 0)
+        break;
+    }
+freeMem(buf);
+}
+
+void *intToPt(int i)
+/* Convert integer to pointer. Use when really want to store an
+ * int in a pointer field. */
+{
+char *pt = NULL;
+return pt+i;
+}
+
+int ptToInt(void *pt)
+/* Convert pointer to integer.  Use when really want to store a
+ * pointer in an int. */
+{
+char *a = NULL, *b = pt;
+return b - a;
+}
+
+void *sizetToPt(size_t i)
+/* Convert size_t to pointer. Use when really want to store a
+ * size_t in a pointer. */
+{
+char *pt = NULL;
+return pt+i;
+}
+
+size_t ptToSizet(void *pt)
+/* Convert pointer to size_t.  Use when really want to store a
+ * pointer in a size_t. */
+{
+char *a = NULL, *b = pt;
+return b - a;
+}
+
+boolean parseQuotedStringNoEscapes( char *in, char *out, char **retNext)
+/* Read quoted string from in (which should begin with first quote).
+ * Write unquoted string to out, which may be the same as in.
+ * Return pointer to character past end of string in *retNext. 
+ * Return FALSE if can't find end.
+ * Unlike parseQuotedString() do not treat backslash as an escape
+ *	character, merely pass it on through.
+ */
+{
+char c, *s = in;
+int quoteChar = *s++;
+
+for (;;)
+   {
+   c = *s++;
+   if (c == 0)
+       {
+       warn("Unmatched %c", quoteChar);
+       return FALSE;
+       }
+   else if (c == quoteChar)
+       break;
+   else
+       *out++ = c;
+   }
+*out = 0;
+if (retNext != NULL)
+    *retNext = s;
+return TRUE;
+}
+
+boolean parseQuotedString( char *in, char *out, char **retNext)
+/* Read quoted string from in (which should begin with first quote).
+ * Write unquoted string to out, which may be the same as in.
+ * Return pointer to character past end of string in *retNext. 
+ * Return FALSE if can't find end. */
+{
+char c, *s = in;
+int quoteChar = *s++;
+boolean escaped = FALSE;
+
+for (;;)
+   {
+   c = *s++;
+   if (c == 0)
+       {
+       warn("Unmatched %c", quoteChar);
+       return FALSE;
+       }
+   if (escaped)
+       {
+       if (c == '\\' || c == quoteChar)
+          *out++ = c;
+       else
+          {
+	  *out++ = '\\';
+	  *out++ = c;
+	  }
+       escaped = FALSE;
+       }
+   else
+       {
+       if (c == '\\')
+           escaped = TRUE;
+       else if (c == quoteChar)
+           break;
+       else
+           *out++ = c;
+       }
+   }
+*out = 0;
+if (retNext != NULL)
+    *retNext = s;
+return TRUE;
+}
+
+char *nextQuotedWord(char **pLine)
+/* Generalization of nextWord.  Returns next quoted
+ * string or if no quotes next word.  Updates *pLine
+ * to point past word that is returned. Does not return
+ * quotes. */
+{
+char *line, c;
+line = skipLeadingSpaces(*pLine);
+if (line == NULL || line[0] == 0)
+    return NULL;
+c = *line;
+if (c == '"' || c == '\'')
+    {
+    if (!parseQuotedString(line, line, pLine))
+        return NULL;
+    return line;
+    }
+else
+    {
+    return nextWord(pLine);
+    }
+}
+
+void escCopy(char *in, char *out, char toEscape, char escape)
+/* Copy in to out, escaping as needed.  Out better be big enough. 
+ * (Worst case is strlen(in)*2 + 1.) */
+{
+char c;
+for (;;)
+    {
+    c = *in++;
+    if (c == toEscape)
+        *out++ = escape;
+    *out++ = c;
+    if (c == 0)
+        break;
+    }
+}
+
+char *makeEscapedString(char *in, char toEscape)
+/* Return string that is a copy of in, but with all
+ * toEscape characters preceded by '\' 
+ * When done freeMem result. */
+{
+int newSize = strlen(in) + countChars(in, toEscape);
+char *out = needMem(newSize+1);
+escCopy(in, out, toEscape, '\\');
+return out;
+}
+
+char *makeQuotedString(char *in, char quoteChar)
+/* Create a string surrounded by quoteChar, with internal
+ * quoteChars escaped.  freeMem result when done. */
+{
+int newSize = 2 + strlen(in) + countChars(in, quoteChar);
+char *out = needMem(newSize+1);
+out[0] = quoteChar;
+escCopy(in, out+1, quoteChar, '\\');
+out[newSize-1] = quoteChar;
+return out;
+}
+
+struct hash *hashThisEqThatLine(char *line, int lineIx, boolean firstStartsWithLetter)
+/* Return a symbol table from a line of form:
+ *   1-this1=val1 2-this='quoted val2' var3="another val" 
+ * If firstStartsWithLetter is true, then the left side of the equals must start with
+ * a letter. */
+{
+char *dupe = cloneString(line);
+char *s = dupe, c;
+char *var, *val;
+struct hash *hash = newHash(8);
+
+for (;;)
+    {
+    if ((var = skipLeadingSpaces(s)) == NULL)
+        break;
+
+    if ((c = *var) == 0)
+        break;
+    if (firstStartsWithLetter && !isalpha(c))
+	errAbort("line %d of custom input: variable needs to start with letter '%s'", lineIx, var);
+    val = strchr(var, '=');
+    if (val == NULL)
+        {
+        errAbort("line %d of var %s in custom input: %s \n missing = in var/val pair", lineIx, var, line);
+        }
+    *val++ = 0;
+    c = *val;
+    if (c == '\'' || c == '"')
+        {
+	if (!parseQuotedString(val, val, &s))
+	    errAbort("line %d of input: missing closing %c", lineIx, c);
+	}
+    else
+	{
+	s = skipToSpaces(val);
+	if (s != NULL) *s++ = 0;
+	}
+    hashAdd(hash, var, cloneString(val));
+    }
+freez(&dupe);
+return hash;
+}
+
+struct hash *hashVarLine(char *line, int lineIx)
+/* Return a symbol table from a line of form:
+ *   var1=val1 var2='quoted val2' var3="another val" */
+{
+return hashThisEqThatLine(line, lineIx, TRUE);
+}
+
+struct slName *stringToSlNames(char *string)
+/* Convert string to a list of slNames separated by
+ * white space, but allowing multiple words in quotes.
+ * Quotes if any are stripped.  */
+{
+struct slName *list = NULL, *name;
+char *dupe = cloneString(string);
+char c, *s = dupe, *e;
+
+for (;;)
+    {
+    if ((s = skipLeadingSpaces(s)) == NULL)
+        break;
+    if ((c = *s) == 0)
+        break;
+    if (c == '\'' || c == '"')
+        {
+	if (!parseQuotedString(s, s, &e))
+	    errAbort("missing closing %c in %s", c, string);
+	}
+    else
+        {
+	e = skipToSpaces(s);
+	if (e != NULL) *e++ = 0;
+	}
+    name = slNameNew(s);
+    slAddHead(&list, name);
+    s = e;
+    }
+freeMem(dupe);
+slReverse(&list);
+return list;
+}
+
+struct slName *charSepToSlNames(char *string, char c)
+/* Convert character-separated list of items to slName list. 
+ * Note that the last occurence of c is optional.  (That
+ * is for a comma-separated list a,b,c and a,b,c, are
+ * equivalent. */
+{
+struct slName *list = NULL, *el;
+char *s, *e;
+
+s = string;
+while (s != NULL && s[0] != 0)
+    {
+    e = strchr(s, c);
+    if (e == NULL)
+        {
+	el = slNameNew(s);
+	slAddHead(&list, el);
+	break;
+	}
+    else
+        {
+	el = slNameNewN(s, e - s);
+	slAddHead(&list, el);
+	s = e+1;
+	}
+    }
+slReverse(&list);
+return list;
+}
+
+struct slName *commaSepToSlNames(char *commaSep)
+/* Convert comma-separated list of items to slName list.  */
+{
+return charSepToSlNames(commaSep, ',');
+}
+
+
+void sprintLongWithCommas(char *s, long long l)
+/* Print out a long number with commas a thousands, millions, etc. */
+{
+long long billions, millions, thousands;
+if (l >= 1000000000)
+    {
+    billions = l/1000000000;
+    l -= billions * 1000000000;
+    millions = l/1000000;
+    l -= millions * 1000000;
+    thousands = l/1000;
+    l -= thousands * 1000;
+    sprintf(s, "%lld,%03lld,%03lld,%03lld", billions, millions, thousands, l);
+    }
+else if (l >= 1000000)
+    {
+    millions = l/1000000;
+    l -= millions * (long long)1000000;
+    thousands = l/1000;
+    l -= thousands * 1000;
+    sprintf(s, "%lld,%03lld,%03lld", millions, thousands, l);
+    }
+else if (l >= 1000)
+    {
+    thousands = l/1000;
+    l -= thousands * 1000;
+    sprintf(s, "%lld,%03lld", thousands, l);
+    }
+else
+    sprintf(s, "%lld", l);
+}
+
+void printLongWithCommas(FILE *f, long long l)
+/* Print out a long number with commas at thousands, millions, etc. */
+{
+char ascii[32];
+sprintLongWithCommas(ascii, l);
+fprintf(f, "%s", ascii);
+}
+
+void sprintWithGreekByte(char *s, int slength, long long size)
+/* Numbers formatted with PB, TB, GB, MB, KB, B */
+{
+char *greek[] = {"B", "KB", "MB", "GB", "TB", "PB"};
+int i = 0;
+long long d = 1;
+while ((size/d) >= 1024)
+    {
+    ++i;
+    d *= 1024;
+    }
+double result = ((double)size)/d;
+if (result < 10)
+    safef(s,slength,"%3.1f %s",((double)size)/d, greek[i]);
+else
+    safef(s,slength,"%3.0f %s",((double)size)/d, greek[i]);
+}
+
+
+void shuffleArrayOfPointers(void *pointerArray, int arraySize, int shuffleCount)
+/* Shuffle array of pointers of given size given number of times. */
+{
+void **array = pointerArray, *pt;
+int i, randIx;
+
+/* Randomly permute an array using the method from Cormen, et al */
+for (i=0; i<arraySize; ++i)
+    {
+    randIx = i + (rand() % (arraySize - i));
+    pt = array[i];
+    array[i] = array[randIx];
+    array[randIx] = pt;
+    }
+}
+
+void shuffleList(void *pList, int shuffleCount)
+/* Randomize order of slList.  Usage:
+ *     randomizeList(&list)
+ * where list is a pointer to a structure that
+ * begins with a next field. */
+{
+struct slList **pL = (struct slList **)pList;
+struct slList *list = *pL;
+int count;
+count = slCount(list);
+if (count > 1)
+    {
+    struct slList *el;
+    struct slList **array;
+    int i;
+    array = needLargeMem(count * sizeof(*array));
+    for (el = list, i=0; el != NULL; el = el->next, i++)
+        array[i] = el;
+    for (i=0; i<4; ++i)
+        shuffleArrayOfPointers(array, count, shuffleCount);
+    list = NULL;
+    for (i=0; i<count; ++i)
+        {
+        array[i]->next = list;
+        list = array[i];
+        }
+    freeMem(array);
+    slReverse(&list);
+    *pL = list;       
+    }
+}
+
+char *stripCommas(char *position)
+/* make a new string with commas stripped out */
+{
+char *newPos = cloneString(position);
+char *nPtr = newPos;
+
+if (position == NULL)
+    return NULL;
+while((*nPtr = *position++))
+    if (*nPtr != ',')
+	nPtr++;
+
+return newPos;
+}
+
+void dotForUserInit(int dotMod)
+/* Set how often dotForUser() outputs a dot. */
+{
+assert(dotMod > 0);
+_dotForUserMod = dotMod;
+}
+
+void dotForUser()
+/* Write out a dot every _dotForUserMod times this is called. */
+{
+static int dot = -10;
+/* Check to see if dot has been initialized. */
+if(dot == - 10)
+    dot = _dotForUserMod;
+
+if (--dot <= 0)
+    {
+    putc('.', stderr);
+    fflush(stderr);
+    dot = _dotForUserMod;
+    }
+}
+
+void spaceToUnderbar(char *s)
+/* Convert white space to underbar. */
+{
+char c;
+while ((c = *s) != 0)
+    {
+    if (isspace(c))
+        *s = '_';
+    ++s;
+    }
+}
+
+void printVmPeak()
+/* print to stderr peak Vm memory usage (if /proc/ business exists) */
+{
+pid_t pid = getpid();
+char temp[256];
+safef(temp, sizeof(temp), "/proc/%d/status", (int) pid);
+struct lineFile *lf = lineFileMayOpen(temp, TRUE);
+if (lf)
+    {
+    char *line;
+    while (lineFileNextReal(lf, &line))
+	{
+	if (stringIn("VmPeak", line))
+	    {
+	    fprintf(stderr, "# pid=%d: %s\n", pid, line);
+	    break;
+	    }
+	}
+    lineFileClose(&lf);
+    }
+else
+    fprintf(stderr, "# printVmPeak: %s - not available\n", temp);
+fflush(stderr);
+}
+
+boolean nameInCommaList(char *name, char *commaList)
+/* Return TRUE if name is in comma separated list. */
+{
+if (commaList == NULL)
+    return FALSE;
+int nameLen = strlen(name);
+for (;;)
+    {
+    char c = *commaList;
+    if (c == 0)
+        return FALSE;
+    if (memcmp(name, commaList, nameLen) == 0)
+        {
+	c = commaList[nameLen];
+	if (c == 0 || c == ',')
+	    return TRUE;
+	}
+    commaList = strchr(commaList, ',');
+    if (commaList == NULL)
+        return FALSE;
+    commaList += 1;
+    }
+}
+
diff --git a/lib/oldGff.c b/lib/oldGff.c
new file mode 100644
index 0000000..602d2b2
--- /dev/null
+++ b/lib/oldGff.c
@@ -0,0 +1,643 @@
+/* oldGff - module for reading GFFs.  This is largely if not
+ * entirely superceded by the gff module. 
+ *
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "dnautil.h"
+#include "oldGff.h"
+#include "dnaseq.h"
+#include "htmshell.h"
+#include "portable.h"
+#include "localmem.h"
+
+
+#define errfile stdout
+
+static char _gffIdent[] = "##gff-version";
+
+struct gffSegLine
+    {
+    char seqname[64];   /* Name of DNA sequence this refers to. */
+    char source[64];	/* Who put this segment here... */
+    char feature[64];      /* CDS, E, I, exon, intron, ??? */
+    long start, end;   /* Offsets into DNA array, end inclusive */
+    char score[62];	/* A number between 0 and 1 */
+    char strand[4];	/* + or - */
+    char frame[4];     /* 0, 1, 2, or . */
+    char group[128];  /* Name of gene  cosmid.number. */
+    };
+
+static int gffSegLineScan(struct gff* gff, struct gffSegLine *seg)
+{
+    int scanned = sscanf(gff->buf, "%s %s %s %ld %ld %s %1s %s %s",
+	seg->seqname, seg->source, seg->feature,
+	&seg->start, &seg->end,
+	seg->score, seg->strand, seg->frame, seg->group);
+    return scanned;
+}
+
+static boolean _gffGetLine(struct gff *gff)
+/* Get the next line into a gff file.  (private)
+ * return FALSE at EOF or if problem. */
+{
+char *s;
+s = fgets(gff->buf, gff->bufSize, gff->file);
+if (s == NULL)
+    {
+    return FALSE;
+    }
+gff->bytesInBuf = strlen(gff->buf);
+gff->readIx = 0;
+gff->lineNumber += 1;
+return TRUE;
+}
+
+static boolean _gffSeekDoubleSharpLine(struct gff *gff)
+/* Go find next line that begins with ## */
+{
+for (;;)
+    {
+    if (!_gffGetLine(gff)) return FALSE;
+    if (gff->bytesInBuf >= 2)
+	if (gff->buf[0] == '#' && gff->buf[1] == '#') 
+		return TRUE;
+    }
+}
+
+boolean gffOpen(struct gff *gff, char *fileName)
+/* Initialize gff structure and open file for it. */
+{
+    dnaUtilOpen();
+
+    /* Initialize structure and open file. */
+    zeroBytes(gff, sizeof(*gff));
+    gff->memPool = lmInit(16*1024);
+    gff->fileSize = fileSize(fileName);
+    if (gff->fileSize < 0 ||
+       (gff->file = fopen(fileName, "rb")) == NULL)
+	    {
+            warn("Couldn't find the file named %s\n", fileName);
+	    return FALSE;
+	    }
+    strcpy(gff->fileName, fileName);
+    gff->bufSize = ArraySize(gff->buf);
+
+    /* Make sure it's a gff file. */
+    _gffSeekDoubleSharpLine(gff);
+    if (strncmp(gff->buf, _gffIdent, strlen(_gffIdent)) != 0)
+	{
+	warn("%s doesn't appear to be a .gff file\n", fileName);
+	return FALSE;
+	}
+
+    return TRUE;
+}
+
+void gffClose(struct gff *gff)
+/* Close down gff structure. */
+{
+if (gff->file != NULL)
+    fclose(gff->file);
+freeMem(gff->dna);
+lmCleanup(&gff->memPool);
+zeroBytes(gff, sizeof(*gff));
+}
+
+#if 0 /* unused */
+static boolean _gffAtEof(struct gff *gff)
+/* Returns TRUE if at the end of gff file. */
+{
+return gff->file == NULL;
+}
+#endif	
+
+#if 0 /* unused */
+static char _getGffChar(struct gff *gff)
+/* Return next byte (not next base) in gff file. Return zero
+ * if at end of file. */
+{
+if (gff->readIx >= gff->bytesInBuf)
+	{
+	if (!_gffGetLine(gff)) return 0;
+	}
+return gff->buf[gff->readIx++];
+}
+#endif
+
+static boolean _gffSeekDna(struct gff *gff)
+/* Skip through file until you get the DNA */ 
+{
+static char dnaIdent[] = "##DNA";
+
+rewind(gff->file);
+for (;;)
+    {
+    if (!_gffGetLine(gff)) return FALSE;
+    if (strncmp(gff->buf, dnaIdent, strlen(dnaIdent)) == 0)
+	{
+	sscanf(gff->buf, "##DNA %s", gff->dnaName);
+	gff->bytesInBuf = 0; /* We're done with gff line. */
+	return TRUE;
+	}
+    }
+}
+
+static boolean gffNextDnaLine(struct gff *gff)
+/* Fetches next line of DNA. */
+{
+static char endIdent[] = "##end-DNA";
+
+if (!_gffSeekDoubleSharpLine(gff)) 
+    return FALSE;
+/* Check to see if have reached end of DNA sequence */
+if (strncmp(gff->buf, endIdent, strlen(endIdent))==0)
+    {
+    gff->bytesInBuf = 0; /* We're done with gff line. */
+    return FALSE;
+    }
+return TRUE;
+}
+
+boolean gffReadDna(struct gff *gff)
+/* Read all the DNA in a file. */
+{
+long dnaSize = 0;
+DNA *dna;
+DNA *line;
+int lineCount;
+DNA b;
+if (gff->dna != NULL)
+	return TRUE; /* We already read it. */
+if (!_gffSeekDna(gff))
+	return FALSE;
+if ((gff->dna = wantMem(gff->fileSize)) == NULL)
+    {
+    warn("Couldn't allocate %ld bytes for DNA\n",
+    	gff->fileSize);
+    return FALSE;
+    }
+dna = gff->dna;
+for (;;)
+    {
+    if (!gffNextDnaLine(gff))
+        break;
+    line = gff->buf + gff->readIx;
+    lineCount = gff->bytesInBuf-gff->readIx;
+    while (--lineCount >= 0)
+        {
+        b = *line++;
+        if ((b = ntChars[(int)b]) != 0)
+            {
+            *dna++ = b;
+            dnaSize += 1;
+            }
+        }
+    }
+gff->dnaSize = dnaSize;
+return TRUE;
+}
+
+struct gffGene *gffFindGene(struct gff *gff, char *geneName)
+/* Find gene with given name.  Case sensitive. */
+{
+struct gffGene *g;
+
+for (g=gff->genes; g!=NULL; g=g->next)
+    {
+    if (strcmp(geneName, g->name) == 0)
+	return g;
+    }
+return NULL;
+}
+
+struct gffGene *gffFindGeneIgnoreCase(struct gff *gff, char *geneName)
+/* Find gene with given name.  Not case sensitive. */
+{
+struct gffGene *g;
+
+for (g=gff->genes; g!=NULL; g=g->next)
+    {
+    if (differentWord(geneName, g->name) == 0)
+	return g;
+    }
+return NULL;
+}
+
+/* Allocate memory and clear it to zero.  Report error
+ * and kill program if can't allocate it. */
+static void *gffNeedMem(struct gff *gff, int size)
+{
+return lmAlloc(gff->memPool, size);
+}
+
+static void gffSegmentInsertSort(struct gffSegment **plist, 
+	struct gffSegment *seg)
+/* Insert segment on list, keeping list ordered by start field 
+   parameters:
+         gffSegment **plist;	 Pointer to list. 
+         gffSegment *seg;	 Segment to insert 
+ */
+{
+struct gffSegment *next;
+long segStart = seg->start;
+
+for (;;)
+    {
+    next = *plist;
+    if (next == NULL)
+	break;
+    if (next->start > segStart)
+	break;
+    plist = &(next->next);
+    }
+seg->next = next;   
+*plist = seg;
+}
+
+static void offsetsFromExons(struct gffGene *gene)
+/* Figure out start and end offsets of gene from it's exons. */
+{
+GffExon *exon;
+long end = 0;
+long start = 0x7fffffff; /* I should use a .h file constant here... */
+for (exon = gene->exons; exon != NULL; exon = exon->next)
+    {
+    if (exon->start < start)
+	start = exon->start;
+    if (exon->end > end)
+	end = exon->end;
+    }
+gene->start = start;
+gene->end = end;
+}
+
+void gffPrintInfo(struct gff *gff, FILE *out)
+/* Print summary info about file. */
+{
+struct gffGene *gene;
+
+fprintf(out, "\n%s\n", gff->fileName);
+fprintf(out, "DNA %s (%ld bases)\n", 
+	gff->dnaName, gff->dnaSize);
+fprintf(out, "%d genes\n", slCount(gff->genes));
+for (gene = gff->genes; gene != NULL; gene = gene->next)
+    {
+    fprintf(out, "gene %s has %ld bases, %d exons, %d introns\n",
+	gene->name, gene->end - gene->start + 1,
+	slCount(gene->exons), slCount(gene->introns));
+    }
+}
+
+static boolean checkWordCount(struct gff *gff, int wordCount)
+{
+if (wordCount >= 9)
+    return TRUE;
+else
+    {
+    warn("???%s???\n", gff->buf);
+    warn("Can't handle line %d of %s.\n", 
+	    gff->lineNumber, gff->fileName);
+    return FALSE;
+    }
+}
+
+boolean gffReadGenes(struct gff *gff)
+/* Read all the gene (as opposed to base) info in file. */
+{
+int wordCount;
+struct gffSegLine seg;
+char curGroup[128];
+struct gffGene *gene = NULL;
+GffIntron *intron = NULL;
+GffExon *exon = NULL;
+boolean warnedUnknown = FALSE;
+boolean isNewGene;
+
+curGroup[0] = 0; /* Start off with no group */
+
+/* Line scanning loop. */
+for (;;)
+    {
+    /* Get next line and parse it into segLine data structure. */
+    if (!_gffGetLine(gff)) 
+	break;	 /* End of file. */
+    if (gff->buf[0] == '#')
+	continue; /* Ignore sharp containing lines. */
+    wordCount = gffSegLineScan(gff, &seg);
+    if (wordCount < 9)
+	continue; /* Ignore blank lines and short ones. */
+
+    /* Make sure that start is less than or equal end. */
+    if (seg.start > seg.end)
+	{
+	warn("start greater than end line %d of %s.\n",
+		gff->lineNumber, gff->fileName);
+	return FALSE;
+	}
+
+    /* Get the gene we're working on.  First see if
+     * it's the same as last time around. */
+    isNewGene = FALSE;
+    if (strcmp(seg.group, curGroup) != 0)
+	{
+	strcpy(curGroup, seg.group);
+	if ((gene = gffFindGene(gff, seg.group)) == NULL)
+	    {
+	    /* It's a new gene! */
+	    if (!checkWordCount(gff, wordCount)) return FALSE;
+	    isNewGene = TRUE;
+	    gene = gffNeedMem(gff, sizeof(*gene));
+	    strcpy(gene->name, seg.group);
+	    slAddTail(&gff->genes, gene); 
+	    gene->strand = seg.strand[0];
+	    gene->frame = atoi(seg.frame);
+	    if (differentWord(seg.feature, "CDS") == 0)
+		{
+		gene->start = seg.start-1;
+		gene->end = seg.end-1;
+		}
+	    }
+	}
+
+    /* Look at what sort of feature it is, and decide what to do. */
+
+    if (differentWord(seg.feature, "CDS")==0)
+	{
+	/* CDS (coding segments) have been processed already
+	 * for the most part. Here just make sure they aren't
+	 * duplicated. */
+	if (!checkWordCount(gff, wordCount)) return FALSE;
+	if (!isNewGene)
+	    {
+	    if (gene->start != 0 || gene->end != 0)
+		{
+		warn("Warning duplicate CDS for %s\n",
+			seg.group);
+		warn("Line %d of %s\n", 
+			gff->lineNumber, gff->fileName);
+		}
+	    }
+	}
+    else if (differentWord(seg.feature, "SE") == 0 
+	||   differentWord(seg.feature, "IE") == 0
+	||   differentWord(seg.feature, "FE") == 0
+	||   differentWord(seg.feature, "E") == 0
+	||   differentWord(seg.feature, "exon") == 0)
+	{
+	/* It's some sort of exon.  We'll deal with the complications
+	 * of it being possibly on the minus strand later, so can
+	 * tread initial, final, single, and regular exons the same
+	 * here. */
+	if (!checkWordCount(gff, wordCount)) return FALSE;
+	exon = gffNeedMem(gff, sizeof(*exon));
+	exon->start = seg.start-1;
+	exon->end = seg.end-1;
+	exon->frame = atoi(seg.frame);
+	gffSegmentInsertSort(&gene->exons, exon);
+	}
+    else if (differentWord(seg.feature, "I") == 0 
+	||   differentWord(seg.feature, "intron") == 0)
+	{
+	/* It's an intron. */
+	if (!checkWordCount(gff, wordCount)) return FALSE;
+	intron = gffNeedMem(gff, sizeof(*intron));
+	intron->start = seg.start-1;
+	intron->end = seg.end-1;
+	intron->frame = atoi(seg.frame);
+	gffSegmentInsertSort(&gene->introns, intron);
+	}
+    else if (strcmp(seg.feature, "IG")  == 0)
+	{
+	/* I don't know what it is, but we can ignore it. */
+	}
+    else
+	{
+	if (!warnedUnknown)
+	    {
+	    warn("Unknown feature %s line %d of %s, ignoring\n",
+		    seg.feature,  gff->lineNumber, gff->fileName);
+	    warnedUnknown = TRUE;
+	    }
+	}
+    }
+
+/* Fix up gene length from exons if needed. */
+for (gene = gff->genes; gene != NULL; gene = gene->next)
+    {
+    if (gene->start >= gene->end)
+	{
+	offsetsFromExons(gene);
+	}
+    }
+return TRUE;
+}
+
+static boolean geneDna(struct gff *gff, struct gffGene *gene,
+    int leftExtra, int rightExtra, char **retDna, long *retDnaSize,
+    int *retStartOffset)
+/* Allocate an array and fill it with dna from a gene. */
+{
+char *dna;
+char *pt;
+long geneSize;
+long i;
+long seqStart, seqEnd, seqSize;
+
+/* Filter out unreasonable looking genes - input to this
+ * program isn't totally clean. */
+geneSize = gene->end - gene->start + 1;
+if (geneSize <= 0 || geneSize >= 1000000)
+    return FALSE;  
+
+/* Figure out extents of DNA we're going to return.
+ * Return extra they ask for if possible, but clip
+ * it to what is actually in GFF file. */
+seqStart = gene->start - leftExtra;
+seqEnd = gene->end + rightExtra + 1;
+if (seqStart < 0)
+    seqStart = 0;
+if (seqEnd > gff->dnaSize)
+    seqEnd = gff->dnaSize;
+seqSize = seqEnd - seqStart;
+
+/* Allocate memory and fetch the dna. */
+dna = needMem(seqSize+1);
+pt = dna;
+for (i=0; i<seqSize; i++)
+    *pt++ = gff->dna[seqStart+i];
+*pt = 0;
+
+/* Report results back to caller. */
+*retDna = dna;
+*retDnaSize = seqSize;
+*retStartOffset = (gene->start - seqStart);
+return TRUE;
+}
+
+static void fixDirectionAndOffsets(struct gffGene *gene, char *dna, long dnaSize, int newStart)
+/* Reverse complement DNA if gene is on negative strand.
+ * Update offsets of exons and introns in gene to 
+ * make them point into dna, rather than into gff->dna. 
+ */
+{
+long oldStart;
+long offset;
+GffIntron *intron;
+GffExon *exon;
+long temp;
+
+oldStart = gene->start;
+offset = oldStart - newStart;
+gene->start -= offset;
+gene->end -= offset;
+for (intron = gene->introns; intron != NULL; intron = intron->next)
+    {
+    intron->start -= offset;
+    intron->end -= offset;
+    }
+for (exon = gene->exons; exon != NULL; exon = exon->next)
+    {
+    exon->start -= offset;
+    exon->end -= offset;
+    }
+if (gene->strand == '-')
+    {
+    reverseComplement(dna, dnaSize);
+    temp = reverseOffset(gene->start, dnaSize);
+    gene->start = reverseOffset(gene->end, dnaSize);
+    gene->end = temp;
+    for (intron = gene->introns; intron != NULL; intron = intron->next)
+	{
+	temp = reverseOffset(intron->start, dnaSize);
+	intron->start = reverseOffset(intron->end, dnaSize);
+	intron->end = temp;
+	}
+    for (exon = gene->exons; exon != NULL; exon = exon->next)
+	{
+	temp = reverseOffset(exon->start, dnaSize);
+	exon->start = reverseOffset(exon->end, dnaSize);
+	exon->end = temp;
+	}
+    slReverse(&gene->introns);
+    slReverse(&gene->exons);
+    gene->strand = '+';
+    }
+}
+
+static struct gffSegment *dupeSegmentList(struct gffSegment *oldList,
+	struct gffSegment *newList)
+/* Duplicate a segment list into array of fresh memory. */
+{
+struct gffSegment *oldEl, *newEl;
+
+if (oldList == NULL)
+    return NULL;
+for (oldEl = oldList, newEl = newList; oldEl != NULL; oldEl=oldEl->next, newEl += 1)
+    {
+    memcpy(newEl, oldEl, sizeof(*newEl));
+    newEl->next = ((oldEl->next == NULL) ? NULL : newEl+1);
+    }
+return newList;
+}
+
+struct gffGene *gffDupeGeneAndSurrounds(struct gff *gff, struct gffGene *oldGene,
+    int leftExtra, int rightExtra)
+/* Make a duplicate of gene with extra DNA around coding region. 
+ * gffFreeGene it when done. */
+/* In a perhaps hair brained scheme to save some cycles,
+ * the memory allocation of the intron and exon lists
+ * is shared with that of the gffGene itself. */
+{
+struct gffGene *g;
+int intronCount = slCount(oldGene->introns);
+int exonCount = slCount(oldGene->exons);
+int memSize = sizeof(*g) + (intronCount + exonCount) * sizeof(struct gffSegment);
+char *memPt;
+int firstExonOffset;
+
+
+memPt = needMem(memSize);
+g = (struct gffGene *)memPt;
+memPt += sizeof(*g);
+g->exons = (struct gffSegment *)memPt;
+memPt += exonCount*sizeof(struct gffSegment);
+g->introns = (struct gffSegment *)memPt;
+
+g->next = NULL;
+g->start = oldGene->start;
+g->end = oldGene->end;
+g->strand = oldGene->strand;
+memcpy(g->name, oldGene->name, sizeof(g->name));
+g->exons = dupeSegmentList(oldGene->exons, g->exons);
+g->introns = dupeSegmentList(oldGene->introns, g->introns);
+if (!geneDna(gff, oldGene, leftExtra, rightExtra, 
+    &g->dna, &g->dnaSize, &firstExonOffset))
+    {
+    gffFreeGene(&g);
+    return NULL;
+    }
+fixDirectionAndOffsets(g, g->dna, g->dnaSize, firstExonOffset);
+return g;
+}
+
+struct gffGene *gffDupeGene(struct gff *gff, struct gffGene *oldGene)
+/* Make a duplicate of gene (with it's own DNA) */
+{
+return gffDupeGeneAndSurrounds(gff, oldGene, 0, 0);
+}
+
+struct gffGene *gffGeneWithOwnDna(struct gff *gff, char *geneName)
+/* Find gene with given name.  Case sensitive. */
+{
+struct gffGene *oldGene;
+
+oldGene = gffFindGeneIgnoreCase(gff, geneName);
+if (oldGene == NULL)
+    return NULL;
+return gffDupeGene(gff, oldGene);
+}
+
+void gffFreeGene(struct gffGene **pGene)
+/* Free a gene returned with dupeGene or geneWithOwnDna. 
+ * (You don't want to free the ones returned by findGene,
+ * they are still owned by the gff.)
+ */
+{
+struct gffGene *g = *pGene;
+if (g == NULL)
+    return;
+freeMem(g->dna);
+freeMem(g);
+*pGene = NULL;
+}
+
+struct dnaSeq *gffReadDnaSeq(char *fileName)
+/* Open gff file and read DNA sequence from it. */
+{
+struct gff gff;
+struct dnaSeq *seq = NULL;
+
+if (!gffOpen(&gff, fileName))
+    return NULL;
+if (gffReadDna(&gff))
+    {
+    seq = newDnaSeq(gff.dna, gff.dnaSize, gff.dnaName);
+    gff.dna = NULL;
+    }
+gffClose(&gff);
+return seq;
+}
+
+boolean gffOpenAndRead(struct gff *gff, char *fileName)
+/* Open up gff file and read everything in it. */
+{
+if (gffOpen(gff, fileName))
+    if (gffReadDna(gff))
+	if (gffReadGenes(gff))
+	    return TRUE;
+gffClose(gff);
+return FALSE;
+}
diff --git a/lib/oligoTm.c b/lib/oligoTm.c
new file mode 100644
index 0000000..5a550f8
--- /dev/null
+++ b/lib/oligoTm.c
@@ -0,0 +1,333 @@
+/* oligoTm - calculate melting temperature of relatively short DNA sequences.
+ * This is based on the nearest-neighbor thermodynamics of bases from Breslauer,
+ * Frank, Bloecker, and Markey, Proc. Natl. Acad. Sci. USA, vol 83, page 3748,
+ * and uses work from see Rychlik, Spencer, Roads, Nucleic Acids Research, vol 18, 
+ * no 21.  This code was imported from the oligotm module of Whitehead Institute's
+ * primer3 program, and adapted into UCSC conventions by Jim Kent.  Any redistribution
+ * of this code should contain the following copyright notice from Whitehead:
+ *
+ * Copyright (c) 1996,1997,1998,1999,2000,2001,2004
+ *         Whitehead Institute for Biomedical Research. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * 1.      Redistributions must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the  documentation
+ * and/or other materials provided with the distribution.  Redistributions of
+ * source code must also reproduce this information in the source code itself.
+ * 
+ * 2.      If the program is modified, redistributions must include a notice
+ * (in the same places as above) indicating that the redistributed program is
+ * not identical to the version distributed by Whitehead Institute.
+ * 
+ * 3.      All advertising materials mentioning features or use of this
+ * software  must display the following acknowledgment:
+ *         This product includes software developed by the
+ *         Whitehead Institute for Biomedical Research.
+ * 
+ * 4.      The name of the Whitehead Institute may not be used to endorse or
+ * promote products derived from this software without specific prior written
+ * permission.
+ * 
+ * We also request that use of this software be cited in publications as 
+ * 
+ *   Rozen, S., Skaletsky, H.  \"Primer3 on the WWW for general users
+ *   and for biologist programmers.\"  In S. Krawetz and S. Misener, eds.
+ *   Bioinformatics Methods and Protocols in the series Methods in 
+ *   Molecular Biology.  Humana Press, Totowa, NJ, 2000, pages 365-386.
+ *   Code available at
+ *   http://fokker.wi.mit.edu/primer3/.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE WHITEHEAD INSTITUTE ``AS IS'' AND  ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE WHITEHEAD INSTITUTE BE LIABLE  FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+
+
+
+#include "common.h"
+#include "oligoTm.h"
+
+
+/* 
+ * Tables of nearest-neighbor thermodynamics for DNA bases.  See Breslauer,
+ * Frank, Bloecker, and Markey, Proc. Natl. Acad. Sci. USA, vol 83, page 3748,
+ * table 2.
+ */
+#define S_A_A 240
+#define S_A_C 173
+#define S_A_G 208
+#define S_A_T 239
+#define S_A_N 215
+  
+#define S_C_A 129
+#define S_C_C 266
+#define S_C_G 278
+#define S_C_T 208
+#define S_C_N 220  
+  
+#define S_G_A 135
+#define S_G_C 267
+#define S_G_G 266
+#define S_G_T 173
+#define S_G_N 210
+  
+#define S_T_A 169
+#define S_T_C 135
+#define S_T_G 129
+#define S_T_T 240
+#define S_T_N 168
+  
+#define S_N_A 168
+#define S_N_C 210
+#define S_N_G 220
+#define S_N_T 215
+#define S_N_N 203
+
+
+#define H_A_A  91
+#define H_A_C  65
+#define H_A_G  78
+#define H_A_T  86
+#define H_A_N  80
+
+#define H_C_A  58
+#define H_C_C 110
+#define H_C_G 119
+#define H_C_T  78
+#define H_C_N  91
+
+#define H_G_A  56
+#define H_G_C 111
+#define H_G_G 110
+#define H_G_T  65
+#define H_G_N  85
+
+#define H_T_A  60
+#define H_T_C  56
+#define H_T_G  58
+#define H_T_T  91
+#define H_T_N  66
+
+#define H_N_A  66
+#define H_N_C  85
+#define H_N_G  91
+#define H_N_T  80
+#define H_N_N  80
+
+/* Delta G's of disruption * 1000. */
+#define G_A_A  1900
+#define G_A_C  1300
+#define G_A_G  1600
+#define G_A_T  1500
+#define G_A_N  1575
+
+#define G_C_A  1900 
+#define G_C_C  3100
+#define G_C_G  3600
+#define G_C_T  1600
+#define G_C_N  2550
+
+#define G_G_A  1600
+#define G_G_C  3100
+#define G_G_G  3100
+#define G_G_T  1300
+#define G_G_N  2275
+
+#define G_T_A   900
+#define G_T_C  1600
+#define G_T_G  1900
+#define G_T_T  1900
+#define G_T_N  1575
+
+#define G_N_A  1575
+#define G_N_C  2275
+#define G_N_G  2550
+#define G_N_T  1575
+#define G_N_N  1994
+
+#define A_CHAR 'A'
+#define G_CHAR 'G'
+#define T_CHAR 'T'
+#define C_CHAR 'C'
+#define N_CHAR 'N'
+
+#define CATID5(A,B,C,D,E) A##B##C##D##E
+#define CATID2(A,B) A##B
+#define DO_PAIR(LAST,THIS)          \
+  if (CATID2(THIS,_CHAR) == c) {    \
+     dh += CATID5(H,_,LAST,_,THIS); \
+     ds += CATID5(S,_,LAST,_,THIS); \
+     goto CATID2(THIS,_STATE);      \
+  }
+
+#define STATE(LAST)     \
+   CATID2(LAST,_STATE): \
+   c = *s; s++;         \
+   DO_PAIR(LAST,A)      \
+   else DO_PAIR(LAST,T) \
+   else DO_PAIR(LAST,G) \
+   else DO_PAIR(LAST,C) \
+   else DO_PAIR(LAST,N) \
+   else if ('\0' == c)  \
+             goto DONE; \
+   else goto ERROR \
+
+double oligoTm(char *dna, double DNA_nM, double K_mM)
+/* Calculate melting point of short DNA sequence given DNA concentration in 
+ * nanomoles, and salt concentration in millimoles.  This is calculated using eqn
+ * (ii) in Rychlik, Spencer, Roads, Nucleic Acids Research, vol 18, no 21, page
+ * 6410, with tables of nearest-neighbor thermodynamics for DNA bases as
+ * provided in Breslauer, Frank, Bloecker, and Markey,
+ * Proc. Natl. Acad. Sci. USA, vol 83, page 3748. */
+{
+    register int dh = 0, ds = 108;
+    register char c;
+    char *dupe = cloneString(dna);
+    char *s = dupe;
+    double delta_H, delta_S;
+
+    touppers(s);
+    /* Use a finite-state machine (DFA) to calucluate dh and ds for s. */
+    c = *s; s++;
+    if (c == 'A') goto A_STATE;
+    else if (c == 'G') goto G_STATE;
+    else if (c == 'T') goto T_STATE;
+    else if (c == 'C') goto C_STATE;
+    else if (c == 'N') goto N_STATE;
+    else goto ERROR;
+    STATE(A);
+    STATE(T);
+    STATE(G);
+    STATE(C);
+    STATE(N);
+
+    DONE:  /* dh and ds are now computed for the given sequence. */
+    delta_H = dh * -100.0;  /* 
+			     * Nearest-neighbor thermodynamic values for dh
+			     * are given in 100 cal/mol of interaction.
+			     */
+    delta_S = ds * -0.1;     /*
+			      * Nearest-neighbor thermodynamic values for ds
+			      * are in in .1 cal/K per mol of interaction.
+			      */
+
+    /* 
+     * See Rychlik, Spencer, Roads, Nucleic Acids Research, vol 18, no 21,
+     * page 6410, eqn (ii).
+     */
+    freeMem(dupe);
+    return delta_H / (delta_S + 1.987 * log(DNA_nM/4000000000.0))
+	- 273.15 + 16.6 * log10(K_mM/1000.0);
+
+    ERROR:  /* 
+	  * length of s was less than 2 or there was an illegal character in
+	  * s.
+	  */
+    freeMem(dupe);
+    errAbort("Not a valid oligo in oligoTm.");
+    return 0;
+}
+#undef DO_PAIR
+
+#define DO_PAIR(LAST,THIS)          \
+  if (CATID2(THIS,_CHAR) == c) {    \
+     dg += CATID5(G,_,LAST,_,THIS); \
+     goto CATID2(THIS,_STATE);      \
+  }
+
+double oligoDg(char *dna)
+/* Calculate dg (change in Gibb's free energy) from melting oligo
+ * the nearest neighbor model. Seq should be relatively short, given 
+ * the characteristics of the nearest neighbor model (36 bases or less
+ * is best). */
+{
+    register int dg = 0;
+    register char c;
+    char *dupe = cloneString(dna);
+    char *s = dupe;
+
+    /* Use a finite-state machine (DFA) to calculate dg s. */
+    c = *s; s++;
+    if (c == 'A') goto A_STATE;
+    else if (c == 'G') goto G_STATE;
+    else if (c == 'T') goto T_STATE;
+    else if (c == 'C') goto C_STATE;
+    else if (c == 'N') goto N_STATE;
+    else goto ERROR;
+    STATE(A);
+    STATE(T);
+    STATE(G);
+    STATE(C);
+    STATE(N);
+
+    DONE:  /* dg is now computed for the given sequence. */
+    freeMem(dupe);
+    return dg / 1000.0;
+
+    ERROR:
+    freeMem(dupe);
+    errAbort("Not a valid oligo in oligoDg.");
+    return 0;
+}
+
+
+double longSeqTm(char *s, int start, int len, double salt_conc)
+/* Calculate the melting temperature of substr(seq, start, length) using the
+ * formula from Bolton and McCarthy, PNAS 84:1390 (1962) as presented in
+ * Sambrook, Fritsch and Maniatis, Molecular Cloning, p 11.46 (1989, CSHL
+ * Press).
+ *
+ * Tm = 81.5 + 16.6(log10([Na+])) + .41*(%GC) - 600/length
+ *
+ * Where [Na+] is the molar sodium concentration, (%GC) is the percent of Gs
+ * and Cs in the sequence, and length is the length of the sequence.
+ *
+ * A similar formula is used by the prime primer selection program in GCG
+ * (http://www.gcg.com), which instead uses 675.0 / length in the last term
+ * (after F. Baldino, Jr, M.-F. Chesselet, and M.E.  Lewis, Methods in
+ * Enzymology 168:766 (1989) eqn (1) on page 766 without the mismatch and
+ * formamide terms).  The formulas here and in Baldino et al. assume Na+ rather
+ * than K+.  According to J.G. Wetmur, Critical Reviews in BioChem. and
+ * Mol. Bio. 26:227 (1991) 50 mM K+ should be equivalent in these formulae to .2
+ * M Na+.
+ *
+ * This function takes salt_conc to be the millimolar (mM) concentration,
+ * since mM is the usual units in PCR applications.  */
+{
+  int GC_count = 0;
+  char *p, *end;
+
+  if(start + len > strlen(s) || start < 0 || len <= 0) 
+	errAbort("bad input to longSeqTm");
+  end = &s[start + len];
+  /* Length <= 0 is nonsensical. */
+  for (p = &s[start]; p < end; p++) {
+    if ('G' == *p || 'g' == *p || 'C' == *p || 'c' == *p)
+      GC_count++;
+  }
+
+  return
+    81.5
+    + (16.6 * log10(salt_conc / 1000.0))
+    + (41.0 * (((double) GC_count) / len))
+    - (600.0 / len);
+
+}
+
+double seqTm(char *seq, double dna_conc, double salt_conc)
+/* Figure out melting temperature of sequence of any length given
+ * dna and salt concentration. */
+{
+  int len = strlen(seq);
+  return (len > 36)
+    ? longSeqTm(seq, 0, len, salt_conc) : oligoTm(seq, dna_conc, salt_conc);
+}
diff --git a/lib/options.c b/lib/options.c
new file mode 100644
index 0000000..9cc4981
--- /dev/null
+++ b/lib/options.c
@@ -0,0 +1,423 @@
+/* Options.c - stuff to handle command line options.
+ * This is smaller and more flexible than the cgiSpoof
+ * routines we used to use - though cgiSpoof is still the
+ * method of choice for actual CGI routines that want to
+ * be tested from the command line. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "hash.h"
+#include "verbose.h"
+#include "options.h"
+#include <limits.h>
+
+
+#ifdef MACHTYPE_alpha
+    #define strtoll strtol
+#endif
+
+static struct optionSpec commonOptions[] = {
+   {"verbose", OPTION_INT},
+   {NULL, 0},
+};
+
+static struct optionSpec *matchingOption(char *name, struct optionSpec *optionSpecs)
+/* Go through spec table and return spec that matches name, or NULL
+ * if none. */
+{
+while (optionSpecs->name != NULL)
+    {
+    if (sameString(optionSpecs->name, name))
+        return optionSpecs;
+    optionSpecs += 1;
+    }
+return NULL;
+}
+
+static void validateOption(char *name, char *val, struct optionSpec *optionSpecs)
+/* validate an option against a list of values */
+{
+char *valEnd;
+struct optionSpec *optionSpec = matchingOption(name, optionSpecs);
+if (optionSpec == NULL)
+    optionSpec = matchingOption(name, commonOptions);
+if (optionSpec == NULL)
+    errAbort("-%s is not a valid option", name);
+
+long long discardMe = 0;
+switch (optionSpec->flags & OPTION_TYPE_MASK) {
+case OPTION_BOOLEAN:
+    if (val != NULL)
+        errAbort("boolean option -%s must not have value", name);
+    break;
+case OPTION_STRING:
+    if (val == NULL)
+        errAbort("string option -%s must have a value", name);
+    break;
+case OPTION_INT:
+    if (val == NULL)
+        errAbort("int option -%s must have a value", name);
+    discardMe = strtol(val, &valEnd, 10);
+    if ((*val == '\0') || (*valEnd != '\0'))
+        errAbort("value of -%s is not a valid integer: \"%s\"",
+                 name, val);
+    break;
+case OPTION_LONG_LONG:
+    if (val == NULL)
+        errAbort("int option -%s must have a value", name);
+    discardMe = strtoll(val, &valEnd, 10);
+    if ((*val == '\0') || (*valEnd != '\0'))
+        errAbort("value of -%s is not a valid long long: \"%s\"",
+                 name, val);
+    break;
+case OPTION_FLOAT:
+    if (val == NULL)
+        errAbort("float option -%s must have a value", name);
+    discardMe = (long long)strtod(val, &valEnd);
+    if ((*val == '\0') || (*valEnd != '\0'))
+        errAbort("value of -%s is not a valid float: \"%s\"",
+                 name, val);
+    break;
+case OPTION_DOUBLE:
+    if (val == NULL)
+        errAbort("double option -%s must have a value", name);
+    discardMe = (long long)strtod(val, &valEnd);
+    if ((*val == '\0') || (*valEnd != '\0'))
+        errAbort("value of -%s is not a valid double: \"%s\"",
+                 name, val);
+    break;
+default:
+    errAbort("bug: invalid type in optionSpec for %s", optionSpec->name);
+}
+}
+
+static void parseMultiOption(struct hash *hash, char *name, char* val, struct optionSpec *spec)
+/* process multiple instances of an option, requres that the optionSpec of the option */
+{
+struct slName *valList;
+switch (spec->flags & OPTION_TYPE_MASK)
+    {
+    case OPTION_STRING:
+        valList = hashFindVal(hash, name);
+        if (valList == NULL)   /* first multi option */
+            {
+            valList = newSlName(val);
+            hashAdd(hash, name, valList);
+            }
+        else
+            {
+            struct slName *el = newSlName(val);
+            slAddTail(valList, el); /* added next multi option */
+            }
+        break;
+    default:
+        errAbort("UNIMPLEMENTED: multiple instances of a non-string option is not currently implemented");
+    }
+}
+
+static boolean parseAnOption(struct hash *hash, char *arg, struct optionSpec *optionSpecs)
+/* Parse a single option argument and add to the hash, validating if
+ * optionSpecs is not NULL.  Return TRUE if it's arg is an option argument
+ * FALSE if it's not.
+ */
+{
+char *name, *val;
+char *eqPtr = strchr(arg, '=');
+
+if (!((eqPtr != NULL) || (arg[0] == '-')))
+    return FALSE;  /* not an option */
+
+/* A dash by itself is not an option.   It can mean
+ * negative strand for some of the DNA oriented utilities. */
+if (arg[0] == '-' && (arg[1] == 0 || isspace(arg[1])))
+    return FALSE;
+
+/* We treat this=that as an option only if the '=' happens before any non-alphanumeric
+ * characters.  This lets us have URLs and SQL statements in the command line even though
+ * they can have equals in them. */
+if (eqPtr != NULL)
+    {
+    char *s, c;
+    for (s=arg; s < eqPtr; ++s)
+        {
+	c = *s;
+	if (c != '_' && c != '-' && !isalnum(c))
+	    return FALSE;
+	}
+    }
+
+name = arg;
+if (name[0] == '-')
+    name++;
+if (eqPtr != NULL)
+    {
+    *eqPtr = '\0';
+    val = eqPtr+1;
+    }
+else
+    val = NULL;
+
+if (optionSpecs != NULL)
+    validateOption(name, val, optionSpecs);
+if (val == NULL)
+    val = "on";
+if (optionSpecs == NULL)
+    hashAdd(hash, name, val);
+else
+    {
+    struct optionSpec *spec = matchingOption(name, optionSpecs);
+    if (spec != NULL && (spec->flags & OPTION_MULTI))    /* process multiple instances of option */
+        parseMultiOption(hash, name, val, spec);
+    else
+        hashAdd(hash, name, val);
+    }
+
+if (eqPtr != NULL)
+    *eqPtr = '=';
+return TRUE;
+}
+
+
+static struct hash *parseOptions(int *pArgc, char *argv[], boolean justFirst,
+                                 struct optionSpec *optionSpecs)
+/* Parse and optionally validate options */
+{
+int i, origArgc, newArgc = 1;
+char **rdPt = argv+1, **wrPt = argv+1;
+struct hash *hash = newHash(6);
+
+origArgc = *pArgc;
+
+/* parse arguments */
+for (i=1; i<origArgc; ++i)
+    {
+    if (sameString(*rdPt, "--"))
+        {
+        rdPt++;
+        i++;
+        break;
+        }
+    if (!parseAnOption(hash, *rdPt, optionSpecs))
+        {
+        /* not an option */
+        if (justFirst)
+            break;
+        *wrPt++ = *rdPt;
+        newArgc++;
+        }
+    rdPt++;
+    }
+
+/* copy any remaining positional args */
+for (; i<origArgc; ++i)
+    {
+    *wrPt++ = *rdPt++;
+    newArgc++;
+    }
+
+*pArgc = newArgc;
+*wrPt = NULL; 
+return hash;
+}
+
+struct hash *optionParseIntoHash(int *pArgc, char *argv[], boolean justFirst)
+/* Read options in command line (only up to first real argument) into
+ * options hash.   Options come in three forms:
+ *      -option         words starting with dash
+ *      option=val      words with = in the middle
+ *      -option=val     combining the two.
+ * The resulting hash will be keyed by the option name with the val
+ * string for value.  For '-option' types the value is 'on'. */
+{
+return parseOptions(pArgc, argv, justFirst, NULL);
+}
+
+static struct hash *options = NULL;
+static struct optionSpec *optionSpecification = NULL;
+
+static void setOptions(struct hash *hash)
+/* Set global options hash to hash, and also do processing
+ * of log file and other common options. */
+{
+options = hash;
+if (optionExists("verbose"))
+    verboseSetLevel(optionInt("verbose", 0));
+}
+
+void optionHashSome(int *pArgc, char *argv[], boolean justFirst)
+/* Set up option hash from command line, optionally only adding
+ * up to first non-optional word. */
+{
+if (options == NULL)
+    {
+    struct hash *hash = parseOptions(pArgc, argv, justFirst, NULL);
+    setOptions(hash);
+    }
+}
+
+void optionHash(int *pArgc, char *argv[])
+/* Read options in command line into options hash.   
+ * Options come in three forms:
+ *      -option         words starting with dash
+ *      option=val      words with = in the middle
+ *      -option=val     combining the two.
+ * The resulting hash will be keyed by the option name with the val
+ * string for value.  For '-option' types the value is 'on'. */
+{
+optionHashSome(pArgc, argv, FALSE);
+}
+
+void optionFree()
+/* free the option hash */
+{
+freeHash(&options);
+}
+
+void optionInit(int *pArgc, char *argv[], struct optionSpec *optionSpecs)
+/* Read options in command line into options hash.
+ * Options come in three forms:
+ *      -option         words starting with dash
+ *      option=val      words with = in the middle
+ *      -option=val     combining the two.
+ * The resulting hash will be keyed by the option name with the val
+ * string for value.  For '-option' types the value is 'on'.
+ * The words in argv are parsed in assending order.  If a word of
+ * "--" is encountered, argument parsing stops.
+ * If optionSpecs is not NULL, it is an array of optionSpec that are
+ * used to validate the options.  An option must exist in the array
+ * and the value must be convertable to the type specified in flags.
+ * Boolean options must no value, all other options must have one.
+ * Array is terminated by a optionSpec with a NULL name.
+ * If array NULL, no validation is done.
+ */
+{
+if (options == NULL)
+    {
+    struct hash *hash = parseOptions(pArgc, argv, FALSE, optionSpecs);
+    setOptions(hash);
+    optionSpecification = optionSpecs;
+    }
+}
+
+static char *optGet(char *name)
+/* Lookup option name.  Complain if options hash not set. */
+{
+if (options == NULL)
+    errAbort("optGet called before optionHash");
+return hashFindVal(options, name);
+}
+ 
+char *optionVal(char *name, char *defaultVal)
+/* Return named option if in options hash, otherwise default. */
+{
+char *ret;
+/* if a optionSpec was used, make sure this option is not a multi option */
+if(optionSpecification != NULL) 
+    {
+    struct optionSpec *spec = matchingOption(name, optionSpecification);
+    if(spec != NULL && (spec->flags & OPTION_MULTI))    
+        errAbort("ERROR: optionVal cannot be used to get the value of an OPTION_MULTI");
+    }
+
+ret = optGet(name);
+if (ret == NULL)
+     ret = defaultVal;
+return ret;
+}
+
+int optionInt(char *name, int defaultVal)
+/* Return integer value of named option, or default value
+ * if not set. */
+{
+char *s = optGet(name);
+char *valEnd;
+long lval;
+if (s == NULL)
+    return defaultVal;
+if (sameString(s,"on"))
+    return defaultVal;
+lval = strtol(s, &valEnd, 10);  // use strtol since strtoi does not exist
+if ((*s == '\0') || (*valEnd != '\0'))
+    errAbort("value of -%s is not a valid integer: \"%s\"", name, s);
+if (lval > INT_MAX)
+    errAbort("value of -%s is is too large: %ld, integer maximum is %d", name, lval, INT_MAX);
+if (lval < INT_MIN)
+    errAbort("value of -%s is is too small: %ld, integer minimum is %d", name, lval, INT_MIN);
+return lval;
+}
+
+long long optionLongLong(char *name, long long defaultVal)
+/* Return long long value of named option, or default value
+ * if not set. */
+{
+char *s = optGet(name);
+char *valEnd;
+long long val;
+if (s == NULL)
+    return defaultVal;
+if (sameString(s,"on"))
+    return defaultVal;
+val = strtoll(s, &valEnd, 10);
+if ((*s == '\0') || (*valEnd != '\0'))
+    errAbort("value of -%s is not a valid long long: \"%s\"", name, s);
+return val;
+}
+
+float optionFloat(char *name, float defaultVal)
+/* Return floating point value or default value if not set. */
+{
+char *s = optGet(name);
+char *valEnd;
+float val;
+if (s == NULL)
+    return defaultVal;
+
+val = strtod(s, &valEnd);
+if ((*s == '\0') || (*valEnd != '\0'))
+    errAbort("value of -%s is not a valid float: \"%s\"", name, s);
+return val;
+}
+
+struct slName *optionMultiVal(char *name, struct slName *defaultVal)
+/* Return named option if in options hash, otherwise default. */
+{
+struct slName *ret;
+if(optionSpecification == NULL)
+    errAbort("ERROR: optionMultiVal can only be used after optionInit is called "
+             "with a non-NULL optionSpecs");
+
+ret = hashFindVal(options, name);
+if (ret == NULL)
+     ret = defaultVal;
+return ret;
+}
+
+double optionDouble(char *name, double defaultVal)
+/* Return double value or default value if not set */
+{
+char *s = optGet(name);
+char *valEnd;
+double val;
+if (s == NULL)
+    return defaultVal;
+
+val = strtod(s, &valEnd);
+if ((*s == '\0') || (*valEnd != '\0'))
+    errAbort("value of -%s is not a valid double: \"%s\"", name, s);
+return val;
+}
+
+boolean optionExists(char *name)
+/* Return TRUE if option has been set. */
+{
+return optGet(name) != NULL;
+}
+
+void optionMustExist(char *name)
+/* Abort if option has not been set. */
+{
+if (optGet(name) == NULL)
+    errAbort("Missing required command line flag %s", name);
+}
diff --git a/lib/osunix.c b/lib/osunix.c
new file mode 100644
index 0000000..a5a4945
--- /dev/null
+++ b/lib/osunix.c
@@ -0,0 +1,641 @@
+/* Some wrappers around operating-system specific stuff. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include <dirent.h>
+#include <sys/utsname.h>
+#include <sys/time.h>
+#include <pwd.h>
+#include <termios.h>
+#include "portable.h"
+#include "portimpl.h"
+#include <sys/wait.h>
+#include <regex.h>
+#include <utime.h>
+
+
+
+
+off_t fileSize(char *pathname)
+/* get file size for pathname. return -1 if not found */
+{
+struct stat mystat;
+ZeroVar(&mystat);
+if (stat(pathname,&mystat)==-1)
+    {
+    return -1;
+    }
+return mystat.st_size;
+}
+
+
+long clock1000()
+/* A millisecond clock. */
+{
+struct timeval tv;
+static long origSec;
+gettimeofday(&tv, NULL);
+if (origSec == 0)
+    origSec = tv.tv_sec;
+return (tv.tv_sec-origSec)*1000 + tv.tv_usec / 1000;
+}
+
+void sleep1000(int milli)
+/* Sleep for given number of 1000ths of second */
+{
+if (milli > 0)
+    {
+    struct timeval tv;
+    tv.tv_sec = milli/1000;
+    tv.tv_usec = (milli%1000)*1000;
+    select(0, NULL, NULL, NULL, &tv);
+    }
+}
+
+long clock1()
+/* A seconds clock. */
+{
+struct timeval tv;
+gettimeofday(&tv, NULL);
+return tv.tv_sec;
+}
+
+void uglyfBreak()
+/* Go into debugger. */
+{
+static char *nullPt = NULL;
+nullPt[0] = 0;
+}
+
+char *getCurrentDir()
+/* Return current directory.  Abort if it fails. */
+{
+static char dir[PATH_LEN];
+
+if (getcwd( dir, sizeof(dir) ) == NULL )
+    errnoAbort("getCurrentDir: can't get current directory");
+return dir;
+}
+
+void setCurrentDir(char *newDir)
+/* Set current directory.  Abort if it fails. */
+{
+if (chdir(newDir) != 0)
+    errnoAbort("setCurrentDir: can't to set current directory: %s", newDir);
+}
+
+boolean maybeSetCurrentDir(char *newDir)
+/* Change directory, return FALSE (and set errno) if fail. */
+{
+return chdir(newDir) == 0;
+}
+
+struct slName *listDir(char *dir, char *pattern)
+/* Return an alphabetized list of all files that match 
+ * the wildcard pattern in directory. */
+{
+struct slName *list = NULL, *name;
+struct dirent *de;
+DIR *d;
+
+if ((d = opendir(dir)) == NULL)
+    return NULL;
+while ((de = readdir(d)) != NULL)
+    {
+    char *fileName = de->d_name;
+    if (differentString(fileName, ".") && differentString(fileName, ".."))
+	{
+	if (pattern == NULL || wildMatch(pattern, fileName))
+	    {
+	    name = newSlName(fileName);
+	    slAddHead(&list, name);
+	    }
+	}
+    }
+closedir(d);
+slNameSort(&list);
+return list;
+}
+
+struct slName *listDirRegEx(char *dir, char *regEx, int flags)
+/* Return an alphabetized list of all files that match 
+ * the regular expression pattern in directory.
+ * See REGCOMP(3) for flags (e.g. REG_ICASE)  */
+{
+struct slName *list = NULL, *name;
+struct dirent *de;
+DIR *d;
+regex_t re;
+int err = regcomp(&re, regEx, flags | REG_NOSUB);
+if(err)
+    errAbort("regcomp failed; err: %d", err);
+
+if ((d = opendir(dir)) == NULL)
+    return NULL;
+while ((de = readdir(d)) != NULL)
+    {
+    char *fileName = de->d_name;
+    if (differentString(fileName, ".") && differentString(fileName, ".."))
+	{
+	if (!regexec(&re, fileName, 0, NULL, 0))
+	    {
+	    name = newSlName(fileName);
+	    slAddHead(&list, name);
+	    }
+	}
+    }
+closedir(d);
+regfree(&re);
+slNameSort(&list);
+return list;
+}
+
+struct fileInfo *newFileInfo(char *name, off_t size, bool isDir, int statErrno, 
+	time_t lastAccess)
+/* Return a new fileInfo. */
+{
+int len = strlen(name);
+struct fileInfo *fi = needMem(sizeof(*fi) + len);
+fi->size = size;
+fi->isDir = isDir;
+fi->statErrno = statErrno;
+fi->lastAccess = lastAccess;
+strcpy(fi->name, name);
+return fi;
+}
+
+int cmpFileInfo(const void *va, const void *vb)
+/* Compare two fileInfo. */
+{
+const struct fileInfo *a = *((struct fileInfo **)va);
+const struct fileInfo *b = *((struct fileInfo **)vb);
+return strcmp(a->name, b->name);
+}
+
+boolean makeDir(char *dirName)
+/* Make dir.  Returns TRUE on success.  Returns FALSE
+ * if failed because directory exists.  Prints error
+ * message and aborts on other error. */
+{
+int err;
+if ((err = mkdir(dirName, 0777)) < 0)
+    {
+    if (errno != EEXIST)
+	{
+	perror("");
+	errAbort("Couldn't make directory %s", dirName);
+	}
+    return FALSE;
+    }
+return TRUE;
+}
+
+
+struct fileInfo *listDirXExt(char *dir, char *pattern, boolean fullPath, boolean ignoreStatFailures)
+/* Return list of files matching wildcard pattern with
+ * extra info. If full path is true then the path will be
+ * included in the name of each file. */
+{
+struct fileInfo *list = NULL, *el;
+struct dirent *de;
+DIR *d;
+int dirNameSize = strlen(dir);
+int fileNameOffset = dirNameSize+1;
+char pathName[512];
+
+if ((d = opendir(dir)) == NULL)
+    return NULL;
+memcpy(pathName, dir, dirNameSize);
+pathName[dirNameSize] = '/';
+
+while ((de = readdir(d)) != NULL)
+    {
+    char *fileName = de->d_name;
+    if (differentString(fileName, ".") && differentString(fileName, ".."))
+	{
+	if (pattern == NULL || wildMatch(pattern, fileName))
+	    {
+	    struct stat st;
+	    bool isDir = FALSE;
+	    int statErrno = 0;
+	    strcpy(pathName+fileNameOffset, fileName);
+	    if (stat(pathName, &st) < 0)
+		{
+		if (ignoreStatFailures)
+		    statErrno = errno;
+		else
+    		    errAbort("stat failed in listDirX");
+		}
+	    if (S_ISDIR(st.st_mode))
+		isDir = TRUE;
+	    if (fullPath)
+		fileName = pathName;
+	    el = newFileInfo(fileName, st.st_size, isDir, statErrno, st.st_atime);
+	    slAddHead(&list, el);
+	    }
+	}
+    }
+closedir(d);
+slSort(&list, cmpFileInfo);
+return list;
+}
+
+struct fileInfo *listDirX(char *dir, char *pattern, boolean fullPath)
+/* Return list of files matching wildcard pattern with
+ * extra info. If full path is true then the path will be
+ * included in the name of each file. */
+{
+return listDirXExt(dir, pattern, fullPath, FALSE);
+}
+
+time_t fileModTime(char *pathName)
+/* Return file last modification time.  The units of
+ * these may vary from OS to OS, but you can depend on
+ * later files having a larger time. */
+{
+struct stat st;
+if (stat(pathName, &st) < 0)
+    errAbort("stat failed in fileModTime: %s", pathName);
+return st.st_mtime;
+}
+
+
+char *getHost()
+/* Return host name. */
+{
+static char *hostName = NULL;
+static char buf[128];
+if (hostName == NULL)
+    {
+    hostName = getenv("HTTP_HOST");
+    if (hostName == NULL)
+        {
+	hostName = getenv("HOST");
+	if (hostName == NULL)
+	    {
+	    if (hostName == NULL)
+		{
+		static struct utsname unamebuf;
+		if (uname(&unamebuf) >= 0)
+		    hostName = unamebuf.nodename;
+		else
+		    hostName = "unknown";
+		}
+	    }
+        }
+    strncpy(buf, hostName, sizeof(buf));
+    chopSuffix(buf);
+    hostName = buf;
+    }
+return hostName;
+}
+
+char *mysqlHost()
+/* Return host computer on network for mySQL database. */
+{
+boolean gotIt = FALSE;
+static char *host = NULL;
+if (!gotIt)
+    {
+    static char hostBuf[128];
+    gotIt = TRUE;
+    if (fileExists("mysqlHost"))
+	{
+	return (host = firstWordInFile("mysqlHost", hostBuf, sizeof(hostBuf)));
+	}
+    else
+	return (host = getenv("MYSQLHOST"));
+    }
+return host;
+}
+
+char *semiUniqName(char *base)
+/* Figure out a name likely to be unique.
+ * Name will have no periods.  Returns a static
+ * buffer, so best to clone result unless using
+ * immediately. */
+{
+int pid = getpid();
+int num = time(NULL)&0xFFFFF;
+char host[512];
+strcpy(host, getHost());
+char *s = strchr(host, '.');
+if (s != NULL)
+     *s = 0;
+subChar(host, '-', '_');
+subChar(host, ':', '_');
+static char name[PATH_LEN];
+safef(name, sizeof(name), "%s_%s_%x_%x",
+	base, host, pid, num);
+return name;
+}
+
+char *rTempName(char *dir, char *base, char *suffix)
+/* Make a temp name that's almost certainly unique. */
+{
+char *x;
+static char fileName[PATH_LEN];
+int i;
+for (i=0;;++i)
+    {
+    x = semiUniqName(base);
+    safef(fileName, sizeof(fileName), "%s/%s%d%s",
+    	dir, x, i, suffix);
+    if (!fileExists(fileName))
+        break;
+    }
+return fileName;
+}
+
+static void eatSlashSlashInPath(char *path)
+/* Convert multiple // to single // */
+{
+char *s, *d;
+s = d = path;
+char c, lastC = 0;
+while ((c = *s++) != 0)
+    {
+    if (c == '/' && lastC == c)
+        continue;
+    *d++ = c;
+    lastC = c;
+    }
+*d = 0;
+}
+
+static void eatExcessDotDotInPath(char *path)
+/* If there's a /.. in path take it out.  Turns 
+ *      'this/long/../dir/file' to 'this/dir/file
+ * and
+ *      'this/../file' to 'file'  
+ *
+ * and
+ *      'this/long/..' to 'this'
+ * and
+ *      'this/..' to  ''   
+ * and
+ *       /this/..' to '/' */
+{
+/* Take out each /../ individually */
+for (;;)
+    {
+    /* Find first bit that needs to be taken out. */
+    char *excess= strstr(path, "/../");
+    char *excessEnd = excess+4;
+    if (excess == NULL || excess == path)
+        break;
+
+    /* Look for a '/' before this */
+    char *excessStart = matchingCharBeforeInLimits(path, excess, '/');
+    if (excessStart == NULL) /* Preceding '/' not found */
+         excessStart = path;
+    else 
+         excessStart += 1;
+    strcpy(excessStart, excessEnd);
+    }
+
+/* Take out final /.. if any */
+if (endsWith(path, "/.."))
+    {
+    if (!sameString(path, "/.."))  /* We don't want to turn this to blank. */
+	{
+	int len = strlen(path);
+	char *excessStart = matchingCharBeforeInLimits(path, path+len-3, '/');
+	if (excessStart == NULL) /* Preceding '/' not found */
+	     excessStart = path;
+	else 
+	     excessStart += 1;
+	*excessStart = 0;
+	}
+    }
+}
+
+char *simplifyPathToDir(char *path)
+/* Return path with ~ and .. taken out.  Also any // or trailing /.   
+ * freeMem result when done. */
+{
+/* Expand ~ if any with result in newPath */
+char newPath[PATH_LEN];
+int newLen = 0;
+char *s = path;
+if (*s == '~')
+    {
+    char *homeDir = getenv("HOME");
+    if (homeDir == NULL)
+        errAbort("No HOME environment var defined after ~ in simplifyPathToDir");
+    ++s;
+    if (*s == '/')  /*    ~/something      */
+        {
+	++s;
+	safef(newPath, sizeof(newPath), "%s/", homeDir);
+	}
+    else            /*   ~something        */
+	{
+	safef(newPath, sizeof(newPath), "%s/../", homeDir);
+	}
+    newLen = strlen(newPath);
+    }
+int remainingLen  = strlen(s);
+if (newLen + remainingLen >= sizeof(newPath))
+    errAbort("path too big in simplifyPathToDir");
+strcpy(newPath+newLen, s);
+
+/* Remove //, .. and trailing / */
+eatSlashSlashInPath(newPath);
+eatExcessDotDotInPath(newPath);
+int lastPos = strlen(newPath)-1;
+if (lastPos > 0 && newPath[lastPos] == '/')
+    newPath[lastPos] = 0;
+
+return cloneString(newPath);
+}
+
+#ifdef DEBUG
+void simplifyPathToDirSelfTest()
+{
+/* First test some cases which should remain the same. */
+assert(sameString(simplifyPathToDir(""),""));
+assert(sameString(simplifyPathToDir("a"),"a"));
+assert(sameString(simplifyPathToDir("a/b"),"a/b"));
+assert(sameString(simplifyPathToDir("/"),"/"));
+assert(sameString(simplifyPathToDir("/.."),"/.."));
+assert(sameString(simplifyPathToDir("/../a"),"/../a"));
+
+/* Now test removing trailing slash. */
+assert(sameString(simplifyPathToDir("a/"),"a"));
+assert(sameString(simplifyPathToDir("a/b/"),"a/b"));
+
+/* Test .. removal. */
+assert(sameString(simplifyPathToDir("a/.."),""));
+assert(sameString(simplifyPathToDir("a/../"),""));
+assert(sameString(simplifyPathToDir("a/../b"),"b"));
+assert(sameString(simplifyPathToDir("/a/.."),"/"));
+assert(sameString(simplifyPathToDir("/a/../"),"/"));
+assert(sameString(simplifyPathToDir("/a/../b"),"/b"));
+assert(sameString(simplifyPathToDir("a/b/.."),"a"));
+assert(sameString(simplifyPathToDir("a/b/../"),"a"));
+assert(sameString(simplifyPathToDir("a/b/../c"),"a/c"));
+assert(sameString(simplifyPathToDir("a/../b/../c"),"c"));
+assert(sameString(simplifyPathToDir("a/../b/../c/.."),""));
+assert(sameString(simplifyPathToDir("/a/../b/../c/.."),"/"));
+
+/* Test // removal */
+assert(sameString(simplifyPathToDir("//"),"/"));
+assert(sameString(simplifyPathToDir("//../"),"/.."));
+assert(sameString(simplifyPathToDir("a//b///c"),"a/b/c"));
+assert(sameString(simplifyPathToDir("a/b///"),"a/b"));
+}
+#endif /* DEBUG */
+
+char *getUser()
+/* Get user name */
+{
+uid_t uid = geteuid();
+struct passwd *pw = getpwuid(uid);
+if (pw == NULL)
+    errnoAbort("getUser: can't get user name for uid %d", (int)uid);
+return pw->pw_name;
+}
+
+int mustFork()
+/* Fork or abort. */
+{
+int childId = fork();
+if (childId == -1)
+    errnoAbort("mustFork: Unable to fork");
+return childId;
+}
+
+int rawKeyIn()
+/* Read in an unbuffered, unechoed character from keyboard. */
+{
+struct termios attr;
+tcflag_t old;
+char c;
+
+/* Set terminal to non-echoing non-buffered state. */
+if (tcgetattr(STDIN_FILENO, &attr) != 0)
+    errAbort("Couldn't do tcgetattr");
+old = attr.c_lflag;
+attr.c_lflag &= ~ICANON;
+attr.c_lflag &= ~ECHO;
+if (tcsetattr(STDIN_FILENO, TCSANOW, &attr) == -1)
+    errAbort("Couldn't do tcsetattr");
+
+/* Read one byte */
+if (read(STDIN_FILENO,&c,1) != 1)
+   errnoAbort("rawKeyIn: I/O error");
+
+/* Put back terminal to how it was. */
+attr.c_lflag = old;
+if (tcsetattr(STDIN_FILENO, TCSANOW, &attr) == -1)
+    errAbort("Couldn't do tcsetattr2");
+return c;
+}
+
+boolean isPipe(int fd)
+/* determine in an open file is a pipe  */
+{
+struct stat buf;
+if (fstat(fd, &buf) < 0)
+    errnoAbort("isPipe: fstat failed");
+return S_ISFIFO(buf.st_mode);
+}
+
+static void execPStack(pid_t ppid)
+/* exec pstack on the specified pid */
+{
+char *cmd[3], pidStr[32];
+safef(pidStr, sizeof(pidStr), "%ld", (long)ppid);
+cmd[0] = "pstack";
+cmd[1] = pidStr;
+cmd[2] = NULL;
+
+// redirect stdout to stderr
+if (dup2(2, 1) < 0)
+    errAbort("dup2 failed");
+
+execvp(cmd[0], cmd);
+errAbort("exec failed: %s", cmd[0]);
+}
+
+void vaDumpStack(char *format, va_list args)
+/* debugging function to run the pstack program on the current process. In
+ * prints a message, following by a new line, and then the stack track.  Just
+ * prints errors to stderr rather than aborts. For debugging purposes
+ * only.  */
+{
+static boolean inDumpStack = FALSE;  // don't allow re-entry if called from error handler
+if (inDumpStack)
+    return;
+inDumpStack = TRUE;
+
+fflush(stdout);  // clear buffer before forking
+vfprintf(stderr, format, args);
+fputc('\n', stderr);
+fflush(stderr);
+pid_t ppid = getpid();
+pid_t pid = fork();
+if (pid < 0)
+    {
+    perror("can't fork pstack");
+    return;
+    }
+if (pid == 0)
+    execPStack(ppid);
+int wstat;
+if (waitpid(pid, &wstat, 0) < 0)
+    perror("waitpid on pstack failed");
+else
+    {
+    if (WIFEXITED(wstat))
+        {
+        if (WEXITSTATUS(wstat) != 0)
+            fprintf(stderr, "pstack failed\n");
+        }
+    else if (WIFSIGNALED(wstat))
+        fprintf(stderr, "pstack signaled %d\n", WTERMSIG(wstat));
+    }
+inDumpStack = FALSE;
+}
+
+void dumpStack(char *format, ...)
+/* debugging function to run the pstack program on the current process. In
+ * prints a message, following by a new line, and then the stack track.  Just
+ * prints errors to stderr rather than aborts. For debugging purposes
+ * only.  */
+{
+va_list args;
+va_start(args, format);
+vaDumpStack(format, args);
+va_end(args);
+}
+
+boolean maybeTouchFile(char *fileName)
+/* If file exists, set its access and mod times to now.  If it doesn't exist, create it.
+ * Return FALSE if we have a problem doing so (e.g. when qateam is gdb'ing and code tries 
+ * to touch some file owned by www). */
+{
+if (fileExists(fileName))
+    {
+    struct utimbuf ut;
+    ut.actime = ut.modtime = clock1();
+    int ret = utime(fileName, &ut);
+    if (ret != 0)
+	{
+	warn("utime(%s) failed (ownership?)", fileName);
+	return FALSE;
+	}
+    }
+else
+    {
+    FILE *f = fopen(fileName, "w");
+    if (f == NULL)
+	return FALSE;
+    else
+	carefulClose(&f);
+    }
+return TRUE;
+}
diff --git a/lib/oswin9x.c b/lib/oswin9x.c
new file mode 100644
index 0000000..5087f5a
--- /dev/null
+++ b/lib/oswin9x.c
@@ -0,0 +1,98 @@
+/* Stuff that's specific for Win95 goes here. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+#include "common.h"
+#include <io.h>
+#include <direct.h>
+#include "portable.h"
+
+
+/* Return how long the named file is in bytes. 
+ * Return -1 if no such file. */
+off_t fileSize(char *fileName)
+{
+int fd;
+long size;
+fd = _open(fileName, _O_RDONLY, 0);
+if (fd < 0)
+    return -1;
+size = _lseek(fd, 0L, SEEK_END);
+_close(fd);
+return size;
+}
+
+long clock1000()
+/* A millisecond clock. */
+{
+return clock() /* 1000/CLOCKS_PER_SEC */;   /* CLOCKS_PER_SEC == 1000 for windows */
+}
+
+long clock1()
+/* Second clock. */
+{
+return clock()/CLOCKS_PER_SEC;
+}
+
+void uglyfBreak()
+/* Go into debugger. */
+{
+__asm { int 3 } /* uglyf */
+}
+
+char *getCurrentDir()
+/* Return current directory. */
+{
+static char dir[_MAX_PATH];
+
+if( _getcwd( dir, _MAX_PATH ) == NULL )
+    errnoAbort("can't get current directory");
+return dir;
+}
+
+void setCurrentDir(char *newDir)
+/* Set current directory.  Abort if it fails. */
+{
+if (_chdir(newDir) != 0)
+    errnoAbort("can't to set current directory: %s", newDir);
+}
+
+struct slName *listDir(char *dir, char *pattern)
+/* Return an alphabetized list of all files that match 
+ * the wildcard pattern in directory. */
+{
+long hFile;
+struct _finddata_t fileInfo;
+struct slName *list = NULL, *name;
+boolean otherDir = FALSE;
+char *currentDir;
+
+if (dir == NULL || sameString(".", dir) || sameString("", dir))
+    dir = "";
+else
+    {
+    currentDir = getCurrentDir();
+    setCurrentDir(dir);
+    otherDir = TRUE;
+    }
+
+if (pattern == NULL)
+    pattern = *;
+if( (hFile = _findfirst( pattern, &fileInfo)) == -1L )
+    return NULL;
+
+do
+    {
+    if (!sameString(".", fileInfo.name) && !sameString("..", fileInfo.name))
+        {
+        name = newSlName(fileInfo.name);
+        slAddHead(&list, name);
+        }
+    }
+while( _findnext( hFile, &fileInfo) == 0 );
+_findclose( hFile );
+if (otherDir)
+    setCurrentDir(currentDir);
+slNameSort(&list);
+return list;
+}
diff --git a/lib/pairHmm.c b/lib/pairHmm.c
new file mode 100644
index 0000000..67eda43
--- /dev/null
+++ b/lib/pairHmm.c
@@ -0,0 +1,346 @@
+/* pairHmm - stuff to help implement pairwise hidden markov models,
+ * which are useful ways of aligning two sequences. 
+ *
+ * This file is copyright 2000-2004 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "axt.h"
+#include "pairHmm.h"
+
+
+UBYTE phmmNullMommy = 0; /* mommy value for orphans.... */
+
+void phmmUnpackMommy(UBYTE mommy, int *retStateIx, int *retQoff, 
+	int *retToff)
+/* Unpack state, query, and target offset. */
+{
+*retStateIx = (mommy&31);
+*retQoff = -((mommy&32)>>5);
+*retToff = -((mommy&64)>>6);
+}
+
+struct phmmMatrix *phmmMatrixNew(int stateCount,
+    char *query, int querySize, char *target, int targetSize)
+/* Allocate all memory required for an phmmMatrix. Set up dimensions. */
+{
+int i;
+struct phmmMommy *allCells;
+int allCellSize;
+int rowSize;
+int *allScores;
+struct phmmMatrix *am;
+
+AllocVar(am);
+am->query = query;
+am->target = target;
+am->querySize = querySize;
+am->targetSize = targetSize;
+am->qDim = rowSize = am->querySize + 1;
+am->tDim = am->targetSize + 1;
+am->stateCount = stateCount;
+am->stateSize = rowSize * am->tDim;
+am->stateByteSize = am->stateSize * sizeof(struct phmmMommy);
+am->states = needMem(stateCount * sizeof(struct phmmState));
+
+/* Initialize matrix of cells for each state. */
+allCellSize = stateCount * am->stateByteSize;
+am->allCells = allCells = needLargeMem(allCellSize); 
+memset(allCells, 0, allCellSize);
+for (i=0; i<stateCount; ++i)
+    {
+    am->states[i].cells = allCells;
+    allCells += am->stateSize;
+    am->states[i].stateIx = i;
+    }
+
+/* Initialize two rows of scores for each state. */
+allScores = am->allScores = needMem(rowSize * 2 * stateCount * sizeof(int) );
+for (i=0; i<stateCount; ++i)
+    {
+    am->states[i].scores = allScores;
+    allScores += rowSize;
+    am->states[i].lastScores = allScores;
+    allScores += rowSize;
+    }
+return am;
+}
+
+void phmmMatrixFree(struct phmmMatrix **pAm)
+/* Free up memory required for an phmmMatrix and make sure
+ * nobody reuses it. */
+{
+struct phmmMatrix *am = *pAm;
+if (am != NULL)
+    {
+    freeMem(am->states);
+    freeMem(am->allCells);
+    freeMem(am->allScores);
+    freez(pAm);
+    }
+}
+
+struct phmmState *phmmNameState(struct phmmMatrix *am, int stateIx, 
+	char *name, char emitLetter)
+/* Give a name to a state and return a pointer to it. */
+{
+struct phmmState *state;
+assert(stateIx < am->stateCount);
+state = &am->states[stateIx];
+state->name = name;
+state->emitLetter = emitLetter;
+return state;
+}
+
+static void phmmFindMatrixIx(struct phmmMatrix *am, struct phmmMommy *cell, 
+	int *retStateIx, int *retQix, int *retTix)
+/* Given a cell in matrix return state, query, and target index. */
+{
+int cellIx = cell - am->allCells;
+*retStateIx = cellIx/am->stateSize;
+cellIx %= am->stateSize;
+*retTix = cellIx / am->qDim;
+*retQix = cellIx % am->qDim;
+}
+
+static struct phmmMommy *phmmFindMommy(struct phmmMatrix *am, 
+	struct phmmMommy *baby)
+/* Find baby's mommy and return it. */
+{
+int momStateIx, qOff, tOff;
+int babyStateIx, qIx, tIx;
+UBYTE mommy;
+
+if ((mommy = baby->mommy) == phmmNullMommy)
+    return NULL;
+phmmUnpackMommy(mommy, &momStateIx, &qOff, &tOff);
+phmmFindMatrixIx(am, baby, &babyStateIx, &qIx, &tIx);
+return am->states[momStateIx].cells + (tOff + tIx) * am->qDim + (qOff + qIx);
+}
+
+struct phmmAliPair
+/* Each position in alignment gets one of these. */
+    {
+    struct phmmAliPair *next;
+    int queryIx;
+    int targetIx;
+    UBYTE hiddenIx;  /* If I code one of these with more than 255 states shoot me! */
+    char querySym;
+    char targetSym;
+    char hiddenSym;
+    };
+
+struct phmmAliPair *phmmTraceBack(struct phmmMatrix *am, struct phmmMommy *end)
+/* Create list of alignment pair by tracing back through matrix from end
+ * state back to a start.*/
+{
+struct phmmAliPair *pairList = NULL, *pair;
+struct phmmMommy *cell, *parent = end;
+int parentSix, parentTix, parentQix;
+int sIx, tIx, qIx;
+
+phmmFindMatrixIx(am, parent, &parentSix, &parentQix, &parentTix);
+for (;;)
+    {
+    cell = parent;
+    sIx = parentSix;
+    tIx = parentTix;
+    qIx = parentQix;
+
+    if ((parent = phmmFindMommy(am, cell)) == NULL)
+        break;
+    phmmFindMatrixIx(am, parent, &parentSix, &parentQix, &parentTix);
+    
+    cell->mommy |= phmmMommyTraceBit;
+
+    AllocVar(pair);
+    pair->hiddenIx = (UBYTE)sIx;
+    pair->hiddenSym = am->states[sIx].emitLetter; 
+
+    if (parentQix == qIx - 1 && parentTix == tIx - 1 )
+        {
+        pair->queryIx = qIx-1;
+        pair->querySym = am->query[qIx-1];
+        pair->targetIx = tIx - 1;
+        pair->targetSym = am->target[tIx-1];
+        }
+    else if (parentQix == qIx) /* && parentTix == tIx-1 */
+        {
+        pair->queryIx = -1;
+        pair->querySym = '-';
+        pair->targetIx = tIx-1;
+        pair->targetSym = am->target[tIx-1];
+        }
+    else  /* parentTix == tIx  && parentQix == qIx-1 */
+        {
+        pair->queryIx = qIx-1;
+        pair->querySym = am->query[qIx-1];
+        pair->targetIx = -1;
+        pair->targetSym = '-';
+        }
+    slAddHead(&pairList, pair);
+    }
+return pairList;
+}
+
+void phmmPrintTrace(struct phmmMatrix *am, struct phmmAliPair *pairList, 
+	boolean showStates, FILE *f, boolean extraAtEnds)
+/* Print out trace to file. */
+{
+struct phmmAliPair *pair;
+#define lineLen 50
+char asyms[lineLen+1];
+char qsyms[lineLen+1];
+char tsyms[lineLen+1];
+char hsyms[lineLen+1];
+int lineIx = 0;
+int qs, ts;
+boolean gotQs = FALSE;
+
+if ((pair = pairList) == NULL)
+    {
+    fprintf(f, "Empty pair list\n");
+    return;
+    }
+
+qs = pair->queryIx;
+ts = pair->targetIx;
+
+/* Print out up to 25 bp of initial non-matching parts. */
+if (extraAtEnds)
+    {
+    int qStart = qs;
+    int tStart = ts;
+    int i;
+
+    for (i= -25; i < 0; ++i)
+        {
+        int qIx = qStart + i;
+        int tIx = tStart + i;
+        qsyms[lineIx] = (qIx >= 0 ? am->query[qIx] : ' ');
+        tsyms[lineIx] = (tIx >= 0 ? am->target[tIx] : ' ' );
+        asyms[lineIx] = hsyms[lineIx] = ' ';
+        if (qIx >= 0 || tIx >= 0)
+            {
+            ++lineIx;
+            if (!gotQs)
+                {
+                gotQs = TRUE;
+                qs = qIx;
+                ts = tIx;
+                }
+            }
+        }
+    }
+
+/* Print out matching parts */
+for (pair = pairList; pair != NULL; pair = pair->next)
+    {
+    qsyms[lineIx] = pair->querySym;
+    tsyms[lineIx] = pair->targetSym;
+    asyms[lineIx] = (pair->querySym == pair->targetSym ? '|' : ' ');
+    hsyms[lineIx] = pair->hiddenSym;
+    if (++lineIx == lineLen)
+        {
+        qsyms[lineIx] = asyms[lineIx] = tsyms[lineIx] = hsyms[lineIx] = 0;
+        fprintf(f, "%5d %s\n", qs, qsyms);
+        fprintf(f, "%5s %s\n", "", asyms);
+        fprintf(f, "%5d %s\n", ts, tsyms);
+        if (showStates)
+            fprintf(f, "%5s %s\n", "", hsyms);
+        fputc('\n', f);
+        lineIx = 0;
+        if (pair->next)
+            {
+            qs = pair->next->queryIx;
+            ts = pair->next->targetIx;
+            }
+        }
+    }
+
+/* Print out last bit - first get last pair. */
+if (extraAtEnds)
+    {
+    for (pair = pairList; pair->next != NULL; pair = pair->next)
+        ;
+
+        {
+        int qIx, tIx, i;
+        int residue = lineLen - lineIx;
+        for (i=1; i<=residue; i++)
+            {
+            if ((qIx = pair->queryIx+i) >= am->querySize)
+                qsyms[lineIx] = ' ';
+            else
+                qsyms[lineIx] = am->query[qIx];
+            if ((tIx = pair->targetIx+i) >= am->targetSize)
+                tsyms[lineIx] = ' ';
+            else
+                tsyms[lineIx] = am->target[tIx];
+            asyms[lineIx] = ' ';
+            hsyms[lineIx] = ' ';
+            ++lineIx;
+            assert(lineIx <= lineLen);
+            }
+        }
+    }
+
+/* Print out anything not printed out yet. */
+if (lineIx != 0)
+    {
+    qsyms[lineIx] = asyms[lineIx] = tsyms[lineIx] = hsyms[lineIx] = 0;
+    fprintf(f, "%5d %s\n", qs, qsyms);
+    fprintf(f, "%5s %s\n", "", asyms);
+    fprintf(f, "%5d %s\n", ts, tsyms);
+    if (showStates)
+        fprintf(f, "%5s %s\n", "", hsyms);
+    fputc('\n', f);
+    lineIx = 0;
+    }
+#undef lineLen
+}
+
+struct axt *phhmTraceToAxt(struct phmmMatrix *am, struct phmmAliPair *pairList, 
+	int score, char *qName, char *tName)
+/* Convert alignment from traceback format to axt. */
+{
+struct axt *axt;
+struct phmmAliPair *pair;
+int qEnd, tEnd;
+char *qSym, *tSym;
+int i;
+
+/* Make sure got something real. */
+if ((pair = pairList) == NULL)
+    return NULL;
+
+/* Allocate memory for axt. */
+AllocVar(axt);
+axt->symCount = slCount(pairList);
+axt->qSym = AllocArray(qSym, axt->symCount+1);
+axt->tSym = AllocArray(tSym, axt->symCount+1);
+
+/* Fill in basic fields. */
+axt->qName = cloneString(qName);
+axt->tName = cloneString(tName);
+axt->qStrand = axt->tStrand = '+';
+axt->qStart = qEnd = pair->queryIx;
+axt->tStart = tEnd = pair->targetIx;
+axt->score = score;
+
+/* Store alignment symbols and keep track of last symbol used. */
+for (i=0, pair = pairList; pair != NULL; pair = pair->next, ++i)
+    {
+    qSym[i] = pair->querySym;
+    tSym[i] = pair->targetSym;
+    qEnd = pair->queryIx;
+    tEnd = pair->targetIx;
+    }
+
+/* Store end and return. */
+axt->qEnd = qEnd + 1;
+axt->tEnd = tEnd + 1;
+return axt;
+}
+
+
diff --git a/lib/peakCluster.c b/lib/peakCluster.c
new file mode 100644
index 0000000..f315dea
--- /dev/null
+++ b/lib/peakCluster.c
@@ -0,0 +1,244 @@
+/* peakCluster - cluster peak calls from different sources. Used by regCluster
+ * and encodeMergeReplicates programs. */
+
+#include "common.h"
+#include "hash.h"
+#include "linefile.h"
+#include "localmem.h"
+#include "sqlNum.h"
+#include "obscure.h"
+#include "peakCluster.h"
+#include "rangeTree.h"
+
+struct peakSource *peakSourceLoadAll(char *fileName, int dimCount)
+/* Read file, parse it line by line and return list of peakSources. */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+int rowSize = dimCount + 6;
+char *row[rowSize];
+struct peakSource *sourceList = NULL, *source;
+while (lineFileNextRow(lf, row, rowSize))
+    {
+    /* Allocate struct and read in fixed fields. */
+    AllocVar(source);
+    source->dataSource = cloneString(row[0]);
+    source->chromColIx = sqlUnsigned(row[1]);
+    source->startColIx = sqlUnsigned(row[2]);
+    source->endColIx = sqlUnsigned(row[3]);
+    source->scoreColIx = sqlUnsigned(row[4]);
+    source->normFactor = sqlDouble(row[5]);
+
+    /* Read in dimension labels. */
+    AllocArray(source->labels, dimCount);
+    int i;
+    for (i=0; i<dimCount; ++i)
+        source->labels[i] = cloneString(row[i+6]);
+
+    /* Calculate required columns. */
+    int minColCount = max(source->chromColIx, source->startColIx);
+    minColCount = max(minColCount, source->endColIx);
+    minColCount = max(minColCount, source->scoreColIx);
+    source->minColCount = minColCount + 1;
+    slAddHead(&sourceList, source);
+    }
+lineFileClose(&lf);
+slReverse(&sourceList);
+return sourceList;
+}
+
+void peakClusterMakerAddFromSource(struct peakClusterMaker *maker, struct peakSource *source)
+/* Read through data source and add items to it to rangeTrees in maker */
+{
+struct hash *chromHash = maker->chromHash;
+struct lineFile *lf = lineFileOpen(source->dataSource, TRUE);
+struct lm *lm = chromHash->lm;	/* Local memory pool - share with hash */
+char *row[source->minColCount];
+struct peakItem *item;
+char *line;
+while (lineFileNextReal(lf, &line))
+    {
+    char *asciiLine = lmCloneString(lm, line);
+    int wordCount = chopByWhite(line, row, source->minColCount);
+    lineFileExpectAtLeast(lf, source->minColCount, wordCount);
+    char *chrom = row[source->chromColIx];
+    struct hashEl *hel = hashLookup(chromHash, chrom);
+    if (hel == NULL)
+        {
+	struct rbTree *tree = rangeTreeNewDetailed(lm, maker->stack);
+	hel = hashAdd(chromHash, chrom, tree);
+	}
+    struct rbTree *tree = hel->val;
+    lmAllocVar(lm, item);
+    item->chrom = hel->name;
+    item->chromStart = sqlUnsigned(row[source->startColIx]);
+    item->chromEnd = sqlUnsigned(row[source->endColIx]);
+    item->score = sqlDouble(row[source->scoreColIx]) * source->normFactor;
+    if (item->score > 1000) item->score = 1000;
+    item->source = source;
+    item->asciiLine = asciiLine;
+    rangeTreeAddValList(tree, item->chromStart, item->chromEnd, item);
+    }
+lineFileClose(&lf);
+}
+
+static void addCluster(struct lm *lm, struct peakItem *itemList, int start, int end,
+	struct peakCluster **pList)
+/* Make cluster of all items that overlap start/end, and put it on list. */
+{
+struct peakCluster *cluster;
+lmAllocVar(lm, cluster);
+double score = 0.0;
+double maxSubScore = 0.0;
+struct slRef  *refList = NULL, *ref;
+struct peakItem *item;
+for (item = itemList; item != NULL; item = item->next)
+    {
+    if (rangeIntersection(start, end, item->chromStart, item->chromEnd) > 0)
+	{
+	lmAllocVar(lm, ref);
+	ref->val = item;
+	slAddHead(&refList, ref);
+	score += item->score;
+	if (item->score > maxSubScore) maxSubScore = item->score;
+	}
+    }
+slReverse(&refList);
+cluster->chrom = itemList->chrom;
+cluster->chromStart = start;
+cluster->chromEnd = end;
+cluster->itemRefList = refList;
+cluster->score = score;
+cluster->maxSubScore = maxSubScore;
+slAddHead(pList, cluster);
+}
+
+struct peakCluster *peakClusterItems(struct lm *lm, struct peakItem *itemList, 
+	double forceJoinScore, double weakLevel)
+/* Convert a list of items to a list of clusters of items.  This may break up clusters that
+ * have weakly linked parts. 
+      [                ]
+      AAAAAAAAAAAAAAAAAA 
+       BBBBBB   DDDDDD
+        CCCC     EEEE
+   gets tranformed into
+       [    ]   [    ]
+      AAAAAAAAAAAAAAAAAA 
+       BBBBBB   DDDDDD
+        CCCC     EEEE
+   The strategy is to build a rangeTree of coverage, which might look something like so:
+      123333211123333211 
+   then define cluster ends that exceed the minimum limit, which is either weakLevel
+   (usually 10%) of the highest or forceJoinScore if weakLevel times the highest is 
+   more than forceJoinScore.  This will go to something like so:
+        [---]   [----]   
+   Finally the items that are overlapping a cluster are assigned to it.  Note that this
+   may mean that an item may be in multiple clusters.
+        [ABC]   [ ADE]
+ */
+{
+int easyMax = round(1.0/weakLevel);
+int itemCount = slCount(itemList);
+struct peakCluster *clusterList = NULL;
+if (itemCount < easyMax)
+    {
+    struct peakItem *item = itemList;
+    int chromStart = item->chromStart;
+    int chromEnd = item->chromEnd;
+    for (item = item->next; item != NULL; item = item->next)
+        {
+	if (item->chromStart < chromStart) chromStart = item->chromStart;
+	if (item->chromEnd > chromEnd) chromEnd = item->chromEnd;
+	}
+    addCluster(lm, itemList, chromStart, chromEnd, &clusterList);
+    }
+else
+    {
+    /* Make up coverage tree. */
+    struct rbTree *covTree = rangeTreeNew();
+    struct peakItem *item;
+    for (item = itemList; item != NULL; item = item->next)
+	rangeTreeAddToCoverageDepth(covTree, item->chromStart, item->chromEnd);
+    struct range *range, *rangeList = rangeTreeList(covTree);
+
+    /* Figure out maximum coverage. */
+    int maxCov = 0;
+    for (range = rangeList; range != NULL; range = range->next)
+        {
+	int cov = ptToInt(range->val);
+	if (cov > maxCov) maxCov = cov;
+	}
+
+    /* Figure coverage threshold. */
+    int threshold = round(maxCov * weakLevel);
+    if (threshold > forceJoinScore-1) threshold = forceJoinScore-1;
+
+    /* Loop through emitting sections over threshold as clusters */
+    boolean inRange = FALSE;
+    boolean start = 0, end = 0;
+    for (range = rangeList; range != NULL; range = range->next)
+        {
+	int cov = ptToInt(range->val);
+	if (cov > threshold)
+	    {
+	    if (inRange)
+	       end = range->end;
+	    else
+	       {
+	       inRange = TRUE;
+	       start = range->start;
+	       end = range->end;
+	       }
+	    }
+	else
+	    {
+	    if (inRange)
+		{
+		addCluster(lm, itemList, start, end, &clusterList);
+		inRange = FALSE;
+		}
+	    }
+	}
+    if (inRange)
+        addCluster(lm, itemList, start, end, &clusterList);
+    }
+slReverse(&clusterList);
+return clusterList;
+}
+
+struct peakClusterMaker *peakClusterMakerNew()
+/* Return a new peakClusterMaker. */
+{
+struct peakClusterMaker *maker;
+AllocVar(maker);
+maker->chromHash = hashNew(0);
+return maker;
+}
+
+void peakClusterMakerFree(struct peakClusterMaker **pMaker)
+/* Free up a peakClusterMaker. */
+{
+struct peakClusterMaker *maker = *pMaker;
+if (maker != NULL)
+    {
+    hashFree(&maker->chromHash);
+    freez(pMaker);
+    }
+}
+
+static int cmpChromEls(const void *va, const void *vb)
+/* Compare to sort based on query start. */
+{
+const struct hashEl *a = *((struct hashEl **)va);
+const struct hashEl *b = *((struct hashEl **)vb);
+return cmpWordsWithEmbeddedNumbers(a->name, b->name);
+}
+
+struct hashEl *peakClusterMakerChromList(struct peakClusterMaker *maker)
+/* Return list of chromosomes.  In hashEl format where the hashEl val is
+ * a rangeTree filled with items. */
+{
+struct hashEl *chromList =  hashElListHash(maker->chromHash);
+slSort(&chromList, cmpChromEls);
+return chromList;
+}
+
diff --git a/lib/phyloTree.c b/lib/phyloTree.c
new file mode 100644
index 0000000..0c49718
--- /dev/null
+++ b/lib/phyloTree.c
@@ -0,0 +1,418 @@
+#include "common.h"
+#include "linefile.h"
+#include "dystring.h"
+#include "phyloTree.h"
+
+
+struct phyloTree *phyloReadTree(struct lineFile *lf)
+/* reads a phyloTree from lineFile (first line only) */
+{
+struct phyloTree *tree = NULL;
+char *ptr;
+int len;
+
+if (lineFileNext(lf, &ptr, &len) && (len > 0))
+    tree = phyloParseString(ptr);
+
+return tree;
+}
+
+struct phyloTree *phyloOpenTree(char *fileName)
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+struct phyloTree *tree = phyloReadTree(lf);
+
+lineFileClose(&lf);
+
+return tree;
+}
+
+
+static struct phyloName *parseIdent(char **ptrPtr)
+/* read a node name with possibile branch length */
+{
+struct phyloName *pName;
+char *start = *ptrPtr;
+char *ptr = *ptrPtr;
+
+AllocVar(pName);
+/* legal id's are alphanumeric */
+while(isalpha(*ptr) || isdigit(*ptr) || (*ptr == '/')
+     || (*ptr == '\'')
+     || (*ptr == '>')
+     || (*ptr == '<')
+    || (*ptr == '.') || (*ptr == '_')) 
+    ptr++;
+
+/* did we read something? */
+if(ptr > start)
+    {
+    char val;
+
+    val = *ptr;
+    *ptr = 0;
+    pName->name = cloneString(start);
+    *ptr = val;
+    }
+
+/* is there some branch length info */
+if (*ptr == ':')
+    {
+    ptr++;
+    sscanf(ptr, "%lg", &pName->length);
+    while ((*ptr != '[') && (*ptr != ')') && (*ptr != ',') && (*ptr != ';'))
+	ptr++;
+    }
+
+*ptrPtr = ptr;
+
+return pName;
+}
+
+static struct phyloTree *newEdge(struct phyloTree *parent, struct phyloTree *child)
+{
+parent->numEdges++;
+
+if (parent->numEdges > parent->allocedEdges)
+    {
+    int oldSize = parent->allocedEdges * sizeof (struct phyloTree *);
+    int newSize;
+
+    parent->allocedEdges += 5;
+    newSize = parent->allocedEdges * sizeof (struct phyloTree *);
+    parent->edges = needMoreMem(parent->edges, oldSize, newSize);
+    }
+
+if (!child)
+    errAbort("unexpected error: child is null in phyloTree.c::newEdge()");
+
+child->parent = parent;
+return parent->edges[parent->numEdges -1 ] = child;
+}
+
+struct phyloTree *phyloAddEdge(struct phyloTree *parent, struct phyloTree *child)
+/* add an edge to a phyloTree node */
+{
+return newEdge(parent, child);
+}
+
+static struct phyloTree *parseSubTree(char **ptrPtr)
+/* the recursive workhorse function, parses a tree from ptr */
+{
+struct phyloTree *node = NULL;
+char *ptr = *ptrPtr;
+
+/* trees are terminated by one of these three chars */
+if ((*ptr == ';') || (*ptr == ',') || (*ptr == ')') )
+    return NULL;
+
+AllocVar(node);
+if (*ptr == '(') 
+    {
+    struct phyloTree *edge;
+
+    ptr++;
+
+    do
+	{
+	struct phyloTree *child = parseSubTree(&ptr);
+	if (!child)
+	    errAbort("missing child/subTree at (%s)",ptr-1);
+	edge = newEdge(node,child);
+	edge->parent = node;
+	} while (*ptr++ == ',');
+    --ptr;
+    if (*ptr++ != ')') 
+	errAbort("unbalanced parenthesis at (%s)",ptr-1);
+    node->ident = parseIdent(&ptr);
+    }
+else 
+    if ((*ptr == ':') || (isalpha(*ptr))|| (isdigit(*ptr)) 
+	 || (*ptr == '\'') || (*ptr == '.'))
+	node->ident = parseIdent(&ptr);
+else
+    errAbort("illegal char '%c' in phyloString",*ptr);
+
+if (*ptr == '[')
+    {
+    if (startsWith("[&&NHX:D=Y]",ptr))
+	node->isDup = TRUE;
+
+    while(*ptr != ']')
+	ptr++;
+
+    ptr++;
+
+    }
+
+*ptrPtr = ptr;
+
+
+return node;
+}
+
+struct phyloTree *phyloParseString(char *string)
+/* build a phyloTree from a string */
+{
+struct phyloTree *tree = NULL;
+char *ptr = string;
+
+eraseWhiteSpace(string);
+
+tree = parseSubTree(&ptr);
+
+if (*ptr != ';')
+    errAbort("expecting tree terminator ';', found '%s'", ptr);
+
+return tree;
+}
+
+
+/*  some static stuff for printing out trees */
+static int recurseCount = 0;
+
+static void tabOut(FILE *f)
+{
+int i;
+
+for(i=0; i < recurseCount; i++)
+    fputc(' ',f);
+}
+
+static void pTree( struct phyloTree *tree,FILE *f, boolean noDups)
+/* print out phylogenetic tree in Newick format */
+{
+if (tree)
+    {
+    int ii;
+    if (noDups && (tree->numEdges == 1))
+	pTree(tree->edges[0], f, noDups);
+    else 
+	{
+	if (tree->numEdges)
+	    {
+	    fprintf(f,"(");
+	    for (ii= 0; ii < tree->numEdges; ii++)
+		{
+		pTree(tree->edges[ii], f, noDups);
+		if (ii + 1 < tree->numEdges)
+		    fprintf(f,",");
+		}
+	    fprintf(f,")");
+	    }
+	if (tree->ident->name)
+	    fprintf(f,"%s",tree->ident->name);
+	//if (tree->ident->length != 0.0)
+	    fprintf(f,":%0.04g", tree->ident->length);
+	if (tree->isDup)
+	    fprintf(f,"[&&NHX:D=Y]");
+	}
+    }
+}
+
+void phyloPrintTreeNoDups( struct phyloTree *tree,FILE *f)
+/* print out phylogenetic tree in Newick format (only speciation nodes) */
+{
+pTree(tree, f, TRUE);
+fprintf(f, ";\n");
+}
+
+void phyloPrintTree( struct phyloTree *tree,FILE *f)
+/* print out phylogenetic tree in Newick format */
+{
+pTree(tree, f, FALSE);
+fprintf(f, ";\n");
+}
+
+void phyloDebugTree( struct phyloTree *tree,FILE *f)
+/* print out phylogenetic tree */
+{
+if (tree)
+    {
+    int ii;
+    fprintf(f,"%s:%g numEdges %d\n",tree->ident->name, tree->ident->length, tree->numEdges);
+    recurseCount++;
+    for (ii= 0; ii < tree->numEdges; ii++)
+	{
+	tabOut(f);
+	phyloDebugTree(tree->edges[ii], f);
+	}
+    recurseCount--;
+    }
+}
+
+struct phyloTree *phyloFindName( struct phyloTree *tree,char *name )
+/* find the node with this name */
+{
+struct phyloTree *subTree = NULL;
+int ii;
+
+if (tree->ident->name && sameString(tree->ident->name, name))
+    return tree;
+
+for (ii=0; ii < tree->numEdges; ii++)
+    {
+    if ((subTree = phyloFindName( tree->edges[ii], name)) != NULL)
+	break;
+    }
+
+return subTree;
+}
+
+void phyloClearTreeMarks(struct phyloTree *tree)
+/* clear the favorite child marks */
+{
+int ii;
+
+tree->mark = 0;
+
+for (ii=0; ii < tree->numEdges; ii++)
+    phyloClearTreeMarks(tree->edges[ii]);
+}
+
+struct phyloTree *phyloFindMarkUpTree(struct phyloTree *tree)
+/* find a marked node somewhere above this node */
+{
+do
+    {
+    if (tree->mark)
+	return tree;
+    tree = tree->parent;
+    } while (tree);
+
+return NULL;
+}
+
+void phyloMarkUpTree(struct phyloTree *tree)
+/* mark all the nodes from this one up to the top of the tree */
+{
+    tree->mark = tree;
+    for(;tree->parent; tree = tree->parent)
+	tree->parent->mark = tree;
+}
+
+char *phyloFindPath(struct phyloTree *tree, char *ref, char *cross)
+/* find the shortest path from ref to cross (returns a list
+ * of the node names separated by spaces) */
+{
+struct phyloTree *treeRef, *treeCross, *parent;
+struct dyString *ds = newDyString(0);
+
+if ((treeRef = phyloFindName(tree,ref)) == NULL)
+    return NULL;
+
+if ((treeCross = phyloFindName(tree,cross)) == NULL)
+    return NULL;
+
+phyloClearTreeMarks(tree);
+phyloMarkUpTree(treeCross);
+if ((parent = phyloFindMarkUpTree(treeRef)) == NULL)
+    return NULL;
+
+/* walk up the tree till we hit the common parent */
+while(treeRef != parent)
+    {
+    treeRef = treeRef->parent;
+    if (ds->stringSize)
+	dyStringAppendC(ds, ' ');
+    if (treeRef->ident->name)
+	dyStringAppendN(ds, treeRef->ident->name, strlen(treeRef->ident->name));
+    }
+
+/* now walk down the tree till we come to the target species */
+while (parent != treeCross)
+    {
+    parent = parent->mark;
+    dyStringAppendC(ds, ' ');
+    if (parent->ident->name)
+	dyStringAppendN(ds, parent->ident->name, strlen(parent->ident->name));
+    }
+
+return ds->string;
+}
+
+
+static void nodeNames(struct phyloTree *tree, struct dyString *ds)
+/* recursive workhorse to add all the node names to a string */
+{
+int ii;
+
+if (tree->ident->name)
+    {
+    dyStringAppendN(ds, tree->ident->name, strlen(tree->ident->name));
+    dyStringAppendC(ds, ' ');
+    }
+
+for (ii=0; ii < tree->numEdges; ii++)
+    nodeNames(tree->edges[ii],ds);
+}
+
+char *phyloNodeNames(struct phyloTree *tree)
+/* add all the node names to a dy string */
+{
+struct dyString *ds = newDyString(0);
+
+nodeNames(tree, ds);
+
+ds->string[ds->stringSize-1]=0;
+
+return ds->string;
+}
+
+
+static void reParent(struct phyloTree *tree)
+{
+if (tree->parent)
+    {
+    struct phyloTree *edge, *saveParent = tree->parent;
+
+    reParent(saveParent); /* make the parent into the root */
+    phyloDeleteEdge(saveParent, tree); /* remove this tree from the
+					  parent tree */
+    tree->parent = NULL; /* make this tree the root */
+    edge = newEdge(tree, saveParent); /* add the old parent tree as a
+					child of the new root */
+    edge->parent = tree; /* set the parent in the new child */
+
+    edge->ident->length = tree->ident->length;
+    }
+}
+
+struct phyloTree *phyloReRoot(struct phyloTree *tree)
+/* return a tree whose root is tree and what were parents are now "right" children */
+{
+reParent(tree);
+tree->ident->length = 0;
+
+return tree;
+}
+
+void phyloDeleteEdge(struct phyloTree *tree, struct phyloTree *edge)
+/* delete an edge from a node.  Aborts on error */
+{
+int ii;
+
+for (ii=0; ii < tree->numEdges; ii++)
+    if (tree->edges[ii] == edge)
+	{
+	memcpy(&tree->edges[ii], &tree->edges[ii+1], sizeof(tree) * (tree->numEdges - ii - 1));
+	tree->numEdges--;
+	//phyloFreeTree(edge);
+	return;
+	}
+
+errAbort("tried to delete non-existant edge");
+}
+
+int phyloCountLeaves(struct phyloTree *tree)
+{
+int ii, count = 0;
+
+if (tree->numEdges == 0)
+    return 1;
+
+for (ii=0; ii < tree->numEdges; ii++)
+    count += phyloCountLeaves(tree->edges[ii]);
+
+return count;
+}
diff --git a/lib/pipeline.c b/lib/pipeline.c
new file mode 100644
index 0000000..417bd31
--- /dev/null
+++ b/lib/pipeline.c
@@ -0,0 +1,698 @@
+/* pipeline.c - create a process pipeline that can be used for reading or
+ * writing  */
+#include "pipeline.h"
+#include "common.h"
+#include "sqlNum.h"
+#include "dystring.h"
+#include "errabort.h"
+#include "portable.h"
+#include "linefile.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+enum procState
+/* process state, in order of transition */
+{
+    procStateNew,  // plProc object created
+    procStateRun,  // proccess running
+    procStateDone  // process finished (ok or failed)
+};
+
+struct plProc
+/* A single process in a pipeline */
+{
+    struct plProc *next;   /* order list of processes */
+    struct pipeline *pl;   /* pipeline we are associated with */
+    char **cmd;            /* null-terminated command for this process */
+    pid_t  pid;            /* pid for process, -1 if not running */
+    enum procState state;  /* state of process */
+    int status;            /* status from wait */
+};
+
+struct pipeline
+/* Object for a process pipeline and associated open file.  Pipeline process
+ * consist of a process group leader and then all of the child process.  The
+ * group leader does no work, just wait on processes to complete and report
+ * errors to the top level process.  This object is create in the calling
+ * process, and then passed down, but not shared, via forks.
+ */
+{
+    struct plProc *procs;      /* list of processes */
+    int numRunning;            /* number of processes running */
+    pid_t groupLeader;         /* process group id, or -1 if not set. This is pid of group leader */
+    char *procName;            /* name to use in error messages. */
+    int pipeFd;                /* fd of pipe to/from process, -1 if none */
+    unsigned options;          /* options */
+    FILE* pipeFh;              /* optional stdio around pipe */
+    char* stdioBuf;            /* optional stdio buffer */
+    struct lineFile *pipeLf;   /* optional lineFile around pipe */
+};
+
+/* file buffer size */
+#define FILE_BUF_SIZE 64*1024
+
+static int pipeCreate(int *writeFd)
+/* create a pipe or die, return readFd */
+{
+int pipeFds[2];
+if (pipe(pipeFds) < 0)
+    errnoAbort("can't create pipe");
+*writeFd = pipeFds[1];
+return pipeFds[0];
+}
+
+static void safeClose(int *fdPtr)
+/* Close with error checking.  *fdPtr == -1 indicated already closed */
+{
+int fd = *fdPtr;
+if (fd != -1)
+    {
+    if (close(fd) < 0)
+        errnoAbort("close failed on fd %d", fd);
+    *fdPtr = -1;
+    }
+}
+
+static void closeNonStdDescriptors(void)
+/* close non-standard file descriptors */
+{
+long maxFd = sysconf(_SC_OPEN_MAX);
+if (maxFd < 0)
+    maxFd = 4096;  // shouldn't really happen
+int fd;
+for (fd = STDERR_FILENO+1; fd < maxFd; fd++)
+    close(fd);
+}
+
+static char* joinCmd(char **cmd)
+/* join an cmd vector into a space separated string */
+{
+struct dyString *str = dyStringNew(512);
+int i;
+for (i = 0; cmd[i] != NULL; i++)
+    {
+    if (i > 0)
+        dyStringAppend(str, " ");
+    dyStringAppend(str, cmd[i]);
+    }
+return dyStringCannibalize(&str);
+}
+
+static char* joinCmds(char ***cmds)
+/* join an cmds vetor into a space and pipe separated string */
+{
+struct dyString *str = dyStringNew(512);
+int i, j;
+for (i = 0; cmds[i] != NULL; i++)
+    {
+    if (i > 0)
+        dyStringAppend(str, " | ");
+    for (j = 0; cmds[i][j] != NULL; j++)
+        {
+        if (j > 0)
+            dyStringAppend(str, " ");
+        dyStringAppend(str, cmds[i][j]);
+        }
+    }
+return dyStringCannibalize(&str);
+}
+
+static char** cloneCmdVector(char **cmd)
+/* make a copy of the vector */
+{
+int i, cmdLen = 0;
+for (i = 0; cmd[i] != NULL; i++)
+    cmdLen++;
+char **cmd2 = needMem((cmdLen+1)*sizeof(char*));
+
+for (i = 0; i < cmdLen; i++)
+    cmd2[i] = cloneString(cmd[i]);
+cmd2[cmdLen] = NULL;
+return cmd2;
+}
+
+static struct plProc* plProcNew(char **cmd, struct pipeline *pl)
+/* create a new plProc object for a command. */
+{
+struct plProc* proc;
+AllocVar(proc);
+proc->pl = pl;
+proc->cmd = cloneCmdVector(cmd);
+proc->state = procStateNew;
+return proc;
+}
+
+static void plProcFree(struct plProc *proc)
+/* free a plProc object. */
+{
+int i;
+for (i = 0; proc->cmd[i] != NULL; i++)
+    freeMem(proc->cmd[i]);
+freeMem(proc->cmd);
+freeMem(proc);
+}
+
+static void plProcStateTrans(struct plProc *proc, enum procState newState)
+/* do state transition for process changing it to a new state  */
+{
+// States must transition in order.  New state must immediately follow the
+// current state.
+if (newState != proc->state+1)
+    errAbort("invalid state transition: %d -> %d", proc->state, newState);
+proc->state = newState;
+}
+
+static void plProcSetup(struct plProc* proc, int stdinFd, int stdoutFd, int stderrFd)
+/* setup signal, error handling, and file descriptors after fork */
+{
+/* treat a closed pipe as an EOF rather than getting SIGPIPE */
+struct sigaction sigAct;
+ZeroVar(&sigAct);
+sigAct.sa_handler = SIG_IGN;
+if (sigaction(SIGPIPE, &sigAct, NULL) != 0)
+    errnoAbort("failed to set SIGPIPE to SIG_IGN");
+
+/* child, first setup stdio files */
+if (stdinFd != STDIN_FILENO)
+    {
+    if (dup2(stdinFd, STDIN_FILENO) < 0)
+        errnoAbort("can't dup2 to stdin");
+    }
+    
+if (stdoutFd != STDOUT_FILENO)
+    {
+    if (dup2(stdoutFd, STDOUT_FILENO) < 0)
+        errnoAbort("can't dup2 to stdout");
+    }
+    
+if (stderrFd != STDERR_FILENO)
+    {
+    if (dup2(stderrFd, STDERR_FILENO) < 0)
+        errnoAbort("can't dup2 to stderr");
+    }
+closeNonStdDescriptors();
+}
+
+static void plProcExecChild(struct plProc* proc, int stdinFd, int stdoutFd, int stderrFd)
+/* child part of process startup. */
+{
+plProcSetup(proc, stdinFd, stdoutFd, stderrFd);
+execvp(proc->cmd[0], proc->cmd);
+errnoAbort("exec failed: %s", proc->cmd[0]);
+}
+
+static void plProcMemWrite(struct plProc* proc, int stdoutFd, int stderrFd, void *otherEndBuf, size_t otherEndBufSize)
+/* implements child process to write memory buffer to pipeline after
+ * fork */
+{
+plProcSetup(proc, STDIN_FILENO, stdoutFd, stderrFd);
+ssize_t wrCnt = write(STDOUT_FILENO, otherEndBuf, otherEndBufSize);
+if (wrCnt < 0)
+    errnoAbort("pipeline input buffer write failed");
+else if (wrCnt != otherEndBufSize)
+    errAbort("pipeline input buffer short write %lld, expected %lld",
+             (long long)wrCnt, (long long)otherEndBufSize);
+else
+    {
+    close(STDOUT_FILENO);
+    exit(0);
+    }
+}
+
+static void plProcHandleTerminate(struct plProc* proc, int status)
+/* handle one of the processes terminating, save exit status */
+{
+proc->status = status;
+if (WIFSIGNALED(proc->status))
+    errAbort("process terminated on signal %d: \"%s\" in pipeline \"%s\"",
+             WTERMSIG(proc->status), joinCmd(proc->cmd), proc->pl->procName);
+assert(WIFEXITED(proc->status));
+
+if (WEXITSTATUS(proc->status) != 0)
+    {
+    // only print an error message if aborting
+    if (!(proc->pl->options & pipelineNoAbort))
+        fprintf(stderr, "process exited with %d: \"%s\" in pipeline \"%s\"\n",
+                WEXITSTATUS(proc->status), joinCmd(proc->cmd), proc->pl->procName);
+    exit(WEXITSTATUS(proc->status));  // pass back exit code
+    }
+proc->pid = -1;
+plProcStateTrans(proc, procStateDone);
+}
+
+static struct pipeline* pipelineNew(char ***cmds, unsigned options)
+/* create a new pipeline object. Doesn't start processes */
+{
+static char *memPseudoCmd[] = {"[mem]", NULL};
+struct pipeline *pl;
+int iCmd;
+
+AllocVar(pl);
+pl->groupLeader = -1;
+pl->pipeFd = -1;
+pl->options = options;
+pl->procName = joinCmds(cmds);
+
+if (cmds[0] == NULL)
+    errAbort("no commands in pipeline");
+
+if (options & pipelineMemInput)
+    {
+    /* add proc for forked process to write memory to pipeline */
+    slAddTail(&pl->procs, plProcNew(memPseudoCmd, pl));
+    }
+
+for(iCmd = 0; cmds[iCmd] != NULL; iCmd++)
+    slAddTail(&pl->procs, plProcNew(cmds[iCmd], pl));
+
+return pl;
+}
+
+void pipelineFree(struct pipeline **plPtr)
+/* free a pipeline object */
+{
+struct pipeline *pl = *plPtr;
+if (pl != NULL)
+    {
+    struct plProc *proc = pl->procs;
+    while (proc != NULL)
+        {
+        struct plProc *delProc = proc;
+        proc = proc->next;
+        plProcFree(delProc);
+        }
+    freez(&pl->procName);
+    freez(&pl->stdioBuf);
+    freez(plPtr);
+    }
+}
+
+static struct plProc *pipelineFindProc(struct pipeline *pl, pid_t pid)
+/* find a plProc by pid */
+{
+struct plProc *proc;
+for (proc = pl->procs; proc != NULL; proc = proc->next)
+    if (proc->pid == pid)
+        return proc;
+errAbort("pid not found in pipeline: %d", (int)pid);
+return 0; // never reached
+}
+
+static void execProcChild(struct pipeline* pl, struct plProc *proc,
+                          int procStdinFd, int procStdoutFd, int stderrFd,
+                          void *otherEndBuf, size_t otherEndBufSize)
+/* handle child process setup after fork.  This does not return */
+{
+if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+    errnoAbort("error ignoring SIGPIPE");
+if (setpgid(getpid(), pl->groupLeader) != 0)
+    errnoAbort("error from setpgid(%d, %d)", getpid(), pl->groupLeader);
+
+if (otherEndBuf != NULL)
+    plProcMemWrite(proc, procStdoutFd, stderrFd, otherEndBuf, otherEndBufSize);
+else
+    plProcExecChild(proc, procStdinFd, procStdoutFd, stderrFd);
+}
+
+static int pipelineExecProc(struct pipeline* pl, struct plProc *proc,
+                            int prevStdoutFd, int stdinFd, int stdoutFd, int stderrFd,
+                            void *otherEndBuf, size_t otherEndBufSize)
+/* start a process in the pipeline, return the stdout fd of the process */
+{
+/* determine stdin/stdout to use */
+int procStdinFd, procStdoutFd;
+if (proc == pl->procs)
+    procStdinFd = stdinFd; /* first process in pipeline */
+else
+    procStdinFd = prevStdoutFd;
+if (proc->next == NULL)
+    procStdoutFd = stdoutFd; /* last process in pipeline */
+else
+    prevStdoutFd = pipeCreate(&procStdoutFd);
+
+/* start process */
+if ((proc->pid = fork()) < 0)
+    errnoAbort("can't fork");
+if (proc->pid == 0)
+    execProcChild(pl, proc, procStdinFd, procStdoutFd, stderrFd, otherEndBuf, otherEndBufSize);
+
+/* record that we did this */
+plProcStateTrans(proc, procStateRun);
+pl->numRunning++;
+
+/* don't leave intermediate pipes open in parent */
+if (proc != pl->procs)
+    safeClose(&procStdinFd);
+if (proc->next != NULL)
+    safeClose(&procStdoutFd);
+
+return prevStdoutFd;
+}
+
+static void pipelineGroupExec(struct pipeline* pl, int stdinFd, int stdoutFd, int stderrFd,
+                              void *otherEndBuf, size_t otherEndBufSize)
+/* Start all processes in a pipeline, stdinFd and stdoutFd are the ends of
+ * the pipeline, stderrFd is applied to all processed */
+{
+struct plProc *proc;
+int prevStdoutFd = -1;
+for (proc = pl->procs; proc != NULL; proc = proc->next)
+    {
+    prevStdoutFd = pipelineExecProc(pl, proc, prevStdoutFd,
+                                    stdinFd, stdoutFd, stderrFd,
+                                    otherEndBuf, otherEndBufSize);
+    otherEndBuf = NULL;  /* only for first process (read pipes) */
+    otherEndBufSize = 0;
+    }
+}
+
+static void waitOnOne(struct pipeline *pl)
+/* wait on one process to finish */
+{
+int status;
+pid_t pid = waitpid(-pl->groupLeader, &status, 0);
+if (pid < 0)
+    errnoAbort("waitpid failed");
+plProcHandleTerminate(pipelineFindProc(pl, pid), status);
+pl->numRunning--;
+assert(pl->numRunning >= 0);
+}
+
+static void groupWait(struct pipeline *pl)
+/* Wait for pipeline to complete */
+{
+/* wait on all processes to complete */
+while (pl->numRunning > 0)
+    waitOnOne(pl);
+}
+
+static void groupLeaderRun(struct pipeline* pl, int stdinFd, int stdoutFd, int stderrFd,
+                           void *otherEndBuf, size_t otherEndBufSize)
+/* group leader process */
+{
+pl->groupLeader = getpid();
+if (setpgid(pl->groupLeader, pl->groupLeader) != 0)
+    errnoAbort("error from child setpgid(%d, %d)", pl->groupLeader, pl->groupLeader);
+pipelineGroupExec(pl, stdinFd, stdoutFd, stderrFd, otherEndBuf, otherEndBufSize);
+
+// only keep stderr open
+close(STDIN_FILENO);
+close(STDOUT_FILENO);
+closeNonStdDescriptors();
+groupWait(pl);
+exit(0);
+}
+
+static int groupLeaderWait(struct pipeline *pl)
+/* Wait for group leader to complete. If pipelineNoAbort was specified, return
+ * the exit code of the first group process exit non-zero, or zero if none
+ * failed. */
+{
+int status;
+pid_t pid = waitpid(-pl->groupLeader, &status, 0);
+if (pid < 0)
+    errnoAbort("waitpid failed");
+if (WIFSIGNALED(status))
+    errAbort("process pipeline terminated on signal %d", WTERMSIG(status));
+assert(WIFEXITED(status));
+
+if ((WEXITSTATUS(status) != 0) && !(pl->options & pipelineNoAbort))
+    errAbort("pipeline exited with %d", WEXITSTATUS(status));
+return WEXITSTATUS(status);
+}
+
+static void pipelineExec(struct pipeline* pl, int stdinFd, int stdoutFd, int stderrFd,
+                         void *otherEndBuf, size_t otherEndBufSize)
+/* Fork the group leader, which then launches all all processes in a pipeline,
+ * stdinFd and stdoutFd are the ends of the pipeline, stderrFd is applied to
+ * all processes, including group leader */
+{
+assert(pl->groupLeader < 0);  // should not be set
+if ((pl->groupLeader = fork()) < 0)
+    errnoAbort("can't fork");
+if (pl->groupLeader == 0)
+    {
+    groupLeaderRun(pl, stdinFd, stdoutFd, stderrFd, otherEndBuf, otherEndBufSize);
+    exit(1); // doesn't return to here
+    }
+else
+    {
+    // parent also must also setpgid to prevent race condition
+    if (setpgid(pl->groupLeader, pl->groupLeader) != 0)
+        errnoAbort("error from parent setpgid(%d, %d)", pl->groupLeader, pl->groupLeader);
+    }
+} 
+
+static int openRead(char *fname)
+/* open a file for reading */
+{
+int fd = open(fname, O_RDONLY);
+if (fd < 0)
+    errnoAbort("can't open for read access: %s", fname);
+return fd;
+}
+
+static int openWrite(char *fname, boolean append)
+/* open a file for write access */
+{
+int flags = O_WRONLY|O_CREAT;
+if (append)
+    flags |= O_APPEND;
+else
+    flags |= O_TRUNC;
+int fd = open(fname, flags, 0666);
+if (fd < 0)
+    errnoAbort("can't open for write access: %s", fname);
+return fd;
+}
+
+static void pipelineStartRead(struct pipeline *pl, int stdinFd, int stderrFd,
+                              void *otherEndBuf, size_t otherEndBufSize)
+/* start a read pipeline */
+{
+int pipeWrFd;
+pl->pipeFd = pipeCreate(&pipeWrFd);
+pipelineExec(pl, stdinFd, pipeWrFd, stderrFd, otherEndBuf, otherEndBufSize);
+safeClose(&pipeWrFd);
+}
+
+static void pipelineStartWrite(struct pipeline *pl, int stdoutFd, int stderrFd)
+/* start a write pipeline */
+{
+int pipeRdFd = pipeCreate(&pl->pipeFd);
+pipelineExec(pl, pipeRdFd, stdoutFd, stderrFd, NULL, 0);
+safeClose(&pipeRdFd);
+}
+
+static void checkOpts(unsigned opts)
+/* check option set for consistency */
+{
+if (((opts & (pipelineRead|pipelineWrite)) == 0)
+    || ((opts & (pipelineRead|pipelineWrite)) == (pipelineRead|pipelineWrite)))
+    errAbort("must specify one of pipelineRead or pipelineWrite to pipelineOpen");
+if ((opts & pipelineAppend) && ((opts & pipelineWrite) == 0))
+    errAbort("pipelineAppend is valid only in conjunction with pipelineWrite");
+}
+
+struct pipeline *pipelineOpenFd(char ***cmds, unsigned opts,
+                                int otherEndFd, int stderrFd)
+/* Create a pipeline from an array of commands.  See pipeline.h for
+ * full documentation. */
+{
+struct pipeline *pl;
+
+checkOpts(opts);
+pl = pipelineNew(cmds, opts);
+if (opts & pipelineRead)
+    pipelineStartRead(pl, otherEndFd, stderrFd, NULL, 0);
+else
+    pipelineStartWrite(pl, otherEndFd, stderrFd);
+return pl;
+}
+
+struct pipeline *pipelineOpen(char ***cmds, unsigned opts,
+                              char *otherEndFile, char *stderrFile)
+/* Create a pipeline from an array of commands.  See pipeline.h for
+ * full documentation */
+{
+int otherEndFd;
+int stderrFd = (stderrFile == NULL) ? STDERR_FILENO : openWrite(stderrFile, FALSE);
+
+checkOpts(opts);
+boolean append = ((opts & pipelineAppend) != 0);
+if (opts & pipelineRead)
+    otherEndFd = (otherEndFile == NULL) ? STDIN_FILENO : openRead(otherEndFile);
+else
+    otherEndFd = (otherEndFile == NULL) ? STDOUT_FILENO : openWrite(otherEndFile, append);
+struct pipeline *pl = pipelineOpenFd(cmds, opts, otherEndFd, stderrFd);
+safeClose(&otherEndFd);
+if (stderrFile != NULL)
+    safeClose(&stderrFd);
+return pl;
+}
+
+struct pipeline *pipelineOpenMem(char ***cmds, unsigned opts,
+                                 void *otherEndBuf, size_t otherEndBufSize,
+                                 int stderrFd)
+/* Create a pipeline from an array of commands, with the pipeline input/output
+ * in a memory buffer.  See pipeline.h for full documentation.  Currently only
+ * input to a read pipeline is supported  */
+{
+struct pipeline *pl;
+checkOpts(opts);
+if (opts & pipelineWrite)
+    errAbort("pipelineOpenMem only supports read pipelines at this time");
+opts |= pipelineMemInput;
+
+pl = pipelineNew(cmds, opts);
+pipelineStartRead(pl, STDIN_FILENO, stderrFd, otherEndBuf, otherEndBufSize);
+return pl;
+}
+
+struct pipeline *pipelineOpenFd1(char **cmd, unsigned opts,
+                                 int otherEndFd, int stderrFd)
+/* like pipelineOpenFd(), only takes a single command */
+{
+char **cmds[2];
+cmds[0] = cmd;
+cmds[1] = NULL;
+return pipelineOpenFd(cmds, opts, otherEndFd, stderrFd);
+}
+
+struct pipeline *pipelineOpen1(char **cmd, unsigned opts,
+                               char *otherEndFile, char *stderrFile)
+/* like pipelineOpen(), only takes a single command */
+{
+char **cmds[2];
+cmds[0] = cmd;
+cmds[1] = NULL;
+return pipelineOpen(cmds, opts, otherEndFile, stderrFile);
+}
+
+struct pipeline *pipelineOpenMem1(char **cmd, unsigned opts,
+                                  void *otherEndBuf, size_t otherEndBufSize,
+                                  int stderrFd)
+/* like pipelineOpenMem(), only takes a single command */
+{
+char **cmds[2];
+cmds[0] = cmd;
+cmds[1] = NULL;
+return pipelineOpenMem(cmds, opts, otherEndBuf, otherEndBufSize, stderrFd);
+}
+
+char *pipelineDesc(struct pipeline *pl)
+/* Get the description of a pipeline for use in error messages */
+{
+return pl->procName;
+}
+
+int pipelineFd(struct pipeline *pl)
+/* Get the file descriptor for a pipeline */
+{
+return pl->pipeFd;
+}
+
+FILE *pipelineFile(struct pipeline *pl)
+/* Get a FILE object wrapped around the pipeline.  Do not close the FILE, is
+ * owned by the pipeline object.  A FILE is created on first call to this
+ * function.  Subsequent calls return the same FILE.*/
+{
+if (pl->pipeFh == NULL)
+    {
+    /* create FILE* on first access */
+    char *mode = (pl->options & pipelineRead) ? "r" : "w";
+    if (pl->pipeLf != NULL)
+        errAbort("can't call pipelineFile after having associated a lineFile with a pipeline");
+    pl->pipeFh = fdopen(pl->pipeFd, mode);
+    if (pl->pipeFh == NULL)
+        errnoAbort("fdopen failed for: %s", pl->procName);
+    pl->stdioBuf = needLargeMem(FILE_BUF_SIZE);
+    setvbuf(pl->pipeFh, pl->stdioBuf,  _IOFBF, FILE_BUF_SIZE);
+    }
+return pl->pipeFh;
+}
+
+struct lineFile *pipelineLineFile(struct pipeline *pl)
+/* Get a lineFile object wrapped around the pipeline.  Do not close the
+ * lineFile, is owned by the pipeline object.  A lineFile is created on first
+ * call to this function.  Subsequent calls return the same object.*/
+{
+if (pl->pipeLf == NULL)
+    {
+    /* create line on first acess */
+    if (pl->pipeFh != NULL)
+        errAbort("can't call pipelineLineFile after having associated a FILE with a pipeline");
+    if (pl->options & pipelineWrite)
+        errAbort("can't associated a lineFile with a write pipeline");
+    pl->pipeLf = lineFileAttach(pipelineDesc(pl), TRUE, pl->pipeFd);
+    }
+return pl->pipeLf;
+}
+
+static void closePipelineFile(struct pipeline *pl)
+/* close a pipeline with a FILE associated with it */
+{
+if (pl->options & pipelineWrite)
+    {
+    fflush(pl->pipeFh);
+    if (ferror(pl->pipeFh))
+        errAbort("write failed to pipeline: %s ", pl->procName);
+    }
+else if (ferror(pl->pipeFh))
+    errAbort("read failed from pipeline: %s ", pl->procName);
+
+if (fclose(pl->pipeFh) == EOF)
+    errAbort("close failed on pipeline: %s ", pl->procName);
+pl->pipeFh = NULL;
+}
+
+static void closePipeline(struct pipeline *pl)
+/* Close the pipe file */
+{
+if (pl->pipeFh != NULL)
+    closePipelineFile(pl);
+else if (pl->pipeLf != NULL)
+    lineFileClose(&pl->pipeLf);
+else
+    {
+    if (close(pl->pipeFd) < 0)
+        errAbort("close failed on pipeline: %s ", pl->procName);
+    }
+pl->pipeFd = -1;
+}
+
+int pipelineWait(struct pipeline *pl)
+/* Wait for processes in a pipeline to complete; normally aborts if any
+ * process exists non-zero.  If pipelineNoAbort was specified, return the exit
+ * code of the first process exit non-zero, or zero if none failed. */
+{
+/* must close before waiting to so processes get pipe EOF */
+closePipeline(pl);
+return groupLeaderWait(pl);
+}
+
+void pipelineDumpCmds(char ***cmds)
+/* Dump out pipeline-formatted commands to stdout for debugging. */
+{
+char **cmd;
+boolean first = TRUE;
+while ((cmd = *cmds++) != NULL)
+   {
+   char *word;
+   if (first)
+      first = FALSE;
+   else
+      printf("| ");
+   while ((word = *cmd++) != NULL)
+       printf("%s ", word);
+   }
+printf("<BR>\n");
+}
+
+/*
+ * Local Variables:
+ * c-file-style: "jkent-c"
+ * End:
+ */
diff --git a/lib/pngwrite.c b/lib/pngwrite.c
new file mode 100644
index 0000000..debdd4b
--- /dev/null
+++ b/lib/pngwrite.c
@@ -0,0 +1,115 @@
+/* pngwrite.c - write out a memGfx to a PNG file, using the reference library libpng */
+/* (libpng is available from sourceforge and included in many open source distros,
+ *  has a wide-open license intended to encourage usage of the PNG format, and the lib
+ *  has been under development and testing for 14 years -- http://libpng.org/) */
+
+
+#include "png.h"   // MUST come before common.h, due to setjmp checking  in pngconf.h 
+#include "common.h"
+#include "memgfx.h"
+
+
+static void pngAbort(png_structp png, png_const_charp errorMessage)
+/* type png_error wrapper around errAbort */
+{
+errAbort("%s", (char *)errorMessage);
+}
+
+static void pngWarn(png_structp png, png_const_charp warningMessage)
+/* type png_error wrapper around warn */
+{
+warn("%s", (char *)warningMessage);
+}
+
+boolean mgSaveToPng(FILE *png_file, struct memGfx *mg, boolean useTransparency)
+/* Save PNG to an already open file.
+ * If useTransparency, then the first color in memgfx's colormap/palette is
+ * assumed to be the image background color, and pixels of that color
+ * are made transparent. */
+/* Reference: http://libpng.org/pub/png/libpng-1.2.5-manual.html */
+{
+if (!png_file || !mg)
+    errAbort("mgSaveToPng: called with a NULL");
+png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+					  NULL, // don't need pointer to data for err/warn handlers
+					  pngAbort, pngWarn);
+if (!png)
+    {
+    errAbort("png_write_struct failed");
+    return FALSE;
+    }
+png_infop info = png_create_info_struct(png);
+if (!info)
+    {
+    errAbort("png create_info_struct failed");
+    png_destroy_write_struct(&png, NULL);
+    return FALSE;
+    }
+
+// If setjmp returns nonzero, it means png_error is returning control here.
+// But that should not happen because png_error should call pngAbort which calls errAbort.
+if (setjmp(png_jmpbuf(png)))
+    {
+    png_destroy_write_struct(&png, &info);
+    fclose(png_file);
+    errAbort("pngwrite: setjmp nonzero.  "
+	     "why didn't png_error..pngAbort..errAbort stop execution before this errAbort?");
+    return FALSE;
+    }
+
+// Configure PNG output params:
+png_init_io(png, png_file);
+#ifdef COLOR32
+png_set_IHDR(png, info, mg->width, mg->height, 8, // 8=bit_depth
+             PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
+             PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+#else
+png_set_IHDR(png, info, mg->width, mg->height, 8, // 8=bit_depth
+             PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
+             PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+png_set_PLTE(png, info,
+             (png_color *)(mg->colorMap), // png_color is same as struct rgbColor!
+             mg->colorsUsed);
+#endif
+#ifndef COLOR32
+if (useTransparency)
+    {
+    // First palette color is assumed to be background/transparent, so
+    // that's the only one we need in the parallel array opacities[].
+    png_byte opacities[] = {0};
+    int num_opacities = ArraySize(opacities);
+    png_color_16p nonPalette_opacities_values = NULL; // n/a for us, we're using palette
+    png_set_tRNS(png, info, opacities, num_opacities, nonPalette_opacities_values);
+    }
+#endif
+
+// Write header/params, write pixels, close and clean up.
+// PNG wants a 2D array of pointers to byte offsets into palette/colorMap.
+// mg has a 1D array of byte offsets.  Make row pointers for PNG:
+
+png_byte **row_pointers = needMem(mg->height * sizeof(png_byte *));
+int i;
+for (i = 0;  i < mg->height;  i++)
+    row_pointers[i] = (unsigned char *)&(mg->pixels[i*mg->width]);
+png_set_rows(png, info, row_pointers);
+png_write_png(png, info, PNG_TRANSFORM_IDENTITY, // no transform
+	      NULL); // unused as of PNG 1.2
+png_destroy_write_struct(&png, &info);
+return TRUE;
+}
+
+void mgSavePng(struct memGfx *mg, char *filename, boolean useTransparency)
+/* Save memory bitmap to filename as a PNG.
+ * If useTransparency, then the first color in memgfx's colormap/palette is
+ * assumed to be the image background color, and pixels of that color
+ * are made transparent. */
+{
+FILE *pngFile = mustOpen(filename, "wb");
+if (!mgSaveToPng(pngFile, mg, useTransparency))
+    {
+    remove(filename);
+    errAbort("Couldn't save %s", filename);
+    }
+if (fclose(pngFile) != 0)
+    errnoAbort("fclose failed");
+}
diff --git a/lib/portimpl.c b/lib/portimpl.c
new file mode 100644
index 0000000..c0a7d19
--- /dev/null
+++ b/lib/portimpl.c
@@ -0,0 +1,136 @@
+/* Implementation file for some portability stuff mostly aimed
+ * at making the same code run under different web servers.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "htmshell.h"
+#include "portable.h"
+#include "obscure.h"
+#include "portimpl.h"
+#include <dirent.h>
+
+
+static struct webServerSpecific *wss = NULL;
+
+static void setupWss()
+{
+if (wss == NULL)
+    {
+    char *s = getenv("SERVER_SOFTWARE");
+    wss = &wssDefault;
+    if (s == NULL)
+        {
+	wss = &wssCommandLine;
+        }
+    else
+        {
+        if (strncmp(wssMicrosoftII.name, s, strlen(wssMicrosoftII.name)) == 0)
+            wss = &wssMicrosoftII;
+        else if (strncmp(wssMicrosoftPWS.name, s, strlen(wssMicrosoftPWS.name)) == 0)
+            wss = &wssMicrosoftPWS;
+	else 
+	    {
+	    char *t = getenv("HTTP_HOST");
+	    if (t != NULL)
+		{
+		if (sameWord(t, "Crunx"))
+		    wss = &wssLinux;
+		else if (endsWith(t, "brc.mcw.edu"))
+		    wss = &wssBrcMcw;
+		}
+	    }
+        }
+    }
+}
+
+void makeTempName(struct tempName *tn, char *base, char *suffix)
+/* Figure out a temp name, and how CGI and HTML will access it. */
+{
+setupWss();
+wss->makeTempName(tn,base,suffix);
+}
+
+char *cgiDir()
+{
+setupWss();
+return wss->cgiDir();
+}
+
+char *trashDir()
+/* Return the relative path to trash directory for CGI binaries */
+{
+setupWss();
+return wss->trashDir();
+}
+
+double machineSpeed()
+/* Return relative speed of machine.  UCSC CSE dept. 1999 web server is 1.0 */
+{
+setupWss();
+return wss->speed();
+}
+
+void envUpdate(char *name, char *value)
+/* Update an environment string */
+{
+int size = strlen(name) + strlen(value) + 2;
+char *s = needMem(size);
+safef(s, size, "%s=%s", name, value);
+putenv(s);
+}
+
+void mkdirTrashDirectory(char *prefix)
+/*	create the specified trash directory if it doesn't exist */
+{
+struct stat buf;
+char trashDirName[128];
+safef(trashDirName, sizeof(trashDirName), "%s/%s", trashDir(), prefix);
+if (stat(trashDirName,&buf))
+    {
+    int result = mkdir (trashDirName, S_IRWXU | S_IRWXG | S_IRWXO);
+    if (0 != result)
+	errnoAbort("failed to create directory %s", trashDirName);
+    }
+}
+
+
+void makeDirsOnPath(char *pathName)
+/* Create directory specified by pathName.  If pathName contains
+ * slashes, create directory at each level of path if it doesn't
+ * already exist.  Abort with error message if there's a problem.
+ * (It's not considered a problem for the directory to already
+ * exist. ) */
+{
+
+/* shortcut for paths that already exist */
+if (fileExists(pathName))
+    return;
+
+/* Make local copy of pathName. */
+int len = strlen(pathName);
+char pathCopy[len+1];
+strcpy(pathCopy, pathName);
+
+/* Tolerate double-slashes in path, everyone else does it. */
+
+/* Start at root if it's an absolute path name. */
+char *s = pathCopy, *e;
+while (*s++ == '/')
+    /* do nothing */;
+
+/* Step through it one slash at a time 
+ * making directory if possible, else dying. */
+for (; !isEmpty(s); s = e)
+    {
+    /* Find end of this section and terminate string there. */
+    e = strchr(s, '/');
+    if (e != NULL)
+	*e = 0;
+    makeDir(pathCopy);
+    if (e != NULL)
+	*e++ = '/';
+    }
+}
+
diff --git a/lib/portimpl.h b/lib/portimpl.h
new file mode 100644
index 0000000..9beadb4
--- /dev/null
+++ b/lib/portimpl.h
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * Copyright (C) 2000 Jim Kent.  This source code may be freely used         *
+ * for personal, academic, and non-profit purposes.  Commercial use          *
+ * permitted only by explicit agreement with Jim Kent (jim_kent at pacbell.net) *
+ *****************************************************************************/
+/* Implement portable stuff.... */
+
+/* There is one of the following structures for each web server
+ * we support.  During run time looking at the environment variable
+ * SERVER_SOFTWARE we decide which of these to use. */
+struct webServerSpecific
+    {
+    char *name;
+
+    /* Make a good name for a temp file. */
+    void (*makeTempName)(struct tempName *tn, char *base, char *suffix);
+
+    /* Return directory to look for cgi in. */
+    char * (*cgiDir)();
+
+#ifdef NEVER
+    /* Return cgi suffix. */
+    char * (*cgiSuffix)();
+#endif /* NEVER */
+    
+    /* Return relative speed of CPU. (UCSC CSE 1999 FTP machine is 1.0) */
+    double (*speed)();
+
+    /* The relative path to trash directory for CGI binaries */
+    char * (*trashDir)();
+
+    };
+
+
+extern struct webServerSpecific wssMicrosoftII, wssMicrosoftPWS, wssDefault,
+	wssLinux, wssCommandLine, wssBrcMcw;
+
+char *rTempName(char *dir, char *base, char *suffix);
+/* Make a temp name that's almost certainly unique. */
diff --git a/lib/ppc/placeHolder.c b/lib/ppc/placeHolder.c
new file mode 100755
index 0000000..e69de29
diff --git a/lib/psGfx.c b/lib/psGfx.c
new file mode 100644
index 0000000..58fc56e
--- /dev/null
+++ b/lib/psGfx.c
@@ -0,0 +1,409 @@
+/* PostScript graphics - 
+ * This provides a bit of a shell around writing graphics to
+ * a postScript file.  Perhaps the most important thing it
+ * does is convert 0,0 from being at the bottom left to
+ * being at the top left. */
+#include "common.h"
+#include "psPoly.h"
+#include "psGfx.h"
+#include "linefile.h"
+
+
+static void psFloatOut(FILE *f, double x)
+/* Write out a floating point number, but not in too much
+ * precision. */
+{
+int i = round(x);
+if (i == x)
+   fprintf(f, "%d ", i);
+else
+   fprintf(f, "%0.4f ", x);
+}
+
+void psClipRect(struct psGfx *ps, double x, double y, 
+	double width, double height)
+/* Set clipping rectangle. */
+{
+FILE *f = ps->f;
+fprintf(f, "cliprestore ");
+psXyOut(ps, x, y+height); 
+psWhOut(ps, width, height);       
+fprintf(f, "rectclip\n");
+}
+
+static void psWriteHeader(FILE *f, double width, double height)
+/* Write postScript header.  It's encapsulated PostScript
+ * actually, so you need to supply image width and height
+ * in points. */
+{
+char *s =
+#include "common.pss"
+;
+
+fprintf(f, "%%!PS-Adobe-3.1 EPSF-3.0\n");
+fprintf(f, "%%%%BoundingBox: 0 0 %d %d\n", (int)ceil(width), (int)ceil(height));
+fprintf(f, "%%%%LanguageLevel: 3\n\n");
+fprintf(f, "%s", s);
+}
+
+void psSetLineWidth(struct psGfx *ps, double factor)
+/* Set line width to factor * a single pixel width. */
+{
+fprintf(ps->f, "%f setlinewidth\n", factor * ps->xScale);
+}
+
+struct psGfx *psOpen(char *fileName, 
+	double userWidth, double userHeight, /* Dimension of image in user's units. */
+	double ptWidth, double ptHeight,     /* Dimension of image in points. */
+	double ptMargin)                     /* Image margin in points. */
+/* Open up a new postscript file.  If ptHeight is 0, it will be
+ * calculated to keep pixels square. */
+{
+struct psGfx *ps;
+
+/* Allocate structure and open file. */
+AllocVar(ps);
+ps->f = mustOpen(fileName, "w");
+
+/* Save page dimensions and calculate scaling factors. */
+ps->userWidth = userWidth;
+ps->userHeight = userHeight;
+ps->ptWidth = ptWidth;
+ps->xScale = (ptWidth - 2*ptMargin)/userWidth;
+if (ptHeight != 0.0)
+   {
+   ps->ptHeight = ptHeight;
+   ps->yScale = (ptHeight - 2*ptMargin) / userHeight;
+   }
+else
+   {
+   ps->yScale = ps->xScale;
+   ptHeight = ps->ptHeight = userHeight * ps->yScale + 2*ptMargin;
+   }
+/* 0.5, 0.5 is the center of the pixel in upper-left corner which corresponds to (0,0) */
+ps->xOff = ptMargin;
+ps->yOff = ptMargin;
+ps->fontHeight = 10;
+
+/* Cope with fact y coordinates are bottom to top rather
+ * than top to bottom. */
+ps->yScale = -ps->yScale;
+ps->yOff = ps->ptHeight - ps->yOff;
+
+psWriteHeader(ps->f, ptWidth, ptHeight);
+
+/* adding a gsave here fixes an old ghostview bug with cliprestore */
+fprintf(ps->f, "gsave\n");
+
+/* Set initial clipping rectangle. */
+psClipRect(ps, 0, 0, ps->userWidth, ps->userHeight);
+
+/* Set line width to a single pixel. */
+psSetLineWidth(ps,1);
+
+return ps;
+}
+
+void psTranslate(struct psGfx *ps, double xTrans, double yTrans)
+/* add a constant to translate all coordinates */
+{
+ps->xOff += xTrans*ps->xScale;   
+ps->yOff += yTrans*ps->yScale;
+}
+
+void psClose(struct psGfx **pPs)
+/* Close out postScript file. */
+{
+struct psGfx *ps = *pPs;
+if (ps != NULL)
+    {
+    carefulClose(&ps->f);
+    freez(pPs);
+    }
+}
+
+void psXyOut(struct psGfx *ps, double x, double y)
+/* Output x,y position transformed into PostScript space. */
+{
+FILE *f = ps->f;
+psFloatOut(f, x * ps->xScale + ps->xOff);
+psFloatOut(f, y * ps->yScale + ps->yOff);
+}
+
+void psWhOut(struct psGfx *ps, double width, double height)
+/* Output width/height transformed into PostScript space. */
+{
+FILE *f = ps->f;
+psFloatOut(f, width * ps->xScale);
+psFloatOut(f, height * -ps->yScale);
+}
+
+void psMoveTo(struct psGfx *ps, double x, double y)
+/* Move PostScript position to given point. */
+{
+psXyOut(ps, x, y);
+fprintf(ps->f, "moveto\n");
+}
+
+void psLineTo(struct psGfx *ps, double x, double y)
+/* Draw line from current point to given point,
+ * and make given point new current point. */
+{
+psXyOut(ps, x, y);
+fprintf(ps->f, "lineto\n");
+}
+
+void psDrawBox(struct psGfx *ps, double x, double y, 
+	double width, double height)
+/* Draw a filled box in current color. */
+{
+if (width > 0 && height > 0)
+    {
+    psWhOut(ps, width, height);
+    psXyOut(ps, x, y+height); 
+    fprintf(ps->f, "fillBox\n");
+    }
+}
+
+void psDrawLine(struct psGfx *ps, double x1, double y1, double x2, double y2)
+/* Draw a line from x1/y1 to x2/y2 */
+{
+FILE *f = ps->f;
+fprintf(f, "newpath\n");
+psMoveTo(ps, x1, y1);
+psXyOut(ps, x2, y2);
+fprintf(ps->f, "lineto\n");
+fprintf(f, "stroke\n");
+}
+
+void psFillUnder(struct psGfx *ps, double x1, double y1, 
+	double x2, double y2, double bottom)
+/* Draw a 4 sided filled figure that has line x1/y1 to x2/y2 at
+ * it's top, a horizontal line at bottom at it's bottom,  and
+ * vertical lines from the bottom to y1 on the left and bottom to
+ * y2 on the right. */
+{
+FILE *f = ps->f;
+fprintf(f, "newpath\n");
+psMoveTo(ps, x1, y1);
+psLineTo(ps, x2, y2);
+psLineTo(ps, x2, bottom);
+psLineTo(ps, x1, bottom);
+fprintf(f, "closepath\n");
+fprintf(f, "fill\n");
+}
+
+void psTimesFont(struct psGfx *ps, double size)
+/* Set font to times of a certain size. */
+{
+FILE *f = ps->f;
+fprintf(f, "/Helvetica findfont ");
+
+/* Note the 1.2 and the 1.0 below seem to get it to 
+ * position about where the stuff developed for pixel
+ * based systems expects it.  It is all a kludge though! */
+fprintf(f, "%f scalefont setfont\n", -size*ps->yScale*1.2);
+ps->fontHeight = size*0.8;
+}
+
+void psTextBox(struct psGfx *ps, double x, double y, char *text)
+/* Output text in current font at given position. */
+{
+char c;
+psMoveTo(ps, x, y + ps->fontHeight);
+fprintf(ps->f, "(");
+while ((c = *text++) != 0)
+    {
+    if (c == ')' || c == '(')
+        fprintf(ps->f, "\\");
+    fprintf(ps->f, "%c", c);
+    }
+fprintf(ps->f, ") fillTextBox\n");
+}
+
+void psTextAt(struct psGfx *ps, double x, double y, char *text)
+/* Output text in current font at given position. */
+{
+char c;
+psMoveTo(ps, x, y + ps->fontHeight);
+fprintf(ps->f, "(");
+while ((c = *text++) != 0)
+    {
+    if (c == ')' || c == '(')
+        fprintf(ps->f, "\\");
+    fprintf(ps->f, "%c", c);
+    }
+fprintf(ps->f, ") show\n");
+}
+
+void psTextRight(struct psGfx *ps, double x, double y, 
+	double width, double height, 
+	char *text)
+/* Draw a line of text right justified in box defined by x/y/width/height */
+{
+y += (height - ps->fontHeight)/2;
+psMoveTo(ps, x+width, y + ps->fontHeight);
+fprintf(ps->f, "(%s) showBefore\n", text);
+}
+
+void psTextCentered(struct psGfx *ps, double x, double y, 
+	double width, double height, 
+	char *text)
+/* Draw a line of text centered in box defined by x/y/width/height */
+{
+char c;
+y += (height - ps->fontHeight)/2;
+psMoveTo(ps, x+width/2, y + ps->fontHeight);
+fprintf(ps->f, "(");
+while ((c = *text++) != 0)
+    {
+    if (c == ')' || c == '(')
+        fprintf(ps->f, "\\");
+    fprintf(ps->f, "%c", c);
+    }
+fprintf(ps->f, ") showMiddle\n");
+}
+
+void psTextDown(struct psGfx *ps, double x, double y, char *text)
+/* Output text going downwards rather than across at position. */
+{
+psMoveTo(ps, x, y);
+fprintf(ps->f, "gsave\n");
+fprintf(ps->f, "-90 rotate\n");
+fprintf(ps->f, "(%s) show\n", text);
+fprintf(ps->f, "grestore\n");
+}
+
+void psSetColor(struct psGfx *ps, int r, int g, int b)
+/* Set current color. */
+{
+FILE *f = ps->f;
+double scale = 1.0/255;
+if (r == g && g == b)
+    {
+    psFloatOut(f, scale * r);
+    fprintf(f, "setgray\n");
+    }
+else
+    {
+    psFloatOut(f, scale * r);
+    psFloatOut(f, scale * g);
+    psFloatOut(f, scale * b);
+    fprintf(f, "setrgbcolor\n");
+    }
+}
+
+void psSetGray(struct psGfx *ps, double grayVal)
+/* Set gray value. */
+{
+FILE *f = ps->f;
+if (grayVal < 0) grayVal = 0;
+if (grayVal > 1) grayVal = 1;
+psFloatOut(f, grayVal);
+fprintf(f, "setgray\n");
+}
+
+void psPushG(struct psGfx *ps)
+/* Save graphics state on stack. */
+{
+fprintf(ps->f, "gsave\n");
+}
+
+void psPopG(struct psGfx *ps)
+/* Pop off saved graphics state. */
+{
+fprintf(ps->f, "grestore\n");
+}
+
+void psDrawPoly(struct psGfx *ps, struct psPoly *poly, boolean filled)
+/* Draw a possibly filled polygon */
+{
+FILE *f = ps->f;
+struct psPoint *p = poly->ptList;
+fprintf(f, "newpath\n");
+psMoveTo(ps, p->x, p->y);
+for (;;)
+    {
+    p = p->next;
+    psLineTo(ps, p->x, p->y);
+    if (p == poly->ptList)
+	break;
+    }
+if (filled)
+    {
+    fprintf(f, "fill\n");
+    }
+else
+    {
+    fprintf(f, "closepath\n");
+    fprintf(f, "stroke\n");
+    }
+}
+
+
+void psFillEllipse(struct psGfx *ps, double x, double y, double xrad, double yrad)
+{
+FILE *f = ps->f;
+fprintf(f, "newpath\n");
+psXyOut(ps, x, y);
+psWhOut(ps, xrad, yrad);
+psFloatOut(f, 0.0);
+psFloatOut(f, 360.0);
+fprintf(f, "ellipse\n");
+fprintf(f, "closepath\n");
+fprintf(f, "fill\n");
+}
+
+void psDrawEllipse(struct psGfx *ps, double x, double y, double xrad, double yrad,
+    double startAngle, double endAngle)
+{
+FILE *f = ps->f;
+fprintf(f, "newpath\n");
+psXyOut(ps, x, y);
+psWhOut(ps, xrad, yrad);
+psFloatOut(f, startAngle);
+psFloatOut(f, endAngle);
+fprintf(f, "ellipse\n");
+fprintf(f, "closepath\n");
+fprintf(f, "stroke\n");
+}
+
+char * convertEpsToPdf(char *epsFile) 
+/* Convert EPS to PDF and return filename, or NULL if failure. */
+{
+char *pdfTmpName = NULL, *pdfName=NULL;
+char cmdBuffer[2048];
+int sysVal = 0;
+struct lineFile *lf = NULL;
+char *line;
+int lineSize=0;
+float width=0, height=0;
+pdfTmpName = cloneString(epsFile);
+
+/* Get the dimensions of bounding box. */
+lf = lineFileOpen(epsFile, TRUE);
+while(lineFileNext(lf, &line, &lineSize)) 
+    {
+    if(strstr( line, "BoundingBox:")) 
+	{
+	char *words[5];
+	chopLine(line, words);
+	width = atof(words[3]);
+	height = atof(words[4]);
+	break;
+	}
+    }
+lineFileClose(&lf);
+	
+/* Do conversion. */
+chopSuffix(pdfTmpName);
+pdfName = addSuffix(pdfTmpName, ".pdf");
+safef(cmdBuffer, sizeof(cmdBuffer), "ps2pdf -dDEVICEWIDTHPOINTS=%d -dDEVICEHEIGHTPOINTS=%d %s %s", 
+      round(width), round(height), epsFile, pdfName);
+sysVal = system(cmdBuffer);
+if(sysVal != 0)
+    freez(&pdfName);
+freez(&pdfTmpName);
+return pdfName;
+}
+
diff --git a/lib/psPoly.c b/lib/psPoly.c
new file mode 100644
index 0000000..e9df86e
--- /dev/null
+++ b/lib/psPoly.c
@@ -0,0 +1,49 @@
+/* psPoly - two dimensional polygon. */
+#include "common.h"
+#include "psPoly.h"
+
+
+struct psPoly *psPolyNew()
+/* Create new (empty) polygon */
+{
+struct psPoly *poly;
+AllocVar(poly);
+return poly;
+}
+
+void psPolyFree(struct psPoly **pPoly)
+/* Free up resources associated with polygon */
+{
+struct psPoly *poly = *pPoly;
+if (poly != NULL)
+    {
+    if (poly->lastPoint != NULL)
+	{
+	poly->lastPoint->next = NULL;
+	slFreeList(&poly->ptList);
+	}
+    freez(pPoly);
+    }
+}
+
+void psPolyAddPoint(struct psPoly *poly, double x, double y)
+/* Add point to polygon. */
+{
+struct psPoint *pt;
+poly->ptCount += 1;
+AllocVar(pt);
+pt->x = x;
+pt->y = y;
+if (poly->ptList == NULL)
+    {
+    poly->ptList = poly->lastPoint = pt;
+    pt->next = pt;
+    }
+else
+    {
+    poly->lastPoint->next = pt;
+    pt->next = poly->ptList;
+    poly->lastPoint = pt;
+    }
+}
+
diff --git a/lib/pscmGfx.c b/lib/pscmGfx.c
new file mode 100644
index 0000000..af30b54
--- /dev/null
+++ b/lib/pscmGfx.c
@@ -0,0 +1,816 @@
+/* pscmGfx - routines for making postScript output seem a
+ * lot like 256 color bitmap output. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include <math.h>
+#ifdef MACHTYPE_sparc
+#include <ieeefp.h>
+int isinf(double x) { return !finite(x) && x==x; }
+#endif
+#include "common.h"
+#include "hash.h"
+#include "memgfx.h"
+#include "gfxPoly.h"
+#include "colHash.h"
+#include "psGfx.h"
+#include "pscmGfx.h"
+#include "gemfont.h"
+#include "vGfx.h"
+#include "vGfxPrivate.h"
+
+
+
+static struct pscmGfx *boxPscm;	 /* Used to keep from drawing the same box again
+                                  * and again with no other calls between.  This
+				  * ends up cutting down the file size by 5x
+				  * in the whole chromosome case of the browser. */
+
+void pscmSetHint(struct pscmGfx *pscm, char *hint, char *value)
+/* set a hint */
+{
+if (!value) return;
+if (sameString(value,""))
+    {
+    hashRemove(pscm->hints, hint);
+    }
+struct hashEl *el = hashLookup(pscm->hints, hint);
+if (el) 
+    {
+    freeMem(el->val);
+    el->val = cloneString(value);
+    }
+else
+    {
+    hashAdd(pscm->hints, hint, cloneString(value));
+    }
+}
+
+char *pscmGetHint(struct pscmGfx *pscm, char *hint)
+/* get a hint */
+{
+return hashOptionalVal(pscm->hints, hint, "");
+}
+
+int pscmGetFontPixelHeight(struct pscmGfx *pscm, MgFont *font)
+/* How high in pixels is font? */
+{
+return font_cel_height(font);
+}
+
+int pscmGetFontStringWidth(struct pscmGfx *pscm, MgFont *font, char *string)
+/* How wide is a string? */
+{
+return fnstring_width(font, (unsigned char *)string, strlen(string));
+}
+
+void pscmSetClip(struct pscmGfx *pscm, int x, int y, int width, int height)
+/* Set clipping rectangle. */
+{
+double x2 = x + width;
+double y2 = y + height;
+pscm->clipMinX = x;
+pscm->clipMinY = y;
+pscm->clipMaxX = x2;     /* one beyond actual last pixel */
+pscm->clipMaxY = y2;
+/* adjust to pixel-centered coordinates */
+x2 -= 1;
+y2 -= 1;
+double x1 = x;
+double y1 = y;
+/* pad a half-pixel all the way around the box */
+x1 -= 0.5;
+y1 -= 0.5;
+x2 += 0.5;
+y2 += 0.5;
+psClipRect(pscm->ps, x1, y1, x2-x1, y2-y1);
+}
+
+void pscmUnclip(struct pscmGfx *pscm)
+/* Set clipping rect to cover full thing. */
+{
+pscmSetClip(pscm, 0, 0, pscm->ps->userWidth, pscm->ps->userHeight);
+}
+
+#ifndef COLOR32
+static Color pscmClosestColor(struct pscmGfx *pscm, 
+	unsigned char r, unsigned char g, unsigned char b)
+/* Returns closest color in color map to r,g,b */
+{
+struct rgbColor *c = pscm->colorMap;
+int closestDist = 0x7fffffff;
+int closestIx = -1;
+int dist, dif;
+int i;
+
+for (i=0; i<pscm->colorsUsed; ++i)
+    {
+    dif = c->r - r;
+    dist = dif*dif;
+    dif = c->g - g;
+    dist += dif*dif;
+    dif = c->b - b;
+    dist += dif*dif;
+    if (dist < closestDist)
+        {
+        closestDist = dist;
+        closestIx = i;
+        }
+    ++c;
+    }
+return closestIx;
+}
+
+static Color pscmAddColor(struct pscmGfx *pscm, 
+	unsigned char r, unsigned char g, unsigned char b)
+/* Adds color to end of color map if there's room. */
+{
+int colIx = pscm->colorsUsed;
+struct rgbColor *c = pscm->colorMap + pscm->colorsUsed;
+c->r = r;
+c->g = g;
+c->b = b;
+pscm->colorsUsed += 1;
+colHashAdd(pscm->colorHash, r, g, b, colIx);;
+return (Color)colIx;
+}
+#endif
+
+int pscmFindColorIx(struct pscmGfx *pscm, int r, int g, int b)
+/* Returns closest color in color map to rgb values.  If it doesn't
+ * already exist in color map and there's room, it will create
+ * exact color in map. */
+{
+#ifdef COLOR32
+return MAKECOLOR_32(r,g,b);
+#else
+struct colHashEl *che;
+if (r>255||g>255||b>255) 
+    errAbort("RGB values out of range (0-255).  r:%d g:%d b:%d", r, g, b);
+if ((che = colHashLookup(pscm->colorHash, r, g, b)) != NULL)
+    return che->ix;
+if (pscm->colorsUsed < 256)
+    return pscmAddColor(pscm, r, g, b);
+return pscmClosestColor(pscm, r, g, b);
+#endif
+}
+
+
+struct rgbColor pscmColorIxToRgb(struct pscmGfx *pscm, int colorIx)
+/* Return rgb value at color index. */
+{
+#ifdef COLOR32
+static struct rgbColor rgb;
+rgb.r = (colorIx >> 0) & 0xff;
+rgb.g = (colorIx >> 8) & 0xff;
+rgb.b = (colorIx >> 16) & 0xff;
+
+return rgb;
+#else
+return pscm->colorMap[colorIx];
+#endif
+}
+
+#ifndef COLOR32
+static void pscmSetDefaultColorMap(struct pscmGfx *pscm)
+/* Set up default color map for a memGfx. */
+{
+/* Note dependency in order here and in MG_WHITE, MG_BLACK, etc. */
+int i;
+for (i=0; i<ArraySize(mgFixedColors); ++i)
+    {
+    struct rgbColor *c = &mgFixedColors[i];
+    pscmFindColorIx(pscm, c->r, c->g, c->b);
+    }
+}
+#endif
+
+void pscmSetWriteMode(struct pscmGfx *pscm, unsigned int writeMode)
+/* Set write mode */
+{
+pscm->writeMode = writeMode;
+}
+
+struct pscmGfx *pscmOpen(int width, int height, char *file)
+/* Return new pscmGfx. */
+{
+struct pscmGfx *pscm;
+
+AllocVar(pscm);
+pscm->ps = psOpen(file, width, height, 72.0 * 7.5, 0, 0);
+psTranslate(pscm->ps,0.5,0.5);  /* translate all coordinates to pixel centers */
+#ifndef COLOR32
+pscm->colorHash = colHashNew();
+pscmSetDefaultColorMap(pscm);
+#endif
+pscm->clipMinX = pscm->clipMinY = 0;
+pscm->clipMaxX = width;     
+pscm->clipMaxY = height;
+pscm->hints = hashNew(6);
+return pscm;
+}
+
+void pscmClose(struct pscmGfx **pPscm)
+/* Finish writing out and free structure. */
+{
+struct pscmGfx *pscm = *pPscm;
+if (pscm != NULL)
+    {
+    psClose(&pscm->ps);
+    colHashFree(&pscm->colorHash);
+    freez(pPscm);
+    }
+}
+
+void pscmSetColor(struct pscmGfx *pscm, Color color)
+/* Set current color to Color. */
+{
+struct rgbColor *col;
+
+#ifdef COLOR32
+struct rgbColor myCol;
+col = &myCol;
+
+col->r = (color >> 0) & 0xff;
+col->g = (color >> 8) & 0xff;
+col->b = (color >> 16) & 0xff;
+#else
+col = pscm->colorMap + color;
+#endif
+
+if (color != pscm->curColor)
+    {
+    psSetColor(pscm->ps, col->r, col->g, col->b);
+    pscm->curColor = color;
+    }
+}
+
+void pscmBoxToPs(struct pscmGfx *pscm, int x, int y, 
+	int width, int height)
+/* adjust coordinates for PS */
+{
+/* Do some clipping here to make the postScript
+ * easier to edit in illustrator. */
+double x2 = x + width;
+double y2 = y + height;
+
+if (x < pscm->clipMinX) x = pscm->clipMinX;
+if (y < pscm->clipMinY) y = pscm->clipMinY;
+if (x2 > pscm->clipMaxX) x2 = pscm->clipMaxX;
+if (y2 > pscm->clipMaxY) y2 = pscm->clipMaxY;
+
+/* adjust to pixel-centered coordinates */
+x2 -= 1;
+y2 -= 1;
+double x1 = x;
+double y1 = y;
+/* pad a half-pixel all the way around the box */
+x1 -= 0.5;
+y1 -= 0.5;
+x2 += 0.5;
+y2 += 0.5;
+psDrawBox(pscm->ps, x1, y1, x2-x1, y2-y1);
+}
+
+void pscmBox(struct pscmGfx *pscm, int x, int y, 
+	int width, int height, int color)
+/* Draw a box. */
+{
+/* When viewing whole chromosomes the browser tends
+ * to draw the same little vertical tick over and
+ * over again.  This tries to remove the worst of
+ * the redundancy anyway. */
+
+static int lx, ly, lw, lh, lc=-1;
+if (x != lx || y != ly || width != lw || height != lh || color != lc || 
+	pscm != boxPscm)
+    {
+    pscmSetColor(pscm, color);
+    pscmBoxToPs(pscm, x, y, width, height);
+    lx = x;
+    ly = y;
+    lw = width;
+    lh = height;
+    lc = color;
+    boxPscm = pscm;
+    }
+}
+
+void pscmDot(struct pscmGfx *pscm, int x, int y, int color)
+/* Set a dot. */
+{
+pscmBox(pscm, x, y, 1, 1, color);
+}
+
+
+
+static void pscmVerticalSmear(struct pscmGfx *pscm,
+	int xOff, int yOff, int width, int height, 
+	Color *dots, boolean zeroClear)
+/* Put a series of one 'pixel' width vertical lines. */
+{
+int x, i;
+struct psGfx *ps = pscm->ps;
+Color c;
+for (i=0; i<width; ++i)
+    {
+    x = xOff + i;
+    c = dots[i];
+    if (c != MG_WHITE || !zeroClear)
+	{
+	pscmSetColor(pscm, c);
+	psDrawBox(ps, x, yOff, 1, height);
+	}
+    }
+}
+
+static void pscmSetFont(struct pscmGfx *pscm, MgFont *font)
+/* Set font. */
+{
+/* For now we basically still get the sizing info from the old
+ * gem fonts.   I'm not sure how to get sizing info out of
+ * PostScript.  We'll try and arrange it so that the PostScript
+ * fonts match the gem fonts more or less. */
+void *v = font;
+if (v != pscm->curFont)
+    {
+    psTimesFont(pscm->ps, font->psHeight);
+    pscm->curFont = v;
+    }
+}
+
+void pscmText(struct pscmGfx *pscm, int x, int y, int color, 
+	MgFont *font, char *text)
+/* Draw a line of text with upper left corner x,y. */
+{
+pscmSetColor(pscm, color);
+pscmSetFont(pscm, font);
+psTextAt(pscm->ps, x, y, text);
+boxPscm = NULL;
+}
+
+void pscmTextRight(struct pscmGfx *pscm, int x, int y, int width, int height,
+	int color, MgFont *font, char *text)
+/* Draw a line of text right justified in box defined by x/y/width/height */
+{
+pscmSetColor(pscm, color);
+pscmSetFont(pscm, font);
+psTextRight(pscm->ps, x, y, width, height, text);
+boxPscm = NULL;
+}
+
+void pscmTextCentered(struct pscmGfx *pscm, int x, int y, 
+	int width, int height, int color, MgFont *font, char *text)
+/* Draw a line of text centered in box defined by x/y/width/height */
+{
+pscmSetColor(pscm, color);
+pscmSetFont(pscm, font);
+psTextCentered(pscm->ps, x, y, width, height, text);
+boxPscm = NULL;
+}
+
+void pscmFillUnder(struct pscmGfx *pscm, int x1, int y1, int x2, int y2, 
+	int bottom, Color color)
+/* Draw a 4 sided filled figure that has line x1/y1 to x2/y2 at
+ * it's top, a horizontal line at bottom at it's bottom,  and
+ * vertical lines from the bottom to y1 on the left and bottom to
+ * y2 on the right. */
+{
+pscmSetColor(pscm, color);
+psFillUnder(pscm->ps, x1, y1, x2, y2, bottom);
+boxPscm = NULL;
+}
+
+void psPolyFindExtremes(struct gfxPoly *poly, 
+  int *pMinX, int *pMaxX,  
+  int *pMinY, int *pMaxY)
+/* find min and max of x and y */
+{
+struct gfxPoint *p = poly->ptList;
+int minX, maxX, minY, maxY;
+minX = maxX =  p->x;
+minY = maxY =  p->y;
+for (;;)
+    {
+    p = p->next;
+    if (p == poly->ptList)
+	break;
+    if (minX > p->x) minX = p->x;
+    if (minY > p->y) minY = p->y;
+    if (maxX < p->x) maxX = p->x;
+    if (maxY < p->y) maxY = p->y;
+    }
+*pMinX = minX;
+*pMaxX = maxX;
+*pMinY = minY;
+*pMaxY = maxY;
+}
+
+double gfxSlope(struct gfxPoint *q, struct gfxPoint *p)
+/* determine slope from two gfxPoints */
+{
+double dx = p->x - q->x;
+double dy = p->y - q->y;
+return dy/dx;
+}
+
+boolean colinearPoly(struct gfxPoly *poly)
+/* determine if points are co-linear */
+{
+if (poly->ptCount < 2) return TRUE;
+struct gfxPoint *q = poly->ptList, *p=q->next;
+double m0 = gfxSlope(q,p);
+for (;;)
+    {
+    p = p->next;
+    if (p == poly->ptList)
+	break;
+    double m1 = gfxSlope(q,p);
+    if (!(isinf(m0) && isinf(m1)) && (m1 != m0))
+	return FALSE;
+    }
+return TRUE;
+}
+
+double fatPixel(double c, double center, double fat)
+/* fatten coordinate by scaling */
+{
+return center+((c-center)*fat);
+}
+
+
+void pscmPolyFatten(struct psPoly *psPoly, 
+  int minX, int maxX, int minY, int maxY)
+/* Fatten polygon by finding the center and then
+ * scaling by 0.5 pixel from the center in all directions.
+ * Caller assures dx and dy will NOT be zero. */
+{
+int dx = maxX - minX;
+int dy = maxY - minY;
+double centerX = (maxX + minX) / 2.0;
+double centerY = (maxY + minY) / 2.0;
+double fatX = (dx + 1.0)/dx;
+double fatY = (dy + 1.0)/dy;
+struct psPoint *p = psPoly->ptList;
+for (;;)
+    {
+    p->x = fatPixel(p->x, centerX, fatX);
+    p->y = fatPixel(p->y, centerY, fatY);
+    p = p->next;
+    if (p == psPoly->ptList)
+	break;
+    }
+}
+
+void findLineParams(double x1, double y1, double x2, double y2, double *m, double *b)
+/* Return parameters slope m and y-intercept b of equation for line from x1,y1 to x2,y2, 
+ * vertical lines return infinite slope with b = x value instead */
+{
+double dx = x2 - x1;
+double dy = y2 - y1;
+*m = dy/dx;
+if (dx == 0)
+    *b = x1;
+else
+    *b = y1 - (*m)*x1;
+}
+
+
+double bDeltaForParallelLine(double d, double m)
+/* find delta-b value for parallel line at distance d for line slope m */
+{
+return d * sqrt(1 + m*m); /* do not call with m == infinity */
+}
+
+void adjustBForParallelLine(boolean cw, double m, 
+double x1, double y1, 
+double x2, double y2, 
+double *b)
+/* adjust the b value for parallel line at distance d for line slope m 
+ *  cw if clockwise */
+{
+if (isinf(m))  /* handle vertical lines */
+    {
+    if ((cw && (y2 < y1)) || (!cw && (y2 > y1)))
+	*b += 1;   /* b holds x-value rather than y-intercept */
+    else
+	*b -= 1;
+    }
+else
+    {
+    /* Y axis is increasing downwards */
+    double bDelta = bDeltaForParallelLine(1.0, m);
+    if ((cw && (x2 > x1)) || (!cw && (x2 < x1)))
+       *b += bDelta; 
+    else
+       *b -= bDelta;
+    }
+}
+
+void findLinesIntersection(boolean cw, double m0, double b0, double m1, double b1, 
+double px, double py, boolean posDeltaX, boolean posDeltaY,
+double *ix, double *iy)
+/* find intersection between two lines */
+{
+
+/* colinear vert */
+if ((isinf(m0) && isinf(m1)) && (b0 == b1)) 
+    {
+    if (cw ^ posDeltaY)
+    	*ix = px+1;
+    else
+    	*ix = px-1;
+    *iy = py; 
+    }
+/* colinear horiz */
+else if (((m0==0)&&(m1==0)) && (b0 == b1)) 
+    {
+    if (cw ^ posDeltaX)
+    	*iy = py+1;
+    else
+    	*iy = py-1;
+    *ix = px; 
+    }
+/* colinear */
+else if ((m0 == m1) && (b0 == b1))  
+    {
+    /* inner point shifted 1 pixel away from the point,
+     *   moving perpendicular to m0 towards the center */
+
+    double dx, dy;
+    double m = -1/m0; 
+    dx = sqrt(1/(1+m*m));
+    dy = m * dx;
+
+    if (!(cw ^ posDeltaX))
+	{
+	*ix = px + dx;
+	*iy = py + dy;
+	}
+    else
+	{
+	*ix = px - dx;
+	*iy = py - dy;
+	}
+
+    }
+/* non-colinear */
+else
+    {
+    if (isinf(m0) && isinf(m1))
+	{  /* should be handled earlier by colinear vert lines above */
+	errAbort("pscmGfx: m0 and m1 both inf, shouldn't get here");
+	}
+    else if (!isinf(m0) && isinf(m1))
+	{
+    	*ix = b1;
+	*iy = m0*(*ix)+b0;
+	}
+    else if (isinf(m0) && !isinf(m1))
+	{
+    	*ix = b0;
+	*iy = m1*(*ix)+b1;
+	}
+    else if (!isinf(m0) && !isinf(m1))
+	{
+    	*ix = -(b1-b0)/(m1-m0);
+	*iy = m0*(*ix)+b0;
+	}
+    }
+}
+
+boolean pscmIsClockwise(struct psPoly *psPoly)
+/* determine if polygon points are in clockwise order or not
+ * using cross-product sum*/
+{
+struct psPoint *p = psPoly->ptList,*q;
+double x0, y0; 
+double x1, y1;
+double x2, y2;
+double crossProd = 0;
+x1 = p->x;
+y1 = p->y;
+p = p->next;
+x2 = p->x;
+y2 = p->y;
+p = p->next;
+q = p;
+for (;;)
+    {
+    x0 = x1;
+    y0 = y1;
+    x1 = x2;
+    y1 = y2;
+    x2 = p->x;
+    y2 = p->y;
+    crossProd += ((x1-x0)*(y2-y1) - (y1-y0)*(x2-x1));
+    p = p->next;
+    if (p == q) 
+	break;
+    }
+return (crossProd > 0);
+}
+
+void pscmPolyTrapStrokeOutline(struct pscmGfx *pscm, struct psPoly *psPoly)
+/* Stroke a fattened polygon using trapezoids. 
+ * Make each stroke-segment of the poly be made of a 4-sided trapezoidal figure
+ * whose inner edge is parallel 1 pixel away and the points are found
+ * by finding the intersections of these parallel lines. */
+{
+
+struct psPoint *p = psPoly->ptList,*q;
+double px0, py0; /* outer points */
+double px1, py1;
+double m0,b0;
+double m1,b1;
+double ix0,iy0;  /* inner points */
+double ix1,iy1;
+
+boolean cw = pscmIsClockwise(psPoly);
+
+px1 = p->x;
+py1 = p->y;
+p = p->next;
+findLineParams(px1, py1, p->x, p->y, &m1, &b1);
+adjustBForParallelLine(cw, m1, px1, py1, p->x, p->y, &b1);
+px0 = px1;
+py0 = py1;
+px1 = p->x;
+py1 = p->y;
+p = p->next;
+m0 = m1;
+b0 = b1;
+findLineParams(px1, py1, p->x, p->y, &m1, &b1);
+adjustBForParallelLine(cw, m1, px1, py1, p->x, p->y, &b1);
+
+findLinesIntersection(cw,m0,b0,m1,b1,px1,py1,
+    (px1<px0) ^ (m0 < 0),
+    (py1>py0),
+    &ix1,&iy1);
+
+px0 = px1;
+py0 = py1;
+px1 = p->x;
+py1 = p->y;
+p = p->next;
+q = p;
+for (;;)
+    {
+
+    m0 = m1;
+    b0 = b1;
+    ix0 = ix1;
+    iy0 = iy1;
+    findLineParams(px1, py1, p->x, p->y, &m1, &b1);
+    adjustBForParallelLine(cw, m1, px1, py1, p->x, p->y, &b1);
+
+    findLinesIntersection(cw,m0,b0,m1,b1,px1,py1,
+	(px1<px0) ^ (m0 < 0),
+	(py1>py0),
+	&ix1,&iy1);
+
+    struct psPoly *inner = psPolyNew();
+    psPolyAddPoint(inner,px0, py0);
+    psPolyAddPoint(inner,px1, py1);
+    psPolyAddPoint(inner,ix1, iy1);
+    psPolyAddPoint(inner,ix0, iy0);
+    psDrawPoly(pscm->ps, inner, TRUE);
+    psPolyFree(&inner);
+
+    px0 = px1;
+    py0 = py1;
+    px1 = p->x;
+    py1 = p->y;
+    p = p->next;
+    if (p == q) 
+	break;
+    }
+
+}
+
+void pscmDrawPoly(struct pscmGfx *pscm, struct gfxPoly *poly, Color color, 
+	boolean filled)
+/* Draw a polygon, possibly filled, in color. */
+{
+struct gfxPoint *p = poly->ptList;
+struct psPoly *psPoly = psPolyNew();
+int minX, maxX, minY, maxY;
+if (poly->ptCount < 1)  /* nothing to do */
+    {
+    return;
+    }
+psPolyFindExtremes(poly, &minX, &maxX, &minY, &maxY);
+/*  check for co-linear polygon, render as line instead */
+if (colinearPoly(poly)) 
+    {
+    pscmLine(pscm, minX, minY, maxX, maxY, color);
+    return;
+    }
+pscmSetColor(pscm, color);
+/* convert pixel coords to real values */
+for (;;)
+    {
+    psPolyAddPoint(psPoly,p->x, p->y);
+    p = p->next;
+    if (p == poly->ptList)
+	break;
+    }
+boolean fat = sameString(pscmGetHint(pscm,"fat"),"on");
+if (fat)
+    pscmPolyFatten(psPoly, minX, maxX, minY, maxY);
+if (fat && !filled)
+    pscmPolyTrapStrokeOutline(pscm,psPoly);
+else
+    psDrawPoly(pscm->ps, psPoly, filled);
+psPolyFree(&psPoly);
+}
+
+
+
+void pscmFatLine(struct pscmGfx *pscm, double x1, double y1, double x2, double y2)
+/* Draw a line from x1/y1 to x2/y2 by making a filled polygon.
+ *  This also avoids some problems with stroke-width variation
+ *  from different postscript implementations. */
+{
+struct psPoly *psPoly = psPolyNew();
+
+double cX = (x1+x2)/2.0;
+double cY = (y1+y2)/2.0;
+double fX;
+double fY;
+
+/* fatten by lengthing line by 0.5 at each end */
+fX = fY = 1.0+0.5*sqrt(0.5);  
+
+/* expand the length of the line by a half-pixel on each end */
+x1 = fatPixel(x1,cX,fX);
+x2 = fatPixel(x2,cX,fX);
+y1 = fatPixel(y1,cY,fY);
+y2 = fatPixel(y2,cY,fY);
+
+
+/* calculate 4 corners {h,i,j,k} of the rectangle covered */
+
+double m = (y2 - y1)/(x2 - x1);
+m = -1/m;  /* rotate slope 90 degrees */
+
+double ddX = sqrt( (0.5*0.5) / (m*m+1) );
+double ddY = m * ddX;
+
+double hX = x1-ddX, hY = y1-ddY;
+double iX = x1+ddX, iY = y1+ddY;
+double jX = x2+ddX, jY = y2+ddY;
+double kX = x2-ddX, kY = y2-ddY;
+
+psPolyAddPoint(psPoly,hX,hY);
+psPolyAddPoint(psPoly,iX,iY);
+psPolyAddPoint(psPoly,jX,jY);
+psPolyAddPoint(psPoly,kX,kY);
+psDrawPoly(pscm->ps, psPoly, TRUE);
+psPolyFree(&psPoly);
+
+}
+
+
+void pscmLine(struct pscmGfx *pscm, 
+	int x1, int y1, int x2, int y2, int color)
+/* Draw a line from one point to another. */
+{
+pscmSetColor(pscm, color);
+boolean fat = sameString(pscmGetHint(pscm,"fat"),"on");
+if (fat)
+    pscmFatLine(pscm, x1, y1, x2, y2);
+else
+    psDrawLine(pscm->ps, x1, y1, x2, y2);
+boxPscm = NULL;
+}
+
+
+struct vGfx *vgOpenPostScript(int width, int height, char *fileName)
+/* Open up something that will someday be a PostScript file. */
+{
+struct vGfx *vg = vgHalfInit(width, height);
+vg->data = pscmOpen(width, height, fileName);
+vg->close = (vg_close)pscmClose;
+vg->dot = (vg_dot)pscmDot;
+vg->box = (vg_box)pscmBox;
+vg->line = (vg_line)pscmLine;
+vg->text = (vg_text)pscmText;
+vg->textRight = (vg_textRight)pscmTextRight;
+vg->textCentered = (vg_textCentered)pscmTextCentered;
+vg->findColorIx = (vg_findColorIx)pscmFindColorIx;
+vg->colorIxToRgb = (vg_colorIxToRgb)pscmColorIxToRgb;
+vg->setClip = (vg_setClip)pscmSetClip;
+vg->unclip = (vg_unclip)pscmUnclip;
+vg->verticalSmear = (vg_verticalSmear)pscmVerticalSmear;
+vg->fillUnder = (vg_fillUnder)pscmFillUnder;
+vg->drawPoly = (vg_drawPoly)pscmDrawPoly;
+vg->setHint = (vg_setHint)pscmSetHint;
+vg->getHint = (vg_getHint)pscmGetHint;
+vg->getFontPixelHeight = (vg_getFontPixelHeight)pscmGetFontPixelHeight;
+vg->getFontStringWidth = (vg_getFontStringWidth)pscmGetFontStringWidth;
+vg->setWriteMode = (vg_setWriteMode)pscmSetWriteMode;
+return vg;
+}
+
diff --git a/lib/psl.as b/lib/psl.as
new file mode 100644
index 0000000..7114683
--- /dev/null
+++ b/lib/psl.as
@@ -0,0 +1,25 @@
+table psl
+"Summary info about a patSpace alignment"
+    (
+    uint matches;  "Number of bases that match that aren't repeats"
+    uint misMatches; "Number of bases that don't match"
+    uint repMatches; "Number of bases that match but are part of repeats"
+    uint nCount;  "Number of 'N' bases"
+    uint qNumInsert; "Number of inserts in query"
+    int qBaseInsert; "Number of bases inserted in query"
+    uint tNumInsert; "Number of inserts in target"
+    int tBaseInsert; "Number of bases inserted in target"
+    char[2] strand; "+ or - for strand. First character query, second target (optional)"
+    string qName; "Query sequence name"
+    uint qSize; "Query sequence size"
+    uint qStart; "Alignment start position in query"
+    uint qEnd; "Alignment end position in query"
+    string tName; "Target sequence name"
+    uint tSize; "Target sequence size"
+    uint tStart; "Alignment start position in target"
+    uint tEnd; "Alignment end position in target"
+    uint blockCount; "Number of blocks in alignment"
+    uint[blockCount] blockSizes; "Size of each block"
+    uint[blockCount] qStarts; "Start of each block in query."
+    uint[blockCount] tStarts; "Start of each block in target."
+    )
diff --git a/lib/psl.c b/lib/psl.c
new file mode 100644
index 0000000..17a94a7
--- /dev/null
+++ b/lib/psl.c
@@ -0,0 +1,2008 @@
+/* psl.c was originally generated by the autoSql program, which also 
+ * generated as_psl.h and as_psl.sql.  This module links the database and the RAM 
+ * representation of objects. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "sqlNum.h"
+#include "sqlList.h"
+#include "localmem.h"
+#include "psl.h"
+#include "hash.h"
+#include "linefile.h"
+#include "dnaseq.h"
+#include "dystring.h"
+#include "fuzzyFind.h"
+#include "aliType.h"
+#include "binRange.h"
+#include "rangeTree.h"
+
+
+static char *createString = 
+"CREATE TABLE %s (\n"
+    "%s"				/* Optional bin */
+    "matches int unsigned not null,	# Number of bases that match that aren't repeats\n"
+    "misMatches int unsigned not null,	# Number of bases that don't match\n"
+    "repMatches int unsigned not null,	# Number of bases that match but are part of repeats\n"
+    "nCount int unsigned not null,	# Number of 'N' bases\n"
+    "qNumInsert int unsigned not null,	# Number of inserts in query\n"
+    "qBaseInsert int unsigned not null,	# Number of bases inserted in query\n"
+    "tNumInsert int unsigned not null,	# Number of inserts in target\n"
+    "tBaseInsert int unsigned not null,	# Number of bases inserted in target\n"
+    "strand char(2) not null,	# + or - for strand.  First character is query, second is target.\n"
+    "qName varchar(255) not null,	# Query sequence name\n"
+    "qSize int unsigned not null,	# Query sequence size\n"
+    "qStart int unsigned not null,	# Alignment start position in query\n"
+    "qEnd int unsigned not null,	# Alignment end position in query\n"
+    "tName varchar(255) not null,	# Target sequence name\n"
+    "tSize int unsigned not null,	# Target sequence size\n"
+    "tStart int unsigned not null,	# Alignment start position in target\n"
+    "tEnd int unsigned not null,	# Alignment end position in target\n"
+    "blockCount int unsigned not null,	# Number of blocks in alignment\n"
+    "blockSizes longblob not null,	# Size of each block\n"
+    "qStarts longblob not null,	# Start of each block in query.\n"
+    "tStarts longblob not null,	# Start of each block in target.\n";
+
+static char *indexString = 
+	  "#Indices\n"
+    "%s"                            /* Optional bin. */
+    "INDEX(qName(12))\n"
+")\n";
+
+
+struct psl *pslxLoad(char **row)
+/* Load a psl from row fetched with select * from psl
+ * from database.  Dispose of this with pslFree(). */
+{
+struct psl *ret = pslLoad(row);
+int retSize;
+sqlStringDynamicArray(row[21],&ret->qSequence, &retSize);
+sqlStringDynamicArray(row[22],&ret->tSequence, &retSize);
+return ret;
+}
+
+struct psl *pslLoad(char **row)
+/* Load a psl from row fetched with select * from psl
+ * from database.  Dispose of this with pslFree(). */
+{
+struct psl *ret;
+int sizeOne;
+
+AllocVar(ret);
+ret->blockCount = sqlUnsigned(row[17]);
+ret->match = sqlUnsigned(row[0]);
+ret->misMatch = sqlUnsigned(row[1]);
+ret->repMatch = sqlUnsigned(row[2]);
+ret->nCount = sqlUnsigned(row[3]);
+ret->qNumInsert = sqlUnsigned(row[4]);
+ret->qBaseInsert = sqlSigned(row[5]);
+ret->tNumInsert = sqlUnsigned(row[6]);
+ret->tBaseInsert = sqlSigned(row[7]);
+strcpy(ret->strand, row[8]);
+ret->qName = cloneString(row[9]);
+ret->qSize = sqlUnsigned(row[10]);
+ret->qStart = sqlUnsigned(row[11]);
+ret->qEnd = sqlUnsigned(row[12]);
+ret->tName = cloneString(row[13]);
+ret->tSize = sqlUnsigned(row[14]);
+ret->tStart = sqlUnsigned(row[15]);
+ret->tEnd = sqlUnsigned(row[16]);
+sqlUnsignedDynamicArray(row[18], &ret->blockSizes, &sizeOne);
+if (sizeOne != ret->blockCount)
+    {
+    printf("sizeOne bloxksizes %d bs %d block=%s\n",sizeOne, ret->blockCount,row[18]);
+    }
+assert(sizeOne == ret->blockCount);
+sqlUnsignedDynamicArray(row[19], &ret->qStarts, &sizeOne);
+if (sizeOne != ret->blockCount)
+    {
+    printf("sizeOne qStarts %d bs %d\n",sizeOne, ret->blockCount);
+    }
+assert(sizeOne == ret->blockCount);
+sqlUnsignedDynamicArray(row[20], &ret->tStarts, &sizeOne);
+if (sizeOne != ret->blockCount)
+    {
+    printf("sizeOne tStarts %d bs %d\n",sizeOne, ret->blockCount);
+    }
+assert(sizeOne == ret->blockCount);
+return ret;
+}
+
+struct psl *pslCommaIn(char **pS, struct psl *ret)
+/* Create a psl out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new psl */
+{
+char *s = *pS;
+int i;
+
+if (ret == NULL)
+    AllocVar(ret);
+ret->match = sqlUnsignedComma(&s);
+ret->misMatch = sqlUnsignedComma(&s);
+ret->repMatch = sqlUnsignedComma(&s);
+ret->nCount = sqlUnsignedComma(&s);
+ret->qNumInsert = sqlUnsignedComma(&s);
+ret->qBaseInsert = sqlSignedComma(&s);
+ret->tNumInsert = sqlUnsignedComma(&s);
+ret->tBaseInsert = sqlSignedComma(&s);
+sqlFixedStringComma(&s, ret->strand, sizeof(ret->strand));
+ret->qName = sqlStringComma(&s);
+ret->qSize = sqlUnsignedComma(&s);
+ret->qStart = sqlUnsignedComma(&s);
+ret->qEnd = sqlUnsignedComma(&s);
+ret->tName = sqlStringComma(&s);
+ret->tSize = sqlUnsignedComma(&s);
+ret->tStart = sqlUnsignedComma(&s);
+ret->tEnd = sqlUnsignedComma(&s);
+ret->blockCount = sqlUnsignedComma(&s);
+s = sqlEatChar(s, '{');
+AllocArray(ret->blockSizes, ret->blockCount);
+for (i=0; i<ret->blockCount; ++i)
+    {
+    ret->blockSizes[i] = sqlUnsignedComma(&s);
+    }
+s = sqlEatChar(s, '}');
+s = sqlEatChar(s, ',');
+s = sqlEatChar(s, '{');
+AllocArray(ret->qStarts, ret->blockCount);
+for (i=0; i<ret->blockCount; ++i)
+    {
+    ret->qStarts[i] = sqlUnsignedComma(&s);
+    }
+s = sqlEatChar(s, '}');
+s = sqlEatChar(s, ',');
+s = sqlEatChar(s, '{');
+AllocArray(ret->tStarts, ret->blockCount);
+for (i=0; i<ret->blockCount; ++i)
+    {
+    ret->tStarts[i] = sqlUnsignedComma(&s);
+    }
+s = sqlEatChar(s, '}');
+s = sqlEatChar(s, ',');
+*pS = s;
+return ret;
+}
+
+void pslFree(struct psl **pEl)
+/* Free a single dynamically allocated psl such as created
+ * with pslLoad(). */
+{
+struct psl *el;
+
+if ((el = *pEl) == NULL) return;
+freeMem(el->qName);
+freeMem(el->tName);
+freeMem(el->blockSizes);
+freeMem(el->qStarts);
+freeMem(el->tStarts);
+if (el->qSequence)
+    {
+    freeMem(el->qSequence[0]);
+    freeMem(el->qSequence);
+    }
+if (el->tSequence)
+    {
+    freeMem(el->tSequence[0]);
+    freeMem(el->tSequence);
+    }
+freez(pEl);
+}
+
+void pslFreeList(struct psl **pList)
+/* Free a list of dynamically allocated psl's */
+{
+struct psl *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    pslFree(&el);
+    }
+*pList = NULL;
+}
+
+void pslOutput(struct psl *el, FILE *f, char sep, char lastSep) 
+/* Print out psl.  Separate fields with sep. Follow last field with lastSep. */
+{
+int i;
+fprintf(f, "%u", el->match);
+fputc(sep,f);
+fprintf(f, "%u", el->misMatch);
+fputc(sep,f);
+fprintf(f, "%u", el->repMatch);
+fputc(sep,f);
+fprintf(f, "%u", el->nCount);
+fputc(sep,f);
+fprintf(f, "%u", el->qNumInsert);
+fputc(sep,f);
+fprintf(f, "%d", el->qBaseInsert);
+fputc(sep,f);
+fprintf(f, "%u", el->tNumInsert);
+fputc(sep,f);
+fprintf(f, "%d", el->tBaseInsert);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->strand);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->qName);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%u", el->qSize);
+fputc(sep,f);
+fprintf(f, "%u", el->qStart);
+fputc(sep,f);
+fprintf(f, "%u", el->qEnd);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->tName);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%u", el->tSize);
+fputc(sep,f);
+fprintf(f, "%u", el->tStart);
+fputc(sep,f);
+fprintf(f, "%u", el->tEnd);
+fputc(sep,f);
+fprintf(f, "%u", el->blockCount);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->blockCount; ++i)
+    {
+    fprintf(f, "%u", el->blockSizes[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->blockCount; ++i)
+    {
+    fprintf(f, "%u", el->qStarts[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->blockCount; ++i)
+    {
+    fprintf(f, "%u", el->tStarts[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+if (el->qSequence)
+    {
+    fputc(sep,f);
+    if (sep == ',') fputc('{',f);
+    for (i=0; i<el->blockCount; ++i)
+	{
+	fprintf(f, "%s", el->qSequence[i]);
+	fputc(',', f);
+	}
+    if (sep == ',') fputc('}',f);
+    fputc(sep,f);
+    if (sep == ',') fputc('{',f);
+    for (i=0; i<el->blockCount; ++i)
+	{
+	fprintf(f, "%s", el->tSequence[i]);
+	fputc(',', f);
+	}
+    if (sep == ',') fputc('}',f);
+    }
+
+fputc(lastSep,f);
+if (ferror(f))
+    {
+    perror("Error writing psl file\n");
+    errAbort("\n");
+    }
+}
+
+/* ----- end autoSql generated part --------------- */
+
+void pslOutputShort(struct psl *el, FILE *f, char sep, char lastSep) 
+/* Print out psl.  Separate fields with sep. Follow last field with lastSep. */
+{
+fprintf(f, "%u", el->match);
+fputc(sep,f);
+fprintf(f, "%u", el->misMatch);
+fputc(sep,f);
+fprintf(f, "%u", el->repMatch);
+fputc(sep,f);
+fprintf(f, "%u", el->qNumInsert);
+fputc(sep,f);
+fprintf(f, "%d", el->qBaseInsert);
+fputc(sep,f);
+fprintf(f, "%u", el->tNumInsert);
+fputc(sep,f);
+fprintf(f, "%d", el->tBaseInsert);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->strand);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->qName);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%u", el->qStart);
+fputc(sep,f);
+fprintf(f, "%u", abs(el->qEnd - el->qStart));
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->tName);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%u", el->tStart);
+fputc(sep,f);
+fprintf(f, "%u", abs(el->tEnd - el->tStart));
+fputc(sep,f);
+fprintf(f, "%u", el->blockCount);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+fputc(lastSep,f);
+if (ferror(f))
+    {
+    perror("Error writing psl file\n");
+    errAbort("\n");
+    }
+}
+
+void pslOutFormat(struct psl *el, FILE *f, char sep, char lastSep) 
+/* Print out selected psl values.  Separate fields with sep. Follow last field with lastSep. */
+/* Prints out a better format with bold field headings followed by value */
+/* Requires further upstream work to ensure that only the field headers */
+/* declared here are printed if replacing an existing psl print function*/
+{
+const char *headers[] = {"Matches", "Mismatches", "Matches in repeats", "Number of N bases", "Query name", "Size", "Start", "End", "Chromosome", "Strand", "Start", "End"};
+char *hformat = "<B>%s:</B> "; /* string for formatted print for headers */
+char *uformat = "<B>%s:</B> %u%c"; /* string for formatted print for unsigned variable */
+char *targName;
+
+fprintf(f, uformat, headers[0], el->match, sep);
+fprintf(f, uformat, headers[1], el->misMatch, sep);
+fprintf(f, uformat, headers[2], el->repMatch, sep);
+fprintf(f, uformat, headers[3], el->nCount, sep);
+
+fprintf(f, hformat, headers[4]);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->qName);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+
+fprintf(f, uformat, headers[5], el->qSize, sep);
+fprintf(f, uformat, headers[6], el->qStart, sep);
+fprintf(f, uformat, headers[7], el->qEnd, sep);
+
+fprintf(f, hformat, headers[8]);
+if (sep == ',') fputc('"',f);
+/* skip leading 'chr' in string to get only chromosome part */
+targName = el->tName;
+if (startsWith("chr", el->tName))
+   targName += 3;
+fprintf(f, "%s", targName);
+
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+
+fprintf(f, hformat, headers[9]);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->strand);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+
+fprintf(f, uformat, headers[10], el->tStart, sep);
+fprintf(f, uformat, headers[11], el->tEnd, sep);
+
+fputc(lastSep,f);
+
+if (ferror(f))
+    {
+    perror("Error writing psl file\n");
+    errAbort("\n");
+    }
+
+}
+
+struct psl *pslLoadAll(char *fileName)
+/* Load all psl's in file. */
+{
+struct lineFile *lf = pslFileOpen(fileName);
+struct psl *pslList = NULL, *psl;
+while ((psl = pslNext(lf)) != NULL)
+    {
+    slAddHead(&pslList, psl);
+    }
+slReverse(&pslList);
+lineFileClose(&lf);
+return pslList;
+}
+
+
+int pslCmpQuery(const void *va, const void *vb)
+/* Compare to sort based on query start. */
+{
+const struct psl *a = *((struct psl **)va);
+const struct psl *b = *((struct psl **)vb);
+int dif;
+dif = strcmp(a->qName, b->qName);
+if (dif == 0)
+    dif = a->qStart - b->qStart;
+return dif;
+}
+
+int pslCmpTarget(const void *va, const void *vb)
+/* Compare to sort based on target start. */
+{
+const struct psl *a = *((struct psl **)va);
+const struct psl *b = *((struct psl **)vb);
+int dif;
+dif = strcmp(a->tName, b->tName);
+if (dif == 0)
+    dif = a->tStart - b->tStart;
+return dif;
+}
+
+int pslCmpTargetAndStrand(const void *va, const void *vb)
+/* Compare to sort based on target, strand,  tStart. */
+{
+const struct psl *a = *((struct psl **)va);
+const struct psl *b = *((struct psl **)vb);
+int dif;
+dif = strcmp(a->tName, b->tName);
+if (dif == 0)
+    dif = strcmp(a->strand, b->strand);
+if (dif == 0)
+    dif = a->tStart - b->tStart;
+return dif;
+}
+
+
+int pslCmpScore(const void *va, const void *vb)
+/* Compare to sort based on score (descending). */
+{
+const struct psl *a = *((struct psl **)va);
+const struct psl *b = *((struct psl **)vb);
+return pslScore(b) - pslScore(a);
+}
+
+int pslCmpQueryScore(const void *va, const void *vb)
+/* Compare to sort based on query then score (descending). */
+{
+const struct psl *a = *((struct psl **)va);
+const struct psl *b = *((struct psl **)vb);
+int diff = strcmp(a->qName, b->qName);
+if (diff == 0)
+    diff = pslScore(b) - pslScore(a);
+return diff;
+}
+
+int pslCmpMatch(const void *va, const void *vb)
+/* Compare to sort based on match */
+{
+const struct psl *a = *((struct psl **)va);
+const struct psl *b = *((struct psl **)vb);
+return b->match - a->match;
+}
+
+static void pslLabelColumns(FILE *f)
+/* Write column info. */
+{
+fputs("\n"
+"match\tmis- \trep. \tN's\tQ gap\tQ gap\tT gap\tT gap\tstrand\tQ        \tQ   \tQ    \tQ  \tT        \tT   \tT    \tT  \tblock\tblockSizes \tqStarts\t tStarts\n"
+"     \tmatch\tmatch\t   \tcount\tbases\tcount\tbases\t      \tname     \tsize\tstart\tend\tname     \tsize\tstart\tend\tcount\n" 
+"---------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
+f);
+}
+
+void pslxWriteHead(FILE *f, enum gfType qType, enum gfType tType)
+/* Write header for extended (possibly protein) psl file. */
+{
+fprintf(f, "psLayout version 4 %s %s\n", gfTypeName(qType), gfTypeName(tType));
+pslLabelColumns(f);
+}
+
+void pslWriteHead(FILE *f)
+/* Write head of psl. */
+{
+fputs("psLayout version 3\n", f);
+pslLabelColumns(f);
+}
+
+void pslWriteAll(struct psl *pslList, char *fileName, boolean writeHeader)
+/* Write a psl file from list. */
+{
+FILE *f;
+struct psl *psl;
+
+f = mustOpen(fileName, "w");
+if (writeHeader)
+    pslWriteHead(f);
+for (psl = pslList; psl != NULL; psl = psl->next)
+    pslTabOut(psl, f);
+fclose(f);
+}
+
+void pslxFileOpen(char *fileName, enum gfType *retQueryType, enum gfType *retTargetType, struct lineFile **retLf)
+/* Read header part of psl and make sure it's right.  Return
+ * sequence types and file handle. */
+{
+char *line;
+int lineSize;
+char *words[30];
+char *version;
+int wordCount;
+int i;
+enum gfType qt = gftRna,  tt = gftDna;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+
+if (!lineFileNext(lf, &line, &lineSize))
+    warn("%s is empty", fileName);
+else
+    {
+    if (startsWith("psLayout version", line))
+	{
+	wordCount = chopLine(line, words);
+	if (wordCount < 3)
+	    errAbort("%s is not a psLayout file", fileName);
+	version = words[2];
+	if (sameString(version, "3"))
+	    {
+	    }
+	else if (sameString(version, "4"))
+	    {
+	    qt = gfTypeFromName(words[3]);
+	    tt = gfTypeFromName(words[4]);
+	    }
+	else
+	    {
+	    errAbort("%s is version %s of psLayout, this program can only handle through version 4",
+		fileName,  version);
+	    }
+	for (i=0; i<4; ++i)
+	    {
+	    if (!lineFileNext(lf, &line, &lineSize))
+		errAbort("%s severely truncated", fileName);
+	    }
+	}
+    else
+        {
+	char *s = cloneString(line);
+        while (line != NULL && line[0] == '#')
+            {
+            freeMem(s);
+            lineFileNext(lf, &line, &lineSize);
+            s = cloneString(line);
+            }
+	wordCount = chopLine(s, words);
+	if (wordCount < 21 || wordCount > 23 || (words[8][0] != '+' && words[8][0] != '-'))
+	    errAbort("%s is not a psLayout file", fileName);
+	else
+	    lineFileReuse(lf); 
+	freeMem(s);
+	}
+    }
+*retQueryType = qt;
+*retTargetType = tt;
+*retLf = lf;
+}
+
+static void pslxFileOpenWithMetaConfig(char *fileName, bool isMetaUnique, enum gfType *retQueryType, enum gfType *retTargetType, struct lineFile **retLf, FILE *f)
+/* Read header part of psl and make sure it's right.  Return
+ * sequence types and file handle and send meta data to output file f */
+{
+char *line;
+int lineSize;
+char *words[30];
+char *version;
+int wordCount;
+int i;
+enum gfType qt = gftRna,  tt = gftDna;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+
+lineFileSetMetaDataOutput(lf, f);
+if (isMetaUnique)
+    lineFileSetUniqueMetaData(lf);
+if (!lineFileNext(lf, &line, &lineSize))
+    warn("%s is empty", fileName);
+else
+    {
+    if (startsWith("psLayout version", line))
+	{
+	wordCount = chopLine(line, words);
+	if (wordCount < 3)
+	    errAbort("%s is not a psLayout file", fileName);
+	version = words[2];
+	if (sameString(version, "3"))
+	    {
+	    }
+	else if (sameString(version, "4"))
+	    {
+	    qt = gfTypeFromName(words[3]);
+	    tt = gfTypeFromName(words[4]);
+	    }
+	else
+	    {
+	    errAbort("%s is version %s of psLayout, this program can only handle through version 4",
+		fileName,  version);
+	    }
+	for (i=0; i<4; ++i)
+	    {
+	    if (!lineFileNext(lf, &line, &lineSize))
+		errAbort("%s severely truncated", fileName);
+	    }
+	}
+    else
+        {
+	char *s = cloneString(line);
+        boolean eof = FALSE;
+        while ((line[0] == '#') && (!eof))
+            {
+            freeMem(s);
+            if (!lineFileNext(lf, &line, &lineSize))
+                eof = TRUE;
+            s = cloneString(line);
+            }
+	wordCount = chopLine(s, words);
+	if ((wordCount < 21 || wordCount > 23 || (words[8][0] != '+' && words[8][0] != '-')) && (!eof))
+	    errAbort("%s is not a psLayout file", fileName);
+	else
+	    lineFileReuse(lf); 
+	freeMem(s);
+	}
+    }
+*retQueryType = qt;
+*retTargetType = tt;
+*retLf = lf;
+}
+
+void pslxFileOpenWithMeta(char *fileName, enum gfType *retQueryType, enum gfType *retTargetType, struct lineFile **retLf, FILE *f)
+/* Read header part of psl and make sure it's right.  Return
+ * sequence types and file handle and send meta data to output file f */
+{
+pslxFileOpenWithMetaConfig(fileName, FALSE, retQueryType, retTargetType, retLf, f);
+}
+
+void pslxFileOpenWithUniqueMeta(char *fileName, enum gfType *retQueryType, enum gfType *retTargetType, struct lineFile **retLf, FILE *f)
+/* Read header part of psl and make sure it's right.  Return
+ * sequence types and file handle and send only unique meta data to output f */
+{
+pslxFileOpenWithMetaConfig(fileName, TRUE, retQueryType, retTargetType, retLf, f);
+}
+
+struct lineFile *pslFileOpen(char *fileName)
+/* Read header part of psl and make sure it's right. 
+ * Return line file handle to it. */
+{
+enum gfType qt, tt;
+struct lineFile *lf;
+pslxFileOpen(fileName, &qt, &tt, &lf);
+return lf;
+}
+
+struct lineFile *pslFileOpenWithMeta(char *fileName, FILE *f)
+/* Read header part of psl and make sure it's right. 
+ * Return line file handle to it. */
+{
+enum gfType qt, tt;
+struct lineFile *lf;
+pslxFileOpenWithMeta(fileName, &qt, &tt, &lf, f);
+return lf;
+}
+
+struct lineFile *pslFileOpenWithUniqueMeta(char *fileName, FILE *f)
+/* Read header part of psl and make sure it's right. 
+ * Set flag to suppress duplicate header comments.
+ * Return line file handle to it. */
+{
+enum gfType qt, tt;
+struct lineFile *lf;
+pslxFileOpenWithUniqueMeta(fileName, &qt, &tt, &lf, f);
+return lf;
+}
+
+struct psl *pslNext(struct lineFile *lf)
+/* Read next line from file and convert it to psl.  Return
+ * NULL at eof. */
+{
+char *line;
+int lineSize;
+char *words[32];
+int wordCount;
+static int lineAlloc = 0;
+static char *chopBuf = NULL;
+
+if (!lineFileNextReal(lf, &line))
+    {
+    return NULL;
+    }
+lineSize = strlen(line);
+if (lineSize >= lineAlloc)
+    {
+    lineAlloc = lineSize+256;
+    chopBuf = needMoreMem(chopBuf, 0, lineAlloc);
+    }
+memcpy(chopBuf, line, lineSize+1);
+wordCount = chopLine(chopBuf, words);
+if (wordCount == 21)
+    {
+    return pslLoad(words);
+    }
+if (wordCount == 23)
+    {
+    return pslxLoad(words);
+    }
+else
+    {
+    errAbort("Bad line %d of %s wordCount is %d instead of 21 or 23\n", lf->lineIx, lf->fileName, wordCount);
+    return NULL;
+    }
+}
+
+struct psl *pslxLoadLm(char **row, struct lm *lm)
+/* Load row into local memory pslx. */
+{
+struct psl *ret = pslLoadLm(row, lm);
+ret->qSequence = lmAlloc(lm, sizeof(ret->qSequence[0]) * ret->blockCount);
+sqlStringArray(lmCloneString(lm,row[21]),ret->qSequence, ret->blockCount);
+ret->tSequence = lmAlloc(lm, sizeof(ret->tSequence[0]) * ret->blockCount);
+sqlStringArray(lmCloneString(lm,row[22]),ret->tSequence, ret->blockCount);
+return ret;
+}
+
+struct psl *pslLoadLm(char **row, struct lm *lm)
+/* Load row into local memory psl. */
+{
+struct psl *ret;
+
+ret = lmAlloc(lm, sizeof(*ret));
+ret->blockCount = sqlUnsigned(row[17]);
+ret->match = sqlUnsigned(row[0]);
+ret->misMatch = sqlUnsigned(row[1]);
+ret->repMatch = sqlUnsigned(row[2]);
+ret->nCount = sqlUnsigned(row[3]);
+ret->qNumInsert = sqlUnsigned(row[4]);
+ret->qBaseInsert = sqlSigned(row[5]);
+ret->tNumInsert = sqlUnsigned(row[6]);
+ret->tBaseInsert = sqlSigned(row[7]);
+strcpy(ret->strand, row[8]);
+ret->qName = lmCloneString(lm,row[9]);
+ret->qSize = sqlUnsigned(row[10]);
+ret->qStart = sqlUnsigned(row[11]);
+ret->qEnd = sqlUnsigned(row[12]);
+ret->tName = lmCloneString(lm, row[13]);
+ret->tSize = sqlUnsigned(row[14]);
+ret->tStart = sqlUnsigned(row[15]);
+ret->tEnd = sqlUnsigned(row[16]);
+ret->blockSizes = lmAlloc(lm, sizeof(ret->blockSizes[0]) * ret->blockCount);
+sqlUnsignedArray(row[18], ret->blockSizes, ret->blockCount);
+ret->qStarts = lmAlloc(lm, sizeof(ret->qStarts[0]) * ret->blockCount);
+sqlUnsignedArray(row[19], ret->qStarts, ret->blockCount);
+ret->tStarts = lmAlloc(lm, sizeof(ret->tStarts[0]) * ret->blockCount);
+sqlUnsignedArray(row[20], ret->tStarts, ret->blockCount);
+return ret;
+}
+
+boolean pslIsProtein(const struct psl *psl)
+/* is psl a protein psl (are it's blockSizes and scores in protein space) */
+{
+int lastBlock = psl->blockCount - 1;
+
+return  (((psl->strand[1] == '+' ) &&
+    (psl->tEnd == psl->tStarts[lastBlock] + 3*psl->blockSizes[lastBlock])) ||
+   ((psl->strand[1] == '-') && 
+    (psl->tStart == (psl->tSize-(psl->tStarts[lastBlock] + 3*psl->blockSizes[lastBlock])))));
+}
+
+int pslCalcMilliBad(struct psl *psl, boolean isMrna)
+/* Calculate badness in parts per thousand. */
+{
+int sizeMul = pslIsProtein(psl) ? 3 : 1;
+int qAliSize, tAliSize, aliSize;
+int milliBad = 0;
+int sizeDif;
+int insertFactor;
+int total;
+
+qAliSize = sizeMul * (psl->qEnd - psl->qStart);
+tAliSize = psl->tEnd - psl->tStart;
+aliSize = min(qAliSize, tAliSize);
+if (aliSize <= 0)
+    return 0;
+sizeDif = qAliSize - tAliSize;
+if (sizeDif < 0)
+    {
+    if (isMrna)
+	sizeDif = 0;
+    else
+	sizeDif = -sizeDif;
+    }
+insertFactor = psl->qNumInsert;
+if (!isMrna)
+    insertFactor += psl->tNumInsert;
+
+total = (sizeMul * (psl->match + psl->repMatch + psl->misMatch));
+if (total != 0)
+    milliBad = (1000 * (psl->misMatch*sizeMul + insertFactor + round(3*log(1+sizeDif)))) / total;
+return milliBad;
+}
+
+int pslScore(const struct psl *psl)
+/* Return score for psl. */
+{
+int sizeMul = pslIsProtein(psl) ? 3 : 1;
+
+return sizeMul * (psl->match + ( psl->repMatch>>1)) - 
+	sizeMul * psl->misMatch - psl->qNumInsert - psl->tNumInsert;
+}
+
+int pslCmpScoreDesc(const void *va, const void *vb)
+/* Compare to sort based on score. */
+{
+const struct psl *a = *((struct psl **)va);
+const struct psl *b = *((struct psl **)vb);
+return pslScore(b) - pslScore(a);
+}
+
+
+struct ffAli *pslToFakeFfAli(struct psl *psl, DNA *needle, DNA *haystack)
+/* Convert from psl to ffAli format.  In some cases you can pass NULL
+ * for needle and haystack - depending what the post-processing is going
+ * to be. */
+{
+struct ffAli *ffList = NULL, *ff;
+int blockCount = psl->blockCount;
+unsigned *blockSizes = psl->blockSizes;
+unsigned *qStarts = psl->qStarts;
+unsigned *tStarts = psl->tStarts;
+int size;
+int i;
+
+for (i=0; i<blockCount; ++i)
+    {
+    size = blockSizes[i];
+    AllocVar(ff);
+    ff->left = ffList;
+    ffList = ff;
+    ff->nStart = ff->nEnd = needle + qStarts[i];
+    ff->nEnd += size;
+    ff->hStart = ff->hEnd = haystack + tStarts[i];
+    ff->hEnd += size;
+    }
+ffList = ffMakeRightLinks(ffList);
+return ffList;
+}
+
+struct psl *pslFromFakeFfAli(struct ffAli *ff, 
+	DNA *needle, DNA *haystack, char strand,
+	char *qName, int qSize, char *tName, int tSize)
+/* This will create a basic psl structure from a sorted series of ffAli
+ * blocks.  The fields that would need actual sequence to be filled in
+ * are left zero however - fields including match, repMatch, mismatch. */
+{
+struct psl *psl;
+unsigned *blockSizes;
+unsigned *qStarts;
+unsigned *tStarts;
+int blockCount;
+int i;
+int nStart, hStart;
+int nEnd, hEnd;
+
+AllocVar(psl);
+psl->blockCount = blockCount = ffAliCount(ff);
+psl->blockSizes = AllocArray(blockSizes, blockCount);
+psl->qStarts = AllocArray(qStarts, blockCount);
+psl->tStarts = AllocArray(tStarts, blockCount);
+psl->qName = cloneString(qName);
+psl->qSize = qSize;
+psl->tName = cloneString(tName);
+psl->tSize = tSize;
+psl->strand[0] = strand;
+
+for (i=0; i<blockCount; ++i)
+    {
+    nStart = ff->nStart - needle;
+    nEnd = ff->nEnd - needle;
+    hStart = ff->hStart - haystack;
+    hEnd = ff->hEnd - haystack;
+    blockSizes[i] = nEnd - nStart;
+    qStarts[i] = nStart;
+    tStarts[i] = hStart;
+    if (i == 0)
+       {
+       psl->qStart = nStart;
+       psl->tStart = hStart;
+       }
+    if (i == blockCount-1)
+       {
+       psl->qEnd = nEnd;
+       psl->tEnd = hEnd;
+       }
+    ff = ff->right;
+    }
+if (strand == '-')
+    {
+    reverseIntRange(&psl->qStart, &psl->qEnd, psl->qSize);
+    }
+return psl;
+}
+
+struct ffAli *pslToFfAli(struct psl *psl, struct dnaSeq *query, struct dnaSeq *target,
+	int targetOffset)
+/* Convert from psl to ffAli format.  Clip to parts that we actually
+ * have sequence for. */
+{
+struct ffAli *ffList = NULL, *ff;
+DNA *needle = query->dna;
+DNA *haystack = target->dna;
+int blockCount = psl->blockCount;
+unsigned *blockSizes = psl->blockSizes;
+unsigned *qStarts = psl->qStarts;
+unsigned *tStarts = psl->tStarts;
+int size;
+int i;
+int tMin = targetOffset;
+int tMax = targetOffset + target->size;
+int tStart, tEnd;
+int clipStart, clipEnd, clipOffset, clipSize;
+
+for (i=0; i<blockCount; ++i)
+    {
+    clipStart = tStart = tStarts[i];
+    size = blockSizes[i];
+    clipEnd = tEnd = tStart + size;
+    if (tStart < tMax && tEnd > tMin)
+	{
+	if (clipStart < tMin) clipStart = tMin;
+	if (clipEnd > tMax) clipEnd = tMax;
+	clipOffset = clipStart - tStart;
+	clipSize = clipEnd - clipStart;
+	AllocVar(ff);
+	ff->left = ffList;
+	ffList = ff;
+	ff->nStart = ff->nEnd = needle + qStarts[i] + clipOffset;
+	ff->nEnd += clipSize;
+	ff->hStart = ff->hEnd = haystack + clipStart - targetOffset;
+	ff->hEnd += clipSize;
+	}
+    }
+ffList = ffMakeRightLinks(ffList);
+ffCountGoodEnds(ffList);
+return ffList;
+}
+
+int pslOrientation(struct psl *psl)
+/* Translate psl strand + or - to orientation +1 or -1 */
+{
+if (psl->strand[1] != '\0')
+    {
+    /* translated blat */
+    if (psl->strand[0] != psl->strand[1])
+        return -1;
+    else
+        return 1;
+    }
+else
+    {
+    if (psl->strand[0] == '-')
+        return -1;
+    else
+        return 1;
+    }
+}
+
+int pslWeightedIntronOrientation(struct psl *psl, struct dnaSeq *genoSeq, int offset)
+/* Return >0 if introns make it look like alignment is on + strand,
+ *        <0 if introns make it look like alignment is on - strand,
+ *        0 if can't tell.  The absolute value of the return indicates
+ * how many splice sites we've seen supporting the orientation.
+ * Sequence should NOT be reverse complemented.  */
+{
+int intronDir = 0;
+int oneDir;
+int i;
+DNA *dna = genoSeq->dna;
+
+/* code below doesn't support negative target strand (translated blat) */
+if (psl->strand[1] == '-')
+    errAbort("pslWeightedIntronOrientation doesn't support a negative target strand");
+
+for (i=1; i<psl->blockCount; ++i)
+    {
+    int iStart, iEnd, blockSize = psl->blockSizes[i-1];
+    if (psl->qStarts[i-1] + blockSize == psl->qStarts[i])
+	{
+	iStart = psl->tStarts[i-1] + psl->blockSizes[i-1] - offset;
+	iEnd = psl->tStarts[i] - offset;
+	oneDir = intronOrientation(dna+iStart, dna+iEnd);
+	intronDir += oneDir;
+	}
+    }
+return intronDir;
+}
+
+int pslIntronOrientation(struct psl *psl, struct dnaSeq *genoSeq, int offset)
+/* Return 1 if introns make it look like alignment is on + strand,
+ *       -1 if introns make it look like alignment is on - strand,
+ *        0 if can't tell.
+ * Sequence should NOT be reverse complemented.  */
+{
+int intronDir = pslWeightedIntronOrientation(psl, genoSeq, offset);
+if (intronDir < 0)
+    intronDir = -1;
+else if (intronDir > 0)
+    intronDir = 1;
+return intronDir;
+}
+
+boolean pslHasIntron(struct psl *psl, struct dnaSeq *seq, int seqOffset)
+/* Return TRUE if there's a probable intron. Sequence should NOT be
+ * reverse complemented.*/
+{
+int blockCount = psl->blockCount, i;
+unsigned *tStarts = psl->tStarts;
+unsigned *blockSizes = psl->blockSizes;
+unsigned *qStarts = psl->qStarts;
+int blockSize, start, end;
+DNA *dna = seq->dna;
+
+for (i=1; i<blockCount; ++i)
+    {
+    blockSize = blockSizes[i-1];
+    start = qStarts[i-1]+blockSize;
+    end = qStarts[i];
+    if (start == end)
+        {
+        start = tStarts[i-1] + blockSize;
+        end = tStarts[i];
+        if (psl->strand[1] == '-')
+            reverseIntRange(&start, &end, psl->tSize);
+        start -= seqOffset;
+        end -= seqOffset;
+	if (intronOrientation(dna+start, dna+end) != 0)
+	    return TRUE;
+	}
+    }
+return FALSE;
+}
+
+void pslTailSizes(struct psl *psl, int *retStartTail, int *retEndTail)
+/* Find the length of "tails" (rather than extensions) implied by psl. */
+{
+int orientation = pslOrientation(psl);
+int qFloppyStart, qFloppyEnd;
+int tFloppyStart, tFloppyEnd;
+
+if (orientation > 0)
+    {
+    qFloppyStart = psl->qStart;
+    qFloppyEnd = psl->qSize - psl->qEnd;
+    }
+else
+    {
+    qFloppyStart = psl->qSize - psl->qEnd;
+    qFloppyEnd = psl->qStart;
+    }
+tFloppyStart = psl->tStart;
+tFloppyEnd = psl->tSize - psl->tEnd;
+*retStartTail = min(qFloppyStart, tFloppyStart);
+*retEndTail = min(qFloppyEnd, tFloppyEnd);
+}
+
+static void rcSeqs(char **seqs, unsigned blockCount, unsigned *blockSizes)
+/* reverses complement sequences in list, maintain property that all strings
+ * are in one malloc block.   blockSizes should already be reversed. */
+{
+char *buf, *next;
+int i, memSz = 0;
+
+/* get a new memory block for strings */
+for (i = 0; i < blockCount; i++)
+    memSz += blockSizes[i]+1;
+next = buf = needLargeMem(memSz);
+
+/* reverse compliment and copy to new memory block */
+for (i = blockCount-1; i >= 0; i--)
+    {
+    int len = strlen(seqs[i]);
+    reverseComplement(seqs[i], len);
+    memcpy(next, seqs[i], len+1);
+    next += len+1;
+    }
+
+/* swap memory and update pointers */
+freeMem(seqs[0]);
+seqs[0] = buf;
+next = buf;
+
+for (i = 0; i < blockCount; i++)
+    {
+    seqs[i] = next;
+    next += blockSizes[i]+1;
+    }
+}
+
+void pslRc(struct psl *psl)
+/* Reverse-complement a PSL alignment.  This makes the target strand explicit. */
+{
+unsigned tSize = psl->tSize, qSize = psl->qSize;
+unsigned blockCount = psl->blockCount, i;
+unsigned *tStarts = psl->tStarts, *qStarts = psl->qStarts, *blockSizes = psl->blockSizes;
+
+/* swap strand, forcing target to have an explict strand */
+psl->strand[0] = (psl->strand[0] != '-') ? '-' : '+';
+psl->strand[1] = (psl->strand[1] != '-') ? '-' : '+';
+psl->strand[2] = 0;
+
+for (i=0; i<blockCount; ++i)
+    {
+    tStarts[i] = tSize - (tStarts[i] + blockSizes[i]);
+    qStarts[i] = qSize - (qStarts[i] + blockSizes[i]);
+    }
+reverseUnsigned(tStarts, blockCount);
+reverseUnsigned(qStarts, blockCount);
+reverseUnsigned(blockSizes, blockCount);
+if (psl->qSequence != NULL)
+    {
+    rcSeqs(psl->qSequence, blockCount, blockSizes);
+    rcSeqs(psl->tSequence, blockCount, blockSizes);
+    }
+}
+
+
+/* macro to swap to variables */
+#define swapVars(a, b, tmp) ((tmp) = (a), (a) = (b), (b) = (tmp))
+
+static void swapBlocks(struct psl *psl)
+/* Swap the blocks in a psl without reverse complementing them. */
+{
+int i;
+unsigned utmp;
+char *stmp; 
+for (i = 0; i < psl->blockCount; i++)
+    {
+    swapVars(psl->qStarts[i], psl->tStarts[i], utmp);
+    if (psl->qSequence != NULL)
+        swapVars(psl->qSequence[i], psl->tSequence[i], stmp);
+    }
+}
+
+static void swapRCBlocks(struct psl *psl)
+/* Swap and reverse complement blocks in a psl. Other psl fields must
+ * be modified first */
+{
+int i;
+unsigned *uatmp;
+char **satmp;
+reverseUnsigned(psl->tStarts, psl->blockCount);
+reverseUnsigned(psl->qStarts, psl->blockCount);
+reverseUnsigned(psl->blockSizes, psl->blockCount);
+swapVars(psl->tStarts, psl->qStarts, uatmp);
+
+/* qSize and tSize have already been swapped */
+for (i = 0; i < psl->blockCount; i++)
+    {
+    psl->qStarts[i] = psl->qSize - (psl->qStarts[i] + psl->blockSizes[i]);
+    psl->tStarts[i] = psl->tSize - (psl->tStarts[i] + psl->blockSizes[i]);
+    }
+if (psl->qSequence != NULL)
+    {
+    /* note: all block sequences are stored in one malloc block, which is
+     * entry zero */
+    rcSeqs(psl->qSequence, psl->blockCount, psl->blockSizes);
+    rcSeqs(psl->tSequence, psl->blockCount, psl->blockSizes);
+    swapVars(psl->qSequence, psl->tSequence, satmp);
+    }
+}
+
+void pslSwap(struct psl *psl, boolean noRc)
+/* swap query and target in psl.  If noRc is TRUE, don't reverse-complement
+ * PSL if needed, instead make target strand explict. */
+{
+int itmp;
+unsigned utmp;
+char ctmp, *stmp; 
+swapVars(psl->qBaseInsert, psl->tBaseInsert, utmp);
+swapVars(psl->tNumInsert, psl->qNumInsert, utmp);
+swapVars(psl->qName, psl->tName, stmp);
+swapVars(psl->qSize, psl->tSize, utmp);
+swapVars(psl->qStart, psl->tStart, itmp);
+swapVars(psl->qEnd, psl->tEnd, itmp);
+
+/* handle strand and block copy */
+if (psl->strand[1] != '\0')
+    {
+    /* translated */
+    swapVars(psl->strand[0], psl->strand[1], ctmp);
+    swapBlocks(psl);
+    }
+else if (noRc)
+    {
+    /* untranslated with no reverse complement */
+    psl->strand[1] = psl->strand[0];
+    psl->strand[0] = '+';
+    swapBlocks(psl);
+    }
+else
+    {
+    /* untranslated */
+    if (psl->strand[0] == '+')
+        swapBlocks(psl);
+    else
+        swapRCBlocks(psl);
+    }
+}
+
+void pslTargetOffset(struct psl *psl, int offset)
+/* Add offset to target positions in psl. */
+{
+int i, blockCount = psl->blockCount;
+unsigned *tStarts = psl->tStarts;
+psl->tStart += offset;
+psl->tEnd += offset;
+for (i=0; i<blockCount; ++i)
+   tStarts[i] += offset;
+}
+
+void pslDump(struct psl *psl, FILE *f)
+/* Dump most of PSL to file - for debugging. */
+{
+int i;
+fprintf(f, "<PRE>\n");
+fprintf(f, "psl %s:%d-%d %s %s:%d-%d %d\n", 
+	psl->qName, psl->qStart, psl->qEnd, psl->strand,
+	psl->tName, psl->tStart, psl->tEnd, psl->blockCount);
+for (i=0; i<psl->blockCount; ++i)
+    fprintf(f, "  size %d, qStart %d, tStart %d\n", 
+    	psl->blockSizes[i], psl->qStarts[i], psl->tStarts[i]);
+fprintf(f, "</PRE>");
+}
+
+static void pslRecalcBounds(struct psl *psl)
+/* Calculate qStart/qEnd tStart/tEnd at top level to be consistent
+ * with blocks. */
+{
+int qStart, qEnd, tStart, tEnd, size;
+int last = psl->blockCount - 1;
+qStart = psl->qStarts[0];
+tStart = psl->tStarts[0];
+size = psl->blockSizes[last];
+qEnd = psl->qStarts[last] + size;
+tEnd = psl->tStarts[last] + size;
+if (psl->strand[0] == '-')
+    reverseIntRange(&qStart, &qEnd, psl->qSize);
+if (psl->strand[1] == '-')
+    reverseIntRange(&tStart, &tEnd, psl->tSize);
+psl->qStart = qStart;
+psl->qEnd = qEnd;
+psl->tStart = tStart;
+psl->tEnd = tEnd;
+}
+
+struct psl *pslTrimToTargetRange(struct psl *oldPsl, int tMin, int tMax)
+/* Return psl trimmed to fit inside tMin/tMax.  Note this does not
+ * update the match/misMatch and related fields. */
+{
+int newSize;
+int oldBlockCount = oldPsl->blockCount;
+boolean tIsRc = (oldPsl->strand[1] == '-');
+int newBlockCount = 0, completeBlockCount = 0;
+int i;
+struct psl *newPsl = NULL;
+int tMn = tMin, tMx = tMax;   /* tMin/tMax adjusted for strand. */
+
+/* Deal with case where we're completely trimmed out quickly. */
+newSize = rangeIntersection(oldPsl->tStart, oldPsl->tEnd, tMin, tMax);
+if (newSize <= 0)
+    return NULL;
+
+if (tIsRc)
+    reverseIntRange(&tMn, &tMx, oldPsl->tSize);
+
+/* Count how many blocks will survive trimming. */
+oldBlockCount = oldPsl->blockCount;
+for (i=0; i<oldBlockCount; ++i)
+    {
+    int s = oldPsl->tStarts[i];
+    int e = s + oldPsl->blockSizes[i];
+    int sz = e - s;
+    int overlap;
+    if ((overlap = rangeIntersection(s, e, tMn, tMx)) > 0)
+        ++newBlockCount;
+    if (overlap == sz)
+        ++completeBlockCount;
+    }
+
+if (newBlockCount == 0)
+    return NULL;
+
+/* Allocate new psl and fill in what we already know. */
+AllocVar(newPsl);
+strcpy(newPsl->strand, oldPsl->strand);
+newPsl->qName = cloneString(oldPsl->qName);
+newPsl->qSize = oldPsl->qSize;
+newPsl->tName = cloneString(oldPsl->tName);
+newPsl->tSize = oldPsl->tSize;
+newPsl->blockCount = newBlockCount;
+AllocArray(newPsl->blockSizes, newBlockCount);
+AllocArray(newPsl->qStarts, newBlockCount);
+AllocArray(newPsl->tStarts, newBlockCount);
+
+/* Fill in blockSizes, qStarts, tStarts with real data. */
+newBlockCount = completeBlockCount = 0;
+for (i=0; i<oldBlockCount; ++i)
+    {
+    int oldSz = oldPsl->blockSizes[i];
+    int sz = oldSz;
+    int tS = oldPsl->tStarts[i];
+    int tE = tS + sz;
+    int qS = oldPsl->qStarts[i];
+    int qE = qS + sz;
+    if (rangeIntersection(tS, tE, tMn, tMx) > 0)
+        {
+	int diff;
+	if ((diff = (tMn - tS)) > 0)
+	    {
+	    tS += diff;
+	    qS += diff;
+	    sz -= diff;
+	    }
+	if ((diff = (tE - tMx)) > 0)
+	    {
+	    tE -= diff;
+	    qE -= diff;
+	    sz -= diff;
+	    }
+	newPsl->qStarts[newBlockCount] = qS;
+	newPsl->tStarts[newBlockCount] = tS;
+	newPsl->blockSizes[newBlockCount] = sz;
+	++newBlockCount;
+	if (sz == oldSz)
+	    ++completeBlockCount;
+	}
+    }
+pslRecalcBounds(newPsl);
+return newPsl;
+}
+
+struct psl *pslTrimToQueryRange(struct psl *oldPsl, int qMin, int qMax)
+/* Return psl trimmed to fit inside qMin/qMax.  Note this does not
+ * update the match/misMatch and related fields. */
+{
+int newSize;
+int oldBlockCount = oldPsl->blockCount;
+boolean qIsRc = (oldPsl->strand[0] == '-');
+int newBlockCount = 0, completeBlockCount = 0;
+int i;
+struct psl *newPsl = NULL;
+int qMn = qMin, qMx = qMax;   /* qMin/qMax adjusted for strand. */
+
+/* Deal with case where we're completely trimmed out quickly. */
+newSize = rangeIntersection(oldPsl->qStart, oldPsl->qEnd, qMin, qMax);
+if (newSize <= 0)
+    return NULL;
+
+if (qIsRc)
+    reverseIntRange(&qMn, &qMx, oldPsl->qSize);
+
+/* Count how many blocks will survive trimming. */
+oldBlockCount = oldPsl->blockCount;
+for (i=0; i<oldBlockCount; ++i)
+    {
+    int s = oldPsl->qStarts[i];
+    int e = s + oldPsl->blockSizes[i];
+    int sz = e - s;
+    int overlap;
+    if ((overlap = rangeIntersection(s, e, qMn, qMx)) > 0)
+        ++newBlockCount;
+    if (overlap == sz)
+        ++completeBlockCount;
+    }
+
+if (newBlockCount == 0)
+    return NULL;
+
+/* Allocate new psl and fill in what we already know. */
+AllocVar(newPsl);
+strcpy(newPsl->strand, oldPsl->strand);
+newPsl->qName = cloneString(oldPsl->qName);
+newPsl->qSize = oldPsl->qSize;
+newPsl->tName = cloneString(oldPsl->tName);
+newPsl->tSize = oldPsl->tSize;
+newPsl->blockCount = newBlockCount;
+AllocArray(newPsl->blockSizes, newBlockCount);
+AllocArray(newPsl->qStarts, newBlockCount);
+AllocArray(newPsl->tStarts, newBlockCount);
+
+/* Fill in blockSizes, qStarts, tStarts with real data. */
+newBlockCount = completeBlockCount = 0;
+for (i=0; i<oldBlockCount; ++i)
+    {
+    int oldSz = oldPsl->blockSizes[i];
+    int sz = oldSz;
+    int qS = oldPsl->qStarts[i];
+    int qE = qS + sz;
+    int tS = oldPsl->tStarts[i];
+    int tE = tS + sz;
+    if (rangeIntersection(qS, qE, qMn, qMx) > 0)
+        {
+	int diff;
+	if ((diff = (qMn - qS)) > 0)
+	    {
+	    tS += diff;
+	    qS += diff;
+	    sz -= diff;
+	    }
+	if ((diff = (qE - qMx)) > 0)
+	    {
+	    tE -= diff;
+	    qE -= diff;
+	    sz -= diff;
+	    }
+	newPsl->qStarts[newBlockCount] = qS;
+	newPsl->tStarts[newBlockCount] = tS;
+	newPsl->blockSizes[newBlockCount] = sz;
+	++newBlockCount;
+	if (sz == oldSz)
+	    ++completeBlockCount;
+	}
+    }
+pslRecalcBounds(newPsl);
+return newPsl;
+}
+char* pslGetCreateSql(char* table, unsigned options, int tNameIdxLen)
+/* Get SQL required to create PSL table.  Options is a bit set consisting
+ * of PSL_TNAMEIX, PSL_WITH_BIN, and PSL_XA_FORMAT.  tNameIdxLen is
+ * the number of characters in target name to index.  If greater than
+ * zero, must specify PSL_TNAMEIX.  If zero and PSL_TNAMEIX is specified,
+ * to will default to 8. */
+{
+struct dyString *sqlCmd = newDyString(2048);
+char *sqlCmdStr;
+char binIx[32];
+
+binIx[0] = '\0';
+
+/* check and default tNameIdxLen */
+if ((tNameIdxLen > 0) && !(options & PSL_TNAMEIX))
+    errAbort("pslGetCreateSql: must specify PSL_TNAMEIX with tNameIdxLen > 0");
+if ((options & PSL_TNAMEIX) && (tNameIdxLen == 0))
+    tNameIdxLen = 8;
+
+/* setup tName and bin index fields */
+if (options & PSL_WITH_BIN)
+    {
+    if (options & PSL_TNAMEIX)
+	safef(binIx, sizeof(binIx), "INDEX(tName(%d),bin),\n", tNameIdxLen);
+    else
+	safef(binIx, sizeof(binIx), "INDEX(bin),\n");
+    }
+else if (options & PSL_TNAMEIX)
+    safef(binIx, sizeof(binIx), "INDEX(tName(%d)),\n", tNameIdxLen);
+dyStringPrintf(sqlCmd, createString, table, 
+    ((options & PSL_WITH_BIN) ? "bin smallint unsigned not null,\n" : ""));
+if (options & PSL_XA_FORMAT)
+    {
+    dyStringPrintf(sqlCmd, "qSeq longblob not null,\n");
+    dyStringPrintf(sqlCmd, "tSeq longblob not null,\n");
+    }
+dyStringPrintf(sqlCmd, indexString, binIx);
+sqlCmdStr = cloneString(sqlCmd->string);
+dyStringFree(&sqlCmd);
+return sqlCmdStr;
+}
+
+static void printPslDesc(char* pslDesc, FILE* out, struct psl* psl)
+/* print description of a PSL on first error */
+{
+fprintf(out, "Error: invalid PSL: %s:%u-%u %s:%u-%u %s %s\n",
+        psl->qName, psl->qStart, psl->qEnd,
+        psl->tName, psl->tStart, psl->tEnd,
+        psl->strand, pslDesc);
+}
+
+
+static void chkError(char* pslDesc, FILE* out, struct psl* psl, int* errCount, char* format, ...)
+/* forward needed to specify printf signature for gcc checking */
+#if defined(__GNUC__)
+__attribute__((format(printf, 5, 6)))
+#endif
+;
+
+static void chkError(char* pslDesc, FILE* out, struct psl* psl, int* errCount, char* format, ...)
+/* error handling on an pslCheck error, counting error and issuing description
+ * of PSL on the first error. */
+{
+if (*errCount == 0)
+    printPslDesc(pslDesc, out, psl);
+va_list args;
+va_start(args, format);
+vfprintf(out, format, args);
+va_end(args);
+(*errCount)++;
+}
+
+static void chkBlkRanges(char* pslDesc, FILE* out, struct psl* psl,
+                         char* pName, char* pLabel, char pCLabel, char pStrand,
+                         unsigned pSize, unsigned pStart, unsigned pEnd,
+                         unsigned iBlk, unsigned* blockSizes,
+                         unsigned* pBlockStarts, int* errCount)
+/* check the target or query ranges in a PSL incrementing errorCnt */
+{
+unsigned blkStart = pBlockStarts[iBlk];
+unsigned blkEnd = blkStart+blockSizes[iBlk];
+/* translate stand to genomic coords */
+unsigned gBlkStart = (pStrand == '+') ? blkStart : (pSize - blkEnd);
+unsigned gBlkEnd = (pStrand == '+') ? blkEnd : (pSize - blkStart);
+
+if ((pSize > 0) && (blkEnd > pSize))
+    chkError(pslDesc, out, psl, errCount,
+             "\t%s %s block %u end %u > %cSize %u\n",
+             pName, pLabel, iBlk, blkEnd, pCLabel, pSize);
+if (gBlkStart < pStart)
+    chkError(pslDesc, out, psl, errCount,
+             "\t%s %s block %u start %u < %cStart %u\n",
+             pName, pLabel, iBlk, gBlkStart, pCLabel, pStart);
+if (gBlkStart >= pEnd)
+    chkError(pslDesc, out, psl, errCount,
+             "\t%s %s block %u start %u >= %cEnd %u\n",
+             pName, pLabel, iBlk, gBlkStart, pCLabel, pEnd);
+if (gBlkEnd < pStart)
+    chkError(pslDesc, out, psl, errCount,
+             "\t%s %s block %u end %u < %cStart %u\n",
+             pName, pLabel, iBlk, gBlkEnd, pCLabel, pStart);
+if (gBlkEnd > pEnd)
+    chkError(pslDesc, out, psl, errCount,
+             "\t%s %s block %u end %u > %cEnd %u\n",
+             pName, pLabel, iBlk, gBlkEnd, pCLabel, pEnd);
+if (iBlk > 0)
+    {
+    unsigned prevBlkEnd = pBlockStarts[iBlk-1]+blockSizes[iBlk-1];
+    if (blkStart < prevBlkEnd)
+        chkError(pslDesc, out, psl, errCount,
+                 "\t%s %s block %u start %u < previous block end %u\n",
+                 pName, pLabel, iBlk, blkStart, prevBlkEnd);
+    }
+}
+
+static void chkRanges(char* pslDesc, FILE* out, struct psl* psl,
+                      char* pName, char* pLabel, char pCLabel, char pStrand,
+                      unsigned pSize, unsigned pStart, unsigned pEnd,
+                      unsigned blockCount, unsigned* blockSizes,
+                      unsigned* pBlockStarts, int blockSizeMult, int* errCount)
+/* check the target or query ranges in a PSL, increment errorCnt */
+{
+unsigned iBlk;
+if (pStart >= pEnd)
+    chkError(pslDesc, out, psl, errCount,
+             "\t%s %cStart %u >= %cEnd %u\n",
+             pName, pCLabel, pStart, pCLabel, pEnd);
+if (pEnd > pSize)
+    chkError(pslDesc, out, psl, errCount,
+             "\t%s %cEnd %u >= %cSize %u\n",
+             pName, pCLabel, pEnd, pCLabel, pSize);
+// check that block start/end matches overall start end
+unsigned pStartStrand = pStart, pEndStrand = pEnd;
+if (pStrand != '+')
+    reverseUnsignedRange(&pStartStrand, &pEndStrand, pSize);
+unsigned lastBlkEnd = pBlockStarts[blockCount-1] + (blockSizeMult * blockSizes[blockCount-1]);
+if ((pStartStrand != pBlockStarts[0]) || (pEndStrand != lastBlkEnd))
+    chkError(pslDesc, out, psl, errCount,
+             "\t%s strand \"%c\" adjusted %cStart-%cEnd range %u-%u != block range %u-%u\n",
+             pName, pStrand, pCLabel, pCLabel, pStartStrand, pEndStrand, pBlockStarts[0], lastBlkEnd);
+
+for (iBlk = 0; iBlk < blockCount; iBlk++)
+    chkBlkRanges(pslDesc, out, psl, pName, pLabel, pCLabel, pStrand,
+                 pSize, pStart, pEnd, iBlk, blockSizes, pBlockStarts, errCount);
+}
+
+int pslCheck(char *pslDesc, FILE* out, struct psl* psl)
+/* Validate a PSL for consistency.  pslDesc is printed the error messages
+ * to file out (open /dev/null to discard). Return count of errors. */
+{
+static char* VALID_STRANDS[] = {
+    "+", "-", "++", "+-", "-+", "--", NULL
+};
+int i, errCount = 0;
+int tBlockSizeMult = pslIsProtein(psl) ? 3 : 1;
+
+/* check strand value */
+for (i = 0; VALID_STRANDS[i] != NULL; i++)
+    {
+    if (strcmp(psl->strand, VALID_STRANDS[i]) == 0)
+        break;
+    }
+if (VALID_STRANDS[i] == NULL)
+    chkError(pslDesc, out, psl, &errCount,
+             "\tinvalid PSL strand: \"%s\"\n", psl->strand);
+
+/* check target */
+chkRanges(pslDesc, out, psl, psl->tName, "target", 't', pslTStrand(psl), psl->tSize, psl->tStart, psl->tEnd,
+          psl->blockCount, psl->blockSizes, psl->tStarts, tBlockSizeMult, &errCount);
+
+/* check query */
+chkRanges(pslDesc, out, psl, psl->qName, "query", 'q', pslQStrand(psl), psl->qSize, psl->qStart, psl->qEnd,
+          psl->blockCount, psl->blockSizes, psl->qStarts, 1, &errCount);
+
+return errCount;
+}
+
+struct hash *readPslToBinKeeper(char *sizeFileName, char *pslFileName)
+/* read a list of psls and return results in hash of binKeeper structure for fast query*/
+{
+struct binKeeper *bk; 
+struct psl *psl;
+struct lineFile *sf = lineFileOpen(sizeFileName, TRUE);
+struct lineFile *pf = lineFileOpen(pslFileName , TRUE);
+struct hash *hash = newHash(0);
+char *chromRow[2];
+char *row[21] ;
+
+while (lineFileRow(sf, chromRow))
+    {
+    char *name = chromRow[0];
+    int size = lineFileNeedNum(sf, chromRow, 1);
+
+    if (hashLookup(hash, name) != NULL)
+        warn("Duplicate %s, ignoring all but first\n", name);
+    else
+        {
+        bk = binKeeperNew(0, size);
+        assert(size > 1);
+	hashAdd(hash, name, bk);
+        }
+    }
+while (lineFileNextRow(pf, row, ArraySize(row)))
+    {
+    psl = pslLoad(row);
+    bk = hashMustFindVal(hash, psl->tName);
+    binKeeperAdd(bk, psl->tStart, psl->tEnd, psl);
+    }
+lineFileClose(&pf);
+lineFileClose(&sf);
+return hash;
+}
+
+static boolean isDelChar(char c)
+/* is this a indel character? */
+{
+return (c == '-') || (c == '.') || (c == '=') || (c == '_');
+}
+
+static void trimAlignment(struct psl* psl, char** qStrPtr, char** tStrPtr,
+                          int* aliSizePtr)
+/* remove leading or trailing indels from alignment */
+{
+char* qStr = *qStrPtr;
+char* tStr = *tStrPtr;
+int aliSize = *aliSizePtr;
+
+// skip lending indels
+while ((aliSize > 0) && (isDelChar(*qStr) || isDelChar(*tStr)))
+    {
+    if (!isDelChar(*qStr))
+        psl->qStart++;
+    else if (!isDelChar(*tStr))
+        psl->tStart++;
+    qStr++;
+    tStr++;
+    aliSize--;
+    }
+
+// skip trailing indels
+while ((aliSize > 0) && (isDelChar(qStr[aliSize-1]) || isDelChar(tStr[aliSize-1])))
+    {
+    if (!isDelChar(qStr[aliSize-1]))
+        psl->qEnd--;
+    else if (!isDelChar(tStr[aliSize-1]))
+        psl->tEnd--;
+    aliSize--;
+    }
+*qStrPtr = qStr;
+*tStrPtr = tStr;
+*aliSizePtr = aliSize;
+}
+
+static void addBlock(struct psl* psl, int qs, int qe, int ts, int te,
+                     int *blockSpace)
+/* add a block to the psl, growing if necessary */
+{
+assert((qe-qs) == (te-ts));  /* same lengths? */
+if (psl->blockCount == *blockSpace)
+    pslGrow(psl, blockSpace);
+psl->blockSizes[psl->blockCount] = qe - qs;
+psl->qStarts[psl->blockCount] = qs;
+psl->tStarts[psl->blockCount] = ts;
+psl->blockCount++;
+}
+
+static void accumCounts(struct psl *psl, char prevQ, char prevT,
+                        char q, char t, unsigned options)
+/* accumulate block and base counts  */
+{
+if (!isDelChar(q) && !isDelChar(t))
+    {
+    /* aligned column. */
+    char qu = toupper(q);
+    char tu = toupper(t);
+    if ((q == 'N') || (t == 'N'))
+        psl->nCount++;
+    else if (qu == tu)
+        {
+        if ((options & PSL_IS_SOFTMASK) && ((qu != q) || (tu != t)))
+            psl->repMatch++;
+        else
+            psl->match++;
+        }
+    else
+        psl->misMatch++;
+    }
+else if (isDelChar(q) && !isDelChar(t))
+    {
+    /* target insert */
+    psl->tBaseInsert++;
+    if (!isDelChar(prevQ))
+        psl->tNumInsert++;
+    }
+else if (isDelChar(t) && !isDelChar(q))
+    {
+    /* query insert */
+    psl->qBaseInsert++;
+    if (!isDelChar(prevT))
+        psl->qNumInsert++;
+    }
+}
+
+struct psl* pslFromAlign(char *qName, int qSize, int qStart, int qEnd, char *qString,
+                         char *tName, int tSize, int tStart, int tEnd, char *tString,
+                         char* strand, unsigned options)
+/* Create a PSL from an alignment.  Options PSL_IS_SOFTMASK if lower case
+ * bases indicate repeat masking.  Returns NULL if alignment is empty after
+ * triming leading and trailing indels.*/
+{
+/* Note, the unit tests for these programs exercise this function:
+ *   hg/embossToPsl
+ *   hg/mouseStuff/axtToPsl
+ *   hg/spideyToPsl
+ *   utils/est2genomeToPsl
+ */
+
+int blockSpace = 16;
+struct psl* psl = NULL;
+int aliSize = strlen(qString);
+boolean eitherInsert = FALSE;	/* True if either in insert state. */
+int i, qs,qe,ts,te;
+char prevQ = '\0',  prevT = '\0';
+AllocVar(psl);
+
+if (strlen(tString) != aliSize)
+    errAbort("query and target alignment strings are different lengths");
+
+psl = pslNew(qName, qSize, qStart, qEnd, tName, tSize, tStart, tEnd,
+             strand, blockSpace, 0);
+trimAlignment(psl, &qString, &tString, &aliSize);
+
+/* Don't create if either query or target is zero length after trim */
+ if ((psl->qStart == psl->qEnd) || (psl->tStart == psl->tEnd))
+     {
+     pslFree(&psl);
+     return NULL;
+     }
+
+/* Get range of alignment in strand-specified coordinates */
+qs = psl->qStart;
+qe = psl->qEnd;
+if (strand[0] == '-')
+    reverseIntRange(&qs, &qe, psl->qSize);
+ts = psl->tStart;
+te = psl->tEnd;
+if (strand[1] == '-')
+    reverseIntRange(&ts, &te, psl->tSize);
+
+eitherInsert = FALSE;
+qe = qs;  /* current block coords */
+te = ts;
+for (i=0; i<aliSize; ++i)
+    {
+    char q = qString[i];
+    char t = tString[i];
+    if (isDelChar(q) && isDelChar(t))
+        {
+        continue; /* nothing in this column, just ignore it */
+        }
+    else if (isDelChar(q) || isDelChar(t))
+        {
+        /* insert in one of the columns */
+	if (!eitherInsert)
+	    {
+            /* end of a block */
+            addBlock(psl, qs, qe, ts, te, &blockSpace);
+	    eitherInsert = TRUE;
+	    }
+	if (!isDelChar(q))
+            qe += 1;
+	if (!isDelChar(t))
+            te += 1;
+	}
+    else
+        {
+        /* columns aligned */
+	if (eitherInsert)
+	    {
+            /* start new block */
+	    qs = qe;
+	    ts = te;
+	    eitherInsert = FALSE;
+	    }
+	qe += 1;
+	te += 1;
+	}
+    accumCounts(psl, prevQ, prevT, q, t, options);
+    prevQ = q; /* will not include skipped empty columns */
+    prevT = t;
+    }
+addBlock(psl, qs, qe, ts, te, &blockSpace);
+return psl;
+}
+
+struct psl* pslNew(char *qName, unsigned qSize, int qStart, int qEnd,
+                   char *tName, unsigned tSize, int tStart, int tEnd,
+                   char *strand, unsigned blockSpace, unsigned opts)
+/* create a new psl with space for the specified number of blocks allocated.
+ * pslGrow maybe used to expand this space if needed.  Valid options are
+ * PSL_XA_FORMAT. */
+{
+struct psl *psl;
+AllocVar(psl);
+assert(blockSpace > 0);
+psl->qName = cloneString(qName);
+psl->qSize = qSize;
+psl->qStart = qStart;
+psl->qEnd = qEnd;
+psl->tName = cloneString(tName);
+psl->tSize = tSize;
+psl->tStart = tStart;
+psl->tEnd = tEnd;
+strncpy(psl->strand, strand, 2);
+AllocArray(psl->blockSizes, blockSpace);
+AllocArray(psl->qStarts, blockSpace);
+AllocArray(psl->tStarts, blockSpace);
+if (opts & PSL_XA_FORMAT)
+    {
+    AllocArray(psl->qSequence, blockSpace);
+    AllocArray(psl->tSequence, blockSpace);
+    }
+return psl;
+}
+
+void pslGrow(struct psl *psl, int *blockSpacePtr)
+/* Increase memory allocated to a psl to hold more blocks.  blockSpacePtr
+ * should point the the current maximum number of blocks and will be
+ * updated to with the new amount of space. */
+{
+int blockSpace = *blockSpacePtr;
+int newSpace = 2 * blockSpace;
+ExpandArray(psl->blockSizes, blockSpace, newSpace);
+ExpandArray(psl->qStarts, blockSpace, newSpace);
+ExpandArray(psl->tStarts, blockSpace, newSpace);
+if (psl->qSequence != NULL)
+    {
+    ExpandArray(psl->qSequence, blockSpace, newSpace);
+    ExpandArray(psl->tSequence, blockSpace, newSpace);
+    }
+*blockSpacePtr = newSpace;
+}
+
+static boolean getNextCigarOp(char **ptr, char *op, int *size)
+/* parts the next cigar op */
+{
+char *str = *ptr;
+
+if ((str == NULL) || (*str == 0))
+    return FALSE;
+
+char *end = strchr(str, '+');
+if (end)
+    {
+    *end = 0;
+    *ptr = end + 1;
+    }
+else 
+    *ptr = NULL;
+
+*op = *str++;
+*size = atoi(str);
+
+return TRUE;
+}
+
+struct psl* pslFromGff3Cigar(char *qName, int qSize, int qStart, int qEnd,
+                             char *tName, int tSize, int tStart, int tEnd,
+                             char* strand, char *cigar)
+/* create a PSL from a GFF3-style cigar formatted alignment */
+{
+// this is currently tested by the gff3ToPsl
+int blocksAlloced = 4;
+struct psl *psl = pslNew(qName, qSize, qStart, qEnd, tName, tSize, tStart, tEnd, strand, blocksAlloced, 0);
+
+char cigarSpec[strlen(cigar+1)];  // copy since parsing is destructive
+strcpy(cigarSpec, cigar);
+char *cigarNext = cigarSpec;
+char op;
+int size;
+int qNext = qStart, qBlkEnd = qEnd;
+if (strand[0] == '-')
+    reverseIntRange(&qNext, &qBlkEnd, qSize);
+int tNext = tStart, tBlkEnd = tEnd;
+if (strand[1] == '-')
+    reverseIntRange(&tNext, &tBlkEnd, tSize);
+
+while(getNextCigarOp(&cigarNext, &op, &size))
+    {
+    switch (op)
+        {
+        case 'M': // match or mismatch (gapless aligned block)
+            if (psl->blockCount == blocksAlloced)
+                pslGrow(psl, &blocksAlloced);
+
+            psl->blockSizes[psl->blockCount] = size;
+            psl->qStarts[psl->blockCount] = qNext;
+            psl->tStarts[psl->blockCount] = tNext;
+            psl->blockCount++;
+            tNext += size;
+            qNext += size;
+            break;
+        case 'I': // inserted in target
+            tNext += size;
+            break;
+        case 'D': // deleted from target
+            qNext += size;
+            break;
+        
+        default:
+            errAbort("unrecognized CIGAR op %c in %s", op, cigar);
+        }
+    }
+assert(qNext == qBlkEnd);
+assert(tNext == tBlkEnd);
+return psl;
+}
+
+int pslRangeTreeOverlap(struct psl *psl, struct rbTree *rangeTree)
+/* Return amount that psl overlaps (on target side) with rangeTree. */
+{
+int i;
+int overlap = 0;
+boolean isRc = (psl->strand[1] == '-');
+for (i=0; i<psl->blockCount; ++i)
+    {
+    int start = psl->tStarts[i];
+    int end = start + psl->blockSizes[i];
+    if (isRc)
+        reverseIntRange(&start, &end, psl->tSize);
+    overlap += rangeTreeOverlapSize(rangeTree, start, end);
+    }
+return overlap;
+}
+
+float pslIdent(struct psl *psl)
+/* computer fraction identity */
+{
+float aligned = psl->match + psl->misMatch + psl->repMatch;
+if (aligned == 0.0)
+    return 0.0;
+else
+    return ((float)(psl->match + psl->repMatch))/aligned;
+}
+
+float pslQueryAligned(struct psl *psl)
+/* compute fraction of query that was aligned */
+{
+float aligned = psl->match + psl->misMatch + psl->repMatch;
+return aligned/(float)psl->qSize;
+}
+
diff --git a/lib/psl.sql b/lib/psl.sql
new file mode 100644
index 0000000..8a1698a
--- /dev/null
+++ b/lib/psl.sql
@@ -0,0 +1,33 @@
+# as_psl.sql was originally generated by the autoSql program, which also 
+# generated as_psl.c and as_psl.h.  This creates the database representation of
+# an object which can be loaded and saved from RAM in a fairly 
+# automatic way.
+
+#Summary info about a patSpace alignment
+CREATE TABLE psl (
+    matches int unsigned not null,	# Number of bases that match that aren't repeats
+    misMatches int unsigned not null,	# Number of bases that don't match
+    repMatches int unsigned not null,	# Number of bases that match but are part of repeats
+    nCount int unsigned not null,	# Number of 'N' bases
+    qNumInsert int unsigned not null,	# Number of inserts in query
+    qBaseInsert int unsigned not null,	# Number of bases inserted in query
+    tNumInsert int unsigned not null,	# Number of inserts in target
+    tBaseInsert int unsigned not null,	# Number of bases inserted in target
+    strand char(2) not null,	# + or - for strand
+    qName varchar(255) not null,	# Query sequence name
+    qSize int unsigned not null,	# Query sequence size
+    qStart int unsigned not null,	# Alignment start position in query
+    qEnd int unsigned not null,	# Alignment end position in query
+    tName varchar(255) not null,	# Target sequence name
+    tSize int unsigned not null,	# Target sequence size
+    tStart int unsigned not null,	# Alignment start position in target
+    tEnd int unsigned not null,	# Alignment end position in target
+    blockCount int unsigned not null,	# Number of blocks in alignment
+    blockSizes longblob not null,	# Size of each block
+    qStarts longblob not null,	# Start of each block in query.
+    tStarts longblob not null,	# Start of each block in target.
+              #Indices
+    INDEX(tStart),
+    INDEX(qName(12)),
+    INDEX(tEnd)
+);
diff --git a/lib/pslGenoShow.c b/lib/pslGenoShow.c
new file mode 100644
index 0000000..08dd8ea
--- /dev/null
+++ b/lib/pslGenoShow.c
@@ -0,0 +1,346 @@
+/* Show aligned exons between a pre-located gene (a stamper gene) in the genome 
+ *and its homologues (stamp elements) in the genome. 
+ *The aligned exon sequences are shown in blue as regular blat alignment. 
+ * The unaligned exon sequence are shown in red. Intron sequences are shown in black.
+ * It is modified from pslShow.c */
+
+
+#include "common.h"
+#include "dnaseq.h"
+#include "htmshell.h"
+#include "psl.h"
+#include "cda.h"
+#include "seqOut.h"
+
+
+static void pslShowAlignmentStranded2(struct psl *psl, boolean isProt,
+	char *qName, bioSeq *qSeq, int qStart, int qEnd,
+	char *tName, bioSeq *tSeq, int tStart, int tEnd, int exnStarts[], int exnEnds[], int exnCnt, FILE *f)
+/* Show stamper gene and stamp elements alignment using genomic sequence.
+ * The aligned exons' sequence of stamper gene are shown in colors as usual, but the
+ * the unaligned exon's sequence of stamper gene are shown in red color.
+ */
+{
+boolean tIsRc = (psl->strand[1] == '-');
+boolean qIsRc = (psl->strand[0] == '-');
+int mulFactor = (isProt ? 3 : 1);
+DNA *dna = NULL;	/* Mixed case version of genomic DNA. */
+int qSize = qSeq->size;
+char *qLetters = cloneString(qSeq->dna);
+int qbafStart, qbafEnd, tbafStart, tbafEnd;
+int qcfmStart, qcfmEnd, tcfmStart, tcfmEnd;
+
+int lineWidth = isProt ? 60 : 50;
+
+tbafStart = tStart;
+tbafEnd   = tEnd;
+tcfmStart = tStart;
+tcfmEnd   = tEnd;
+
+qbafStart = qStart;
+qbafEnd   = qEnd;
+qcfmStart = qStart;
+qcfmEnd   = qEnd;
+
+/* Deal with minus strand. */
+if (tIsRc)
+    {
+    int temp;
+    reverseComplement(tSeq->dna, tSeq->size);
+
+    tbafStart = tEnd;
+    tbafEnd   = tStart;
+    tcfmStart = tEnd;
+    tcfmEnd   = tStart;
+    
+    temp = psl->tSize - tEnd;
+    tEnd = psl->tSize - tStart;
+    tStart = temp;
+    }
+if (qIsRc)
+    {
+    int temp, j;
+    reverseComplement(qSeq->dna, qSeq->size);
+    reverseComplement(qLetters, qSeq->size);
+
+    qcfmStart = qEnd;
+    qcfmEnd   = qStart;
+    qbafStart = qEnd;
+    qbafEnd   = qStart;
+    
+    temp = psl->qSize - qEnd;
+    qEnd = psl->qSize - qStart;
+    qStart = temp;
+    for(j = 0; j < exnCnt; j++)
+	{
+	temp = psl->qSize - exnStarts[j];
+	exnStarts[j] = psl->qSize - exnEnds[j];
+	exnEnds[j] = temp;
+	}
+    reverseInts(exnEnds, exnCnt);
+    reverseInts(exnStarts, exnCnt);
+    }
+
+dna = cloneString(tSeq->dna);
+
+if (qName == NULL) 
+    qName = psl->qName;
+if (tName == NULL)
+    tName = psl->tName;
+
+
+fputs("Matching bases are colored blue and capitalized. " 
+      "Light blue bases mark the boundaries of gaps in either aligned sequence. "
+      "Red bases are unaligned exons' bases of the query gene. \n", f);
+
+fprintf(f, "<H4><A NAME=cDNA></A>%s%s</H4>\n", qName, (qIsRc  ? " (reverse complemented)" : ""));
+fprintf(f, "<PRE><TT>");
+tolowers(qLetters);
+
+/* Display query sequence. */
+    {
+    struct cfm *cfm;
+    char *colorFlags = needMem(qSeq->size);
+    int i = 0, j = 0, exnIdx = 0;
+    int preStop = 0;
+    
+    for (i=0; i<psl->blockCount; ++i)
+	{
+	int qs = psl->qStarts[i] - qStart;
+	int ts = psl->tStarts[i] - tStart;
+	int sz = psl->blockSizes[i]-1;
+	int end = 0;
+	bool omitExon = FALSE;
+	while(exnIdx < exnCnt && psl->qStarts[i] > exnEnds[exnIdx])
+	    {
+	    if(omitExon)
+		{
+		for( j = exnStarts[exnIdx] - qStart; j < exnEnds[exnIdx]-qStart; j++)
+		    {
+		    colorFlags[j] = socRed;
+		    }
+		}
+	    exnIdx++;
+	    preStop = exnStarts[exnIdx] - qStart;
+	    omitExon = TRUE;
+	    }
+
+	/*mark the boundary bases */
+	colorFlags[qs] = socBrightBlue;
+	qLetters[qs] = toupper(qLetters[qs]);
+	colorFlags[qs+sz] = socBrightBlue;
+	qLetters[qs+sz] = toupper(qLetters[qs+sz]);
+	
+	/* determine block end */
+	if( i < psl->blockCount -1)
+	    end = psl->qStarts[i+1] < exnEnds[exnIdx] ? psl->qStarts[i+1] - qStart : exnEnds[exnIdx] - qStart;
+	else
+	    end = qs + sz;
+	    
+	for (j=preStop; j < end; j++)
+	    {
+	    if(j == 82)
+		fprintf(stderr, "right here\n");
+	    if (j > qs && j < qs+sz)
+		{
+		if (qSeq->dna[j] == tSeq->dna[ts+j-qs])
+		    {
+		    colorFlags[j] = socBlue;
+		    qLetters[j] = toupper(qLetters[j]);
+		    }		
+		}
+	    else if(colorFlags[j] != socBrightBlue && colorFlags[j] != socBlue)
+		colorFlags[j] = socRed;
+	    }
+	preStop = end;
+	}
+    cfm = cfmNew(10, lineWidth, TRUE, qIsRc, f, qcfmStart);
+    for (i=0; i<qSize; ++i)
+	cfmOut(cfm, qLetters[i], seqOutColorLookup[(int)colorFlags[i]]);
+    cfmFree(&cfm);
+    freez(&colorFlags);
+    htmHorizontalLine(f);
+    }
+fprintf(f, "</TT></PRE>\n");
+fprintf(f, "<H4><A NAME=genomic></A>%s %s:</H4>\n", 
+	tName, (tIsRc ? "(reverse strand)" : ""));
+fprintf(f, "<PRE><TT>");
+
+/* Display DNA sequence. */
+    {
+    struct cfm *cfm;
+    char *colorFlags = needMem(tSeq->size);
+    int i,j;
+    int curBlock = 0;
+
+    for (i=0; i<psl->blockCount; ++i)
+	{
+	int qs = psl->qStarts[i] - qStart;
+	int ts = psl->tStarts[i] - tStart;
+	int sz = psl->blockSizes[i];
+	if (isProt)
+	    {
+	    for (j=0; j<sz; ++j)
+		{
+		AA aa = qSeq->dna[qs+j];
+		int codonStart = ts + 3*j;
+		DNA *codon = &tSeq->dna[codonStart];
+		AA trans = lookupCodon(codon);
+		if (trans != 'X' && trans == aa)
+		    {
+		    colorFlags[codonStart] = socBlue;
+		    colorFlags[codonStart+1] = socBlue;
+		    colorFlags[codonStart+2] = socBlue;
+		    toUpperN(dna+codonStart, 3);
+		    }
+		}
+	    }
+	else
+	    {
+	    for (j=0; j<sz; ++j)
+		{
+		if (qSeq->dna[qs+j] == tSeq->dna[ts+j])
+		    {
+		    colorFlags[ts+j] = socBlue;
+		    dna[ts+j] = toupper(dna[ts+j]);
+		    }
+		}
+	    }
+	colorFlags[ts] = socBrightBlue;
+	colorFlags[ts+sz*mulFactor-1] = socBrightBlue;
+	}
+
+    cfm = cfmNew(10, lineWidth, TRUE, tIsRc, f, tcfmStart);
+	
+    for (i=0; i<tSeq->size; ++i)
+	{
+	/* Put down "anchor" on first match position in haystack
+	 * so user can hop here with a click on the needle. */
+	if (curBlock < psl->blockCount && psl->tStarts[curBlock] == (i + tStart) )
+	    {
+	    fprintf(f, "<A NAME=%d></A>", ++curBlock);
+	    /* Watch out for (rare) out-of-order tStarts! */
+	    while (curBlock < psl->blockCount &&
+		   psl->tStarts[curBlock] <= tStart + i)
+		curBlock++;
+	    }
+	cfmOut(cfm, dna[i], seqOutColorLookup[(int)colorFlags[i]]);
+	}
+    cfmFree(&cfm);
+    freez(&colorFlags);
+    htmHorizontalLine(f);
+    }
+
+/* Display side by side. */
+fprintf(f, "</TT></PRE>\n");
+fprintf(f, "<H4><A NAME=ali></A>Side by Side Alignment*</H4>\n");
+fprintf(f, "<PRE><TT>");
+    {
+    struct baf baf;
+    int i,j;
+
+    bafInit(&baf, qSeq->dna, qbafStart, qIsRc,
+	    tSeq->dna, tbafStart, tIsRc, f, lineWidth, isProt);
+		
+    if (isProt)
+	{
+	for (i=0; i<psl->blockCount; ++i)
+	    {
+	    int qs = psl->qStarts[i] - qStart;
+	    int ts = psl->tStarts[i] - tStart;
+	    int sz = psl->blockSizes[i];
+
+	    bafSetPos(&baf, qs, ts);
+	    bafStartLine(&baf);
+	    for (j=0; j<sz; ++j)
+		{
+		AA aa = qSeq->dna[qs+j];
+		int codonStart = ts + 3*j;
+		DNA *codon = &tSeq->dna[codonStart];
+		bafOut(&baf, ' ', codon[0]);
+		bafOut(&baf, aa, codon[1]);
+		bafOut(&baf, ' ', codon[2]);
+		}
+	    bafFlushLine(&baf);
+	    }
+	fprintf( f, "<I>*when aa is different, BLOSUM positives are in green, BLOSUM negatives in red</I>\n");
+	}
+    else
+	{
+	int lastQe = psl->qStarts[0] - qStart;
+	int lastTe = psl->tStarts[0] - tStart;
+	int maxSkip = 8;
+	bafSetPos(&baf, lastQe, lastTe);
+	bafStartLine(&baf);
+	for (i=0; i<psl->blockCount; ++i)
+	    {
+	    int qs = psl->qStarts[i] - qStart;
+	    int ts = psl->tStarts[i] - tStart;
+	    int sz = psl->blockSizes[i];
+	    boolean doBreak = TRUE;
+	    int qSkip = qs - lastQe;
+	    int tSkip = ts - lastTe;
+
+	    if (qSkip >= 0 && qSkip <= maxSkip && tSkip == 0)
+		{
+		for (j=0; j<qSkip; ++j)
+		    bafOut(&baf, qSeq->dna[lastQe+j], '-');
+		doBreak = FALSE;
+		}
+	    else if (tSkip > 0 && tSkip <= maxSkip && qSkip == 0)
+		{
+		for (j=0; j<tSkip; ++j)
+		    bafOut(&baf, '-', tSeq->dna[lastTe+j]);
+		doBreak = FALSE;
+		}
+	    if (doBreak)
+		{
+		bafFlushLine(&baf);
+		bafSetPos(&baf, qs, ts);
+		bafStartLine(&baf);
+		}
+	    for (j=0; j<sz; ++j)
+		bafOut(&baf, qSeq->dna[qs+j], tSeq->dna[ts+j]);
+	    lastQe = qs + sz;
+	    lastTe = ts + sz;
+	    }
+	bafFlushLine(&baf);
+
+	fprintf( f, "<I>*Aligned Blocks with gaps <= %d bases are merged for this display</I>\n", maxSkip);
+	}
+    }
+fprintf(f, "</TT></PRE>");
+if (qIsRc)
+    reverseComplement(qSeq->dna, qSeq->size);
+if (tIsRc)
+    reverseComplement(tSeq->dna, tSeq->size);
+freeMem(dna);
+freeMem(qLetters);
+}
+
+
+int pslGenoShowAlignment(struct psl *psl, boolean isProt,
+	char *qName, bioSeq *qSeq, int qStart, int qEnd,
+	char *tName, bioSeq *tSeq, int tStart, int tEnd, int exnStarts[], int exnEnds[], int exnCnt, FILE *f)
+/* Show aligned exons between a pre-located gene (a stamper gene)and its homologues (stamp elements)
+ * in the genome. The aligned exon sequences are shown in blue as regular blat alignment. * The unaligned exon sequence are shown in red. Intron sequences are shown in black */
+{
+/* At this step we just do a little shuffling of the strands for
+ * untranslated DNA alignments. */
+char origStrand[2];
+boolean needsSwap = (psl->strand[0] == '-' && psl->strand[1] == 0);
+if (needsSwap)
+    {
+    memcpy(origStrand, psl->strand, 2);
+    pslRc(psl);
+    }
+pslShowAlignmentStranded2(psl, isProt, qName, qSeq, qStart, qEnd,
+    tName, tSeq, tStart, tEnd,exnStarts, exnEnds, exnCnt, f);
+if (needsSwap)
+    {
+    pslRc(psl);
+    memcpy(psl->strand, origStrand, 2);
+    }
+return psl->blockCount;
+}
+
diff --git a/lib/pslShow.c b/lib/pslShow.c
new file mode 100644
index 0000000..c827e9a
--- /dev/null
+++ b/lib/pslShow.c
@@ -0,0 +1,317 @@
+/* pslShow - stuff to help visual psl format alignments. 
+ * This file is copyright 2002-2004 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "dnaseq.h"
+#include "htmshell.h"
+#include "psl.h"
+#include "cda.h"
+#include "seqOut.h"
+
+
+static void pslShowAlignmentStranded(struct psl *psl, boolean isProt,
+	char *qName, bioSeq *qSeq, int qStart, int qEnd,
+	char *tName, bioSeq *tSeq, int tStart, int tEnd, FILE *f)
+/* Show protein/DNA alignment or translated DNA alignment in HTML format. */
+{
+boolean tIsRc = (psl->strand[1] == '-');
+boolean qIsRc = (psl->strand[0] == '-');
+int mulFactor = (isProt ? 3 : 1);
+DNA *dna = NULL;	/* Mixed case version of genomic DNA. */
+int qSize = qSeq->size;
+char *qLetters = cloneString(qSeq->dna);
+int qbafStart, qbafEnd, tbafStart, tbafEnd;
+int qcfmStart, qcfmEnd, tcfmStart, tcfmEnd;
+
+int lineWidth = isProt ? 60 : 50;
+
+tbafStart = tStart;
+tbafEnd   = tEnd;
+tcfmStart = tStart;
+tcfmEnd   = tEnd;
+
+qbafStart = qStart;
+qbafEnd   = qEnd;
+qcfmStart = qStart;
+qcfmEnd   = qEnd;
+
+/* Deal with minus strand. */
+if (tIsRc)
+    {
+    int temp;
+    reverseComplement(tSeq->dna, tSeq->size);
+
+    tbafStart = tEnd;
+    tbafEnd   = tStart;
+    tcfmStart = tEnd;
+    tcfmEnd   = tStart;
+
+    temp = psl->tSize - tEnd;
+    tEnd = psl->tSize - tStart;
+    tStart = temp;
+    }
+if (qIsRc)
+    {
+    int temp;
+    reverseComplement(qSeq->dna, qSeq->size);
+    reverseComplement(qLetters, qSeq->size);
+
+    qcfmStart = qEnd;
+    qcfmEnd   = qStart;
+    qbafStart = qEnd;
+    qbafEnd   = qStart;
+    
+    temp = psl->qSize - qEnd;
+    qEnd = psl->qSize - qStart;
+    qStart = temp;
+    }
+dna = cloneString(tSeq->dna);
+
+if (qName == NULL) 
+    qName = psl->qName;
+if (tName == NULL)
+    tName = psl->tName;
+
+
+fputs("Matching bases are colored blue and capitalized. " 
+      "Light blue bases mark the boundaries of gaps in either sequence.\n", f);
+
+fprintf(f, "<H4><A NAME=cDNA></A>%s%s</H4>\n", qName, (qIsRc  ? " (reverse complemented)" : ""));
+fprintf(f, "<PRE><TT>");
+tolowers(qLetters);
+
+/* Display query sequence. */
+    {
+    struct cfm *cfm;
+    char *colorFlags = needMem(qSeq->size);
+    int i,j;
+
+    for (i=0; i<psl->blockCount; ++i)
+	{
+	int qs = psl->qStarts[i] - qStart;
+	int ts = psl->tStarts[i] - tStart;
+	int sz = psl->blockSizes[i]-1;
+	colorFlags[qs] = socBrightBlue;
+	qLetters[qs] = toupper(qLetters[qs]);
+	colorFlags[qs+sz] = socBrightBlue;
+	qLetters[qs+sz] = toupper(qLetters[qs+sz]);
+	if (isProt)
+	    {
+	    for (j=1; j<sz; ++j)
+		{
+		AA aa = qSeq->dna[qs+j];
+		DNA *codon = &tSeq->dna[ts + 3*j];
+		AA trans = lookupCodon(codon);
+		if (trans != 'X' && trans == aa)
+		    {
+		    colorFlags[qs+j] = socBlue;
+		    qLetters[qs+j] = toupper(qLetters[qs+j]);
+		    }
+		}
+	    }
+	else
+	    {
+	    for (j=1; j<sz; ++j)
+		{
+		if (qSeq->dna[qs+j] == tSeq->dna[ts+j])
+		    {
+		    colorFlags[qs+j] = socBlue;
+		    qLetters[qs+j] = toupper(qLetters[qs+j]);
+		    }
+		}
+	    }
+	}
+    cfm = cfmNew(10, lineWidth, TRUE, qIsRc, f, qcfmStart);
+    for (i=0; i<qSize; ++i)
+	cfmOut(cfm, qLetters[i], seqOutColorLookup[(int)colorFlags[i]]);
+    cfmFree(&cfm);
+    freez(&colorFlags);
+    htmHorizontalLine(f);
+    }
+fprintf(f, "</TT></PRE>\n");
+fprintf(f, "<H4><A NAME=genomic></A>%s %s:</H4>\n", 
+	tName, (tIsRc ? "(reverse strand)" : ""));
+fprintf(f, "<PRE><TT>");
+
+/* Display DNA sequence. */
+    {
+    struct cfm *cfm;
+    char *colorFlags = needMem(tSeq->size);
+    int i,j;
+    int curBlock = 0;
+
+    for (i=0; i<psl->blockCount; ++i)
+	{
+	int qs = psl->qStarts[i] - qStart;
+	int ts = psl->tStarts[i] - tStart;
+	int sz = psl->blockSizes[i];
+	if (isProt)
+	    {
+	    for (j=0; j<sz; ++j)
+		{
+		AA aa = qSeq->dna[qs+j];
+		int codonStart = ts + 3*j;
+		DNA *codon = &tSeq->dna[codonStart];
+		AA trans = lookupCodon(codon);
+		if (trans != 'X' && trans == aa)
+		    {
+		    colorFlags[codonStart] = socBlue;
+		    colorFlags[codonStart+1] = socBlue;
+		    colorFlags[codonStart+2] = socBlue;
+		    toUpperN(dna+codonStart, 3);
+		    }
+		}
+	    }
+	else
+	    {
+	    for (j=0; j<sz; ++j)
+		{
+		if (qSeq->dna[qs+j] == tSeq->dna[ts+j])
+		    {
+		    colorFlags[ts+j] = socBlue;
+		    dna[ts+j] = toupper(dna[ts+j]);
+		    }
+		}
+	    }
+	colorFlags[ts] = socBrightBlue;
+	colorFlags[ts+sz*mulFactor-1] = socBrightBlue;
+	}
+
+    cfm = cfmNew(10, lineWidth, TRUE, tIsRc, f, tcfmStart);
+	
+    for (i=0; i<tSeq->size; ++i)
+	{
+	/* Put down "anchor" on first match position in haystack
+	 * so user can hop here with a click on the needle. */
+	if (curBlock < psl->blockCount && psl->tStarts[curBlock] == (i + tStart) )
+	    {
+	    fprintf(f, "<A NAME=%d></A>", ++curBlock);
+	    /* Watch out for (rare) out-of-order tStarts! */
+	    while (curBlock < psl->blockCount &&
+		   psl->tStarts[curBlock] <= tStart + i)
+		curBlock++;
+	    }
+	cfmOut(cfm, dna[i], seqOutColorLookup[(int)colorFlags[i]]);
+	}
+    cfmFree(&cfm);
+    freez(&colorFlags);
+    htmHorizontalLine(f);
+    }
+
+/* Display side by side. */
+fprintf(f, "</TT></PRE>\n");
+fprintf(f, "<H4><A NAME=ali></A>Side by Side Alignment*</H4>\n");
+fprintf(f, "<PRE><TT>");
+    {
+    struct baf baf;
+    int i,j;
+
+    bafInit(&baf, qSeq->dna, qbafStart, qIsRc,
+	    tSeq->dna, tbafStart, tIsRc, f, lineWidth, isProt);
+		
+    if (isProt)
+	{
+	for (i=0; i<psl->blockCount; ++i)
+	    {
+	    int qs = psl->qStarts[i] - qStart;
+	    int ts = psl->tStarts[i] - tStart;
+	    int sz = psl->blockSizes[i];
+
+	    bafSetPos(&baf, qs, ts);
+	    bafStartLine(&baf);
+	    for (j=0; j<sz; ++j)
+		{
+		AA aa = qSeq->dna[qs+j];
+		int codonStart = ts + 3*j;
+		DNA *codon = &tSeq->dna[codonStart];
+		bafOut(&baf, ' ', codon[0]);
+		bafOut(&baf, aa, codon[1]);
+		bafOut(&baf, ' ', codon[2]);
+		}
+	    bafFlushLine(&baf);
+	    }
+	fprintf( f, 
+"<I>*When the translated amino acid in the genomic sequence differs from the \n"
+"corresponding amino acid in the protein, the coloring indicates the\n"
+"similarity of the two amino acids.  Similar amino acids are green, \n"
+"dissimilar amino acids are red.  The sign of the corresponding entry in\n"
+"the BLOSUM 62 matrix is used as the basis of this coloring.</I>\n");
+	}
+    else
+	{
+	int lastQe = psl->qStarts[0] - qStart;
+	int lastTe = psl->tStarts[0] - tStart;
+	int maxSkip = 8;
+	bafSetPos(&baf, lastQe, lastTe);
+	bafStartLine(&baf);
+	for (i=0; i<psl->blockCount; ++i)
+	    {
+	    int qs = psl->qStarts[i] - qStart;
+	    int ts = psl->tStarts[i] - tStart;
+	    int sz = psl->blockSizes[i];
+	    boolean doBreak = TRUE;
+	    int qSkip = qs - lastQe;
+	    int tSkip = ts - lastTe;
+
+	    if (qSkip >= 0 && qSkip <= maxSkip && tSkip == 0)
+		{
+		for (j=0; j<qSkip; ++j)
+		    bafOut(&baf, qSeq->dna[lastQe+j], '-');
+		doBreak = FALSE;
+		}
+	    else if (tSkip > 0 && tSkip <= maxSkip && qSkip == 0)
+		{
+		for (j=0; j<tSkip; ++j)
+		    bafOut(&baf, '-', tSeq->dna[lastTe+j]);
+		doBreak = FALSE;
+		}
+	    if (doBreak)
+		{
+		bafFlushLine(&baf);
+		bafSetPos(&baf, qs, ts);
+		bafStartLine(&baf);
+		}
+	    for (j=0; j<sz; ++j)
+		bafOut(&baf, qSeq->dna[qs+j], tSeq->dna[ts+j]);
+	    lastQe = qs + sz;
+	    lastTe = ts + sz;
+	    }
+	bafFlushLine(&baf);
+
+	fprintf( f, "<I>*Aligned Blocks with gaps <= %d bases are merged for this display</I>\n", maxSkip);
+	}
+    }
+fprintf(f, "</TT></PRE>");
+if (qIsRc)
+    reverseComplement(qSeq->dna, qSeq->size);
+if (tIsRc)
+    reverseComplement(tSeq->dna, tSeq->size);
+freeMem(dna);
+freeMem(qLetters);
+}
+
+int pslShowAlignment(struct psl *psl, boolean isProt,
+	char *qName, bioSeq *qSeq, int qStart, int qEnd,
+	char *tName, bioSeq *tSeq, int tStart, int tEnd, FILE *f)
+/* Show protein/DNA alignment or translated DNA alignment in HTML format. */
+{
+/* At this step we just do a little shuffling of the strands for
+ * untranslated DNA alignments. */
+char origStrand[2];
+boolean needsSwap = (psl->strand[0] == '-' && psl->strand[1] == 0);
+if (needsSwap)
+    {
+    memcpy(origStrand, psl->strand, 2);
+    pslRc(psl);
+    }
+pslShowAlignmentStranded(psl, isProt, qName, qSeq, qStart, qEnd,
+    tName, tSeq, tStart, tEnd, f);
+if (needsSwap)
+    {
+    pslRc(psl);
+    memcpy(psl->strand, origStrand, 2);
+    }
+return psl->blockCount;
+}
+
diff --git a/lib/pslTbl.c b/lib/pslTbl.c
new file mode 100644
index 0000000..6c596e6
--- /dev/null
+++ b/lib/pslTbl.c
@@ -0,0 +1,86 @@
+/* table of psl alignments, grouped by query */
+#include "common.h"
+#include "pslTbl.h"
+#include "psl.h"
+#include "hash.h"
+#include "linefile.h"
+#include "localmem.h"
+
+static struct pslQuery *pslQueryGet(struct pslTbl *pslTbl,
+                                    char *qName)
+/* get pslQuery object for qName, creating if it doesn't exist. */
+{
+struct hashEl *qHel = hashStore(pslTbl->queryHash, qName);
+if (qHel->val == NULL)
+    {
+    struct pslQuery *pslQuery;
+    lmAllocVar(pslTbl->queryHash->lm, pslQuery);
+    pslQuery->qName = qHel->name;
+    qHel->val = pslQuery;
+    }
+return qHel->val;
+}
+
+static void loadPsl(struct pslTbl *pslTbl, char **row)
+/* load a psl record into the table */
+{
+struct psl *psl = pslLoadLm(row, pslTbl->queryHash->lm);
+struct pslQuery *pslQuery = pslQueryGet(pslTbl, psl->qName);
+slAddHead(&pslQuery->psls, psl);
+}
+
+static void loadPsls(struct pslTbl *pslTbl, char *pslFile)
+/* load a psl records into the table */
+{
+struct lineFile *lf = lineFileOpen(pslFile, TRUE);
+char *row[PSL_NUM_COLS];
+while (lineFileNextRowTab(lf, row, ArraySize(row)))
+    loadPsl(pslTbl, row);
+lineFileClose(&lf);
+}
+
+struct pslTbl *pslTblNew(char *pslFile, char *setName)
+/* construct a new object, loading the psl file.  If setName is NULL, the file
+* name is saved as the set name. */
+{
+struct pslTbl *pslTbl;
+AllocVar(pslTbl);
+pslTbl->setName = (setName == NULL) ? cloneString(pslFile)
+    : cloneString(setName);
+pslTbl->queryHash = hashNew(22);
+loadPsls(pslTbl, pslFile);
+return pslTbl;
+}
+
+void pslTblFree(struct pslTbl **pslTblPtr)
+/* free object */
+{
+struct pslTbl *pslTbl = *pslTblPtr;
+if (pslTbl != NULL)
+    {
+    /* pslQuery and psl objects are in local mem */
+    freeMem(pslTbl->setName);
+    hashFree(&pslTbl->queryHash);
+    freeMem(pslTbl);
+    }
+}
+
+void pslTblFreeList(struct pslTbl **pslTblList)
+/* free list of pslTbls */
+{
+struct pslTbl *pslTbl = *pslTblList;
+while (pslTbl != NULL)
+    {
+    struct pslTbl *pslTblDel = pslTbl;
+    pslTbl = pslTbl->next;
+    pslTblFree(&pslTblDel);
+    }
+*pslTblList = NULL;
+}
+
+/*
+ * Local Variables:
+ * c-file-style: "jkent-c"
+ * End:
+ */
+
diff --git a/lib/pslTransMap.c b/lib/pslTransMap.c
new file mode 100644
index 0000000..34c21d1
--- /dev/null
+++ b/lib/pslTransMap.c
@@ -0,0 +1,325 @@
+/* pslTransMap - transitive mapping of an alignment another sequence, via a
+ * common alignment */
+#include "common.h"
+#include "pslTransMap.h"
+#include "psl.h"
+
+/*
+ * Notes:
+ *  - This code is used with both large and small mapping psls.  Large
+ *    psls used for doing cross-species mappings and small psl are used for
+ *    doing protein to mRNA mappings.  This introduces some speed issues.  For
+ *    chain mapping, a large amount of time is spent in getBlockMapping()
+ *    searching for the starting point of a mapping.  However an optimization
+ *    to find the starting point, such as a binKeeper, could be inefficient
+ *    for a large number of small psls.  Implementing such an optimzation
+ *    would have to be dependent on the type of mapping.  The code was made
+ *    16x faster for genome mappings by remembering the current location in
+ *    the mapping psl between blocks (iMapBlkPtr arg).  This will do for a
+ *    while.
+ */
+
+
+struct block
+/* coordinates of a block */
+{
+    int qStart;          /* Query start position. */
+    int qEnd;            /* Query end position. */
+    int tStart;          /* Target start position. */
+    int tEnd;            /* Target end position. */
+};
+
+static void pslProtToNA(struct psl *psl)
+/* convert a protein/NA alignment to a NA/NA alignment */
+{
+int iBlk;
+
+psl->qStart *= 3;
+psl->qEnd *= 3;
+psl->qSize *= 3;
+for (iBlk = 0; iBlk < psl->blockCount; iBlk++)
+    {
+    psl->blockSizes[iBlk] *= 3;
+    psl->qStarts[iBlk] *= 3;
+    }
+}
+
+static void pslNAToProt(struct psl *psl)
+/* undo pslProtToNA */
+{
+int iBlk;
+
+psl->qStart /= 3;
+psl->qEnd /= 3;
+psl->qSize /= 3;
+for (iBlk = 0; iBlk < psl->blockCount; iBlk++)
+    {
+    psl->blockSizes[iBlk] /= 3;
+    psl->qStarts[iBlk] /= 3;
+    }
+}
+
+static struct psl* createMappedPsl(struct psl* inPsl, struct psl *mapPsl,
+                                   int mappedPslMax)
+/* setup a PSL for the output alignment */
+{
+char strand[3];
+assert(pslTStrand(inPsl) == pslQStrand(mapPsl));
+
+/* strand can be taken from both alignments, since common sequence is in same
+ * orientation. */
+strand[0] = pslQStrand(inPsl);
+strand[1] = pslTStrand(mapPsl);
+strand[2] = '\n';
+
+return pslNew(inPsl->qName, inPsl->qSize, 0, 0,
+              mapPsl->tName, mapPsl->tSize, 0, 0,
+              strand, mappedPslMax, 0);
+}
+
+static struct block blockFromPslBlock(struct psl* psl, int iBlock)
+/* fill in a block object from a psl block */
+{
+struct block block;
+block.qStart = psl->qStarts[iBlock];
+block.qEnd = psl->qStarts[iBlock] + psl->blockSizes[iBlock];
+block.tStart = psl->tStarts[iBlock];
+block.tEnd = psl->tStarts[iBlock] + psl->blockSizes[iBlock];
+return block;
+}
+
+static void addPslBlock(struct psl* psl, struct block* blk, int* pslMax)
+/* add a block to a psl */
+{
+unsigned newIBlk = psl->blockCount;
+
+assert((blk->qEnd - blk->qStart) == (blk->tEnd - blk->tStart));
+if (newIBlk >= *pslMax)
+    pslGrow(psl, pslMax);
+psl->qStarts[newIBlk] = blk->qStart;
+psl->tStarts[newIBlk] = blk->tStart;
+psl->blockSizes[newIBlk] = blk->qEnd - blk->qStart;
+/* lie about match counts. */
+psl->match += psl->blockSizes[newIBlk];
+/* count gaps */
+if (newIBlk > 0)
+    {
+    if (psl->qStarts[newIBlk] > pslQEnd(psl, newIBlk-1))
+        {
+        psl->qNumInsert++;
+        psl->qBaseInsert += psl->qStarts[newIBlk] - pslQEnd(psl, newIBlk-1);
+        }
+    if (psl->tStarts[newIBlk] > pslTEnd(psl, newIBlk-1))
+        {
+        psl->tNumInsert++;
+        psl->tBaseInsert += psl->tStarts[newIBlk] - pslTEnd(psl, newIBlk-1);
+        }
+    }
+psl->blockCount++;
+}
+
+static void setPslBounds(struct psl* mappedPsl)
+/* set sequences bounds on mapped PSL */
+{
+int lastBlk = mappedPsl->blockCount-1;
+
+/* set start/end of sequences */
+mappedPsl->qStart = mappedPsl->qStarts[0];
+mappedPsl->qEnd = mappedPsl->qStarts[lastBlk] + mappedPsl->blockSizes[lastBlk];
+if (pslQStrand(mappedPsl) == '-')
+    reverseIntRange(&mappedPsl->qStart, &mappedPsl->qEnd, mappedPsl->qSize);
+
+mappedPsl->tStart = mappedPsl->tStarts[0];
+mappedPsl->tEnd = mappedPsl->tStarts[lastBlk] + mappedPsl->blockSizes[lastBlk];
+if (pslTStrand(mappedPsl) == '-')
+    reverseIntRange(&mappedPsl->tStart, &mappedPsl->tEnd, mappedPsl->tSize);
+}
+
+static void adjustOrientation(unsigned opts, struct psl *inPsl, char *inPslOrigStrand,
+                              struct psl* mappedPsl)
+/* adjust strand, possibly reverse complementing, based on
+ * pslTransMapKeepTrans option and input psls. */
+{
+if (!(opts&pslTransMapKeepTrans) || ((inPslOrigStrand[1] == '\0') && (mappedPsl->strand[1] == '\0')))
+    {
+    /* make untranslated */
+    if (pslTStrand(mappedPsl) == '-')
+        pslRc(mappedPsl);
+    mappedPsl->strand[1] = '\0';  /* implied target strand */
+    }
+}
+
+static struct block getBeforeBlockMapping(unsigned mqStart, unsigned mqEnd,
+                                          struct block* align1Blk)
+/* map part of an ungapped psl block that occurs before a mapPsl block */
+{
+struct block mappedBlk;
+
+/* mRNA start in genomic gap before this block, this will
+ * be an inPsl insert */
+unsigned size = (align1Blk->tEnd < mqStart)
+    ? (align1Blk->tEnd - align1Blk->tStart)
+    : (mqStart - align1Blk->tStart);
+ZeroVar(&mappedBlk);
+mappedBlk.qStart = align1Blk->qStart;
+mappedBlk.qEnd = align1Blk->qStart + size;
+return mappedBlk;
+}
+
+static struct block getOverBlockMapping(unsigned mqStart, unsigned mqEnd,
+                                        unsigned mtStart, struct block* align1Blk)
+/* map part of an ungapped psl block that overlapps a mapPsl block. */
+{
+struct block mappedBlk;
+
+/* common sequence start contained in this block, this handles aligned
+ * and genomic inserts */
+unsigned off = align1Blk->tStart - mqStart;
+unsigned size = (align1Blk->tEnd > mqEnd)
+    ? (mqEnd - align1Blk->tStart)
+    : (align1Blk->tEnd - align1Blk->tStart);
+ZeroVar(&mappedBlk);
+mappedBlk.qStart = align1Blk->qStart;
+mappedBlk.qEnd = align1Blk->qStart + size;
+mappedBlk.tStart = mtStart + off;
+mappedBlk.tEnd = mtStart + off + size;
+return mappedBlk;
+}
+
+static struct block getBlockMapping(struct psl* inPsl, struct psl *mapPsl,
+                                    int *iMapBlkPtr, struct block* align1Blk)
+/* Map part or all of a ungapped psl block to the genome.  This returns the
+ * coordinates of the sub-block starting at the beginning of the align1Blk.
+ * If this is a gap, either the target or query coords are zero.  This works
+ * in genomic strand space.  The search starts at the specified map block,
+ * which is updated to prevent rescanning large psls.
+ */
+{
+int iBlk;
+struct block mappedBlk;
+
+/* search for block or gap containing start of mrna block */
+for (iBlk = *iMapBlkPtr; iBlk < mapPsl->blockCount; iBlk++)
+    {
+    unsigned mqStart = mapPsl->qStarts[iBlk];
+    unsigned mqEnd = mapPsl->qStarts[iBlk]+mapPsl->blockSizes[iBlk];
+    if (align1Blk->tStart < mqStart)
+        {
+        *iMapBlkPtr = iBlk;
+        return getBeforeBlockMapping(mqStart, mqEnd, align1Blk);
+        }
+    if ((align1Blk->tStart >= mqStart) && (align1Blk->tStart < mqEnd))
+        {
+        *iMapBlkPtr = iBlk;
+        return getOverBlockMapping(mqStart, mqEnd, mapPsl->tStarts[iBlk], align1Blk);
+        }
+    }
+
+/* reached the end of the mRNA->genome alignment, finish off the 
+ * rest of the the protein as an insert */
+ZeroVar(&mappedBlk);
+mappedBlk.qStart = align1Blk->qStart;
+mappedBlk.qEnd = align1Blk->qEnd;
+*iMapBlkPtr = iBlk;
+return mappedBlk;
+}
+
+static boolean mapBlock(struct psl *inPsl, struct psl *mapPsl, int *iMapBlkPtr,
+                        struct block *align1Blk, struct psl* mappedPsl,
+                        int* mappedPslMax)
+/* Add a PSL block from a ungapped portion of an alignment, mapping it to the
+ * genome.  If the started of the inPsl block maps to a part of the mapPsl
+ * that is aligned, it is added as a PSL block, otherwise the gap is skipped.
+ * Block starts are adjusted for next call.  Return FALSE if the end of the
+ * alignment is reached. */
+{
+struct block mappedBlk;
+unsigned size;
+assert(align1Blk->qStart <= align1Blk->qEnd);
+assert(align1Blk->tStart <= align1Blk->tEnd);
+assert((align1Blk->qEnd - align1Blk->qStart) == (align1Blk->tEnd - align1Blk->tStart));
+
+if ((align1Blk->qStart >= align1Blk->qEnd) || (align1Blk->tStart >= align1Blk->tEnd))
+    return FALSE;  /* end of ungapped block. */
+
+/* find block or gap with start coordinates of mrna */
+mappedBlk = getBlockMapping(inPsl, mapPsl, iMapBlkPtr, align1Blk);
+
+if ((mappedBlk.qEnd != 0) && (mappedBlk.tEnd != 0))
+    addPslBlock(mappedPsl, &mappedBlk, mappedPslMax);
+
+/* advance past block or gap */
+size = (mappedBlk.qEnd != 0)
+    ? (mappedBlk.qEnd - mappedBlk.qStart)
+    : (mappedBlk.tEnd - mappedBlk.tStart);
+align1Blk->qStart += size;
+align1Blk->tStart += size;
+
+return TRUE;
+}
+
+struct psl* pslTransMap(unsigned opts, struct psl *inPsl, struct psl *mapPsl)
+/* map a psl via a mapping psl, a single psl is returned, or NULL if it
+ * couldn't be mapped. */
+{
+int mappedPslMax = 8; /* allocated space in output psl */
+int iMapBlk = 0;
+char inPslOrigStrand[3];
+boolean rcInPsl = (pslTStrand(inPsl) != pslQStrand(mapPsl));
+boolean cnv1 = (pslIsProtein(inPsl) && !pslIsProtein(mapPsl));
+boolean cnv2 = (pslIsProtein(mapPsl) && !pslIsProtein(inPsl));
+int iBlock;
+struct psl* mappedPsl;
+
+/* sanity check size, but allow names to vary to allow ids to have
+ * unique-ifying suffixes. */
+if (inPsl->tSize != mapPsl->qSize)
+    errAbort("Error: inPsl %s tSize (%d) != mapPsl %s qSize (%d)",
+            inPsl->tName, inPsl->tSize, mapPsl->qName, mapPsl->qSize);
+
+/* convert protein PSLs */
+if (cnv1)
+    pslProtToNA(inPsl);
+if (cnv2)
+    pslProtToNA(mapPsl);
+
+/* need to ensure common sequence is in same orientation, save strand for later */
+safef(inPslOrigStrand, sizeof(inPslOrigStrand), "%s", inPsl->strand);
+if (rcInPsl)
+    pslRc(inPsl);
+
+mappedPsl = createMappedPsl(inPsl, mapPsl, mappedPslMax);
+
+/* Fill in ungapped blocks.  */
+for (iBlock = 0; iBlock < inPsl->blockCount; iBlock++)
+    {
+    struct block align1Blk = blockFromPslBlock(inPsl, iBlock);
+    while (mapBlock(inPsl, mapPsl, &iMapBlk, &align1Blk, mappedPsl,
+                    &mappedPslMax))
+        continue;
+    }
+
+/* finish up psl, or free if no blocks were added */
+assert(mappedPsl->blockCount <= mappedPslMax);
+if (mappedPsl->blockCount == 0)
+    pslFree(&mappedPsl);  /* nothing made it */
+else
+    {
+    setPslBounds(mappedPsl);
+    adjustOrientation(opts, inPsl, inPslOrigStrand, mappedPsl);
+    }
+
+/* restore input */
+if (rcInPsl)
+    {
+    pslRc(inPsl);
+    strcpy(inPsl->strand, inPslOrigStrand);
+    }
+if (cnv1)
+    pslNAToProt(inPsl);
+if (cnv2)
+    pslNAToProt(mapPsl);
+
+return mappedPsl;
+}
+
diff --git a/lib/pslWScore.as b/lib/pslWScore.as
new file mode 100644
index 0000000..59bf474
--- /dev/null
+++ b/lib/pslWScore.as
@@ -0,0 +1,26 @@
+table pslWScore
+"Summary info about a patSpace alignment with a score addition"
+    (
+    uint    match;      "Number of bases that match that aren't repeats"
+    uint    misMatch;   "Number of bases that don't match"
+    uint    repMatch;   "Number of bases that match but are part of repeats"
+    uint    nCount;       "Number of 'N' bases"
+    uint    qNumInsert;   "Number of inserts in query"
+    int     qBaseInsert;  "Number of bases inserted in query"
+    uint    tNumInsert;   "Number of inserts in target"
+    int     tBaseInsert;  "Number of bases inserted in target"
+    char[2] strand;       "+ or - for query strand. For mouse second +/- for genomic strand"
+    string  qName;        "Query sequence name"
+    uint    qSize;        "Query sequence size"
+    uint    qStart;       "Alignment start position in query"
+    uint    qEnd;         "Alignment end position in query"
+    string  tName;        "Target sequence name"
+    uint    tSize;        "Target sequence size"
+    uint    tStart;       "Alignment start position in target"
+    uint    tEnd;         "Alignment end position in target"
+    uint    blockCount;   "Number of blocks in alignment"
+    uint[blockCount] blockSizes;  "Size of each block"
+    uint[blockCount] qStarts;     "Start of each block in query."
+    uint[blockCount] tStarts;     "Start of each block in target."
+    float     score;         "score field"
+    )
diff --git a/lib/pslWScore.sql b/lib/pslWScore.sql
new file mode 100644
index 0000000..80f40ad
--- /dev/null
+++ b/lib/pslWScore.sql
@@ -0,0 +1,31 @@
+# pslWScore.sql was originally generated by the autoSql program, which also 
+# generated pslWScore.c and pslWScore.h.  This creates the database representation of
+# an object which can be loaded and saved from RAM in a fairly 
+# automatic way.
+
+#Summary info about a patSpace alignment with a score addition
+CREATE TABLE uniGene (
+    matches int unsigned not null,	# Number of bases that match that arent repeats
+    misMatch int unsigned not null,	# Number of bases that dont match
+    repMatch int unsigned not null,	# Number of bases that match but are part of repeats
+    nCount int unsigned not null,	# Number of N bases
+    qNumInsert int unsigned not null,	# Number of inserts in query
+    qBaseInsert int not null,	# Number of bases inserted in query
+    tNumInsert int unsigned not null,	# Number of inserts in target
+    tBaseInsert int not null,	# Number of bases inserted in target
+    strand char(2) not null,	# + or - for query strand. For mouse second +- for genomic strand
+    qName varchar(255) not null,	# Query sequence name
+    qSize int unsigned not null,	# Query sequence size
+    qStart int unsigned not null,	# Alignment start position in query
+    qEnd int unsigned not null,	# Alignment end position in query
+    tName varchar(255) not null,	# Target sequence name
+    tSize int unsigned not null,	# Target sequence size
+    tStart int unsigned not null,	# Alignment start position in target
+    tEnd int unsigned not null,	# Alignment end position in target
+    blockCount int unsigned not null,	# Number of blocks in alignment
+    blockSizes longblob not null,	# Size of each block
+    qStarts longblob not null,	# Start of each block in query.
+    tStarts longblob not null,	# Start of each block in target.
+    score float not null,	# score field
+    index(tName(32),tStart,tEnd)
+);
diff --git a/lib/pthreadWrap.c b/lib/pthreadWrap.c
new file mode 100644
index 0000000..fcc89b3
--- /dev/null
+++ b/lib/pthreadWrap.c
@@ -0,0 +1,102 @@
+/* pthreadWrap - error checking wrappers around Posix
+ * thread functions.  Most of the errors here are invariably
+ * fatal, but shouldn't happen unless the kernal or
+ * the program is hosed. */
+
+#include "common.h"
+#include "errabort.h"
+#include "pthreadWrap.h"
+
+
+static void pwarn(char *function, int err)
+/* Print a warning message on non-zero error code. */
+{
+if (err != 0)
+    warn("Couldn't %s: %s\n", function, strerror(err));
+}
+
+static void perr(char *function, int err)
+/* Print out error for function and abort on
+ * non-zero error code.. */
+{
+if (err != 0)
+    {
+    pwarn(function, err);
+    noWarnAbort();
+    }
+}
+
+void pthreadCreate(pthread_t *thread, const pthread_attr_t *attr,
+	void *(*start_routine)(void *), void *arg)
+/* Create a thread or squawk and die. */
+{
+int err = pthread_create(thread, attr, start_routine, arg);
+perr("pthread_create", err);
+}
+
+boolean pthreadMayCreate(pthread_t *thread, const pthread_attr_t *attr,
+	void *(*start_routine)(void *), void *arg)
+/* Create a thread.  Warn and return FALSE if there is a problem. */
+{
+int err = pthread_create(thread, attr, start_routine, arg);
+pwarn("pthread_create", err);
+return err == 0;
+}
+
+void pthreadMutexInit(pthread_mutex_t *mutex)
+/* Initialize mutex or die trying */
+{
+int err = pthread_mutex_init(mutex, NULL);
+perr("pthread_mutex_init", err);
+}
+
+void pthreadMutexDestroy(pthread_mutex_t *mutex)
+/* Free up mutex. */
+{
+int err = pthread_mutex_destroy(mutex);
+perr("pthread_mutex_destroy", err);
+}
+
+void pthreadMutexLock(pthread_mutex_t *mutex)
+/* Lock a mutex to gain exclusive access or die trying. */
+{
+int err = pthread_mutex_lock(mutex);
+perr("pthread_mutex_lock", err);
+}
+
+void pthreadMutexUnlock(pthread_mutex_t *mutex)
+/* Unlock a mutex or die trying. */
+{
+int err = pthread_mutex_unlock(mutex);
+perr("pthread_mutex_unlock", err);
+}
+
+void pthreadCondInit(pthread_cond_t *cond)
+/* Initialize pthread conditional. */
+{
+int err = pthread_cond_init(cond, NULL);
+perr("pthread_cond_init", err);
+}
+
+void pthreadCondDestroy(pthread_cond_t *cond)
+/* Free up conditional. */
+{
+int err = pthread_cond_destroy(cond);
+perr("pthread_cond_destroy", err);
+}
+
+void pthreadCondSignal(pthread_cond_t *cond)
+/* Set conditional signal to wake up a sleeping thread, or
+ * die trying. */
+{
+int err = pthread_cond_signal(cond);
+perr("pthread_cond_signal", err);
+}
+
+void pthreadCondWait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+/* Wait for conditional signal. */
+{
+int err = pthread_cond_wait(cond, mutex);
+perr("pthread_cond_wait", err);
+}
+
diff --git a/lib/qa.c b/lib/qa.c
new file mode 100644
index 0000000..65f171f
--- /dev/null
+++ b/lib/qa.c
@@ -0,0 +1,219 @@
+/* qa - Modules to help do testing, especially on html based apps. */
+
+#include "common.h"
+#include "hash.h"
+#include "dystring.h"
+#include "portable.h"
+#include "htmlPage.h"
+#include "errabort.h"
+#include "errCatch.h"
+#include "htmshell.h"
+#include "qa.h"
+
+
+char *qaStringBetween(char *text, char *startPattern, char *endPattern)
+/* Return text that occurs between startPattern and endPattern,
+ * or NULL if no startPattern.  (Will return up to 100 characters
+ * after startPattern if there is no endPattern) */
+{
+char *startMid = stringIn(startPattern, text);
+if (startMid != NULL)
+    {
+    char *endMid;
+    int midSize;
+    startMid += strlen(startPattern);
+    endMid = stringIn(startMid, endPattern);
+    if (endMid == NULL)
+        {
+	midSize = strlen(startMid);
+	if (midSize > 100)
+	    midSize = 100;
+	}
+    else
+        midSize = endMid - startMid;
+    return cloneStringZ(startMid, midSize);
+    }
+return NULL;
+}
+
+char *qaScanForErrorMessage(char *text)
+/* Scan text for error message.  If one exists then
+ * return copy of it.  Else return NULL. */
+{
+return qaStringBetween(text, htmlWarnStartPattern(), htmlWarnEndPattern());
+}
+
+int qaCountBetween(char *s, char *startPattern, char *endPattern, 
+	char *midPattern)
+/* Count the number of midPatterns that occur between start and end pattern. */
+{
+int count = 0;
+char *e;
+s = stringIn(startPattern, s);
+if (s != NULL)
+    {
+    s += strlen(startPattern);
+    e = stringIn(endPattern, s);
+    while (s < e)
+        {
+	if (startsWith(midPattern, s))
+	    ++count;
+	s += 1;
+	}
+    }
+return count;
+}
+
+void qaStatusReportOne(FILE *f, struct qaStatus *qs, char *format, ...)
+/* Report status */
+{
+char *errMessage = qs->errMessage;
+char *severity = "ok";
+va_list args;
+va_start(args, format);
+if (errMessage == NULL)
+    errMessage = "";
+else
+    {
+    if (qs->hardError)
+        severity = "hard";
+    else
+        severity = "soft";
+    }
+  
+vfprintf(f, format, args);
+fprintf(f, " %4.3fs (%s) %s\n", 0.001*qs->milliTime, severity, errMessage);
+va_end(args);
+}
+
+static struct qaStatus *qaStatusOnPage(struct errCatch *errCatch, 
+	struct htmlPage *page, long startTime, struct htmlPage **retPage)
+/* Assuming you have fetched page with the given error catcher,
+ * starting the fetch at the given startTime, then create a
+ * qaStatus that describes how the fetch went.  If *retPage is non-null
+ * then return the page there, otherwise free it. */
+{
+char *errMessage = NULL;
+struct qaStatus *qs;
+AllocVar(qs);
+if (errCatch->gotError || page == NULL)
+    {
+    errMessage = errCatch->message->string;
+    qs->hardError = TRUE;
+    }
+else
+    {
+    if (page->status->status != 200)
+	{
+	dyStringPrintf(errCatch->message, "HTTP status code %d\n", 
+		page->status->status);
+	errMessage = errCatch->message->string;
+	qs->hardError = TRUE;
+	htmlPageFree(&page);
+	}
+    else
+        {
+	errMessage = qaScanForErrorMessage(page->fullText);
+	}
+    }
+qs->errMessage = cloneString(errMessage);
+if (qs->errMessage != NULL)
+    subChar(qs->errMessage, '\n', ' ');
+qs->milliTime = clock1000() - startTime;
+if (retPage != NULL)
+    *retPage = page;
+else
+    htmlPageFree(&page);
+return qs;
+}
+
+struct qaStatus *qaPageGet(char *url, struct htmlPage **retPage)
+/* Get info on given url, (and return page if retPage non-null). */
+{
+struct errCatch *errCatch = errCatchNew();
+struct qaStatus *qs;
+struct htmlPage *page = NULL;
+long startTime = clock1000();
+if (errCatchStart(errCatch))
+    {
+    page = htmlPageGet(url);
+    htmlPageValidateOrAbort(page);
+    }
+else
+    {
+    htmlPageFree(&page);
+    }
+errCatchEnd(errCatch);
+qs = qaStatusOnPage(errCatch, page, startTime, retPage);
+errCatchFree(&errCatch);
+return qs;
+}
+
+struct qaStatus *qaPageFromForm(struct htmlPage *origPage, struct htmlForm *form, 
+	char *buttonName, char *buttonVal, struct htmlPage **retPage)
+/* Get update to form based on pressing a button. */
+{
+struct errCatch *errCatch = errCatchNew();
+struct qaStatus *qs;
+struct htmlPage *page = NULL;
+long startTime = clock1000();
+if (errCatchStart(errCatch))
+    {
+    page = htmlPageFromForm(origPage, form, buttonName, buttonVal);
+    htmlPageValidateOrAbort(page);
+    }
+else
+    {
+    htmlPageFree(&page);
+    }
+errCatchEnd(errCatch);
+qs = qaStatusOnPage(errCatch, page, startTime, retPage);
+errCatchFree(&errCatch);
+return qs;
+}
+
+void qaStatusSoftError(struct qaStatus *qs, char *format, ...)
+/* Add error message for something less than a crash. */
+{
+struct dyString *dy = dyStringNew(0);
+va_list args, args2;
+va_start(args, format);
+/* args can't be reused, so vaWarn needs its own va_list: */
+va_start(args2, format);
+vaWarn(format, args2);
+if (qs->errMessage)
+    {
+    dyStringAppend(dy, qs->errMessage);
+    dyStringAppendC(dy, '\n');
+    }
+dyStringVaPrintf(dy, format, args);
+va_end(args);
+va_end(args2);
+freez(&qs->errMessage);
+qs->errMessage = cloneString(dy->string);
+dyStringFree(&dy);
+}
+
+void qaStatisticsAdd(struct qaStatistics *stats, struct qaStatus *qs)
+/* Add test results to totals */
+{
+stats->testCount += 1;
+stats->milliTotal += qs->milliTime;
+if (qs->errMessage)
+    {
+    if (qs->hardError)
+        stats->hardCount += 1;
+    else
+        stats->softCount += 1;
+    }
+}
+
+void qaStatisticsReport(struct qaStatistics *stats, char *label, FILE *f)
+/* Write a line of stats to file. */
+{
+fprintf(f, "%20s:  %3d tests, %2d soft errors, %2d hard errors, %5.2f seconds\n",
+	label, stats->testCount, stats->softCount, stats->hardCount, 
+	0.001 * stats->milliTotal);
+}
+
+
diff --git a/lib/quickHeap.c b/lib/quickHeap.c
new file mode 100644
index 0000000..eec8fe2
--- /dev/null
+++ b/lib/quickHeap.c
@@ -0,0 +1,196 @@
+/* quickHeap - Heap implemented as an array for speed.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial.
+ *
+ *    The array can be resized as it grows.
+ *  By preserving the relationship that the children of n are at 2n+1 and 2n+2,
+ *  and therefore the parent of n is at (n-1)/2, we can save alot of pointer
+ *  manipulation and get some speed.  
+ *    This routine could for instance be used at the heart of a multi-way mergesort
+ *  or other situation such as a priority queue.
+ *
+ * Maintaining the heap is quick and easy since
+ * we just use an array with the following relationships:
+ * children(n) == 2n+1,2n+2. parent(n) == (n-1)/2.
+ * The highest score is always at the top of the heap in 
+ * position 0. When the top element is consumed and 
+ * and the next element for the previously top elem is 
+ * set in, we simply balance the heap to maintain the heap property
+ * by swapping with the largest child until both children 
+ * are smaller, or we hit the end of the array (==heapCount).
+ * Also note that scores are not necessarily unique, heap members
+ * may have equal score.  So A parent need not only be greater
+ * than its children, it may also be equal to them.
+ */
+
+#include "common.h"
+#include "quickHeap.h"
+
+
+
+struct quickHeap *newQuickHeap(int initSize, 
+   int (*compare )(const void *elem1,  const void *elem2))
+/* Create a new array quick heap of initial size specified,
+ * The compare function must return > 0 if elem1 > elem2, etc.*/
+{
+struct quickHeap *h;
+if (initSize < 1)
+    errAbort("invalid initial size for newQuickHeap: %d",initSize);
+AllocVar(h);
+h->heapCount=0;
+h->heapMax = initSize;
+h->heap = AllocN(void *,h->heapMax);
+h->compareFunc = compare;
+return h;
+}
+
+
+void freeQuickHeap(struct quickHeap **pH)
+/* Heap needs more space, double the size of the array preserving elements */
+{
+struct quickHeap *h = *pH;
+freez(&h->heap);
+freez(pH);
+}
+
+static void expandQuickHeap(struct quickHeap *h)
+/* Heap needs more space, double the size of the array preserving elements */
+{
+int newSize = h->heapMax * 2;
+ExpandArray(h->heap, h->heapMax, newSize);
+h->heapMax = newSize;
+}
+
+void addToQuickHeap(struct quickHeap *h, void *elem)
+/* add to heap at end (expands array if needed), rebalance */
+{
+int n, p;   /* node, parent */
+if (h->heapCount >= h->heapMax)
+    expandQuickHeap(h);
+/* preserve heap property as it grows */
+n = h->heapCount;
+h->heap[h->heapCount++] = elem;
+p = (n-1)/2;
+while (n > 0 && h->compareFunc(h->heap[p], h->heap[n]) < 0)
+    {
+    void *temp = h->heap[p];
+    h->heap[p] = h->heap[n];
+    h->heap[n] = temp;
+    n = p;
+    p = (n-1)/2;
+    }
+}
+
+
+static void quickHeapBalanceWithChildren(struct quickHeap *h, int n)
+/* only the value of the n-th element has changed, now rebalance */
+{
+int c1, c2, hc;   /* child1, child2, heapCount */
+if (n < 0 || n >= h->heapCount)
+    errAbort("attempt to quickHeapBalanceWithChildren with invalid value "
+		"for n: %d, heapCount=%d", n, h->heapCount);
+/* balance heap - swap node with biggest child until both children are 
+ * either less or equal or hit end of heap (no more children) */
+hc = h->heapCount;
+c1 = 2*n+1;
+c2 = 2*n+2;
+while (TRUE)
+    {
+    void *temp = NULL;
+    int bestc = n;
+    if (c1 < hc && h->compareFunc(h->heap[c1], h->heap[bestc]) > 0)
+	bestc = c1;
+    if (c2 < hc && h->compareFunc(h->heap[c2], h->heap[bestc]) > 0)
+	bestc = c2;
+    if (bestc == n)
+	break;
+    temp = h->heap[bestc];
+    h->heap[bestc] = h->heap[n];
+    h->heap[n] = temp;
+    n = bestc;
+    c1 = 2*n+1;
+    c2 = 2*n+2;
+    }
+}
+
+
+void quickHeapTopChanged(struct quickHeap *h)
+/* only the value of the top element has changed, now rebalance */
+{
+/* balance heap - swap node with biggest child until both children are 
+ * either less or equal or hit end of heap (no more children) */
+quickHeapBalanceWithChildren(h,0);
+}
+
+boolean quickHeapEmpty(struct quickHeap *h)
+/* return TRUE if quick heap is empty, otherwise FALSE */
+{
+return h->heapCount < 1;
+}
+
+static void removeFromQuickHeapN(struct quickHeap *h, int n)
+/* Remove element n from the heap by swapping 
+ * it with the last element in the heap and rebalancing.
+ * If heap is empty it will errAbort, but that should not happen. */
+{
+if (n < 0 || n >= h->heapCount)
+    errAbort("attempt to removeFromQuickHeapN with invalid value "
+		"for n: %d, heapCount=%d", n, h->heapCount);
+h->heap[n] = h->heap[--h->heapCount]; /* wipes out n by moving tail to it */
+h->heap[h->heapCount] = NULL; /* not needed but clean */
+/* balance heap - swap node with biggest child until both children are 
+ * either less or equal or hit end of heap (no more children) */
+if (n < h->heapCount)  /* i.e. true for all but when n was the tail */
+    quickHeapBalanceWithChildren(h,n);
+}
+
+
+static int findElemInQuickHeap(struct quickHeap *h, void *elem)
+/* Do a linear search in heap array for elem,
+ * return position n or -1 if not found */
+{
+int n = -1;
+while (++n < h->heapCount)
+    {
+    if (h->heap[n] == elem)
+	return n;
+    }
+return -1;    
+}
+
+
+boolean removeFromQuickHeapByElem(struct quickHeap *h, void *elem)
+/* Do a linear search in heap array for elem,
+ * then remove it by position n. Return TRUE
+ * if found and removed, otherwise return FALSE. */
+{
+int n = findElemInQuickHeap(h, elem);
+if (n < 0) 
+    return FALSE;
+removeFromQuickHeapN(h,n);
+return TRUE;
+}
+
+void *peekQuickHeapTop(struct quickHeap *h)
+/* return the top element or NULL if empty */
+{
+if (h->heapCount < 1) 
+    return NULL;
+return h->heap[0];    
+}
+
+void *removeQuickHeapTop(struct quickHeap *h)
+/* Return elem (pointer) in heap array[0]
+ * which will be NULL if heap is empty.
+ * Then that top element if found is removed. */
+{
+void *result = h->heap[0]; 
+/* this is ok, but depends on removeFromQuickHeapN NULLing as it empties */   
+if (h->heapCount > 0) 
+    {
+    removeFromQuickHeapN(h,0);
+    }
+return result;
+}
+
diff --git a/lib/quotedP.c b/lib/quotedP.c
new file mode 100644
index 0000000..1342a4d
--- /dev/null
+++ b/lib/quotedP.c
@@ -0,0 +1,114 @@
+#include "common.h"
+#include "linefile.h"
+#include "dystring.h"
+#include "quotedP.h"
+
+
+char *quotedPrintableEncode(char *input)
+/* Use Quoted-Printable standard to encode a string. */
+{
+struct dyString *dy = dyStringNew(0);
+size_t i=0,l=strlen(input);
+int width = 0;
+for (i=0; i < l; ++i)
+    {
+    char c = input[i];
+    switch (c)
+	{
+	case '=':
+	case '\t':
+	case '\r':
+	case '\n':
+	case ' ':
+	    dyStringAppendC(dy, '=');
+	    dyStringPrintf(dy, "%2x", c);
+	    width += 3;
+	    break;
+	default:
+	    dyStringAppendC(dy, c);
+	    ++width;
+	}
+    if (width > 72)
+	{
+	dyStringAppendC(dy, '=');
+	dyStringAppendC(dy, '\n');
+	width = 0;
+	}
+	
+    }
+/* add terminator to prevent extra newline */
+if (lastChar(dy->string) != '=')  
+    dyStringAppendC(dy, '=');
+    
+return dyStringCannibalize(&dy);
+}
+
+boolean quotedPCollapse(char *line)
+/* Use Quoted-Printable standard to decode a string.
+ * Return true if the line does not end in '='
+ * which indicate continuation. */
+{
+size_t i=0,j=0,l=strlen(line);
+boolean result = lastChar(line) != '=';
+char c1 = ' ', c2 = ' ';
+while(i < l)
+    {
+    if (line[i] == '=')
+	{
+	if (i > (l-3)) 
+	    break;     /* not enough room left for whole char */
+	++i;	    
+	c1 = line[i++];
+	c2 = line[i++];
+	c1 = toupper(c1);
+	c2 = toupper(c2);
+	if (isdigit(c1))
+	    c1 -= 48;
+	else
+	    c1 -= 55;
+	if (isdigit(c2))
+	    c2 -= 48;
+	else
+	    c2 -= 55;
+	line[j++] = (c1 * 16) + c2;
+	}
+    else
+	{
+	line[j++] = line[i++];
+	}
+    }
+line[j] = 0; /* terminate line */
+return result;
+}
+
+char *quotedPrintableDecode(char *input)
+/* Use Quoted-Printable standard to decode a string.  Return decoded
+ * string which will be freeMem'd.  */
+{
+size_t inplen = strlen(input);
+char *result = (char *)needMem(inplen+1);
+size_t j=0;
+char *line = NULL;
+int size = 0;
+int i = 0;
+boolean newLine = FALSE;
+
+struct lineFile *lf = lineFileOnString("", TRUE, cloneString(input));
+
+while (lineFileNext(lf, &line, &size))
+    {
+    newLine = quotedPCollapse(line);
+    size = strlen(line); 
+    for (i = 0; i < size; )
+	result[j++] = line[i++];
+    if (newLine)
+	result[j++] = '\n';
+    }
+
+lineFileClose(&lf);  /* frees cloned string */
+
+result[j] = 0;  /* terminate text string */
+     
+return result;
+}
+
diff --git a/lib/ra.c b/lib/ra.c
new file mode 100644
index 0000000..efabdf3
--- /dev/null
+++ b/lib/ra.c
@@ -0,0 +1,400 @@
+/* Stuff to parse .ra files. Ra files are simple text databases.
+ * The database is broken into records by blank lines.
+ * Each field takes a line.  The name of the field is the first
+ * word in the line.  The value of the field is the rest of the line.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "localmem.h"
+#include "dystring.h"
+#include "ra.h"
+
+
+boolean raSkipLeadingEmptyLines(struct lineFile *lf, struct dyString *dy)
+/* Skip leading empty lines and comments.  Returns FALSE at end of file.
+ * Together with raNextTagVal you can construct your own raNextRecord....
+ * If dy parameter is non-null, then the text parsed gets placed into dy. */
+{
+char *line;
+/* Skip leading empty lines and comments. */
+if (dy)
+    dyStringClear(dy);
+for (;;)
+    {
+    if (!lineFileNext(lf, &line, NULL))
+       return FALSE;
+    char *tag = skipLeadingSpaces(line);
+    if (tag[0] == 0 || tag[0] == '#')
+       {
+       if (dy)
+	   {
+	   dyStringAppend(dy, line);
+	   dyStringAppendC(dy, '\n');
+	   }
+	}
+    else
+       break;
+    }
+lineFileReuse(lf);
+return TRUE;
+}
+
+boolean raNextTagVal(struct lineFile *lf, char **retTag, char **retVal, struct dyString *dyRecord)
+// Read next line.  Return FALSE at end of file or blank line.  Otherwise fill in
+// *retTag and *retVal and return TRUE.  If dy parameter is non-null, then the text parsed
+// gets appended to dy. Continuation lines in RA file will be joined to produce tag and val,
+// but dy will be filled with the unedited multiple lines containing the continuation chars.
+// NOTE: retTag & retVal, if returned, point to static mem which will be overwritten on next call!
+{
+*retTag = NULL;
+*retVal = NULL;
+
+char *line, *raw = NULL;
+int lineLen,rawLen;
+
+// Don't bother with raw if it isn't used.
+char **pRaw    = NULL;
+int   *pRawLen = NULL;
+if (dyRecord != NULL)
+    {
+    pRaw    = &raw;
+    pRawLen = &rawLen;
+    }
+
+while (lineFileNextFull(lf, &line, &lineLen, pRaw, pRawLen)) // Joins continuation lines
+    {
+    char *clippedText = skipLeadingSpaces(line);
+    if (*clippedText == 0)
+        {
+        if (dyRecord)
+            lineFileReuse(lf);   // Just so don't loose leading space in dy.
+        return FALSE;
+        }
+
+    // Append whatever line was read from file.
+    if (dyRecord)
+        {
+        if (raw != NULL)
+            dyStringAppendN(dyRecord, raw, rawLen);
+        else
+            dyStringAppendN(dyRecord, line, lineLen);
+        dyStringAppendC(dyRecord,'\n');
+        }
+
+    // Skip comments
+    if (*clippedText == '#')
+        {
+        if (startsWith("#EOF", clippedText))
+            return FALSE;
+        else
+            continue;
+        }
+    *retTag = nextWord(&line);
+    *retVal = trimSpaces(line);
+    return TRUE;
+    }
+return FALSE;
+}
+
+struct hash *raNextStanza(struct lineFile *lf)
+// Return a hash containing next record.
+// Will ignore '#' comments and joins continued lines (ending in '\').
+// Returns NULL at end of file.  freeHash this when done.
+// Note this will free the hash keys and values as well,
+// so you'll have to cloneMem them if you want them for later.
+{
+struct hash *hash = NULL;
+char *key, *val;
+
+if (!raSkipLeadingEmptyLines(lf, NULL))
+    return NULL;
+
+while (raNextTagVal(lf, &key, &val, NULL))
+    {
+    if (hash == NULL)
+        hash = newHash(7);
+    hashAdd(hash, key, lmCloneString(hash->lm, val));
+    }
+return hash;
+}
+
+struct slPair *raNextStanzAsPairs(struct lineFile *lf)
+// Return ra stanza as an slPair list instead of a hash.  Handy to preserve the
+// order.  Will ignore '#' comments and joins continued lines (ending in '\').
+{
+struct slPair *list = NULL;
+char *key, *val;
+if (!raSkipLeadingEmptyLines(lf, NULL))
+    return NULL;
+
+while (raNextTagVal(lf, &key, &val, NULL))
+    {
+    slPairAdd(&list, key, cloneString(val)); // key gets cloned by slPairAdd
+    }
+
+slReverse(&list);
+return list;
+}
+
+struct slPair *raNextStanzaLinesAndUntouched(struct lineFile *lf)
+// Return list of lines starting from current position, up through last line of next stanza.
+// May return a few blank/comment lines at end with no real stanza.
+// Will join continuation lines, allocating memory as needed.
+// returns pairs with name=joined line and if joined,
+// val will contain raw lines '\'s and linefeeds, else val will be NULL.
+{
+struct slPair *pairs = NULL;
+boolean stanzaStarted = FALSE;
+char *line, *raw;
+int lineLen,rawLen;
+while (lineFileNextFull(lf, &line, &lineLen, &raw, &rawLen)) // Joins continuation lines
+    {
+    char *clippedText = skipLeadingSpaces(line);
+
+    if (stanzaStarted && clippedText[0] == 0)
+        {
+        lineFileReuse(lf);
+        break;
+        }
+    if (!stanzaStarted && clippedText[0] != 0 && clippedText[0] != '#')
+        stanzaStarted = TRUE; // Comments don't start stanzas and may be followed by blanks
+
+    slPairAdd(&pairs, line,(raw != NULL ? cloneString(raw) : NULL));
+    }
+slReverse(&pairs);
+return pairs;
+}
+
+struct hash *raFromString(char *string)
+/* Return hash of key/value pairs from string.
+ * As above freeHash this when done. */
+{
+char *dupe = cloneString(string);
+char *s = dupe, *lineEnd;
+struct hash *hash = newHash(7);
+char *key, *val;
+
+for (;;)
+    {
+    s = skipLeadingSpaces(s);
+    if (s == NULL || s[0] == 0)
+        break;
+    lineEnd = strchr(s, '\n');
+    if (lineEnd != NULL)
+        *lineEnd++ = 0;
+    key = nextWord(&s);
+    val = skipLeadingSpaces(s);
+    s = lineEnd;
+    val = lmCloneString(hash->lm, val);
+    hashAdd(hash, key, val);
+    }
+freeMem(dupe);
+return hash;
+}
+
+char *raFoldInOneRetName(struct lineFile *lf, struct hash *hashOfHash)
+/* Fold in one record from ra file into hashOfHash.
+ * This will add ra's and ra fields to whatever already
+ * exists in the hashOfHash,  overriding fields of the
+ * same name if they exist already. */
+{
+char *word, *line, *name;
+struct hash *ra;
+struct hashEl *hel;
+
+/* Get first nonempty non-comment line and make sure
+ * it contains name. */
+if (!lineFileNextFullReal(lf, &line))
+    return NULL;
+word = nextWord(&line);
+if (!sameString(word, "name"))
+    errAbort("Expecting 'name' line %d of %s, got %s",
+             lf->lineIx, lf->fileName, word);
+name = nextWord(&line);
+if (name == NULL)
+    errAbort("Short name field line %d of %s", lf->lineIx, lf->fileName);
+
+/* Find ra hash associated with name, making up a new
+ * one if need be. */
+if ((ra = hashFindVal(hashOfHash, name)) == NULL)
+    {
+    ra = newHash(7);
+    hashAdd(hashOfHash, name, ra);
+    hashAdd(ra, "name", lmCloneString(ra->lm, name));
+    }
+
+/* Fill in fields of ra hash with data up to next
+ * blank line or end of file. */
+for (;;)
+    {
+    if (!lineFileNextFull(lf, &line, NULL,NULL,NULL)) // Not using FullReal to detect end of stanza
+        break;
+    line = skipLeadingSpaces(line);
+    if (line[0] == 0)
+        break;                                        // End of stanza detected
+    if (line[0] == '#')
+        continue;
+    word = nextWord(&line);
+    line = skipLeadingSpaces(line);
+    if (line == NULL)
+        line = "";
+    hel = hashLookup(ra, word);
+    if (hel == NULL)
+        hel = hashAdd(ra, word, lmCloneString(ra->lm, line));
+    else
+        hel->val = lmCloneString(ra->lm, line);
+    }
+return hashFindVal(ra, "name");
+}
+
+boolean raFoldInOne(struct lineFile *lf, struct hash *hashOfHash)
+{
+return raFoldInOneRetName(lf, hashOfHash) != NULL;
+}
+
+void raFoldIn(char *fileName, struct hash *hashOfHash)
+/* Read ra's in file name and fold them into hashOfHash.
+ * This will add ra's and ra fields to whatever already
+ * exists in the hashOfHash,  overriding fields of the
+ * same name if they exist already. */
+{
+struct lineFile *lf = lineFileMayOpen(fileName, TRUE);
+if (lf != NULL)
+    {
+    struct hash *uniqHash = hashNew(0);
+    char *name;
+    while ((name = raFoldInOneRetName(lf, hashOfHash)) != NULL)
+	{
+	if (hashLookup(uniqHash, name))
+            errAbort("%s duplicated in record ending line %d of %s", name,
+                     lf->lineIx, lf->fileName);
+	hashAdd(uniqHash, name, NULL);
+	}
+    lineFileClose(&lf);
+    hashFree(&uniqHash);
+    }
+}
+
+struct hash *raReadSingle(char *fileName)
+/* Read in first ra record in file and return as hash. */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+struct hash *hash = raNextRecord(lf);
+lineFileClose(&lf);
+return hash;
+}
+
+struct hash *raReadAll(char *fileName, char *keyField)
+/* Return hash that contains all ra records in file keyed
+ * by given field, which must exist.  The values of the
+ * hash are themselves hashes. */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+struct hash *bigHash = hashNew(0);
+struct hash *hash;
+while ((hash = raNextRecord(lf)) != NULL)
+    {
+    char *key = hashFindVal(hash, keyField);
+    if (key == NULL)
+        errAbort("Couldn't find key field %s line %d of %s",
+		keyField, lf->lineIx, lf->fileName);
+    hashAdd(bigHash, key, hash);
+    }
+lineFileClose(&lf);
+return bigHash;
+}
+
+struct hash *raReadWithFilter(char *fileName, char *keyField,char *filterKey,char *filterValue)
+/* Return hash that contains all filtered ra records in file keyed by given field, which must exist.
+ * The values of the hash are themselves hashes.  The filter is a key/value pair that must exist.
+ * Example raReadWithFilter(file,"term","type","antibody"): returns hash of hashes of every term with type=antibody */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+struct hash *bigHash = hashNew(14);
+struct hash *hash;
+while ((hash = raNextRecord(lf)) != NULL)
+    {
+    char *key = hashFindVal(hash, keyField);
+    if (key == NULL)
+        errAbort("Couldn't find key field %s line %d of %s",
+                 keyField, lf->lineIx, lf->fileName);
+    if (filterKey != NULL)
+        {
+        char *filter = hashFindVal(hash, filterKey);
+        if (filter == NULL)
+            {
+            hashFree(&hash);
+            continue;
+            }
+        if (filterValue != NULL && differentString(filterValue,filter))
+            {
+            hashFree(&hash);
+            continue;
+            }
+        }
+    hashAdd(bigHash, key, hash);
+    }
+lineFileClose(&lf);
+if (hashNumEntries(bigHash) == 0)
+    hashFree(&bigHash);
+return bigHash;
+}
+
+struct hash *raReadThreeLevels(char *fileName, char *lowKeyField, char *middleKeyField)
+/* Return 3 level hash that contains all ra records in file keyed by lowKeyField, which must exist.
+ * and broken into sub hashes based upon middleKeyField that must exist.
+ * Example raReadThreeLevels("cv.ra","term","type"):
+ *         returns hash of 'type' hashes of 'term' hashes of every stanza in cv.ra */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+struct hash *topHash = hashNew(0); // Not expecting that many types
+struct hash *bottomHash;
+while ((bottomHash = raNextRecord(lf)) != NULL)
+    {
+    char *lowKey = hashFindVal(bottomHash, lowKeyField);
+    if (lowKey == NULL)
+        errAbort("Couldn't find key field %s line %d of %s",
+                 lowKeyField, lf->lineIx, lf->fileName);
+
+    char *middleKey = hashFindVal(bottomHash, middleKeyField);
+    if (middleKey == NULL)
+        errAbort("Couldn't find middle key field %s line %d of %s",
+                 middleKeyField, lf->lineIx, lf->fileName);
+
+    struct hash *middleHash = hashFindVal(topHash, middleKey);
+    if (middleHash == NULL)
+        {
+        middleHash = hashNew(16); // could be quite a few terms per type.
+        hashAdd(topHash, middleKey, middleHash);
+        }
+    hashAdd(middleHash, lowKey, bottomHash);
+    }
+lineFileClose(&lf);
+if (hashNumEntries(topHash) == 0)
+    hashFree(&topHash);
+return topHash;
+}
+
+struct hash *raTagVals(char *fileName, char *tag)
+/* Return a hash of all values of given tag seen in any stanza of ra file. */
+{
+struct hash *hash = hashNew(0);
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *line;
+while (lineFileNextFullReal(lf, &line))
+    {
+    char *word = nextWord(&line);
+    if (sameString(word, tag))
+        {
+	char *val = trimSpaces(line);
+	if (!hashLookup(hash, val))
+	    hashAdd(hash, val, NULL);
+	}
+    }
+lineFileClose(&lf);
+return hash;
+}
diff --git a/lib/rainbow.c b/lib/rainbow.c
new file mode 100644
index 0000000..3bb540c
--- /dev/null
+++ b/lib/rainbow.c
@@ -0,0 +1,151 @@
+/* rainbow - stuff to generate rainbow colors. */
+
+#include "common.h"
+#include "memgfx.h"
+#include "rainbow.h"
+
+struct rgbColor saturatedRainbowTable[28] = {
+/* This table was built by hand for the default Autodesk Animator palette, and then edited
+ * to reduce the amount of green colors that are indistinguishable. */
+    {255, 0, 0},
+    {255, 64, 0},
+    {255, 128, 0},
+    {255, 164, 0},
+    {255, 210, 0},
+    {255, 255, 0},
+    {210, 255, 0},
+    {164, 255, 0},
+    {128, 255, 0},
+    {0, 255, 0},
+    {0, 255, 128},
+    {0, 255, 164},
+    {0, 255, 210},
+    {0, 255, 255},
+    {0, 210, 255},
+    {0, 164, 255},
+    {0, 128, 255},
+    {0, 64, 255},
+    {0, 0, 255},
+    {64, 0, 255},
+    {128, 0, 255},
+    {164, 0, 255},
+    {210, 0, 255},
+    {255, 0, 255},
+    {255, 0, 210},
+    {255, 0, 164},
+    {255, 0, 128},
+    {255, 0, 64},
+    };
+
+static struct rgbColor lightRainbowTable[28] = {
+/* This is a mixture of 1/2 white and 1/2 saturated rainbow.  It's good for rainbow
+ * fringe graphs with a moderate amount of colors (up to about 10) */
+   {255,128,128},
+   {255,160,128},
+   {255,192,128},
+   {255,210,128},
+   {255,233,128},
+   {255,255,128},
+   {233,255,128},
+   {210,255,128},
+   {192,255,128},
+   {128,255,128},
+   {128,255,192},
+   {128,255,210},
+   {128,255,233},
+   {128,255,255},
+   {128,233,255},
+   {128,210,255},
+   {128,192,255},
+   {128,160,255},
+   {128,128,255},
+   {160,128,255},
+   {192,128,255},
+   {210,128,255},
+   {233,128,255},
+   {255,128,255},
+   {255,128,233},
+   {255,128,210},
+   {255,128,192},
+   {255,128,160},
+};
+
+static struct rgbColor veryLightRainbowTable[30] = {
+/* This is a mixture of 2/3 white and 1/3 saturated rainbow.  It's good for rainbow
+ * fringe graphs with a lot of colors (more than 10) */
+   {255,174,174},
+   {255,191,174},
+   {255,207,174},
+   {255,223,174},
+   {255,239,174},
+   {255,255,174},
+   {239,255,174},
+   {223,255,174},
+   {207,255,174},
+   {191,255,174},
+   {174,255,174},
+   {174,255,191},
+   {174,255,207},
+   {174,255,223},
+   {174,255,239},
+   {174,255,255},
+   {174,239,255},
+   {174,223,255},
+   {174,207,255},
+   {174,191,255},
+   {174,174,255},
+   {191,174,255},
+   {207,174,255},
+   {223,174,255},
+   {239,174,255},
+   {255,174,255},
+   {255,174,239},
+   {255,174,223},
+   {255,174,207},
+   {255,174,191},
+};
+
+static struct rgbColor interpolatedHue(struct rgbColor *table, int tableSize, double pos)
+/* Given pos, a number between 0 and 1, return interpolated color, doing interpolation
+ * between first and last color for numbers close to 1. */
+{
+double wrappedPos = pos - floor(pos);	/* Make it so numbers higher than 1 keep circling rainbow */
+double scaledPos = tableSize * wrappedPos;
+double startSlot = floor(scaledPos);	
+double endFactor = scaledPos - startSlot;
+double startFactor = 1.0 - endFactor;
+int startIx = startSlot;
+int endIx = startIx + 1;
+if (endIx == tableSize)
+    endIx = 0;
+
+struct rgbColor *start = table+startIx;
+struct rgbColor *end = table+endIx;
+struct rgbColor col;
+col.r = start->r * startFactor + end->r * endFactor;
+col.g = start->g * startFactor + end->g * endFactor;
+col.b = start->b * startFactor + end->b * endFactor;
+return col;
+}
+
+struct rgbColor veryLightRainbowAtPos(double pos)
+/* Given pos, a number between 0 and 1, return a light rainbow rgbColor
+ * where 0 maps to red,  0.1 is orange, and 0.9 is violet and 1.0 is back to red */
+{
+return interpolatedHue(veryLightRainbowTable, ArraySize(veryLightRainbowTable), pos);
+}
+
+struct rgbColor lightRainbowAtPos(double pos)
+/* Given pos, a number between 0 and 1, return a lightish rainbow rgbColor
+ * where 0 maps to red,  0.1 is orange, and 0.9 is violet and 1.0 is back to red */
+{
+return interpolatedHue(lightRainbowTable, ArraySize(lightRainbowTable), pos);
+}
+
+struct rgbColor saturatedRainbowAtPos(double pos)
+/* Given pos, a number between 0 and 1, return a saturated rainbow rgbColor
+ * where 0 maps to red,  0.1 is orange, and 0.9 is violet and 1.0 is back to red */
+{
+return interpolatedHue(saturatedRainbowTable, ArraySize(saturatedRainbowTable), pos);
+}
+
diff --git a/lib/rangeTree.c b/lib/rangeTree.c
new file mode 100644
index 0000000..de519bb
--- /dev/null
+++ b/lib/rangeTree.c
@@ -0,0 +1,333 @@
+/* rangeTree - This module is a way of keeping track of
+ * non-overlapping ranges (half-open intervals). It is
+ * based on the self-balancing rbTree code.  Use it in
+ * place of a bitmap when the total number of ranges
+ * is significantly smaller than the number of bits would
+ * be. 
+ * Beware the several static/global variables which can be
+ * changed by various function calls. */
+
+#include "common.h"
+#include "limits.h"
+#include "localmem.h"
+#include "obscure.h"
+#include "rbTree.h"
+#include "rangeTree.h"
+
+
+int rangeCmp(void *va, void *vb)
+/* Return -1 if a before b,  0 if a and b overlap,
+ * and 1 if a after b. */
+{
+struct range *a = va;
+struct range *b = vb;
+if (a->end <= b->start)
+    return -1;
+else if (b->end <= a->start)
+    return 1;
+else
+    return 0;
+}
+
+
+static void *sumInt(void *a, void *b)
+/* Local function used by rangeTreeAddValCount, which sums two ints a and b, 
+ * referenced by void pointers, returning the result in a */
+{
+int *i = a, *j = b;
+*i += *j;
+return a;
+}
+
+
+struct range *rangeTreeAddVal(struct rbTree *tree, int start, int end, void *val, void *(*mergeVals)(void *existingVal, void *newVal) )
+/* Add range to tree, merging with existing ranges if need be. 
+ * If this is a new range, set the value to this val.
+ * If there are existing items for this range, and if mergeVals function is not null, 
+ * apply mergeVals to the existing values and this new val, storing the result as the val
+ * for this range (see rangeTreeAddValCount() and rangeTreeAddValList() below for examples). */
+{
+struct range *r, *existing;
+r = lmAlloc(tree->lm, sizeof(*r)); /* alloc new zeroed range */
+r->start = start;
+r->end = end;
+r->val = val;
+while ((existing = rbTreeRemove(tree, r)) != NULL)
+    {
+    r->start = min(r->start, existing->start);
+    r->end = max(r->end, existing->end);
+    if (mergeVals)
+	r->val = mergeVals(existing->val, r->val);
+    }
+rbTreeAdd(tree, r);
+return r;
+}
+
+
+struct range *rangeTreeAdd(struct rbTree *tree, int start, int end)
+/* Add range to tree, merging with existing ranges if need be. */
+{
+    return rangeTreeAddVal(tree, start, end, NULL, NULL);
+}
+
+
+struct range *rangeTreeAddValCount(struct rbTree *tree, int start, int end)
+/* Add range to tree, merging with existing ranges if need be. 
+ * Set range val to count of elements in the range. Counts are pointers to 
+ * ints allocated in tree localmem */
+{
+    int *a = lmAlloc(tree->lm, sizeof(*a)); /* keep the count in localmem */
+    *a = 1;
+    return rangeTreeAddVal(tree, start, end, (void *)a, sumInt);
+}
+
+
+struct range *rangeTreeAddValList(struct rbTree *tree, int start, int end, void *val)
+/* Add range to tree, merging with existing ranges if need be. 
+ * Add val to the list of values (if any) in each range.
+ * val must be valid argument to slCat (ie, be a struct with a 'next' pointer as its first member) */
+{
+    return rangeTreeAddVal(tree, start, end, val, slCat);
+}
+
+void rangeTreeAddToCoverageDepth(struct rbTree *tree, int start, int end)
+/* Add area from start to end to a tree that is being built up to store the
+ * depth of coverage.  Recover coverage back out by looking at ptToInt(range->val)
+ * on tree elements. */
+{
+struct range q;
+q.start = start;
+q.end = end;
+
+struct range *r, *existing = rbTreeFind(tree, &q);
+if (existing == NULL)
+    {
+    lmAllocVar(tree->lm, r);
+    r->start = start;
+    r->end = end;
+    r->val = intToPt(1);
+    rbTreeAdd(tree, r);
+    }
+else
+    {
+    if (existing->start <= start && existing->end >= end)
+    /* The existing one completely encompasses us */
+        {
+	/* Make a new section for the bit before start. */
+	if (existing->start < start)
+	    {
+	    lmAllocVar(tree->lm, r);
+	    r->start = existing->start;
+	    r->end = start;
+	    r->val = existing->val;
+	    existing->start = start;
+	    rbTreeAdd(tree, r);
+	    }
+	/* Make a new section for the bit after end. */
+	if (existing->end > end)
+	    {
+	    lmAllocVar(tree->lm, r);
+	    r->start = end;
+	    r->end = existing->end;
+	    r->val = existing->val;
+	    existing->end = end;
+	    rbTreeAdd(tree, r);
+	    }
+	/* Increment existing section in overlapping area. */
+        existing->val = (char *)(existing->val) + 1;
+	}
+    else
+    /* In general case fetch list of regions that overlap us. 
+       Remaining cases to handle are: 
+	     r >> e     rrrrrrrrrrrrrrrrrrrr
+			     eeeeeeeeee
+
+	     e < r           rrrrrrrrrrrrrrr
+			eeeeeeeeeeee
+
+	     r < e      rrrrrrrrrrrr
+			     eeeeeeeeeeeee
+     */
+        {
+	struct range *existingList = rangeTreeAllOverlapping(tree, start, end);
+
+#ifdef DEBUG
+	/* Make sure that list is really sorted for debugging... */
+	int lastStart = existingList->start;
+	for (r = existingList; r != NULL; r = r->next)
+	    {
+	    int start = r->start;
+	    if (start < lastStart)
+	        internalErr();
+	    }
+#endif /* DEBUG */
+
+	int s = start, e = end;
+	for (existing = existingList; existing != NULL; existing = existing->next)
+	    {
+	    /* Deal with start of new range that comes before existing */
+	    if (s < existing->start)
+	        {
+		lmAllocVar(tree->lm, r);
+		r->start = s;
+		r->end = existing->start;
+		r->val = intToPt(1);
+		s = existing->start;
+		rbTreeAdd(tree, r);
+		}
+	    else if (s > existing->start)
+	        {
+		lmAllocVar(tree->lm, r);
+		r->start = existing->start;
+		r->end = s;
+		r->val = existing->val;
+		existing->start = s;
+		rbTreeAdd(tree, r);
+		}
+	    existing->val = (char *)(existing->val) + 1;
+	    s = existing->end;
+	    }
+	if (s < e)
+	/* Deal with end of new range that doesn't overlap with anything. */
+	    {
+	    lmAllocVar(tree->lm, r);
+	    r->start = s;
+	    r->end = e;
+	    r->val = intToPt(1);
+	    rbTreeAdd(tree, r);
+	    }
+	}
+    }
+
+}
+
+boolean rangeTreeOverlaps(struct rbTree *tree, int start, int end)
+/* Return TRUE if start-end overlaps anything in tree */
+{
+struct range tempR;
+tempR.start = start;
+tempR.end = end;
+tempR.val = NULL;
+return rbTreeFind(tree, &tempR) != NULL;
+}
+
+static struct range *rangeList;
+
+static void rangeListAdd(void *v)
+/* Callback to add item to range list. */
+{
+struct range *r = v;
+slAddHead(&rangeList, r);
+}
+
+struct range *rangeTreeList(struct rbTree *tree)
+/* Return list of all ranges in tree in order.  Not thread safe. 
+ * No need to free this when done, memory is local to tree. */
+{
+rangeList = NULL;
+rbTreeTraverse(tree, rangeListAdd);
+slReverse(&rangeList);
+return rangeList;
+}
+
+struct range *rangeTreeFindEnclosing(struct rbTree *tree, int start, int end)
+/* Find item in range tree that encloses range between start and end 
+ * if there is any such item. */
+{
+struct range tempR, *r;
+tempR.start = start;
+tempR.end = end;
+r = rbTreeFind(tree, &tempR);
+if (r != NULL && r->start <= start && r->end >= end)
+    {
+    r->next = NULL; /* this can be set by previous calls to the List functions */
+    return r;
+    }
+return NULL;
+}
+
+struct range *rangeTreeAllOverlapping(struct rbTree *tree, int start, int end)
+/* Return list of all items in range tree that overlap interval start-end.
+ * Do not free this list, it is owned by tree.  However it is only good until
+ * next call to rangeTreeFindInRange or rangeTreeList. Not thread safe. */
+{
+struct range tempR;
+tempR.start = start;
+tempR.end = end;
+rangeList = NULL;
+rbTreeTraverseRange(tree, &tempR, &tempR, rangeListAdd);
+slReverse(&rangeList);
+return rangeList;
+}
+
+
+struct range *rangeTreeMaxOverlapping(struct rbTree *tree, int start, int end)
+/* Return item that overlaps most with start-end. Not thread safe.  Trashes list used
+ * by rangeTreeAllOverlapping. */
+{
+struct range *range, *best = NULL;
+int bestOverlap = 0; 
+for (range  = rangeTreeAllOverlapping(tree, start, end); range != NULL; range = range->next)
+    {
+    int overlap = rangeIntersection(range->start, range->end, start, end);
+    if (overlap > bestOverlap)
+        {
+	bestOverlap = overlap;
+	best = range;
+	}
+    }
+if (best)
+    best->next = NULL; /* could be set by calls to List functions */
+return best;
+}
+
+/* A couple of variables used to calculate total overlap. */
+static int totalOverlap;
+static int overlapStart, overlapEnd;
+
+static void addOverlap(void *v)
+/* Callback to add item to range list. */
+{
+struct range *r = v;
+totalOverlap += positiveRangeIntersection(r->start, r->end, 
+	overlapStart, overlapEnd);
+}
+
+int rangeTreeOverlapSize(struct rbTree *tree, int start, int end)
+/* Return the total size of intersection between interval
+ * from start to end, and items in range tree. Sadly not
+ * thread-safe. 
+ * On 32 bit machines be careful not to overflow
+ * range of start, end or total size return value. */
+{
+struct range tempR;
+tempR.start = overlapStart = start;
+tempR.end = overlapEnd = end;
+totalOverlap = 0;
+rbTreeTraverseRange(tree, &tempR, &tempR, addOverlap);
+return totalOverlap;
+}
+
+int rangeTreeOverlapTotalSize(struct rbTree *tree)
+/* Return the total size of all ranges in range tree.
+ * Sadly not thread-safe. 
+ * On 32 bit machines be careful not to overflow
+ * range of start, end or total size return value. */
+{
+return rangeTreeOverlapSize(tree, INT_MIN, INT_MAX);
+}
+
+struct rbTree *rangeTreeNew()
+/* Create a new, empty, rangeTree. */
+{
+return rbTreeNew(rangeCmp);
+}
+
+struct rbTree *rangeTreeNewDetailed(struct lm *lm, struct rbTreeNode *stack[128])
+/* Allocate rangeTree on an existing local memory & stack.  This is for cases
+ * where you want a lot of trees, and don't want the overhead for each one. 
+ * Note, to clean these up, just do freez(&rbTree) rather than rbFreeTree(&rbTree). */
+{
+return rbTreeNewDetailed(rangeCmp, lm, stack);
+}
+
diff --git a/lib/rbTree.c b/lib/rbTree.c
new file mode 100644
index 0000000..42952f8
--- /dev/null
+++ b/lib/rbTree.c
@@ -0,0 +1,740 @@
+/* rbTree - rbTreeRed-rbTreeBlack Tree - a type of binary tree which 
+ * automatically keeps relatively balanced during
+ * inserts and deletions.
+ *   original author: Shane Saunders
+ *   adapted into local conventions: Jim Kent
+ */
+
+#include "common.h"
+#include "localmem.h"
+#include "rbTree.h"
+
+
+
+static struct rbTreeNode *restructure(struct rbTree *t, int tos, 
+	struct rbTreeNode *x, struct rbTreeNode *y, struct rbTreeNode *z)
+/* General restructuring function - checks for all
+ * restructuring cases.  Call when insert has messed up tree.
+ * Sadly delete has to do even more work. */
+{
+struct rbTreeNode *parent, *midNode;
+
+if(y == x->left) 
+    {
+    if(z == y->left) 
+        {  /* in-order:  z, y, x */
+	midNode = y;
+	y->left = z;
+	x->left = y->right;
+	y->right = x;
+	}
+    else 
+        {  /* in-order:  y, z, x */
+	midNode = z;
+	y->right = z->left;
+	z->left = y;
+	x->left = z->right;
+	z->right = x;
+	}
+    }
+else 
+    {
+    if(z == y->left) 
+	{  /* in-order:  x, z, y */
+	midNode = z;
+	x->right = z->left;
+	z->left = x;
+	y->left = z->right;
+	z->right = y;
+	}
+    else 
+	{  /* in-order:  x, y, z */
+	midNode = y;
+	x->right = y->left;
+	y->left = x;
+	y->right = z;
+	}
+    }
+if(tos != 0) 
+    {
+    parent = t->stack[tos-1];
+    if(x == parent->left) 
+	parent->left = midNode;
+    else 
+	parent->right = midNode;
+    }
+else 
+    t->root = midNode;
+
+return midNode;
+}
+
+struct rbTree *rbTreeNewDetailed(int (*compare)(void *, void *), struct lm *lm, 
+	struct rbTreeNode *stack[128])
+/* Allocate rbTree on an existing local memory & stack.  This is for cases
+ * where you want a lot of trees, and don't want the overhead for each one. 
+ * Note, to clean these up, just do freez(&rbTree) rather than rbFreeTree(&rbTree). */
+{
+struct rbTree *t;
+AllocVar(t);
+t->root = NULL;
+t->compare = compare;
+t->lm = lm;
+t->stack = stack;	
+t->n = 0;
+return t;
+}
+
+struct rbTree *rbTreeNew(int (*compare)(void *, void *))
+/* rbTreeNew() - Allocates space for a red-black tree and returns a pointer
+ * to it.  The function compare compares they keys of two items, and returns a
+ * negative, zero, or positive integer depending on whether the first item is
+ * less than, equal to, or greater than the second.  */
+{
+/* The stack keeps us from having to keep explicit
+ * parent, grandparent, greatgrandparent variables.
+ * It needs to be big enough for the maximum depth
+ * of tree.  Since the whole point of rb trees is
+ * that they are self-balancing, this is not all
+ * that deep, just 2*log2(N).  Therefore a stack of
+ * 128 is good for up to 2^64 items in stack, which
+ * should keep us for the next couple of decades... */
+struct lm *lm = lmInit(0);
+struct rbTreeNode **stack = lmAlloc(lm, 128 * sizeof(stack[0]));	
+return rbTreeNewDetailed(compare, lm, stack);
+}
+
+
+void rbTreeFree(struct rbTree **pTree)
+/* rbTreeFree() - Frees space used by the red-black tree pointed to by t. */
+{
+struct rbTree *tree = *pTree;
+if (tree != NULL)
+    {
+    lmCleanup(&tree->lm);
+    freez(pTree);
+    }
+}
+
+void rbTreeFreeList(struct rbTree **pList)
+/* Free up a list of rbTrees. */
+{
+struct rbTree *tree, *next;
+for (tree = *pList; tree != NULL; tree = next)
+    {
+    next = tree->next;
+    rbTreeFree(&tree);
+    }
+}
+
+void *rbTreeAdd(struct rbTree *t, void *item)
+/* rbTreeAdd() - Inserts an item into the red-black tree pointed to by t,
+ * according the the value its key.  The key of an item in the red-black
+ * tree must be unique among items in the tree.  If an item with the same key
+ * already exists in the tree, a pointer to that item is returned.  Otherwise,
+ * NULL is returned, indicating insertion was successful.
+ */
+{
+struct rbTreeNode *x, *p, *q, *m, **attachX;
+int (* compare)(void *, void *);
+int cmpResult;
+rbTreeColor col;
+struct rbTreeNode **stack = NULL;
+int tos;
+
+tos = 0;    
+if((p = t->root) != NULL) 
+    {
+    compare = t->compare;
+    stack = t->stack;
+
+    /* Repeatedly explore either the left branch or the right branch
+     * depending on the value of the key, until an empty branch is chosen.
+     */
+    for(;;) 
+        {
+	stack[tos++] = p;
+	cmpResult = compare(item, p->item);
+	if(cmpResult < 0) 
+	    {
+	    p = p->left;
+	    if(!p) 
+	        {
+		p = stack[--tos];
+		attachX = &p->left;
+		break;
+		}
+	    }
+	else if(cmpResult > 0) 
+	    {
+	    p = p->right;
+	    if(!p) 
+	        {
+		p = stack[--tos];
+		attachX = &p->right;
+		break;
+		}
+	    }
+	else 
+	    {
+	    return p->item;
+	    }
+	}
+    col = rbTreeRed;
+    }
+else 
+    {
+    attachX = &t->root;
+    col = rbTreeBlack;
+    }
+
+/* Allocate new node and place it in tree. */
+if ((x = t->freeList) != NULL)
+    t->freeList = x->right;
+else
+    lmAllocVar(t->lm, x);
+x->left = x->right = NULL;
+x->item = item;
+x->color = col;
+*attachX = x;
+t->n++;
+
+/* Restructuring or recolouring will be needed if node x and its parent, p,
+ * are both red.
+ */
+if(tos > 0) 
+    {
+    while(p->color == rbTreeRed) 
+	{  /* Double red problem. */
+
+	/* Obtain a pointer to p's parent, m, and sibling, q. */
+	m = stack[--tos];
+	q = p == m->left ? m->right : m->left;
+	
+	/* Determine whether restructuring or recolouring is needed. */
+	if(!q || q->color == rbTreeBlack) 
+	    {
+	    /* Sibling is black.  ==>  Perform restructuring. */
+	    
+	    /* Restructure according to the left to right order, of nodes
+	     * m, p, and x.
+	     */
+	    m = restructure(t, tos, m, p, x);
+	    m->color = rbTreeBlack;
+	    m->left->color = m->right->color = rbTreeRed;
+
+	    /* Restructuring eliminates the double red problem. */
+	    break;
+	    }
+	/* else just need to flip color */
+	
+	/* Sibling is also red.  ==>  Perform recolouring. */
+	p->color = rbTreeBlack;
+	q->color = rbTreeBlack;
+
+	if(tos == 0) break;  /* The root node always remains black. */
+	    
+	m->color = rbTreeRed;
+
+	/* Continue, checking colouring higher up. */
+	x = m;
+	p = stack[--tos];
+	}
+    }
+
+return NULL;
+}
+
+
+void *rbTreeFind(struct rbTree *t, void *item)
+/* rbTreeFind() - Find an item in the red-black tree with the same key as the
+ * item pointed to by `item'.  Returns a pointer to the item found, or NULL
+ * if no item was found.
+ */
+{
+struct rbTreeNode *p, *nextP;
+int (*compare)(void *, void *) = t->compare;
+int cmpResult;
+    
+/* Repeatedly explore either the left or right branch, depending on the
+ * value of the key, until the correct item is found.  */
+for (p = t->root; p != NULL; p = nextP)
+    {
+    cmpResult = compare(item, p->item);
+    if(cmpResult < 0) 
+	nextP = p->left;
+    else if(cmpResult > 0) 
+	nextP = p->right;
+    else 
+	return p->item;
+    }
+return NULL;
+}
+
+
+void *rbTreeRemove(struct rbTree *t, void *item)
+/* rbTreeRemove() - Delete an item in the red-black tree with the same key as
+ * the item pointed to by `item'.  Returns a pointer to the deleted item,
+ * and NULL if no item was found.
+ */
+{
+struct rbTreeNode *p, *r, *x, *y, *z, *b, *newY;
+struct rbTreeNode *m;
+rbTreeColor removeCol;
+void *returnItem;
+int (* compare)(void *, void *);
+int cmpResult;
+struct rbTreeNode **stack;
+int i, tos;
+
+
+/* Attempt to locate the item to be deleted. */
+if((p = t->root)) 
+    {
+    compare = t->compare;
+    stack = t->stack;
+    tos = 0;
+    
+    for(;;) 
+	{
+	stack[tos++] = p;
+	cmpResult = compare(item, p->item);
+	if(cmpResult < 0) 
+	    p = p->left;
+	else if(cmpResult > 0) 
+	    p = p->right;
+	else 
+	    /* Item found. */
+	    break;
+	if(!p) return NULL;
+	}
+    }
+else 
+    return NULL;
+
+/* p points to the node to be deleted, and is currently on the top of the
+ * stack.
+ */
+if(!p->left) 
+    {
+    tos--;  /* Adjust tos to remove p. */
+    /* Right child replaces p. */
+    if(tos == 0) 
+	{
+	r = t->root = p->right;
+	x = y = NULL;
+	}
+    else 
+	{
+	x = stack[--tos];
+	if(p == x->left) 
+	    {
+	    r = x->left = p->right;
+	    y = x->right;
+	    }
+	else 
+	    {
+	    r = x->right = p->right;
+	    y = x->left;
+	    }
+	}
+    removeCol = p->color;
+    }
+else if(!p->right) 
+    {
+    tos--;  /* Adjust tos to remove p. */
+    /* Left child replaces p. */
+    if(tos == 0) 
+	{
+	r = t->root = p->left;
+	x = y = NULL;
+	}
+    else 
+	{
+	x = stack[--tos];
+	if(p == x->left) 
+	    {
+	    r = x->left = p->left;
+	    y = x->right;
+	    }
+	else 
+	    {
+	    r = x->right = p->left;
+	    y = x->left;
+	    }
+	}
+    removeCol = p->color;
+    }
+else 
+    {
+    /* Save p's stack position. */
+    i = tos-1;
+    
+    /* Minimum child, m, in the right subtree replaces p. */
+    m = p->right;
+    do 
+	{
+	stack[tos++] = m;
+	m = m->left;
+	} while(m);
+    m = stack[--tos];
+
+    /* Update either the left or right child pointers of p's parent. */
+    if(i == 0) 
+	{
+	t->root = m;
+	}
+    else 
+	{
+	x = stack[i-1];  /* p's parent. */
+	if(p == x->left) 
+	    {
+	    x->left = m;
+	    }
+	else 
+	    {
+	    x->right = m;
+	    }
+	}
+    
+    /* Update the tree part m is removed from, and assign m the child
+     * pointers of p (only if m is not the right child of p).
+     */
+    stack[i] = m;  /* Node m replaces node p on the stack. */
+    x = stack[--tos];
+    r = m->right;
+    if(tos != i) 
+	{  /* x is equal to the parent of m. */
+	y = x->right;
+	x->left = r;
+	m->right = p->right;
+	}
+    else 
+	{ /* m was the right child of p, and x is equal to m. */
+	y = p->left;
+	}
+    m->left = p->left;
+
+    /* We treat node m as the node which has been removed. */
+    removeCol = m->color;
+    m->color = p->color;
+    }
+
+/* Get return value and reuse the space used by node p. */
+returnItem = p->item;
+p->right = t->freeList;
+t->freeList = p;
+
+t->n--;
+
+/* The pointers x, y, and r point to nodes which may be involved in
+ * restructuring and recolouring.
+ *  x - the parent of the removed node.
+ *  y - the sibling of the removed node.
+ *  r - the node which replaced the removed node.
+ * From the above code, the next entry off the stack will be the parent of
+ * node x.
+ */
+
+/* The number of black nodes on paths to all external nodes (NULL child
+ * pointers) must remain the same for all paths.  Restructuring or
+ * recolouring of nodes may be necessary to enforce this.
+ */
+if(removeCol == rbTreeBlack) 
+    {
+    /* Removal of a black node requires some adjustment. */
+    
+    if(!r || r->color == rbTreeBlack) 
+	{
+	/* A black node replaced the deleted black node.  Note that
+	 * external nodes (NULL child pointers) are always black, so
+	 * if r is NULL it is treated as a black node.
+	 */
+
+	/* This causes a double-black problem, since node r would need to
+	 * be coloured double-black in order for the black color on
+	 * paths through r to remain the same as for other paths.
+	 */
+
+	/* If r is the root node, the double-black color is not necessary
+	 * to maintain the color balance.  Otherwise, some adjustment of
+	 * nearby nodes is needed in order to eliminate the double-black
+	 * problem.  NOTE:  x points to the parent of r.
+	 */
+	if(x) for(;;) 
+	    {
+
+	    /* There are three adjustment cases:
+	     *  1.  r's sibling, y, is black and has a red child, z.
+	     *  2.  r's sibling, y, is black and has two black children.
+	     *  3.  r's sibling, y, is red.
+	     */
+	    if(y->color == rbTreeBlack) 
+		{
+
+		/* Note the conditional evaluation for assigning z. */
+		if(((z = y->left) && z->color == rbTreeRed) ||
+		   ((z = y->right) && z->color == rbTreeRed)) 
+		       {		    
+		    /* Case 1:  perform a restructuring of nodes x, y, and
+		     * z.
+		     */
+		    
+		    b = restructure(t, tos, x, y, z);
+		    b->color = x->color;
+		    b->left->color = b->right->color = rbTreeBlack;
+		    
+		    break;
+		    }
+		else 
+		    {
+		    /* Case 2:  recolour node y red. */
+		    
+		    y->color = rbTreeRed;
+		    
+		    if(x->color == rbTreeRed) 
+			{
+			x->color = rbTreeBlack;
+			break;
+			}
+		    /* else */
+
+		    if(tos == 0) break;  /* Root level reached. */
+		    /* else */
+		    
+		    r = x;
+		    x = stack[--tos];  /* x <- parent of x. */
+		    y = x->left == r ? x->right : x->left;
+		    }
+		}
+	    else 
+		{
+		/* Case 3:  Restructure nodes x, y, and z, where:
+		 *  - If node y is the left child of x, then z is the left
+		 *    child of y.  Otherwise z is the right child of y.
+		 */
+		if(x->left == y) 
+		    {
+		    newY = y->right;
+		    z = y->left;
+		    }
+		else 
+		    {
+		    newY = y->left;
+		    z = y->right;
+		    }
+		
+		restructure(t, tos, x, y, z);
+		y->color = rbTreeBlack;
+		x->color = rbTreeRed;
+
+		/* Since x has moved down a place in the tree, and y is the
+		 * new the parent of x, the stack must be adjusted so that
+		 * the parent of x is correctly identified in the next call
+		 * to restructure().
+		 */
+		stack[tos++] = y;
+
+		/* After restructuring, node r has a black sibling, newY,
+		 * so either case 1 or case 2 applies.  If case 2 applies
+		 * the double-black problem does not reappear.
+		 */
+		y = newY;
+		
+		/* Note the conditional evaluation for assigning z. */
+		if(((z = y->left) && z->color == rbTreeRed) ||
+		   ((z = y->right) && z->color == rbTreeRed)) 
+		   {		    
+		    /* Case 1:  perform a restructuring of nodes x, y, and
+		     * z.
+		     */
+		    
+		    b = restructure(t, tos, x, y, z);
+		    b->color = rbTreeRed;  /* Since node x was red. */
+		    b->left->color = b->right->color = rbTreeBlack;
+		    }
+		else 
+		    {
+		    /* Case 2:  recolour node y red. */
+
+		    /* Note that node y is black and node x is red. */
+		    
+		    y->color = rbTreeRed;
+		    x->color = rbTreeBlack;
+		    }
+
+		break;
+		}
+	    }
+	}
+    else 
+	{
+	/* A red node replaced the deleted black node. */
+
+	/* In this case we can simply color the red node black. */
+	r->color = rbTreeBlack;
+	}
+    }
+return returnItem;
+}
+
+/* Some variables to help recursively dump tree. */
+static int dumpLevel;	/* Indentation level. */
+static FILE *dumpFile;  /* Output file */
+static void (*dumpIt)(void *item, FILE *f);  /* Item dumper. */
+
+static void rTreeDump(struct rbTreeNode *n)
+/* Recursively dump. */
+{
+if (n == NULL)
+    return;
+spaceOut(dumpFile, ++dumpLevel * 3);
+fprintf(dumpFile, "%c ", (n->color ==  rbTreeRed ? 'r' : 'b'));
+dumpIt(n->item, dumpFile);
+fprintf(dumpFile, "\n");
+rTreeDump(n->left);
+rTreeDump(n->right);
+--dumpLevel;
+}
+
+void rbTreeDump(struct rbTree *tree, FILE *f, 
+	void (*dumpItem)(void *item, FILE *f))
+/* Dump out rb tree to file, mostly for debugging. */
+{
+dumpFile = f;
+dumpLevel = 0;
+dumpIt = dumpItem;
+fprintf(f, "rbTreeDump\n");
+rTreeDump(tree->root);
+}
+
+
+
+/* Variables to help recursively traverse tree. */
+static void (*doIt)(void *item);
+static void *minIt, *maxIt;
+static int (*compareIt)(void *, void *);
+
+static void rTreeTraverseRange(struct rbTreeNode *n)
+/* Recursively traverse tree in range applying doIt. */
+{
+if (n != NULL)
+   {
+   int minCmp = compareIt(n->item, minIt);
+   int maxCmp = compareIt(n->item, maxIt);
+   if (minCmp >= 0)
+       rTreeTraverseRange(n->left);
+   if (minCmp >= 0 && maxCmp <= 0)
+       doIt(n->item);
+   if (maxCmp <= 0)
+       rTreeTraverseRange(n->right);
+   }
+}
+
+static void rTreeTraverse(struct rbTreeNode *n)
+/* Recursively traverse full tree applying doIt. */
+{
+if (n != NULL)
+    {
+    rTreeTraverse(n->left);
+    doIt(n->item);
+    rTreeTraverse(n->right);
+    }
+}
+
+
+void rbTreeTraverseRange(struct rbTree *tree, void *minItem, void *maxItem,
+	void (*doItem)(void *item))
+/* Apply doItem function to all items in tree such that
+ * minItem <= item <= maxItem */
+{
+doIt = doItem;
+minIt = minItem;
+maxIt = maxItem;
+compareIt = tree->compare;
+rTreeTraverseRange(tree->root);
+}
+
+void rbTreeTraverse(struct rbTree *tree, void (*doItem)(void *item))
+/* Apply doItem function to all items in tree */
+{
+doIt = doItem;
+rTreeTraverse(tree->root);
+}
+
+struct rTreeContext
+/* Context for traversing a tree when you want to be fully thread safe and reentrant. */
+    {
+    void *context;	/* Some context carried from user and passed to doIt. */
+    void (*doItem)(void *item, void *context);
+    };
+
+static void rTreeTraverseWithContext(struct rbTreeNode *n, struct rTreeContext *context)
+/* Traverse tree with a little context so don't need little static variables that
+ * prevent reentrancy of callback functions. */
+{
+if (n != NULL)
+    {
+    rTreeTraverseWithContext(n->left, context);
+    context->doItem(n->item, context->context);
+    rTreeTraverseWithContext(n->right, context);
+    }
+}
+
+void rbTreeTraverseWithContext(struct rbTree *tree, 
+	void (*doItem)(void *item, void *context), void *context)
+/* Traverse tree calling doItem on every item with context pointer passed through to doItem.
+ * This often avoids having to declare global or static variables for the doItem callback to use. */
+{
+struct rTreeContext ctx;
+ctx.context = context;
+ctx.doItem = doItem;
+rTreeTraverseWithContext(tree->root, &ctx);
+}
+
+struct slRef *itList;  /* List of items that rbTreeItemsInRange returns. */
+
+static void addRef(void *item)
+/* Add item it itList. */
+{
+refAdd(&itList, item);
+}
+
+struct slRef *rbTreeItemsInRange(struct rbTree *tree, void *minItem, void *maxItem)
+/* Return a sorted list of references to items in tree between range.
+ * slFreeList this list when done. */
+{
+itList = NULL;
+rbTreeTraverseRange(tree, minItem, maxItem, addRef);
+slReverse(&itList);
+return itList;
+}
+
+static void addRefWithContext(void *item, void *context)
+/* Add item it itList. */
+{
+struct slRef **pList = context;
+refAdd(pList, item);
+}
+
+
+struct slRef *rbTreeItems(struct rbTree *tree)
+/* Return sorted list of items.  slFreeList this when done.*/
+{
+struct slRef *list = NULL;
+rbTreeTraverseWithContext(tree, addRefWithContext, &list);
+slReverse(&list);
+return list;
+}
+
+int rbTreeCmpString(void *a, void *b)
+/* Set up rbTree so as to work on strings. */
+{
+return strcmp(a, b);
+}
+
+int rbTreeCmpWord(void *a, void *b)	
+/* Set up rbTree so as to work on case-insensitive strings. */
+{
+return differentWord(a,b);
+}
diff --git a/lib/regexHelper.c b/lib/regexHelper.c
new file mode 100644
index 0000000..9c9e340
--- /dev/null
+++ b/lib/regexHelper.c
@@ -0,0 +1,88 @@
+/* regexHelper: easy wrappers on POSIX Extended Regular Expressions (man 7 regex, man 3 regex) */
+
+#include "regexHelper.h"
+#include "hash.h"
+
+const regex_t *regexCompile(const char *exp, const char *description, int compileFlags)
+/* Compile exp (or die with an informative-as-possible error message).
+ * Cache pre-compiled regex's internally (so don't free result after use). */
+{
+static struct hash *reHash = NULL;
+struct hashEl *hel = NULL;
+char key[512];
+safef(key, sizeof(key), "%d.%s", compileFlags, exp);
+
+if (reHash == NULL)
+    reHash = newHash(10);
+hel = hashLookup(reHash, key);
+if (hel != NULL)
+    return((regex_t *)hel->val);
+else
+    {
+    regex_t *compiledExp = NULL;
+    int errNum = 0;
+    AllocVar(compiledExp);
+    errNum = regcomp(compiledExp, exp, compileFlags);
+    if (errNum != 0)
+	{
+	char errBuf[512];
+	regerror(errNum, compiledExp, errBuf, sizeof(errBuf));
+	errAbort("%s \"%s\" got regular expression compilation error %d:\n%s\n",
+		 description, exp, errNum, errBuf);
+	}
+    hashAdd(reHash, key, compiledExp);
+    return(compiledExp);
+    }
+}
+
+static boolean regexMatchSubstrMaybeCase(const char *string, const char *exp,
+					 regmatch_t substrArr[], size_t substrArrSize,
+					 boolean isCaseInsensitive)
+/* Return TRUE if string matches regular expression exp;
+ * regexec fills in substrArr with substring offsets. */
+{
+int compileFlags = REG_EXTENDED;
+char desc[256];
+safecpy(desc, sizeof(desc), "Regular expression");
+if (isCaseInsensitive)
+    {
+    compileFlags |= REG_ICASE;
+    safecat(desc, sizeof(desc), " (case insensitive)");
+    }
+if (substrArr == NULL)
+    compileFlags |= REG_NOSUB;
+else
+    safecat(desc, sizeof(desc), " with substrings");
+
+const regex_t *compiledExp = regexCompile(exp, desc, compileFlags);
+return(regexec(compiledExp, string, substrArrSize, substrArr, 0) == 0);
+}
+
+boolean regexMatch(const char *string, const char *exp)
+/* Return TRUE if string matches regular expression exp (case sensitive). */
+{
+return regexMatchSubstrMaybeCase(string, exp, NULL, 0, FALSE);
+}
+
+boolean regexMatchNoCase(const char *string, const char *exp)
+/* Return TRUE if string matches regular expression exp (case insensitive). */
+{
+return regexMatchSubstrMaybeCase(string, exp, NULL, 0, TRUE);
+}
+
+boolean regexMatchSubstr(const char *string, const char *exp,
+			 regmatch_t substrArr[], size_t substrArrSize)
+/* Return TRUE if string matches regular expression exp (case sensitive);
+ * regexec fills in substrArr with substring offsets. */
+{
+return regexMatchSubstrMaybeCase(string, exp, substrArr, substrArrSize, FALSE);
+}
+
+boolean regexMatchSubstrNoCase(const char *string, const char *exp,
+			       regmatch_t substrArr[], size_t substrArrSize)
+/* Return TRUE if string matches regular expression exp (case insensitive);
+ * regexec fills in substrArr with substring offsets. */
+{
+return regexMatchSubstrMaybeCase(string, exp, substrArr, substrArrSize, TRUE);
+}
+
diff --git a/lib/repMask.c b/lib/repMask.c
new file mode 100644
index 0000000..4e79ca9
--- /dev/null
+++ b/lib/repMask.c
@@ -0,0 +1,170 @@
+/* repMask.c was originally generated by the autoSql program, which also 
+ * generated repMask.h and repMask.sql.  This module links the database and the RAM 
+ * representation of objects. */
+
+#include "common.h"
+#include "sqlList.h"
+#include "sqlNum.h"
+#include "repMask.h"
+
+
+void repeatMaskOutStaticLoad(char **row, struct repeatMaskOut *ret)
+/* Load a row from repeatMaskOut table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+{
+int i;
+
+ret->score = sqlUnsigned(row[0]);
+ret->percDiv = atof(row[1]);
+ret->percDel = atof(row[2]);
+ret->percInc = atof(row[3]);
+ret->qName = row[4];
+ret->qStart = sqlSigned(row[5]);
+ret->qEnd = sqlSigned(row[6]);
+ret->qLeft = row[7];
+strcpy(ret->strand, row[8]);
+ret->rName = row[9];
+ret->rFamily = row[10];
+ret->rStart = row[11];	/* sometimes this number is enclosed in (parens) */
+/* This row[12] is interpreted as an Unsigned - but I can find no good reason
+ * for it to be an error exit when there is a negative number here.
+ * The only programs that use this routine are blat, psLayout and
+ * maskOutFa and none of them even use this number for anything.
+ * For data base loading of the rmsk tracks, these .out files are parsed
+ * by hgLoadOut and none of this business is referenced.
+ */
+i = sqlSigned(row[12]);
+if( i < 0 ) {
+    warn("WARNING: negative rEnd: %d %s:%d-%d %s", i, ret->qName, ret->qStart, ret->qEnd, ret->rName);
+    ret->rEnd = 0;
+} else {
+ret->rEnd = sqlUnsigned(row[12]);
+}
+ret->rLeft = row[13];
+}
+
+struct repeatMaskOut *repeatMaskOutLoad(char **row)
+/* Load a repeatMaskOut from row fetched with select * from repeatMaskOut
+ * from database.  Dispose of this with repeatMaskOutFree(). */
+{
+struct repeatMaskOut *ret;
+
+AllocVar(ret);
+ret->score = sqlUnsigned(row[0]);
+ret->percDiv = atof(row[1]);
+ret->percDel = atof(row[2]);
+ret->percInc = atof(row[3]);
+ret->qName = cloneString(row[4]);
+ret->qStart = sqlSigned(row[5]);
+ret->qEnd = sqlSigned(row[6]);
+ret->qLeft = cloneString(row[7]);
+strcpy(ret->strand, row[8]);
+ret->rName = cloneString(row[9]);
+ret->rFamily = cloneString(row[10]);
+ret->rStart = cloneString(row[11]);
+ret->rEnd = sqlUnsigned(row[12]);
+ret->rLeft = cloneString(row[13]);
+return ret;
+}
+
+struct repeatMaskOut *repeatMaskOutCommaIn(char **pS)
+/* Create a repeatMaskOut out of a comma separated string. */
+{
+struct repeatMaskOut *ret;
+char *s = *pS;
+
+AllocVar(ret);
+ret->score = sqlUnsignedComma(&s);
+ret->percDiv = sqlSignedComma(&s);
+ret->percDel = sqlSignedComma(&s);
+ret->percInc = sqlSignedComma(&s);
+ret->qName = sqlStringComma(&s);
+ret->qStart = sqlSignedComma(&s);
+ret->qEnd = sqlSignedComma(&s);
+ret->qLeft = sqlStringComma(&s);
+sqlFixedStringComma(&s, ret->strand, sizeof(ret->strand));
+ret->rName = sqlStringComma(&s);
+ret->rFamily = sqlStringComma(&s);
+ret->rStart = sqlStringComma(&s);
+ret->rEnd = sqlUnsignedComma(&s);
+ret->rLeft = sqlStringComma(&s);
+*pS = s;
+return ret;
+}
+
+void repeatMaskOutFree(struct repeatMaskOut **pEl)
+/* Free a single dynamically allocated repeatMaskOut such as created
+ * with repeatMaskOutLoad(). */
+{
+struct repeatMaskOut *el;
+
+if ((el = *pEl) == NULL) return;
+freeMem(el->qName);
+freeMem(el->qLeft);
+freeMem(el->rName);
+freeMem(el->rFamily);
+freeMem(el->rStart);
+freeMem(el->rLeft);
+freez(pEl);
+}
+
+void repeatMaskOutFreeList(struct repeatMaskOut **pList)
+/* Free a list of dynamically allocated repeatMaskOut's */
+{
+struct repeatMaskOut *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    repeatMaskOutFree(&el);
+    }
+*pList = NULL;
+}
+
+void repeatMaskOutOutput(struct repeatMaskOut *el, FILE *f, char sep, char lastSep) 
+/* Print out repeatMaskOut.  Separate fields with sep. Follow last field with lastSep. */
+{
+fprintf(f, "%u", el->score);
+fputc(sep,f);
+fprintf(f, "%f", el->percDiv);
+fputc(sep,f);
+fprintf(f, "%f", el->percDel);
+fputc(sep,f);
+fprintf(f, "%f", el->percInc);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->qName);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%d", el->qStart);
+fputc(sep,f);
+fprintf(f, "%d", el->qEnd);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->qLeft);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->strand);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->rName);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->rFamily);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->rStart);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%u", el->rEnd);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->rLeft);
+if (sep == ',') fputc('"',f);
+fputc(lastSep,f);
+}
+
diff --git a/lib/rle.c b/lib/rle.c
new file mode 100644
index 0000000..58ff09b
--- /dev/null
+++ b/lib/rle.c
@@ -0,0 +1,102 @@
+/* rle - byte oriented run length encoding. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "rle.h"
+
+
+static int countSameAsStart(signed char *s, int max)
+/* Count number of signed chars that are the same as first. */
+{
+signed char v = *s;
+int i;
+if (max > 127)
+    max = 127;
+for (i=1; i<max; ++i)
+   if (s[i] != v)
+       break;
+return i;
+}
+
+int rleCompress(void *vIn, int inSize, signed char *out)
+/* Compress in to out.  Out should be at least inSize * 1.5. 
+ * Returns compressed size. */
+{
+signed char *in = vIn;
+signed char *endIn = in + inSize;
+signed char *s = in, *d = out;
+signed char *uncStart = in;
+int uncSize, sameCount;
+int sizeLeft;
+
+while ((sizeLeft = (endIn - s)) != 0)
+    {
+    sameCount = countSameAsStart(s, sizeLeft);
+    uncSize = s - uncStart;
+    if (sameCount >= 3)
+        {
+	int uncSize = s - uncStart;
+	while (uncSize > 0)
+	    {
+	    int size = uncSize;
+	    if (size > 127) size = 127;
+	    *d++ = size;
+	    memcpy(d, uncStart, size);
+	    d += size;
+	    uncSize -= size;
+	    uncStart += size;
+	    }
+	*d++ = -sameCount;
+	*d++ = *s;
+	s += sameCount;
+	uncStart = s;
+	}
+    else
+        s += sameCount;
+    }  
+uncSize = s - uncStart;
+while (uncSize > 0)
+    {
+    int size = uncSize;
+    if (size > 127) size = 127;
+    *d++ = size;
+    memcpy(d, uncStart, size);
+    d += size;
+    uncSize -= size;
+    uncStart += size;
+    }
+return d - out;
+}
+
+void rleUncompress(signed char *in, int inSize, void *vOut, int outSize)
+/* Uncompress in to out. */
+{
+int count;
+signed char *out = vOut;
+signed char *endOut = out + outSize;
+#ifndef NDEBUG
+signed char *endIn = in + inSize;
+#endif
+
+while (out < endOut)
+     {
+     count = *in++;
+     if (count > 0)
+          {
+	  memcpy(out, in, count);
+	  in += count;
+	  out += count;
+	  }
+    else
+          {
+	  count = -count;
+	  memset(out, *in++, count);
+	  out += count;
+	  }
+	  
+    }
+assert(out == endOut && in == endIn);
+}
+
diff --git a/lib/rnautil.c b/lib/rnautil.c
new file mode 100644
index 0000000..6988374
--- /dev/null
+++ b/lib/rnautil.c
@@ -0,0 +1,220 @@
+/* rnautil.c - functions for dealing with RNA and RNA secondary structure.  */
+#include "rnautil.h"
+#include "common.h"
+
+const char *RNA_PAIRS[] = {"AU","UA","GC","CG","GU","UG",0};
+/* Null terminated array of rna pairs */
+
+void dna2rna(char *s)
+/* Replace 't' with 'u' and 'T' with 'U' in s. */
+{
+for (;*s;s++)
+    {
+    if (*s == 't')
+	*s = 'u';
+    if (*s == 'T')
+	*s = 'U';
+    }
+}
+
+bool rnaPair(char a, char b)
+/* Returns TRUE if a and b can pair, and false otherwise */
+{
+char pair[] = {a,b,'\0'};
+int i;
+dna2rna(pair);
+touppers(pair);
+
+for (i=0;RNA_PAIRS[i] != 0; i++)
+    if (pair[0] == RNA_PAIRS[i][0] && pair[1] == RNA_PAIRS[i][1] )
+	return TRUE;
+return FALSE;
+}
+
+void reverseFold(char *s)
+/* Reverse the order of the parenthesis defining an RNA secondary structure annotation. */
+{
+reverseBytes(s, strlen(s));
+for (;*s;s++)
+    {
+    if (*s == '(')
+	*s = ')';
+    else if (*s == ')')
+	*s = '(';
+    }
+}
+
+void fold2pairingList(char *fold, int len, int **p2pairList)
+/* take a parenthesis string, allocate and return an array of pairing
+   positions: pairList[i] = j <=> i pair with j and pairList[i] = -1
+   <=> i does not pair.*/
+{
+int i,j, stackSize = 0;
+int *pairList      = needMem(len * sizeof(int));
+*p2pairList        = pairList;
+
+/* initialize array */
+for (i = 0; i < len; i++)
+    pairList[i] = -1;
+
+/* fill out pairList */
+for (i = 0; i < len; i++) 
+    {
+    if (fold[i] == '(')
+	{
+	stackSize = 1;
+	for (j = i+1; j < len; j++) 
+	    {
+	    if (fold[j] == '(')
+		stackSize += 1;
+	    else if (fold[j] == ')')
+		stackSize -= 1;
+	    if (stackSize == 0)  /* found pair partner */
+		{
+		pairList[i] = j;
+		pairList[j] = i;
+		break;
+		}
+	    }
+	}
+    }
+}
+
+void mkPairPartnerSymbols(int *pairList, char *pairSymbols, int size)
+{
+/* Make a symbol string indicating pairing partner */
+int i;
+char symbols[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*=+{}|[]\\;'"; /* length 80 */
+int  symbolMax = strlen(symbols);
+int index;
+for (i = 0, index = 0; i < size; i++)
+    {
+    pairSymbols[i] = ' ';
+    if (pairList[i] >= 0)
+	{
+	if (pairList[i] < i)
+	    {
+            --index;
+	    if (index<0)
+		index = symbolMax-1;
+	    }
+	pairSymbols[i] = symbols[index];
+	if (pairList[i] > i)
+	    {
+            ++index;
+	    if (index>=symbolMax)
+		index=0;
+	    }
+	}
+    }
+}
+
+char * projectString(char *s, char *ref, char refChar, char insertChar)
+/* Insert 'insertChar' in 's' at every position 'ref' has 'refChar'. */
+{
+int i,j,size = strlen(ref);
+char *copy = (char *) needMem(size + 1);
+
+if (strlen(s) != strlen(ref) - countChars(ref, refChar))
+  errAbort("ERROR from rnautil::projectString: Input string 's' has wrong length.\n"); 
+
+for (i = 0, j = 0; i < size; i++)
+    {
+    if (ref[i] == refChar)
+	copy[i] = insertChar;
+    else
+	{	
+	copy[i] = s[j];
+	j++;
+	}
+    }
+return copy;
+}
+
+char *gapAdjustFold(char *s, char *ref)
+/* Insert space in s when there is a gap ('-') in ref. */
+{
+return projectString(s, ref, '-', ' ');
+}
+
+
+int *projectIntArray(int *in, char *ref, char refChar, int insertInt)
+/* Insert 'insertChar' in 's' at every positin 'ref' has 'refChar'. */
+{
+int i,j,size = strlen(ref);
+int   *copy = (int *) needMem(size *sizeof(int) );
+
+for (i = 0, j = 0; i < size; i++)
+    {
+    if (ref[i] == refChar)
+	copy[i] = insertInt;
+    else
+	{	
+	copy[i] = in[j];
+	j++;
+	}
+    }
+return copy;
+}
+
+int * gapIntArrayAdjust(int *in, char *ref)
+/* Insert space in s when there is a gap ('-') in ref. */
+{
+return projectIntArray(in, ref, '-', 0);
+}
+
+void markCompensatoryMutations(char *s, char *ref, int *pairList, int *markList)
+/* Compares s to ref and pairList and sets values in markList
+ * according to pairing properties. The value of markList[i] specifies
+ * the pairing property of the i'th position. The following values are
+ * used: 
+ * 0: not pairing, no substitution (default) 
+ * 1: not pairing, single substitution
+ * 2: pairing, no substitutions 
+ * 3: pairing, single substitution (one of: CG<->TG, GC<->GT, TA<->TG, AT<->GT)
+ * 4: pairing, double substitution (i.e. a compensatory change)
+ * 5: annotated as pairing but dinucleotide cannot pair, single substitution
+ * 6: annotated as pairing but dinucleotide cannot pair, doubble substitution
+ * 7: annotated as pairing but dinucleotide cannot pair, involves indel ('-' substitution)
+ */
+{
+int i, size = strlen(s);
+for (i = 0; i < size; i++)
+    {
+    if (pairList[i] == -1)
+	if (toupper(s[i]) != toupper(ref[i]) && s[i] != '.' && s[i] != '-' && ref[i] != '-')
+	    markList[i] = 1;
+	else
+	    markList[i] = 0;
+    else
+	{
+	if (s[i] == '.' || s[pairList[i]] == '.') /* treat missing data as possible pair partner */
+	    markList[i] = 2;
+	else if (!rnaPair(s[i], s[pairList[i]]))
+	  if (s[i] == '-' || s[pairList[i]] == '-')
+	    markList[i] = 7;
+	  else if (toupper( s[i] ) != toupper( ref[i] ) && toupper( s[pairList[i]] ) != toupper( ref[pairList[i]] ) )
+	    markList[i] = 6;
+	  else
+	    markList[i] = 5;
+	else if (toupper( s[i] ) != toupper( ref[i] ) && toupper( s[pairList[i]] ) != toupper( ref[pairList[i]] ) )
+	    markList[i] = 4;
+	else if (toupper( s[i] ) != toupper( ref[i] ) || toupper( s[pairList[i]] ) != toupper( ref[pairList[i]] ) )
+	    markList[i] = 3;
+	else
+	    markList[i] = 2;
+	}
+    }
+}
+
+int assignBin(double val, double minVal, double maxVal, int binCount)
+/* Divide range given by minVal and maxVal into binCount intervals
+   (bins), and return index of the bin val falls into. */
+{
+double range = maxVal - minVal;
+int maxBin   = binCount - 1;
+int level    = (int) ( (val-minVal)*maxBin/range);
+if (level <= 0) level = 0;
+if (level > maxBin) level = maxBin;
+return level;
+}
diff --git a/lib/rqlEval.c b/lib/rqlEval.c
new file mode 100644
index 0000000..3024da1
--- /dev/null
+++ b/lib/rqlEval.c
@@ -0,0 +1,332 @@
+/* rqlEval - evaluate tree returned by rqlParse given a record and function to lookup fields
+ * in the record. . */
+
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "dystring.h"
+#include "localmem.h"
+#include "tokenizer.h"
+#include "sqlNum.h"
+#include "rql.h"
+
+
+static struct rqlEval rqlLocalEval(struct rqlParse *p, void *record, RqlEvalLookup lookup, 
+	struct lm *lm);
+/* Evaluate self on parse tree, allocating memory if needed from lm. */
+
+struct rqlEval rqlEvalCoerceToBoolean(struct rqlEval r)
+/* Return TRUE if it's a nonempty string or a non-zero number. */
+{
+switch (r.type)
+    {
+    case rqlTypeBoolean:
+	break;	/* It's already done. */
+    case rqlTypeString:
+        r.val.b = (r.val.s != NULL && r.val.s[0] != 0);
+	break;
+    case rqlTypeInt:
+        r.val.b = (r.val.i != 0);
+	break;
+    case rqlTypeDouble:
+        r.val.b = (r.val.x != 0.0);
+	break;
+    default:
+	internalErr();
+	r.val.b = FALSE;
+	break;
+    }
+r.type = rqlTypeBoolean;
+return r;
+}
+
+static struct rqlEval rqlEvalEq(struct rqlParse *p, 
+	void *record, RqlEvalLookup lookup, struct lm *lm)
+/* Return true if two children are equal regardless of children type
+ * (which are just gauranteed to be the same). */
+{
+struct rqlParse *lp = p->children;
+struct rqlParse *rp = lp->next;
+struct rqlEval lv = rqlLocalEval(lp, record, lookup, lm);
+struct rqlEval rv = rqlLocalEval(rp, record, lookup, lm);
+struct rqlEval res;
+res.type = rqlTypeBoolean;
+assert(lv.type == rv.type);
+switch (lv.type)
+    {
+    case rqlTypeBoolean:
+        res.val.b = (lv.val.b == rv.val.b);
+	break;
+    case rqlTypeString:
+	res.val.b = sameString(lv.val.s, rv.val.s);
+	break;
+    case rqlTypeInt:
+	res.val.b = (lv.val.i == rv.val.i);
+	break;
+    case rqlTypeDouble:
+	res.val.b = (lv.val.x == rv.val.x);
+	break;
+    default:
+	internalErr();
+	res.val.b = FALSE;
+	break;
+    }
+return res;
+}
+
+static struct rqlEval rqlEvalLt(struct rqlParse *p, void *record, RqlEvalLookup lookup,
+	struct lm *lm)
+/* Return true if r < l . */
+{
+struct rqlParse *lp = p->children;
+struct rqlParse *rp = lp->next;
+struct rqlEval lv = rqlLocalEval(lp, record, lookup, lm);
+struct rqlEval rv = rqlLocalEval(rp, record, lookup, lm);
+struct rqlEval res;
+res.type = rqlTypeBoolean;
+switch (lv.type)
+    {
+    case rqlTypeBoolean:
+        res.val.b = (lv.val.b < rv.val.b);
+	break;
+    case rqlTypeString:
+	res.val.b = strcmp(lv.val.s, rv.val.s) < 0;
+	break;
+    case rqlTypeInt:
+	res.val.b = (lv.val.i < rv.val.i);
+	break;
+    case rqlTypeDouble:
+	res.val.b = (lv.val.x < rv.val.x);
+	break;
+    default:
+	internalErr();
+	res.val.b = FALSE;
+	break;
+    }
+return res;
+}
+
+static struct rqlEval rqlEvalGt(struct rqlParse *p, void *record, RqlEvalLookup lookup,
+	struct lm *lm)
+/* Return true if r > l . */
+{
+struct rqlParse *lp = p->children;
+struct rqlParse *rp = lp->next;
+struct rqlEval lv = rqlLocalEval(lp, record, lookup, lm);
+struct rqlEval rv = rqlLocalEval(rp, record, lookup, lm);
+struct rqlEval res;
+res.type = rqlTypeBoolean;
+switch (lv.type)
+    {
+    case rqlTypeBoolean:
+        res.val.b = (lv.val.b > rv.val.b);
+	break;
+    case rqlTypeString:
+	res.val.b = strcmp(lv.val.s, rv.val.s) > 0;
+	break;
+    case rqlTypeInt:
+	res.val.b = (lv.val.i > rv.val.i);
+	break;
+    case rqlTypeDouble:
+	res.val.b = (lv.val.x > rv.val.x);
+	break;
+    default:
+	internalErr();
+	res.val.b = FALSE;
+	break;
+    }
+return res;
+}
+
+static struct rqlEval rqlEvalLike(struct rqlParse *p, void *record, RqlEvalLookup lookup,
+	struct lm *lm)
+/* Return true if r like l . */
+{
+struct rqlParse *lp = p->children;
+struct rqlParse *rp = lp->next;
+struct rqlEval lv = rqlLocalEval(lp, record, lookup, lm);
+struct rqlEval rv = rqlLocalEval(rp, record, lookup, lm);
+struct rqlEval res;
+res.type = rqlTypeBoolean;
+assert(rv.type == rqlTypeString);
+assert(rv.type == lv.type);
+res.val.b = sqlMatchLike(rv.val.s, lv.val.s);
+return res;
+}
+
+static struct rqlEval rqlEvalArrayIx(struct rqlParse *p, void *record, RqlEvalLookup lookup,
+	struct lm *lm)
+/* Handle parse tree generated by an indexed array. */
+{
+struct rqlParse *array = p->children;
+struct rqlParse *index = array->next;
+struct rqlEval arrayVal = rqlLocalEval(array, record, lookup, lm);
+struct rqlEval indexVal = rqlLocalEval(index, record, lookup, lm);
+struct rqlEval res;
+res.type = rqlTypeString;
+res.val.s = emptyForNull(lmCloneSomeWord(lm, arrayVal.val.s, indexVal.val.i));
+return res;
+}
+
+static struct rqlEval rqlLocalEval(struct rqlParse *p, void *record, RqlEvalLookup lookup, 
+	struct lm *lm)
+/* Evaluate self on parse tree, allocating memory if needed from lm. */
+{
+struct rqlEval res;
+switch (p->op)
+    {
+    case rqlOpLiteral:
+	res.val = p->val;
+	res.type = p->type;
+	break;
+    case rqlOpSymbol:
+	res.type = rqlTypeString;
+	char *s = lookup(record, p->val.s);
+	if (s == NULL)
+	    res.val.s = "";
+	else
+	    res.val.s = s;
+	break;
+    case rqlOpEq:
+	res = rqlEvalEq(p, record, lookup, lm);
+	break;
+    case rqlOpNe:
+	res = rqlEvalEq(p, record, lookup, lm);
+	res.val.b = !res.val.b;
+	break;
+
+    /* Inequalities. */
+    case rqlOpLt:
+        res = rqlEvalLt(p, record, lookup, lm);
+	break;
+    case rqlOpGt:
+        res = rqlEvalGt(p, record, lookup, lm);
+	break;
+    case rqlOpLe:
+        res = rqlEvalGt(p, record, lookup, lm);
+	res.val.b = !res.val.b;
+	break;
+    case rqlOpGe:
+        res = rqlEvalLt(p, record, lookup, lm);
+	res.val.b = !res.val.b;
+	break;
+    case rqlOpLike:
+        res = rqlEvalLike(p,record, lookup, lm);
+	break;
+
+    /* Logical ops. */
+    case rqlOpAnd:
+	{
+        res.type = rqlTypeBoolean;
+	res.val.b = TRUE;
+	struct rqlParse *c;
+	for (c = p->children; c != NULL; c= c->next)
+	    {
+	    struct rqlEval e = rqlLocalEval(c, record, lookup, lm);
+	    if (!e.val.b)
+		{
+	        res.val.b = FALSE;
+		break;
+		}
+	    }
+	break;
+	}
+    case rqlOpOr:
+	{
+        res.type = rqlTypeBoolean;
+	res.val.b = FALSE;
+	struct rqlParse *c;
+	for (c = p->children; c != NULL; c= c->next)
+	    {
+	    struct rqlEval e = rqlLocalEval(c, record, lookup, lm);
+	    if (e.val.b)
+		{
+	        res.val.b = TRUE;
+		break;
+		}
+	    }
+	break;
+	}
+
+    case rqlOpNot:
+        res = rqlLocalEval(p->children, record, lookup, lm);
+	res.val.b = !res.val.b;
+	break;
+
+    /* Type casts. */
+    case rqlOpStringToBoolean:
+	res = rqlLocalEval(p->children, record, lookup, lm);
+	res.type = rqlTypeBoolean;
+	res.val.b = (res.val.s[0] != 0);
+	break;
+    case rqlOpIntToBoolean:
+        res = rqlLocalEval(p->children, record, lookup, lm);
+	res.type = rqlTypeBoolean;
+	res.val.b = (res.val.i != 0);
+	break;
+    case rqlOpDoubleToBoolean:
+        res = rqlLocalEval(p->children, record, lookup, lm);
+	res.type = rqlTypeBoolean;
+	res.val.b = (res.val.x != 0.0);
+	break;
+    case rqlOpStringToInt:
+	res = rqlLocalEval(p->children, record, lookup, lm);
+	res.type = rqlTypeInt;
+	res.val.i = atoi(res.val.s);
+	break;
+    case rqlOpDoubleToInt:
+	res = rqlLocalEval(p->children, record, lookup, lm);
+	res.type = rqlTypeInt;
+	res.val.i = res.val.x;
+	break;
+
+    case rqlOpStringToDouble:
+	res = rqlLocalEval(p->children, record, lookup, lm);
+	res.type = rqlTypeDouble;
+	res.val.x = atof(res.val.s);
+	break;
+    case rqlOpBooleanToInt:
+	res = rqlLocalEval(p->children, record, lookup, lm);
+	res.type = rqlTypeInt;
+	res.val.i = res.val.b;
+	break;
+    case rqlOpBooleanToDouble:
+	res = rqlLocalEval(p->children, record, lookup, lm);
+	res.type = rqlTypeDouble;
+	res.val.x = res.val.b;
+	break;
+    case rqlOpIntToDouble:
+	res = rqlLocalEval(p->children, record, lookup, lm);
+	res.type = rqlTypeDouble;
+	res.val.x = res.val.b;
+	break;
+
+    /* Arithmetical negation. */
+    case rqlOpUnaryMinusInt:
+        res = rqlLocalEval(p->children, record, lookup, lm);
+	res.val.i = -res.val.i;
+	break;
+    case rqlOpUnaryMinusDouble:
+        res = rqlLocalEval(p->children, record, lookup, lm);
+	res.val.x = -res.val.x;
+	break;
+
+    case rqlOpArrayIx:
+       res = rqlEvalArrayIx(p, record, lookup, lm);
+       break;
+
+    default:
+        errAbort("Unknown op %s\n", rqlOpToString(p->op));
+	res.type = rqlTypeInt;	// Keep compiler from complaining.
+	res.val.i = 0;	// Keep compiler from complaining.
+	break;
+    }
+return res;
+}
+
+struct rqlEval rqlEvalOnRecord(struct rqlParse *p, void *record, RqlEvalLookup lookup, 
+	struct lm *lm)
+/* Evaluate parse tree on record, using lm for memory for string operations. */
+{
+return rqlLocalEval(p, record, lookup, lm);
+}
diff --git a/lib/rqlParse.c b/lib/rqlParse.c
new file mode 100644
index 0000000..054e273
--- /dev/null
+++ b/lib/rqlParse.c
@@ -0,0 +1,764 @@
+/* rqlParse - parse restricted sql-like query language.  Produce rqlParse tree.  See rqlEval.c
+ * for the rqlParse interpreter. */
+
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "dystring.h"
+#include "tokenizer.h"
+#include "sqlNum.h"
+#include "rql.h"
+
+
+char *rqlOpToString(enum rqlOp op)
+/* Return string representation of parse op. */
+{
+switch (op)
+    {
+    case rqlOpLiteral:
+	return "rqlOpLiteral";
+    case rqlOpSymbol:
+	return "rqlOpSymbol";
+    
+    case rqlOpStringToBoolean:
+        return "rqlOpStringToBoolean";
+    case rqlOpIntToBoolean:
+        return "rqlOpIntToBoolean";
+    case rqlOpDoubleToBoolean:
+        return "rqlOpDoubleToBoolean";
+    case rqlOpStringToInt:
+        return "rqlOpStringToInt";
+    case rqlOpDoubleToInt:
+        return "rqlOpDoubleToInt";
+    case rqlOpBooleanToInt:
+        return "rqlOpBooleanToInt";
+    case rqlOpStringToDouble:
+        return "rqlOpStringToDouble";
+    case rqlOpBooleanToDouble:
+        return "rqlOpBooleanToDouble";
+    case rqlOpIntToDouble:
+        return "rqlOpIntToDouble";
+
+    case rqlOpEq:
+	return "rqlOpEq";
+    case rqlOpNe:
+	return "rqlOpNe";
+    case rqlOpGt:
+        return "rqlOpGt";
+    case rqlOpLt:
+        return "rqlOpLt";
+    case rqlOpGe:
+        return "rqlOpGe";
+    case rqlOpLe:
+        return "rqlOpLe";
+    case rqlOpLike:
+	return "rqlOpLike";
+
+    case rqlOpAnd:
+	return "rqlOpAnd";
+    case rqlOpOr:
+	return "rqlOpOr";
+    case rqlOpNot:
+        return "rqlOpNot";
+
+    case rqlOpUnaryMinusInt:
+        return "rqlOpUnaryMinusInt";
+    case rqlOpUnaryMinusDouble:
+        return "rqlOpUnaryMinusDouble";
+
+    case rqlOpArrayIx:
+        return "rqlOpArrayIx";
+
+    default:
+	return "rqlOpUnknown";
+    }
+}
+
+void rqlValDump(union rqlVal val, enum rqlType type, FILE *f)
+/* Dump out value to file. */
+{
+switch (type)
+    {
+    case rqlTypeBoolean:
+        fprintf(f, "%s", (val.b ? "true" : "false") );
+	break;
+    case rqlTypeString:
+        fprintf(f, "%s", val.s);
+	break;
+    case rqlTypeInt:
+        fprintf(f, "%d", val.i);
+	break;
+    case rqlTypeDouble:
+        fprintf(f, "%f", val.x);
+	break;
+    }
+}
+
+void rqlParseDump(struct rqlParse *p, int depth, FILE *f)
+/* Dump out rqlParse tree and children. */
+{
+spaceOut(f, 3*depth);
+fprintf(f, "%s ", rqlOpToString(p->op));
+rqlValDump(p->val, p->type,  f);
+fprintf(f, "\n");
+struct rqlParse *child;
+for (child = p->children; child != NULL; child= child->next)
+    rqlParseDump(child, depth+1, f);
+}
+
+static void expectingGot(struct tokenizer *tkz, char *expecting, char *got)
+/* Print out error message about unexpected input. */
+{
+errAbort("Expecting %s, got %s, line %d of %s", expecting, got, tkz->lf->lineIx,
+	tkz->lf->fileName);
+}
+
+static void skipOverRequired(struct tokenizer *tkz, char *expecting)
+/* Make sure that next token is tok, and skip over it. */
+{
+tokenizerMustHaveNext(tkz);
+if (!sameString(tkz->string, expecting))
+    expectingGot(tkz, expecting, tkz->string);
+}
+
+
+struct rqlParse *rqlParseExpression(struct tokenizer *tkz);
+/* Parse out a clause, usually a where clause. */
+
+static struct rqlParse *rqlParseAtom(struct tokenizer *tkz)
+/* Return low level (symbol or literal) */
+{
+char *tok = tokenizerMustHaveNext(tkz);
+struct rqlParse *p;
+AllocVar(p);
+char c = tok[0];
+if (c == '\'' || c == '"')
+    {
+    p->op = rqlOpLiteral;
+    p->type = rqlTypeString;
+    int len = strlen(tok+1);
+    p->val.s = cloneStringZ(tok+1, len-1);
+    }
+else if (isalpha(c) || c == '_')
+    {
+    p->op = rqlOpSymbol;
+    p->type = rqlTypeString;	/* String until promoted at least. */
+    p->val.s = cloneString(tok);
+    }
+else if (isdigit(c))
+    {
+    p->op = rqlOpLiteral;
+    p->type = rqlTypeInt;
+    p->val.i = sqlUnsigned(tok);
+    if ((tok = tokenizerNext(tkz)) != NULL)
+	{
+	if (tok[0] == '.')
+	    {
+	    char buf[32];
+	    tok = tokenizerMustHaveNext(tkz);
+	    safef(buf, sizeof(buf), "%d.%s", p->val.i, tok);
+	    p->type = rqlTypeDouble;
+	    p->val.x = sqlDouble(buf);
+	    }
+	else
+	    tokenizerReuse(tkz);
+	}
+    }
+else if (c == '(')
+    {
+    p = rqlParseExpression(tkz);
+    skipOverRequired(tkz, ")");
+    }
+else
+    {
+    errAbort("Unexpected %s line %d of %s", tok, tkz->lf->lineIx, tkz->lf->fileName);
+    }
+return p;
+}
+
+static enum rqlType commonTypeForBop(enum rqlType left, enum rqlType right)
+/* Return type that will work for a binary operation. */
+{
+if (left == right)
+    return left;
+else if (left == rqlTypeDouble || right == rqlTypeDouble)
+    return rqlTypeDouble;
+else if (left == rqlTypeInt || right == rqlTypeInt)
+    return rqlTypeInt;
+else if (left == rqlTypeBoolean || right == rqlTypeBoolean)
+    return rqlTypeBoolean;
+else if (left == rqlTypeString || right == rqlTypeString)
+    return rqlTypeString;
+else
+    {
+    errAbort("Can't find commonTypeForBop");
+    return rqlTypeInt;
+    }
+}
+
+static enum rqlOp booleanCastOp(enum rqlType oldType)
+/* Return op to convert oldType to boolean. */
+{
+switch (oldType)
+    {
+    case rqlTypeString:
+        return rqlOpStringToBoolean;
+    case rqlTypeInt:
+        return rqlOpIntToBoolean;
+    case rqlTypeDouble:
+        return rqlOpDoubleToBoolean;
+    default:
+        internalErr();
+	return rqlOpUnknown;
+    }
+}
+
+static enum rqlOp intCastOp(enum rqlType oldType)
+/* Return op to convert oldType to int. */
+{
+switch (oldType)
+    {
+    case rqlTypeString:
+        return rqlOpStringToInt;
+    case rqlTypeBoolean:
+        return rqlOpBooleanToInt;
+    case rqlTypeDouble:
+        return rqlOpDoubleToInt;
+    default:
+        internalErr();
+	return rqlOpUnknown;
+    }
+}
+
+static enum rqlOp doubleCastOp(enum rqlType oldType)
+/* Return op to convert oldType to double. */
+{
+switch (oldType)
+    {
+    case rqlTypeString:
+        return rqlOpStringToDouble;
+    case rqlTypeBoolean:
+        return rqlOpBooleanToDouble;
+    case rqlTypeInt:
+        return rqlOpIntToDouble;
+    default:
+        internalErr();
+	return rqlOpUnknown;
+    }
+}
+
+
+static struct rqlParse *rqlParseCoerce(struct rqlParse *p, enum rqlType type)
+/* If p is not of correct type, wrap type conversion node around it. */
+{
+if (p->type == type)
+    return p;
+else
+    {
+    struct rqlParse *cast;
+    AllocVar(cast);
+    cast->children = p;
+    cast->type = type;
+    switch (type)
+        {
+	case rqlTypeBoolean:
+	    cast->op = booleanCastOp(p->type);
+	    break;
+	case rqlTypeInt:
+	    cast->op = intCastOp(p->type);
+	    break;
+	case rqlTypeDouble:
+	    cast->op = doubleCastOp(p->type);
+	    break;
+	default:
+	    internalErr();
+	    break;
+	}
+    return cast;
+    }
+}
+
+static struct rqlParse *rqlParseIndex(struct tokenizer *tkz)
+/* Handle the [] in this[6].  Convert it into tree:
+*         rqlOpArrayIx
+*            rqlParseAtom
+*            rqlParseAtom */
+{
+struct rqlParse *collection = rqlParseAtom(tkz);
+struct rqlParse *p = collection;
+char *tok = tokenizerNext(tkz);
+if (tok == NULL)
+    tokenizerReuse(tkz);
+else if (tok[0] == '[')
+    {
+    // struct rqlParse *index = rqlParseExpression(tkz);
+    struct rqlParse *index = rqlParseAtom(tkz);
+    index = rqlParseCoerce(index, rqlTypeInt);
+    skipOverRequired(tkz, "]");
+    AllocVar(p);
+    p->op = rqlOpArrayIx;
+    p->type = rqlTypeString;
+    p->children = collection;
+    collection->next = index;
+    }
+else
+    tokenizerReuse(tkz);
+return p;
+}
+
+
+static struct rqlParse *rqlParseUnaryMinus(struct tokenizer *tkz)
+/* Return unary minus sort of parse tree if there's a leading '-' */
+{
+char *tok = tokenizerMustHaveNext(tkz);
+if (tok[0] == '-')
+    {
+    struct rqlParse *c = rqlParseIndex(tkz);
+    struct rqlParse *p;
+    AllocVar(p);
+    if (c->type == rqlTypeInt)
+        {
+	p->op = rqlOpUnaryMinusInt;
+	p->type = rqlTypeInt;
+	}
+    else
+	{
+	c = rqlParseCoerce(c, rqlTypeDouble);
+	p->op = rqlOpUnaryMinusDouble;
+	p->type = rqlTypeDouble;
+	}
+    p->children = c;
+    return p;
+    }
+else
+    {
+    tokenizerReuse(tkz);
+    return rqlParseIndex(tkz);
+    }
+}
+
+static boolean eatMatchingTok(struct tokenizer *tkz, char *s)
+/* If next token matches s then eat it and return TRUE */
+{
+char *tok = tokenizerNext(tkz);
+if (tok != NULL && sameString(tok, s))
+    return TRUE;
+else
+    {
+    tokenizerReuse(tkz);
+    return FALSE;
+    }
+}
+
+static struct rqlParse *rqlParseCmp(struct tokenizer *tkz)
+/* Parse out comparison. */
+{
+struct rqlParse *l = rqlParseUnaryMinus(tkz);
+struct rqlParse *p = l;
+char *tok = tokenizerNext(tkz);
+boolean forceString = FALSE;
+boolean needNot = FALSE;
+if (tok != NULL)
+    {
+    enum rqlOp op = rqlOpUnknown;
+    if (sameString(tok, "="))
+        {
+	op = rqlOpEq;
+	}
+    else if (sameString(tok, "!"))
+        {
+	op = rqlOpNe;
+	skipOverRequired(tkz, "=");
+	}
+    else if (sameString(tok, ">"))
+        {
+	if (eatMatchingTok(tkz, "="))
+	    op = rqlOpGe;
+	else
+	    op = rqlOpGt;
+	}
+    else if (sameString(tok, "<"))
+        {
+	if (eatMatchingTok(tkz, "="))
+	    op = rqlOpGe;
+	else
+	    op = rqlOpLe;
+	}
+    else if (sameString(tok, "not"))
+        {
+	forceString = TRUE;
+	op = rqlOpLike;
+	needNot = TRUE;
+	skipOverRequired(tkz, "like");
+	}
+    else if (sameString(tok, "like"))
+        {
+	forceString = TRUE;
+	op = rqlOpLike;
+	}
+    else
+        {
+	tokenizerReuse(tkz);
+	return p;
+	}
+    struct rqlParse *r = rqlParseUnaryMinus(tkz);
+    AllocVar(p);
+    p->op = op;
+    p->type = rqlTypeBoolean;
+
+    /* Now force children to be the same type, inserting casts if need be. */
+    if (forceString)
+	{
+	if (l->type != rqlTypeString || r->type != rqlTypeString)
+	    {
+	    errAbort("Expecting string type around comparison line %d of %s",
+	    	tkz->lf->lineIx, tkz->lf->fileName);
+	    }
+	}
+    else
+	{
+	enum rqlType childType = commonTypeForBop(l->type, r->type);
+	l = rqlParseCoerce(l, childType);
+	r = rqlParseCoerce(r, childType);
+	}
+
+    /* Now hang children onto node. */
+    p->children = l;
+    l->next = r;
+
+    /* Put in a not around self if need be. */
+    if (needNot)
+        {
+	struct rqlParse *n;
+	AllocVar(n);
+	n->op = rqlOpNot;
+	n->type = rqlTypeBoolean;
+	n->children = p;
+	p = n;
+	}
+    }
+return p;
+}
+
+static struct rqlParse *rqlParseNot(struct tokenizer *tkz)
+/* parse out a logical not. */
+{
+char *tok = tokenizerNext(tkz);
+if (sameString(tok, "not"))
+    {
+    struct rqlParse *p = rqlParseCoerce(rqlParseCmp(tkz), rqlTypeBoolean);
+    struct rqlParse *n;
+    AllocVar(n);
+    n->op = rqlOpNot;
+    n->type = rqlTypeBoolean;
+    n->children = p;
+    return n;
+    }
+else
+    {
+    tokenizerReuse(tkz);
+    return rqlParseCmp(tkz);
+    }
+}
+
+static struct rqlParse *rqlParseAnd(struct tokenizer *tkz)
+/* Parse out and or or. */
+{
+struct rqlParse *p = rqlParseNot(tkz);
+struct rqlParse *parent = NULL;
+for (;;)
+    {
+    char *tok = tokenizerNext(tkz);
+    if (tok == NULL || !sameString(tok, "and"))
+        {
+	tokenizerReuse(tkz);
+	return p;
+	}
+    else
+        {
+	if (parent == NULL)
+	    {
+	    p = rqlParseCoerce(p, rqlTypeBoolean);
+	    AllocVar(parent);
+	    parent->op = rqlOpAnd;
+	    parent->type = rqlTypeBoolean;
+	    parent->children = p;
+	    p = parent;
+	    }
+	struct rqlParse *r = rqlParseCoerce(rqlParseNot(tkz), rqlTypeBoolean);
+	slAddTail(&parent->children, r);
+	}
+    }
+}
+
+static struct rqlParse *rqlParseOr(struct tokenizer *tkz)
+/* Parse out and or or. */
+{
+struct rqlParse *p = rqlParseAnd(tkz);
+struct rqlParse *parent = NULL;
+for (;;)
+    {
+    char *tok = tokenizerNext(tkz);
+    if (tok == NULL || !sameString(tok, "or"))
+        {
+	tokenizerReuse(tkz);
+	return p;
+	}
+    else
+        {
+	if (parent == NULL)
+	    {
+	    p = rqlParseCoerce(p, rqlTypeBoolean);
+	    AllocVar(parent);
+	    parent->op = rqlOpOr;
+	    parent->type = rqlTypeBoolean;
+	    parent->children = p;
+	    p = parent;
+	    }
+	struct rqlParse *r = rqlParseCoerce(rqlParseAnd(tkz), rqlTypeBoolean);
+	slAddTail(&parent->children, r);
+	}
+    }
+}
+
+struct rqlParse *rqlParseExpression(struct tokenizer *tkz)
+/* Parse out a clause, usually a where clause. */
+{
+return rqlParseOr(tkz);
+}
+
+static char *rqlParseFieldSpec(struct tokenizer *tkz, struct dyString *buf)
+/* Return a field spec, which may contain * and ?. Put results in buf, and 
+ * return buf->string. */
+{
+boolean firstTime = TRUE;
+dyStringClear(buf);
+for (;;)
+   {
+   char *tok = tokenizerNext(tkz);
+   if (tok == NULL)
+       break;
+   char c = *tok;
+   if (c == '?' || c == '*' || isalpha(c) || c == '_' || c == '/' || c == '.')
+       {
+       if (firstTime)
+	   dyStringAppend(buf, tok);
+       else
+           {
+	   if (tkz->leadingSpaces == 0)
+	       dyStringAppend(buf, tok);
+	   else
+	       {
+	       tokenizerReuse(tkz);
+	       break;
+	       }
+	   }
+       }
+   else
+       {
+       tokenizerReuse(tkz);
+       break;
+       }
+    firstTime = FALSE;
+    }
+if (buf->stringSize == 0)
+    errAbort("Expecting field name line %d of %s", tkz->lf->lineIx, tkz->lf->fileName);
+return buf->string;
+}
+
+
+void rqlParseVarsUsed(struct rqlParse *p, struct slName **pVarList)
+/* Put variables used by self and children onto varList. */
+{
+if (p->op == rqlOpSymbol)
+    slNameStore(pVarList, p->val.s);
+struct rqlParse *child;
+for (child = p->children; child != NULL; child = child->next)
+    rqlParseVarsUsed(child, pVarList);
+}
+
+struct rqlStatement *rqlStatementParse(struct lineFile *lf)
+/* Parse an RQL statement out of text */
+{
+struct tokenizer *tkz = tokenizerOnLineFile(lf);
+tkz->uncommentShell = TRUE;
+tkz->uncommentC = TRUE;
+tkz->leaveQuotes = TRUE;
+struct rqlStatement *rql;
+AllocVar(rql);
+rql->command = cloneString(tokenizerMustHaveNext(tkz));
+if (sameString(rql->command, "select"))
+    {
+    struct dyString *buf = dyStringNew(0);
+    struct slName *list = NULL;
+    char *tok = rqlParseFieldSpec(tkz, buf);
+    /* Look for count(*) as special case. */
+    boolean countOnly = FALSE;
+    if (sameString(tok, "count"))
+        {
+	char *paren = tokenizerNext(tkz);
+	if (paren[0] == '(')
+	    {
+	    while ((paren = tokenizerMustHaveNext(tkz)) != NULL)
+	        {
+		if (paren[0] == ')')
+		    break;
+		}
+	    countOnly = TRUE;
+	    freez(&rql->command);
+	    rql->command = cloneString("count");
+	    }
+	else
+	    {
+	    tokenizerReuse(tkz);
+	    }
+	}
+    if (!countOnly)
+	{
+	list = slNameNew(tok);
+	for (;;)
+	    {
+	    /* Parse out comma-separated field list. */
+	    char *comma = tokenizerNext(tkz);
+	    if (comma == NULL || comma[0] != ',')
+		{
+		tokenizerReuse(tkz);
+		break;
+		}
+	    slNameAddHead(&list, rqlParseFieldSpec(tkz, buf));
+	    }
+	slReverse(&list);
+	rql->fieldList = list;
+	}
+    dyStringFree(&buf);
+    }
+else if (sameString(rql->command, "count"))
+    {
+    /* No parameters to count. */
+    }
+else
+    errAbort("Unknown RQL command '%s line %d of %s\n", rql->command, lf->lineIx, lf->fileName);
+    
+char *from = tokenizerNext(tkz);
+if (from != NULL)
+    {
+    if (sameString(from, "from"))
+        {
+	for (;;)
+	    {
+	    struct dyString *buf = dyStringNew(0);
+	    char *table = rqlParseFieldSpec(tkz, buf);
+	    slNameAddTail(&rql->tableList, table);
+	    char *comma = tokenizerNext(tkz);
+	    if (comma == NULL)
+	        break;
+	    if (comma[0] != ',')
+	        {
+		tokenizerReuse(tkz);
+		break;
+		}
+	    dyStringFree(&buf);
+	    }
+	}
+    else
+	{
+	errAbort("missing 'from' clause in %s\n", rql->command);
+	}
+    }
+
+/* Parse where clause. */
+char *where = tokenizerNext(tkz);
+if (where != NULL)
+    {
+    if (!sameString(where, "where"))
+	{
+        tokenizerReuse(tkz);
+	}
+    else
+        {
+	rql->whereClause = rqlParseExpression(tkz);
+	rqlParseVarsUsed(rql->whereClause, &rql->whereVarList);
+	}
+    }
+
+/* Parse limit clause. */
+char *limit = tokenizerNext(tkz);
+rql->limit = -1;	
+if (limit != NULL)
+    {
+    if (!sameString(limit, "limit"))
+        errAbort("Unknown clause '%s' line %d of %s", limit, lf->lineIx, lf->fileName);
+    char *count = tokenizerMustHaveNext(tkz);
+    if (!isdigit(count[0]))
+       errAbort("Expecting number after limit, got %s line %d of %s", 
+       	count, lf->lineIx, lf->fileName);
+    rql->limit = atoi(count);
+    }
+
+/* Check that are at end of statement. */
+char *extra = tokenizerNext(tkz);
+if (extra != NULL)
+    errAbort("Extra stuff starting with '%s' past end of statement line %d of %s", 
+    	extra, lf->lineIx, lf->fileName);
+return rql;
+}
+
+void rqlStatementDump(struct rqlStatement *rql, FILE *f)
+/* Print out statement to file. */
+{
+fprintf(f, "%s:", rql->command);
+if (rql->fieldList)
+    {
+    fprintf(f, " ");
+    struct slName *field = rql->fieldList;
+    fprintf(f, "%s", field->name);
+    for (field = field->next; field != NULL; field = field->next)
+        fprintf(f, ",%s", field->name);
+    }
+fprintf(f, "\n");
+if (rql->tableList)
+    {
+    fprintf(f, "from: ");
+    struct slName *table = rql->tableList;
+    fprintf(f, "%s", table->name);
+    for (table = table->next; table != NULL; table = table->next)
+        fprintf(f, ",%s", table->name);
+    fprintf(f, "\n");
+    }
+if (rql->whereClause)
+    {
+    fprintf(f, " where:\n");
+    rqlParseDump(rql->whereClause, 0, f);
+    }
+if (rql->limit >= 0)
+    fprintf(f, "limit: %d\n", rql->limit);
+}
+
+static void rqlParseFreeRecursive(struct rqlParse *p)
+/* Depth-first recursive free. */
+{
+struct rqlParse *child, *next;
+for (child = p->children; child != NULL; child = next)
+    {
+    next = child->next;
+    rqlParseFreeRecursive(child);
+    }
+freeMem(p);
+}
+
+void rqlStatementFree(struct rqlStatement **pRql)
+/* Free up an rql statement. */
+{
+struct rqlStatement *rql = *pRql;
+if (rql != NULL)
+    {
+    freeMem(rql->command);
+    slFreeList(&rql->fieldList);
+    slFreeList(&rql->tableList);
+    if (rql->whereClause !=NULL)
+	rqlParseFreeRecursive(rql->whereClause);
+    slFreeList(&rql->whereVarList);
+    freez(pRql);
+    }
+}
+
diff --git a/lib/rudp.c b/lib/rudp.c
new file mode 100644
index 0000000..4904b91
--- /dev/null
+++ b/lib/rudp.c
@@ -0,0 +1,560 @@
+/* rudp - (semi) reliable UDP communication.  This adds an
+ * acknowledgement and resend layer on top of UDP. 
+ *
+ * UDP is a packet based rather than stream based internet communication 
+ * protocol. Messages sent by UDP are checked for integrety by the UDP layer, 
+ * and discarded if transmission errors are detected.  However packets are
+ * not necessarily received in the same order that they are sent,
+ * and packets may be duplicated or lost.  
+ 
+ * Using rudp packets are only very rarely lost, and the sender is 
+ * notified if they are.  After rudp there are still duplicate
+ * packets that may arrive out of order.  Aside from the duplicates
+ * the packets are in order though.
+ *
+ * For many, perhaps most applications, TCP/IP is a saner choice
+ * than UDP or rudp.  If the communication channel is between just 
+ * two computers you can pretty much just treat TCP/IP as a fairly
+ * reliable pipe.   However if the communication involves many
+ * computers sometimes UDP can be a better choice.  It is possible to
+ * do broadcast and multicast with UDP but not with TCP/IP.  Also
+ * for systems like parasol, where a server may be making and breaking
+ * connections rapidly to thousands of computers, TCP paradoxically
+ * can end up less reliable than UDP.  Though TCP is relatively 
+ * robust when a connection is made,  it can relatively easily fail
+ * to make a connection in the first place, and spend quite a long
+ * time figuring out that the connection can't be made.  Moreover at
+ * the end of each connection TCP goes into a 'TIMED_WAIT' state,  which
+ * prevents another connection from coming onto the same port for a
+ * time that can be as long as 255 seconds.  Since there are only
+ * about 15000 available ports,  this limits TCP/IP to 60 connections
+ * per second in some cases.  Generally the system does not handle
+ * running out of ports gracefully, and this did occur with the 
+ * TCP/IP based version of Parasol.
+ *
+ * This module puts a thin layer around UDP to make it a little bit more
+ * reliable.  Currently the interface is geared towards Parasol rather
+ * than broadcast type applications.  This module will try to send
+ * a message a limited number of times before giving up.  It puts
+ * a small header containing a message ID and timestamp on each message.   
+ * This header is echoed back in acknowledgment by the reciever. This
+ * echo lets the sender know if it needs to resend the message, and
+ * lets it know how long a message takes to get to the destination and
+ * back.  It uses this round trip time information to figure out how
+ * long to wait between resends. 
+ *
+ * Much of this code is based on the 'Adding Reliability to a UDP Application
+ * section in volume I, chapter 20, section 5, of _UNIX Network Programming_
+ * by W. Richard Stevens. */
+
+
+#include "common.h"
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include "errabort.h"
+#include "hash.h"
+#include "dlist.h"
+#include "obscure.h"
+#include "rudp.h"
+
+
+#define MAX_TIME_OUT 999999
+
+static int rudpCalcTimeOut(struct rudp *ru)
+/* Return calculation of time out based on current data. */
+{
+int timeOut = ru->rttAve + (ru->rttVary<<2);
+if (timeOut > MAX_TIME_OUT) timeOut = MAX_TIME_OUT; /* No more than a second. */
+if (timeOut < 10000) timeOut = 10000;	/* No less than 1/100th second */
+return timeOut;
+}
+
+static void rudpAddRoundTripTime(struct rudp *ru, int time)
+/* Add info about round trip time and based on this recalculate
+ * time outs. */
+{
+int delta;
+ru->rttLast = time;
+delta = time - ru->rttAve;
+ru->rttAve += (delta>>3);		      /* g = 1/8 */
+if (delta < 0) delta = -delta;
+ru->rttVary += ((delta - ru->rttVary) >> 2);  /* h = 1/4 */
+ru->timeOut = rudpCalcTimeOut(ru);
+}
+
+static void rudpTimedOut(struct rudp *ru)
+/* Tell system about a time-out. */
+{
+ru->timeOut <<=  1;   /* Back off exponentially. */
+if (ru->timeOut >= MAX_TIME_OUT)
+    ru->timeOut = MAX_TIME_OUT;
+}
+
+struct rudp *rudpNew(int socket)
+/* Wrap a rudp around a socket. Call rudpFree when done, or
+ * rudpClose if you also want to close(socket). */
+{
+/* Note scope of variable and mutex are the same */
+static pthread_mutex_t rudpConnMutex = PTHREAD_MUTEX_INITIALIZER;
+static int nextRudpConnId=0;
+struct rudp *ru;
+assert(socket >= 0);
+AllocVar(ru);
+ru->socket = socket;
+ru->rttVary = 250;	/* Initial variance 250 microseconds. */
+ru->timeOut = rudpCalcTimeOut(ru);
+ru->maxRetries = 7;
+ru->pid = getpid();
+pthread_mutex_lock( &rudpConnMutex );
+ru->connId = ++nextRudpConnId;
+pthread_mutex_unlock( &rudpConnMutex );
+return ru;
+}
+
+void freePacketSeen(struct packetSeen **pP)
+/* Free packet seen */
+{
+freez(pP);
+}
+
+void rudpFree(struct rudp **pRu)
+/* Free up rudp.  Note this does *not* close the associated socket. */
+{
+struct rudp *ru = *pRu;
+if (ru->recvHash)
+    {
+    struct dlNode *node;
+    while (!dlEmpty(ru->recvList))
+	{
+	node = dlPopHead(ru->recvList);
+	struct packetSeen *p = node->val;
+	freeMem(node);
+	hashRemove(ru->recvHash, p->recvHashKey);
+    	freePacketSeen(&p);
+	}
+    freeDlList(&ru->recvList);
+    hashFree(&ru->recvHash);
+    }
+freez(pRu);
+}
+
+struct rudp *rudpOpen()
+/* Open up an unbound rudp.   This is suitable for
+ * writing to and for reading responses.  However 
+ * you'll want to rudpBind if you want to listen for
+ * incoming messages.   Call rudpClose() when done 
+ * with this one.  Warns and returns NULL if there is
+ * a problem. */
+{
+int sd = socket(AF_INET,  SOCK_DGRAM, IPPROTO_UDP);
+if (sd < 0)
+    {
+    warn("Couldn't open socket in rudpOpen %s", strerror(errno));
+    return NULL;
+    }
+return rudpNew(sd);
+}
+
+struct rudp *rudpMustOpen()
+/* Open up unbound rudp.  Warn and die if there is a problem. */
+{
+struct rudp *ru = rudpOpen();
+if (ru == NULL)
+    noWarnAbort();
+return ru;
+}
+
+struct rudp *rudpOpenBound(struct sockaddr_in *sai)
+/* Open up a rudp socket bound to a particular port and address.
+ * Use this rather than rudpOpen if you want to wait for
+ * messages at a specific address in a server or the like. */
+{
+struct rudp *ru = rudpOpen();
+if (ru != NULL)
+    {
+    if (bind(ru->socket, (struct sockaddr *)sai, sizeof(*sai)) < 0)
+	{
+	warn("Couldn't bind rudp socket: %s", strerror(errno));
+	rudpClose(&ru);
+	}
+    }
+return ru;
+}
+
+struct rudp *rudpMustOpenBound(struct sockaddr_in *sai)
+/* Open up a rudp socket bound to a particular port and address
+ * or die trying. */
+{
+struct rudp *ru = rudpOpenBound(sai);
+if (ru == NULL)
+    noWarnAbort();
+return ru;
+}
+
+void rudpClose(struct rudp **pRu)
+/* Close socket and free memory. */
+{
+struct rudp *ru = *pRu;
+if (ru != NULL)
+    {
+    close(ru->socket);
+    rudpFree(pRu);
+    }
+}
+
+static int timeDiff(struct timeval *t1, struct timeval *t2)
+/* Return difference in microseconds between t1 and t2.  t2 must be
+ * later than t1 (but less than 50 minutes later). */
+{
+int secDiff = t2->tv_sec - t1->tv_sec;
+int microDiff = 0;
+if (secDiff != 0)
+    microDiff = secDiff * 1000000;
+microDiff += (t2->tv_usec - t1->tv_usec);
+if (microDiff < 0)
+    {
+    /* Note, this case actually happens, currently particularly on
+     * kkr2u62 and kkr8u19.  I think this is just a bug in their clock
+     * hardware/software.  However in general it _could_ happen very
+     * rarely on normal machines when the clock is reset by the
+     * network time protocol thingie. */
+    warn("t1 %u.%u, t2 %u.%u.  t1 > t2 but later?!", (unsigned)t1->tv_sec,
+         (unsigned)t1->tv_usec, (unsigned)t2->tv_sec, (unsigned)t2->tv_usec);
+    microDiff = 0;
+    }
+return microDiff;
+}
+
+static boolean readReadyWait(int sd, int microseconds)
+/* Wait for descriptor to have some data to read, up to
+ * given number of microseconds. */
+{
+struct timeval tv;
+fd_set set;
+int readyCount;
+
+for (;;)
+    {
+    if (microseconds >= 1000000)
+	{
+	tv.tv_sec = microseconds/1000000;
+	tv.tv_usec = microseconds%1000000;
+	}
+    else
+	{
+	tv.tv_sec = 0;
+	tv.tv_usec = microseconds;
+	}
+    FD_ZERO(&set);
+    FD_SET(sd, &set);
+    readyCount = select(sd+1, &set, NULL, NULL, &tv);
+    if (readyCount < 0) 
+	{
+	if (errno == EINTR)	/* Select interrupted, not timed out. */
+	    continue;
+    	else 
+    	    warn("select failure in rudp: %s", strerror(errno));
+    	}
+    else
+	{
+    	return readyCount > 0;	/* Zero readyCount indicates time out */
+	}
+    }
+}
+
+static boolean getOurAck(struct rudp *ru, struct timeval *startTv, struct sockaddr_in *sai)
+/* Wait for acknowledgement to the message we just sent.
+ * The set should be zeroed out. Only wait for up to
+ * ru->timeOut microseconds.   Prints a message and returns FALSE
+ * if there's a problem.   */
+{
+struct rudpHeader head;
+int readSize;
+int timeOut = ru->timeOut;
+struct sockaddr_in retFrom;
+unsigned int retFromSize = sizeof(retFrom);
+
+for (;;)
+    {
+    /* Set up select with our time out. */
+    int dt;
+    struct timeval tv;
+
+    if (readReadyWait(ru->socket, timeOut))
+	{
+	/* Read message and if it's our ack return true.   */
+	readSize = recvfrom(ru->socket, &head, sizeof(head), 0, 
+		    (struct sockaddr*)&retFrom, &retFromSize);
+	if (readSize >= sizeof(head) && head.type == rudpAck && head.id == ru->lastId)
+	    {
+	    if ((sai->sin_addr.s_addr==retFrom.sin_addr.s_addr) &&
+		(sai->sin_port==retFrom.sin_port))
+		{
+		gettimeofday(&tv, NULL);
+		dt = timeDiff(startTv, &tv);
+		rudpAddRoundTripTime(ru, dt);
+		return TRUE;
+		}
+	    else
+		{
+		char retFromDottedQuad[17];
+		char saiDottedQuad[17];
+		internetIpToDottedQuad(ntohl(retFrom.sin_addr.s_addr), retFromDottedQuad);
+		internetIpToDottedQuad(ntohl(sai->sin_addr.s_addr), saiDottedQuad);
+		warn("rudp: discarding mistaken ack from %s:%d by confirming recipient ip:port %s:%d"
+		    , retFromDottedQuad, retFrom.sin_port
+		    , saiDottedQuad, sai->sin_port
+		    );
+		}
+	    }
+	}
+
+    /* If we got to here then we did get a message, but it's not our
+     * ack.  We ignore the message and loop around again,  but update
+     * our timeout so that we won't keep getting other people's messages
+     * forever. */
+    gettimeofday(&tv, NULL);
+    timeOut = ru->timeOut - timeDiff(startTv, &tv);
+    if (timeOut <= 0)
+	return FALSE;
+    }
+}
+
+int rudpSend(struct rudp *ru, struct sockaddr_in *sai, void *message, int size)
+/* Send message of given size to port at host via rudp.  Prints a warning and
+ * sets errno and returns -1 if there's a problem. */
+{
+struct timeval sendTv;	/* Current time. */
+
+char outBuf[udpEthMaxSize];
+struct rudpHeader *head;
+int fullSize = size + sizeof(*head);
+int i, err = 0, maxRetry = ru->maxRetries;
+
+
+/* Make buffer with header in front of message. 
+ * At some point we might replace this with a scatter/gather
+ * iovector. */
+ru->sendCount += 1;
+ru->resend = FALSE;
+assert(size <= rudpMaxSize);
+head = (struct rudpHeader *)outBuf;
+memcpy(head+1, message, size);
+head->pid = ru->pid;
+head->connId = ru->connId;
+head->id = ++ru->lastId;
+head->type = rudpData;
+
+/* Go into send/wait for ack/retry loop. */
+for (i=0; i<maxRetry; ++i)
+    {
+    gettimeofday(&sendTv, NULL);
+    head->sendSec = sendTv.tv_sec;
+    head->sendMicro = sendTv.tv_usec;
+    err =  sendto(ru->socket, outBuf, fullSize, 0, 
+	(struct sockaddr *)sai, sizeof(*sai));
+    if (err < 0) 
+	{
+	/* Warn, wait, and retry. */
+	struct timeval tv;
+	warn("sendto problem %s", strerror(errno));
+	tv.tv_sec = 0;
+	tv.tv_usec = ru->timeOut;
+	select(0, NULL, NULL, NULL, &tv);
+	rudpTimedOut(ru);
+	ru->resendCount += 1;
+	ru->resend = TRUE;
+	continue;
+	}
+    if (getOurAck(ru, &sendTv, sai))
+	{
+	return 0;
+	}
+    rudpTimedOut(ru);
+    ru->resendCount += 1;
+    ru->resend = TRUE;
+    }
+if (err >= 0)
+    {
+    err = ETIMEDOUT;
+    warn("rudpSend timed out");
+    }
+ru->failCount += 1;
+return err;
+}
+
+void sweepOutOldPacketsSeen(struct rudp *ru, long now)
+/* Sweep out old packets seen, we can only remember so many. */
+{
+int period = 8;  /* seconds */
+struct dlNode *node;
+struct packetSeen *p;
+while (TRUE)
+    {
+    if (dlEmpty(ru->recvList))
+        break;
+    p = ru->recvList->head->val;
+    if (now - p->lastChecked < period)
+        break;
+    --ru->recvCount;
+    node = dlPopHead(ru->recvList);
+    freeMem(node);
+    hashRemove(ru->recvHash, p->recvHashKey);
+    freePacketSeen(&p);
+    }
+}
+
+
+int rudpReceiveTimeOut(struct rudp *ru, void *messageBuf, int bufSize, 
+	struct sockaddr_in *retFrom, int timeOut)
+/* Read message into buffer of given size.  Returns actual size read on
+ * success. On failure prints a warning, sets errno, and returns -1. 
+ * Also returns ip address of message source. If timeOut is nonzero,
+ * it represents the timeout in milliseconds.  It will set errno to
+ * ETIMEDOUT in this case.*/
+{
+char inBuf[udpEthMaxSize];
+struct rudpHeader *head = (struct rudpHeader *)inBuf;
+struct rudpHeader ackHead;
+struct sockaddr_in sai;
+socklen_t saiSize = sizeof(sai);
+int readSize, err;
+assert(bufSize <= rudpMaxSize);
+ru->receiveCount += 1;
+for (;;)
+    {
+    if (timeOut != 0)
+	{
+	if (!readReadyWait(ru->socket, timeOut))
+	    {
+	    warn("rudpReceive timed out\n");
+	    errno = ETIMEDOUT;
+	    return -1;
+	    }
+	}
+    readSize = recvfrom(ru->socket, inBuf, sizeof(inBuf), 0, 
+	(struct sockaddr*)&sai, &saiSize);
+    if (retFrom != NULL)
+	*retFrom = sai;
+    if (readSize < 0)
+	{
+	if (errno == EINTR)
+	    continue;
+	warn("recvfrom error: %s", strerror(errno));
+	ru->failCount += 1;
+	return readSize;
+	}
+    if (readSize < sizeof(*head))
+	{
+	warn("rudpRecieve truncated message");
+	continue;
+	}
+    if (head->type != rudpData)
+	{
+	if (head->type != rudpAck)
+	    warn("skipping non-data message %d in rudpReceive", head->type);
+	continue;
+	}
+    ackHead = *head;
+    ackHead.type = rudpAck;
+    err = sendto(ru->socket, &ackHead, sizeof(ackHead), 0, 
+	(struct sockaddr *)&sai, sizeof(sai));
+    if (err < 0)
+	{
+	warn("problem sending ack in rudpRecieve: %s", strerror(errno));
+	}
+    readSize -= sizeof(*head);
+    if (readSize > bufSize)
+	{
+	warn("read more bytes than have room for in rudpReceive");
+	readSize = bufSize;
+	}
+    memcpy(messageBuf, head+1, readSize);
+
+    /* check for duplicate packet */
+    if (!ru->recvHash)
+	{ /* take advantage of new auto-expanding hashes */
+	ru->recvHash = newHashExt(4, FALSE);  /* do not use local mem in hash */
+	ru->recvList = newDlList();
+	ru->recvCount = 0;
+	}
+    char hashKey[64];
+    char saiDottedQuad[17];
+    internetIpToDottedQuad(ntohl(sai.sin_addr.s_addr), saiDottedQuad);
+    safef(hashKey, sizeof(hashKey), "%s-%d-%d-%d" 
+    	, saiDottedQuad 
+        , head->pid              
+        , head->connId
+        , head->id
+      );		    
+    if (hashLookup(ru->recvHash, hashKey))
+	{
+	warn("duplicate packet filtered out: %s", hashKey);
+	continue;
+	}
+    long now = time(NULL);
+    struct packetSeen *p;
+    AllocVar(p);
+    AllocVar(p->node);
+    p->node->val = p;
+    p->recvHashKey = hashStoreName(ru->recvHash, hashKey);
+    p->lastChecked = now;
+    dlAddTail(ru->recvList, p->node);
+    ++ru->recvCount;
+   
+    sweepOutOldPacketsSeen(ru, now);
+
+    ru->lastIdReceived = head->id;
+    break;
+    }
+return readSize;
+}
+
+
+int rudpReceiveFrom(struct rudp *ru, void *messageBuf, int bufSize, 
+	struct sockaddr_in *retFrom)
+/* Read message into buffer of given size.  Returns actual size read on
+ * success. On failure prints a warning, sets errno, and returns -1. 
+ * Also returns ip address of message source. */
+{
+return rudpReceiveTimeOut(ru, messageBuf, bufSize, retFrom, 0);
+}
+
+int rudpReceive(struct rudp *ru, void *messageBuf, int bufSize)
+/* Read message into buffer of given size.  Returns actual size read on
+ * success. On failure prints a warning, sets errno, and returns -1. */
+{
+return rudpReceiveFrom(ru, messageBuf, bufSize, NULL);
+}
+
+void rudpPrintStatus(struct rudp *ru)
+/* Print out rudpStatus */
+{
+printf("rudp status:\n");
+printf("  receiveCount %d\n", ru->receiveCount);
+printf("  sendCount %d\n", ru->sendCount);
+printf("  resendCount %d\n", ru->resendCount);
+printf("  failCount %d\n", ru->failCount);
+printf("  timeOut %d\n", ru->timeOut);
+printf("  rttVary %d\n", ru->rttVary);
+printf("  rttAve %d\n", ru->rttAve);
+printf("  rttLast %d\n", ru->rttLast);
+}
+
+void rudpTest()
+/* Test out rudp stuff. */
+{
+static int times[] = {1000, 200, 200, 100, 200, 200, 200, 400, 200, 200, 200, 200, 1000, 
+	200, 200, 200, 200};
+struct rudp *ru = rudpNew(0);
+int i;
+
+for (i=0; i<ArraySize(times); ++i)
+    {
+    int oldTimeOut = ru->timeOut;
+    rudpAddRoundTripTime(ru, times[i]);
+    printf("%d\t%d\t%d\t%d\n", i, oldTimeOut, times[i], ru->timeOut);
+    }
+}
diff --git a/lib/scoreWindow.c b/lib/scoreWindow.c
new file mode 100644
index 0000000..83faf6d
--- /dev/null
+++ b/lib/scoreWindow.c
@@ -0,0 +1,47 @@
+/* scoreWindow - find window with most matches to a given char */
+#include "common.h"
+
+
+int scoreWindow(char c, char *s, int size, int *score, int *start, int *end, int match, int misMatch)
+/* simple program to find max scoring window representing string of char c in a string s of size size */
+/* index of max score is returned , match and misMatch are the scores to assign, suggested defaults are match=1 and misMatch=1*/
+/* when used for scoring polyA tails, set c='A' for positive strand  or c='T' for neg strand */
+/* start, end are returned pointing to the start and end of the highest scoring window in s */
+{
+int i=0, j=0, max=0, count = 0; 
+
+*end = 0;
+
+for (i=0 ; i<size ; i++)
+    {
+    int prevScore = (i > 0) ? score[i-1] : 0;
+
+    if (toupper(s[i]) == toupper(c) )
+        score[i] = prevScore+match;
+    else
+        score[i] = prevScore-misMatch;
+    if (score[i] >= max)
+        {
+        max = score[i];
+        *end = i;
+        /* traceback to find start */
+        for (j=i ; j>=0 ; j--)
+            if (score[j] == 0)
+                {
+                *start = j+1;
+                break;
+                }
+        }
+    if (score[i] < 0) 
+        score[i] = 0;
+    }
+assert (*end < size);
+
+for (i=*start ; i<=*end ; i++)
+    {
+    assert (i < size);
+    if (toupper(s[i]) == toupper(c) )
+        count++;
+    }
+return count;
+}
diff --git a/lib/seg.c b/lib/seg.c
new file mode 100644
index 0000000..49997fa
--- /dev/null
+++ b/lib/seg.c
@@ -0,0 +1,472 @@
+/* seg.c - read/write seg format. */
+#include "common.h"
+#include "linefile.h"
+#include "errabort.h"
+#include "obscure.h"
+#include "seg.h"
+#include "hash.h"
+#include <fcntl.h>
+
+
+
+
+void segCompFree(struct segComp **pObj)
+/* Free up a segment component. */
+{
+struct segComp *obj = *pObj;
+if (obj == NULL)
+	return;
+freeMem(obj->src);
+freez(pObj);
+}
+
+
+void segCompFreeList(struct segComp **pList)
+/* Free up a list of segment components. */
+{
+struct segComp *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+	{
+	next = el->next;
+	segCompFree(&el);
+	}
+*pList = NULL;
+}
+
+
+void segBlockFree(struct segBlock **pObj)
+/* Free up a segment block. */
+{
+struct segBlock *obj = *pObj;
+if (obj == NULL)
+	return;
+freeMem(obj->name);
+segCompFreeList(&obj->components);
+freez(pObj);
+}
+
+
+void segBlockFreeList(struct segBlock **pList)
+/* Free up a list of segment blocks. */
+{
+struct segBlock *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+	{
+	next = el->next;
+	segBlockFree(&el);
+	}
+*pList = NULL;
+}
+
+
+void segFileFree(struct segFile **pObj)
+/* Free up a segment file including closing file handle if necessary. */
+{
+struct segFile *obj = *pObj;
+if (obj == NULL)
+	return;
+segBlockFreeList(&obj->blocks);
+lineFileClose(&obj->lf);
+freez(pObj);
+}
+
+
+void segFileFreeList(struct segFile **pList)
+/* Free up a list of segment files. */
+{
+struct segFile *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+	{
+	next = el->next;
+	segFileFree(&el);
+	}
+*pList = NULL;
+}
+
+
+struct segFile *segMayOpen(char *fileName)
+/* Open up a segment file for reading. Read header and verify. Prepare
+ * for subsequent calls to segNext(). Return NULL if file does not exist. */
+{
+struct segFile *sf;
+struct lineFile *lf;
+char *line, *name, *val, *word;
+char *sig = "##seg";
+
+/* Open fileName. */
+if ((lf = lineFileMayOpen(fileName, TRUE)) == NULL)
+	return NULL;
+AllocVar(sf);
+sf->lf = lf;
+
+/* Check for a valid signature. */
+lineFileNeedNext(lf, &line, NULL);
+if (!startsWith(sig, line))
+	errAbort("%s does not start with %s", fileName, sig);
+line += strlen(sig);
+
+/* parse name=val. */
+while ((word = nextWord(&line)) != NULL)
+	{
+	name = word;
+	val = strchr(word, '=');
+	if (val == NULL)
+		errAbort("Missing = after %s line 1 of %s", name, fileName);
+	*val++ = 0;
+
+	if (sameString(name, "version"))
+		sf->version = atoi(val);
+	}
+
+if (sf->version == 0)
+	errAbort("No version line 1 of %s", fileName);
+
+return sf;
+}
+
+
+struct segFile *segOpen(char *fileName)
+/* Like segMayOpen() above, but prints an error message and aborts if
+ * there is a problem. */
+{
+struct segFile *sf = segMayOpen(fileName);
+if (sf == NULL)
+	errnoAbort("Couldn't open %s", fileName);
+return sf;
+}
+
+
+void segRewind(struct segFile *sf)
+/* Seek to beginning of open segment file */
+{
+if (sf == NULL)
+	errAbort("segment file rewind failed -- file not open");
+lineFileSeek(sf->lf, 0, SEEK_SET);
+}
+
+static boolean nextLine(struct lineFile *lf, char **pLine)
+/* Get next line that is not a comment. */
+{
+for (;;)
+	{
+	if (!lineFileNext(lf, pLine, NULL))
+		return FALSE;
+	if (**pLine != '#')
+		return TRUE;
+	}
+}
+
+
+struct segBlock *segNextWithPos(struct segFile *sf, off_t *retOffset)
+/* Return next segment in segment file or NULL if at end. If retOffset
+ * is not NULL, return start offset of record in file. */
+{
+struct lineFile *lf = sf->lf;
+struct segBlock *block;
+struct segComp *comp, *tail = NULL;
+char *line, *name, *row[6], *val, *word;
+int wordCount;
+
+/* Loop until we get a segment paragraph or reach end of file. */
+for (;;)
+	{
+	/* Get segment header line. If it's not there assume end of file. */
+	if (!nextLine(lf, &line))
+		{
+		lineFileClose(&sf->lf);
+		return NULL;
+		}
+
+	/* Parse segment header line. */
+	word = nextWord(&line);
+	if (word == NULL)
+		continue;	/* Ignore blank lines. */
+
+	if (sameString(word, "b"))
+		{
+		if (retOffset != NULL)
+			*retOffset = lineFileTell(sf->lf);
+		AllocVar(block);
+		/* Parse name=val. */
+		while ((word = nextWord(&line)) != NULL)
+			{
+			name = word;
+			val = strchr(word, '=');
+			if (val == NULL)
+				errAbort("Missing = after %s line %d of %s",
+					name, lf->lineIx, lf->fileName);
+			*val++ = 0;
+
+			if (sameString(name, "name"))
+				block->name = cloneString(val);
+			else if (sameString(name, "val"))
+				block->val = atoi(val);
+			}
+
+		/* Parse segment components until blank line. */
+		for (;;)
+			{
+			if (!nextLine(lf, &line))
+				errAbort("Unexpected end of file %s", lf->fileName);
+			word = nextWord(&line);
+			if (word == NULL)
+				break;
+			if (sameString(word, "s"))
+				{
+				/* Chop line up by white space. This involves a few +=1's
+				 * because we have already chopped out the first word. */
+				row[0] = word;
+				wordCount = chopByWhite(line, row+1, ArraySize(row)-1) +1;
+				lineFileExpectWords(lf, ArraySize(row), wordCount);
+				AllocVar(comp);
+
+				/* Convert ASCII text representation to segComp structure. */
+				comp->src     = cloneString(row[1]);
+				comp->start   = lineFileNeedNum(lf, row, 2);
+				comp->size    = lineFileNeedNum(lf, row, 3);
+				comp->strand  = row[4][0];
+				comp->srcSize = lineFileNeedNum(lf, row, 5);
+
+				/* Do some sanity checking. */
+				if (comp->size <= 0 || comp->srcSize <= 0)
+					errAbort("Got a negative or zero size line %d of %s",
+						lf->lineIx, lf->fileName);
+				if (comp->start < 0 || comp->start + comp->size > comp->srcSize)
+					errAbort("Coordinates out of range line %d of %s",
+						lf->lineIx, lf->fileName);
+				if (comp->strand != '+' && comp->strand != '-')
+					errAbort("Invalid strand line %d of %s",
+						lf->lineIx, lf->fileName);
+
+				/* Add the new component to the current list. */
+				if (block->components == NULL)
+					block->components = comp;
+				else
+					tail->next = comp;
+				tail = comp;
+				}
+			}
+		return block;
+		}
+		else	/* Skip over paragraph we don't understand. */
+		{
+		for (;;)
+			{
+			if (!nextLine(lf, &line))
+				return NULL;
+			if (nextWord(&line) == NULL)
+				break;
+			}
+		}
+	}
+}
+
+
+struct segBlock *segNext(struct segFile *sf)
+/* Return next segment in segment file or NULL if at end.  This will
+ * close the open file handle at the end as well. */
+{
+return segNextWithPos(sf, NULL);
+}
+
+
+struct segFile *segReadAll(char *fileName)
+/* Read in full segment file */
+{
+struct segFile *sf = segOpen(fileName);
+struct segBlock *block, *tail = NULL;
+while ((block = segNext(sf)) != NULL)
+	{
+	if (sf->blocks == NULL)
+		sf->blocks = block;
+	else
+		{
+		tail->next = block;
+		block->prev = tail;
+		}
+	tail = block;
+	}
+return sf;
+}
+
+
+void segWriteStart(FILE *f)
+/* Write segment file header to the file. */
+{
+fprintf(f, "##seg version=1\n");
+}
+
+
+void segWrite(FILE *f, struct segBlock *block)
+/* Write next segment block to the file. */
+{
+struct segComp *comp;
+int srcChars = 0, startChars = 0, sizeChars = 0, srcSizeChars = 0;
+
+/* Write segment block header. */
+fprintf(f, "b");
+if (block->name != NULL)
+	fprintf(f, " name=%s", block->name);
+if (block->val != 0)
+	fprintf(f, " val=%d", block->val);
+fprintf(f, "\n");
+
+/* Figure out length of each field. */
+for (comp = block->components; comp != NULL; comp = comp->next)
+	{
+	int len = 0;
+	/* A name line '.' will break some tools, so replace it with a
+	 * generic name */
+	if (sameString(comp->src, "."))
+		{
+		freeMem(&comp->src);
+		comp->src = cloneString("defaultName");
+		}
+	len = strlen(comp->src);
+	if (srcChars < len)
+		srcChars = len;
+	len = digitsBaseTen(comp->start);
+	if (startChars < len)
+		startChars = len;
+	len = digitsBaseTen(comp->size);
+	if (sizeChars < len)
+		sizeChars = len;
+	len = digitsBaseTen(comp->srcSize);
+	if (srcSizeChars < len)
+		srcSizeChars = len;
+	}
+
+/* Write out each component. */
+for (comp = block->components; comp != NULL; comp = comp->next)
+	{
+	fprintf(f, "s %-*s %*d %*d %c %*d\n",
+		srcChars, comp->src, startChars, comp->start, sizeChars, comp->size,
+		comp->strand, srcSizeChars, comp->srcSize);
+	}
+
+/* Write out blank separator line. */
+fprintf(f, "\n");
+}
+
+
+void segWriteEnd(FILE *f)
+/* Write segment file end tag to the file.  In this case, nothing. */
+{
+}
+
+struct segComp *segMayFindCompSpecies(struct segBlock *sb, char *src,
+	char sepChar)
+/* Find component with a source that matches src up to and possibly
+   including sepChar. Return NULL if not found. */
+{
+struct segComp *sc;
+char *p, *q;
+
+for (sc = sb->components; sc != NULL; sc = sc->next)
+	{
+	for (p = sc->src, q = src;
+		 *p != '\0' && *p != sepChar && *q != '\0' && *q != sepChar;
+		 p++, q++)
+		{
+		if (*p != *q)
+			break;
+		}
+
+	if ((*p == *q)
+		|| (*p == sepChar && *q == '\0')
+		|| (*p == '\0' && *q == sepChar))
+		{
+		return(sc);
+		}
+	}
+
+return(NULL);
+}
+
+
+struct segComp *segFindCompSpecies(struct segBlock *sb, char *src,
+	char sepChar)
+/* Find component with a source that matches src up to and possibly
+   including sepChar or die trying. */
+{
+struct segComp *sc = segMayFindCompSpecies(sb, src, sepChar);
+char *p;
+
+if (sc == NULL)
+	{
+	if ((p = strchr(src, sepChar)) != NULL)
+		*p = '\0';
+
+	errAbort("Couldn't find %s%c or just %s... in block.", src, sepChar, src);
+	}
+
+return(sc);
+}
+
+struct segComp *cloneSegComp(struct segComp *sc)
+/* Return a copy of the argument segment component. */
+{
+struct segComp *newSc;
+
+AllocVar(newSc);
+
+newSc->next    = sc->next;
+newSc->src     = cloneString(sc->src);
+newSc->start   = sc->start;
+newSc->size    = sc->size;
+newSc->strand  = sc->strand;
+newSc->srcSize = sc->srcSize;
+
+return(newSc);
+}
+
+char *segFirstCompSpecies(struct segBlock *sb, char sepChar)
+/* Return the species possibly followed by sepChar of the first component
+   of the argument block. Return NULL if the block has no components. */
+{
+char *p, *species;
+
+if (sb->components == NULL)
+	return(NULL);
+
+/* Temporarily split src into species and chrom. */
+if ((p = strchr(sb->components->src, sepChar)) != NULL)
+	*p = '\0';
+
+species = cloneString(sb->components->src);
+
+/* Restore src. */
+if (p != NULL)
+	*p = sepChar;
+
+return(species);
+}
+
+struct slName *segSecSpeciesList(struct segBlock *sb, struct segComp *refComp,
+    char sepChar)
+/* Return a name list containing the species possibly followed by sepChar
+of all components other than refComp on the block. */
+{
+struct segComp *sc;
+char *p;
+struct slName *speciesList = NULL;
+
+for (sc = sb->components; sc != NULL; sc = sc->next)
+	{
+	if (sc == refComp)
+		continue;
+
+	if ((p = strchr(sc->src, '.')) != NULL)
+		*p = '\0';
+
+	slNameStore(&speciesList, sc->src);
+
+	if (p != NULL)
+		*p = '.';
+	}
+
+return(speciesList);
+}
diff --git a/lib/seqOut.c b/lib/seqOut.c
new file mode 100644
index 0000000..1a44eed
--- /dev/null
+++ b/lib/seqOut.c
@@ -0,0 +1,330 @@
+/* seqOut - stuff to output sequences and alignments in web
+ * or ascii viewable form.
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "obscure.h"
+#include "dnautil.h"
+#include "fuzzyFind.h"
+#include "seqOut.h"
+#include "htmshell.h"
+#include "axt.h"
+
+
+struct cfm *cfmNew(int wordLen, int lineLen,
+	boolean lineNumbers, boolean countDown, FILE *out, int numOff)
+/* Set up colored sequence formatting for html. */
+{
+struct cfm *cfm;
+AllocVar(cfm);
+cfm->inWord = cfm->inLine = cfm->charCount = 0;
+cfm->color = 0;
+cfm->wordLen = wordLen;
+cfm->lineLen = lineLen;
+cfm->lineNumbers = lineNumbers;
+cfm->countDown = countDown;
+cfm->out = out;
+cfm->numOff = numOff;
+cfm->bold = cfm->underline = cfm->italic = FALSE;
+return cfm;
+}
+
+static void cfmPopFormat(struct cfm *cfm)
+/* Restore format to default. */
+{
+if (cfm->color != 0)
+    fprintf(cfm->out, "</span>");
+if (cfm->underline)
+    fprintf(cfm->out, "</span>");
+if (cfm->bold)
+  fprintf(cfm->out, "</B>");
+if (cfm->italic)
+  fprintf(cfm->out, "</I>");
+}
+
+static void cfmPushFormat(struct cfm *cfm)
+/* Set format. */
+{
+if (cfm->italic)
+  fprintf(cfm->out, "<I>");
+if (cfm->bold)
+  fprintf(cfm->out, "<B>");
+if (cfm->underline)
+    fprintf(cfm->out, "<span style='text-decoration:underline;'>");
+if (cfm->color != 0)
+    fprintf(cfm->out, "<span style='color:#%06X;'>", cfm->color);
+}
+
+void cfmOutExt(struct cfm *cfm, char c, int color, boolean underline, boolean bold, boolean italic)
+/* Write out a byte, and formatting extras  */
+{
+if (color != cfm->color || underline != cfm->underline
+   || bold != cfm->bold || italic != cfm->italic)
+   {
+   cfmPopFormat(cfm);
+   cfm->color = color;
+   cfm->underline = underline;
+   cfm->bold = bold;
+   cfm->italic = italic;
+   cfmPushFormat(cfm);
+   }
+
+++cfm->charCount;
+fputc(c, cfm->out);
+if (cfm->wordLen)
+    {
+    if (++cfm->inWord >= cfm->wordLen)
+	{
+	cfmPopFormat(cfm);
+	fputc(' ', cfm->out);
+	cfmPushFormat(cfm);
+	cfm->inWord = 0;
+	}
+    }
+if (cfm->lineLen)
+    {
+    if (++cfm->inLine >= cfm->lineLen)
+	{
+	if (cfm->lineNumbers)
+	    {
+	    int pos = cfm->charCount;
+	    if (cfm->countDown)
+		{
+	        pos = 1-pos;
+		}
+	    pos += cfm->numOff;
+	    cfmPopFormat(cfm);
+	    fprintf(cfm->out, " %d", pos);
+	    cfmPushFormat(cfm);
+	    }
+	fprintf(cfm->out, "\n");
+	cfm->inLine = 0;
+	}
+    }
+}
+
+void cfmOut(struct cfm *cfm, char c, int color)
+/* Write out a byte, and depending on color formatting extras  */
+{
+cfmOutExt(cfm, c, color, FALSE, FALSE, FALSE);
+}
+
+void cfmFree(struct cfm **pCfm)
+/* Finish up cfm formatting job. */
+{
+struct cfm *cfm = *pCfm;
+if (cfm != NULL)
+    {
+    cfmPopFormat(cfm);
+    freez(pCfm);
+    }
+}
+
+int seqOutColorLookup[] =
+    {
+    0x000000,
+    0x3300FF,
+    0x22CCEE,
+    0xFF0033,
+    0xFFcc22,
+    0x00aa00,
+    0xFF0000,
+    };
+
+
+void bafInit(struct baf *baf, DNA *needle, int nNumOff,  boolean nCountDown,
+        DNA *haystack, int hNumOff, boolean hCountDown, FILE *out,
+        int lineSize, boolean isTrans )
+/* Initialize block alignment formatter. */
+{
+baf->cix = 0;
+baf->needle = needle;
+baf->nCountDown = nCountDown;
+baf->haystack = haystack;
+baf->nNumOff = nNumOff;
+baf->hNumOff = hNumOff;
+baf->hCountDown = hCountDown;
+baf->out = out;
+baf->lineSize = lineSize;
+baf->isTrans = isTrans;
+baf->nCurPos = baf->hCurPos = 0;
+baf->nLineStart = baf->hLineStart = 0;
+}
+
+void bafSetAli(struct baf *baf, struct ffAli *ali)
+/* Set up block formatter around an ffAli block. */
+{
+baf->nCurPos = ali->nStart - baf->needle;
+baf->hCurPos = ali->hStart - baf->haystack;
+}
+
+void bafSetPos(struct baf *baf, int nStart, int hStart)
+/* Set up block formatter starting at nStart/hStart. */
+{
+if (baf->isTrans)
+    nStart *= 3;
+baf->nCurPos = nStart;
+baf->hCurPos = hStart;
+}
+
+void bafStartLine(struct baf *baf)
+/* Set up block formatter to start new line at current position. */
+{
+baf->nLineStart = baf->nCurPos;
+baf->hLineStart = baf->hCurPos;
+}
+
+static int maxDigits(int x, int y)
+{
+int xDigits = digitsBaseTen(x);
+int yDigits = digitsBaseTen(y);
+return (xDigits > yDigits ? xDigits : yDigits);
+}
+
+void bafWriteLine(struct baf *baf)
+/* Write out a line of an alignment (which takes up
+ * three lines on the screen. */
+{
+int i;
+int count = baf->cix;
+int nStart = baf->nLineStart + 1 + baf->nNumOff;
+int hStart = baf->hLineStart + 1 + baf->hNumOff;
+int nEnd = baf->nCurPos + baf->nNumOff;
+int hEnd = baf->hCurPos + baf->hNumOff;
+int startDigits = maxDigits(nStart, hStart);
+int endDigits = maxDigits(nEnd, hEnd);
+int hStartNum, hEndNum;
+int nStartNum, nEndNum;
+static struct axtScoreScheme *ss = 0;  /* Scoring scheme. */
+struct cfm cfm;
+extern char blosumText[];
+extern struct axtScoreScheme *axtScoreSchemeFromProteinText(char *text, char *fileName);
+boolean revArrows = (baf->nCountDown ^ baf->hCountDown);
+char arrowChar = (revArrows ? '<' : '>');
+
+ZeroVar(&cfm);
+cfm.out = baf->out;
+if (ss == 0)
+    ss = axtScoreSchemeFromProteinText(blosumText, "fake");
+
+if (baf->nCountDown)
+    {
+    nStartNum = baf->nNumOff - baf->nLineStart;
+    nEndNum = 1+baf->nNumOff - baf->nCurPos;
+    }
+else
+    {
+    nStartNum = 1+baf->nNumOff + baf->nLineStart;
+    nEndNum = baf->nNumOff + baf->nCurPos;
+    }
+fprintf(baf->out, "%0*d ", startDigits, nStartNum);
+for (i=0; i<count; ++i)
+    fputc(baf->nChars[i], baf->out);
+fprintf(baf->out, " %0*d\n", endDigits, nEndNum);
+
+for (i=0; i<startDigits; ++i)
+    fputc(arrowChar, baf->out);
+fputc(' ', baf->out);
+for (i=0; i<count; ++i)
+    {
+    char n,h,c =  ' ';
+
+    n = baf->nChars[i];
+    h = baf->hChars[i];
+    if (baf->isTrans)
+        {
+	if (n != ' ')
+	    {
+	    DNA codon[4];
+	    codon[0] = baf->hChars[i-1];
+	    codon[1] = h;
+	    codon[2] = baf->hChars[i+1];
+	    codon[3] = 0;
+	    tolowers(codon);
+	    c  = lookupCodon(codon);
+	    cfmPushFormat(&cfm);
+	    if (toupper(n) == c)
+		cfmOut(&cfm, '|', seqOutColorLookup[0]);
+            else
+                {
+                int color;
+
+                if (c == 0)
+                    c = 'X';
+                if (ss->matrix[(int)toupper(n)][(int)c] > 0)
+		    color = 5;
+		else
+		    color = 6;
+		cfmOut(&cfm, c, seqOutColorLookup[color]);
+		}
+	    cfmPopFormat(&cfm);
+	    }
+	else
+	    {
+	    fputc(c, baf->out);
+	    }
+	}
+    else
+        {
+	if (toupper(n) == toupper(h))
+	     c = '|';
+	fputc(c, baf->out);
+	}
+    }
+fputc(' ', baf->out);
+for (i=0; i<endDigits; ++i)
+    fputc(arrowChar, baf->out);
+fprintf(baf->out, "\n");
+
+if (baf->hCountDown)
+    {
+    hStartNum = baf->hNumOff - baf->hLineStart;
+    hEndNum = 1+baf->hNumOff - baf->hCurPos;
+    }
+else
+    {
+    hStartNum = 1+baf->hNumOff + baf->hLineStart;
+    hEndNum = baf->hNumOff + baf->hCurPos;
+    }
+fprintf(baf->out, "%0*d ", startDigits, hStartNum);
+for (i=0; i<count; ++i)
+    fputc(baf->hChars[i], baf->out);
+fprintf(baf->out, " %0*d\n\n", endDigits, hEndNum);
+}
+
+void bafOut(struct baf *baf, char n, char h)
+/* Write a pair of character to block alignment. */
+{
+baf->nChars[baf->cix] = n;
+baf->hChars[baf->cix] = h;
+if (n != '.' && n != '-')
+    baf->nCurPos += 1;
+if (h != '.' && h != '-')
+    baf->hCurPos += 1;
+if (++(baf->cix) >= baf->lineSize)
+    {
+    bafWriteLine(baf);
+    baf->cix = 0;
+    baf->nLineStart = baf->nCurPos;
+    baf->hLineStart = baf->hCurPos;
+    }
+}
+
+void bafFlushLineNoHr(struct baf *baf)
+/* Write out alignment line if it has any characters in it (no <HR>). */
+{
+if (baf->cix > 0)
+    bafWriteLine(baf);
+fflush(baf->out);
+baf->cix = 0;
+}
+
+void bafFlushLine(struct baf *baf)
+/* Write out alignment line if it has any characters in it, and an <HR>. */
+{
+bafFlushLineNoHr(baf);
+fprintf(baf->out, "<HR ALIGN=\"CENTER\">");
+}
+
diff --git a/lib/seqStats.c b/lib/seqStats.c
new file mode 100644
index 0000000..30f56d4
--- /dev/null
+++ b/lib/seqStats.c
@@ -0,0 +1,36 @@
+#include "common.h"
+#include "dnautil.h"
+#include "seqStats.h"
+
+double dnaMatchEntropy(DNA *query, DNA *target, int baseCount)
+/* Return entropy of matching bases - a number between 0 and 1, with
+ * higher numbers the more diverse the matching bases. */
+{
+#define log4 1.386294
+#define invLog4 (1.0/log4)
+double p, q, e = 0, invTotal;
+int c, count[4], total;
+int i, qVal, tVal;
+count[0] = count[1] = count[2] = count[3] = 0;
+for (i=0; i<baseCount; ++i)
+    {
+    qVal = ntVal[(int)query[i]];
+    tVal = ntVal[(int)target[i]];
+    if (qVal == tVal && qVal >= 0)
+	count[qVal] += 1;
+    }
+total = count[0] + count[1] + count[2] + count[3];
+invTotal = 1.0/total;
+for (i=0; i<4; ++i)
+    {
+    if ((c = count[i]) > 0)
+        {
+	p = c * invTotal;
+	q = log(p);
+	e -= p*q;
+	}
+    }
+e *= invLog4;
+return e;
+}
+
diff --git a/lib/servBrcMcw.c b/lib/servBrcMcw.c
new file mode 100644
index 0000000..6e945d1
--- /dev/null
+++ b/lib/servBrcMcw.c
@@ -0,0 +1,47 @@
+/* Stuff that's specific for .brc.mcw.edu server goes here. 
+ *
+ * This file is copyright 2004 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "portable.h"
+#include "portimpl.h"
+#include "obscure.h"
+#include "hash.h"
+
+
+static char *__trashDir = "/trash";
+
+static void _makeTempName(struct tempName *tn, char *base, char *suffix)
+/* Figure out a temp name, and how CGI and HTML will access it. */
+{
+char *tname;
+
+tname = rTempName(__trashDir, base, suffix);
+strcpy(tn->forCgi, tname);
+strcpy(tn->forHtml, tname);
+}
+
+static char *_cgiDir()
+{
+return "/cgi-bin/";
+}
+
+static char *_trashDir()
+{
+return __trashDir;
+}
+
+static double _speed()
+{
+return 3.0;
+}
+    
+struct webServerSpecific wssBrcMcw =
+    {
+    "default",
+    _makeTempName,
+    _cgiDir,
+    _speed,
+    _trashDir,
+    };
diff --git a/lib/servCrunx.c b/lib/servCrunx.c
new file mode 100644
index 0000000..a85e1f7
--- /dev/null
+++ b/lib/servCrunx.c
@@ -0,0 +1,51 @@
+/* Stuff that's specific for local linux server goes here. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "portable.h"
+#include "portimpl.h"
+#include "obscure.h"
+
+
+static char *__trashDir = "/home/httpd/html/trash";
+
+static void _makeTempName(struct tempName *tn, char *base, char *suffix)
+/* Figure out a temp name, and how CGI and HTML will access it. */
+{
+char *tname;
+char *tempDirCgi = __trashDir;
+char *tempDirHtml = "/trash";
+int tlcLen = strlen(tempDirCgi);
+int tlhLen = strlen(tempDirHtml);
+
+tname = rTempName(tempDirCgi, base, suffix);
+strcpy(tn->forCgi, tname);
+memcpy(tn->forHtml, tempDirHtml, tlhLen);
+strcpy(tn->forHtml+tlhLen, tn->forCgi+tlcLen);
+}
+
+static char *_cgiDir()
+{
+return "../cgi-bin/";
+}
+
+static char *_trashDir()
+{
+return __trashDir;
+}
+
+static double _speed()
+{
+return 3.0;
+}
+    
+struct webServerSpecific wssLinux =
+    {
+    "linux",
+    _makeTempName,
+    _cgiDir,
+    _speed,
+    _trashDir,
+    };
diff --git a/lib/servcis.c b/lib/servcis.c
new file mode 100644
index 0000000..b79e15c
--- /dev/null
+++ b/lib/servcis.c
@@ -0,0 +1,48 @@
+/* Stuff that's specific for Comp Science dept. web server goes here. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "portable.h"
+#include "portimpl.h"
+#include "obscure.h"
+#include "hash.h"
+
+
+static char *__trashDir = "../trash";
+
+static void _makeTempName(struct tempName *tn, char *base, char *suffix)
+/* Figure out a temp name, and how CGI and HTML will access it. */
+{
+char *tname;
+
+tname = rTempName(__trashDir, base, suffix);
+strcpy(tn->forCgi, tname);
+strcpy(tn->forHtml, tname);
+}
+
+static char *_cgiDir()
+{
+return "../cgi-bin/";
+}
+
+static char *_trashDir()
+{
+return __trashDir;
+}
+
+static double _speed()
+{
+return 3.0;
+}
+
+    
+struct webServerSpecific wssDefault =
+    {
+    "default",
+    _makeTempName,
+    _cgiDir,
+    _speed,
+    _trashDir,
+    };
diff --git a/lib/servcl.c b/lib/servcl.c
new file mode 100644
index 0000000..0825d66
--- /dev/null
+++ b/lib/servcl.c
@@ -0,0 +1,49 @@
+/* "Web Server" for command line execution. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "portable.h"
+#include "portimpl.h"
+#include "obscure.h"
+
+
+static char *__trashDir = ".";
+
+static void _makeTempName(struct tempName *tn, char *base, char *suffix)
+/* Figure out a temp name, and how CGI and HTML will access it. */
+{
+char *tname = rTempName(__trashDir, base, suffix);
+strcpy(tn->forCgi, tname);
+strcpy(tn->forHtml, tn->forCgi);
+}
+
+static char *_cgiDir()
+{
+char *jkwebDir;
+if ((jkwebDir = getenv("JKWEB")) == NULL)
+    return "";
+else
+    return jkwebDir;
+}
+
+static char *_trashDir()
+{
+return __trashDir;
+}
+
+static double _speed()
+{
+return 1.0;
+}
+    
+    
+struct webServerSpecific wssCommandLine =
+    {
+    "commandLine",
+    _makeTempName,
+    _cgiDir,
+    _speed,
+    _trashDir,
+    };
diff --git a/lib/servmsII.c b/lib/servmsII.c
new file mode 100644
index 0000000..c56c6c3
--- /dev/null
+++ b/lib/servmsII.c
@@ -0,0 +1,45 @@
+/* Stuff that's specific for the MS II Web Server goes here. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "portable.h"
+#include "portimpl.h"
+#include "obscure.h"
+
+
+static char *__trashDir = "..\\trash";
+
+static void _makeTempName(struct tempName *tn, char *base, char *suffix)
+/* Figure out a temp name, and how CGI and HTML will access it. */
+{
+long tempIx = incCounterFile("tcounter");
+sprintf(tn->forCgi, "%s\\%s%ld%s", __trashDir, base, tempIx, suffix);
+sprintf(tn->forHtml, "%s\\%s%ld%s", __trashDir, base, tempIx, suffix);
+}
+
+static char *_cgiDir()
+{
+return "";
+}
+
+static char *_trashDir()
+{
+return __trashDir;
+}
+
+static double _speed()
+{
+return 2.5;
+}
+
+    
+struct webServerSpecific wssMicrosoftII =
+    {
+    "Microsoft-IIS",
+    _makeTempName,
+    _cgiDir,
+    _speed,
+    _trashDir,
+    };
diff --git a/lib/servpws.c b/lib/servpws.c
new file mode 100644
index 0000000..6ee091e
--- /dev/null
+++ b/lib/servpws.c
@@ -0,0 +1,44 @@
+/* Stuff that's specific for the Personal Web Server goes here. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "portable.h"
+#include "portimpl.h"
+#include "obscure.h"
+
+
+static char *__trashDir = "..\\trash";
+
+static void _makeTempName(struct tempName *tn, char *base, char *suffix)
+/* Figure out a temp name, and how CGI and HTML will access it. */
+{
+long tempIx = incCounterFile("tcounter");
+sprintf(tn->forCgi, "%s\\%s%ld%s", __trashDir, base, tempIx, suffix);
+sprintf(tn->forHtml, "%s\\%s%ld%s", __trashDir, base, tempIx, suffix);
+}
+
+static char *_cgiDir()
+{
+return "../cgi-bin/";
+}
+
+static char *_trashDir()
+{
+return __trashDir;
+}
+
+static double _speed()
+{
+return 1.25;
+}
+        
+struct webServerSpecific wssMicrosoftPWS =
+    {
+    "Microsoft-PWS",
+    _makeTempName,
+    _cgiDir,
+    _speed,
+    _trashDir,
+    };
diff --git a/lib/shaRes.c b/lib/shaRes.c
new file mode 100644
index 0000000..740d472
--- /dev/null
+++ b/lib/shaRes.c
@@ -0,0 +1,80 @@
+/* ShaRes.c - implementation of shared resources 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "shaRes.h"
+
+
+static void shaFreeNode(struct shaResNode *node)
+/* Free a node.  (Don't look at link count, just do it.) */
+{
+struct shaResNode *next = node->next;
+struct shaResNode *prev = node->prev;
+struct shaResList *list = node->list;
+
+if (next != NULL)
+    next->prev = prev;
+if (prev != NULL)
+    prev->next = next;
+else
+    list->head = next;
+list->freeData(node->data);
+freeMem(node->name);
+freeMem(node);
+}        
+
+void shaUnlink(struct shaResNode *node)
+/* Decrement link count and free if down to zero. */
+{
+if (--node->links <= 0)
+    shaFreeNode(node);
+}
+
+void shaLink(struct shaResNode *node)
+/* Increment link count. */
+{
+++node->links;
+}
+
+struct shaResNode *shaNewNode(struct shaResList *list, char *name, void *data)
+/* Create a new node with link count of one. */
+{
+struct shaResNode *nn = needMem(sizeof(*nn));
+struct shaResNode *head = list->head;
+
+/* Store the goods and what list we're on, and start with one link. */
+nn->list = list;
+nn->data = data;
+nn->links = 1;
+nn->name = cloneString(name);
+
+/* Put us at the front of the list. */
+nn->next = head;
+nn->prev = NULL;
+if (head != NULL)
+    head->prev = nn;
+list->head = nn;
+return nn;
+}
+
+void shaCleanup(struct shaResList *list)
+/* Free every node on list. */
+{
+struct shaResNode *node, *next;
+
+for (node = list->head;node != NULL;node = next)
+    {
+    next = node->next;
+    shaFreeNode(node);
+    }
+list->head = NULL;
+}
+
+void shaInit(struct shaResList *list, void (*freeData)(void *pData))
+/* Start up resource list. */
+{
+list->head = NULL;
+list->freeData = freeData;
+}
diff --git a/lib/slog.c b/lib/slog.c
new file mode 100644
index 0000000..a38bcd5
--- /dev/null
+++ b/lib/slog.c
@@ -0,0 +1,32 @@
+/* slog - fixed point scaled logarithm stuff. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "slog.h"
+
+
+double fSlogScale = 8192.0;	/* Convert to fixed point by multiplying by this. */
+double invSlogScale = 0.0001220703125; /* Conver back to floating point with this. */
+
+int slog(double val)
+/* Return scaled log. */
+{
+return (round(fSlogScale*log(val)));
+}
+
+int carefulSlog(double val)
+/* Returns scaled log that makes sure there's no int overflow. */
+{
+if (val < 0.0000001)
+    val = 0.0000001;
+return slog(val);
+}
+
+double invSlog(int scaledLog)
+/* Inverse of slog. */
+{
+return exp(scaledLog*invSlogScale);
+}
+
diff --git a/lib/snof.c b/lib/snof.c
new file mode 100644
index 0000000..cea5631
--- /dev/null
+++ b/lib/snof.c
@@ -0,0 +1,293 @@
+/* Snof.c Sorted Name Offset File.
+ * This accesses a file of name/offset pairs that are sorted by
+ * name.  Does a binary search of file to find the offset given name.
+ * Most typically this is used to do a quick lookup given an index file. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "snof.h"
+#include "snofmake.h"
+
+
+void snofClose(struct snof **pSnof)
+/* Close down the index file. */
+{
+struct snof *snof = *pSnof;
+if (snof != NULL)
+    {
+    if (snof->file != NULL)
+        fclose(snof->file);
+    if (snof->first != NULL)
+        freeMem(snof->first);
+    freeMem(snof);
+    *pSnof = NULL;
+    }
+}
+
+static boolean makeSnofName(char *snofName, char *rootName)
+/* Figure out whether it's .xi or .ix by looking at
+ * signature.  Usually just need to open a file to
+ * do this once per program run. */
+{
+static char *suffixes[2] = {".ix", ".xi"};
+static char *suff = NULL;
+int sigBuf[4];
+FILE *f;
+int i;
+
+if (suff == NULL)
+    {
+    for (i=0; i<ArraySize(suffixes); ++i)
+	{
+	sprintf(snofName, "%s%s", rootName, suffixes[i]);
+	if ((f = fopen(snofName, "rb")) != NULL)
+	    {
+	    if ((fread(sigBuf, sizeof(sigBuf), 1, f)) == 1)
+		{
+		if (isSnofSig(&sigBuf))
+		    {
+		    suff = suffixes[i];
+		    }
+		}
+	    fclose(f);
+	    }
+	if (suff != NULL)
+	    break;
+	}
+    }
+if (suff == NULL)
+    return FALSE;
+sprintf(snofName, "%s%s", rootName, suff);
+return TRUE;
+}
+
+struct snof *snofOpen(char *indexName)
+/* Open up the index file.  Returns NULL if there's any problem. */
+{
+struct snof *snof;
+int sigBuf[4];
+FILE *f;
+char fileName[512];
+
+if (!makeSnofName(fileName, indexName))
+    return NULL;
+if ((snof = needMem(sizeof(*snof))) == NULL)
+    return NULL;
+
+if ((snof->file = f = fopen(fileName, "rb")) == NULL)
+    {
+    freeMem(snof);
+    return NULL;
+    }
+if ((fread(sigBuf, sizeof(sigBuf), 1, f)) != 1)
+    {
+    snofClose(&snof);
+    return NULL;
+    }
+if (!isSnofSig(&sigBuf))
+    {
+    snofClose(&snof);
+    return NULL;
+    }
+if ((fread(&snof->maxNameSize, sizeof(snof->maxNameSize), 1, f)) != 1)
+    {
+    snofClose(&snof);
+    return NULL;
+    }
+snof->headSize = ftell(f);
+snof->itemSize = snof->maxNameSize + sizeof(unsigned);
+if ((snof->first = needMem(5*snof->itemSize)) == NULL)
+    {
+    snofClose(&snof);
+    return NULL;
+    }
+snof->last = snof->first + snof->itemSize;
+snof->less = snof->last + snof->itemSize;
+snof->mid = snof->less + snof->itemSize;
+snof->more = snof->mid + snof->itemSize;
+
+if (fread(snof->first, snof->itemSize, 1, f) != 1)
+    {
+    snofClose(&snof);
+    return NULL;
+    }
+fseek(f, -snof->itemSize, SEEK_END);
+snof->endIx = (ftell(f)-snof->headSize)/snof->itemSize;
+if (fread(snof->last, snof->itemSize, 1, f) != 1)
+    {
+    snofClose(&snof);
+    return NULL;
+    }
+return snof;
+}
+
+struct snof *snofMustOpen(char *indexName)
+/* Open up index file or die. */
+{
+struct snof *snof = snofOpen(indexName);
+if (snof == NULL)
+    errAbort("Couldn't open index file %s", indexName);
+return snof;
+}
+
+static long retrieveOffset(char *item, int itemSize)
+{
+unsigned offset;
+memcpy(&offset, item+itemSize-sizeof(offset), sizeof(offset));
+return offset;
+}
+
+static int snofCmp(char *prefix, char *name, int maxSize, boolean isPrefix)
+{
+if (isPrefix)
+    return memcmp(prefix, name, maxSize);
+else
+    return strcmp(prefix, name);
+}
+
+static boolean snofSearch(struct snof *snof, char *name, int nameSize, 
+    boolean isPrefix, int *pIx, char **pNameOffset)
+/* Find index of name by binary search.
+ * Returns FALSE if no such name in the index file. */
+ {
+char *startName, *endName, *midName;
+int startIx, endIx, midIx;
+int cmp;
+int itemSize = snof->itemSize;
+FILE *f = snof->file;
+int headSize = snof->headSize;
+
+/* Truncate name size if necessary. */
+if (nameSize > snof->maxNameSize)
+    nameSize = snof->maxNameSize;
+
+/* Set up endpoints of binary search */
+startName = snof->less;
+memcpy(startName, snof->first, itemSize);
+endName = snof->more;
+memcpy(endName, snof->last, itemSize);
+midName = snof->mid;
+
+startIx = 0;
+endIx = snof->endIx;
+
+/* Check for degenerate initial case */
+if (snofCmp(name, startName, nameSize, isPrefix) == 0)
+    {
+    *pIx = startIx;
+    *pNameOffset = startName;
+    return TRUE;
+    }
+if (snofCmp(name, endName, nameSize, isPrefix) == 0)
+    {
+    *pIx = endIx;
+    *pNameOffset =  endName;
+    return TRUE;
+    }
+
+/* Do binary search. */
+for (;;)
+    {
+    midIx = (startIx + endIx ) / 2;
+    if (midIx == startIx || midIx == endIx)
+	{
+        *pIx = -1;
+        return FALSE;
+        }
+    fseek(f, headSize + midIx*itemSize, SEEK_SET);
+    if (fread(midName, itemSize, 1, f) < 1)
+        {
+        *pIx = 0;
+        return FALSE;
+        }
+    cmp = snofCmp(name, midName, nameSize, isPrefix);
+    if (cmp == 0)
+        {
+        *pIx = midIx;
+        *pNameOffset = midName;
+        return TRUE;
+        }
+    else if (cmp > 0)
+	{
+	memcpy(startName, midName, itemSize);
+	startIx = midIx;
+	}
+    else
+	{
+	memcpy(endName, midName, itemSize);
+	endIx = midIx;
+	}
+    }
+}
+
+boolean snofFindOffset(struct snof *snof, char *name, long *pOffset)
+/* Find offset corresponding with name.  Returns FALSE if no such name
+ * in the index file. */
+{
+char *nameOffset;
+int matchIx;
+if (!snofSearch(snof, name, strlen(name), FALSE,  &matchIx, &nameOffset))
+    {
+    *pOffset = matchIx; /* Pass along error code such as it is. */
+    return FALSE;
+    }
+*pOffset = retrieveOffset(nameOffset, snof->itemSize);
+return TRUE;
+}
+
+boolean snofFindFirstStartingWith(struct snof *snof, char *prefix, int prefixSize,
+    int *pSnofIx)
+/* Find first index in snof file whose name begins with prefix. */
+{
+char *nameOffset;
+int matchIx;
+if (!snofSearch(snof, prefix, prefixSize, TRUE,  &matchIx, &nameOffset))
+    {
+    *pSnofIx = matchIx; /* Pass along error code such as it is. */
+    return FALSE;
+    }
+while (--matchIx >= 0)
+    {
+    nameOffset = snofNameAtIx(snof, matchIx);
+    if (snofCmp(prefix, nameOffset, prefixSize, TRUE) != 0)
+        break;
+    }
+++matchIx;
+*pSnofIx = matchIx;
+return TRUE;
+}
+
+int snofElementCount(struct snof *snof)
+/* How many names are in snof file? */
+{
+return snof->endIx + 1;
+}
+
+long snofOffsetAtIx(struct snof *snof, int ix)
+/* The offset of a particular index in file. */
+{
+char *nameOffset = snofNameAtIx(snof, ix);
+return retrieveOffset(nameOffset, snof->itemSize);
+}
+
+char *snofNameAtIx(struct snof *snof, int ix)
+/* The name at a particular index in file.  (This will be overwritten by
+ * later calls to snof system. Strdup if you want to keep it.)
+ */
+{
+fseek(snof->file, snof->headSize + ix*snof->itemSize, SEEK_SET);
+if (fread(snof->mid, snof->itemSize, 1, snof->file) != 1 && ferror(snof->file))
+    errAbort("snofNameAtIx: fread failed: %s", strerror(ferror(snof->file)));
+return snof->mid;
+}
+
+void snofNameOffsetAtIx(struct snof *snof, int ix, char **pName, long *pOffset)
+/* Get both name and offset for an index. */
+{
+char *nameOffset = snofNameAtIx(snof, ix);
+*pName = nameOffset;
+*pOffset = retrieveOffset(nameOffset, snof->itemSize);
+}
+
diff --git a/lib/snofmake.c b/lib/snofmake.c
new file mode 100644
index 0000000..b0e0d39
--- /dev/null
+++ b/lib/snofmake.c
@@ -0,0 +1,228 @@
+/* snofmake - Write out an index file. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "localmem.h"
+#include "snofmake.h"
+#include "errabort.h"
+
+
+static jmp_buf errRecover;
+
+static void ourErrAbort()
+/* Default error handler. Prints message and exits
+ * program. */
+{
+longjmp(errRecover, -1);
+}
+
+static struct lm *lm;
+
+static void initMem()
+{
+lm = lmInit((1<<16));
+}
+
+static void cleanupMem()
+{
+lmCleanup(&lm);
+}
+
+static void *localNeedMem(int size)
+{
+return lmAlloc(lm, size);
+}
+
+struct offsetList
+    {
+    struct offsetList *next;
+    char *name;
+    unsigned offset;
+    };
+
+static struct offsetList *newOffset(char *name, int nameLen)
+/* Return a fresh name list entry. */
+{
+struct offsetList *nl = localNeedMem(sizeof(*nl));
+nl->name = localNeedMem(nameLen+1);
+memcpy(nl->name, name, nameLen);
+nl->name[nameLen] = 0;
+return nl;
+}
+
+static int cmpOffsetPointers(const void *va, const void *vb)
+/* comparison function for qsort on an array of offset pointers*/
+{
+struct offsetList **pa, **pb;
+struct offsetList *a, *b;
+pa = (struct offsetList **)va;
+pb = (struct offsetList **)vb;
+a = *pa;
+b = *pb;
+return strcmp(a->name, b->name);
+}
+
+static int longestNameSize(struct offsetList *list)
+{
+struct offsetList *el;
+int size, longestSize = 0;
+
+for (el = list; el != NULL; el = el->next)
+    {
+    size = strlen(el->name);
+    if (size > longestSize) 
+        {
+        longestSize = size;
+        }
+    }
+return longestSize;
+}
+
+static struct offsetList *makeOffsetList(FILE *inFile, 
+    boolean (*nextRecord)(FILE *inFile, void *data, char **rName, int *rNameLen), void *data)
+/* Build up a list of records and their offsets into file. */
+{
+struct offsetList *list = NULL;
+struct offsetList *newEl;
+for (;;)
+    {
+    long offset = ftell(inFile);
+    char *name;
+    int nameLen;
+    if (!nextRecord(inFile, data, &name, &nameLen))
+        break;
+    if (nameLen > 0)
+        {
+        newEl = newOffset(name, nameLen);
+        newEl->offset = offset;
+        newEl->next = list;
+        list = newEl;
+        }
+    }
+slReverse(&list);
+return list;
+}
+
+boolean warnAboutDupes(struct offsetList **array, int size)
+/* Since list is sorted it's easy to warn about duplications. */
+{
+char *name, *prevName;
+int i;
+boolean ok = TRUE;
+
+if (size < 2)
+    return FALSE;
+prevName = array[0]->name;
+for (i=1; i<size; ++i)
+    {
+    name = array[i]->name;
+    if (!differentWord(name, prevName))
+	{
+        warn("Duplicate strings: %s %s", prevName, name);
+	ok = FALSE;
+	}
+    prevName = name;
+    }
+return ok;
+}
+
+static void makeIndex(FILE *in, FILE *out, 
+    boolean (*nextRecord)(FILE *in, void *data, char **rName, int *rNameLen), void *data,
+    boolean dupeOk)
+/* Make index.  Throw error if there's a problem. */
+{
+struct offsetList *list;
+int listSize;
+struct offsetList **array;
+int i;
+struct offsetList *el;
+int nameSize;
+char *nameBuf;
+char *indexSig;
+int indexSigSize;
+
+printf("Reading input\n");
+list = makeOffsetList(in, nextRecord, data);
+listSize = slCount(list);
+array = localNeedMem(listSize * sizeof(*array));
+nameSize = longestNameSize(list)+1;
+
+printf("Got %d offsets %d nameSize.  Sorting...\n", listSize, nameSize);
+nameBuf = localNeedMem(nameSize);
+
+/* Make an array of pointers, one for each element in list. */
+for (i=0, el = list; i<listSize; i+=1, el = el->next)
+    array[i] = el;
+
+/* Sort alphabetically based on name. */
+qsort(array, listSize, sizeof(array[0]), cmpOffsetPointers);
+if (!dupeOk)
+    warnAboutDupes(array, listSize);
+
+/* Write out file header */
+printf("Writing index file \n");
+snofSignature(&indexSig, &indexSigSize);
+mustWrite(out, indexSig, indexSigSize);
+mustWrite(out, &nameSize, sizeof(nameSize));
+    
+/* Write out sorted output */
+for (i=0; i<listSize; ++i)
+    {
+    zeroBytes(nameBuf, nameSize);
+    strcpy(nameBuf, array[i]->name);
+    mustWrite(out, nameBuf, nameSize);
+    mustWrite(out, &array[i]->offset, sizeof(array[i]->offset));
+    }
+}
+
+boolean snofDupeOkIndex(FILE *inFile, char *outName, 
+    boolean (*nextRecord)(FILE *inFile, void *data, char **rName, int *rNameLen), 
+    void *data, boolean dupeOk)
+/* Make an index file, as in snofMakeIndex, but optionally allow duplicates
+ * without complaining. */
+{
+FILE *outFile;
+int status;
+
+/* Initialize */
+if ((outFile = fopen(outName, "wb")) == NULL)
+    {
+    fprintf(stderr, "Couldn't create index file %s\n", outName);
+    return FALSE;
+    }
+initMem();
+
+/* Wrap error recovery around main routine. */
+status = setjmp(errRecover);
+if (status == 0)
+    {
+    pushAbortHandler(ourErrAbort);
+    makeIndex(inFile, outFile, nextRecord, data, dupeOk);
+    }
+popAbortHandler();
+
+/* Cleanup. */
+fclose(outFile);
+cleanupMem();
+return status == 0;
+}
+
+boolean snofMakeIndex(FILE *inFile, char *outName, 
+    boolean (*nextRecord)(FILE *inFile, void *data, char **rName, int *rNameLen), 
+    void *data)
+/* Make an index file - name/offset pairs that are sorted by name.
+ * Inputs:
+ *     inFile - open file that you're indexing with header read and verified.
+ *     outName - name of index file to create
+ *     nextRecord - function that reads next record in file you're indexing
+ *                  and returns the name of that record.
+ *     data - void pointer passed through to nextRecord.
+ *
+ * In this implementation this function just is an error recovery wrapper
+ * around the local function makeIndex, which does the real work. */
+{
+return snofDupeOkIndex(inFile, outName, nextRecord, data, FALSE);
+}
+
diff --git a/lib/snofsig.c b/lib/snofsig.c
new file mode 100644
index 0000000..9ae6b22
--- /dev/null
+++ b/lib/snofsig.c
@@ -0,0 +1,24 @@
+/* snofSig - signature (first 16 bytes) of a snof format file. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "snofmake.h"
+
+
+static int ixSig[4] = {0x693F8ED1, 0x7EDA1C32, 0x4BA58983, 0x277CB89C,};
+
+void snofSignature(char **rSig, int *rSigSize)
+/* Return signature. */
+{
+*rSig = (char *)ixSig;
+*rSigSize = sizeof(ixSig);
+}
+
+boolean isSnofSig(void *sig)
+/* Return true if sig is right. */
+{
+return memcmp(sig, ixSig, sizeof(ixSig)) == 0;
+}
+
diff --git a/lib/spaceSaver.c b/lib/spaceSaver.c
new file mode 100644
index 0000000..b39bd60
--- /dev/null
+++ b/lib/spaceSaver.c
@@ -0,0 +1,144 @@
+/* spaceSaver - routines that help layout 1-D objects into a
+ * minimum number of tracks so that no two objects overlap
+ * within a single track. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "spaceSaver.h"
+
+
+
+struct spaceSaver *spaceSaverMaxCellsNew(int winStart, int winEnd, int maxRows, int maxCells)
+/* Create a new space saver around the given window.   */
+{
+struct spaceSaver *ss;
+float winWidth;
+
+AllocVar(ss);
+ss->winStart = winStart;
+ss->winEnd = winEnd;
+ss->maxRows = maxRows;
+winWidth = winEnd - winStart;
+ss->cellsInRow = winWidth;
+while (ss->cellsInRow > maxCells)
+    ss->cellsInRow /= 2;
+ss->scale = ss->cellsInRow/winWidth;
+return ss;
+}
+
+struct spaceSaver *spaceSaverNew(int winStart, int winEnd, int maxRows)
+/* Create a new space saver around the given window.   */
+{
+return spaceSaverMaxCellsNew(winStart, winEnd, maxRows, 800);
+}
+
+void spaceSaverFree(struct spaceSaver **pSs)
+/* Free up a space saver. */
+{
+struct spaceSaver *ss = *pSs;
+if (ss != NULL)
+    {
+    struct spaceRowTracker *srt;
+    for (srt = ss->rowList; srt != NULL; srt = srt->next)
+	freeMem(srt->used);
+    slFreeList(&ss->rowList);
+    slFreeList(&ss->nodeList);
+    freez(pSs);
+    }
+}
+
+static boolean allClear(bool *b, int count)
+/* Return TRUE if count bools starting at b are all 0 */
+{
+int i;
+for (i=0; i<count; ++i)
+    if (b[i])
+	return FALSE;
+return TRUE;
+}
+
+struct spaceNode *spaceSaverAddOverflow(struct spaceSaver *ss, int start, int end, 
+					void *val, boolean allowOverflow)
+/* Add a new node to space saver. Returns NULL if can't fit item in
+ * and allowOverflow == FALSE. If allowOverflow == TRUE then put items
+ * that won't fit in last row. */
+{
+int cellStart, cellEnd, cellWidth;
+struct spaceRowTracker *srt, *freeSrt = NULL;
+int rowIx = 0;
+struct spaceNode *sn;
+
+if (ss->isFull)
+    return NULL;
+
+if ((start -= ss->winStart) < 0)
+    start = 0;
+end -= ss->winStart;	/* We'll clip this in cell coordinates. */
+
+cellStart = round(start * ss->scale);
+cellEnd = round(end * ss->scale)+1;
+if (cellEnd > ss->cellsInRow)
+    cellEnd = ss->cellsInRow;
+cellWidth = cellEnd - cellStart;
+
+/* Find free row. */
+for (srt = ss->rowList; srt != NULL; srt = srt->next)
+    {
+    if (allClear(srt->used + cellStart, cellWidth))
+	{
+	freeSrt = srt;
+	break;
+	}
+    ++rowIx;
+    }
+
+/* If no free row make new row. */
+if (freeSrt == NULL)
+    {
+    if (ss->rowCount >= ss->maxRows)
+	{
+	/* Abort if too many rows and no
+	   overflow allowed. */
+	if(!allowOverflow) 
+	    {
+	    ss->isFull = TRUE;
+	    return NULL;
+	    }
+	}
+    else 
+	{
+	AllocVar(freeSrt);
+	freeSrt->used = needMem(ss->cellsInRow);
+	slAddTail(&ss->rowList, freeSrt);
+	++ss->rowCount;
+	}
+    }
+
+/* Mark that part of row used (except in overflow case). */
+if(freeSrt != NULL)
+    memset(freeSrt->used + cellStart, 1, cellWidth);
+
+/* Make a space node. If allowing overflow it will
+ all end up in the last row. */
+AllocVar(sn);
+sn->row = rowIx;
+sn->val = val;
+slAddHead(&ss->nodeList, sn);
+return sn;
+}
+
+struct spaceNode *spaceSaverAdd(struct spaceSaver *ss, 
+	int start, int end, void *val)
+/* Add a new node to space saver. Returns NULL if can't fit
+ * item in. */
+{
+return spaceSaverAddOverflow(ss, start, end, val, FALSE);
+}
+
+void spaceSaverFinish(struct spaceSaver *ss)
+/* Tell spaceSaver done adding nodes. */
+{
+slReverse(&ss->nodeList);
+}
diff --git a/lib/spacedColumn.c b/lib/spacedColumn.c
new file mode 100644
index 0000000..c1256e4
--- /dev/null
+++ b/lib/spacedColumn.c
@@ -0,0 +1,134 @@
+/* spacedColumn - stuff to handle parsing text files where fields are
+ * fixed width rather than tab delimited. */
+
+#include "common.h"
+#include "linefile.h"
+#include "spacedColumn.h"
+#include "obscure.h"
+#include "sqlNum.h"
+
+
+struct spacedColumn *spacedColumnFromSample(char *sample)
+/* Return spaced column list from a sampleline , which is assumed to
+ * have no spaces except between columns */
+{
+struct spacedColumn *col, *colList = NULL;
+char *dupe = cloneString(sample);
+char *word, *line = dupe;
+while ((word = nextWord(&line)) != NULL)
+    {
+    AllocVar(col);
+    col->start = word - dupe;
+    col->size = strlen(word);
+    slAddHead(&colList, col);
+    }
+freeMem(dupe);
+slReverse(&colList);
+return colList;
+}
+
+struct spacedColumn *spacedColumnFromLineFile(struct lineFile *lf)
+/* Scan through lineFile and figure out column spacing. Assumes
+ * file contains nothing but columns. */
+{
+int maxLine = 64*1024;
+int lineSize, widestLine = 0;
+char *projection = needMem(maxLine+1);
+char *line;
+struct spacedColumn *colList;
+int i;
+
+/* Create projection of all lines. */
+for (i=0; i<maxLine; ++i)
+    projection[i] = ' ';
+while (lineFileNext(lf, &line, &lineSize))
+    {
+    if (lineSize > widestLine)
+         widestLine = lineSize;
+    for (i=0; i<lineSize; ++i)
+        {
+	char c = line[i];
+	if (c != 0 && c != ' ')
+	    projection[i] = line[i];
+	}
+    }
+projection[widestLine] = 0;
+colList = spacedColumnFromSample(projection);
+freeMem(projection);
+return colList;
+}
+
+struct spacedColumn *spacedColumnFromFile(char *fileName)
+/* Read file and figure out where columns are. */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+struct spacedColumn *colList = spacedColumnFromLineFile(lf);
+lineFileClose(&lf);
+return colList;
+}
+
+int spacedColumnBiggestSize(struct spacedColumn *colList)
+/* Return size of biggest column. */
+{
+int maxSize = 0;
+struct spacedColumn *col;
+for (col = colList; col != NULL; col = col->next)
+    if (maxSize < col->size)
+        maxSize = col->size;
+return maxSize;
+}
+
+boolean spacedColumnParseLine(struct spacedColumn *colList, 
+	char *line, char *row[])
+/* Parse line into row according to colList.  This will
+ * trim leading and trailing spaces. It will write 0's
+ * into line.  Returns FALSE if there's a problem (like
+ * line too short.) */
+{
+struct spacedColumn *col;
+int i, len = strlen(line);
+for (i=0, col = colList; col != NULL; col = col->next, ++i)
+    {
+    if (col->start > len)
+	return FALSE;
+    int end = col->start + col->size;
+    if (end > len) end = len;
+    line[end] = 0;
+    row[i] = trimSpaces(line + col->start);
+    }
+return TRUE;
+}
+
+struct spacedColumn *spacedColumnFromWidthArray(int array[], int size)
+/* Return a list of spaced columns corresponding to widths in array.
+ * The final char in each column should be whitespace. */
+{
+struct spacedColumn *col, *colList = NULL;
+int i;
+int start = 0;
+for (i=0; i<size; ++i)
+    {
+    int width = array[i];
+    AllocVar(col);
+    col->start = start;
+    col->size = width-1;
+    slAddHead(&colList, col);
+    start += width;
+    }
+slReverse(&colList);
+return colList;
+}
+
+struct spacedColumn *spacedColumnFromSizeCommaList(char *commaList)
+/* Given an comma-separated list of widths in ascii, return
+ * a list of spacedColumns. */
+{
+struct slName *ascii, *asciiList = commaSepToSlNames(commaList);
+int colCount = slCount(asciiList);
+int widths[colCount], i;
+for (ascii = asciiList, i=0; ascii != NULL; ascii = ascii->next, ++i)
+    widths[i] = sqlUnsigned(ascii->name);
+slFreeList(&asciiList);
+return spacedColumnFromWidthArray(widths, colCount);
+}
+
diff --git a/lib/spacedSeed.c b/lib/spacedSeed.c
new file mode 100644
index 0000000..169e223
--- /dev/null
+++ b/lib/spacedSeed.c
@@ -0,0 +1,65 @@
+/* spacedSeed - stuff to help with spaced seeds for alignments. */
+
+#include "common.h"
+#include "spacedSeed.h"
+
+
+/* Seeds - the weight 9 and 11 seeds are from PatternHunter paper.
+ * The weights 10,12,13,14,15,16,17 and 18 are from the Choi, Zeng,
+ * and Zhang paper.  The others are just guesses. */
+
+char *spacedSeeds[] = {
+    /*  0 */ "",
+    /*  1 */ "1",
+    /*  2 */ "11",
+    /*  3 */ "1101",
+    /*  4 */ "110101",
+    /*  5 */ "1101011",
+    /*  6 */ "111001011",
+    /*  7 */ "1110010111",
+    /*  8 */ "1110010100111",
+    /*  9 */ "111001010011011",
+    /* 10 */ "1101100011010111",
+    /* 11 */ "111010010100110111",
+    /* 12 */ "111010110100110111",
+    /* 13 */ "11101011001100101111",
+    /* 14 */ "111011100101100101111",
+    /* 15 */ "11110010101011001101111",
+#ifdef EVER_NEEDED_IN_64_BIT_MACHINE
+    /* 16 */ "111100110101011001101111",
+    /* 17 */ "111101010111001101101111",
+    /* 18 */ "1111011001110101011011111",
+#endif /* EVER_NEEDED_IN_64_BIT_MACHINE */
+};
+
+int spacedSeedMaxWeight()
+/* Return max weight of spaced seed. */
+{
+return ArraySize(spacedSeeds)-1;
+}
+
+int *spacedSeedOffsets(int weight)
+/* Return array with offsets for seed of given weight. */
+{
+char *seed;
+int *output, offset, outCount = 0, seedSize;
+
+assert(weight >= 1 && weight < ArraySize(spacedSeeds));
+seed = spacedSeeds[weight];
+seedSize = strlen(seed);
+AllocArray(output, weight);
+for (offset=0; offset<seedSize; ++offset)
+    {
+    if (seed[offset] == '1')
+	output[outCount++] = offset;
+    }
+assert(outCount == weight);
+return output;
+}
+
+int spacedSeedSpan(int weight)
+/* Return span of seed of given weight */
+{
+return strlen(spacedSeeds[weight]);
+}
+
diff --git a/lib/sparc/placeHolder.c b/lib/sparc/placeHolder.c
new file mode 100755
index 0000000..e69de29
diff --git a/lib/splatAli.as b/lib/splatAli.as
new file mode 100644
index 0000000..0e8c7c0
--- /dev/null
+++ b/lib/splatAli.as
@@ -0,0 +1,12 @@
+table splatAli
+"A parsed out splat format alignment."
+    (
+    string chrom;	"Chromosome mapped to"
+    int chromStart;	"Start position in chromosome (zero based)"
+    int chromEnd;	"End position in genome (one based)"
+    string alignedBases;"Tag bases - in upper case for match, -/^ for insert/delete"
+    int score;		"Mapping score. 1000/placesMapped"
+    char[1] strand;     "+ or - for strand"
+    string readName;	"Name of read"
+    )
+
diff --git a/lib/splatAli.c b/lib/splatAli.c
new file mode 100644
index 0000000..dcd9809
--- /dev/null
+++ b/lib/splatAli.c
@@ -0,0 +1,234 @@
+/* splatAli.c was originally generated by the autoSql program, which also 
+ * generated splatAli.h and splatAli.sql.  This module links the database and
+ * the RAM representation of objects. */
+/* This file is copyright 2008 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "linefile.h"
+#include "dystring.h"
+#include "sqlNum.h"
+#include "sqlList.h"
+#include "splatAli.h"
+
+
+void splatAliStaticLoad(char **row, struct splatAli *ret)
+/* Load a row from splatAli table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+{
+
+ret->chrom = row[0];
+ret->chromStart = sqlSigned(row[1]);
+ret->chromEnd = sqlSigned(row[2]);
+ret->alignedBases = row[3];
+ret->score = sqlSigned(row[4]);
+safecpy(ret->strand, sizeof(ret->strand), row[5]);
+ret->readName = row[6];
+}
+
+struct splatAli *splatAliLoad(char **row)
+/* Load a splatAli from row fetched with select * from splatAli
+ * from database.  Dispose of this with splatAliFree(). */
+{
+struct splatAli *ret;
+
+AllocVar(ret);
+ret->chrom = cloneString(row[0]);
+ret->chromStart = sqlSigned(row[1]);
+ret->chromEnd = sqlSigned(row[2]);
+ret->alignedBases = cloneString(row[3]);
+ret->score = sqlSigned(row[4]);
+safecpy(ret->strand, sizeof(ret->strand), row[5]);
+ret->readName = cloneString(row[6]);
+return ret;
+}
+
+struct splatAli *splatAliLoadAll(char *fileName) 
+/* Load all splatAli from a whitespace-separated file.
+ * Dispose of this with splatAliFreeList(). */
+{
+struct splatAli *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[7];
+
+while (lineFileRow(lf, row))
+    {
+    el = splatAliLoad(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct splatAli *splatAliLoadAllByChar(char *fileName, char chopper) 
+/* Load all splatAli from a chopper separated file.
+ * Dispose of this with splatAliFreeList(). */
+{
+struct splatAli *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[7];
+
+while (lineFileNextCharRow(lf, chopper, row, ArraySize(row)))
+    {
+    el = splatAliLoad(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct splatAli *splatAliCommaIn(char **pS, struct splatAli *ret)
+/* Create a splatAli out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new splatAli */
+{
+char *s = *pS;
+
+if (ret == NULL)
+    AllocVar(ret);
+ret->chrom = sqlStringComma(&s);
+ret->chromStart = sqlSignedComma(&s);
+ret->chromEnd = sqlSignedComma(&s);
+ret->alignedBases = sqlStringComma(&s);
+ret->score = sqlSignedComma(&s);
+sqlFixedStringComma(&s, ret->strand, sizeof(ret->strand));
+ret->readName = sqlStringComma(&s);
+*pS = s;
+return ret;
+}
+
+void splatAliFree(struct splatAli **pEl)
+/* Free a single dynamically allocated splatAli such as created
+ * with splatAliLoad(). */
+{
+struct splatAli *el;
+
+if ((el = *pEl) == NULL) return;
+freeMem(el->chrom);
+freeMem(el->alignedBases);
+freeMem(el->readName);
+freez(pEl);
+}
+
+void splatAliFreeList(struct splatAli **pList)
+/* Free a list of dynamically allocated splatAli's */
+{
+struct splatAli *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    splatAliFree(&el);
+    }
+*pList = NULL;
+}
+
+void splatAliOutput(struct splatAli *el, FILE *f, char sep, char lastSep) 
+/* Print out splatAli.  Separate fields with sep. Follow last field with lastSep. */
+{
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->chrom);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%d", el->chromStart);
+fputc(sep,f);
+fprintf(f, "%d", el->chromEnd);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->alignedBases);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%d", el->score);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->strand);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->readName);
+if (sep == ',') fputc('"',f);
+fputc(lastSep,f);
+}
+
+/* -------------------------------- End autoSql Generated Code -------------------------------- */
+
+int splatAliCmpReadName(const void *va, const void *vb)
+/* Compare two based on readName. Also separate secondarily on chrom position. */
+{
+const struct splatAli *a = *((struct splatAli **)va);
+const struct splatAli *b = *((struct splatAli **)vb);
+int diff = strcmp(a->readName, b->readName);
+if (diff == 0)
+    diff = a->chromStart - b->chromStart;
+if (diff == 0)
+    diff = a->chromEnd - b->chromEnd;
+if (diff == 0)
+    diff = a->strand - b->strand;
+if (diff == 0)
+    diff = strcmp(a->chrom, b->chrom);
+return diff;
+}
+
+int splatAliScore(char *ali)
+/* Score splat-encoded alignment. */
+{
+int score = 0;
+char c;
+while ((c = *ali++))
+    {
+    switch (c)
+        {
+	case 'a':
+	case 'c':
+	case 'g':
+	case 't':
+	    score -= 2;
+	    break;
+	case 'A':
+	case 'C':
+	case 'G':
+	case 'T':
+	    score += 2;
+	    break;
+	case 'n':
+	case 'N':
+	    break;
+	case '^':
+	    score -= 3;
+	    ali += 1;
+	    break;
+	case '-':
+	    score -= 3;
+	    break;
+	}
+    }
+return score;
+}
+
+void splatAliLookForBest(struct splatAli *start, struct splatAli *end, 
+	int *retBestScore, int *retBestCount)
+/* Scan through list from start up to but not including end (which may be NULL)
+ * and figure out best score and number of elements in list with that score. */
+{
+int bestScore = 0, bestCount = 0;
+struct splatAli *el;
+for (el = start; el != end; el = el->next)
+    {
+    int score = splatAliScore(el->alignedBases);
+    if (score >= bestScore)
+        {
+	if (score > bestScore)
+	    {
+	    bestScore = score;
+	    bestCount = 1;
+	    }
+	else
+	    bestCount += 1;
+	}
+    }
+*retBestScore = bestScore;
+*retBestCount = bestCount;
+}
+
diff --git a/lib/sqlList.c b/lib/sqlList.c
new file mode 100644
index 0000000..fbfce7e
--- /dev/null
+++ b/lib/sqlList.c
@@ -0,0 +1,1306 @@
+/* Stuff for processing comma separated lists - a little long so
+ * in a separate module from jksql.c though interface is still
+ * in jksql.c. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+/* The various static routines sql<Type>StaticArray are NOT thread-safe. */
+
+#include "common.h"
+#include "sqlNum.h"
+#include "sqlList.h"
+#include "dystring.h"
+#include "hash.h"
+
+
+int sqlByteArray(char *s, signed char *array, int arraySize)
+/* Convert comma separated list of numbers to an array.  Pass in 
+ * array an max size of array. */
+{
+unsigned count = 0;
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0 || count == arraySize)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    array[count++] = sqlSigned(s);
+    s = e;
+    }
+return count;
+}
+
+void sqlByteStaticArray(char *s, signed char **retArray, int *retSize)
+/* Convert comma separated list of numbers to an array which will be
+ * overwritten next call to this function, but need not be freed. */
+{
+static signed char *array = NULL;
+static unsigned alloc = 0;
+unsigned count = 0;
+
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    if (count >= alloc)
+	{
+	if (alloc == 0)
+	    alloc = 64;
+	else
+	    alloc <<= 1;
+	ExpandArray(array, count, alloc);
+	}
+    array[count++] = sqlSigned(s);
+    s = e;
+    }
+*retSize = count;
+*retArray = array;
+}
+
+void sqlByteDynamicArray(char *s, signed char **retArray, int *retSize)
+/* Convert comma separated list of numbers to an dynamically allocated
+ * array, which should be freeMem()'d when done. Thread-safe. */
+{
+signed char *array = NULL;
+int count = 0;
+
+if (s)
+    {
+    count = countSeparatedItems(s, ',');
+    if (count > 0)
+	{
+	AllocArray(array, count);
+	count = 0;
+	for (;;)
+	    {
+	    array[count++] = sqlSignedInList(&s);
+	    if (*s++ == 0)
+		break;
+	    if (*s == 0)
+		break;
+	    }
+	}
+    }
+*retArray = array;
+*retSize = count;
+}
+
+/*-------------------------*/
+
+int sqlUbyteArray(char *s, unsigned char *array, int arraySize)
+/* Convert comma separated list of numbers to an array.  Pass in 
+ * array an max size of array. */
+{
+unsigned count = 0;
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0 || count == arraySize)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    array[count++] = sqlUnsigned(s);
+    s = e;
+    }
+return count;
+}
+
+void sqlUbyteStaticArray(char *s, unsigned char **retArray, int *retSize)
+/* Convert comma separated list of numbers to an array which will be
+ * overwritten next call to this function, but need not be freed. */
+{
+static unsigned char *array = NULL;
+static unsigned alloc = 0;
+unsigned count = 0;
+
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    if (count >= alloc)
+	{
+	if (alloc == 0)
+	    alloc = 64;
+	else
+	    alloc <<= 1;
+	ExpandArray(array, count, alloc);
+	}
+    array[count++] = sqlUnsigned(s);
+    s = e;
+    }
+*retSize = count;
+*retArray = array;
+}
+
+void sqlUbyteDynamicArray(char *s, unsigned char **retArray, int *retSize)
+/* Convert comma separated list of numbers to an dynamically allocated
+ * array, which should be freeMem()'d when done. Thread-safe. */
+{
+unsigned char *array = NULL;
+int count = 0;
+
+if (s)
+    {
+    count = countSeparatedItems(s, ',');
+    if (count > 0)
+	{
+	AllocArray(array, count);
+	count = 0;
+	for (;;)
+	    {
+	    array[count++] = sqlUnsignedInList(&s);
+	    if (*s++ == 0)
+		break;
+	    if (*s == 0)
+		break;
+	    }
+	}
+    }
+*retArray = array;
+*retSize = count;
+}
+
+/*-------------------------*/
+
+int sqlCharArray(char *s, char *array, int arraySize)
+/* Convert comma separated list of chars to an array.  Pass in 
+ * array and max size of array. */
+{
+unsigned count = 0;
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0 || count == arraySize)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    array[count++] = s[0];
+    s = e;
+    }
+return count;
+}
+
+void sqlCharStaticArray(char *s, char **retArray, int *retSize)
+/* Convert comma separated list of chars to an array which will be
+ * overwritten next call to this function, but need not be freed. */
+{
+static char *array = NULL;
+static unsigned alloc = 0;
+unsigned count = 0;
+
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    if (count >= alloc)
+	{
+	if (alloc == 0)
+	    alloc = 64;
+	else
+	    alloc <<= 1;
+	ExpandArray(array, count, alloc);
+	}
+    array[count++] = s[0];
+    s = e;
+    }
+*retSize = count;
+*retArray = array;
+}
+
+void sqlCharDynamicArray(char *s, char **retArray, int *retSize)
+/* Convert comma separated list of chars to a dynamically allocated
+ * array, which should be freeMem()'d when done. Thread-safe. */
+{
+char *array = NULL;
+int count = 0;
+
+if (s)
+    {
+    count = countSeparatedItems(s, ',');
+    if (count > 0)
+	{
+	AllocArray(array, count);
+	count = 0;
+	for (;;)
+	    {
+	    if (*s == ',')
+		errAbort("Empty element in list. Each element should contain one character.");
+	    array[count++] = *s++;
+	    if (!(*s == 0 || *s == ','))
+		{
+		--s;
+		char *e = strchr(s, ',');
+		if (e)
+		    *e = 0;
+		errAbort("Invalid character: %s", s);
+		}
+	    if (*s++ == 0)
+		break;
+	    if (*s == 0)
+		break;
+	    }
+	}
+    }
+*retArray = array;
+*retSize = count;
+}
+
+/*-------------------------*/
+
+int sqlShortArray(char *s, short *array, int arraySize)
+/* Convert comma separated list of numbers to an array.  Pass in 
+ * array an max size of array. */
+{
+unsigned count = 0;
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0 || count == arraySize)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    array[count++] = sqlSigned(s);
+    s = e;
+    }
+return count;
+}
+
+void sqlShortStaticArray(char *s, short **retArray, int *retSize)
+/* Convert comma separated list of numbers to an array which will be
+ * overwritten next call to this function, but need not be freed. */
+{
+static short *array = NULL;
+static unsigned alloc = 0;
+unsigned count = 0;
+
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    if (count >= alloc)
+	{
+	if (alloc == 0)
+	    alloc = 64;
+	else
+	    alloc <<= 1;
+	ExpandArray(array, count, alloc);
+	}
+    array[count++] = sqlSigned(s);
+    s = e;
+    }
+*retSize = count;
+*retArray = array;
+}
+
+void sqlShortDynamicArray(char *s, short **retArray, int *retSize)
+/* Convert comma separated list of numbers to an dynamically allocated
+ * array, which should be freeMem()'d when done. Thread-safe. */
+{
+short *array = NULL;
+int count = 0;
+
+if (s)
+    {
+    count = countSeparatedItems(s, ',');
+    if (count > 0)
+	{
+	AllocArray(array, count);
+	count = 0;
+	for (;;)
+	    {
+	    array[count++] = sqlSignedInList(&s);
+	    if (*s++ == 0)
+		break;
+	    if (*s == 0)
+		break;
+	    }
+	}
+    }
+*retArray = array;
+*retSize = count;
+}
+
+/*-------------------------*/
+
+int sqlUshortArray(char *s, unsigned short *array, int arraySize)
+/* Convert comma separated list of numbers to an array.  Pass in 
+ * array an max size of array. */
+{
+unsigned count = 0;
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0 || count == arraySize)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    array[count++] = sqlUnsigned(s);
+    s = e;
+    }
+return count;
+}
+
+void sqlUshortStaticArray(char *s, unsigned short **retArray, int *retSize)
+/* Convert comma separated list of numbers to an array which will be
+ * overwritten next call to this function, but need not be freed. */
+{
+static unsigned short *array = NULL;
+static unsigned alloc = 0;
+unsigned count = 0;
+
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    if (count >= alloc)
+	{
+	if (alloc == 0)
+	    alloc = 64;
+	else
+	    alloc <<= 1;
+	ExpandArray(array, count, alloc);
+	}
+    array[count++] = sqlUnsigned(s);
+    s = e;
+    }
+*retSize = count;
+*retArray = array;
+}
+
+void sqlUshortDynamicArray(char *s, unsigned short **retArray, int *retSize)
+/* Convert comma separated list of numbers to an dynamically allocated
+ * array, which should be freeMem()'d when done. Thread-safe. */
+{
+unsigned short *array = NULL;
+int count = 0;
+
+if (s)
+    {
+    count = countSeparatedItems(s, ',');
+    if (count > 0)
+	{
+	AllocArray(array, count);
+	count = 0;
+	for (;;)
+	    {
+	    array[count++] = sqlUnsignedInList(&s);
+	    if (*s++ == 0)
+		break;
+	    if (*s == 0)
+		break;
+	    }
+	}
+    }
+*retArray = array;
+*retSize = count;
+}
+
+/*-------------------------*/
+int sqlDoubleArray(char *s, double *array, int maxArraySize)
+/* Convert comma separated list of floating point numbers to an array.  
+ * Pass in array and max size of array. */
+{
+unsigned count = 0;
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0 || count == maxArraySize)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    array[count++] = atof(s);
+    s = e;
+    }
+return count;
+}
+
+
+int sqlFloatArray(char *s, float *array, int maxArraySize)
+/* Convert comma separated list of floating point numbers to an array.  
+ * Pass in array and max size of array. */
+{
+unsigned count = 0;
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0 || count == maxArraySize)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    array[count++] = atof(s);
+    s = e;
+    }
+return count;
+}
+
+void sqlDoubleStaticArray(char *s, double **retArray, int *retSize)
+/* Convert comma separated list of numbers to an array which will be
+ * overwritten next call to this function, but need not be freed. */
+{
+static double *array = NULL;
+static unsigned alloc = 0;
+unsigned count = 0;
+
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    if (count >= alloc)
+	{
+	if (alloc == 0)
+	    alloc = 64;
+	else
+	    alloc <<= 1;
+	ExpandArray(array, count, alloc);
+	}
+    array[count++] = atof(s);
+    s = e;
+    }
+*retSize = count;
+*retArray = array;
+}
+
+void sqlFloatStaticArray(char *s, float **retArray, int *retSize)
+/* Convert comma separated list of numbers to an array which will be
+ * overwritten next call to this function, but need not be freed. */
+{
+static float *array = NULL;
+static unsigned alloc = 0;
+unsigned count = 0;
+
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    if (count >= alloc)
+	{
+	if (alloc == 0)
+	    alloc = 128;
+	else
+	    alloc <<= 1;
+	ExpandArray(array, count, alloc);
+	}
+    array[count++] = atof(s);
+    s = e;
+    }
+*retSize = count;
+*retArray = array;
+}
+
+void sqlDoubleDynamicArray(char *s, double **retArray, int *retSize)
+/* Convert comma separated list of numbers to an dynamically allocated
+ * array, which should be freeMem()'d when done. Thread-safe.*/
+{
+double *array = NULL;
+int count = 0;
+
+if (s)
+    {
+    count = countSeparatedItems(s, ',');
+    if (count > 0)
+	{
+	AllocArray(array, count);
+	count = 0;
+	for (;;)
+	    {
+	    array[count++] = sqlDoubleInList(&s);
+	    if (*s++ == 0)
+		break;
+	    if (*s == 0)
+		break;
+	    }
+	}
+    }
+*retArray = array;
+*retSize = count;
+}
+
+void sqlFloatDynamicArray(char *s, float **retArray, int *retSize)
+/* Convert comma separated list of numbers to an dynamically allocated
+ * array, which should be freeMem()'d when done. Thread-safe. */
+{
+float *array = NULL;
+int count = 0;
+
+if (s)
+    {
+    count = countSeparatedItems(s, ',');
+    if (count > 0)
+	{
+	AllocArray(array, count);
+	count = 0;
+	for (;;)
+	    {
+	    array[count++] = sqlFloatInList(&s);
+	    if (*s++ == 0)
+		break;
+	    if (*s == 0)
+		break;
+	    }
+	}
+    }
+*retArray = array;
+*retSize = count;
+}
+
+/*-------------------------*/
+
+int sqlUnsignedArray(char *s, unsigned *array, int arraySize)
+/* Convert comma separated list of numbers to an array.  Pass in 
+ * array and max size of array. */
+{
+unsigned count = 0;
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0 || count == arraySize)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    array[count++] = sqlUnsigned(s);
+    s = e;
+    }
+return count;
+}
+
+void sqlUnsignedStaticArray(char *s, unsigned **retArray, int *retSize)
+/* Convert comma separated list of numbers to an array which will be
+ * overwritten next call to this function, but need not be freed. */
+{
+static unsigned *array = NULL;
+static unsigned alloc = 0;
+unsigned count = 0;
+
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    if (count >= alloc)
+	{
+	if (alloc == 0)
+	    alloc = 64;
+	else
+	    alloc <<= 1;
+	ExpandArray(array, count, alloc);
+	}
+    array[count++] = sqlUnsigned(s);
+    s = e;
+    }
+*retSize = count;
+*retArray = array;
+}
+
+void sqlUnsignedDynamicArray(char *s, unsigned **retArray, int *retSize)
+/* Convert comma separated list of numbers to an dynamically allocated
+ * array, which should be freeMem()'d when done. Thread-safe. */
+{
+unsigned *array = NULL;
+int count = 0;
+
+if (s)
+    {
+    count = countSeparatedItems(s, ',');
+    if (count > 0)
+	{
+	AllocArray(array, count);
+	count = 0;
+	for (;;)
+	    {
+	    array[count++] = sqlUnsignedInList(&s);
+	    if (*s++ == 0)
+		break;
+	    if (*s == 0)
+		break;
+	    }
+	}
+    }
+*retArray = array;
+*retSize = count;
+}
+
+/*-------------------------*/
+
+int sqlSignedArray(char *s, int *array, int arraySize)
+/* Convert comma separated list of numbers to an array.  Pass in 
+ * array an max size of array. */
+{
+int count = 0;
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0 || count == arraySize)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    array[count++] = sqlSigned(s);
+    s = e;
+    }
+return count;
+}
+
+void sqlSignedStaticArray(char *s, int **retArray, int *retSize)
+/* Convert comma separated list of numbers to an array which will be
+ * overwritten next call to this function, but need not be freed. */
+{
+static int *array = NULL;
+static int alloc = 0;
+int count = 0;
+
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    if (count >= alloc)
+	{
+	if (alloc == 0)
+	    alloc = 64;
+	else
+	    alloc <<= 1;
+	ExpandArray(array, count, alloc);
+	}
+    array[count++] = sqlSigned(s);
+    s = e;
+    }
+*retSize = count;
+*retArray = array;
+}
+
+void sqlSignedDynamicArray(char *s, int **retArray, int *retSize)
+/* Convert comma separated list of numbers to an dynamically allocated
+ * array, which should be freeMem()'d when done. Thread-safe. */
+{
+int *array = NULL;
+int count = 0;
+
+if (s)
+    {
+    count = countSeparatedItems(s, ',');
+    if (count > 0)
+	{
+	AllocArray(array, count);
+	count = 0;
+	for (;;)
+	    {
+	    array[count++] = sqlSignedInList(&s);
+	    if (*s++ == 0)
+		break;
+	    if (*s == 0)
+		break;
+	    }
+	}
+    }
+*retArray = array;
+*retSize = count;
+}
+
+
+/*-------------------------*/
+
+int sqlLongLongArray(char *s, long long *array, int arraySize)
+/* Convert comma separated list of numbers to an array.  Pass in 
+ * array and max size of array. */
+{
+unsigned count = 0;
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0 || count == arraySize)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    array[count++] = sqlLongLong(s);
+    s = e;
+    }
+return count;
+}
+
+void sqlLongLongStaticArray(char *s, long long **retArray, int *retSize)
+/* Convert comma separated list of numbers to an array which will be
+ * overwritten next call to this function, but need not be freed. */
+{
+static long long *array = NULL;
+static unsigned alloc = 0;
+unsigned count = 0;
+
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    if (count >= alloc)
+	{
+	if (alloc == 0)
+	    alloc = 64;
+	else
+	    alloc <<= 1;
+	ExpandArray(array, count, alloc);
+	}
+    array[count++] = sqlLongLong(s);
+    s = e;
+    }
+*retSize = count;
+*retArray = array;
+}
+
+void sqlLongLongDynamicArray(char *s, long long **retArray, int *retSize)
+/* Convert comma separated list of numbers to an dynamically allocated
+ * array, which should be freeMem()'d when done. Thread-safe. */
+{
+long long *array = NULL;
+int count = 0;
+
+if (s)
+    {
+    count = countSeparatedItems(s, ',');
+    if (count > 0)
+	{
+	AllocArray(array, count);
+	count = 0;
+	for (;;)
+	    {
+	    array[count++] = sqlLongLongInList(&s);
+	    if (*s++ == 0)
+		break;
+	    if (*s == 0)
+		break;
+	    }
+	}
+    }
+*retArray = array;
+*retSize = count;
+}
+
+/*-------------------------*/
+
+
+int sqlStringArray(char *s, char **array, int maxArraySize)
+/* Convert comma separated list of strings to an array.  Pass in 
+ * array and max size of array.  Returns actual size*/
+{
+int count = 0;
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0 || count == maxArraySize)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    array[count++] = s;
+    s = e;
+    }
+return count;
+}
+
+void sqlStringStaticArray(char *s, char  ***retArray, int *retSize)
+/* Convert comma separated list of strings to an array which will be
+ * overwritten next call to this function,  but need not be freed. */
+{
+static char **array = NULL;
+static int alloc = 0;
+int count = 0;
+
+for (;;)
+    {
+    char *e;
+    if (s == NULL || s[0] == 0)
+	break;
+    e = strchr(s, ',');
+    if (e != NULL)
+	*e++ = 0;
+    if (count >= alloc)
+	{
+	if (alloc == 0)
+	    alloc = 64;
+	else
+	    alloc <<= 1;
+	ExpandArray(array, count, alloc);
+	}
+    array[count++] = s;
+    s = e;
+    }
+*retSize = count;
+*retArray = array;
+}
+
+void sqlStringDynamicArray(char *s, char ***retArray, int *retSize)
+/* Convert comma separated list of strings to an dynamically allocated
+ * array, which should be freeMem()'d when done. As a speed option all
+ * of the elements in the array are needMem()'d at the same time. This 
+ * means that all the entries are free()'d by calling freeMem() on the
+ * first element. For example:
+ * sqlStringDynamicArray(s, &retArray, &retSize);
+ * DoSomeFunction(retArray, retSize);
+ * freeMem(retArray[0]);
+ * freeMem(retArray);
+ * Thread-safe. */
+{
+char **array = NULL;
+int count = 0;
+if (s)
+    {
+    count = countSeparatedItems(s, ',');
+    if (count > 0)
+	{
+	AllocArray(array, count);
+	count = 0;
+	s = cloneString(s);
+	for (;;)
+	    {
+	    char *e;
+	    if (s == NULL || s[0] == 0)
+		break;
+	    e = strchr(s, ',');
+	    if (e != NULL)
+		*e++ = 0;
+	    array[count++] = s;
+	    s = e;
+	    }
+	}
+    }
+*retArray = array;
+*retSize = count;
+}
+
+char *sqlDoubleArrayToString( double *array, int arraySize)
+{
+int i;
+struct dyString *string = newDyString(256);
+char *toRet = NULL;
+for( i = 0 ; i < arraySize; i++ )
+    {
+    dyStringPrintf(string, "%f,", array[i]);
+    }
+toRet = cloneString(string->string);
+dyStringFree(&string);
+return toRet;
+}
+
+char *sqlFloatArrayToString( float *array, int arraySize)
+{
+int i;
+struct dyString *string = newDyString(256);
+char *toRet = NULL;
+for( i = 0 ; i < arraySize; i++ )
+    {
+    dyStringPrintf(string, "%f,", array[i]);
+    }
+toRet = cloneString(string->string);
+dyStringFree(&string);
+return toRet;
+}
+
+char *sqlUnsignedArrayToString( unsigned *array, int arraySize)
+{
+int i;
+struct dyString *string = newDyString(256);
+char *toRet = NULL;
+for( i = 0 ; i < arraySize; i++ )
+    {
+    dyStringPrintf(string, "%u,", array[i]);
+    }
+toRet = cloneString(string->string);
+dyStringFree(&string);
+return toRet;
+}
+
+char *sqlSignedArrayToString( int *array, int arraySize)
+{
+int i;
+struct dyString *string = newDyString(256);
+char *toRet = NULL;
+for( i = 0 ; i < arraySize; i++ )
+    {
+    dyStringPrintf(string, "%d,", array[i]);
+    }
+toRet = cloneString(string->string);
+dyStringFree(&string);
+return toRet;
+}
+
+char *sqlShortArrayToString( short *array, int arraySize)
+{
+int i;
+struct dyString *string = newDyString(256);
+char *toRet = NULL;
+for( i = 0 ; i < arraySize; i++ )
+    {
+    dyStringPrintf(string, "%d,", array[i]);
+    }
+toRet = cloneString(string->string);
+dyStringFree(&string);
+return toRet;
+}
+
+char *sqlUshortArrayToString( unsigned short *array, int arraySize)
+{
+int i;
+struct dyString *string = newDyString(256);
+char *toRet = NULL;
+for( i = 0 ; i < arraySize; i++ )
+    {
+    dyStringPrintf(string, "%u,", array[i]);
+    }
+toRet = cloneString(string->string);
+dyStringFree(&string);
+return toRet;
+}
+
+char *sqlByteArrayToString( signed char *array, int arraySize)
+{
+int i;
+struct dyString *string = newDyString(256);
+char *toRet = NULL;
+for( i = 0 ; i < arraySize; i++ )
+    {
+    dyStringPrintf(string, "%d,", array[i]);
+    }
+toRet = cloneString(string->string);
+dyStringFree(&string);
+return toRet;
+}
+
+char *sqlUbyteArrayToString( unsigned char *array, int arraySize)
+{
+int i;
+struct dyString *string = newDyString(256);
+char *toRet = NULL;
+for( i = 0 ; i < arraySize; i++ )
+    {
+    dyStringPrintf(string, "%u,", array[i]);
+    }
+toRet = cloneString(string->string);
+dyStringFree(&string);
+return toRet;
+}
+
+char *sqlCharArrayToString( char *array, int arraySize)
+{
+int i;
+struct dyString *string = newDyString(256);
+char *toRet = NULL;
+for( i = 0 ; i < arraySize; i++ )
+    {
+    dyStringPrintf(string, "%c,", array[i]);
+    }
+toRet = cloneString(string->string);
+dyStringFree(&string);
+return toRet;
+}
+
+char *sqlLongLongArrayToString( long long *array, int arraySize)
+{
+int i;
+struct dyString *string = newDyString(256);
+char *toRet = NULL;
+for( i = 0 ; i < arraySize; i++ )
+    {
+    dyStringPrintf(string, "%lld,", array[i]);
+    }
+toRet = cloneString(string->string);
+dyStringFree(&string);
+return toRet;
+}
+
+char *sqlStringArrayToString( char **array, int arraySize)
+{
+int i;
+struct dyString *string = newDyString(256);
+char *toRet = NULL;
+for( i = 0 ; i < arraySize; i++ )
+    {
+    dyStringPrintf(string, "%s,", array[i]);
+    }
+toRet = cloneString(string->string);
+dyStringFree(&string);
+return toRet;
+}
+
+
+/* -------------- */
+
+
+
+void sqlStringFreeDynamicArray(char ***pArray)
+/* Free up a dynamic array (ends up freeing array and first string on it.) */
+{
+char **array;
+if ((array = *pArray) != NULL)
+    {
+    freeMem(array[0]);
+    freez(pArray);
+    }
+}
+
+int sqlUnsignedComma(char **pS)
+/* Return signed number at *pS.  Advance *pS past comma at end */
+{
+char *s = *pS;
+char *e = strchr(s, ',');
+unsigned ret;
+
+*e++ = 0;
+*pS = e;
+ret = sqlUnsigned(s);
+return ret;
+}
+
+
+int sqlSignedComma(char **pS)
+/* Return signed number at *pS.  Advance *pS past comma at end */
+{
+char *s = *pS;
+char *e = strchr(s, ',');
+int ret;
+
+*e++ = 0;
+*pS = e;
+ret = sqlSigned(s);
+return ret;
+}
+
+char sqlCharComma(char **pS)
+/* Return char at *pS.  Advance *pS past comma after char */
+{
+char *s = *pS;
+char *e = strchr(s, ',');
+int ret;
+
+*e++ = 0;
+*pS = e;
+ret = s[0];
+return ret;
+}
+
+long long sqlLongLongComma(char **pS)
+/* Return offset (often 64 bits) at *pS.  Advance *pS past comma at 
+ * end */
+{
+char *s = *pS;
+char *e = strchr(s, ',');
+long long ret;
+
+*e++ = 0;
+*pS = e;
+ret = sqlLongLong(s);
+return ret;
+}
+
+float sqlFloatComma(char **pS)
+/* Return signed number at *pS.  Advance *pS past comma at end */
+{
+char *s = *pS;
+char *e = strchr(s, ',');
+float ret;
+
+*e++ = 0;
+*pS = e;
+ret = atof(s);
+return ret;
+}
+
+double sqlDoubleComma(char **pS)
+/* Return signed number at *pS.  Advance *pS past comma at end */
+{
+char *s = *pS;
+char *e = strchr(s, ',');
+double ret;
+
+*e++ = 0;
+*pS = e;
+ret = atof(s);
+return ret;
+}
+
+
+static char *findStringEnd(char *start, char endC)
+/* Return end of string. */
+{
+char c;
+char *s = start;
+
+for (;;)
+    {
+    c = *s;
+    if (c == endC)
+	return s;
+    else if (c == 0)
+	errAbort("Unterminated string");
+    ++s;
+    }
+}
+
+static char *sqlGetOptQuoteString(char **pS)
+/* Return string at *pS.  (Either quoted or not.)  Advance *pS. */
+{
+char *s = *pS;
+char *e;
+char c = *s;
+
+if (c  == '"' || c == '\'')
+    {
+    s += 1;
+    e = findStringEnd(s, c);
+    *e++ = 0;
+    if (*e++ != ',')
+	errAbort("Expecting comma after string");
+    }
+else
+    {
+    e = strchr(s, ',');
+    *e++ = 0;
+    }
+*pS = e;
+return s;
+}
+
+char *sqlStringComma(char **pS)
+/* Return string at *pS.  (Either quoted or not.)  Advance *pS. */
+{
+return cloneString(sqlGetOptQuoteString(pS));
+}
+
+void sqlFixedStringComma(char **pS, char *buf, int bufSize)
+/* Copy string at *pS to buf.  Advance *pS. */
+{
+strncpy(buf, sqlGetOptQuoteString(pS), bufSize);
+}
+
+char *sqlEatChar(char *s, char c)
+/* Make sure next character is 'c'.  Return past next char */
+{
+if (*s++ != c)
+    errAbort("Expecting %c got %c (%d) in database", c, s[-1], s[-1]);
+return s;
+}
+
+static struct hash *buildSymHash(char **values, boolean isEnum)
+/* build a hash of values for either enum or set symbolic column */
+{
+struct hash *valHash = hashNew(0);
+unsigned setVal = 1; /* not used for enum */
+int iVal;
+for (iVal = 0; values[iVal] != NULL; iVal++)
+    {
+    if (isEnum)
+        hashAddInt(valHash, values[iVal], iVal);
+    else
+        {
+        hashAddInt(valHash, values[iVal], setVal);
+        setVal = setVal << 1;
+        }
+    }
+return valHash;
+}
+
+unsigned sqlEnumParse(char *valStr, char **values, struct hash **valHashPtr)
+/* parse an enumerated column value */
+{
+if (*valHashPtr == NULL)
+    *valHashPtr = buildSymHash(values, TRUE);
+return hashIntVal(*valHashPtr, valStr);
+}
+
+unsigned sqlEnumComma(char **pS, char **values, struct hash **valHashPtr)
+/* Return enum at *pS.  (Either quoted or not.)  Advance *pS. */
+{
+return sqlEnumParse(sqlGetOptQuoteString(pS), values, valHashPtr);
+}
+
+void sqlEnumPrint(FILE *f, unsigned value, char **values)
+/* print an enumerated column value */
+{
+fputs(values[value], f);
+}
+
+unsigned sqlSetParse(char *valStr, char **values, struct hash **valHashPtr)
+/* parse a set column value */
+{
+if (*valHashPtr == NULL)
+    *valHashPtr = buildSymHash(values, FALSE);
+/* parse comma separated string */
+unsigned value = 0;
+char *val = strtok(valStr, ",");
+while (val != NULL)
+    {
+    value |= hashIntVal(*valHashPtr, val);
+    val = strtok(NULL, ",");
+    }
+
+return value;
+}
+
+unsigned sqlSetComma(char **pS, char **values, struct hash **valHashPtr)
+/* Return set at *pS.  (Either quoted or not.)  Advance *pS. */
+{
+return sqlSetParse(sqlGetOptQuoteString(pS), values, valHashPtr);
+}
+
+void sqlSetPrint(FILE *f, unsigned value, char **values)
+/* print a set column value */
+{
+int iVal;
+unsigned curVal = 1;
+int cnt = 0;
+for (iVal = 0; values[iVal] != NULL; iVal++, curVal = curVal << 1)
+    {
+    if (curVal & value)
+        {
+        if (cnt > 0)
+            fputc(',', f);
+        fputs(values[iVal], f);
+        cnt++;
+        }
+    }
+}
diff --git a/lib/sqlNum.c b/lib/sqlNum.c
new file mode 100644
index 0000000..081f857
--- /dev/null
+++ b/lib/sqlNum.c
@@ -0,0 +1,301 @@
+/* sqlnum.c - Routines to convert from ascii to integer
+ * representation of numbers. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "sqlNum.h"
+
+/* The sql<Type>InList functions allow for fast thread-safe processing of dynamic arrays in sqlList */
+
+
+unsigned sqlUnsigned(char *s)
+/* Convert series of digits to unsigned integer about
+ * twice as fast as atoi (by not having to skip white 
+ * space or stop except at the null byte.) */
+{
+unsigned res = 0;
+char *p = s;
+char c;
+
+while (((c = *(p++)) >= '0') && (c <= '9'))
+    {
+    res *= 10;
+    res += c - '0';
+    }
+--p;
+/* test for invalid character or empty */
+if ((c != '\0') || (p == s))
+    errAbort("invalid unsigned integer: \"%s\"", s);
+return res;
+}
+
+unsigned sqlUnsignedInList(char **pS)
+/* Convert series of digits to unsigned integer about
+ * twice as fast as atoi (by not having to skip white 
+ * space or stop except at the null byte.) 
+ * All of string is number. Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+{
+char *s = *pS;
+unsigned res = 0;
+char *p = s;
+char c;
+
+while (((c = *(p++)) >= '0') && (c <= '9'))
+    {
+    res *= 10;
+    res += c - '0';
+    }
+--p;
+if (!(c == '\0' || c == ',') || (p == s))
+    {
+    char *e = strchr(s, ',');
+    if (e)
+	*e = 0;
+    errAbort("invalid unsigned integer: \"%s\"", s);
+    }
+*pS = p;
+return res;
+}
+
+unsigned long sqlUnsignedLong(char *s)
+/* Convert series of digits to unsigned long about
+ * twice as fast as atol (by not having to skip white 
+ * space or stop except at the null byte.) */
+{
+unsigned long res = 0;
+char *p = s;
+char c;
+
+while (((c = *(p++)) >= '0') && (c <= '9'))
+    {
+    res *= 10;
+    res += c - '0';
+    }
+--p;
+if ((c != '\0') || (p == s))
+    errAbort("invalid unsigned long: \"%s\"", s);
+return res;
+}
+
+unsigned long sqlUnsignedLongInList(char **pS)
+/* Convert series of digits to unsigned long about
+ * twice as fast as atol (by not having to skip white 
+ * space or stop except at the null byte.) 
+ * All of string is number. Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+{
+char *s = *pS;
+unsigned long res = 0;
+char *p = s;
+char c;
+
+while (((c = *(p++)) >= '0') && (c <= '9'))
+    {
+    res *= 10;
+    res += c - '0';
+    }
+--p;
+if (!(c == '\0' || c == ',') || (p == s))
+    {
+    char *e = strchr(s, ',');
+    if (e)
+	*e = 0;
+    errAbort("invalid unsigned long: \"%s\"", s);
+    }
+*pS = p;
+return res;
+}
+
+int sqlSigned(char *s)
+/* Convert string to signed integer.  Unlike atol assumes 
+ * all of string is number. */
+{
+int res = 0;
+char *p, *p0 = s;
+
+if (*p0 == '-')
+    p0++;
+p = p0;
+while ((*p >= '0') && (*p <= '9'))
+    {
+    res *= 10;
+    res += *p - '0';
+    p++;
+    }
+/* test for invalid character, empty, or just a minus */
+if ((*p != '\0') || (p == p0))
+    errAbort("invalid signed integer: \"%s\"", s);
+if (*s == '-')
+    return -res;
+else
+    return res;
+}
+
+int sqlSignedInList(char **pS)
+/* Convert string to signed integer.  Unlike atol assumes 
+ * all of string is number. Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+{
+char *s = *pS;
+int res = 0;
+char *p, *p0 = s;
+
+if (*p0 == '-')
+    p0++;
+p = p0;
+while ((*p >= '0') && (*p <= '9'))
+    {
+    res *= 10;
+    res += *p - '0';
+    p++;
+    }
+/* test for invalid character, empty, or just a minus */
+if (!(*p == '\0' || *p == ',') || (p == p0))
+    {
+    char *e = strchr(s, ',');
+    if (e)
+	*e = 0;
+    errAbort("invalid signed integer: \"%s\"", s);
+    }
+*pS = p;
+if (*s == '-')
+    return -res;
+else
+    return res;
+}
+
+long long sqlLongLong(char *s)
+/* Convert string to a long long.  Unlike atol assumes all of string is
+ * number. */
+{
+long long res = 0;
+char *p, *p0 = s;
+
+if (*p0 == '-')
+    p0++;
+p = p0;
+while ((*p >= '0') && (*p <= '9'))
+    {
+    res *= 10;
+    res += *p - '0';
+    p++;
+    }
+/* test for invalid character, empty, or just a minus */
+if ((*p != '\0') || (p == p0))
+    errAbort("invalid signed long long: \"%s\"", s);
+if (*s == '-')
+    return -res;
+else
+    return res;
+}
+
+long long sqlLongLongInList(char **pS)
+/* Convert string to a long long.  Unlike atol, assumes 
+ * all of string is number. Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+{
+char *s = *pS;
+long long res = 0;
+char *p, *p0 = s;
+
+if (*p0 == '-')
+    p0++;
+p = p0;
+while ((*p >= '0') && (*p <= '9'))
+    {
+    res *= 10;
+    res += *p - '0';
+    p++;
+    }
+/* test for invalid character, empty, or just a minus */
+if (!(*p == '\0' || *p == ',') || (p == p0))
+    {
+    char *e = strchr(s, ',');
+    if (e)
+	*e = 0;
+    errAbort("invalid signed long long: \"%s\"", s);
+    }
+*pS = p;
+if (*s == '-')
+    return -res;
+else
+    return res;
+}
+
+float sqlFloat(char *s)
+/* Convert string to a float.  Assumes all of string is number
+ * and aborts on an error. */
+{
+char* end;
+/*	used to have an ifdef here to use strtof() but that doesn't
+ *	actually exist on all systems and since strtod() does, may as
+ *	well use it since it will do the job here.
+ */
+float val = (float) strtod(s, &end);
+
+if ((end == s) || (*end != '\0'))
+    errAbort("invalid float: %s", s);
+return val;
+}
+
+float sqlFloatInList(char **pS)
+/* Convert string to a float.  Assumes all of string is number
+ * and aborts on an error. 
+ * Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+{
+char *s = *pS;
+char* end;
+/*	used to have an ifdef here to use strtof() but that doesn't
+ *	actually exist on all systems and since strtod() does, may as
+ *	well use it since it will do the job here.
+ */
+float val = (float) strtod(s, &end);
+
+if ((end == s) || !(*end == '\0' || *end == ','))
+    {
+    char *e = strchr(s, ',');
+    if (e)
+	*e = 0;
+    errAbort("invalid float: %s", s);
+    }
+*pS = end;
+return val;
+}
+
+double sqlDouble(char *s)
+/* Convert string to a double.  Assumes all of string is number
+ * and aborts on an error. */
+{
+char* end;
+double val = strtod(s, &end);
+
+if ((end == s) || (*end != '\0'))
+    errAbort("invalid double: %s", s);
+return val;
+}
+
+double sqlDoubleInList(char **pS)
+/* Convert string to a double.  Assumes all of string is number
+ * and aborts on an error.
+ * Number may be delimited by a comma.
+ * Returns the position of the delimiter or the terminating 0. */
+{
+char *s = *pS;
+char* end;
+double val = strtod(s, &end);
+
+if ((end == s) || !(*end == '\0' || *end == ','))
+    {
+    char *e = strchr(s, ',');
+    if (e)
+        *e = 0;
+    errAbort("invalid double: %s", s);
+    }
+*pS = end;
+return val;
+}
+
diff --git a/lib/status b/lib/status
new file mode 100644
index 0000000..ce92227
--- /dev/null
+++ b/lib/status
@@ -0,0 +1,482 @@
+# On branch master
+# Your branch and 'origin/master' have diverged,
+# and have 6 and 10 different commit(s) each, respectively.
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#   (use "git checkout -- <file>..." to discard changes in working directory)
+#
+#	modified:   ../hg/makeDb/trackDb/human/hg19/metaDb/alpha/wgEncodeReg.ra
+#	modified:   ../utils/textBetween/textBetween.c
+#	modified:   ../utils/verticalSplitSqlTable/verticalSplitSqlTable.c
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#	../../clean.log
+#	../../compile.log
+#	../../diff
+#	../../foo2
+#	../../pull
+#	../../python/.styleCommentsJk.txt.swp
+#	../../python/ENV/
+#	../../python/idioms.txt
+#	../../python/makefile
+#	../../python/users/kent/
+#	../../python/users/makefile
+#	../ai/wordChain/996
+#	../ai/wordChain/donQuixote.chain
+#	../ai/wordChain/donQuixote.non
+#	../ai/wordChain/donQuixote.txt
+#	../ai/wordChain/foo.chain
+#	../ai/wordChain/foo.nonsense
+#	../ai/wordChain/jumbled.txt
+#	../ai/wordChain/nonsense
+#	../ai/wordChain/pull
+#	../ai/wordChain/questions
+#	../ai/wordChain/quixote.chain
+#	../ai/wordChain/short.txt
+#	../blat/mCrea.geno.rc
+#	../diff
+#	../diffs
+#	../foo2
+#	../hg/autoSql/foo.c
+#	../hg/autoSql/foo.django
+#	../hg/autoSql/foo.h
+#	../hg/autoSql/foo.sql
+#	../hg/autoSql/out/
+#	../hg/autoSql/status
+#	../hg/checkTableCoords/tests/1
+#	../hg/diffs
+#	../hg/encode/encodeMergeReplicates/foo1
+#	../hg/encode/encodeMergeReplicates/merged.narrowPeak
+#	../hg/encode/encodeMergeReplicates/out
+#	../hg/encode/encodeMergeReplicates/outRep1Rep2Add.narrowPeak
+#	../hg/encode/encodeMergeReplicates/outRep1Rep2AddAddMin.narrowPeak
+#	../hg/encode/encodeMergeReplicates/outRep1Rep2Agree.narrowPeak
+#	../hg/encode/encodeMergeReplicates/outRep1Rep2Default.narrowPeak
+#	../hg/encode/encodeMergeReplicates/outRep1Rep2Threshold10.narrowPeak
+#	../hg/encode/encodeMergeReplicatesBatch/doHud.sh
+#	../hg/encode/encodeMergeReplicatesBatch/hud.ra
+#	../hg/encode/encodeMergeReplicatesBatch/hudOut.ra
+#	../hg/encode/encodeMergeReplicatesBatch/inDir
+#	../hg/encode/encodeMergeReplicatesBatch/out.ra
+#	../hg/encode/encodeMergeReplicatesBatch/out.sh
+#	../hg/encode/encodeMergeReplicatesBatch/snyder.ra
+#	../hg/encode/encodeMergeReplicatesBatch/status
+#	../hg/hgGene/status
+#	../hg/hgGene/tags
+#	../hg/hgHubConnect/status
+#	../hg/hgTables/all.joiner
+#	../hg/hgTables/hgTablesTest.log
+#	../hg/hgTables/status
+#	../hg/hgTables/tags
+#	../hg/hgTablesTest/log
+#	../hg/hgTrackUi/coo
+#	../hg/hgTrackUi/status
+#	../hg/hgTracks/bam.ra
+#	../hg/hgTracks/blame
+#	../hg/hgTracks/cart.ra
+#	../hg/hgTracks/diff
+#	../hg/hgTracks/full
+#	../hg/hgTracks/gilt.out
+#	../hg/hgTracks/hgt/
+#	../hg/hgTracks/hgtIdeo/
+#	../hg/hgTracks/output.ps
+#	../hg/hgTracks/pull
+#	../hg/hgTracks/status
+#	../hg/hgTracks/tags
+#	../hg/hgTracks/track.ra
+#	../hg/hgTracks/track2.ra
+#	../hg/hgTracks/track3.ra
+#	../hg/hgc/status
+#	../hg/hgc/tags
+#	../hg/inc/omiciaUi.h
+#	../hg/inc/oregannoOther.h
+#	../hg/lib/blame
+#	../hg/lib/cart.new
+#	../hg/lib/diff
+#	../hg/lib/omiciaUi.c
+#	../hg/lib/oregannoOther.as
+#	../hg/lib/oregannoOther.c
+#	../hg/lib/oregannoOther.sql
+#	../hg/lib/pull
+#	../hg/lib/push
+#	../hg/lib/status
+#	../hg/logCrawl/encodeUserDbCrawl/foo2
+#	../hg/logCrawl/encodeUserDbCrawl/foo3
+#	../hg/logCrawl/encodeUserDbCrawl/foo4
+#	../hg/logCrawl/encodeUserDbCrawl/goo3
+#	../hg/logCrawl/encodeUserDbCrawl/out
+#	../hg/makeDb/doc/foo1
+#	../hg/makeDb/doc/hg18.old
+#	../hg/makeDb/doc/log
+#	../hg/makeDb/doc/status
+#	../hg/makeDb/genbank/bin/
+#	../hg/makeDb/genbank/lib/
+#	../hg/makeDb/schema/foo.joiner
+#	../hg/makeDb/schema/joinTwoInfo/hgFixed.snoop
+#	../hg/makeDb/schema/joinTwoInfo/snoop
+#	../hg/makeDb/schema/sp090821.snoop
+#	../hg/makeDb/schema/sp100331.snoop
+#	../hg/makeDb/schema/sp101005.snoop
+#	../hg/makeDb/schema/status
+#	../hg/makeDb/schema/uniProt.snoop
+#	../hg/makeDb/trackDb/allRas
+#	../hg/makeDb/trackDb/foo.ra
+#	../hg/makeDb/trackDb/human/hg18/myTrackDb.ra
+#	../hg/makeDb/trackDb/human/hg19/foo2.ra
+#	../hg/makeDb/trackDb/human/hg19/jkExperiments.ra
+#	../hg/makeDb/trackDb/status
+#	../hg/merge
+#	../hg/oneShot/cartSim/cartSim.log
+#	../hg/oneShot/cartSim/jorgesDbs/
+#	../hg/oneShot/cartSim/longInnoDb1/
+#	../hg/oneShot/cartSim/longRun1/
+#	../hg/oneShot/cartSim/longRun2/
+#	../hg/oneShot/cartSim/longRun3/
+#	../hg/oneShot/cartSim/notes
+#	../hg/oneShot/cartSimNoInsert/cartFreen.log
+#	../hg/oneShot/freen/foo.col
+#	../hg/oneShot/freen/foo1
+#	../hg/oneShot/freen/foo2
+#	../hg/oneShot/freen/good.out
+#	../hg/oneShot/freen/hg18.tracks
+#	../hg/oneShot/freen/test.html
+#	../hg/oneShot/freen/test.ra
+#	../hg/oneShot/testCvToSql/backup/
+#	../hg/oneShot/testCvToSql/cv.as
+#	../hg/oneShot/testCvToSql/cv.atree
+#	../hg/oneShot/testCvToSql/cv.django/
+#	../hg/oneShot/testCvToSql/cv.ra
+#	../hg/oneShot/testCvToSql/cv.sql
+#	../hg/oneShot/testCvToSql/cv.stats
+#	../hg/oneShot/testCvToSql/cv.tab/
+#	../hg/oneShot/testCvToSql/doIt
+#	../hg/oneShot/testCvToSql/literal/
+#	../hg/oneShot/testCvToSql/loadTabs
+#	../hg/oneShot/testCvToSql/makefile
+#	../hg/oneShot/testCvToSql/old.atree
+#	../hg/oneShot/testCvToSql/out
+#	../hg/oneShot/testCvToSql/pull
+#	../hg/oneShot/testCvToSql/raTagNames
+#	../hg/oneShot/testCvToSql/splitAntibody.ra
+#	../hg/oneShot/testCvToSql/status
+#	../hg/oneShot/testCvToSql/tableDescriptions.tab
+#	../hg/oneShot/testCvToSql/testCvToSql.out
+#	../hg/oneShot/testCvToSql/try/
+#	../hg/oneShot/testCvToSql/tryIt
+#	../hg/oneShot/tryNewColorOverlay/rna.lst
+#	../hg/oneShot/wgEncodeRegGenRa/status
+#	../hg/oneShot/wgEncodeRegTfbsDedupeHelp/
+#	../hg/protein/spToDb/blame
+#	../hg/protein/spToDb/spDbInno.sql
+#	../hg/protein/spToDb/spDbInnoDjango.sql
+#	../hg/protein/spToDb/spToDb.myVersion.c
+#	../hg/protein/spToDb/subs.in
+#	../hg/regulate/companion/hive
+#	../hg/regulate/companion/regCompanion5C/foo.out
+#	../hg/regulate/companion/regCompanion5C/test.bed
+#	../hg/regulate/companion/regCompanion5C/test.download
+#	../hg/regulate/companion/regCompanionChia/50kPromEnhanceViaChia.notes
+#	../hg/regulate/companion/regCompanionChia/50kPromEnhanceViaChia.tab
+#	../hg/regulate/companion/regCompanionChia/chia3enh3pro.tab
+#	../hg/regulate/companion/regCompanionChia/chia3pro3pro.tab
+#	../hg/regulate/companion/regCompanionChia/chiaPetK562SameChrom.tab
+#	../hg/regulate/companion/regCompanionChia/chiaPetK562SameChromSepBlocks.bed
+#	../hg/regulate/companion/regCompanionChia/chiaPromOtherEnd.bed
+#	../hg/regulate/companion/regCompanionChia/chiaPromOtherEnd.tab
+#	../hg/regulate/companion/regCompanionChia/chiaSamChromK562Exons.bed
+#	../hg/regulate/companion/regCompanionChia/chiaSameChromK562.bed
+#	../hg/regulate/companion/regCompanionChia/enhStringentGm12878.bed
+#	../hg/regulate/companion/regCompanionChia/enhStringentK562.bed
+#	../hg/regulate/companion/regCompanionChia/foo2
+#	../hg/regulate/companion/regCompanionChia/foo3
+#	../hg/regulate/companion/regCompanionChia/foo4
+#	../hg/regulate/companion/regCompanionChia/foo5
+#	../hg/regulate/companion/regCompanionChia/foo6
+#	../hg/regulate/companion/regCompanionChia/foo7
+#	../hg/regulate/companion/regCompanionChia/foofoo
+#	../hg/regulate/companion/regCompanionChia/gm12878Ctcf.bed
+#	../hg/regulate/companion/regCompanionChia/oneEnd.lst
+#	../hg/regulate/companion/regCompanionChia/oneEnd.tab
+#	../hg/regulate/companion/regCompanionChia/other.bed
+#	../hg/regulate/companion/regCompanionChia/other.lst
+#	../hg/regulate/companion/regCompanionChia/promoters.bed
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/1.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/1shuf.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/2-7.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/2-8.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/actToAct.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/actToAct90.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/actToPermuted.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/activeEnh.bed
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/activeEnh.lst
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/activeEnh.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/activeEnhToProm.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/activeGene.bed
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/activeGene.lst
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/activeGene.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/bed.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/ctcfInterference.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/enh.bed
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/enhToProm.bed
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/enhToProm.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/enhToProm100k.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/enhToProm10k.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/foo.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/outBad
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/outGood
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/permute707.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/permute90.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/permuted.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/permutedGene.lst
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/permutedGene.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/permutedOut.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/pro.bed
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/r90Lengths.tab
+#	../hg/regulate/companion/regCompanionCorrelateEnhancerAndExpression/rc
+#	../hg/regulate/companion/regCompanionCtcfInterference/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/Gm12878.lst
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/GmPhylo.lst
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/H1hesc.lst
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/K562.lst
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/canonical/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/chromHmm/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/corEnhGm12878.tab
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/corEnhStrandedGm12878.tab
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/ctcf/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/enh/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/enh2/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/ez/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/firstCodingSplice/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/gmEnh/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/oldOne.tab
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/one.lst
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/one.tab
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/p300/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/phyloP.lst
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/regPeaks/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/run2/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/secondCodingSplice/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/short.lst
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/stringent3/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/stringent4/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/stringent5/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/stringent6/
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/take2.err
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/tier1.lst
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/tier1Txn.lst
+#	../hg/regulate/companion/regCompanionGraphVsFixedPoints/toR.csh
+#	../hg/regulate/companion/regCompanionHistoneBox/bedToTabR.csh
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878Dnase.bed
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878Dnase.fat
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878Dnase.tab
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k27acBox.bed
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k27acBox.fat
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k27acBox.narrowPeak
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k27acBox.tab
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k4me1Box.bed
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k4me1Box.fat
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k4me1Box.narrowPeak
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k4me1Box.tab
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k4me1Box30.bed
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k4me1Box30.fat
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k4me1Box30.narrowPeak
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k4me1Box30.tab
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k4me3Box50.bed
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k4me3Box50.fat
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k4me3Box50.narrowPeak
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseH3k4me3Box50.tab
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseTop50.bed
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseTop50.fat
+#	../hg/regulate/companion/regCompanionHistoneBox/gm12878DnaseTop50.tab
+#	../hg/regulate/companion/regCompanionPickEnhancers/examplesByHand.txt
+#	../hg/regulate/companion/regCompanionPickEnhancers/foo.csh
+#	../hg/regulate/companion/regCompanionPickEnhancers/hsmm.csh
+#	../hg/regulate/companion/regCompanionPickEnhancers/loose.csh
+#	../hg/regulate/companion/regCompanionPickEnhancers/nhek.csh
+#	../hg/regulate/companion/regCompanionPickEnhancers/nhekDnaseChr1.narrowPeak
+#	../hg/regulate/companion/regCompanionPickEnhancers/oldOut.tab
+#	../hg/regulate/companion/regCompanionPickEnhancers/out.tab
+#	../hg/regulate/companion/regCompanionPickEnhancers/pickedBeds/
+#	../hg/regulate/companion/regCompanionPickEnhancers/std20.tab
+#	../hg/regulate/companion/regCompanionPickEnhancers/std25.tab
+#	../hg/regulate/companion/regCompanionPickEnhancers/std30.tab
+#	../hg/regulate/companion/regCompanionPickEnhancers/stringent.csh
+#	../hg/regulate/companion/regCompanionPickEnhancers/stringent.tab
+#	../hg/regulate/companion/regCompanionPickEnhancers/stringent2.csh
+#	../hg/regulate/companion/regCompanionPickEnhancers/stringent2/
+#	../hg/regulate/companion/regCompanionPickEnhancers/stringent3.csh
+#	../hg/regulate/companion/regCompanionPickEnhancers/stringent3/
+#	../hg/regulate/companion/regCompanionPickEnhancers/stringent4.csh
+#	../hg/regulate/companion/regCompanionPickEnhancers/stringent4/
+#	../hg/regulate/companion/regCompanionPickEnhancers/stringent5.csh
+#	../hg/regulate/companion/regCompanionPickEnhancers/stringent5/
+#	../hg/regulate/companion/regCompanionPickEnhancers/stringent6/
+#	../hg/regulate/companion/regCompanionPickEnhancers/subsetH1hesc.narrowPeak
+#	../hg/regulate/companion/regCompanionPickEnhancers/take1/
+#	../hg/regulate/companion/regCompanionPickEnhancers/take2/
+#	../hg/regulate/companion/regCompanionPickEnhancers/take3/
+#	../hg/regulate/companion/regCompanionPickEnhancers/take4/
+#	../hg/regulate/companion/regCompanionPickEnhancers/take5/
+#	../hg/regulate/companion/regCompanionSquishGraph/
+#	../hg/regulate/companion/regCompanionTopPeaks/
+#	../hg/regulate/log
+#	../hg/regulate/regBeadPos/.readBeadPos.doc.swp
+#	../hg/regulate/regBeadPos/bak/
+#	../hg/regulate/regBeadPos/dnaseSize.tab
+#	../hg/regulate/regBeadPos/firstGenomeRun.csh
+#	../hg/regulate/regBeadPos/firstGenomeRun.in
+#	../hg/regulate/regBeadPos/foo.bed
+#	../hg/regulate/regBeadPos/foo2
+#	../hg/regulate/regBeadPos/fullDnase.bw
+#	../hg/regulate/regBeadPos/fullH3k27ac.bw
+#	../hg/regulate/regBeadPos/fullH3k4me1.bw
+#	../hg/regulate/regBeadPos/histSize.tab
+#	../hg/regulate/regBeadPos/peak.bed
+#	../hg/regulate/regBeadPos/regBeads.narrowPeak
+#	../hg/regulate/regBeadPos/run2.bed
+#	../hg/regulate/regBeadPos/run2.csh
+#	../hg/regulate/regBeadPos/run2.in
+#	../hg/regulate/regBeadPos/run2.narrowPeak
+#	../hg/regulate/regBeadPos/stateProbes.cur
+#	../hg/regulate/regBeadPos/stateProbs.txt
+#	../hg/regulate/regBeadPos/test2.in
+#	../hg/regulate/regBeadPos/testAc.bw
+#	../hg/regulate/regBeadPos/testDnase.bw
+#	../hg/regulate/regCluster/diff
+#	../hg/regulate/regCluster/status
+#	../hg/regulate/regCluster/tests/needBreak/out.bed
+#	../hg/regulate/regCluster/tests/needBreak/out.cluster
+#	../hg/regulate/regClusterAttachMetadataToTableOfTables/filtered.bed
+#	../hg/regulate/regClusterBedExpCfg/hud/
+#	../hg/regulate/regClusterBedExpCfg/in.ra
+#	../hg/regulate/regClusterBedExpCfg/in.tab
+#	../hg/regulate/regClusterBedExpCfg/out.bed
+#	../hg/regulate/regClusterBedExpCfg/out.cfg
+#	../hg/regulate/regClusterBedExpCfg/out.exps
+#	../hg/regulate/regClusterBedExpCfg/yale
+#	../hg/regulate/regClusterTreeCells/clusterInput.lst
+#	../hg/regulate/regClusterTreeCells/foo2
+#	../hg/regulate/regClusterTreeCells/matrix
+#	../hg/regulate/regClusterTreeCells/status
+#	../hg/regulate/regClusterTreeCells/test2.lst
+#	../hg/regulate/regClusterTreeCells/tests/in2/
+#	../hg/regulate/regClusterTreeCells/tests/out.tree
+#	../hg/regulate/regClusterTreeCells/uwAffy.lst
+#	../hg/regulate/regStartSampleEmbl/.extra.embl.swp
+#	../hg/regulate/regStartSampleEmbl/extra.embl
+#	../hg/regulate/regStartSampleEmbl/foo2.embl
+#	../hg/regulate/status
+#	../hg/status
+#	../hg/trash/
+#	../hg/txGene/txGeneAccession/txLastId
+#	../hg/utils/bedRandom/5000.bed
+#	../hg/utils/bedRandom/5000masked.bed
+#	../hg/utils/bedRandom/5000maskedGc.tab
+#	../hg/utils/bedRandom/chrom.sizes
+#	../hg/utils/bedRandom/foo.bed
+#	../hg/utils/bedRandom/rmsk.bed
+#	../hg/utils/hubCheck/status
+#	../hg/utils/hubCheck/udc/
+#	../hg/utils/makeTrackIndex/foo2
+#	../hg/utils/mdbQuery/log
+#	../hg/utils/mdbQuery/status
+#	../hgFiles
+#	../kehayden/alphaChain/#alphaChain.c#
+#	../kehayden/alphaChain/DYZ3_alphaChain.out
+#	../kehayden/alphaChain/DYZ3_alphaChain.out2
+#	../kehayden/alphaChain/DYZ3_alphaChain.out3
+#	../kehayden/alphaChain/DYZ3_alphaChain.txt
+#	../kehayden/alphaChain/alphaChain.jk.works
+#	../kehayden/alphaChain/backup/
+#	../kehayden/alphaChain/textOUT
+#	../kehayden/alphaChain/textOUT2
+#	diff
+#	diffs
+#	status
+#	x86_64/stXXXX0Bjo48
+#	../log
+#	../merge
+#	../oneShot/rgbaGfxTest/9
+#	../oneShot/status
+#	../oneShot/testGitRename/blame
+#	../oneShot/testGitRename/status
+#	../oneShot/testGitRename/test.out
+#	../oneShot/testGitRename/testGitRename.blame
+#	../oneShot/testGitRename/upperFile.blame
+#	../parasol/bin/
+#	../pull
+#	../sourceFiles
+#	../status
+#	../tags
+#	../tdb
+#	../tee
+#	../utils/bedCommonRegions/status
+#	../utils/bedCommonRegions/tests/inOver/
+#	../utils/bedCommonRegions/tests/out.bed
+#	../utils/bedGeneParts/firstCodingSplice.out
+#	../utils/bedGeneParts/firstExon.out
+#	../utils/bedGeneParts/foo2
+#	../utils/bedGeneParts/introns.out
+#	../utils/bedGeneParts/promoter.out
+#	../utils/bedGeneParts/ugly.out
+#	../utils/bedRemoveOverlap/status
+#	../utils/bedToClosestPoint/enhK562.bed
+#	../utils/bedToClosestPoint/makefile
+#	../utils/bedToClosestPoint/promo.bed
+#	../utils/bedToClosestPoint/refSeq.bed
+#	../utils/bedToClosestPoint/testOne.bed
+#	../utils/bigWigAverageOverBed/bad.bed
+#	../utils/bigWigAverageOverBed/bad.out
+#	../utils/bigWigAverageOverBed/big.bed
+#	../utils/bigWigAverageOverBed/big.out
+#	../utils/bigWigAverageOverBed/bigBlock.out
+#	../utils/bigWigAverageOverBed/bigChrom.out
+#	../utils/bigWigAverageOverBed/block.out
+#	../utils/bigWigAverageOverBed/chr22.bed
+#	../utils/bigWigAverageOverBed/chrom.out
+#	../utils/bigWigAverageOverBed/dupe.bed
+#	../utils/bigWigAverageOverBed/foo1
+#	../utils/bigWigAverageOverBed/foo2
+#	../utils/bigWigAverageOverBed/phylop.bw
+#	../utils/bigWigAverageOverBed/phylop_1.ave
+#	../utils/bigWigAverageOverBed/phylop_2.ave
+#	../utils/bigWigAverageOverBed/phylop_3.ave
+#	../utils/bigWigAverageOverBed/phylop_4.ave
+#	../utils/bigWigAverageOverBed/rna1.bw
+#	../utils/bigWigAverageOverBed/rna1_1.ave
+#	../utils/bigWigAverageOverBed/rna1_2.ave
+#	../utils/bigWigAverageOverBed/rna1_3.ave
+#	../utils/bigWigAverageOverBed/test.bed
+#	../utils/bigWigAverageOverBed/test.out
+#	../utils/bigWigAverageOverBed/timeNotes
+#	../utils/bigWigAverageOverBed/ucscGenes.out
+#	../utils/bigWigMerge/18m.bw
+#	../utils/bigWigMerge/18p.bw
+#	../utils/bigWigMerge/19m.bw
+#	../utils/bigWigMerge/19p.bw
+#	../utils/colTransform/test.in
+#	../utils/colTransform/test.out
+#	../utils/compareIds/
+#	../utils/faToTwoBit/tests/output/
+#	../utils/linesInAllFiles/in1.txt
+#	../utils/linesInAllFiles/in2.txt
+#	../utils/linesInAllFiles/in3.txt
+#	../utils/pslLiftSubrangeBlat/tests/output/
+#	../utils/replaceTextBetween/
+#	../utils/status
+#	../utils/verticalSplitSqlTable/doIt
+#	../utils/verticalSplitSqlTable/status
+#	../utils/verticalSplitSqlTable/tests/out/
+#	../utils/wigToBigWig/dupTest1.wig
+#	../utils/wigToBigWig/dupTest2.wig
+#	../utils/wigToBigWig/dupTest3.wig
+#	../utils/wigToBigWig/foo.bigWig
+#	../utils/wigToBigWig/quickCheckWig.pl
+#	../../status
+#	../../tags.log
+#	../../test.log
+#	../../throughputNotest.txt
+no changes added to commit (use "git add" and/or "git commit -a")
diff --git a/lib/subText.c b/lib/subText.c
new file mode 100644
index 0000000..c5bf83e
--- /dev/null
+++ b/lib/subText.c
@@ -0,0 +1,153 @@
+/* subText - Stuff to do text substitutions. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "subText.h"
+
+
+struct subText *subTextNew(char *in, char *out)
+/* Make new substitution structure. */
+{
+struct subText *sub;
+AllocVar(sub);
+sub->in = cloneString(in);
+sub->out = cloneString(out);
+sub->inSize = strlen(in);
+sub->outSize = strlen(out);
+return sub;
+}
+
+void subTextFree(struct subText **pSub)
+/* Free a subText. */
+{
+struct subText *sub = *pSub;
+if (sub != NULL)
+    {
+    freeMem(sub->in);
+    freeMem(sub->out);
+    freez(pSub);
+    }
+}
+
+void subTextFreeList(struct subText **pList)
+/* Free a list of dynamically allocated subText's */
+{
+struct subText *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    subTextFree(&el);
+    }
+*pList = NULL;
+}
+
+#if 0 /* unused */
+static boolean firstSame(char *s, char *t, int len)
+/* Return TRUE if  the  first len characters of the strings s and t
+ * are the same. */
+{
+while (--len >= 0)
+    {
+    if (*s++ != *t++)
+	return FALSE;
+    }
+return TRUE;
+}
+#endif
+
+static struct subText *firstInList(struct subText *l, char *name)
+/* Return first element in Sub list who's in string matches the
+ * first part of name. */
+{
+struct subText *text = l;
+char *start;
+char *end;
+char *cmp;
+
+for(; text; text = text->next)
+    {
+    start = text->in;
+    end = &start[text->inSize];
+    cmp = name;
+    for(;(start < end) && (*start == *cmp); start++, cmp++)
+	;
+    if (start == end)
+    	return text;
+    }
+return NULL;
+}
+
+
+int subTextSizeAfter(struct subText *subList, char *in)
+/* Return size string will be after substitutions. */
+{
+struct subText *sub;
+char *s;
+int size = 0;
+
+s = in;
+while (*s)
+    {
+    if ((sub = firstInList(subList, s)) != NULL)
+	{
+	s += sub->inSize;
+	size += sub->outSize;
+	}
+    else
+	{
+	size += 1;
+	s += 1;
+	}
+    }
+return size;
+}
+
+
+static void doSub(char *in, char *buf, struct subText *subList)
+/* Do substitutions in list while copying from in to buf.  This
+ * cheap little routine doesn't check that out is big enough.... */
+{
+struct subText *sub;
+char *s, *d;
+
+s = in;
+d = buf;
+while (*s)
+    {
+    if ((sub = firstInList(subList, s)) != NULL)
+	{
+	s += sub->inSize;
+	memcpy(d, sub->out, sub->outSize);
+	d += strlen(sub->out);
+	}
+    else
+	{
+	*d++ = *s++;
+	}
+    }
+*d++ = 0;
+}
+
+void subTextStatic(struct subText *subList, char *in, char *out, int outMaxSize)
+/* Do substition to output buffer of given size.  Complain
+ * and die if not big enough. */
+{
+int newSize = subTextSizeAfter(subList, in);
+if (newSize >= outMaxSize)
+    errAbort("%s would expand to more than %d bytes", in, outMaxSize);
+doSub(in, out, subList);
+}
+
+char *subTextString(struct subText *subList, char *in)
+/* Return string with substitutions in list performed.  freeMem
+ * this string when done. */
+{
+int size = subTextSizeAfter(subList, in);
+char *out = needMem(size+1);
+doSub(in, out, subList);
+return out;
+}
+
diff --git a/lib/sufa.c b/lib/sufa.c
new file mode 100644
index 0000000..81e0c01
--- /dev/null
+++ b/lib/sufa.c
@@ -0,0 +1,142 @@
+/* sufa - suffix array for genome.  Use sufaMake utility to create one of these, and
+ * the routines here to access it. */
+/* This file is copyright 2008 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include <sys/mman.h>
+#include "sufa.h"
+
+static void *pointerOffset(void *pt, bits64 offset)
+/* A little wrapper around pointer arithmetic in terms of bytes. */
+{
+char *s = pt;
+return s + offset;
+}
+
+struct sufa *sufaRead(char *fileName, boolean memoryMap)
+/* Read in a sufa from a file.  Does this via memory mapping if you like,
+ * which will be faster typically for about 100 reads, and slower for more
+ * than that (_much_ slower for thousands of reads and more). */
+{
+/* Open file (low level), read in header, and check it. */
+int fd = open(fileName, O_RDONLY);
+if (fd < 0)
+    errnoAbort("Can't open %s", fileName);
+struct sufaFileHeader h;
+if (read(fd, &h, sizeof(h)) < sizeof(h))
+    errnoAbort("Couldn't read header of file %s", fileName);
+if (h.magic != SUFA_MAGIC)
+    errAbort("%s does not seem to be a sufa file.", fileName);
+if (h.majorVersion > SUFA_MAJOR_VERSION)
+    errAbort("%s is a newer, incompatible version of sufa format. "
+             "This program works on version %d and below. "
+	     "%s is version %d.",  fileName, SUFA_MAJOR_VERSION, fileName, h.majorVersion);
+
+struct sufa *sufa;
+verbose(2, "sufa file %s size %lld\n", fileName, h.size);
+
+/* Get a pointer to data in memory, via memory map, or allocation and read. */
+struct sufaFileHeader *header ;
+if (memoryMap)
+    {
+#ifdef MACHTYPE_sparc
+    header = (struct sufaFileHeader *)mmap(NULL, h.size, PROT_READ, MAP_SHARED, fd, 0);
+#else
+    header = mmap(NULL, h.size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0);
+#endif
+    if (header == (void*)(-1))
+	errnoAbort("Couldn't mmap %s, sorry", fileName);
+    }
+else
+    {
+    header = needHugeMem(h.size);
+    if (lseek(fd, 0, SEEK_SET) < 0)
+	errnoAbort("Couldn't seek back to start of sufa file %s.  "
+		   "Splix files must be random access files, not pipes and the like"
+		   , fileName);
+    if (read(fd, header, h.size) < h.size)
+        errnoAbort("Couldn't read all of sufa file %s.", fileName);
+    }
+
+/* Allocate wrapper structure and fill it in. */
+AllocVar(sufa);
+sufa->header = header;
+sufa->isMapped = memoryMap;
+
+/* Make an array for easy access to chromosome names. */
+int chromCount = header->chromCount;
+char **chromNames = AllocArray(sufa->chromNames, chromCount);
+char *s = pointerOffset(header, sizeof(*header) );
+int i;
+for (i=0; i<chromCount; ++i)
+    {
+    chromNames[i] = s;
+    s += strlen(s)+1;
+    }
+
+/* Keep track of where we are in memmap. */
+bits64 mapOffset = sizeof(*header) + header->chromNamesSize;
+
+/* Point into chromSizes array. */
+bits32 *chromSizes = sufa->chromSizes 
+	= pointerOffset(header, mapOffset);
+mapOffset += sizeof(bits32) * chromCount;
+
+verbose(2, "total dna size %lld in %d chromosomes\n", (long long)header->dnaDiskSize, header->chromCount);
+sufa->allDna = pointerOffset(header, mapOffset);
+mapOffset += header->dnaDiskSize;
+
+/* Calculate chromOffset array. */
+bits32 offset = 0;
+bits32 *chromOffsets = AllocArray(sufa->chromOffsets, chromCount);
+for (i=0; i<chromCount; ++i)
+    {
+    chromOffsets[i] = offset;
+    offset += chromSizes[i] + 1;
+    verbose(2, "sufa contains %s,  %d bases, %d offset\n", 
+    	sufa->chromNames[i], (int)sufa->chromSizes[i], (int)chromOffsets[i]);
+    }
+
+/* Finally point to the suffix array!. */
+sufa->array = pointerOffset(header, mapOffset);
+mapOffset += header->arraySize * sizeof(bits32);
+
+
+assert(mapOffset == header->size);	/* Sanity check */
+return sufa;
+}
+
+void sufaFree(struct sufa **pSufa)
+/* Free up resources associated with index. */
+{
+struct sufa *sufa = *pSufa;
+if (sufa != NULL)
+    {
+    freeMem(sufa->chromNames);
+    freeMem(sufa->chromOffsets);
+    if (sufa->isMapped)
+	munmap((void *)sufa->header, sufa->header->size);
+    else
+	freeMem(sufa->header);
+    freez(pSufa);
+    }
+}
+
+int sufaOffsetToChromIx(struct sufa *sufa, bits32 tOffset)
+/* Figure out index of chromosome containing tOffset */
+{
+int i;
+int chromCount = sufa->header->chromCount;
+/* TODO - convert to binary search - will need to sort chromosome list though.... */
+for (i=0; i<chromCount; ++i)
+    {
+    int chromStart = sufa->chromOffsets[i];
+    int chromEnd = chromStart + sufa->chromSizes[i];
+    if (tOffset >= chromStart && tOffset < chromEnd)
+        return i;
+    }
+errAbort("tOffset %d out of range\n", tOffset);
+return -1;
+}
+
diff --git a/lib/sufx.c b/lib/sufx.c
new file mode 100644
index 0000000..b706c2b
--- /dev/null
+++ b/lib/sufx.c
@@ -0,0 +1,146 @@
+/* sufx - suffix array for genome.  Use sufxMake utility to create one of these, and
+ * the routines here to access it. */
+/* This file is copyright 2008 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include <sys/mman.h>
+#include "sufx.h"
+#include "net.h"
+
+static void *pointerOffset(void *pt, bits64 offset)
+/* A little wrapper around pointer arithmetic in terms of bytes. */
+{
+char *s = pt;
+return s + offset;
+}
+
+struct sufx *sufxRead(char *fileName, boolean memoryMap)
+/* Read in a sufx from a file.  Does this via memory mapping if you like,
+ * which will be faster typically for about 100 reads, and slower for more
+ * than that (_much_ slower for thousands of reads and more). */
+{
+/* Open file (low level), read in header, and check it. */
+int fd = open(fileName, O_RDONLY);
+if (fd < 0)
+    errnoAbort("Can't open %s", fileName);
+struct sufxFileHeader h;
+if (read(fd, &h, sizeof(h)) < sizeof(h))
+    errnoAbort("Couldn't read header of file %s", fileName);
+if (h.magic != SUFX_MAGIC)
+    errAbort("%s does not seem to be a sufx file.", fileName);
+if (h.majorVersion > SUFX_MAJOR_VERSION)
+    errAbort("%s is a newer, incompatible version of sufx format. "
+             "This program works on version %d and below. "
+	     "%s is version %d.",  fileName, SUFX_MAJOR_VERSION, fileName, h.majorVersion);
+
+struct sufx *sufx;
+verbose(2, "sufx file %s size %lld\n", fileName, h.size);
+
+/* Get a pointer to data in memory, via memory map, or allocation and read. */
+struct sufxFileHeader *header ;
+if (memoryMap)
+    {
+#ifdef MACHTYPE_sparc
+    header = (struct sufxFileHeader *)mmap(NULL, h.size, PROT_READ, MAP_SHARED, fd, 0);
+#else
+    header = mmap(NULL, h.size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0);
+#endif
+    if (header == (void*)(-1))
+	errnoAbort("Couldn't mmap %s, sorry", fileName);
+    }
+else
+    {
+    header = needHugeMem(h.size);
+    if (lseek(fd, 0, SEEK_SET) < 0)
+	errnoAbort("Couldn't seek back to start of sufx file %s.  "
+		   "Splix files must be random access files, not pipes and the like"
+		   , fileName);
+    if (netReadAll(fd, header, h.size) < h.size)
+        errnoAbort("Couldn't read all of sufx file %s.", fileName);
+    }
+
+/* Allocate wrapper structure and fill it in. */
+AllocVar(sufx);
+sufx->header = header;
+sufx->isMapped = memoryMap;
+
+/* Make an array for easy access to chromosome names. */
+int chromCount = header->chromCount;
+char **chromNames = AllocArray(sufx->chromNames, chromCount);
+char *s = pointerOffset(header, sizeof(*header) );
+int i;
+for (i=0; i<chromCount; ++i)
+    {
+    chromNames[i] = s;
+    s += strlen(s)+1;
+    }
+
+/* Keep track of where we are in memmap. */
+bits64 mapOffset = sizeof(*header) + header->chromNamesSize;
+
+/* Point into chromSizes array. */
+bits32 *chromSizes = sufx->chromSizes 
+	= pointerOffset(header, mapOffset);
+mapOffset += sizeof(bits32) * chromCount;
+
+verbose(2, "total dna size %lld in %d chromosomes\n", (long long)header->dnaDiskSize, header->chromCount);
+sufx->allDna = pointerOffset(header, mapOffset);
+mapOffset += header->dnaDiskSize;
+
+/* Calculate chromOffset array. */
+bits32 offset = 0;
+bits32 *chromOffsets = AllocArray(sufx->chromOffsets, chromCount);
+for (i=0; i<chromCount; ++i)
+    {
+    chromOffsets[i] = offset;
+    offset += chromSizes[i] + 1;
+    verbose(2, "sufx contains %s,  %d bases, %d offset\n", 
+    	sufx->chromNames[i], (int)sufx->chromSizes[i], (int)chromOffsets[i]);
+    }
+
+/* Point to the suffix array. */
+sufx->array = pointerOffset(header, mapOffset);
+mapOffset += header->arraySize * sizeof(bits32);
+
+/* Finally point to the traverse array!. */
+sufx->traverse = pointerOffset(header, mapOffset);
+mapOffset += header->arraySize * sizeof(bits32);
+
+assert(mapOffset == header->size);	/* Sanity check */
+return sufx;
+}
+
+void sufxFree(struct sufx **pSufx)
+/* Free up resources associated with index. */
+{
+struct sufx *sufx = *pSufx;
+if (sufx != NULL)
+    {
+    freeMem(sufx->chromNames);
+    freeMem(sufx->chromOffsets);
+    if (sufx->isMapped)
+	munmap((void *)sufx->header, sufx->header->size);
+    else
+	freeMem(sufx->header);
+    freez(pSufx);
+    }
+}
+
+int sufxOffsetToChromIx(struct sufx *sufx, bits32 tOffset)
+/* Figure out index of chromosome containing tOffset */
+{
+int i;
+int chromCount = sufx->header->chromCount;
+/* TODO - convert to binary search - will need to sort chromosome list though.... */
+for (i=0; i<chromCount; ++i)
+    {
+    int chromStart = sufx->chromOffsets[i];
+    int chromEnd = chromStart + sufx->chromSizes[i];
+    if (tOffset >= chromStart && tOffset < chromEnd)
+        return i;
+    }
+errAbort("tOffset %d out of range\n", tOffset);
+return -1;
+}
+
diff --git a/lib/synQueue.c b/lib/synQueue.c
new file mode 100644
index 0000000..7d18757
--- /dev/null
+++ b/lib/synQueue.c
@@ -0,0 +1,107 @@
+/* synQueue - a sychronized message queue for messages between
+ * threads. */
+
+#include "common.h"
+#include "dlist.h"
+#include "pthreadWrap.h"
+#include "synQueue.h"
+
+
+struct synQueue
+/* A synchronized queue for messages between threads. */
+    {
+    struct synQueue *next;	/* Next in list of queues. */
+    struct dlList *queue;	/* The queue itself. */
+    pthread_mutex_t mutex;	/* Mutex to prevent simultanious access. */
+    pthread_cond_t cond;	/* Conditional to allow waiting until non-empty. */
+    };
+
+struct synQueue *synQueueNew()
+/* Make a new, empty, synQueue. */
+{
+struct synQueue *sq;
+AllocVar(sq);
+pthreadMutexInit(&sq->mutex);
+pthreadCondInit(&sq->cond);
+sq->queue = dlListNew();
+return sq;
+}
+
+void synQueueFree(struct synQueue **pSq)
+/* Free up synQueue.  Be sure no other threads are using
+ * it first though! This will not free any dynamic memory
+ * in the messages.  Use synQueueFreeAndVals for that. */
+{
+struct synQueue *sq = *pSq;
+if (sq == NULL)
+    return;
+dlListFree(&sq->queue);
+pthreadCondDestroy(&sq->cond);
+pthreadMutexDestroy(&sq->mutex);
+freez(pSq);
+}
+
+void synQueueFreeAndVals(struct synQueue **pSq)
+/* Free up synQueue.  Be sure no other threads are using
+ * it first though! This will freeMem all the messages */
+{
+struct synQueue *sq = *pSq;
+if (sq == NULL)
+    return;
+dlListFreeAndVals(&sq->queue);
+pthreadCondDestroy(&sq->cond);
+pthreadMutexDestroy(&sq->mutex);
+freez(pSq);
+}
+
+void synQueuePut(struct synQueue *sq, void *message)
+/* Add message to end of queue. */
+{
+pthreadMutexLock(&sq->mutex);
+dlAddValTail(sq->queue, message);
+pthreadCondSignal(&sq->cond);
+pthreadMutexUnlock(&sq->mutex);
+}
+
+void *synQueueGet(struct synQueue *sq)
+/* Get message off start of queue.  Wait until there is
+ * a message if queue is empty. */
+{
+void *message;
+struct dlNode *node;
+pthreadMutexLock(&sq->mutex);
+while (dlEmpty(sq->queue))
+    pthreadCondWait(&sq->cond, &sq->mutex);
+node = dlPopHead(sq->queue);
+pthreadMutexUnlock(&sq->mutex);
+message = node->val;
+freeMem(node);
+return message;
+}
+
+void *synQueueGrab(struct synQueue *sq)
+/* Get message off start of queue.  Return NULL immediately 
+ * if queue is empty. */
+{
+void *message = NULL;
+struct dlNode *node;
+pthreadMutexLock(&sq->mutex);
+node = dlPopHead(sq->queue);
+pthreadMutexUnlock(&sq->mutex);
+if (node != NULL)
+    {
+    message = node->val;
+    freeMem(node);
+    }
+return message;
+}
+
+int synQueueSize(struct synQueue *sq)
+/* Return number of messages currently on queue. */
+{
+int size;
+pthreadMutexLock(&sq->mutex);
+size = dlCount(sq->queue);
+pthreadMutexUnlock(&sq->mutex);
+return size;
+}
diff --git a/lib/tabRow.c b/lib/tabRow.c
new file mode 100644
index 0000000..0d61025
--- /dev/null
+++ b/lib/tabRow.c
@@ -0,0 +1,229 @@
+/* tabRow - a row from a database or a tab-separated file held in
+ * memory.   Just a light wrapper around an array of strings. 
+ * Also some routines to convert slLines to tabRows. */
+
+#include "common.h"
+#include "tabRow.h"
+
+
+struct tabRow *tabRowNew(int colCount)
+/* Return new row. */
+{
+struct tabRow *row = needMem(sizeof(*row) + colCount*sizeof(char*));
+row->colCount = colCount;
+return row;
+}
+
+int tabRowMaxColCount(struct tabRow *rowList)
+/* Return largest column count */
+{
+int maxCount = 0;
+struct tabRow *row;
+for (row = rowList; row != NULL; row = row->next)
+    if (row->colCount > maxCount)
+        maxCount = row->colCount;
+return maxCount;
+}
+
+struct tabRow *tabRowByWhite(struct slName *lineList, char *fileName,
+	boolean varCol)
+/* Convert lines to rows based on spaces.  If varCol is TRUE then not
+ * all rows need to have same number of columns. */
+{
+struct slName *line;
+struct tabRow *rowList = NULL, *row;
+
+if (varCol)
+    {
+    for (line = lineList; line != NULL; line = line->next)
+        {
+	char *s = line->name;
+	int rowSize = chopByWhite(s, NULL, 0);
+	row = tabRowNew(rowSize);
+	chopByWhite(s, row->columns, rowSize);
+	slAddHead(&rowList, row);
+	}
+    }
+else
+    {
+    if (lineList)
+        {
+	int rowSize = chopByWhite(lineList->name, NULL, 0);
+	int extraSize = rowSize+1;
+	int ix = 1;
+	for (line = lineList; line != NULL; line = line->next, ++ix)
+	    {
+	    int oneSize;
+	    row = tabRowNew(rowSize);
+	    oneSize = chopByWhite(line->name, row->columns, extraSize);
+	    if (oneSize != rowSize)
+	        {
+		if (oneSize > rowSize)
+		    errAbort("Got more than the expected %d columns line %d of %s",
+			    rowSize, ix, fileName);
+		else
+		    errAbort("Expecting %d columns got %d, line %d of %s",
+		    	rowSize, oneSize, ix, fileName);
+
+		}
+	    slAddHead(&rowList, row);
+	    }
+	}
+    }
+slReverse(&rowList);
+return rowList;
+}
+
+struct tabRow *tabRowByChar(struct slName *lineList, char c, char *fileName,
+	boolean varCol)
+/* Convert lines to rows based on character separation.  If varCol is TRUE then not
+ * all rows need to have same number of columns. */
+{
+struct slName *line;
+struct tabRow *rowList = NULL, *row;
+
+if (varCol)
+    {
+    for (line = lineList; line != NULL; line = line->next)
+        {
+	char *s = line->name;
+	int rowSize = countChars(s, c) + 1;
+	row = tabRowNew(rowSize);
+	chopByChar(s, c, row->columns, rowSize);
+	slAddHead(&rowList, row);
+	}
+    }
+else
+    {
+    if (lineList)
+        {
+	int rowSize = countChars(lineList->name, c) + 1;
+	int extraSize = rowSize+1;
+	int ix = 1;
+	for (line = lineList; line != NULL; line = line->next, ++ix)
+	    {
+	    int oneSize;
+	    row = tabRowNew(rowSize);
+	    oneSize = chopByChar(line->name, c, row->columns, extraSize);
+	    if (oneSize != rowSize)
+	        {
+		if (oneSize > rowSize)
+		    errAbort("Got more than the expected %d columns line %d of %s",
+			    rowSize, ix, fileName);
+		else
+		    errAbort("Expecting %d columns got %d, line %d of %s",
+		    	rowSize, oneSize, ix, fileName);
+
+		}
+	    slAddHead(&rowList, row);
+	    }
+	}
+    }
+return rowList;
+}
+
+struct slInt *tabRowGuessFixedOffsets(struct slName *lineList, char *fileName)
+/* Return our best guess list of starting positions for space-padded fixed
+ * width fields. */
+{
+struct slInt *offList = NULL, *off;
+
+if (lineList)
+    {
+    char *spaceRec = cloneString(lineList->name), *s;
+    int lineSize = strlen(spaceRec);
+    struct slName *line;
+    int lineIx=1;
+
+    /* First 'or' together all lines into spaceRec, which will
+     * have a space wherever all columns of all lines are space and
+     * non-space elsewhere. */
+    for (line = lineList->next; line != NULL; line = line->next, ++lineIx)
+        {
+	int i;
+	s = line->name;
+	if (strlen(s) != lineSize)
+	   errAbort("Line %d of %s has %lu chars, but first line has just %d",
+	       lineIx, fileName, (unsigned long)strlen(s), lineSize);
+	for (i=0; i<lineSize; ++i)
+	    {
+	    if (s[i] != ' ')
+	        spaceRec[i] = 'X';
+	    }
+	}
+
+    /* Now make up slInt list that describes where words begin */
+    s = spaceRec;
+    for (;;)
+        {
+	s = skipLeadingSpaces(s);
+	if (s == NULL || s[0] == 0)
+	    break;
+	AllocVar(off);
+	off->val = s - spaceRec;
+	slAddHead(&offList, off);
+	s = skipToSpaces(s);
+	}
+    slReverse(&offList);
+    }
+return offList;
+}
+
+struct tabRow *tabRowByFixedOffsets(struct slName *lineList, struct slInt *offList,
+	char *fileName)
+/* Return rows parsed into fixed width fields whose starts are defined by
+ * offList. */
+{
+struct slName *line;
+struct slInt *off;
+struct tabRow *rowList = NULL, *row;
+int rowSize = slCount(offList);
+
+if (lineList)
+    {
+    int lineSize = strlen(lineList->name);
+    int lineIx = 1;
+    for (off = offList; off != NULL; off = off->next)
+        {
+	if (off->val >= lineSize)
+	    errAbort("Offset %d is bigger than lineSize of %d", off->val, lineSize);
+	}
+    for (line = lineList; line != NULL; line = line->next, ++lineIx)
+	{
+	char *linePt = line->name;
+	int offIx = 0;
+	if (strlen(linePt) != lineSize)
+	   errAbort("Line %d of %s has %lu chars, but first line has just %d",
+	       lineIx, fileName, (unsigned long)strlen(linePt), lineSize);
+	row = tabRowNew(rowSize);
+	for (off = offList; off != NULL; off = off->next, ++offIx)
+	    {
+	    int start = off->val, end;
+	    if (off->next != NULL)
+		{
+	        end = off->next->val-1;
+		if (linePt[end] != ' ')
+		   errAbort("Line %d of %s expecting space column %d, got %c",
+			   lineIx, fileName, end, linePt[end]);
+		}
+	    else
+	        end = lineSize;
+	    linePt[end] = 0;
+	    row->columns[offIx] = trimSpaces(linePt + start);
+	    }
+	slAddHead(&rowList, row);
+	}
+    slReverse(&rowList);
+    }
+return rowList;
+}
+
+struct tabRow *tabRowByFixedGuess(struct slName *lineList, char *fileName)
+/* Return rows parsed into fixed-width fields. */
+{
+struct slInt *offList = tabRowGuessFixedOffsets(lineList, fileName);
+struct tabRow *rowList = tabRowByFixedOffsets(lineList, offList, fileName);
+slFreeList(&offList);
+return rowList;
+}
+
diff --git a/lib/tests/dyStringTester.c b/lib/tests/dyStringTester.c
new file mode 100644
index 0000000..720dccd
--- /dev/null
+++ b/lib/tests/dyStringTester.c
@@ -0,0 +1,101 @@
+/* dyStringTest - tests for dyString */
+
+#include "common.h"
+#include "dystring.h"
+
+static void usage()
+/* Print usage message */
+{
+errAbort(
+   "dyStringTest - check for dyString\n"
+   "usage:\n"
+   "   dyStringTest\n"
+   "\n");
+}
+int errCount = 0;  /* count of errors */
+
+static void dyStringCheck(char *id, struct dyString *ds, char *expect)
+/* check if a dyString contains the expected value */
+{
+if (!sameString(ds->string, expect))
+    {
+    fprintf(stderr, "dyString test %s failed: expected \"%s\", got \"%s\"\n",
+            id, expect, ds->string);
+    errCount++;
+    }
+}
+
+static char *mkString(int len)
+/* create test string with repetative pattern */
+{
+static char *base = "abcdefghijklmnopABCDEFGHIJKLMNOP";
+int baseLen = strlen(base);
+int numRep = (len+2*baseLen)/baseLen; /* a little slop */
+int i;
+char *p, *str = needMem((numRep*baseLen)+1);
+
+for (p = str, i = 0; i < numRep; i++, p += baseLen)
+    strcpy(p, base);
+str[len] = '\0';
+return str;
+}
+
+static void printfLargeTest(char *id, int len)
+/* test dyStringPrintf with a large string */
+{
+struct dyString *ds = dyStringNew(0);
+char *str = mkString(len);
+
+dyStringPrintf(ds, "%s", str);
+if (ds->stringSize != len)
+    {
+    fprintf(stderr, "dyString test %s failed: expected length of %d, got %d\n",
+            id, len, ds->stringSize);
+    errCount++;
+    }
+else 
+    dyStringCheck(id, ds, str);
+
+freeMem(str);
+dyStringFree(&ds);
+}
+
+static void printfTest()
+/* test dyStringPrintf */
+{
+struct dyString *ds = dyStringNew(0);
+int initBufSize = ds->bufSize;  /* size of new string buffer */
+
+/* small string */
+dyStringPrintf(ds, "%d %.2s %d", 10, "abcdefg", 20);
+dyStringCheck("printfSmall", ds, "10 ab 20");
+dyStringClear(ds);
+
+/* large strings */
+printfLargeTest("printfUnderBufSz", initBufSize-1);
+printfLargeTest("printfAtBufSz", initBufSize);
+printfLargeTest("printfOverBufSz", initBufSize+1);
+#if 0 /* until x86_64 bug is fixed */
+printfLargeTest("printf8000", 8000);
+#endif
+
+dyStringFree(&ds);
+}
+
+static void dyStringTest()
+/* dyStringTest - tests for dyString */
+{
+printfTest();
+if (errCount > 0)
+    errAbort("%d tests failed", errCount);
+}
+
+int main(int argc, char *argv[])
+{
+if (argc != 1)
+    usage();
+dyStringTest();
+return 0;
+}
+
+
diff --git a/lib/tests/errCatchTest.c b/lib/tests/errCatchTest.c
new file mode 100644
index 0000000..ed2227c
--- /dev/null
+++ b/lib/tests/errCatchTest.c
@@ -0,0 +1,56 @@
+/* errCatchTest - test error catching by putting a wrapper
+ * around a file read. */
+
+#include "common.h"
+#include "errCatch.h"
+
+void usage()
+/* Print usage message */
+{
+errAbort(
+   "errCatchTest - check error catching\n"
+   "usage:\n"
+   "   errCatchTest password\n"
+   "This will abort (but be caught) unless password is 'secret'\n");
+}
+
+void flakyStuff(char *password)
+/* Count lines in file. */
+{
+printf("Checking password %s\n", password);
+if (!sameString(password, "secret"))
+    {
+    errAbort("%s is not secret password!", password);
+    }
+}
+
+void test(char *password)
+/* See if password works. */
+{
+struct errCatch *errCatch = errCatchNew();
+if (errCatchStart(errCatch))
+    {
+    flakyStuff(password);
+    printf("access confirmed\n");
+    }
+else
+    {
+    printf("access denied\n");
+    }
+errCatchEnd(errCatch);
+if (errCatch->gotError)
+    printf("Caught error: %s", errCatch->message->string);
+else
+    printf("You know the secret password\n");
+errCatchFree(&errCatch);
+}
+
+int main(int argc, char *argv[])
+{
+if (argc != 2)
+    usage();
+test(argv[1]);
+return 0;
+}
+
+
diff --git a/lib/tests/expected/base64Decode.out b/lib/tests/expected/base64Decode.out
new file mode 100644
index 0000000..21507c0
--- /dev/null
+++ b/lib/tests/expected/base64Decode.out
@@ -0,0 +1,3 @@
+original input: [TXkgVGVzdCBTdHJpbmc=]
+base-64 encoding: [VFhrZ1ZHVnpkQ0JUZEhKcGJtYz0=]
+base-64 decoding: [My Test String]
diff --git a/lib/tests/expected/base64Encode.out b/lib/tests/expected/base64Encode.out
new file mode 100644
index 0000000..7f000c5
--- /dev/null
+++ b/lib/tests/expected/base64Encode.out
@@ -0,0 +1,3 @@
+original input: [My Test String]
+base-64 encoding: [TXkgVGVzdCBTdHJpbmc=]
+base-64 decoding: [3$޲ԭ�)�]
diff --git a/lib/tests/expected/errCatch.bad b/lib/tests/expected/errCatch.bad
new file mode 100644
index 0000000..b08be08
--- /dev/null
+++ b/lib/tests/expected/errCatch.bad
@@ -0,0 +1,3 @@
+Checking password bad
+access denied
+Caught error: bad is not secret password!
diff --git a/lib/tests/expected/errCatch.good b/lib/tests/expected/errCatch.good
new file mode 100644
index 0000000..edcc2ec
--- /dev/null
+++ b/lib/tests/expected/errCatch.good
@@ -0,0 +1,3 @@
+Checking password secret
+access confirmed
+You know the secret password
diff --git a/lib/tests/expected/gff3DiscontiousTest.out b/lib/tests/expected/gff3DiscontiousTest.out
new file mode 100644
index 0000000..bf2d733
--- /dev/null
+++ b/lib/tests/expected/gff3DiscontiousTest.out
@@ -0,0 +1,31 @@
+##gff-version 3
+apidb|Pf3D7_13	ApiDB	gene	801913	806230	.	+	.	ID=apidb|MAL13P1.103;Name=MAL13P1.103;description=conserved+Plasmodium+protein%2C+unknown+function;size=4318,4318;web_id=MAL13P1.103;locus_tag=MAL13P1.103
+apidb|Pf3D7_13	ApiDB	mRNA	801913	806230	.	+	.	ID=apidb|rna_MAL13P1.103-1;Name=MAL13P1.103-1;description=conserved+Plasmodium+protein%2C+unknown+function;size=4318;Parent=apidb|MAL13P1.103;Dbxref=ApiDB_PlasmoDB:MAL13P1.103,NCBI_gi:124513148,NCBI_gi:23615347,taxon:36329
+apidb|Pf3D7_13	ApiDB	CDS	801913	804064	.	+	0	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=2152;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	804194	804264	.	+	2	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=71;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	804423	804569	.	+	0	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=147;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	804663	804788	.	+	0	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=126;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	804950	805115	.	+	0	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=166;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	805197	805277	.	+	2	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=81;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	805391	805476	.	+	2	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=86;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	805587	805642	.	+	0	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=56;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	805730	805811	.	+	1	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=82;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	805985	806230	.	+	0	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=246;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	801913	804064	.	+	.	ID=apidb|exon_MAL13P1.103-1;Name=exon;description=exon;size=2152;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	804194	804264	.	+	.	ID=apidb|exon_MAL13P1.103-2;Name=exon;description=exon;size=71;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	804423	804569	.	+	.	ID=apidb|exon_MAL13P1.103-3;Name=exon;description=exon;size=147;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	804663	804788	.	+	.	ID=apidb|exon_MAL13P1.103-4;Name=exon;description=exon;size=126;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	804950	805115	.	+	.	ID=apidb|exon_MAL13P1.103-5;Name=exon;description=exon;size=166;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	805197	805277	.	+	.	ID=apidb|exon_MAL13P1.103-6;Name=exon;description=exon;size=81;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	805391	805476	.	+	.	ID=apidb|exon_MAL13P1.103-7;Name=exon;description=exon;size=86;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	805587	805642	.	+	.	ID=apidb|exon_MAL13P1.103-8;Name=exon;description=exon;size=56;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	805730	805811	.	+	.	ID=apidb|exon_MAL13P1.103-9;Name=exon;description=exon;size=82;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	805985	806230	.	+	.	ID=apidb|exon_MAL13P1.103-10;Name=exon;description=exon;size=246;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	gene	816023	818599	.	-	.	ID=apidb|MAL13P1.105;Name=MAL13P1.105;description=ser/thr+protein+phosphatase+2A+regulatory+subunit+A%2C+putative;size=2577,2577;web_id=MAL13P1.105;locus_tag=MAL13P1.105
+apidb|Pf3D7_13	ApiDB	mRNA	816023	818599	.	-	.	ID=apidb|rna_MAL13P1.105-1;Name=MAL13P1.105-1;description=ser/thr+protein+phosphatase+2A+regulatory+subunit+A%2C+putative;size=2577;Parent=apidb|MAL13P1.105;Ontology_term=GO:0005488;Dbxref=ApiDB_PlasmoDB:MAL13P1.105,EC:3.1.3.16,NCBI_gi:124513154,NCBI_gi:23615350,taxon:36329
+apidb|Pf3D7_13	ApiDB	CDS	816023	818599	.	-	0	ID=apidb|cds_MAL13P1.105-1;Name=cds;description=.;size=2577;Parent=apidb|rna_MAL13P1.105-1
+apidb|Pf3D7_13	ApiDB	exon	816023	818599	.	-	.	ID=apidb|exon_MAL13P1.105-1;Name=exon;description=exon;size=2577;Parent=apidb|rna_MAL13P1.105-1
+apidb|Pf3D7_13	ApiDB	gene	820942	821379	.	+	.	ID=apidb|MAL13P1.106;Name=MAL13P1.106;description=probable+protein%2C+unknown+function;size=438,438;web_id=MAL13P1.106;locus_tag=MAL13P1.106
+apidb|Pf3D7_13	ApiDB	mRNA	820942	821379	.	+	.	ID=apidb|rna_MAL13P1.106-1;Name=MAL13P1.106-1;description=probable+protein%2C+unknown+function;size=438;Parent=apidb|MAL13P1.106;Dbxref=ApiDB_PlasmoDB:MAL13P1.106,NCBI_gi:124513156,NCBI_gi:23615351,taxon:36329
+apidb|Pf3D7_13	ApiDB	CDS	820942	821379	.	+	0	ID=apidb|cds_MAL13P1.106-1;Name=cds;description=.;size=438;Parent=apidb|rna_MAL13P1.106-1
+apidb|Pf3D7_13	ApiDB	exon	820942	821379	.	+	.	ID=apidb|exon_MAL13P1.106-1;Name=exon;description=exon;size=438;Parent=apidb|rna_MAL13P1.106-1
diff --git a/lib/tests/expected/gff3ErrorCasesTest.err b/lib/tests/expected/gff3ErrorCasesTest.err
new file mode 100644
index 0000000..a1560c6
--- /dev/null
+++ b/lib/tests/expected/gff3ErrorCasesTest.err
@@ -0,0 +1,4 @@
+input/errorCasesTest.gff3:28: expected Target attribute in the form "target_id start end [strand]", got "CG41424-RA AABU01002023_1064-818 22000976 22001221 +"
+Annotation records for discontinuous features with ID="DMG5-chr2RHet.4.001.a" do not have the same type, found "gene" and "mRNA"
+Can't find annotation record "DMG5-chr2RHet.4.001" referenced by "DMG5-chr2RHet.4.001.a" Parent attribute
+GFF3: 3 parser errors
diff --git a/lib/tests/expected/gff3SacCerTest.out b/lib/tests/expected/gff3SacCerTest.out
new file mode 100644
index 0000000..ae0eb15
--- /dev/null
+++ b/lib/tests/expected/gff3SacCerTest.out
@@ -0,0 +1,36 @@
+##gff-version 3
+chrI	SGD	chromosome	1	230208	.	.	.	ID=chrI;dbxref=NCBI:NC_001133
+chrI	SGD	repeat_region	1	62	.	-	.	ID=TEL01L-TR;Name=TEL01L-TR;Note=Terminal stretch of telomeric repeats on the left arm of Chromosome I;dbxref=SGD:S000028864
+chrI	SGD	telomere	1	801	.	-	.	ID=TEL01L;Name=TEL01L;Note=Telomeric region on the left arm of Chromosome I%3B composed of an X element core sequence%2C X element combinatorial repeats%2C and a short terminal stretch of telomeric repeats;dbxref=SGD:S000028862
+chrI	SGD	repeat_region	63	336	.	-	.	ID=TEL01L-XR;Name=TEL01L-XR;Note=Telomeric X element combinatorial Repeat region on the left arm of Chromosome I%3B contains repeats of the D%2C C%2C B and A types%2C as well as Tbf1p binding sites%3B formerly called SubTelomeric Repeats;dbxref=SGD:S000028866
+chrI	SGD	gene	335	649	.	+	.	ID=YAL069W;Name=YAL069W;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Dubious open reading frame unlikely to encode a protein%2C based on available experimental and comparative sequence data;dbxref=SGD:S000002143;orf_classification=Dubious
+chrI	SGD	CDS	335	649	.	+	0	Parent=YAL069W;Name=YAL069W;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Dubious open reading frame unlikely to encode a protein%2C based on available experimental and comparative sequence data;dbxref=SGD:S000002143;orf_classification=Dubious
+chrI	SGD	repeat_region	337	801	.	-	.	ID=TEL01L-XC;Name=TEL01L-XC;Note=Telomeric X element Core sequence on the left arm of Chromosome I%3B contains an ARS consensus sequence%2C an Abf1p binding site consensus sequence and two small overlapping ORFs (YAL068W-A and YAL069W);dbxref=SGD:S000028865
+chrI	SGD	nucleotide_match	753	763	.	-	.	Parent=TEL01L-XC;Name=TEL01L-XC;Note=Telomeric X element Core sequence on the left arm of Chromosome I%3B contains an ARS consensus sequence%2C an Abf1p binding site consensus sequence and two small overlapping ORFs (YAL068W-A and YAL069W);dbxref=SGD:S000028865
+chrI	SGD	binding_site	532	544	.	-	.	Parent=TEL01L-XC;Name=TEL01L-XC;Note=Telomeric X element Core sequence on the left arm of Chromosome I%3B contains an ARS consensus sequence%2C an Abf1p binding site consensus sequence and two small overlapping ORFs (YAL068W-A and YAL069W);dbxref=SGD:S000028865
+chrI	SGD	gene	538	792	.	+	.	ID=YAL068W-A;Name=YAL068W-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Dubious open reading frame unlikely to encode a protein%3B identified by gene-trapping%2C microarray-based expression analysis%2C and genome-wide homology searching;dbxref=SGD:S000028594;orf_classification=Dubious
+chrI	SGD	CDS	538	792	.	+	0	Parent=YAL068W-A;Name=YAL068W-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Dubious open reading frame unlikely to encode a protein%3B identified by gene-trapping%2C microarray-based expression analysis%2C and genome-wide homology searching;dbxref=SGD:S000028594;orf_classification=Dubious
+chrI	SGD	ARS	650	1791	.	.	.	ID=ARS102;Name=ARS102;Alias=ARSI-1;Note=Autonomously Replicating Sequence;dbxref=SGD:S000121252
+chrI	SGD	gene	1807	2169	.	-	.	ID=YAL068C;Name=YAL068C;gene=PAU8;Alias=PAU8;Ontology_term=GO:0003674,GO:0005575,GO:0030437,GO:0045944;Note=Hypothetical protein of unknown function%3B YAL068C is not an essential gene;dbxref=SGD:S000002142;orf_classification=Uncharacterized
+chrI	SGD	CDS	1807	2169	.	-	0	Parent=YAL068C;Name=YAL068C;gene=PAU8;Alias=PAU8;Ontology_term=GO:0003674,GO:0005575,GO:0030437,GO:0045944;Note=Hypothetical protein of unknown function%3B YAL068C is not an essential gene;dbxref=SGD:S000002142;orf_classification=Uncharacterized
+chrI	SGD	gene	2480	2707	.	+	.	ID=YAL067W-A;Name=YAL067W-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative protein of unknown function%3B identified by gene-trapping%2C microarray-based expression analysis%2C and genome-wide homology searching;dbxref=SGD:S000028593;orf_classification=Uncharacterized
+chrI	SGD	CDS	2480	2707	.	+	0	Parent=YAL067W-A;Name=YAL067W-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative protein of unknown function%3B identified by gene-trapping%2C microarray-based expression analysis%2C and genome-wide homology searching;dbxref=SGD:S000028593;orf_classification=Uncharacterized
+chrI	SGD	gene	7236	9017	.	-	.	ID=YAL067C;Name=YAL067C;gene=SEO1;Alias=SEO1;Ontology_term=GO:0005215,GO:0006810,GO:0016020;Note=Putative permease%2C member of the allantoate transporter subfamily of the major facilitator superfamily%3B mutation confers resistance to ethionine sulfoxide;dbxref=SGD:S000000062;orf_classification=Verified
+chrI	SGD	CDS	7236	9017	.	-	0	Parent=YAL067C;Name=YAL067C;gene=SEO1;Alias=SEO1;Ontology_term=GO:0005215,GO:0006810,GO:0016020;Note=Putative permease%2C member of the allantoate transporter subfamily of the major facilitator superfamily%3B mutation confers resistance to ethionine sulfoxide;dbxref=SGD:S000000062;orf_classification=Verified
+chrI	SGD	ARS	7998	8548	.	.	.	ID=ARS103;Name=ARS103;Alias=ARSI-8;Note=Autonomously Replicating Sequence;dbxref=SGD:S000121253
+chrI	SGD	gene	10092	10400	.	+	.	ID=YAL066W;Name=YAL066W;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Dubious open reading frame unlikely to encode a protein%2C based on available experimental and comparative sequence data;dbxref=SGD:S000000061;orf_classification=Dubious
+chrI	SGD	CDS	10092	10400	.	+	0	Parent=YAL066W;Name=YAL066W;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Dubious open reading frame unlikely to encode a protein%2C based on available experimental and comparative sequence data;dbxref=SGD:S000000061;orf_classification=Dubious
+chrI	SGD	gene	11566	11952	.	-	.	ID=YAL065C;Name=YAL065C;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative protein of unknown function%3B has homology to FLO1%3B possible pseudogene;dbxref=SGD:S000001817;orf_classification=Uncharacterized
+chrI	SGD	CDS	11566	11952	.	-	0	Parent=YAL065C;Name=YAL065C;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative protein of unknown function%3B has homology to FLO1%3B possible pseudogene;dbxref=SGD:S000001817;orf_classification=Uncharacterized
+chrI	SGD	gene	12047	12427	.	+	.	ID=YAL064W-B;Name=YAL064W-B;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Fungal-specific protein of unknown function;dbxref=SGD:S000002141;orf_classification=Uncharacterized
+chrI	SGD	CDS	12047	12427	.	+	0	Parent=YAL064W-B;Name=YAL064W-B;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Fungal-specific protein of unknown function;dbxref=SGD:S000002141;orf_classification=Uncharacterized
+chrI	SGD	gene	13364	13744	.	-	.	ID=YAL064C-A;Name=YAL064C-A;gene=TDA8;Alias=TDA8,YAL065C-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative protein of unknown function%3B YAL064C-A is not an essential gene;dbxref=SGD:S000002140;orf_classification=Uncharacterized
+chrI	SGD	CDS	13364	13744	.	-	0	Parent=YAL064C-A;Name=YAL064C-A;gene=TDA8;Alias=TDA8,YAL065C-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative protein of unknown function%3B YAL064C-A is not an essential gene;dbxref=SGD:S000002140;orf_classification=Uncharacterized
+chrI	SGD	gene	21526	21852	.	+	.	ID=YAL064W;Name=YAL064W;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Protein of unknown function%3B may interact with ribosomes%2C based on co-purification experiments;dbxref=SGD:S000000060;orf_classification=Verified
+chrI	SGD	CDS	21526	21852	.	+	0	Parent=YAL064W;Name=YAL064W;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Protein of unknown function%3B may interact with ribosomes%2C based on co-purification experiments;dbxref=SGD:S000000060;orf_classification=Verified
+chrI	SGD	long_terminal_repeat	22232	22554	.	+	.	ID=YALWdelta1;Name=YALWdelta1;Ontology_term=SO:0000286;Note=Ty1 LTR;dbxref=SGD:S000006787
+chrI	SGD	gene	22397	22687	.	-	.	ID=YAL063C-A;Name=YAL063C-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative protein of unknown function%3B identified by expression profiling and mass spectrometry;dbxref=SGD:S000028813;orf_classification=Uncharacterized
+chrI	SGD	CDS	22397	22687	.	-	0	Parent=YAL063C-A;Name=YAL063C-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative protein of unknown function%3B identified by expression profiling and mass spectrometry;dbxref=SGD:S000028813;orf_classification=Uncharacterized
+chrI	landmark	region	24001	27969	.	-	.	ID=FLO9
+chrXVI	SGD	gene	101608	102702	.	-	.	ID=YPL236C;Name=YPL236C;gene=ENV7;Alias=ENV7;Ontology_term=GO:0000329,GO:0004674,GO:0008150;Note=;dbxref=SGD:S000006157;orf_classification=Uncharacterized
+chrXVI	SGD	CDS	101608	102702	.	-	0	Parent=YPL236C;Name=YPL236C;gene=ENV7;Alias=ENV7;Ontology_term=GO:0000329,GO:0004674,GO:0008150;Note=;dbxref=SGD:S000006157;orf_classification=Uncharacterized
diff --git a/lib/tests/expected/google.out b/lib/tests/expected/google.out
new file mode 100644
index 0000000..137a45a
--- /dev/null
+++ b/lib/tests/expected/google.out
@@ -0,0 +1,6 @@
+f	GET	/search
+	hl	INPUT	hidden	en
+	ie	INPUT	hidden	ISO-8859-1
+	q	INPUT	TEXT	
+	btnG	INPUT	submit	n/a
+	btnI	INPUT	submit	n/a
diff --git a/lib/tests/expected/hacTreeTest.out b/lib/tests/expected/hacTreeTest.out
new file mode 100644
index 0000000..30632ea
--- /dev/null
+++ b/lib/tests/expected/hacTreeTest.out
@@ -0,0 +1,103 @@
+Clustering by numeric value:
+(2.562:13.375:
+ (9.250:5.500:
+  (6.500:2.000:
+   (7.500:1.000:
+    {8.000},
+    {7.000}
+   ),
+   (5.500:1.000:
+    {6.000},
+    {5.000}
+   )
+  ),
+  {12.000}
+ ),
+ (-4.125:5.750:
+  (-1.250:3.500:
+   {-3.000},
+   (0.500:1.000:
+    {1.000},
+    {0.000}
+   )
+  ),
+  (-7.000:2.000:
+   {-6.000},
+   {-8.000}
+  )
+ )
+)
+Clustering by haplotype similarity:
+(NNNNN:2.250000:
+ (NTANN:1.000000:
+  (CTAGG:0.000000:
+   (CTAGG:0.000000:
+    {CTAGG},
+    {CTAGG}
+   ),
+   (CTAGG:0.000000:
+    {CTAGG},
+    (CTAGG:0.000000:
+     {CTAGG},
+     {CTAGG}
+    )
+   )
+  ),
+  (NTATN:0.500000:
+   (CTATA:0.000000:
+    (CTATA:0.000000:
+     {CTATA},
+     {CTATA}
+    ),
+    (CTATA:0.000000:
+     {CTATA},
+     (CTATA:0.000000:
+      {CTATA},
+      {CTATA}
+     )
+    )
+   ),
+   (GTATG:0.000000:
+    (GTATG:0.000000:
+     {GTATG},
+     {GTATG}
+    ),
+    (GTATG:0.000000:
+     {GTATG},
+     (GTATG:0.000000:
+      {GTATG},
+      {GTATG}
+     )
+    )
+   )
+  )
+ ),
+ (GCGTN:0.250000:
+  (GCGTA:0.000000:
+   (GCGTA:0.000000:
+    {GCGTA},
+    {GCGTA}
+   ),
+   (GCGTA:0.000000:
+    {GCGTA},
+    (GCGTA:0.000000:
+     {GCGTA},
+     {GCGTA}
+    )
+   )
+  ),
+  (GCGTC:0.000000:
+   (GCGTC:0.000000:
+    {GCGTC},
+    {GCGTC}
+   ),
+   (GCGTC:0.000000:
+    {GCGTC},
+    (GCGTC:0.000000:
+     {GCGTC},
+     {GCGTC}
+    )
+   )
+  )
+ )
+)
diff --git a/lib/tests/expected/hashTest1.out b/lib/tests/expected/hashTest1.out
new file mode 100644
index 0000000..83980d4
--- /dev/null
+++ b/lib/tests/expected/hashTest1.out
@@ -0,0 +1,62 @@
+apple=apple1
+cat=cat1
+dog=dog1
+elephant=elephant1
+frog=frog1
+frog=frog2
+frog=frog3
+frog=frog4
+girl=girl1
+house=house1
+infix=infix1
+jail=jail1
+kite=kite1
+kite=kite2
+kite=kite3
+lamb=lamb1
+mother=mother1
+nana=nana1
+nana=nana2
+ostrich=ostrich1
+pool=pool1
+yak=yak1
+yak=yak2
+zebra=zebra1
+-----------
+keys and values:
+apple apple1
+cat cat1
+dog dog1
+elephant elephant1
+frog frog4 frog3 frog2 frog1
+girl girl1
+house house1
+infix infix1
+jail jail1
+kite kite3 kite2 kite1
+lamb lamb1
+mother mother1
+nana nana2 nana1
+ostrich ostrich1
+pool pool1
+yak yak2 yak1
+zebra zebra1
+----RESIZED HASH-------
+keys and values:
+apple apple1
+cat cat1
+dog dog1
+elephant elephant1
+frog frog4 frog3 frog2 frog1
+girl girl1
+house house1
+infix infix1
+jail jail1
+kite kite3 kite2 kite1
+lamb lamb1
+mother mother1
+nana nana2 nana1
+ostrich ostrich1
+pool pool1
+yak yak2 yak1
+zebra zebra1
diff --git a/lib/tests/expected/htmlExpandUrlTest b/lib/tests/expected/htmlExpandUrlTest
new file mode 100644
index 0000000..02a0572
--- /dev/null
+++ b/lib/tests/expected/htmlExpandUrlTest
@@ -0,0 +1,48 @@
+genome.ucsc.edu credits.html -> genome.ucsc.edu/credits.html
+genome.ucsc.edu /credits.html -> genome.ucsc.edu/credits.html
+More ..'s in "../credits.html" than directories in ""
+genome.ucsc.edu ../credits.html -> genome.ucsc.edu/
+More ..'s in "../news/chimp.html" than directories in ""
+genome.ucsc.edu ../news/chimp.html -> genome.ucsc.edu/
+genome.ucsc.edu http://test.org/credits.html -> http://test.org/credits.html
+http://genome.ucsc.edu credits.html -> http://genome.ucsc.edu/credits.html
+http://genome.ucsc.edu /credits.html -> http://genome.ucsc.edu/credits.html
+More ..'s in "../credits.html" than directories in ""
+http://genome.ucsc.edu ../credits.html -> http://genome.ucsc.edu/
+More ..'s in "../news/chimp.html" than directories in ""
+http://genome.ucsc.edu ../news/chimp.html -> http://genome.ucsc.edu/
+http://genome.ucsc.edu http://test.org/credits.html -> http://test.org/credits.html
+http://genome.ucsc.edu/index.html credits.html -> http://genome.ucsc.edu/credits.html
+http://genome.ucsc.edu/index.html /credits.html -> http://genome.ucsc.edu/credits.html
+More ..'s in "../credits.html" than directories in ""
+http://genome.ucsc.edu/index.html ../credits.html -> http://genome.ucsc.edu/
+More ..'s in "../news/chimp.html" than directories in ""
+http://genome.ucsc.edu/index.html ../news/chimp.html -> http://genome.ucsc.edu/
+http://genome.ucsc.edu/index.html http://test.org/credits.html -> http://test.org/credits.html
+http://genome.ucsc.edu/goldenPath/ credits.html -> http://genome.ucsc.edu/goldenPath/credits.html
+http://genome.ucsc.edu/goldenPath/ /credits.html -> http://genome.ucsc.edu/credits.html
+http://genome.ucsc.edu/goldenPath/ ../credits.html -> http://genome.ucsc.edu/credits.html
+http://genome.ucsc.edu/goldenPath/ ../news/chimp.html -> http://genome.ucsc.edu/news/chimp.html
+http://genome.ucsc.edu/goldenPath/ http://test.org/credits.html -> http://test.org/credits.html
+http://genome.ucsc.edu/goldenPath/downloads.html credits.html -> http://genome.ucsc.edu/goldenPath/credits.html
+http://genome.ucsc.edu/goldenPath/downloads.html /credits.html -> http://genome.ucsc.edu/credits.html
+http://genome.ucsc.edu/goldenPath/downloads.html ../credits.html -> http://genome.ucsc.edu/credits.html
+http://genome.ucsc.edu/goldenPath/downloads.html ../news/chimp.html -> http://genome.ucsc.edu/news/chimp.html
+http://genome.ucsc.edu/goldenPath/downloads.html http://test.org/credits.html -> http://test.org/credits.html
+http://genome.ucsc.edu/goldenPath/hg16/ credits.html -> http://genome.ucsc.edu/goldenPath/hg16/credits.html
+http://genome.ucsc.edu/goldenPath/hg16/ /credits.html -> http://genome.ucsc.edu/credits.html
+http://genome.ucsc.edu/goldenPath/hg16/ ../credits.html -> http://genome.ucsc.edu/goldenPath/credits.html
+http://genome.ucsc.edu/goldenPath/hg16/ ../news/chimp.html -> http://genome.ucsc.edu/goldenPath/news/chimp.html
+http://genome.ucsc.edu/goldenPath/hg16/ http://test.org/credits.html -> http://test.org/credits.html
+http://genome.ucsc.edu/goldenPath/hg16/index.html credits.html -> http://genome.ucsc.edu/goldenPath/hg16/credits.html
+http://genome.ucsc.edu/goldenPath/hg16/index.html /credits.html -> http://genome.ucsc.edu/credits.html
+http://genome.ucsc.edu/goldenPath/hg16/index.html ../credits.html -> http://genome.ucsc.edu/goldenPath/credits.html
+http://genome.ucsc.edu/goldenPath/hg16/index.html ../news/chimp.html -> http://genome.ucsc.edu/goldenPath/news/chimp.html
+http://genome.ucsc.edu/goldenPath/hg16/index.html http://test.org/credits.html -> http://test.org/credits.html
+http://genome.ucsc.edu/ credits.html -> http://genome.ucsc.edu/credits.html
+http://genome.ucsc.edu/ /credits.html -> http://genome.ucsc.edu/credits.html
+More ..'s in "../credits.html" than directories in ""
+http://genome.ucsc.edu/ ../credits.html -> http://genome.ucsc.edu/
+More ..'s in "../news/chimp.html" than directories in ""
+http://genome.ucsc.edu/ ../news/chimp.html -> http://genome.ucsc.edu/
+http://genome.ucsc.edu/ http://test.org/credits.html -> http://test.org/credits.html
diff --git a/lib/tests/expected/htmlMime1.out b/lib/tests/expected/htmlMime1.out
new file mode 100644
index 0000000..5a17d23
--- /dev/null
+++ b/lib/tests/expected/htmlMime1.out
@@ -0,0 +1,13 @@
+3490 ok
+3491 ok
+3492 ok
+3493 ok
+3494 ok
+3495 ok
+3496 ok
+3497 ok
+3498 ok
+3499 ok
+3500 ok
+3501 ok
+3502 ok
diff --git a/lib/tests/expected/mime1.out b/lib/tests/expected/mime1.out
new file mode 100644
index 0000000..be30681
--- /dev/null
+++ b/lib/tests/expected/mime1.out
@@ -0,0 +1,17 @@
+content-type: multipart/form-data, boundary=AaB03x
+nested MIME structure
+
+ content-disposition: form-data; name="field1"
+ main:[form-data]
+ name:[field1]
+ size:[8]
+ data:[Joe Blow]
+
+ content-disposition: form-data; name="pics"; filename="file1.txt"
+ main:[form-data]
+ name:[pics]
+ filename:[file1.txt]
+ content-type: text/plain
+ size:[30]
+ data:[ ... contents of file1.txt ...]
+
diff --git a/lib/tests/expected/mime2.out b/lib/tests/expected/mime2.out
new file mode 100644
index 0000000..a8c1ee7
--- /dev/null
+++ b/lib/tests/expected/mime2.out
@@ -0,0 +1,35 @@
+content-type: multipart/form-data, boundary=AaB03x; extra=whocares
+nested MIME structure
+
+ content-disposition: form-data; name="field1"
+ main:[form-data]
+ name:[field1]
+ size:[8]
+ data:[Joe Blow]
+
+ content-disposition: form-data; name="pics"
+ main:[form-data]
+ name:[pics]
+ content-type: multipart/mixed, boundary="BbC04y"
+ size:[0]
+ data:[(null)]
+
+ nested MIME structure
+
+  content-disposition: attachment; filename="file1.txt"
+  main:[attachment]
+  name:[(null)]
+  filename:[file1.txt]
+  content-type: text/plain
+  size:[29]
+  data:[... contents of file1.txt ...]
+
+  content-disposition: attachment; filename="file2.gif"
+  main:[attachment]
+  name:[(null)]
+  filename:[file2.gif]
+  content-type: image/gif
+  content-transer-encoding: binary
+  size:[29]
+  data:[  ...contents of file2.gif...]
+
diff --git a/lib/tests/expected/mime3.out b/lib/tests/expected/mime3.out
new file mode 100644
index 0000000..4d7c578
--- /dev/null
+++ b/lib/tests/expected/mime3.out
@@ -0,0 +1,44 @@
+content-type: multipart/form-data, boundary=AaB03x
+nested MIME structure
+
+ content-disposition: form-data; name="field1"
+ main:[form-data]
+ name:[field1]
+ size:[8]
+ data:[Joe Blow]
+
+ content-disposition: form-data; name="pics"
+ main:[form-data]
+ name:[pics]
+ content-type: multipart/mixed, boundary=BbC04y
+ size:[0]
+ data:[(null)]
+
+ nested MIME structure
+
+  content-disposition: attachment; filename="file1.txt"
+  main:[attachment]
+  name:[(null)]
+  filename:[file1.txt]
+  content-type: text/plain
+  size:[29]
+  data:[... contents of file1.txt ...]
+
+  content-disposition: attachment; filename="file2.gif"
+  main:[attachment]
+  name:[(null)]
+  filename:[file2.gif]
+  content-type: image/gif
+  content-transer-encoding: binary
+  size:[29]
+  data:[  ...contents of file2.gif...]
+
+  content-disposition: attachment; filename="file3.gif"
+  main:[attachment]
+  name:[(null)]
+  filename:[file3.gif]
+  content-type: image/gif
+  content-transer-encoding: binary
+  size:[29]
+  data:[  ...contents of file3.gif...]
+
diff --git a/lib/tests/expected/mime4.out b/lib/tests/expected/mime4.out
new file mode 100644
index 0000000..624d569
--- /dev/null
+++ b/lib/tests/expected/mime4.out
@@ -0,0 +1,53 @@
+content-type: multipart/form-data, boundary=AaB03x
+nested MIME structure
+
+ content-disposition: form-data; name="field1"
+ main:[form-data]
+ name:[field1]
+ size:[8]
+ data:[Joe Blow]
+
+ content-disposition: form-data; name="pics"
+ main:[form-data]
+ name:[pics]
+ content-type: multipart/mixed, boundary=BbC04y
+ size:[0]
+ data:[(null)]
+
+ nested MIME structure
+
+  content-disposition: attachment; filename="file1.txt"
+  main:[attachment]
+  name:[(null)]
+  filename:[file1.txt]
+  content-type: text/plain
+  size:[29]
+  data:[... contents of file1.txt ...]
+
+  content-disposition: attachment; filename="file2.gif"
+  main:[attachment]
+  name:[(null)]
+  filename:[file2.gif]
+  content-type: image/gif
+  content-transer-encoding: binary
+  size:[29]
+  data:[  ...contents of file2.gif...]
+
+  content-disposition: form-data; name="pics"
+  main:[form-data]
+  name:[pics]
+  content-type: multipart/mixed, boundary=CcD05y
+  size:[0]
+  data:[(null)]
+
+  nested MIME structure
+
+   content-disposition: attachment; filename="file4.gz"
+   main:[attachment]
+   name:[(null)]
+   filename:[file4.gz]
+   content-type: application/octetsomething
+   content-transer-encoding: binary
+   size:[28]
+   data:[  ...contents of file4.gz...]
+
diff --git a/lib/tests/expected/mime5.out b/lib/tests/expected/mime5.out
new file mode 100644
index 0000000..9e5e8aa
--- /dev/null
+++ b/lib/tests/expected/mime5.out
@@ -0,0 +1,58 @@
+content-type: multipart/form-data, boundary=----------0xKhTmLbOuNdArY
+nested MIME structure
+
+ content-disposition: form-data; name="hgsid"
+ main:[form-data]
+ name:[hgsid]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="org"
+ main:[form-data]
+ name:[org]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="db"
+ main:[form-data]
+ name:[db]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="type"
+ main:[form-data]
+ name:[type]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="sort"
+ main:[form-data]
+ name:[sort]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="output"
+ main:[form-data]
+ name:[output]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="userSeq"
+ main:[form-data]
+ name:[userSeq]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="Submit"
+ main:[form-data]
+ name:[Submit]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="seqFile"; filename=""
+ main:[form-data]
+ name:[seqFile]
+ filename:[]
+ size:[0]
+ data:[]
+
diff --git a/lib/tests/expected/mimeAltHead.out b/lib/tests/expected/mimeAltHead.out
new file mode 100644
index 0000000..0fe85aa
--- /dev/null
+++ b/lib/tests/expected/mimeAltHead.out
@@ -0,0 +1,61 @@
+Alternate Header Text:
+CONTENT-TYPE:multipart/form-data; boundary=----------0xKhTmLbOuNdArY
+
+content-type: multipart/form-data; boundary=----------0xKhTmLbOuNdArY
+nested MIME structure
+
+ content-disposition: form-data; name="hgsid"
+ main:[form-data]
+ name:[hgsid]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="org"
+ main:[form-data]
+ name:[org]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="db"
+ main:[form-data]
+ name:[db]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="type"
+ main:[form-data]
+ name:[type]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="sort"
+ main:[form-data]
+ name:[sort]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="output"
+ main:[form-data]
+ name:[output]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="userSeq"
+ main:[form-data]
+ name:[userSeq]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="Submit"
+ main:[form-data]
+ name:[Submit]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="seqFile"; filename=""
+ main:[form-data]
+ name:[seqFile]
+ filename:[]
+ size:[0]
+ data:[]
+
diff --git a/lib/tests/expected/mimeAutoBoundary.out b/lib/tests/expected/mimeAutoBoundary.out
new file mode 100644
index 0000000..9c5bd51
--- /dev/null
+++ b/lib/tests/expected/mimeAutoBoundary.out
@@ -0,0 +1,58 @@
+content-type: multipart/form-data; boundary=----------0xKhTmLbOuNdArY
+nested MIME structure
+
+ content-disposition: form-data; name="hgsid"
+ main:[form-data]
+ name:[hgsid]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="org"
+ main:[form-data]
+ name:[org]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="db"
+ main:[form-data]
+ name:[db]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="type"
+ main:[form-data]
+ name:[type]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="sort"
+ main:[form-data]
+ name:[sort]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="output"
+ main:[form-data]
+ name:[output]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="userSeq"
+ main:[form-data]
+ name:[userSeq]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="Submit"
+ main:[form-data]
+ name:[Submit]
+ size:[0]
+ data:[]
+
+ content-disposition: form-data; name="seqFile"; filename=""
+ main:[form-data]
+ name:[seqFile]
+ filename:[]
+ size:[0]
+ data:[]
+
diff --git a/lib/tests/expected/mimeBin.out b/lib/tests/expected/mimeBin.out
new file mode 100644
index 0000000..bfdeab4
--- /dev/null
+++ b/lib/tests/expected/mimeBin.out
@@ -0,0 +1,36 @@
+content-type: multipart/form-data, boundary=AaB03x
+nested MIME structure
+
+ content-disposition: form-data; name="field1"
+ main:[form-data]
+ name:[field1]
+ size:[8]
+ data:[Joe Blow]
+
+ content-disposition: form-data; name="pics"
+ main:[form-data]
+ name:[pics]
+ content-type: multipart/mixed, boundary=BbC04y
+ size:[0]
+ data:[(null)]
+
+ nested MIME structure
+
+  content-disposition: attachment; filename="file1.txt"
+  main:[attachment]
+  name:[(null)]
+  filename:[file1.txt]
+  content-type: text/plain
+  size:[29]
+  data:[... contents of file1.txt ...]
+
+  content-disposition: attachment; filename="file2.gif"
+  main:[attachment]
+  name:[(null)]
+  filename:[file2.gif]
+  content-type: image/gif
+  content-transer-encoding: binary
+  size:[29]
+  binary (contains zeros)
+  data:[<binary data not safe to print>]
+
diff --git a/lib/tests/expected/mimeBlat.out b/lib/tests/expected/mimeBlat.out
new file mode 100644
index 0000000..7aad67a
--- /dev/null
+++ b/lib/tests/expected/mimeBlat.out
@@ -0,0 +1,121 @@
+Alternate Header Text:
+CONTENT-TYPE:multipart/form-data; boundary=----------0xKhTmLbOuNdArY
+
+content-type: multipart/form-data; boundary=----------0xKhTmLbOuNdArY
+nested MIME structure
+
+ content-disposition: form-data; name="hgsid"
+ main:[form-data]
+ name:[hgsid]
+ size:[8]
+ data:[63932244]
+
+ content-disposition: form-data; name="org"
+ main:[form-data]
+ name:[org]
+ size:[5]
+ data:[Human]
+
+ content-disposition: form-data; name="db"
+ main:[form-data]
+ name:[db]
+ size:[4]
+ data:[hg17]
+
+ content-disposition: form-data; name="type"
+ main:[form-data]
+ name:[type]
+ size:[12]
+ data:[BLAT's guess]
+
+ content-disposition: form-data; name="sort"
+ main:[form-data]
+ name:[sort]
+ size:[11]
+ data:[query,score]
+
+ content-disposition: form-data; name="output"
+ main:[form-data]
+ name:[output]
+ size:[9]
+ data:[hyperlink]
+
+ content-disposition: form-data; name="userSeq"
+ main:[form-data]
+ name:[userSeq]
+ size:[3502]
+ data:[>NM_000230 (LEP)
+gtaggaatcgcagcgccaacggttgcaaggcccaagaagccatcctgggaaggaaaatgc
+attggggaaccctgtgcggattcttgtggctttggccctatcttttctatgtccaagctg
+tgcccatccaaaaagtccaagatgacaccaaaaccctcatcaagacaattgtcaccagga
+tcaatgacatttcacacacgcagtcagtctcctccaaacagaaagtcaccggtttggact
+tcattcctgggctccaccccatcctgaccttatccaagatggaccagacactggcagtct
+accaacagatcctcaccagtatgccttccagaaacgtgatccaaatatccaacgacctgg
+agaacctccgggatcttcttcacgtgctggccttctctaagagctgccacttgccctggg
+ccagtggcctggagaccttggacagcctggggggtgtcctggaagcttcaggctactcca
+cagaggtggtggccctgagcaggctgcaggggtctctgcaggacatgctgtggcagctgg
+acctcagccctgggtgctgaggccttgaaggtcactcttcctgcaaggactacgttaagg
+gaaggaactctggcttccaggtatctccaggattgaagagcattgcatggacacccctta
+tccaggactctgtcaatttccctgactcctctaagccactcttccaaaggcataagaccc
+taagcctccttttgcttgaaaccaaagatatatacacaggatcctattctcaccaggaag
+ggggtccacccagcaaagagtgggctgcatctgggattcccaccaaggtcttcagccatc
+aacaagagttgtcttgtcccctcttgacccatctccccctcactgaatgcctcaatgtga
+ccaggggtgatttcagagagggcagaggggtaggcagagcctttggatgaccagaacaag
+gttccctctgagaattccaaggagttccatgaagaccacatccacacacgcaggaactcc
+cagcaacacaagctggaagcacatgtttatttattctgcattttattctggatggatttg
+aagcaaagcaccagcttctccaggctctttggggtcagccagggccaggggtctccctgg
+agtgcagtttccaatcccatagatgggtctggctgagctgaacccattttgagtgactcg
+agggttgggttcatctgagcaagagctggcaaaggtggctctccagttagttctctcgta
+actggtttcatttctactgtgactgatgttacatcacagtgtttgcaatggtgttgccct
+gagtggatctccaaggaccaggttattttaaaaagatttgttttgtcaagtgtcatatgt
+aggtgtctgcacccaggggtggggaatgtttgggcagaagggagaaggatctagaatgtg
+ttttctgaataacatttgtgtggtgggttctttggaaggagtgagatcattttcttatct
+tctgcaattgcttaggatgtttttcatgaaaatagctctttcaggggggttgtgaggcct
+ggccaggcaccccctggagagaagtttctggccctggctgaccccaaagagcctggagaa
+gctgatgctttgcttcaaatccatccagaataaaacgcaaagggctgaaagccatttgtt
+ggggcagtggtaagctctggctttctccgactgctagggagtggtctttcctatcatgga
+gtgacggtcccacactggtgactgcgatcttcagagcaggggtccttggtgtgaccctct
+gaatgggtccagggttgatcacactctgggtttattacatggcagtgttcctatttgggg
+cttgcatgccaaattgtagttcttgtctgattggctcacccaagcaaggccaaaattacc
+aaaaatcttggggggtttttactccagtggtgaagaaaactcctttagcaggtggtcctg
+agacctgacaagcactgctaggcgagtgccaggactccccaggccaggccaccaggatgc
+ccttcccactggaggtcacattcaggaagatgaaagaggaggtttggggtctgccaccat
+cctgctgctgtgtttttgctatcacacagtgggtggtggatctgtccaaggaaacttgaa
+tcaaagcagttaactttaagactgagcacctgcttcatgctcagccctgactggtgctat
+aggctggagaagctcacccaataaacattaagattgaggcctgccctcagggatcttgcg
+ttcccagtggtcaaaccgcactcacccatgtgccaaggtggggtatttaccacagcagct
+gaacagccaaatgcatggtgcagttgacagcaggtgggaaatggtatgagctgagggggg
+ccgtgcccaggggcccacagggaaccctgcttgcactttgtaacatgtttacttttcagg
+gcatcttagcttctattatagccacatccctttgaaacaagataactgagaatttaaaaa
+taagaaaatacataagaccataacagccaacaggtggcaggaccaggactatagcccagg
+tcctctgatacccagagcattacgtgagccaggtaatgagggactggaaccagggagacc
+gagcgctttctggaaaagaggagtttcgaggtagagtttgaaggaggtgagggatgtgaa
+ttgcctgcagagagaagcctgttttgttggaaggtttggtgtgtggagatgcagaggtaa
+aagtgtgagcagtgagttacagcgagaggcagagaaagaagagacaggagggcaagggcc
+atgctgaagggaccttgaagggtaaagaagtttgatattaaaggagttaagagtagcaag
+ttctagagaagaggctggtgctgtggccagggtgagagctgctctggaaaatgtgaccca
+gatcctcacaaccacctaatcaggctgaggtgtcttaagccttttgctcacaaaacctgg
+cacaatggctaattcccagagtgtgaaacttcctaagtataaatggttgtctgtttttgt
+aacttaaaaaaaaaaaaaaaagtttggccgggtgcggtggctcacgcctgtaatcccagc
+actttgggaggccaaggtggggggatcacaaggtcactagatggcgagcatcctggccaa
+catggtgaaaccccgtctctactaaaaacacaaaagttagctgagcgtggtggcgggcgc
+ctgtagtcccagccactcgggaggctgagacaggagaatcgcttaaacctgggaggcgga
+gagtacagtgagccaagatcgcgccactgcactccggcctgatgacagagcgagattccg
+tcttaaaaaaaaaaaaaaaaaaagtttgtttttaaaaaaatctaaataaaataactttgc
+cccctg
+
+]
+
+ content-disposition: form-data; name="Submit"
+ main:[form-data]
+ name:[Submit]
+ size:[6]
+ data:[Submit]
+
+ content-disposition: form-data; name="seqFile"; filename=""
+ main:[form-data]
+ name:[seqFile]
+ filename:[]
+ size:[0]
+ data:[]
+
diff --git a/lib/tests/expected/noName1.html b/lib/tests/expected/noName1.html
new file mode 100644
index 0000000..8bf0d6f
--- /dev/null
+++ b/lib/tests/expected/noName1.html
@@ -0,0 +1,121 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML><HEAD><TITLE>Dilbert is Alive and Well!!!</TITLE>
+<META http-equiv=Content-Type content="text/html; charset=iso-8859-1">
+<STYLE type=text/css>BLOCKQUOTE {
+	PADDING-BOTTOM: 0px; PADDING-TOP: 0px
+}
+DL {
+	PADDING-BOTTOM: 0px; PADDING-TOP: 0px
+}
+UL {
+	PADDING-BOTTOM: 0px; PADDING-TOP: 0px
+}
+OL {
+	PADDING-BOTTOM: 0px; PADDING-TOP: 0px
+}
+LI {
+	PADDING-BOTTOM: 0px; PADDING-TOP: 0px
+}
+</STYLE>
+
+<META content="MSHTML 6.00.2800.1543" name=GENERATOR></HEAD>
+<BODY bgColor=#ffffff>
+<DIV><FONT face=Arial size=2></FONT><BR></DIV>
+<BLOCKQUOTE cite="" type="cite">
+  <BLOCKQUOTE cite="" type="cite">
+    <BLOCKQUOTE cite="" type="cite" align="center"><FONT 
+    size=-1><BR></FONT></BLOCKQUOTE>
+    <BLOCKQUOTE cite="" type="cite" align="center"><IMG height=97 
+      alt="image001 12.jpg" src="image001 12.jpg" 
+      width=180><FONT face=Verdana size=-1><BR><BR></FONT><FONT face=Papyrus 
+      size=-1><BR></FONT><FONT face=Papyrus size=+1>A magazine recently ran a 
+      "Dilbert Quotes" contest. They were looking for people to submit quotes 
+      from their real-life Dilbert-comic-strip-type managers. These were voted 
+      the top ten quotes from the managers we work for in corporate 
+      America:</FONT><FONT face=Verdana size=-1><BR><BR><IMG height=150 
+      alt="image002 2.jpg" src="image002 2.jpg" 
+      width=136></FONT><FONT size=-1><BR> <BR><FONT 
+      face=Papyrus>"</FONT></FONT><FONT face=Papyrus size=+1>As of tomorrow, 
+      employees will only be able to access the building using individual 
+      security cards. Pictures will be taken next Wednesday, and employees will 
+      receive their cards in two weeks."</FONT><FONT size=-1><BR></FONT><FONT 
+      face=Papyrus color=#ff0000 size=+1><I>(This was the winning quote from 
+      Fred Dales, Microsoft Corp. in Redmond WA)</I></FONT><FONT 
+      size=-1><BR><FONT face=Verdana><BR><BR><IMG height=141 
+      alt="image003 3.jpg" src="image003 3.jpg" 
+      width=126></FONT><BR> <BR><FONT face=Papyrus>"</FONT></FONT><FONT 
+      face=Papyrus size=+1>What I need is an exact list of specific unknown 
+      problems we might encounter."</FONT><FONT size=-1><BR></FONT><FONT 
+      face=Papyrus color=#0000ff size=+1><I>(Lykes Lines 
+      Shipping)</I></FONT><FONT size=-1><BR></FONT><FONT face=Verdana 
+      size=+1><BR></FONT><FONT face=Verdana size=-1><BR><IMG height=116 
+      alt="image004 1.gif" src="image004 1.gif" 
+      width=92></FONT><FONT size=-1><BR> <BR><FONT 
+      face=Papyrus>"</FONT></FONT><FONT face=Papyrus size=+1>E-mail is not to be 
+      used to pass on information or data. It should be used only for company 
+      business."</FONT><FONT size=-1><BR></FONT><FONT face=Papyrus color=#0000ff 
+      size=+1><I>(Accounting manager, Electric Boat Company)</I></FONT><FONT 
+      size=-1><BR><FONT face=Verdana><BR><BR><IMG height=151 
+      alt="image005 2.jpg" src="image005 2.jpg" 
+      width=92><BR> <BR></FONT><FONT face=Papyrus>"</FONT></FONT><FONT 
+      face=Papyrus size=+1>This project is so important we can't let things that 
+      are more important interfere with it."</FONT><FONT 
+      size=-1><BR></FONT><FONT face=Papyrus color=#0000ff 
+      size=+1><I>(Advertising/Marketing manager,</I></FONT><FONT 
+      size=-1><BR></FONT><FONT face=Papyrus color=#0000ff size=+1><I>United 
+      Parcel Service)</I></FONT><FONT size=-1><BR><FONT 
+      face=Verdana><BR><BR><IMG height=150 alt=image006.jpg 
+      src="image006.jpg" 
+      width=111><BR> <BR></FONT><FONT face=Papyrus>"</FONT></FONT><FONT 
+      face=Papyrus size=+1>Doing it right is no excuse</FONT><FONT 
+      size=-1><BR></FONT><FONT face=Papyrus size=+1>for not meeting the 
+      schedule<I>."</I></FONT><FONT size=-1><BR></FONT><FONT face=Papyrus 
+      color=#0000ff size=+1><I>(Plant Manager, Delco 
+      Corporation)</I></FONT><FONT size=-1><BR><FONT face=Verdana><BR><BR><IMG 
+      height=134 alt=image007.jpg 
+      src="image007.jpg" 
+      width=216><BR> <BR></FONT><FONT face=Papyrus>"</FONT></FONT><FONT 
+      face=Papyrus size=+1>No one will believe you solved</FONT><FONT 
+      size=-1><BR></FONT><FONT face=Papyrus size=+1>this problem in one 
+      day!</FONT><FONT size=-1><BR></FONT><FONT face=Papyrus size=+1>We've been 
+      working on it for months.</FONT><FONT size=-1><BR></FONT><FONT 
+      face=Papyrus size=+1>Now go act busy for a few weeks and</FONT><FONT 
+      size=-1><BR></FONT><FONT face=Papyrus size=+1>I'll let you know when it's 
+      time to tell them."</FONT><FONT size=-1><BR></FONT><FONT face=Papyrus 
+      color=#0000ff size=+1><I>(R&D supervisor, Minnesota Mining and 
+      Manufacturing/3M Corp.)</I></FONT><FONT size=-1><BR><FONT 
+      face=Verdana><BR><BR><IMG height=111 alt="image008 1.jpg" 
+      src="image008 1.jpg" 
+      width=192></FONT><BR> <BR></FONT><FONT face=Papyrus size=+1><B>Quote 
+      from the Boss:</B></FONT><FONT size=-1><BR></FONT><FONT face=Papyrus 
+      size=+1><B>"Teamwork is a lot of people doing</B></FONT><FONT 
+      size=-1><BR></FONT><FONT face=Papyrus size=+1><B>what I 
+      say."</B></FONT><FONT size=-1><BR></FONT><FONT face=Papyrus color=#0000ff 
+      size=+1><I><B>(Marketing executive, Citrix 
+      Corporation)</B></I></FONT><FONT size=-1><BR><FONT 
+      face=Verdana><B><BR><BR><IMG height=117 alt="image009 1.jpg" 
+      src="image009 1.jpg" 
+      width=156></B></FONT><BR> <BR></FONT><FONT face=Papyrus size=+1><B>My 
+      sister passed away and her funeral was scheduled for Monday. When I told 
+      my Boss, he said she died on purpose so that I would have to miss work on 
+      the busiest day of the year. He then asked if we could change her burial 
+      to Friday.</B></FONT><FONT size=-1><BR></FONT><FONT face=Papyrus 
+      size=+1><B>He said,<I> "That would be better for me."</I></B></FONT><FONT 
+      size=-1><BR></FONT><FONT face=Papyrus color=#0000ff 
+      size=+1><I><B>(Shipping executive, FTD Florists)</B></I></FONT><FONT 
+      size=-1><BR><FONT face=Verdana><B><BR><BR><IMG height=175 
+      alt="image010 1.gif" src="image010 1.gif" 
+      width=200></B></FONT><BR> </FONT></BLOCKQUOTE>
+    <BLOCKQUOTE cite="" type="cite" align="center"><FONT face=Papyrus 
+      size=-1><B>"</B></FONT><FONT face=Papyrus size=+1><B>We know that 
+      communication is a problem, but the company is not going to discuss it 
+      with the employees." </B></FONT></BLOCKQUOTE>
+    <BLOCKQUOTE cite="" type="cite" align="center"><FONT face=Papyrus 
+      color=#0000ff size=+1><I><B>(Switching supervisor, AT&T Long Lines 
+      Division)</B></I></FONT><FONT face=Verdana size=-1><B><BR><BR><BR><IMG 
+      height=203 alt=image011.gif 
+      src="image011.gif" 
+    width=203></B></FONT></BLOCKQUOTE>
+    <BLOCKQUOTE cite="" type="cite"><FONT color=#000080></FONT><FONT 
+      size=-1><BR></FONT><FONT face="Comic Sans MS" 
+    color=#800040> </FONT></BLOCKQUOTE></BLOCKQUOTE></BLOCKQUOTE></BODY></HTML>
diff --git a/lib/tests/expected/pipelineExecError.err b/lib/tests/expected/pipelineExecError.err
new file mode 100644
index 0000000..6bc834d
--- /dev/null
+++ b/lib/tests/expected/pipelineExecError.err
@@ -0,0 +1,2 @@
+No such file or directory
+exec failed: ./thatDoesNotCompute
diff --git a/lib/tests/expected/pipelineExecError.parent.err b/lib/tests/expected/pipelineExecError.parent.err
new file mode 100644
index 0000000..2c03c76
--- /dev/null
+++ b/lib/tests/expected/pipelineExecError.parent.err
@@ -0,0 +1,2 @@
+process exited with 255: "./thatDoesNotCompute" in pipeline "./thatDoesNotCompute"
+pipeline exited with 255
diff --git a/lib/tests/expected/pipelineWriteErr.out b/lib/tests/expected/pipelineWriteErr.out
new file mode 100644
index 0000000..e3968ed
--- /dev/null
+++ b/lib/tests/expected/pipelineWriteErr.out
@@ -0,0 +1 @@
+OUT2
diff --git a/lib/tests/expected/quotedPDecode.out b/lib/tests/expected/quotedPDecode.out
new file mode 100644
index 0000000..df2aa38
--- /dev/null
+++ b/lib/tests/expected/quotedPDecode.out
@@ -0,0 +1,3 @@
+original input: [taxes=20are=20quite=20high=20=]
+quoted-printable encoding: [taxes=3d20are=3d20quite=3d20high=3d20=3d=]
+quoted-p decoding: [taxes are quite high ]
diff --git a/lib/tests/expected/quotedPEncode.out b/lib/tests/expected/quotedPEncode.out
new file mode 100644
index 0000000..41fe883
--- /dev/null
+++ b/lib/tests/expected/quotedPEncode.out
@@ -0,0 +1,4 @@
+original input: [taxes are quite high ]
+quoted-printable encoding: [taxes=20are=20quite=20high=20=]
+quoted-p decoding: [taxes are quite high 
+]
diff --git a/lib/tests/expected/simple1.wc b/lib/tests/expected/simple1.wc
new file mode 100644
index 0000000..4bc1500
--- /dev/null
+++ b/lib/tests/expected/simple1.wc
@@ -0,0 +1 @@
+      6       6      28
diff --git a/lib/tests/expected/tabixFetch1kGNoGenotypes.out b/lib/tests/expected/tabixFetch1kGNoGenotypes.out
new file mode 100644
index 0000000..d7f2f0a
--- /dev/null
+++ b/lib/tests/expected/tabixFetch1kGNoGenotypes.out
@@ -0,0 +1,6 @@
+*** First (up to) 10 lines from query on 2:26790860-194631353:
+2	26790860	ns17	T	<INS>	.	.	CIPOS=0,0;END=26790860;CIEND=-0,0;SAMPLE=NA12878,NA12891,NA12892;PT=SLX;AL=SOAP;SVLEN=2387;INSSEQ=GGGCCCTCCATCTGGAGTGGCTGGGGCATAGACAGGGCACAGTGCCCTTTGGACCAGAGCAAGTATAGGGGACTTCTGAAAGGAAACAGTGCCACATAGCTAACGTCAAAGGCCAGCAGGCAGAAGCCCAGCCCTCTCCCTCCCGTCCCTCAGGCTGCATTGTTCCTGTCTCTGCCTTGCTCTGCCTTTCTCGGGCTTCTCTTCCCCCGCATGTGGCTTGGGCTTACCCTGGTCCCAGCCAGGACTCACCTCTTTCTAACCCTGCAGCTCAGCCCCTCACAGCTGACCCAGCCCCTCAGCCCATCACAATTCCTGGAAGAGAGAATGTGAATTGCTAAGCCCAGCCAAGTCCTCTCAGCCCAGGTG [...]
+2	46973364	ns18	GTTCAGTCCTGTGGGACTTGAGCCACTGAGG	<INS>	.	.	NOVEL;CIPOS=0,0;END=46973364;CIEND=-0,0;SAMPLE=NA12878;PT=SLX/454;AL=Cortex_DeNovo;SVLEN=73;INSSEQ=GCCGTCAATGGCCATGCCCCATCCTGTCCTCTTGGGCTGTACCCTCAGCTGGGGGCAGGGGACCCTCAGCCTGCTTCAGTCCTGTGGGACTTGAGCCACTGAGG
+2	76637610	ns19	G	<INS>	.	.	NOVEL;CIPOS=0,0;END=76637610;CIEND=-0,0;SAMPLE=NA12878;PT=SLX/454;AL=Cortex_Ref,CortexDeNovo;SVLEN=172;INSSEQ=CAGGAGTTGGGCTGAGATTAAAACATAAAGTTACTAGATCCACAGTCAATTCATTGACCATGCTCTTCATTTGAGAAAACACTTAATGCTTGTTTCCCACTTTGTTCCTTTAAATTGCTACAATTCCAGGGTTATTTCAGAGAACTCTCTTTTCGCAATAATTATAAGAATT
+2	171613233	ns20	C	<INS>	.	.	NOVEL;CIPOS=0,354;END=171613587;CIEND=-354,0;SAMPLE=NA12878;PT=SLX/454;AL=Cortex_Ref;SVLEN=72;INSSEQ=TCTAATATCACAAGGACATTATTGTGATATCACAATAATCACACAATAATCAAACAAGAGTTTGATATCTGC
+2	194631353	ns21	G	<INS>	.	.	NOVEL;CIPOS=0,0;END=194631353;CIEND=-0,0;SAMPLE=NA12878,NA12891,NA12892;PT=SLX;AL=SOAP;SVLEN=1421;INSSEQ=TAGAGAAGCATGCCTATTCATGGATTGGAATGCCTGATATAAGAAAGAGCTAATTCTCCCAAATGTATCTATAGGTTTATTGTAATTAATTTCTTTCAAGCTCCCTGAAAGTCTCTTATGTAAATAGATAGTAAATACATAAATTTACTCTAAAATGTACGTGGAAGGACAAAGGTCCTAGAATAGCTGAACATTGACATAACTCACATTTTATGCAAAAATAGATTCACAATCAACCATGGAGTTTAATGTGAAATGTTAATGTATAAAATTTAGAAAAACATATGAGAAAAGCTTCAGGAAAAAGGGCTAAGCAAATGGTTCTTAGATTTGACACCAAATTCATTACTGATAAAAG [...]
diff --git a/lib/tests/expected/tabixFetch1kGWithGenotypes.out b/lib/tests/expected/tabixFetch1kGWithGenotypes.out
new file mode 100644
index 0000000..459dd48
--- /dev/null
+++ b/lib/tests/expected/tabixFetch1kGWithGenotypes.out
@@ -0,0 +1,7 @@
+*** First (up to) 10 lines from query on 2:26793738-26794385:
+2	26793738	rs1662988	C	T	.	PASS	AA=C;AC=73;AN=118;DP=227;HM2;HM3	GT:DP:CB	1|0:1:SMB	1|1:3:SMB	1|0:1:SMB	0|1:3:SMB	1|1:3:SMB	1|1:6:SMB	1|1:5:SMB	1|1:11:SMB	1|1:4:SMB	0|1:7:SMB	0|0:6:SMB	1|1:1:SMB	1|1:2:SMB	1|0:6:SMB	0|0:6:SMB	0|0:3:SM	1|1:5:SMB	1|0:3:SMB	1|1:3:SMB	1|1:2:MB	1|1:4:SMB	0|1:5:SMB	0|0:4:SMB	1|1:3:SMB	1|0:2:SMB	1|1:4:SMB	0|0:8:SMB	1|1:3:SMB	0|1:2:SMB	1|0:1:SMB	1|1:8:SMB	1|1:6:SMB	1|0:14:SMB	0|0:5:SMB	1|0:2:SMB	1|1:2:SMB	1|0:4:SMB	0|0:2:SMB	0|1:6:SMB	1|1:6:SMB	1|0:4:SMB	1|0:2:SM [...]
+2	26793756	.	A	G	.	PASS	AA=A;AC=1;AN=118;DP=237	GT:DP:CB	0|0:1:SMB	0|0:0:SMB	0|0:5:SMB	0|0:2:SMB	0|0:5:SMB	0|0:8:SMB	0|0:4:SMB	0|0:7:SMB	0|0:3:SMB	0|0:4:SMB	0|0:3:SMB	0|0:2:SMB	0|0:1:SMB	0|0:5:SMB	0|0:8:SMB	0|0:3:SMB	0|0:7:SMB	0|0:4:SMB	0|0:3:SMB	0|0:2:SMB	0|0:4:SMB	0/1:8:SMB	0|0:8:SMB	0|0:5:SMB	0|0:5:SMB	0|0:5:SMB	0|0:4:SMB	0|0:2:SMB	0|0:3:SMB	0|0:3:SMB	0|0:10:SMB	0|0:5:SMB	0|0:7:SMB	0|0:10:SMB	0|0:1:SMB	0|0:1:SMB	0|0:4:SMB	0|0:3:SMB	0|0:10:SMB	0|0:3:SMB	0|0:4:SMB	0|0:2:SMB	0|0:0:SMB	0| [...]
+2	26793798	rs12468863	C	T	.	PASS	AA=C;AC=11;AN=118;DP=227;HM2	GT:DP:CB	0|0:1:SMB	0|0:1:SMB	0|0:4:SMB	0|0:5:SMB	0|0:7:SMB	0|0:3:SMB	0|0:10:SMB	0|0:4:SMB	0|0:2:SMB	1|0:4:SMB	1|0:3:SMB	0|0:2:SMB	0|0:2:SMB	0|0:2:SMB	0|0:2:SMB	0|0:0:SMB	0|0:5:SMB	0|0:3:SMB	0|0:4:SMB	0|0:1:SMB	0|0:5:SMB	0|0:3:SMB	1|0:5:SMB	0|0:8:SMB	0|0:4:SMB	0|0:5:SMB	0|0:9:SMB	0|0:4:SMB	0|0:8:SMB	0|0:1:SMB	0|0:6:SMB	0|0:4:SMB	0|1:9:SMB	1|1:6:SMB	0|1:1:SMB	0|0:2:SMB	0|0:5:SMB	0|0:0:SMB	0|0:11:SMB	0|0:6:SMB	0|0:5:SMB	0|0:2:SMB [...]
+2	26794095	rs4233713	C	T	.	PASS	AA=C;AC=74;AN=118;DP=176	GT:DP:CB	1|0:4:SMB	1|1:3:SMB	1|0:1:SMB	0|1:2:SMB	1|1:5:SMB	1|1:2:SMB	1|1:0:SMB	1|1:5:SMB	1|1:6:SMB	0|1:4:SMB	0|0:0:SB	1|1:0:SMB	1|1:1:SB	1|0:5:SMB	0|0:4:SMB	1|0:0:SMB	1|1:2:SMB	1|1:3:SMB	1|1:4:SMB	1|1:1:SMB	1|1:4:SMB	0|1:3:SMB	0|0:3:SMB	1|1:3:SMB	1|0:3:SMB	1|1:7:SMB	0|0:2:SMB	1|1:3:SMB	0|1:9:SMB	1|0:2:SMB	1|1:5:MB	1|1:4:SMB	1|0:5:SMB	0|0:7:SMB	1|0:0:SB	1|1:2:SMB	0|0:2:SM	0|0:4:SMB	1|1:14:SMB	0|1:3:MB	1|0:3:SMB	1|0:4:SMB	0|1:1:SMB	0 [...]
+2	26794307	rs1662989	G	A	.	PASS	AA=G;AC=76;AN=118;DP=248	GT:DP:CB	1|0:0:SMB	1|1:1:SMB	1|0:2:SMB	0|1:4:SMB	1|1:8:SMB	1|1:4:SMB	1|1:8:SMB	1|1:6:SMB	1|1:2:SMB	0|1:4:SMB	0|0:2:SMB	1|1:4:SMB	1|1:3:SMB	1|0:1:SMB	0|0:5:SMB	1|0:2:SMB	1|1:8:SMB	1|1:4:SMB	1|1:6:SMB	1|1:4:SMB	1|1:7:SMB	0|1:8:SMB	0|0:4:SMB	1|1:3:SMB	1|0:7:SMB	1|1:4:SMB	0|0:14:SMB	1|1:3:SMB	0|1:7:SMB	1|0:0:SMB	1|1:6:SMB	1|1:5:SMB	1|0:13:SMB	0|0:7:SMB	1|0:0:SMB	1|1:2:SMB	1|0:4:SMB	0|0:4:SMB	1|1:11:SMB	1|1:6:SMB	1|0:2:SMB	1|0:4:SMB	0|1 [...]
+2	26794385	rs1731238	C	T	.	PASS	AA=C;AC=76;AN=118;DP=242	GT:DP:CB	1|0:2:SMB	1|1:6:SMB	1|0:3:SMB	0|1:3:SMB	1|1:7:SMB	1|1:5:SMB	1|1:6:SMB	1|1:6:SMB	1|1:4:SMB	0|1:6:SMB	0|0:4:SMB	1|1:2:SMB	1|1:2:SMB	1|0:3:SMB	0|0:4:SMB	1|0:5:SMB	1|1:4:SMB	1|1:1:SMB	1|1:3:SMB	1|1:3:SMB	1|1:5:SMB	0|1:5:SMB	0|0:3:SMB	1|1:8:SMB	1|0:8:SMB	1|1:4:SMB	0|0:5:SMB	1|1:7:SMB	0|1:11:SMB	1|0:1:SMB	1|1:5:SMB	1|1:3:SMB	1|0:8:SMB	0|0:7:SMB	1|0:1:SMB	1|1:3:SMB	1|0:4:SMB	0|0:1:SMB	1|1:7:SMB	1|1:4:SMB	1|0:1:SMB	1|0:3:SMB	0|1:1 [...]
diff --git a/lib/tests/expected/vcfParse1kGNoGenotypes.out b/lib/tests/expected/vcfParse1kGNoGenotypes.out
new file mode 100644
index 0000000..b63a787
--- /dev/null
+++ b/lib/tests/expected/vcfParse1kGNoGenotypes.out
@@ -0,0 +1,7 @@
+Finished parsing "input/YRI.trio.2010_06.novelsequences.sites.vcf.gz" items in 2:26790860-194631353, got 5 data rows
+First (up to) 100 rows in range:
+2	26790859	26790860	ns17:T/<INS>	.
+2	46973363	46973364	ns18:GTTCAGTCCTGTGGGACTTGAGCCACTGAGG/<INS>	.
+2	76637609	76637610	ns19:G/<INS>	.
+2	171613232	171613587	ns20:C/<INS>	.
+2	194631352	194631353	ns21:G/<INS>	.
diff --git a/lib/tests/expected/vcfParse1kGWithGenotypes.out b/lib/tests/expected/vcfParse1kGWithGenotypes.out
new file mode 100644
index 0000000..f8ec7d8
--- /dev/null
+++ b/lib/tests/expected/vcfParse1kGWithGenotypes.out
@@ -0,0 +1,8 @@
+Finished parsing "input/YRI.low_coverage.2010_07_excerpt.genotypes.vcf.gz" items in 2:26793738-26794385, got 6 data rows
+First (up to) 100 rows in range:
+2	26793737	26793738	rs1662988:C/T	.
+2	26793755	26793756	.:A/G	.
+2	26793797	26793798	rs12468863:C/T	.
+2	26794094	26794095	rs4233713:C/T	.
+2	26794306	26794307	rs1662989:G/A	.
+2	26794384	26794385	rs1731238:C/T	.
diff --git a/lib/tests/expected/vcfParseOldV3.out b/lib/tests/expected/vcfParseOldV3.out
new file mode 100644
index 0000000..79bfb2d
--- /dev/null
+++ b/lib/tests/expected/vcfParseOldV3.out
@@ -0,0 +1,44 @@
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "LOD"
+input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz:-1: There is no INFO header defining "SLOD"
+Finished parsing "input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz" items in 1:3001-50000, got 14 data rows
+First (up to) 100 rows in range:
+1	3164	3165	.:C/T	145.1
+1	4769	4770	.:A/G	379.5
+1	4792	4793	.:A/G	846.1
+1	6119	6120	.:G/C	128.6
+1	6240	6241	.:T/C	100.5
+1	9651	9652	.:G/A	6.5
+1	9992	9993	.:G/A	730.4
+1	16861	16862	.:A/G	138.9
+1	18425	18426	.:A/G	176.1
+1	20747	20748	.:T/C	51.9
+1	39160	39161	.:T/C	223.9
+1	44570	44571	.:G/C	20.1
+1	45161	45162	.:C/T	668.7
+1	48676	48677	.:G/A	245.9
diff --git a/lib/tests/fetchUrlTest.c b/lib/tests/fetchUrlTest.c
new file mode 100644
index 0000000..fc4c94b
--- /dev/null
+++ b/lib/tests/fetchUrlTest.c
@@ -0,0 +1,81 @@
+/* fetchUrlTest - test some stuff in net module. */
+#include "common.h"
+#include "options.h"
+#include "dystring.h"
+#include "obscure.h"
+#include "net.h"
+
+
+void usage()
+/* Explain usage and exit */
+{
+errAbort(
+"fetchUrlTest - try to fetch url\n"
+"usage:\n"
+"   fetchUrlTest URL\n");
+}
+
+static struct optionSpec options[] = {
+   {NULL, 0},
+};
+
+void fetchUrlTest(char *url)
+/* Fetch given URL, send to stdout. */
+{
+struct dyString *dy = netSlurpUrl(url);
+mustWrite(stdout, dy->string, dy->stringSize);
+}
+
+void fetchUrlBody(char *url)
+/* Fetch given URL, send to stdout. */
+{
+int sd = netUrlOpen(url);
+if (sd < 0)
+    {
+    errAbort("Couldn't open %s", url);
+    }
+char *newUrl = NULL;
+int newSd = 0;
+#define BUFSIZE 65536
+char buf[BUFSIZE];
+ssize_t readCount = 0;
+if (startsWith("http://",url) || startsWith("https://",url))
+    {
+    if (!netSkipHttpHeaderLinesHandlingRedirect(sd, url, &newSd, &newUrl))
+	{
+	errAbort("Error processing http response for %s", url);
+	}
+    if (newUrl != NULL)
+	{
+	/*  Update sd with newSd, replace it with newUrl, etc. */
+	sd = newSd;
+	url = newUrl;
+	}
+    }
+while (TRUE)
+    {
+    readCount = read(sd, buf, BUFSIZE);
+    if (readCount == 0)
+	break;
+    if (readCount < 0)
+	errnoAbort("error reading from socket for url %s", url);
+    mustWrite(stdout, buf, readCount);
+    }
+close(sd);
+if (newUrl) 
+    freeMem(newUrl); 
+}
+
+
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, options);
+if (argc != 2)
+    usage();
+//fetchUrlTest(argv[1]);
+fetchUrlBody(argv[1]);
+return 0;
+}
+
diff --git a/lib/tests/gff3Tester.c b/lib/tests/gff3Tester.c
new file mode 100644
index 0000000..033287f
--- /dev/null
+++ b/lib/tests/gff3Tester.c
@@ -0,0 +1,31 @@
+/* gff3Tester - tester for GFF3 objects */
+
+#include "common.h"
+#include "gff3.h"
+
+static void usage()
+/* Print usage message */
+{
+errAbort(
+   "gff3Tester - tester for GFF3 objects\n"
+   "usage:\n"
+   "   gff3Tester gff3In gff3Out\n"
+   "\n");
+}
+static void gff3Tester(char *gff3InFile, char *gff3OutFile)
+/* tester for GFF3 objects */
+{
+struct gff3File *g3f = gff3FileOpen(gff3InFile, -1, NULL);
+gff3FileWrite(g3f, gff3OutFile);
+gff3FileFree(&g3f);
+}
+
+int main(int argc, char *argv[])
+{
+if (argc != 3)
+    usage();
+gff3Tester(argv[1], argv[2]);
+return 0;
+}
+
+
diff --git a/lib/tests/hacTreeTest.c b/lib/tests/hacTreeTest.c
new file mode 100644
index 0000000..536038a
--- /dev/null
+++ b/lib/tests/hacTreeTest.c
@@ -0,0 +1,260 @@
+/* hacTreeTest - Read in items from a file and print the resulting clusters. */
+#include "common.h"
+#include "linefile.h"
+#include "options.h"
+#include "sqlNum.h"
+#include "hacTree.h"
+
+void usage()
+/* Explain usage and exit. */
+{
+errAbort(
+  "hacTreeTest - Read in haplotypes from a file and print the resulting clusters.\n"
+  "usage:\n"
+  "   hacTreeTest in.txt out.txt\n"
+  "All lines of in.txt must have the same length.\n"
+  "Actually, before clustering in.txt, it clusters some numbers because that is easier.\n"
+  "\n"
+  );
+}
+
+static struct optionSpec options[] = {
+   {NULL, 0},
+};
+
+//------------------- numeric example ------------------
+
+static void rPrintSlDoubleTree(FILE *f, struct hacTree *tree, int level)
+/* Recursively print out cluster as nested-parens with {}'s around leaf nodes. */
+{
+double val = ((struct slDouble *)(tree->itemOrCluster))->val;
+int i;
+for (i=0;  i < level;  i++)
+    fputc(' ', f);
+if (tree->left == NULL && tree->right == NULL)
+    {
+    fprintf(f, "{%0.3lf}", val);
+    return;
+    }
+else if (tree->left == NULL || tree->right == NULL)
+    errAbort("\nHow did we get a node with one NULL kid??");
+fprintf(f, "(%0.3lf:%0.3lf:\n", val, tree->childDistance);
+rPrintSlDoubleTree(f, tree->left, level+1);
+fputs(",\n", f);
+rPrintSlDoubleTree(f, tree->right, level+1);
+fputc('\n', f);
+for (i=0;  i < level;  i++)
+    fputc(' ', f);
+fputs(")", f);
+}
+
+void printSlDoubleTree(FILE *f, struct hacTree *tree)
+/* Print out cluster as nested-parens with {}'s around leaf nodes. */
+{
+if (tree == NULL)
+    {
+    fputs("Empty tree.\n", f);
+    return;
+    }
+rPrintSlDoubleTree(f, tree, 0);
+fputc('\n', f);
+}
+
+double slDoubleDistance(const struct slList *item1, const struct slList *item2, void *extraData)
+/* Return the absolute difference between the two kids' values. */
+{
+const struct slDouble *kid1 = (const struct slDouble *)item1;
+const struct slDouble *kid2 = (const struct slDouble *)item2;
+double diff = kid1->val - kid2->val;
+if (diff < 0)
+    diff = -diff;
+return diff;
+}
+
+struct slList *slDoubleMidpoint(const struct slList *item1, const struct slList *item2,
+				void *unusedExtraData)
+/* Make a new slDouble that is the midpoint/average of kids' values. */
+{
+const struct slDouble *kid1 = (const struct slDouble *)item1;
+const struct slDouble *kid2 = (const struct slDouble *)item2;
+double midpoint = (kid1->val + kid2->val) / 2.0;
+return (struct slList *)(slDoubleNew(midpoint));
+}
+
+void hacTreeTestInts(FILE *f, struct lm *localMem)
+/* Cluster a list of integers (use doubles to get more precise cluster points). */
+{
+struct slDouble *sldList = NULL;
+slAddHead(&sldList, slDoubleNew(0));
+slAddHead(&sldList, slDoubleNew(5));
+slAddHead(&sldList, slDoubleNew(7));
+slAddHead(&sldList, slDoubleNew(1));
+slAddHead(&sldList, slDoubleNew(-8));
+slAddHead(&sldList, slDoubleNew(12));
+slAddHead(&sldList, slDoubleNew(6));
+slAddHead(&sldList, slDoubleNew(-6));
+slAddHead(&sldList, slDoubleNew(-3));
+slAddHead(&sldList, slDoubleNew(8));
+struct hacTree *clusters = hacTreeFromItems((struct slList *)sldList, localMem,
+					    slDoubleDistance, slDoubleMidpoint, NULL, NULL);
+fputs("Clustering by numeric value:\n", f);
+printSlDoubleTree(f, clusters);
+}
+
+
+//-------------------------------------------------------------------
+// Center-weighted alpha clustering of haplotypes -- see Redmine #3711, #2823 note 7
+
+static void rPrintSlNameTree(FILE *f, struct hacTree *tree, int level)
+/* Recursively print out cluster as nested-parens with {}'s around leaf nodes. */
+{
+char *contents = ((struct slName *)(tree->itemOrCluster))->name;
+int i;
+for (i=0;  i < level;  i++)
+    fputc(' ', f);
+if (tree->left == NULL && tree->right == NULL)
+    {
+    fprintf(f, "{%s}", contents);
+    return;
+    }
+else if (tree->left == NULL || tree->right == NULL)
+    errAbort("\nHow did we get a node with one NULL kid??");
+fprintf(f, "(%s:%f:\n", contents, tree->childDistance);
+rPrintSlNameTree(f, tree->left, level+1);
+fputs(",\n", f);
+rPrintSlNameTree(f, tree->right, level+1);
+fputc('\n', f);
+for (i=0;  i < level;  i++)
+    fputc(' ', f);
+fputs(")", f);
+}
+
+void printSlNameTree(FILE *f, struct hacTree *tree)
+/* Print out cluster as nested-parens with {}'s around leaf nodes. */
+{
+if (tree == NULL)
+    {
+    fputs("Empty tree.\n", f);
+    return;
+    }
+rPrintSlNameTree(f, tree, 0);
+fputc('\n', f);
+}
+
+struct cwaExtraData
+/* Helper data for hacTree clustering of haplotypes by center-weighted alpha distance */
+{
+    int center;    // index from which each point's contribution to distance is to be weighted
+    int len;       // total length of haplotype strings
+    double alpha;  // weighting factor for distance from center
+    struct lm *localMem;
+};
+
+static double cwaDistance(const struct slList *item1, const struct slList *item2, void *extraData)
+/* Center-weighted alpha sequence distance function for hacTree clustering of haplotype seqs */
+// This is inner-loop so I am not doing defensive checks.  Caller must ensure:
+// 1. kids's sequences' lengths are both equal to helper->len
+// 2. 0 <= helper->center <= len
+// 3. 0.0 < helper->alpha <= 1.0
+{
+const struct slName *kid1 = (const struct slName *)item1;
+const struct slName *kid2 = (const struct slName *)item2;
+const char *hap1 = kid1->name;
+const char *hap2 = kid2->name;
+struct cwaExtraData *helper = extraData;
+double distance = 0;
+double weight = 1; // start at center: alpha to the 0th power
+int i;
+for (i=helper->center;  i >= 0;  i--)
+    {
+    if (hap1[i] != hap2[i])
+	distance += weight;
+    weight *= helper->alpha;
+    }
+weight = helper->alpha; // start at center+1: alpha to the 1st power
+for (i=helper->center+1;  i < helper->len;  i++)
+    {
+    if (hap1[i] != hap2[i])
+	distance += weight;
+    weight *= helper->alpha;
+    }
+return distance;
+}
+
+static struct slList *cwaMerge(const struct slList *item1, const struct slList *item2,
+			       void *extraData)
+/* Make a consensus haplotype from two input haplotypes, for hacTree clustering by
+ * center-weighted alpha distance. */
+// This is inner-loop so I am not doing defensive checks.  Caller must ensure that
+// kids's sequences' lengths are both equal to helper->len.
+{
+const struct slName *kid1 = (const struct slName *)item1;
+const struct slName *kid2 = (const struct slName *)item2;
+const char *hap1 = kid1->name;
+const char *hap2 = kid2->name;
+struct cwaExtraData *helper = extraData;
+struct slName *consensus = lmSlName(helper->localMem, (char *)hap1);
+int i;
+for (i=0; i < helper->len;  i++)
+    if (hap1[i] != hap2[i])
+	consensus->name[i] = 'N';
+return (struct slList *)consensus;
+}
+
+static int cwaCmp(const struct slList *item1, const struct slList *item2, void *extraData)
+/* Use strcmp on haplotype strings. */
+{
+const struct slName *kid1 = (const struct slName *)item1;
+const struct slName *kid2 = (const struct slName *)item2;
+return strcmp(kid1->name, kid2->name);
+}
+
+void hacTreeTestHaplos(char *inFileName, FILE *f, struct lm *localMem)
+/* Read in haplotypes of same length from a file and print the resulting clusters. */
+{
+struct slName *sln, *slnList = NULL;
+struct lineFile *lf = lineFileOpen(inFileName, TRUE);
+int len = 0;
+char *line;
+int size;
+while (lineFileNext(lf, &line, &size))
+    {
+    if (len == 0)
+	len = size-1;
+    else if (size-1 != len)
+	lineFileAbort(lf, "All lines in input file must have same length (got %d vs. %d)",
+		      size-1, len);
+    sln = slNameNewN(line, size);
+    slAddHead(&slnList, sln);
+    }
+lineFileClose(&lf);
+slReverse(&slnList);
+int center = len / 2;
+double alpha = 0.5;
+struct cwaExtraData helper = { center, len, alpha, localMem };
+struct hacTree *clusters = hacTreeFromItems((struct slList *)slnList, localMem,
+					    cwaDistance, cwaMerge, cwaCmp, &helper);
+fputs("Clustering by haplotype similarity:\n", f);
+printSlNameTree(f, clusters);
+carefulClose(&f);
+}
+
+void hacTreeTest(char *inFileName, char *outFileName)
+/* Read in items from a file and print the resulting clusters. */
+{
+FILE *f = mustOpen(outFileName, "w");
+struct lm *localMem = lmInit(0);
+hacTreeTestInts(f, localMem);
+hacTreeTestHaplos(inFileName, f, localMem);
+lmCleanup(&localMem);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, options);
+if (argc != 3)
+    usage();
+hacTreeTest(argv[1], argv[2]);
+return 0;
+}
diff --git a/lib/tests/htmlExpandUrlTest.c b/lib/tests/htmlExpandUrlTest.c
new file mode 100644
index 0000000..dcc6e47
--- /dev/null
+++ b/lib/tests/htmlExpandUrlTest.c
@@ -0,0 +1,259 @@
+/* htmlPageTest - test some stuff in htmlPage module. */
+#include "common.h"
+#include "options.h"
+#include "htmlPage.h"
+
+
+static void testHtmlExpandUrl()
+/* DO some testing of expandRelativeUrl. */
+{
+    {
+    char *oldUrl = "genome.ucsc.edu";
+    char *relUrl = "credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "genome.ucsc.edu";
+    char *relUrl = "/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "genome.ucsc.edu";
+    char *relUrl = "../credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "genome.ucsc.edu";
+    char *relUrl = "../news/chimp.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "genome.ucsc.edu";
+    char *relUrl = "http://test.org/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu";
+    char *relUrl = "credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu";
+    char *relUrl = "/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu";
+    char *relUrl = "../credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu";
+    char *relUrl = "../news/chimp.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu";
+    char *relUrl = "http://test.org/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/index.html";
+    char *relUrl = "credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/index.html";
+    char *relUrl = "/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/index.html";
+    char *relUrl = "../credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/index.html";
+    char *relUrl = "../news/chimp.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/index.html";
+    char *relUrl = "http://test.org/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/";
+    char *relUrl = "credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/";
+    char *relUrl = "/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/";
+    char *relUrl = "../credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/";
+    char *relUrl = "../news/chimp.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/";
+    char *relUrl = "http://test.org/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/downloads.html";
+    char *relUrl = "credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/downloads.html";
+    char *relUrl = "/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/downloads.html";
+    char *relUrl = "../credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/downloads.html";
+    char *relUrl = "../news/chimp.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/downloads.html";
+    char *relUrl = "http://test.org/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/hg16/";
+    char *relUrl = "credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/hg16/";
+    char *relUrl = "/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/hg16/";
+    char *relUrl = "../credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/hg16/";
+    char *relUrl = "../news/chimp.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/hg16/";
+    char *relUrl = "http://test.org/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/hg16/index.html";
+    char *relUrl = "credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/hg16/index.html";
+    char *relUrl = "/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/hg16/index.html";
+    char *relUrl = "../credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/hg16/index.html";
+    char *relUrl = "../news/chimp.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/goldenPath/hg16/index.html";
+    char *relUrl = "http://test.org/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/";
+    char *relUrl = "credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/";
+    char *relUrl = "/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/";
+    char *relUrl = "../credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/";
+    char *relUrl = "../news/chimp.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+    {
+    char *oldUrl = "http://genome.ucsc.edu/";
+    char *relUrl = "http://test.org/credits.html";
+    char *newUrl = htmlExpandUrl(oldUrl, relUrl);
+    printf("%s %s -> %s\n", oldUrl, relUrl, newUrl);
+    }
+}
+
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+testHtmlExpandUrl();
+return 0;
+}
+
diff --git a/lib/tests/htmlMimeTest.c b/lib/tests/htmlMimeTest.c
new file mode 100644
index 0000000..d26b374
--- /dev/null
+++ b/lib/tests/htmlMimeTest.c
@@ -0,0 +1,94 @@
+/* htmlMimeTest - test mime-encoded posts using htmlPage module. */
+#include "common.h"
+#include "options.h"
+#include "verbose.h"
+#include "htmlPage.h"
+#include "obscure.h"
+#include "qa.h"
+
+
+void usage()
+/* Explain usage and exit */
+{
+errAbort(
+"htmlMimeTest - post mime-encoded page with series on input sizes\n"
+"usage:\n"
+"   htmlMimeTest url-to-hgBlat dnaText startSize endSize\n"
+"e.g. htmlMimeTest http://hgwdev-${user}.cse.ucsc.edu/cgi-bin/hgBlat input/htmlMime.txt 100 200\n"
+"options:\n"
+"   -asFile - send data as type FILE upload (seqFile) instead of TEXTAREA (userSeq) \n"
+);
+}
+
+static struct optionSpec options[] = {
+   {"asFile", OPTION_BOOLEAN},
+   {NULL, 0},
+};
+
+void htmlMimeTest(char *url, char *dnaFileName, int size)
+/* Submit a sequence to hgBlat which will exercise mime parsing code 
+ * because the form uses ENCTYPE="multipart/form-data" */
+{
+struct htmlPage *rootPage, *page;
+struct htmlForm *form, *mainForm;
+struct qaStatus *qs;
+struct htmlFormVar *orgVar;
+char *dna, *dnaSeg;
+qs = qaPageGet(url, &rootPage);
+if (qs->errMessage)
+    errAbort("%s",qs->errMessage);
+if (qs->hardError)
+    errAbort("hard error");
+htmlPageValidateOrAbort(rootPage);
+
+if (verboseLevel() == 2)
+    {
+    for (form = rootPage->forms; form != NULL; form = form->next)
+	htmlFormPrint(form, stderr);
+    }
+    
+if ((mainForm = htmlFormGet(rootPage, "mainForm")) == NULL)
+    errAbort("Couldn't get main form");
+
+readInGulp(dnaFileName, &dna, NULL);
+dnaSeg = cloneStringZ(dna,size);
+verbose(2,"dna=[%s]\n",dnaSeg);
+
+if (optionExists("asFile"))
+    htmlPageSetVar(rootPage, mainForm, "seqFile", dnaFileName);
+else    
+    htmlPageSetVar(rootPage, mainForm, "userSeq", dnaSeg);
+
+qs = qaPageFromForm(rootPage, mainForm,
+                "Submit", "submit", &page);
+
+if (qs->errMessage)
+    errAbort("%s",qs->errMessage);
+if (qs->hardError)
+    errAbort("hard error");
+htmlPageValidateOrAbort(page);
+
+verbose(2,"full html response = [%s]\n",page->fullText);
+
+fprintf(stdout,"%d ok\n",size);
+
+freez(&dnaSeg);
+freez(&dna);
+htmlPageFree(&page);
+htmlPageFree(&rootPage);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+int start, end, i;
+optionInit(&argc, argv, options);
+if (argc != 5)
+    usage();
+start = atoi(argv[3]);    
+end   = atoi(argv[4]);
+for (i=start; i<=end; ++i)
+    htmlMimeTest(argv[1],argv[2],i);
+return 0;
+}
+
diff --git a/lib/tests/htmlPageTest.c b/lib/tests/htmlPageTest.c
new file mode 100644
index 0000000..f6a88a5
--- /dev/null
+++ b/lib/tests/htmlPageTest.c
@@ -0,0 +1,43 @@
+/* htmlPageTest - test some stuff in htmlPage module. */
+#include "common.h"
+#include "options.h"
+#include "htmlPage.h"
+#include "obscure.h"
+
+
+void usage()
+/* Explain usage and exit */
+{
+errAbort(
+"htmlPageTest - print some diagnostic info on page\n"
+"usage:\n"
+"   htmlPageTest file.html\n");
+}
+
+static struct optionSpec options[] = {
+   {NULL, 0},
+};
+
+void htmlPageTest(char *fileName)
+/* Do some checks on file and print. */
+{
+char *html;
+struct htmlPage *page;
+struct htmlForm *form;
+readInGulp(fileName, &html, NULL);
+page = htmlPageParseNoHead(fileName, html);
+htmlPageValidateOrAbort(page);
+for (form = page->forms; form != NULL; form = form->next)
+    htmlFormPrint(form, stdout);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, options);
+if (argc != 2)
+    usage();
+htmlPageTest(argv[1]);
+return 0;
+}
+
diff --git a/lib/tests/input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz b/lib/tests/input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz
new file mode 100644
index 0000000..862d4cd
Binary files /dev/null and b/lib/tests/input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz differ
diff --git a/lib/tests/input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz.tbi b/lib/tests/input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz.tbi
new file mode 100644
index 0000000..940d749
Binary files /dev/null and b/lib/tests/input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz.tbi differ
diff --git a/lib/tests/input/YRI.low_coverage.2010_07_excerpt.genotypes.vcf.gz b/lib/tests/input/YRI.low_coverage.2010_07_excerpt.genotypes.vcf.gz
new file mode 100644
index 0000000..6131b73
Binary files /dev/null and b/lib/tests/input/YRI.low_coverage.2010_07_excerpt.genotypes.vcf.gz differ
diff --git a/lib/tests/input/YRI.low_coverage.2010_07_excerpt.genotypes.vcf.gz.tbi b/lib/tests/input/YRI.low_coverage.2010_07_excerpt.genotypes.vcf.gz.tbi
new file mode 100644
index 0000000..9c06c0a
Binary files /dev/null and b/lib/tests/input/YRI.low_coverage.2010_07_excerpt.genotypes.vcf.gz.tbi differ
diff --git a/lib/tests/input/YRI.trio.2010_06.novelsequences.sites.vcf.gz b/lib/tests/input/YRI.trio.2010_06.novelsequences.sites.vcf.gz
new file mode 100644
index 0000000..bf0eda9
Binary files /dev/null and b/lib/tests/input/YRI.trio.2010_06.novelsequences.sites.vcf.gz differ
diff --git a/lib/tests/input/YRI.trio.2010_06.novelsequences.sites.vcf.gz.tbi b/lib/tests/input/YRI.trio.2010_06.novelsequences.sites.vcf.gz.tbi
new file mode 100644
index 0000000..78b55f5
Binary files /dev/null and b/lib/tests/input/YRI.trio.2010_06.novelsequences.sites.vcf.gz.tbi differ
diff --git a/lib/tests/input/discontinuous.gff3 b/lib/tests/input/discontinuous.gff3
new file mode 100644
index 0000000..e7f5959
--- /dev/null
+++ b/lib/tests/input/discontinuous.gff3
@@ -0,0 +1,31 @@
+##gff-version	3
+apidb|Pf3D7_13	ApiDB	gene	801913	806230	.	+	.	ID=apidb|MAL13P1.103;Name=MAL13P1.103;description=conserved+Plasmodium+protein%2C+unknown+function;size=4318;web_id=MAL13P1.103;locus_tag=MAL13P1.103;size=4318
+apidb|Pf3D7_13	ApiDB	mRNA	801913	806230	.	+	.	ID=apidb|rna_MAL13P1.103-1;Name=MAL13P1.103-1;description=conserved+Plasmodium+protein%2C+unknown+function;size=4318;Parent=apidb|MAL13P1.103;Dbxref=ApiDB_PlasmoDB:MAL13P1.103,NCBI_gi:124513148,NCBI_gi:23615347,taxon:36329
+apidb|Pf3D7_13	ApiDB	CDS	801913	804064	.	+	0	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=2152;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	804194	804264	.	+	2	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=71;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	804423	804569	.	+	0	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=147;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	804663	804788	.	+	0	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=126;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	804950	805115	.	+	0	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=166;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	805197	805277	.	+	2	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=81;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	805391	805476	.	+	2	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=86;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	805587	805642	.	+	0	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=56;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	805730	805811	.	+	1	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=82;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	CDS	805985	806230	.	+	0	ID=apidb|cds_MAL13P1.103-1;Name=cds;description=.;size=246;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	801913	804064	.	+	.	ID=apidb|exon_MAL13P1.103-1;Name=exon;description=exon;size=2152;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	804194	804264	.	+	.	ID=apidb|exon_MAL13P1.103-2;Name=exon;description=exon;size=71;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	804423	804569	.	+	.	ID=apidb|exon_MAL13P1.103-3;Name=exon;description=exon;size=147;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	804663	804788	.	+	.	ID=apidb|exon_MAL13P1.103-4;Name=exon;description=exon;size=126;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	804950	805115	.	+	.	ID=apidb|exon_MAL13P1.103-5;Name=exon;description=exon;size=166;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	805197	805277	.	+	.	ID=apidb|exon_MAL13P1.103-6;Name=exon;description=exon;size=81;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	805391	805476	.	+	.	ID=apidb|exon_MAL13P1.103-7;Name=exon;description=exon;size=86;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	805587	805642	.	+	.	ID=apidb|exon_MAL13P1.103-8;Name=exon;description=exon;size=56;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	805730	805811	.	+	.	ID=apidb|exon_MAL13P1.103-9;Name=exon;description=exon;size=82;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	exon	805985	806230	.	+	.	ID=apidb|exon_MAL13P1.103-10;Name=exon;description=exon;size=246;Parent=apidb|rna_MAL13P1.103-1
+apidb|Pf3D7_13	ApiDB	gene	816023	818599	.	-	.	ID=apidb|MAL13P1.105;Name=MAL13P1.105;description=ser%2Fthr+protein+phosphatase+2A+regulatory+subunit+A%2C+putative;size=2577;web_id=MAL13P1.105;locus_tag=MAL13P1.105;size=2577
+apidb|Pf3D7_13	ApiDB	mRNA	816023	818599	.	-	.	ID=apidb|rna_MAL13P1.105-1;Name=MAL13P1.105-1;description=ser%2Fthr+protein+phosphatase+2A+regulatory+subunit+A%2C+putative;size=2577;Parent=apidb|MAL13P1.105;Ontology_term=GO:0005488;Dbxref=ApiDB_PlasmoDB:MAL13P1.105,EC:3.1.3.16,NCBI_gi:124513154,NCBI_gi:23615350,taxon:36329
+apidb|Pf3D7_13	ApiDB	CDS	816023	818599	.	-	0	ID=apidb|cds_MAL13P1.105-1;Name=cds;description=.;size=2577;Parent=apidb|rna_MAL13P1.105-1
+apidb|Pf3D7_13	ApiDB	exon	816023	818599	.	-	.	ID=apidb|exon_MAL13P1.105-1;Name=exon;description=exon;size=2577;Parent=apidb|rna_MAL13P1.105-1
+apidb|Pf3D7_13	ApiDB	gene	820942	821379	.	+	.	ID=apidb|MAL13P1.106;Name=MAL13P1.106;description=probable+protein%2C+unknown+function;size=438;web_id=MAL13P1.106;locus_tag=MAL13P1.106;size=438
+apidb|Pf3D7_13	ApiDB	mRNA	820942	821379	.	+	.	ID=apidb|rna_MAL13P1.106-1;Name=MAL13P1.106-1;description=probable+protein%2C+unknown+function;size=438;Parent=apidb|MAL13P1.106;Dbxref=ApiDB_PlasmoDB:MAL13P1.106,NCBI_gi:124513156,NCBI_gi:23615351,taxon:36329
+apidb|Pf3D7_13	ApiDB	CDS	820942	821379	.	+	0	ID=apidb|cds_MAL13P1.106-1;Name=cds;description=.;size=438;Parent=apidb|rna_MAL13P1.106-1
+apidb|Pf3D7_13	ApiDB	exon	820942	821379	.	+	.	ID=apidb|exon_MAL13P1.106-1;Name=exon;description=exon;size=438;Parent=apidb|rna_MAL13P1.106-1
diff --git a/lib/tests/input/errorCasesTest.gff3 b/lib/tests/input/errorCasesTest.gff3
new file mode 100644
index 0000000..f7851da
--- /dev/null
+++ b/lib/tests/input/errorCasesTest.gff3
@@ -0,0 +1,28 @@
+##gff-version 3
+# duplicate ids
+2RHet	MB6	mRNA	2317085	2318224	.	-	.	ID=DMG5-chr2RHet.4.001.a;Parent=DMG5-chr2RHet.4.001;Name=DMG5-chr2RHet.4.001.a
+2RHet	MB6	exon	2317085	2317489	.	-	.	Parent=DMG5-chr2RHet.4.001.a
+2RHet	MB6	exon	2317537	2317812	.	-	.	Parent=DMG5-chr2RHet.4.001.a
+2RHet	MB6	exon	2317913	2318224	.	-	.	Parent=DMG5-chr2RHet.4.001.a
+2RHet	MB6	stop_codon	2317085	2317087	.	-	0	Parent=DMG5-chr2RHet.4.001.a
+2RHet	MB6	CDS	2317085	2317489	.	-	0	Parent=DMG5-chr2RHet.4.001.a
+2RHet	MB6	CDS	2317537	2317812	.	-	0	Parent=DMG5-chr2RHet.4.001.a
+2RHet	MB6	CDS	2317913	2318182	.	-	0	Parent=DMG5-chr2RHet.4.001.a
+2RHet	MB6	start_codon	2318180	2318182	.	-	0	Parent=DMG5-chr2RHet.4.001.a
+2RHet	MB6	five_prime_UTR	2318183	2318224	.	-	.	Parent=DMG5-chr2RHet.4.001.a
+2RHet	MB6	gene	2316753	2318224	0	-	.	ID=DMG5-chr2RHet.4.001.a;Name=DMG5-chr2RHet.4.001.a
+2RHet	MB6	mRNA	2316753	2318224	.	-	.	ID=DMG5-chr2RHet.4.001.a.a;Parent=DMG5-chr2RHet.4.001.a;Name=DMG5-chr2RHet.4.001.a.a
+2RHet	MB6	exon	2316753	2316903	.	-	.	Parent=DMG5-chr2RHet.4.001.a.a
+2RHet	MB6	exon	2317224	2317454	.	-	.	Parent=DMG5-chr2RHet.4.001.a.a
+2RHet	MB6	exon	2317553	2317812	.	-	.	Parent=DMG5-chr2RHet.4.001.a.a
+2RHet	MB6	exon	2317913	2318224	.	-	.	Parent=DMG5-chr2RHet.4.001.a.a
+2RHet	MB6	stop_codon	2316753	2316755	.	-	0	Parent=DMG5-chr2RHet.4.001.a.a
+2RHet	MB6	CDS	2316753	2316903	.	-	1	Parent=DMG5-chr2RHet.4.001.a.a
+2RHet	MB6	CDS	2317224	2317454	.	-	1	Parent=DMG5-chr2RHet.4.001.a.a
+2RHet	MB6	CDS	2317553	2317812	.	-	0	Parent=DMG5-chr2RHet.4.001.a.a
+2RHet	MB6	CDS	2317913	2318182	.	-	0	Parent=DMG5-chr2RHet.4.001.a.a
+2RHet	MB6	start_codon	2318180	2318182	.	-	0	Parent=DMG5-chr2RHet.4.001.a.a
+2RHet	MB6	five_prime_UTR	2318183	2318224	.	-	.	Parent=DMG5-chr2RHet.4.001.a.a
+# bogus target with escaped space
+2L	sim4_preR5_gadfly4U_transcripts.fasta	match	22229547	22229792	.	-	.	ID=:194490_sim4_preR5_gadfly4U_transcripts.fasta;Name=CG41424-RA AABU01002023_1064-818-2Lh_cyto_het-preR5_gadfly4U_tra;program=sim4;programversion=1.0;sourcename=preR5_gadfly4U_transcripts.fasta;Target=CG41424-RA_AABU01002023_1064-818 22000976 22001221 +
+2L	sim4_preR5_gadfly4U_transcripts.fasta	match_part	22229547	22229792	98	-	.	Name=:200589;Parent=:194490_sim4_preR5_gadfly4U_transcripts.fasta;target_type=match;Target=CG41424-RA%20AABU01002023_1064-818 22000976 22001221 +
diff --git a/lib/tests/input/google.html b/lib/tests/input/google.html
new file mode 100644
index 0000000..11e07c4
--- /dev/null
+++ b/lib/tests/input/google.html
@@ -0,0 +1,13 @@
+<html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><title>Google</title><style><!--
+body,td,a,p,.h{font-family:arial,sans-serif;}
+.h{font-size: 20px;}
+.q{color:#0000cc;text-decoration: none;}
+//-->
+</style>
+<script>
+<!--
+function sf(){document.f.q.focus();}
+// -->
+</script>
+</head><body bgcolor=#ffffff text=#000000 link=#0000cc vlink=#551a8b alink=#ff0000 onLoad=sf()><center><table border=0 cellspacing=0 cellpadding=0><tr><td><img src="/images/logo.gif" width=276 height=110 alt="Google"></td></tr></table><br>
+<table border=0 cellspacing=0 cellpadding=0><tr><td width=15> </td><td id=0 bgcolor=#3366cc align=center width=95 nowrap><font color=#ffffff size=-1><b>Web</b></font></td><td width=15> </td><td id=1 bgcolor=#efefef align=center width=95 nowrap onClick="" style=cursor:pointer;cursor:hand;><a id=1a class=q href="/imghp?hl=en&tab=wi&ie=UTF-8"><font size=-1>Images</font></a></td><td width=15> </td><td id=2 bgcolor=#efefef align=center width=95 nowrap onClick="" style=cursor:po [...]
\ No newline at end of file
diff --git a/lib/tests/input/hacTreeTest.txt b/lib/tests/input/hacTreeTest.txt
new file mode 100644
index 0000000..f640e4b
--- /dev/null
+++ b/lib/tests/input/hacTreeTest.txt
@@ -0,0 +1,25 @@
+GCGTC
+GTATG
+GCGTA
+CTATA
+CTAGG
+GCGTC
+GTATG
+GCGTA
+CTATA
+CTAGG
+GCGTC
+GTATG
+GCGTA
+CTATA
+CTAGG
+GCGTC
+GTATG
+GCGTA
+CTATA
+CTAGG
+GCGTC
+GTATG
+GCGTA
+CTATA
+CTAGG
diff --git a/lib/tests/input/hashTest1.txt b/lib/tests/input/hashTest1.txt
new file mode 100644
index 0000000..58e4f0f
--- /dev/null
+++ b/lib/tests/input/hashTest1.txt
@@ -0,0 +1,24 @@
+apple apple1
+cat cat1
+dog dog1
+elephant elephant1
+frog frog1
+frog frog2
+frog frog3
+frog frog4
+girl girl1
+house house1
+infix infix1
+jail jail1
+kite kite1
+kite kite2
+kite kite3
+lamb lamb1
+mother mother1
+nana nana1
+nana nana2
+ostrich ostrich1
+pool pool1
+yak yak1
+yak yak2
+zebra zebra1
diff --git a/lib/tests/input/htmlMime.txt b/lib/tests/input/htmlMime.txt
new file mode 100644
index 0000000..df0913e
--- /dev/null
+++ b/lib/tests/input/htmlMime.txt
@@ -0,0 +1,60 @@
+>NM_000230 (LEP)
+gtaggaatcgcagcgccaacggttgcaaggcccaagaagccatcctgggaaggaaaatgc
+attggggaaccctgtgcggattcttgtggctttggccctatcttttctatgtccaagctg
+tgcccatccaaaaagtccaagatgacaccaaaaccctcatcaagacaattgtcaccagga
+tcaatgacatttcacacacgcagtcagtctcctccaaacagaaagtcaccggtttggact
+tcattcctgggctccaccccatcctgaccttatccaagatggaccagacactggcagtct
+accaacagatcctcaccagtatgccttccagaaacgtgatccaaatatccaacgacctgg
+agaacctccgggatcttcttcacgtgctggccttctctaagagctgccacttgccctggg
+ccagtggcctggagaccttggacagcctggggggtgtcctggaagcttcaggctactcca
+cagaggtggtggccctgagcaggctgcaggggtctctgcaggacatgctgtggcagctgg
+acctcagccctgggtgctgaggccttgaaggtcactcttcctgcaaggactacgttaagg
+gaaggaactctggcttccaggtatctccaggattgaagagcattgcatggacacccctta
+tccaggactctgtcaatttccctgactcctctaagccactcttccaaaggcataagaccc
+taagcctccttttgcttgaaaccaaagatatatacacaggatcctattctcaccaggaag
+ggggtccacccagcaaagagtgggctgcatctgggattcccaccaaggtcttcagccatc
+aacaagagttgtcttgtcccctcttgacccatctccccctcactgaatgcctcaatgtga
+ccaggggtgatttcagagagggcagaggggtaggcagagcctttggatgaccagaacaag
+gttccctctgagaattccaaggagttccatgaagaccacatccacacacgcaggaactcc
+cagcaacacaagctggaagcacatgtttatttattctgcattttattctggatggatttg
+aagcaaagcaccagcttctccaggctctttggggtcagccagggccaggggtctccctgg
+agtgcagtttccaatcccatagatgggtctggctgagctgaacccattttgagtgactcg
+agggttgggttcatctgagcaagagctggcaaaggtggctctccagttagttctctcgta
+actggtttcatttctactgtgactgatgttacatcacagtgtttgcaatggtgttgccct
+gagtggatctccaaggaccaggttattttaaaaagatttgttttgtcaagtgtcatatgt
+aggtgtctgcacccaggggtggggaatgtttgggcagaagggagaaggatctagaatgtg
+ttttctgaataacatttgtgtggtgggttctttggaaggagtgagatcattttcttatct
+tctgcaattgcttaggatgtttttcatgaaaatagctctttcaggggggttgtgaggcct
+ggccaggcaccccctggagagaagtttctggccctggctgaccccaaagagcctggagaa
+gctgatgctttgcttcaaatccatccagaataaaacgcaaagggctgaaagccatttgtt
+ggggcagtggtaagctctggctttctccgactgctagggagtggtctttcctatcatgga
+gtgacggtcccacactggtgactgcgatcttcagagcaggggtccttggtgtgaccctct
+gaatgggtccagggttgatcacactctgggtttattacatggcagtgttcctatttgggg
+cttgcatgccaaattgtagttcttgtctgattggctcacccaagcaaggccaaaattacc
+aaaaatcttggggggtttttactccagtggtgaagaaaactcctttagcaggtggtcctg
+agacctgacaagcactgctaggcgagtgccaggactccccaggccaggccaccaggatgc
+ccttcccactggaggtcacattcaggaagatgaaagaggaggtttggggtctgccaccat
+cctgctgctgtgtttttgctatcacacagtgggtggtggatctgtccaaggaaacttgaa
+tcaaagcagttaactttaagactgagcacctgcttcatgctcagccctgactggtgctat
+aggctggagaagctcacccaataaacattaagattgaggcctgccctcagggatcttgcg
+ttcccagtggtcaaaccgcactcacccatgtgccaaggtggggtatttaccacagcagct
+gaacagccaaatgcatggtgcagttgacagcaggtgggaaatggtatgagctgagggggg
+ccgtgcccaggggcccacagggaaccctgcttgcactttgtaacatgtttacttttcagg
+gcatcttagcttctattatagccacatccctttgaaacaagataactgagaatttaaaaa
+taagaaaatacataagaccataacagccaacaggtggcaggaccaggactatagcccagg
+tcctctgatacccagagcattacgtgagccaggtaatgagggactggaaccagggagacc
+gagcgctttctggaaaagaggagtttcgaggtagagtttgaaggaggtgagggatgtgaa
+ttgcctgcagagagaagcctgttttgttggaaggtttggtgtgtggagatgcagaggtaa
+aagtgtgagcagtgagttacagcgagaggcagagaaagaagagacaggagggcaagggcc
+atgctgaagggaccttgaagggtaaagaagtttgatattaaaggagttaagagtagcaag
+ttctagagaagaggctggtgctgtggccagggtgagagctgctctggaaaatgtgaccca
+gatcctcacaaccacctaatcaggctgaggtgtcttaagccttttgctcacaaaacctgg
+cacaatggctaattcccagagtgtgaaacttcctaagtataaatggttgtctgtttttgt
+aacttaaaaaaaaaaaaaaaagtttggccgggtgcggtggctcacgcctgtaatcccagc
+actttgggaggccaaggtggggggatcacaaggtcactagatggcgagcatcctggccaa
+catggtgaaaccccgtctctactaaaaacacaaaagttagctgagcgtggtggcgggcgc
+ctgtagtcccagccactcgggaggctgagacaggagaatcgcttaaacctgggaggcgga
+gagtacagtgagccaagatcgcgccactgcactccggcctgatgacagagcgagattccg
+tcttaaaaaaaaaaaaaaaaaaagtttgtttttaaaaaaatctaaataaaataactttgc
+cccctg
+
diff --git a/lib/tests/input/mime1.txt b/lib/tests/input/mime1.txt
new file mode 100644
index 0000000..252d649
--- /dev/null
+++ b/lib/tests/input/mime1.txt
@@ -0,0 +1,12 @@
+Content-type: multipart/form-data, boundary=AaB03x
+
+--AaB03x
+content-disposition: form-data; name="field1"
+
+Joe Blow
+--AaB03x
+content-disposition: form-data; name="pics"; filename="file1.txt"
+Content-Type: text/plain
+
+ ... contents of file1.txt ...
+--AaB03x--
diff --git a/lib/tests/input/mime2.txt b/lib/tests/input/mime2.txt
new file mode 100644
index 0000000..3df06c5
--- /dev/null
+++ b/lib/tests/input/mime2.txt
@@ -0,0 +1,24 @@
+Content-type: multipart/form-data, boundary=AaB03x; extra=whocares
+
+--AaB03x
+content-disposition: form-data; name="field1"
+
+Joe Blow
+--AaB03x
+content-disposition: form-data; name="pics"
+Content-type: multipart/mixed, boundary="BbC04y"
+
+--BbC04y
+Content-disposition: attachment; filename="file1.txt"
+Content-Type: text/plain
+
+... contents of file1.txt ...
+--BbC04y
+Content-disposition: attachment; filename="file2.gif"
+Content-type: image/gif
+Content-Transfer-Encoding: binary
+
+  ...contents of file2.gif...
+--BbC04y--
+--AaB03x--
+
diff --git a/lib/tests/input/mime3.txt b/lib/tests/input/mime3.txt
new file mode 100644
index 0000000..5049170
--- /dev/null
+++ b/lib/tests/input/mime3.txt
@@ -0,0 +1,30 @@
+Content-type: multipart/form-data, boundary=AaB03x
+
+--AaB03x
+content-disposition: form-data; name="field1"
+
+Joe Blow
+--AaB03x
+content-disposition: form-data; name="pics"
+Content-type: multipart/mixed, boundary=BbC04y
+
+--BbC04y
+Content-disposition: attachment; filename="file1.txt"
+Content-Type: text/plain
+
+... contents of file1.txt ...
+--BbC04y
+Content-disposition: attachment; filename="file2.gif"
+Content-type: image/gif
+Content-Transfer-Encoding: binary
+
+  ...contents of file2.gif...
+--BbC04y
+Content-disposition: attachment; filename="file3.gif"
+Content-type: image/gif
+Content-Transfer-Encoding: binary
+
+  ...contents of file3.gif...
+--BbC04y--
+--AaB03x--
+
diff --git a/lib/tests/input/mime4.txt b/lib/tests/input/mime4.txt
new file mode 100644
index 0000000..5ceff21
--- /dev/null
+++ b/lib/tests/input/mime4.txt
@@ -0,0 +1,40 @@
+Content-type: multipart/form-data, boundary=AaB03x
+
+--AaB03x
+content-disposition: form-data; name="field1"
+
+Joe Blow
+--AaB03x
+content-disposition: form-data; name="pics"
+Content-type: multipart/mixed, boundary=BbC04y
+
+--BbC04y
+Content-disposition: attachment; filename="file1.txt"
+Content-Type: text/plain
+
+... contents of file1.txt ...
+--BbC04y
+Content-disposition: attachment; filename="file2.gif"
+Content-type: image/gif
+Content-Transfer-Encoding: binary
+
+  ...contents of file2.gif...
+--BbC04y
+content-disposition: form-data; name="pics"
+Content-type: multipart/mixed, boundary=CcD05y
+
+--CdD05y
+Content-disposition: attachment; filename="file3.txt"
+Content-Type: text/plain
+
+... contents of file3.txt ...
+--CcD05y
+Content-disposition: attachment; filename="file4.gz"
+Content-type: application/octetsomething
+Content-Transfer-Encoding: binary
+
+  ...contents of file4.gz...
+--CcD05y--
+--BbC04y--
+--AaB03x--
+
diff --git a/lib/tests/input/mime5.txt b/lib/tests/input/mime5.txt
new file mode 100644
index 0000000..065a5ae
--- /dev/null
+++ b/lib/tests/input/mime5.txt
@@ -0,0 +1,39 @@
+Content-type: multipart/form-data, boundary=----------0xKhTmLbOuNdArY
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="hgsid"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="org"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="db"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="type"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="sort"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="output"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="userSeq"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="Submit"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="seqFile"; filename=""
+
+
+------------0xKhTmLbOuNdArY--
diff --git a/lib/tests/input/mimeAltHead.txt b/lib/tests/input/mimeAltHead.txt
new file mode 100644
index 0000000..56abb4d
--- /dev/null
+++ b/lib/tests/input/mimeAltHead.txt
@@ -0,0 +1,37 @@
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="hgsid"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="org"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="db"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="type"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="sort"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="output"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="userSeq"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="Submit"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="seqFile"; filename=""
+
+
+------------0xKhTmLbOuNdArY--
diff --git a/lib/tests/input/mimeAutoBoundary.txt b/lib/tests/input/mimeAutoBoundary.txt
new file mode 100644
index 0000000..56abb4d
--- /dev/null
+++ b/lib/tests/input/mimeAutoBoundary.txt
@@ -0,0 +1,37 @@
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="hgsid"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="org"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="db"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="type"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="sort"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="output"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="userSeq"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="Submit"
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="seqFile"; filename=""
+
+
+------------0xKhTmLbOuNdArY--
diff --git a/lib/tests/input/mimeBin.txt b/lib/tests/input/mimeBin.txt
new file mode 100644
index 0000000..895d64c
Binary files /dev/null and b/lib/tests/input/mimeBin.txt differ
diff --git a/lib/tests/input/mimeBlat.txt b/lib/tests/input/mimeBlat.txt
new file mode 100644
index 0000000..d4aae77
--- /dev/null
+++ b/lib/tests/input/mimeBlat.txt
@@ -0,0 +1,97 @@
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="hgsid"
+
+63932244
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="org"
+
+Human
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="db"
+
+hg17
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="type"
+
+BLAT's guess
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="sort"
+
+query,score
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="output"
+
+hyperlink
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="userSeq"
+
+>NM_000230 (LEP)
+gtaggaatcgcagcgccaacggttgcaaggcccaagaagccatcctgggaaggaaaatgc
+attggggaaccctgtgcggattcttgtggctttggccctatcttttctatgtccaagctg
+tgcccatccaaaaagtccaagatgacaccaaaaccctcatcaagacaattgtcaccagga
+tcaatgacatttcacacacgcagtcagtctcctccaaacagaaagtcaccggtttggact
+tcattcctgggctccaccccatcctgaccttatccaagatggaccagacactggcagtct
+accaacagatcctcaccagtatgccttccagaaacgtgatccaaatatccaacgacctgg
+agaacctccgggatcttcttcacgtgctggccttctctaagagctgccacttgccctggg
+ccagtggcctggagaccttggacagcctggggggtgtcctggaagcttcaggctactcca
+cagaggtggtggccctgagcaggctgcaggggtctctgcaggacatgctgtggcagctgg
+acctcagccctgggtgctgaggccttgaaggtcactcttcctgcaaggactacgttaagg
+gaaggaactctggcttccaggtatctccaggattgaagagcattgcatggacacccctta
+tccaggactctgtcaatttccctgactcctctaagccactcttccaaaggcataagaccc
+taagcctccttttgcttgaaaccaaagatatatacacaggatcctattctcaccaggaag
+ggggtccacccagcaaagagtgggctgcatctgggattcccaccaaggtcttcagccatc
+aacaagagttgtcttgtcccctcttgacccatctccccctcactgaatgcctcaatgtga
+ccaggggtgatttcagagagggcagaggggtaggcagagcctttggatgaccagaacaag
+gttccctctgagaattccaaggagttccatgaagaccacatccacacacgcaggaactcc
+cagcaacacaagctggaagcacatgtttatttattctgcattttattctggatggatttg
+aagcaaagcaccagcttctccaggctctttggggtcagccagggccaggggtctccctgg
+agtgcagtttccaatcccatagatgggtctggctgagctgaacccattttgagtgactcg
+agggttgggttcatctgagcaagagctggcaaaggtggctctccagttagttctctcgta
+actggtttcatttctactgtgactgatgttacatcacagtgtttgcaatggtgttgccct
+gagtggatctccaaggaccaggttattttaaaaagatttgttttgtcaagtgtcatatgt
+aggtgtctgcacccaggggtggggaatgtttgggcagaagggagaaggatctagaatgtg
+ttttctgaataacatttgtgtggtgggttctttggaaggagtgagatcattttcttatct
+tctgcaattgcttaggatgtttttcatgaaaatagctctttcaggggggttgtgaggcct
+ggccaggcaccccctggagagaagtttctggccctggctgaccccaaagagcctggagaa
+gctgatgctttgcttcaaatccatccagaataaaacgcaaagggctgaaagccatttgtt
+ggggcagtggtaagctctggctttctccgactgctagggagtggtctttcctatcatgga
+gtgacggtcccacactggtgactgcgatcttcagagcaggggtccttggtgtgaccctct
+gaatgggtccagggttgatcacactctgggtttattacatggcagtgttcctatttgggg
+cttgcatgccaaattgtagttcttgtctgattggctcacccaagcaaggccaaaattacc
+aaaaatcttggggggtttttactccagtggtgaagaaaactcctttagcaggtggtcctg
+agacctgacaagcactgctaggcgagtgccaggactccccaggccaggccaccaggatgc
+ccttcccactggaggtcacattcaggaagatgaaagaggaggtttggggtctgccaccat
+cctgctgctgtgtttttgctatcacacagtgggtggtggatctgtccaaggaaacttgaa
+tcaaagcagttaactttaagactgagcacctgcttcatgctcagccctgactggtgctat
+aggctggagaagctcacccaataaacattaagattgaggcctgccctcagggatcttgcg
+ttcccagtggtcaaaccgcactcacccatgtgccaaggtggggtatttaccacagcagct
+gaacagccaaatgcatggtgcagttgacagcaggtgggaaatggtatgagctgagggggg
+ccgtgcccaggggcccacagggaaccctgcttgcactttgtaacatgtttacttttcagg
+gcatcttagcttctattatagccacatccctttgaaacaagataactgagaatttaaaaa
+taagaaaatacataagaccataacagccaacaggtggcaggaccaggactatagcccagg
+tcctctgatacccagagcattacgtgagccaggtaatgagggactggaaccagggagacc
+gagcgctttctggaaaagaggagtttcgaggtagagtttgaaggaggtgagggatgtgaa
+ttgcctgcagagagaagcctgttttgttggaaggtttggtgtgtggagatgcagaggtaa
+aagtgtgagcagtgagttacagcgagaggcagagaaagaagagacaggagggcaagggcc
+atgctgaagggaccttgaagggtaaagaagtttgatattaaaggagttaagagtagcaag
+ttctagagaagaggctggtgctgtggccagggtgagagctgctctggaaaatgtgaccca
+gatcctcacaaccacctaatcaggctgaggtgtcttaagccttttgctcacaaaacctgg
+cacaatggctaattcccagagtgtgaaacttcctaagtataaatggttgtctgtttttgt
+aacttaaaaaaaaaaaaaaaagtttggccgggtgcggtggctcacgcctgtaatcccagc
+actttgggaggccaaggtggggggatcacaaggtcactagatggcgagcatcctggccaa
+catggtgaaaccccgtctctactaaaaacacaaaagttagctgagcgtggtggcgggcgc
+ctgtagtcccagccactcgggaggctgagacaggagaatcgcttaaacctgggaggcgga
+gagtacagtgagccaagatcgcgccactgcactccggcctgatgacagagcgagattccg
+tcttaaaaaaaaaaaaaaaaaaagtttgtttttaaaaaaatctaaataaaataactttgc
+cccctg
+
+
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="Submit"
+
+Submit
+------------0xKhTmLbOuNdArY
+Content-Disposition: form-data; name="seqFile"; filename=""
+
+
+------------0xKhTmLbOuNdArY--
diff --git a/lib/tests/input/mimeDecodeTest.txt b/lib/tests/input/mimeDecodeTest.txt
new file mode 100644
index 0000000..21b1960
--- /dev/null
+++ b/lib/tests/input/mimeDecodeTest.txt
@@ -0,0 +1,1391 @@
+Subject: Fw: Dilbert is Alive and Well!!!
+Date: Wed, 7 Jun 2006 10:39:21 -0700
+
+This is a multi-part message in MIME format.
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450
+Content-Type: multipart/alternative;
+	boundary="----=_NextPart_001_001D_01C68A1E.A2C4B450"
+
+
+------=_NextPart_001_001D_01C68A1E.A2C4B450
+Content-Type: text/plain;
+	charset="iso-8859-1"
+Content-Transfer-Encoding: quoted-printable
+
+Dilbert is Alive and Well!!!
+
+
+
+
+
+
+      A magazine recently ran a "Dilbert Quotes" contest. They were =
+looking for people to submit quotes from their real-life =
+Dilbert-comic-strip-type managers. These were voted the top ten quotes =
+from the managers we work for in corporate America:
+
+
+      =20
+      "As of tomorrow, employees will only be able to access the =
+building using individual security cards. Pictures will be taken next =
+Wednesday, and employees will receive their cards in two weeks."
+      (This was the winning quote from Fred Dales, Microsoft Corp. in =
+Redmond WA)
+
+
+
+      =20
+      "What I need is an exact list of specific unknown problems we =
+might encounter."
+      (Lykes Lines Shipping)
+
+
+
+      =20
+      "E-mail is not to be used to pass on information or data. It =
+should be used only for company business."
+      (Accounting manager, Electric Boat Company)
+
+
+
+      =20
+      "This project is so important we can't let things that are more =
+important interfere with it."
+      (Advertising/Marketing manager,
+      United Parcel Service)
+
+
+
+      =20
+      "Doing it right is no excuse
+      for not meeting the schedule."
+      (Plant Manager, Delco Corporation)
+
+
+
+      =20
+      "No one will believe you solved
+      this problem in one day!
+      We've been working on it for months.
+      Now go act busy for a few weeks and
+      I'll let you know when it's time to tell them."
+      (R&D supervisor, Minnesota Mining and Manufacturing/3M Corp.)
+
+
+
+      =20
+      Quote from the Boss:
+      "Teamwork is a lot of people doing
+      what I say."
+      (Marketing executive, Citrix Corporation)
+
+
+
+      =20
+      My sister passed away and her funeral was scheduled for Monday. =
+When I told my Boss, he said she died on purpose so that I would have to =
+miss work on the busiest day of the year. He then asked if we could =
+change her burial to Friday.
+      He said, "That would be better for me."
+      (Shipping executive, FTD Florists)
+
+
+
+      =20
+      "We know that communication is a problem, but the company is not =
+going to discuss it with the employees."=20
+      (Switching supervisor, AT&T Long Lines Division)
+
+
+
+
+       
+------=_NextPart_001_001D_01C68A1E.A2C4B450
+Content-Type: text/html;
+	charset="iso-8859-1"
+Content-Transfer-Encoding: quoted-printable
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML><HEAD><TITLE>Dilbert is Alive and Well!!!</TITLE>
+<META http-equiv=3DContent-Type content=3D"text/html; =
+charset=3Diso-8859-1">
+<STYLE type=3Dtext/css>BLOCKQUOTE {
+	PADDING-BOTTOM: 0px; PADDING-TOP: 0px
+}
+DL {
+	PADDING-BOTTOM: 0px; PADDING-TOP: 0px
+}
+UL {
+	PADDING-BOTTOM: 0px; PADDING-TOP: 0px
+}
+OL {
+	PADDING-BOTTOM: 0px; PADDING-TOP: 0px
+}
+LI {
+	PADDING-BOTTOM: 0px; PADDING-TOP: 0px
+}
+</STYLE>
+
+<META content=3D"MSHTML 6.00.2800.1543" name=3DGENERATOR></HEAD>
+<BODY bgColor=3D#ffffff>
+<DIV><FONT face=3DArial size=3D2></FONT><BR></DIV>
+<BLOCKQUOTE cite=3D"" type=3D"cite">
+  <BLOCKQUOTE cite=3D"" type=3D"cite">
+    <BLOCKQUOTE cite=3D"" type=3D"cite" align=3D"center"><FONT=20
+    size=3D-1><BR></FONT></BLOCKQUOTE>
+    <BLOCKQUOTE cite=3D"" type=3D"cite" align=3D"center"><IMG =
+height=3D97=20
+      alt=3D"image001 12.jpg" =
+src=3D"cid:001101c68a59$4f153470$6401a8c0 at madhouse"=20
+      width=3D180><FONT face=3DVerdana size=3D-1><BR><BR></FONT><FONT =
+face=3DPapyrus=20
+      size=3D-1><BR></FONT><FONT face=3DPapyrus size=3D+1>A magazine =
+recently ran a=20
+      "Dilbert Quotes" contest. They were looking for people to submit =
+quotes=20
+      from their real-life Dilbert-comic-strip-type managers. These were =
+voted=20
+      the top ten quotes from the managers we work for in corporate=20
+      America:</FONT><FONT face=3DVerdana size=3D-1><BR><BR><IMG =
+height=3D150=20
+      alt=3D"image002 2.jpg" =
+src=3D"cid:001201c68a59$4f153470$6401a8c0 at madhouse"=20
+      width=3D136></FONT><FONT size=3D-1><BR> <BR><FONT=20
+      face=3DPapyrus>"</FONT></FONT><FONT face=3DPapyrus size=3D+1>As of =
+tomorrow,=20
+      employees will only be able to access the building using =
+individual=20
+      security cards. Pictures will be taken next Wednesday, and =
+employees will=20
+      receive their cards in two weeks."</FONT><FONT =
+size=3D-1><BR></FONT><FONT=20
+      face=3DPapyrus color=3D#ff0000 size=3D+1><I>(This was the winning =
+quote from=20
+      Fred Dales, Microsoft Corp. in Redmond WA)</I></FONT><FONT=20
+      size=3D-1><BR><FONT face=3DVerdana><BR><BR><IMG height=3D141=20
+      alt=3D"image003 3.jpg" =
+src=3D"cid:001301c68a59$4f153470$6401a8c0 at madhouse"=20
+      width=3D126></FONT><BR> <BR><FONT =
+face=3DPapyrus>"</FONT></FONT><FONT=20
+      face=3DPapyrus size=3D+1>What I need is an exact list of specific =
+unknown=20
+      problems we might encounter."</FONT><FONT =
+size=3D-1><BR></FONT><FONT=20
+      face=3DPapyrus color=3D#0000ff size=3D+1><I>(Lykes Lines=20
+      Shipping)</I></FONT><FONT size=3D-1><BR></FONT><FONT =
+face=3DVerdana=20
+      size=3D+1><BR></FONT><FONT face=3DVerdana size=3D-1><BR><IMG =
+height=3D116=20
+      alt=3D"image004 1.gif" =
+src=3D"cid:001401c68a59$4f153470$6401a8c0 at madhouse"=20
+      width=3D92></FONT><FONT size=3D-1><BR> <BR><FONT=20
+      face=3DPapyrus>"</FONT></FONT><FONT face=3DPapyrus =
+size=3D+1>E-mail is not to be=20
+      used to pass on information or data. It should be used only for =
+company=20
+      business."</FONT><FONT size=3D-1><BR></FONT><FONT face=3DPapyrus =
+color=3D#0000ff=20
+      size=3D+1><I>(Accounting manager, Electric Boat =
+Company)</I></FONT><FONT=20
+      size=3D-1><BR><FONT face=3DVerdana><BR><BR><IMG height=3D151=20
+      alt=3D"image005 2.jpg" =
+src=3D"cid:001501c68a59$4f153470$6401a8c0 at madhouse"=20
+      width=3D92><BR> <BR></FONT><FONT =
+face=3DPapyrus>"</FONT></FONT><FONT=20
+      face=3DPapyrus size=3D+1>This project is so important we can't let =
+things that=20
+      are more important interfere with it."</FONT><FONT=20
+      size=3D-1><BR></FONT><FONT face=3DPapyrus color=3D#0000ff=20
+      size=3D+1><I>(Advertising/Marketing manager,</I></FONT><FONT=20
+      size=3D-1><BR></FONT><FONT face=3DPapyrus color=3D#0000ff =
+size=3D+1><I>United=20
+      Parcel Service)</I></FONT><FONT size=3D-1><BR><FONT=20
+      face=3DVerdana><BR><BR><IMG height=3D150 alt=3Dimage006.jpg=20
+      src=3D"cid:001601c68a59$4f153470$6401a8c0 at madhouse"=20
+      width=3D111><BR> <BR></FONT><FONT =
+face=3DPapyrus>"</FONT></FONT><FONT=20
+      face=3DPapyrus size=3D+1>Doing it right is no excuse</FONT><FONT=20
+      size=3D-1><BR></FONT><FONT face=3DPapyrus size=3D+1>for not =
+meeting the=20
+      schedule<I>."</I></FONT><FONT size=3D-1><BR></FONT><FONT =
+face=3DPapyrus=20
+      color=3D#0000ff size=3D+1><I>(Plant Manager, Delco=20
+      Corporation)</I></FONT><FONT size=3D-1><BR><FONT =
+face=3DVerdana><BR><BR><IMG=20
+      height=3D134 alt=3Dimage007.jpg=20
+      src=3D"cid:001701c68a59$4f153470$6401a8c0 at madhouse"=20
+      width=3D216><BR> <BR></FONT><FONT =
+face=3DPapyrus>"</FONT></FONT><FONT=20
+      face=3DPapyrus size=3D+1>No one will believe you =
+solved</FONT><FONT=20
+      size=3D-1><BR></FONT><FONT face=3DPapyrus size=3D+1>this problem =
+in one=20
+      day!</FONT><FONT size=3D-1><BR></FONT><FONT face=3DPapyrus =
+size=3D+1>We've been=20
+      working on it for months.</FONT><FONT size=3D-1><BR></FONT><FONT=20
+      face=3DPapyrus size=3D+1>Now go act busy for a few weeks =
+and</FONT><FONT=20
+      size=3D-1><BR></FONT><FONT face=3DPapyrus size=3D+1>I'll let you =
+know when it's=20
+      time to tell them."</FONT><FONT size=3D-1><BR></FONT><FONT =
+face=3DPapyrus=20
+      color=3D#0000ff size=3D+1><I>(R&D supervisor, Minnesota Mining =
+and=20
+      Manufacturing/3M Corp.)</I></FONT><FONT size=3D-1><BR><FONT=20
+      face=3DVerdana><BR><BR><IMG height=3D111 alt=3D"image008 1.jpg"=20
+      src=3D"cid:001801c68a59$4f153470$6401a8c0 at madhouse"=20
+      width=3D192></FONT><BR> <BR></FONT><FONT face=3DPapyrus =
+size=3D+1><B>Quote=20
+      from the Boss:</B></FONT><FONT size=3D-1><BR></FONT><FONT =
+face=3DPapyrus=20
+      size=3D+1><B>"Teamwork is a lot of people doing</B></FONT><FONT=20
+      size=3D-1><BR></FONT><FONT face=3DPapyrus size=3D+1><B>what I=20
+      say."</B></FONT><FONT size=3D-1><BR></FONT><FONT face=3DPapyrus =
+color=3D#0000ff=20
+      size=3D+1><I><B>(Marketing executive, Citrix=20
+      Corporation)</B></I></FONT><FONT size=3D-1><BR><FONT=20
+      face=3DVerdana><B><BR><BR><IMG height=3D117 alt=3D"image009 1.jpg" =
+
+      src=3D"cid:001901c68a59$4f153470$6401a8c0 at madhouse"=20
+      width=3D156></B></FONT><BR> <BR></FONT><FONT face=3DPapyrus =
+size=3D+1><B>My=20
+      sister passed away and her funeral was scheduled for Monday. When =
+I told=20
+      my Boss, he said she died on purpose so that I would have to miss =
+work on=20
+      the busiest day of the year. He then asked if we could change her =
+burial=20
+      to Friday.</B></FONT><FONT size=3D-1><BR></FONT><FONT =
+face=3DPapyrus=20
+      size=3D+1><B>He said,<I> "That would be better for =
+me."</I></B></FONT><FONT=20
+      size=3D-1><BR></FONT><FONT face=3DPapyrus color=3D#0000ff=20
+      size=3D+1><I><B>(Shipping executive, FTD =
+Florists)</B></I></FONT><FONT=20
+      size=3D-1><BR><FONT face=3DVerdana><B><BR><BR><IMG height=3D175=20
+      alt=3D"image010 1.gif" =
+src=3D"cid:001a01c68a59$4f153470$6401a8c0 at madhouse"=20
+      width=3D200></B></FONT><BR> </FONT></BLOCKQUOTE>
+    <BLOCKQUOTE cite=3D"" type=3D"cite" align=3D"center"><FONT =
+face=3DPapyrus=20
+      size=3D-1><B>"</B></FONT><FONT face=3DPapyrus size=3D+1><B>We know =
+that=20
+      communication is a problem, but the company is not going to =
+discuss it=20
+      with the employees." </B></FONT></BLOCKQUOTE>
+    <BLOCKQUOTE cite=3D"" type=3D"cite" align=3D"center"><FONT =
+face=3DPapyrus=20
+      color=3D#0000ff size=3D+1><I><B>(Switching supervisor, AT&T =
+Long Lines=20
+      Division)</B></I></FONT><FONT face=3DVerdana =
+size=3D-1><B><BR><BR><BR><IMG=20
+      height=3D203 alt=3Dimage011.gif=20
+      src=3D"cid:001b01c68a59$4f153470$6401a8c0 at madhouse"=20
+    width=3D203></B></FONT></BLOCKQUOTE>
+    <BLOCKQUOTE cite=3D"" type=3D"cite"><FONT =
+color=3D#000080></FONT><FONT=20
+      size=3D-1><BR></FONT><FONT face=3D"Comic Sans MS"=20
+    =
+color=3D#800040> </FONT></BLOCKQUOTE></BLOCKQUOTE></BLOCKQUOTE></BOD=
+Y></HTML>
+
+------=_NextPart_001_001D_01C68A1E.A2C4B450--
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450
+Content-Type: image/jpeg;
+	name="image001 12.jpg"
+Content-Transfer-Encoding: base64
+Content-ID: <001101c68a59$4f153470$6401a8c0 at madhouse>
+
+/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
+HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
+MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABhALQDASIA
+AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
+AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
+ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm
+p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA
+AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx
+BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK
+U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3
+uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iii
+gAooooAKKKKACiiigAooooAhu7qCxtJrq5kEcEKF5HIztA6modM1Sy1iyW80+cT27EgOARkjg9ak
+v7KHUrCeyuATDOhjcKcHB4PNV9F0az0DTUsLBXWBGLAO245Jyean3ubyN0qPsW3fnv8AK353uaFF
+Ymm+KbDVNfvtGgScXNlnzS6gKcEDg59626cZKWqIq0alKXLUVnv94UUUUzMKKKKACiiigAooooAK
+KKKACvM9U+OnhDSNWvNNuU1Lz7SZ4JNluCNykg4O7pkV6ZXzB4T0uw1j9onV7TUrOG7tjeXrGKZA
+ykgtg4NAHqen/HjwNfXHkyXd3Z+klzbkKTnGMqTj8eK9KiljmiSWJ1eN1DK6nIYHoQe4ry/4i/CX
+QdV8J3cmiaRaWWqWyGWBrdBGHxyVYDAOQDjPQ1ifs7eKLnUNGv8Aw/cszrp+2S3Y87UYnK59iOPr
+QB3et/E3w/oHi238NXovPt1wYwhjiDJ85wuTnP6VZ8Z+PtG8CQ2kusLdFbtmWPyIw/K4znJHqK8T
++KX/ACcFo/8A10sv/Q63v2l/+Qb4e/67T/ySgD27Tr6HVNMtdQtt3kXUKTR7hg7WAIyPoas1h+DP
++RG0D/sHW/8A6LWtygAooooA5TxH4Y1LWPEGm6haaobWC12+ZDlh5mH3HocdOK534n+MVtIJtBgS
+dLmRI5VuY5NoA3Zxxz2rV8ea/Jb3en+H45ZLRdScJNe8ARx5AO0nvzz6D6151L4R0dfHEGirrQay
+kg8w3W9OGwTtz07D868/ETavGnu9GfX5Rh4zVOvjH7sE3FJdE92159He46fWjqOgabpmmaNc2+ry
+vGjX6Da1wcHOWGCckg8ntXrHhbSU8NaVFa3uoGa/nw8rTTZJb+6uT0HT3q/o2lLp2m2lm6rILJfL
+gkPLbcY3H0JGelZXiLwXH4g1/TtVa9aE2RXEYj3b8Nu654rSnRlT9/d/ccWLzGhi39Xv7OndtvWT
+b6eaXl0+R1NFFFdh86FFFFABRRRQAUUUUAFFFFABXzZ4B/5OV1b/AK+77+bV9J14RrHwH1u+8Val
+rVl4lgtGu7qWdNiOrIHYnGQffFAHqXj7xLbeFPBuo6lcAOwiKRRbsGR2+UD6ZPPtXkv7NmlXaHW9
+WeIrZyrHBG5/jYEk49cZH50+P9nnU7+6Vtc8WvcRIpClUZ3B9BvbgV7Zomi6f4e0i30vTLdYLS3X
+aiDv6knuSeSaAPnr4pf8nBaP/wBdLL/0Ot79pf8A5Bvh7/rtP/JK6Xxb8KLzxJ8SbHxRHqkEEFu0
+DGFoiWPltk85xzWh8VPhzdfEK20yK11CGz+xvIzGVC27cFHGPpQB03gz/kRtA/7B1v8A+i1rcrwG
+P4EeLYo1jj8bsiKAqqplAAHYDdXqHw78K6n4Q8PzadqurHU5nuWlWYljtUqo2/MSeoJ/GgDrq5Lx
+34yj8K6YFhKvqM4IgjPIUd3PsP1P41reJPEFp4a0eW/ujkj5YoweZH7KP8e1fOWs6vd67qs+oXr7
+ppWzjso7KPYVx4vE+zXLHdn0nD2TPG1PbVV+7j+L7enf7i14g8Uan4mkgfUpI3aAEJsQLwcZ6fSu
+98NaP4X0bwjpnirV7adpxIefmYb9zbTt6dADXM+APBr+J9T865UrpluwMzdPMPZB/X0H1r3S+0XT
+dS05NPu7SOS0Tbti5AGOBjHpXNhaM53qy1fS57We5jh8LyYKleMU/e5dLLXT53uP0vUrfWNMg1C0
+LGCddyFlwcZx0/CrlV7GxttNsorOziEVvEMIgJwB171Yr1Fe2u58JU5Od+z+G+l97dAooopkBRRR
+QAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAVBe3tvp1lNeXcoighUu7nsKmJABJIAHUmvCviR41Ov
+Xx0ywkP9m27csP8Als47/Qdvz9Kwr1lRjd7nqZTllTMK6px0it32X+b6GJ4x8VXHirWGuGylpFlb
+eI/wr6n3Peq3hnw7deJ9ZjsLYFV+9NLjiNO5/wABWfYWFzqd/DZWcRluJm2oo7n/AAr6L8IeF7fw
+roy2seHuZMNcTY++3+A6CvLoUZYipzS26n3ea5hSyjCqjQXvWtFdvN/1q/maWk6VaaLpkGn2UYSC
+FcD1Y9yfcnmrtZ2p+ING0V411TVbKxaUEoLmdYywHXGTzVD/AITvwj/0M+j/APgbH/jXtJJKyPzK
+c5Tk5Sd2zoKKit7iC7gSe2mjmicZWSNgysPYiq2p61peixxyapqNpZJIdqNczLGGPoMnmmSXqK5/
+/hO/CP8A0M+j/wDgbH/jWhpmu6Rrfm/2VqlnfeVjzPs06ybM5xnB4zg/lQBoUVnan4g0bRXjXVNV
+srFpQSguZ1jLAdcZPNUP+E78I/8AQz6P/wCBsf8AjQB0FFV7O+tNRtlubK6huYHGVkhkDqfoRVTU
+/EWiaLKkWqavY2UjruRLm4WMsOmQCelAGnRXP/8ACd+Ef+hn0f8A8DY/8au6b4j0TWZnh0vV7G9l
+RdzJb3CyFR0yQD0oA06KKKACiiigAooooAKKK4v4g+M18Nab9ltHB1O4X92P+eS/3z/Qf4VFScYR
+cpHRhcLUxVaNGkrtnP8AxQ8beSknh7TZf3jDF3Kp+6P7g+vf8vWvIVUswVQSScADvSyO8sjSSMWd
+iWZickk9TXq3wu8E7jH4h1KPjrZxMP8AyIf6fn6V43v4qr/WiP0xLDZFgddfzlL+vuR0Pw68FDw9
+Yf2hfRj+07heQf8Alih/h+p4z+Vd1RRXs06cacVGJ+aYzF1cXWlWqvV/1Y+dv2lv+Qp4e/64zf8A
+oS1sXPwI8IQ+E31J9Sv7eRbPzjNJMnlq23OSNo4z2zWP+0t/yFPD3/XGb/0Jakt/2e9SvdMgdvF5
+2SxK/lG3YqMgED7/APSrOYl/Zr1C7Ztd04sTaII5lBzhXJIOPqAPyrQ/aU/5F7Q/+vt//QKyvgD4
+in0zxBqXg26VWQs8sTog4kQ4fLdSCAMfT3rW/aU/5F7Q/wDr7f8A9AoAj8J/ArwprXhHSdUurnU/
+tF3axzSeXMgUMwycDaeK9G8E/DvRvAX23+yJLt/tmzzPtEgbGzdjGAP7xrx3w38C9S1nw1pupx+L
+Xtku7dJlhWBiEDDOM7x6+levfDrwTP4G0a6sbjVn1J57jzvMZCu0bQMck+lAHk/7S3/IU8Pf9cZv
+/Qlro7b4AeD5dGhupr3U42a3WR5DOgVSVyT93oK5z9pb/kKeHv8ArjN/6EtV7/4Y/E6bwrJNJ4oN
+5aNbCQ2IvpTvTAO3BG08ds4oAb+z7dT2fj3WNJt5/OsGt3YsAdrFHAVh2GQxr17xp8MNC8d6hbXu
+rS3qS28XlILeRVGMk85U+tee/s33umNZatZRWDJqaFZJrotkSRkkKo9MHP1zXu9AHx4/gvTV+M3/
+AAiIluP7O+3i337h5mzGeuMZ/Cvo3wZ8LtB8C6lcX2lS3ryzw+SwuJFYbcg8YUc8CvFZP+ToB/2F
+l/8AQRX1BQAUUUUAFFFFABRRRQBieKfEtr4X0Z72fDyn5YIc4Mj+n09TXzlqepXWsalPf3shknmb
+cx9PQD2A4r6G17wVpHiS8S61IXEjomxFWYqqj2FZX/CqPC3/ADwuf+/5rgxNCtWlpax9bkeaZdl1
+Nuak6j3dl9y1POvh54KPiPUPtt7Gf7Mt2+bP/LZv7o9vX8u9e9qqoioihVUYAA4Aqvp+n2ulWENj
+ZxCK3hXaij/PJqzXRh6Coxt1PHzfNJ5hX53pFbLsv831CiiitzyjxX46+CvEXizUNGk0PTXvEt4p
+VlKui7SSuPvEehrIivfjzDZpbR6cFRIxGp2W+4ADA5z1r6BooA8V+Dvwu1jw/rVx4k8SL5V66MkM
+PmBmyx+dnxx9Oe5rT+OfhTW/Fei6TBolg95JDcO8iq6rtBXAPzEV6vRQB886ZL8c9I0u102z0pVt
+rWJYolKW5IVRgc7ua7f4e3/xQuPEMkfjGySLTPs7FXCRA+ZlcD5Dnpur0+igDxX46+CvEXizUNFk
+0PTXvEt4pVlKui7SSuPvEehr1qK1lHh5LMgCYWoiIzwG2Y6/WtCigDw34I+DfFHhDxHqY1nRnt7a
+5twouDMjAMrcDAJJyCfyr3KiigDwR/AHig/H0eIBpbf2V/aAn+0+YmNm3rjOf0r3uiigAooooAKK
+KKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA//2Q==
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450
+Content-Type: image/jpeg;
+	name="image002 2.jpg"
+Content-Transfer-Encoding: base64
+Content-ID: <001201c68a59$4f153470$6401a8c0 at madhouse>
+
+/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
+HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
+MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCACWAIgDASIA
+AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
+AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
+ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm
+p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA
+AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx
+BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK
+U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3
+uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iii
+gAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoqO4SSS2lSGXypWQhJNudjY4OO
++K42wsbiV5rW7v8AVYri0ZUuFS/ZkmYqCHVvvKOc4GPTms6lRU1dlRjzOyO2orlxpk64K6zqgOfn
+JmDbl9OVwv1ABqtcz61b3SW1jfXl7d7RJHG8UQiCbsfvG4PPPI59qzjiYSdkVKm1qzsaKKK6DMKK
+Ky/EV6+n+Hr65jR5JViIjRPvMx4AHvk0AV28U2L3v2KySa9uMZ2Q7VGOehcqG6HoT0rQs9ShvHaL
+bJDcINzQTLtcD19CPcZFeVeCNY1LxT4ch1Bz9g/4mSW6MYQCxWMIME8bQu7oPvV3uuSS217C8R3f
+Y7ZrlSeWARlDAnqQyFh9QKAOkopAcgEdDS0AFFFFABRRRQAUUUUAFc1aMZNU1iU/8/YjH0WJP8a6
+WuFtfEemQ6lqdtLLIr/a5HLeUzKRwoIKg/3T7cVzYq/s9DSl8R0VQ2DZ8TyrjpYof/Ij1mz+IbNo
+glnI0lzK6xQh7eQLvYhRklQMc561UivZNH8YMt5eTTkvFZ+YbcJFsdS43MOAwc98cEDknNc+Gg+b
+mexpVkmrI7uiiivROcKxtQniu9WtLJCSbaZZ53zhU4IRSf7xJBA/H0zPraXcmn4tPMP7xTKsTbZG
+jz8wQ9jj/wCtzXIw6hDBY2zwNEL+5uhFBY7Cz2kjttaSUMSzMo6k/QcEUAdJ4pM8ejqkEY8l50S5
+YQ+YY4ifmcLg5I47cde1Z1oka+GNSnFsY3unlggZlIZ42YrFgNyBgjj8e9VdNt9eigeW01tp0M8o
+Vb0b2wrkDJx7dsVDq0Otag8R1KHzrSPJNtDHmN2/vEqxfge1K4Hdx7REgUgqAMEHrTq5W08WW1tH
+HayWBhWNQixwuPlAGANrbW/IGti117TrtkQTGKVuBHOhjYn0G4DP4ZpgaVFFFABRRRQAUUUUAFcJ
+4UtbyzhmZlj+yzSM6MG+bj5B0HQhQcHpnjNdrd3MVlZzXUxIihQyPgZOAMmuV0a7itrC2sLtvs17
+Gm14ZvkOc54zw3XqCa5cXflVjWla5p3UCXdu8EpbY2OVbBBByCD2IIBrLlmtYjdaTHb3eoXk6F5Y
+2QkybhgFnICgcAZ7Y6VtYPpUFp8viZDz+8smA/4DIP8A4uuOiuaSg3obVNFdGppsM9tplrBcyCSe
+OFEkcfxMAAT+dWqKK9Y5ArI1iCP7Rp7qiCR7uMO4UZYAMcE+nFa9YevS+XcWrA8wxXE+P92PH83F
+AEGi86Nat/fUv/30xb+tXqgso/J0+1i/uQov5KKnqChJFWZNkqLIv911DD8jWTqWk6fHpty62/lA
+JuxC7ICQQRwDjr7Vr1T1RPN0yaLOPMKRj8XUf1oQHQ0UUVZIUUUUAFFFYXjLUJdN8J389u+ydkEU
+bA8hnIXI9xnP4UAZGt+LNO1OeTw1YGae5u3+yNPEmYoyfv8AzZ5IUN0zgitybSrsRGKO6ju4f+eN
+/GJB/wB9Dn881558PbOOTxbHtXEdnaO6D0JIQfpur1l5EjALuqgkKCxxknoKAOXbToLY5k0e8tcH
+/WadcMy/98gg/wDjteH/ABG8Y+I9F8eQy2F5f21hZMBbfaQQ0mQN7FSAWUkYwcjivo69sWuSksNx
+Jb3Ef3JF5GPRlPDD9fQivM/ij4Xn8XafAsunmTVtMDTLHCSRcwtgMUPXcCFO08+mahxW9jajaU1F
+u1+r2Xm9HodN428f2/g7wbb68Lf7d9pZEhRH2Biylgc88YFVPhj44vPG9nqFzdrAoidDEsKkBVYH
+g5JyQVPNeBWFn4y8dTReF7q2vmitlP2ZZ4ii2vzfeckD6ZPPYV9HeDvCOj/Drw4LWGQBmKm5upDg
+zP0H0GTgAevrT1bKahCn0bf4Wf6o6yuZ8SSZmul5BTTnAP8A10dV/wDZa1Rrmnn7kzv/ALkLt/IV
+h6o0Gtah5VlNN5jQgXCSK0SeWrZHJXdksf4fQ1TOc2Su07f7vFJXH63Z+Lbe4jl0y4uZICnzJDOJ
+CrZ9JBkjHp6Vmi+8eR8eRqD/AO9ZRt/KosM9Cqte/MbOP/npeRA/8By//sorldOvfHNxeRRy2SrC
+T87z2qxhRj1Ddc47VvC5uLG+spdYdEiDsI/s8RbdJtOAcZI43EcdqaQHVUVmDxBpxBO+4AAzzayj
+/wBlrRjkSaJJI2DI4DKw6EGqEOooooAK4z4lSAaBaRd5LxP/AB0M39K7OuE+JzYsdLX1umP/AJCe
+gDP+GSZ1fVZMfdghX82c/wBK9GubaK8tpLedA0bjBH+HofevPfhjIBqGrxZGTHC4H4uK9HoAxI9Q
+vdPVrG7t5Lq6HFtIg4uB6seiEfxZ47jrisaaK/sLhry+knt79jzfW6Ga3Zc8IydQoz3A5yd3JrtK
+KmUeZb2GnY4uK+vEaG9ED3pjnLmWym85WjfAdQpIZR0YDnBFR+IPE0DCWa3uDE9quIEkhbcZmBy2
+wjJ2rkDjqx9K29fstOt7Ge/axQ3IAVHiBR2diFXleepFY18NZ06CBtJlvNQdUKSxXcLDc3GGDbQR
+34ye1Q/aLs/wH7rOL0BfFGsakdQ1G71O+tEdlCwEhBjqQAR83XjrnFdlotnNqUklzrXkX87WlsyM
+YNuxWViRj61T0jR9RZ5bjVbm+hlnU+bGkbuCd2RjCgYAOOck+wFbElotw6LLbQ/IgjEyWE24qOg2
+4AGPqa0V2tRFs6LpxOTptuT7x0v9i6eOmnQj6R4rOFjb7wqpLkdPM0qXH5jFObToUPFsjbuudPuD
+/wCzUrBcvnRrA5zYRc9flqte6fp9mLa5+yW8JjuoW81ht2fMBnPb0qt9kgxzYA/9w64/+Kp6QRxu
+jxWIVkO5SdNnOD64JosFzrIpY54xJFIkiHoyMCD+NZ9gTZXs2nMf3ZzNbf7hPzL/AMBJ/IiqWnSW
++nNO/kXzyzsGkKWLouR6KBge56mjVdTRoEuIbO/+0W7ebGTaOAcDlSSOARkfr2qhHQUUUUAFcR8T
+YydI0+YfdjvAG/4EjqP1Irt6o6zpVvrek3Gn3O4RzLjcv3kYHIYe4IBoA8e0LW5PDmr/ANpJbtcx
++S0U0CEB3XIYFc8bgR0PXJrbj/aB8Fk7Zl1OBhwyvbdD6HBNYesaJqWgSlNRhPlA/LdxKTE49Sf4
+D7H8Ca5u/wDD+j62xkuLWOSXvLC2G/Ejr+NAHoMn7QPghASrai59FtsfzNZ9x+0d4WjU+RpmqzN2
+yiKPz3V5hcfDSwck295dQ+zqHA/lVGb4YuFzFqiZ/wCmkJA/MGgD0y2+OkfizXdL0K10JrdLu9hR
+ppbjcVAdTkAD29a90r5M8F+BNXsvGulahF5N3aWV5DJcSwtxGN4HOQOeeg5r6zoAKKKKACiiigAo
+oooAKraj/wAgy6/64t/I1ZqtqP8AyDLr/ri38jQBZHQUUDoKKACiiquoanY6Tatdahdw2sC9XlcK
+P1oAtda86+LWmabb+BL27jsbaO78yIJMkYVwTIucEc9M1m+IvjRaQB4fD9oblhx9quAUjHuF+834
+4rz3WX8V+KtKuNb1X7RNpkGG3yfuoRkhR5a9zk9Rn60AT/Cqxt9Y8a/Y9SVrq3+ySMIpZGI3Arg4
+z7mvdY/BfhqJty6LZk/7Ue7+dfNOiWupx6l52gpeC+hjaTfasS6oMZ+o6cc16F4f+M2p2TCDX7Vb
+6IHBngURzL/vL0P6GgD13U7aG20fybeKOGMSxEIihVH7xewrUrlV8VaL4m0N5NKvo5mDxF4T8sif
+vF+8p5FdVQAUUUUAFFFFABRRRQAVW1H/AJBl1/1xb+RqzVbUf+QZdf8AXJv5GgCyOgooHQUUAFeK
+/HC68zVtHs+CIoZJvoWIH/spr2qvl/4o+JZ9U8e3w+zfZlswLVUmzuYKSd/sDnI9sUAel/DHwLol
+z4es9ev7UXd3OWZFm+aOMBiBhehPHU5re+LBVPhzfKAADJAoA/66rU/wuuorv4caM8MboFiKMHHV
+gx3EeoJzj2rM+NF3FbfD9xI+GkuoVRB1fDZIA+gJ/CgDzz4SPt+IdsP71tMP0B/pXsviDwToPiVW
+N/YqJyOLmH5JR/wIdfxzXhfwn1GD/hY+nKxaPzI5UUuMBiU4H14/SvpWgD5rv/Dx8MfEyx0tLh5R
+Fe2zRzY2syM6nBx+IPrX0pXhvxSnEPxc8OJGhV5Dbb3bgN+/ONvuOc/hXuVABRRRQAUUUUAFFFFA
+BVTVG26TeNjOIXP6GrdU9W/5A97/ANcH/wDQTQBbHQUUDoKKAFrPvtB0jVJlmv8AS7O6lX7rzQqx
+H4kUUUAXo444Y1jiRUjUYVVGAB6AVj+J/C2meLtJOnapG7Rhg6PG2142HdT+JoooA53wr8JtB8K6
+qupxyXN5dx58l7hhiLIwSAABnGRk+td5RRQBQ1XSLTV4FS5hjaSNg8UrRqzRsCCCuenIFH2S/wD+
+gm3/AH4WiigB4trwAZvyT6+UtL9mu/8An/P/AH6WiigA+zXf/P8An/v0tH2a7/5/z/36WiigA+zX
+f/P+f+/S0fZrv/n/AD/36WiigA+zXf8Az/n/AL9LUVxYXNzbSwPfuElQoSIlzgjFFFAGh0ooooA/
+/9k=
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450
+Content-Type: image/jpeg;
+	name="image003 3.jpg"
+Content-Transfer-Encoding: base64
+Content-ID: <001301c68a59$4f153470$6401a8c0 at madhouse>
+
+/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
+HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCACNAH4BAREA/8QAHwAAAQUBAQEB
+AQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1Fh
+ByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZ
+WmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG
+x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APf6KKKKKKKrLqFm921q
+tzEbhese4ZqzRRRRRRRRRRRRRUc88VtA800ixxINzMx4ArGi06XUYLuWTdax3DCS3jKgvEw/5ac9
+GPBx2+pNWre+lt7trO/JLFwIJxGVSXIzjuAw5HvWnRRRRRRRRRRRTZJEijaSR1RFGWZjgAVlQxtr
+Fwl3OrLZRtut4WGPMI6SMP8A0Efj1xjXqC7tIb2DyZwxXcGG1ipBByCCOetZ2lX8yyJZXTxzNl1j
+uI5Q4faeVbgYcDGfoa2KKKKKKKKKKZNNHBC8szqkaDLMxwAK5MwJ4g1dlvnnjjKsYIXXbwDwSp7E
+c598HGAK39PunDfYbvi7iQc9plHG9f6jsfwJ0Ky7+eW7uv7Ms3KNgNczL1iQ9AP9tu3oOfSrFrpV
+hZyLJbWkUThNgZV52+mauUUUUUUUUVDdXUVpAZpSQoIAAGSxPAAHcms20VtaZby6UpBG58q1bqrq
+cEyf7QI4HQe56bFZmuov9mPPys0GHhkBwY26Z+nPPtmsu7v5LS4RbfVFkmWJ5J5JhmHheAAOA2cE
+AHOAetbWlWq2unx5D+bIPNmaT7zORkk+/b2xirisrKGUgqehBpaKKKKKKKgvLuKytzNKTjICqoyz
+seigdyayW059VWSW6nVb2MgwxxtlbRuq/VvU+hwOOrLK98i5Fw6eXDdv5dwn/PC5HH5NgDPrj+9X
+QVUvr6KwjWS4Ui3J2yS/wx+hb27ZrH1eSxnitLKzXzStws22yCsYgvO7jgdh+NNlNu6CK/udVFqW
+AdLmLaj56BnC8DPuB61R0TQLpDFNZ3UtjaFmEsCyfMMZGNu3aCCO3607xb4m1TwPo76pLYNrFhGR
+5rxuI5YQeMsMYYZxyMYzWd8OviJqnj6aeY+HGsdLiTAu2n3B5Mj5VG0Z75Pbj1r0KiiiimySJFG0
+kjKiICzMxwAB1Jrm9PafxNKuqq7QadyLUjiR16Fx/dLevUDpjJrejittOtG2KkMEYLNjt3JPr9ay
+LoIIxqMtuwsruMLewuOVX+GQgdwOD7f7tW7GeW0uF0+6cyBhm2uD/wAtV/usf7wH5jn1rM1e4XUQ
+5E0kcELlbXyhuae5HQgfxKpHQ8E5zwK1LJbTRtNhFw8Ns7gNK0jqC8h5Yk9zmpf7V0ucGL7faOGG
+Cvmqcj6Zrldc8W6d8OtGlmuoZrjTxJ/o32RQ5BYklGOcDBzgnqOOory3xN+0JBqunXumWnhwPa3M
+bQs11NyUZSD8qjg88c1c+Ffibxr4wvtOsrMWmleHtJx9oa1tsLKBjEXOeSPTHcnnFe/UUUUVi6pP
+FcavZaXNk28oZ5Rj5WI+4jexwxx321XmhvofEsh05oYEMHmtA4O26bOCc9EKjHIBJ3DPSppbptYk
+i0/7NPD8we7WVMbUB4XPRtxwOD0BrbIDKQQCDwQa8W+Id1YpqY8LDUtTtdRWWK40ybzjHbRqOTGz
+AjoAcE5Iytem6JZQWGlQ39zJucW4IdzkQxYyEX2Axk9SRk1BHpd1qmryapcBraJowkAD4lVevIxg
+ZJJwc9qg1jwvqWsW/kNq7QRpJkBYlBlHbcy449qyrDwFdWcV1aXg0/VtPuFIaC6Ugqc5yrYJH0z6
+YxXz3rfgc6P4vso9RsbrT9GvbwQqqyrNLGMjK545wQRnse/NfWmi6Hpvh3TE07SbOO1tUOQiDqT1
+JPc+9aFFFFMmlSCF5pG2pGpZj6Ac1l2+nfbNMle53JcXZEzMPvRHqmP93A/EH1qJ3nvLZZVQf2pp
+7/PGON/HIHs68j3x6Vr21xFd20dxC26ORQympGZUUs7BVAySTgCvIfGXiy4tvGdtplp4eXXbO+Zb
+iOSBd7o4Xy3ABGPu4Ocjr1rodT8aaLaW1r4WuHuf7amtlC2oiKspCZyWPy4+U9znFdVZXupukC3m
+mhXcLvkglBQZHPDYb9DWpSNnaduN2OM9M15p4g8CXnjHxPZHU7yGC1sJ0vJokBkaYnhVBwAqgJ6E
+/Ma9MoooorL16aKOxijncJHPcRRMT3BYZH5A1nS+L7ODxNLYTzpHZxxBfOKNtM5Ygru6DAx17mk1
+TV47LxJaEqI1DiCeQtyyMpKtjH3Q2Buzxk+9Q6jawXF4iaBOY7yRm86S3c+Wit1dyOMgjIHc545J
+rQXwvZyfNfz3N83fz5Tt/wC+RxVHVtPtrd7kW6GIw2bSq6OQyuTgMGznIC4+nFc9r3gTQ7fxbBr7
+XV2+rysHaa5nLRRRqMHcAOARhOePmrptP1aC6mg1BtJuUluYTJHNCQ6yR8DdgHPdTyM4NaM3iHTr
+faJmnjZm2KrW0mWb0Hy8moLrVL3KrHALdpP9XG48yZ/cIDgD3J471HbR3mnX0V3eyl/thEEoJBEZ
+5MfQDuSD7kVv0UUUVk+I7KS80S4EDMtzGpkhZBk7gDxjuCMgj3rn9a0vw4fB93PBFbs0FoVEsD+W
++cYG4rg9euauRa7Ndada2aeW11cBIRcKVkXkfMxU4PQE4xiqotLrwnrFvez6jHdW14Y7OQTfIy9S
+rL1HGTkcVd1bxVdWupC00nSZNVCxCSVoJF+XJ4HP+eap6rq1tJYajeuwR5IIYhblh5u8OdybOu4F
+sVbm3YuxdPsd08zUJVOfKix8sK+5H8ye4psWlWVlbrdT2JW9uDtt7WByhjGOI1wRgADLHpnJ7Cls
+ZIAsb2V1HqGqXJYLIZWkS3UcNjJyFHT1Y/pvWVjFaBmDGWd/9bO/LOff0HsOBS6hbLfWE9tkBnTA
+P91uqn8Dg0un3RvLCGcjDMvzr6MOGH4EGrNFFFFeU/H029r8OpJFiRbme6ijEirhu7Hn6LXzx4W8
+ba14S1S3vbC4Mghzi3nJaIgjB+XPHB6ivSNQ+PF3rQsJF0RIbiyZ5pNt0QrjaRx8uRwT61s+C/jT
+on9sXEmpWF5FeXpigiWCON1ABOASNuSS3Uj+VehW8WoRalK11HbHZMZIrZYxvNxI7GMO/favzEDp
+wcnFa0iQW8gtppC1vZ4ur2QjmaYnKjHc55x/uCrIlazH9o3sbPf3P7u3tVOWUdQg9+7N0/ACrWl6
+e1mJ7icp9puX8yURjCLx0X+p7nJpNB50W3kJyZd0pJ/2mLf1pLMY1/Ux6pCf0Yf0pdN/dXmo2pz8
+s3mr/uuM/wDoW6tKiiiivFf2kbgJ4T0i37yXpf8ABUP/AMVXzVV/TU3Q6g+QNlqT+bKP61a8JKje
+MdG83/Vi9iZ/oHBP8q+wtJQBp9Suzhbfe7E/89W5kP8AwEYQf7pqvaSqqG8vVYrE/nvGBkyXL8qg
+HcqpVQPU+1ben2Mola/vsNeyDGAcrCv9xf6nufwAm1SY22lXcwOCkLsPrg4qSyg+zWFvBjHlxKn5
+DFU7P/kP6mf9iEfo3+NPwU8RZzxLa8/VX/8As60KKKKK+f8A9pe4O7w7bZ4xPJj/AL4FeAVfsm2a
+dqR7tEi/+Pqf6VtfDa1hvPiT4fhnAMZvUYg9ypyB+YFfWF3b3tvpU9vP5SWccrFdrbpLjL5VfRQS
+QCeT16VPolmbjyr2Y744932fj77N9+Y+7EnHov1rfrM135tNEP8Az3niiP0Lrn9M1p1mWGG1fVm9
+JI0/KMH+tOuTt12wP96KZf8A0A/0rRoooor5t/aTm3eJtFg7JZs/5uR/7LXiVaVog/sLUnOMh4VH
+4lj/AErpvhDZR3/xP0eCVcpukbg4IIjYgg9iDgg+1fTM1rqmowW3nym8sIbqXzo41VJnVCyqCcgE
+euME1ux61p4ASSYWzDA2XCmIj/vrH6VejljmXdFIjr6qcisnxTbXF3oU0NvEJRkNIgIDFV5+UkEZ
+yB2NclJe2EcLJY6hdxzHIVFOQW+YD7pBxlfTuK7fR9PGm2AjMsk0rsZJJZM7mY+ufQYH0FNufn1y
+wUdUjlkP0+Uf1rRoooor5c/aJm8z4h20WeI9Pj/VnNeR1o24P/CP3zA8efCD+T12fwPAPxX0rP8A
+cm/9FtX1XowxpoPrLKfzkanFmk1loHO6H7MG2HkZ3Hmkl0TTZW3NZRK395BsP5jFN/saAEeXcXsQ
+HZLp8fqaP7IXJIvr0E9SJuT+lV77Ski0+6lF5flkhdhm6cYIB9DVrTNPtrWFJo4sTyRr5kjMWZuM
+9SSetX6KKKK+Tfj3Jv8AildL/wA87aFf/Hc/1rzKtKEEeG7xuxuoR/47JXZ/A5N/xX0v2SY/+Q2r
+6p0Jt2jW7eu4/wDjxpV/5GKT/r0T/wBDatCiiqup/wDIKvP+uD/+gmmC4aCKNBbyyYjU7kGR6VH/
+AGqTwthekjsYsUsOqrNMsYsr1dxxueEhR9TWhRRXyB8bHZ/ixrGf4fKUfTylrz+tNePC8nvepn8E
+b/Gu0+BZx8VdPPpDP/6LavqrRwF0ayx3hU/mKYh/4qScf9Okf/ob1o0UVT1U40i8P/TB/wCRpZbK
+K7hhEhcFACpRip6e1V10O1QgrJdDDbv+Phuv51ZtrCG1mkljaXMhJYNISMk54B6Var//2Q==
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450
+Content-Type: image/gif;
+	name="image004 1.gif"
+Content-Transfer-Encoding: base64
+Content-ID: <001401c68a59$4f153470$6401a8c0 at madhouse>
+
+R0lGODdhXAB0AHcAACH+GlNvZnR3YXJlOiBNaWNyb3NvZnQgT2ZmaWNlACwAAAAAXAB0AIf/////
+5sUAAAAZEBCEhJT/78WlnIzv7+9SY1oxMSEIEAitnK1SSkrmEEoxGTEQYxk6Woy1QkoQWoxjWozm
+CBmEe2NaCBC1EGvma2vma621a++1EO+1aym1EK3ma0rma4y1a861EM61awi1EIx7Slr3AADmKRml
+OhmECBDOxb1jhFoxY1I6794671o6rd46rVqEpVqEKVI6rZw6rRk675w67xk6Ga06Kd4Qrd4QrVoQ
+rZwQrRkQGa0QY1IQ794Q71paKVIQ75wQ7xkQKd5jpVpj795j71pjlO9j75xj7xljGa1jpRljKd6E
+zt6EzlqElM6EzpyEzhmEGYw6zt46zlqECFI6zpw6zhk6CN4Qzt4QzlpaCFIQzpwQzhkQCN5jhBlj
+CN4xEBA6Ojqtvb1SUikQEDG9CBCt5r3mQkoQEGOt5pTe1t7/79ata63mEGuta2vma+/mEO/maynm
+EK2ta4yta0rma87mEM7mawjmEIwQOhnmnGs6Wu86Wq3mnK3O5r0xYxmEWimEKRm1Qmvvxb21nO+1
+Qu+1nCm1Qq2172u17ykQWq1aKRkQWu+1xWu1xSljpZxjWq1jWu9aWgiEWozmnEo6Ws7mnIyEWgi1
+nM61Qs61nAi1Qoy170q17wgQWs61xUq1xQhjhJxjWs6tvZRza2uE796E71qElO+E75yE7xmEpRmE
+Ga2EKd6EhBmECN7mShnFOhmtlGvOvZTmnO/m72vmQmvmQu8xEGPmnCnmQq3m7ynO5pTmxWvmxSnv
+xZStnErmnM7m70rmQs7mnAjmQozm7wjmxUrmxQjmvealxeal7+alEEqlCBCEWu+EWq2EpZyEWs7m
+5t7//97377U6jO86jGs6jK06jCk6KYwQjO8QjGsQjK0QjCkQKYwQQmNjzu9jzmtjpc5jzq1jzilj
+KYw6jM46jEo6jIw6jAg6CIwQjM4QjEoQjIwQjAgQCIwQQkJjzs5jzkpjhM5jzoxjzghjCIzFxeZ7
+Y0rF7+bFEEoxOmPv75Tv5sX/zuYAAAgI/wABCBxIsKDBgwgTKlzIsKFDhwfGjEkhMAWBUgbWCDzA
+gAFFAGtKlfoIYMwCiQceqlzJ8IAYBWEGiCHgQECCAQMQEBAjM+eYBAleiinFM8zNAQZYKlWaEkCp
+BH/Y/CEhQAApNtIMJBDAoN+0FFsZSJs2RoEABCkKSOtX6t+9pXBXMkhagM00UhWmFZj2tZTXvxX6
+sdmLdy/faf0UjInLWGFTMQlIFQgQgM1gygEKaM6c+cBkzAfY9Bszq9QABimnNV59cIEDpJr9faa8
+GbNt29PwCSjDgEBT1sALphCQd/bt47c1QyZJsOnv4HAPIJ2GvPpxNgwQQN9ecM2AMcYDyP+2fhs7
+A4PPucddoCBtAX+cP78nvzf7RvXQKyToN3lyv+SYjVeefQg5hx9LCDjAGXm00QZfZgWQIMZ9B7KW
+AALUMXjcbNMQOFB6FTp2kBgMsKEhebmdBwCIFIbokAN52SaggCgioCJ6Lq4kzQDQZNjgj5jNd1tu
+2gGgWo5wraHAVbf9R5k0AJZHFI7NIVlQet6lYGKUJ05TgRgsWvnQGgmkdRw1DArIBj43UimmQikM
+QMhs/80W24aYTWPAAAau+KZD0CRQG2WipaBXnXVtWV4FZYTZ4p8FETXNgwF4eRM+Wmq2wCxrKEqb
+lwNI0xKkBYmBwGCaSSPhAgsgkMA0f4j/AdkAskhDp54JgOhoiGEeUAY+Ju6l328dJVDKAdIQgJSi
+dcnS6IeQ6jqQRQYQR10BfwzA3BgCTDjQnmt8JtiwBb4J4h9lJGDWAtOwcYBWwgmwGEEJ4COfngq8
+5We5f3I0IQI2iWQAiQX91KeNeiVcbSkEaPQoqQJNU0YFAMjS7U1VeTvtABpN0xQB/xhAishjMFAV
+UA5DnF4KZchigGmasbEGPmWI2tRPKQvEbVU8V5VUAklBu6+YN4uhn6yowqotQaUIkDMA+pGWggEG
+6GaohxAXRADQsjKgV2YdFrniPwIQUBDQehnGrQEVMKCxm2ISRQoZA1SwpWbDNVxyAgxw/zwQNNrK
+V0CcpJAI5r675pjg1AOwK7gBCgzA9xrUlPFdydNhxt8s2hqeuHq/pWeangKYSRl/BVCTgqF1/VGB
+AnzP4iOEKSiWnQPMCf3nGEjxxN9t1LBRQQWb2cUAPu1umC0pDCRQRu68MmTaP/sZ55UsgdPGBlgG
+eEobIQMQIMtTz32+lLSIf5gCUYM5iWY/ZZSS4WfTLDDAH+EV0M8AZNSfK7+kspFm/oMmfJkuSNMw
+mvcysxW8PCtH5huIsTSjvwBQowAwC09lGFCKywSpHw74B2TMpjvooC8hLokRZQr4lEH9bhrsExJt
+TCWNp13JRX0aiHcMMLvgVSBUtUldZv/chirbFMBUKDxQBGsHHiMWQEny+wyaRCMAHh5nGgkgAdyC
+E8Gh3aM9GixAtfKCKqmIgQye2ZDbspY+g0BuTqejjbBESAK29Y0BC3Kiq0pYJeCEriFb+10ewUaK
+p0gOAQZII3Kw8zY+Wik9WtGgbewyOMF4cEMY/B8AV9NFpnlNQxTUUG4ScMPoDS1MCBDDoJBzpw1R
+qlKlgEfiOslJHV5odtaR5Ibe8EAcqmQBZOMhmk6koQPAgE8UyiF3/tii2m2lFKuMIzGNaIB/2JCN
+TtFOtbpCp8y8MjnfpAzpoFfKxnTRJR+x33e+Rh4asXJP+kJSn3JIpnmtCGB+yR+l9Dn/SVK0h0q0
+BE41n0YABYihH4oEEisnGSeSBFQ9YqiiQdbAAAXI4pLTzMwsnreQhx4kgtDYzYVARIAyiGENs3MS
+g7b3z0cm8z7DEcs9+mbPgUgDAQPwi2iIiTcFkFBoHmWMGGo2EGVVAET2E4OhFnib8RTgFwqABjYF
+EtLcpWAfZUJPKRTgEcvkEkLZopiIalnOA0jnp1pLgG8M8pOzLDUAKk3O/kg4y5ee7yCMOtJBUuC2
+mhb1Jl2dFCsTg1a7jio6YyusXr9lLBYtgCdiMAA1ktek8Pmxowl5ymITMtMELAAh6wMKAxaAUK/u
+JQyl6GNZVcuS56zhH4VdSKAQcE2Q/0CjeXzLiFcOkACxNiYFHjXNNR0VEqQQlwCuCtgPD1fKXhWE
+PakdGmubE1VHKoR3CYgnQgjQM5v0Zle7UgHPyPnRbzlNuukJU0gaC9qt9Iy2KhCDXzcJAO7yrJFb
+XEMZVDDW6ZbEAQmwp3O2QjayVcVsjyUvlRbQ3XxtViEhda5KmsaAnDXtHxiuygAODIDe2JVFgOvu
+WTb5mDYNZAzR9a9BUsCTz5aEZ2QbAAoo0IyMieEPClkAjgViXxH7rSFxqmlTGOaYBYQJGulKAYN5
+ZgEzlKAEFNiwJhEysLesAWAi5tl8VduRg4xBDHpl0WgTQtF0abgZT36yGbqF3+aUQv8jLAtDM1CQ
+ZQGkWCFrEICLIyW2zK5gIRYxy4wp8GQKoOA7Su1jSj6mAAsU2gJZbnN6tvbRAD/qOXv6nH1RYIZO
+09kBB0CAi8P0BwE4Os0UgLSIFbwRy/aJd5/j3ZbZGlEBbPhkTrlzpVGQ5kLTubttJgh7RGWQUjhg
+iyD5zn0WrbtpYJlnjTLAPjoKj1P3OtWrdhMS0TMT6wqkngNpVUrW4NBvr9olxAaqQBAQhl73+tc8
+i+208uXl+yVxI/KVYHQR0Odv3zreAMi3QppmBkJDGdWqzlhm2/QbA/RyIZF9F8DQwuBSSKQgADNL
+GMLwr586VgDNILTIEZ4x8pJpz6X/0nWvxLAA7uqEKCRqHqgJUi1Tl6DGU9N1MxtdaFQ/mc5TFhp7
+NIKlpd1bICw3jZfLkLPhhMHgFrDGYztaBgsYfORqlpdCUokjaBxbdyxSq43qne4V3STNh15Ahae7
+M14b/N3B3kgZgmYQtarEWNsu2I8HAjA0P3kAK1B2QnYGcgqMnNAWkLefynJN3u34hAMRA9l0XpJQ
+FaRaVv+5zxRCFQGQjdc+FzxCnoIjh5eXy1WRakGmsYaTXmkrb99wkQ7gsRWlBBpmgXHI09wMZCbE
+WKPX+kNqjfIPWZpCEwB5ocMggK9fKaQw/oegoW7i7iig+B96ikkrsADtHgTL2Ec6/92NBAAGWx3b
+Arj+h8awExhXxcCFL0FOHyYQhzOTIGswADRKUQaDdoQABGAAKUBu5FZr85IeOmEQOyIAZgBv6YcA
+JAAPt2YBzQBpued56ceANTZr69ZvClEBXFEsAyB9AiCB6VJR5FUK1ecUddYzTSZyzFcVF2hr6adg
+vDV+CwEzfKE/3HIsKbAYOLNdHggAtfN+GchkfpdmCdczt0Z501IGW8YiT4E6mkEIwudv4Vd+vqc1
+ImYWmeduNdaCFAEN3sdjpKRiAxFDhEIKelYQZaB6LRIow/VvPJOEb2d4LZha62MA88V1D0FEeVIt
+xYcATmg/LOISNFgVBXdwb/dkMf/YXQiALBPwMrlzVkc3EL/iI2xgMTs2LVlVbFP2HCZTh3cociK3
+hFURXQaAXPP1RaNGf/RCAHczDSSwhXwXdMmmeFAjBjUhACjQDM3QacA4ZyiAAhZAh2OmPgdRLbXV
+R38QMrXhbAqgK+liZGswBlrhhAIhElc2gw3Wf10zEg9hGhJGEPdgFfMxWSSAixsBc85zfIN3hvdg
+AAigAA6QSr2RETVUjgeBNfdWLe7xJHxzeiDxB8PVHRw1EAzgWyvBInnXRgahLPwBH5rBG2joEFlC
+EPzmR56FWWlYPf2xP3B4VwKRD40jbM7HFAQhDWWQhaXENx6kPz5FkqXCXzbFIxD/YV3ScHzpdRB8
+w06Dc5KG1Ua7MhTNMTHI1hC88zSO4hIdhBlsMAsK0IxKQXpME3crYYgeCRIKYEXixIz0dXq/UVLP
+wR7KxBKwNibfwSxaISoPthQhlTM74pIqAThghxDsEZCV8iX+NU8LoSR+BXwXmWO22FxUNQCCBEvB
+Zj4ggkWFpQJlsBpgQZUFUYuDUgB+2JDlFHC6BjlnqRIsuRj3ZxCyYifm0SJBtY2NlA9daU7w2FEK
+gCFBUgB2xy+fiZdE9SEDIAqrYZT0FzoKQALMwga+qRLlYxDZkjtd5m3SU30swi3FQRv7g3JBFToO
+MJL1hUypyXhK+Q8qhDdGl5SbHIlxusZgrAYRggk3axNEtXOet5lZjYQuHNgQAQEAOw==
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450
+Content-Type: image/jpeg;
+	name="image005 2.jpg"
+Content-Transfer-Encoding: base64
+Content-ID: <001501c68a59$4f153470$6401a8c0 at madhouse>
+
+/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
+HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCACXAFwBAREA/8QAHwAAAQUBAQEB
+AQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1Fh
+ByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZ
+WmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG
+x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APf6KKxb7WLmWW5sdGtT
+dXcQCPMWURQM394k5YgfMVHOMdM0ug3ErzalaT3sl1Ja3AjLSqquMordFA+UknHt9K2aKKKKKKKa
+7rGjO7BUUEsxOAB61zT3V74qMsGnyXFhpBiw140OJLndniLd91cfxkc5GPWt+zsLTTrcQWVrDbwg
+52RIFGfXjvWfq2mTNcR6rpoVdSgXbgnC3Ef/ADzc/qD/AAn2JBu6bqMGqWKXUG5Q2VeNxh43HDIw
+7MDwat0UUUUUVHcQR3VtLbyjdHKhRxnGQRg1zqpdeF7u2M2oXV7pU5WCR7oqWtn6I2VUfIeFOehw
+e5rpqKwdRt5tJvn1qwhaVJMC/to+TIo4Eiju6jt/EOOoFbUE8V1bx3EEiyQyqHR1OQwPIIqSiiii
+iiorq2hvLWW1uIxJDMhR0boykYIrkYNd1SwvE8PLCbi5S5NvHqN0cQuPL81VYryZNnB4AOM57Vbh
+1HWNY1GfSJIo9Le2VTdOkm95VbODDwMKcEbjyCCMZGai8NwyWeu3tna3NzNYQllcTI6iNvlKgFgA
+Ty/K8Ebc89bj58M3+9RjRbqT5xni0lY/eHpGxPP91jnoTjoaKKKKKKK4vW9Fa/8AGMNnFePBDdxf
+bbgRnEkcsBVY5I25AJ3gEY5CD1Od/TdImtb2S+vb+S9u3iEIdo1jCoCTgKvck5J/lWrUc8EVzBJB
+PGskUilHRxkMp4II9K5rw/rC294+jymR7RZXi068dsicJ96PP95DkAn7wUnsa6miiiiiisfWLO7W
+8tdW06ITXVsrRvAWC+dE2CygngMCqkZ44I4zmqk/ie5hVJ20G9gslkC3NxdMiCFScbgoLFgCeegx
+k54ro6x9Zu5ZZE0eykKXl0uXkXrBDnDP7HqF9/oaxpNKs9Xi2RWTz6Ppq+TZW8LhS8o4aVWJHKch
+TnruOelWtJ8QNa3H9l6000Ewx9nurmPyxOp6At93zB0IB56jrgdPRRRRRRTJYo54XhlRXjkUq6sM
+hgeCDXGWfi610x5PDYmS71i2m+zWsW/aJ1xlSWPHyrgP1IKnjJAq6bSeKT+yo52l1O/Am1G9UbfL
+i6YX+7nlUHbk9QSelt4IrW3jt4I1jhiUIiKMBQOABWb4m1C203w/dXF1HFKhARYpgCruxAUEHtkj
+PoMms2x0fU9M0i3Oka19r2Rg+TdYkil9Qrj5kB7csBxxW9pt9HqemW19ErKlxGsgVuoyM4q1XN+N
+9SvdK8PfabOR4R58aTzJs3RRscFgX+QYJGS3AGTWN4SfW9T0K11W01MveHdFdwX83nI7A8sAmPKO
+c4AGNpGRnmui3+KRj9xo7+v76Vf/AGU1ia942uvC89lBrCaXDNfOyW6LPM28jGc4iJHUDp1NWl8R
+6lfywJaHS4IWjllkuBM1ztCBcrtATBy46np2rwtb7R73x7FBrqya5cRQwJYQ2aeXaRyS4dmkw2eH
+kySOpznpX0XoGiLolj5T3U15dPgzXU5BeQgYGfYAYH9SSaS+tdRgvDf6bMZcgCaymf5JAO6H+Bv0
+PcDrVa2ll1vWYriWzuba0sFJVLmLaXnYYyPUKuRkcEvweKzLmR9P8N6ve2EarLqMxSyggAXORsBU
+cZY4Z66jTTbHTLT7GQbXyU8kjumBj9KtVFc20N5ay21zEksEqFJI3GQykYIIrnLX4eeGLYyk6as5
+kbP79y+0ZJwCe2SffnrVoeDPD6sGGngEDAxK/A/76rlL7SdB8JeM28SapaTwafZ2ISzmAaWGJyWM
+hPJKuQVA4APrmuA8N/ECbxHq3i/WL+V7SymtjBaK/Ece8omN2Mb9qgnn17Cug0Pxd4R1TVrvw/od
+q8mralqrGS4hgAR4Um3bt/8Ad8tOPc/jXtFY8uryppOs32xVFl53lg9/LXqfqQfwqvqDXV1daZp5
+vpLeO7t5TJLb7QzuAvA3A4GGY8c8e1WJ7VE1jR4Aqi2t45DEvXDhQq/kpek0NPsVzqOljPlwTebD
+ntHJlsD2DbwPYCtmiiimTQxXMEkE8aSxSKVdHGVYHggg9RXAN4fl+H/h/U4tHXS30aSR5/st5G+7
+c+F8sEHDAnaoyOMgHNL4D+HGj+Cb/wC0x2zy6reRM8kwGYrcZBMcZ7DnAySSFr0GsiPS7iC/uVV4
+JdLu9zTW8inersPm2noVbuCOMnntUx0W0l0yKwu1N1FEf3bS/fXH3SGGCCBwCOfels9HtrO4WcSX
+M0iIY4zPM0mxTjIGT3wOevAqtek2vijTbgABLqOS1kPqQPMT/wBBk/Otmiiiobu5jsrOe6mOIoI2
+kc+iqMn+VfFvjPx1rHjTWZ7y9uZVtmf9xaBz5cSjoAOhPqe5rNsfE2u6a4ax1nULcr08q5dcfka7
+fR/jv420tVSe6ttRjHa7h+bH+8uD+dd5o/7Sdm+E1rQZoT3ks5A4/wC+Wx/OvQdI+LngjWEUxa7B
+buePLu8wsP8Avrj8jXYWt5a3sQltLmGeM9HicOPzFZOuSxSajo9moMl39rWdUXqiKGDOfRcHGfUg
+VuUUUVS1m2a90PULRPvT20kY+rKR/Wvg5lZHKsCGU4IPY1o6DoV94k1mDSdNWN7yfPlo8gQMQCcZ
+PHQGr/iLwN4k8KGL+2dMktllfy433Kyu3oCpNYlxZ3NqxW4t5YiDgh0I5/Goa0NJi1ea7VNHS9e4
+JAUWgYtk/wC7zX1P8H/CGr+G9Du77xDLK+rak6M6zSGR441B2qzEnnknHbivSKKKKK+KfiRpI0T4
+i65YpH5cQumkjUdAj/OMfg1YWk6ncaNq9pqdo5W4tZlljPupz+VeyfH3XINd0bwffWcm62u4JrhR
+npkR9fccj868VF3cqoUTyhQQwG84B9a+h/gD4c03UvCmoanqen2l7PJfFUe5gWRlCovQkHHLGvbL
+aztrOPy7W3hgT+7EgUfkKmooooor57+O3gW+v/EsWv2clmsD2u2fzrlImVkyc4YjdkYHGTkV5HP4
+atrWyFxP4j0feyqywQyPK/OODtUgEA85Pat74h6K/hzRvC2lHUotQh+ySXUE8SlVKSvkAZ57Z/Hp
+XBV9L/s33wl8IarY7QDb3vmbs9Q6Af8Asle0UUUUVzHjvxtZeA9A/tS8t5rgu/lQxRD7zkEjLdFH
+HX+dfP2rfFv4geM3kttEt57S3c7fK02Fnk+hfBP5YrC/4Vh8QtXEl7caLfu2wuz3TgO2B0wx3E+g
+xUGn/CfxzqTqIvDt3ECfvXAEIH/fRFb/AMXfD9/oGieCrfUjGbqLTntpPLbcAUfIGfo4/KvLa9w/
+Zt1OOHX9a0xzh7i3SZPfYxB/9DH5V9H0UUUVFc2tveQNBdQRTwt96OVAyn6g8Uw2ogsngsFhtm2E
+RkRDYjY4O0YyPbiuavI720m8i+8Q6xPNJHkR6fp6gDtnIRsc+rUukWazanDLJba83l7nWbULzCg/
+9cg/OfdeK4b9ozSWuvBun6mig/Yrva5xyFcY/mF/OvmWun+HviU+EvHGm6sxIt0k8u4HrE3yt+QO
+fwr7XVldA6sGVhkEHIIpaKKKKKa6CRGRs7WBBwcfrVLTdE03SA/2G0jhZ/vuMl2+rHJP4ms/xtoU
+fiXwbqukOUDXEDCIuQAJByh/76Ar5AvPA+v2FxHb3VtbxzSSCJUN7CTuP0fgcdTxVmD4faw99ZWl
+xc6VayXkvlRGXUYW+bGQCEZiM9BkckgV9beC9K1bRPCdjpmtXkN3eWyeX5sQIGwfdGT1IHGeK36K
+KKKKK8l+JMfxVv8AXTZeFYxb6R5YxPBNGruxHO4sQV54GPTOa80l+DPxM1Vi1/Mjljkm51Df/jUF
+98APGlnp73MYsLqRSMW8Ex3tk443ADj61S074KeP5bmN/wCyVtijgh5rmMYx34JNfXC52jd1xzil
+ooqnqMN7PCi2NytvIGyWZdwxg9vris42PiFp2Y6tAkRVQFWAEqwxuPPXOD9M1JHaa7HJbk6jDIqQ
+uJQ0eN7lsqeB0A4/xqv9m8WCUY1DSzEQNwNu4Yc84Oce34VLNF4nSRRb3GmyRggkyo4Y8kkccdMD
+NOlXxIFVo301mDn5drgMpAxnvkHP1FQyf8JaplEY0dweIy3mLj3IqVX8TGGzZotMEuMXShnK5z1Q
+/T1rboor/9k=
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450
+Content-Type: image/jpeg;
+	name="image006.jpg"
+Content-Transfer-Encoding: base64
+Content-ID: <001601c68a59$4f153470$6401a8c0 at madhouse>
+
+/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
+HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
+MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCACWAG8DASIA
+AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
+AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
+ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm
+p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA
+AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx
+BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK
+U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3
+uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0fxL4
+w1Jdefw14YtIZ9UjiWW6uLpiIbRG+6TjlmPYCs7y/HOn25uoPEsOqXSfO1ncWaRRS+qqy8r7Vv65
+4Ig1TV21iy1K90rU3iEMs1owxKgOQHUjBx61zLjV9B8faZolzrE2pWl9ZzTP50YBjZMYII+tc1f2
+q96L0RvS5H7slqRQ2njfWEGrXviOTR74ktBpkESvBCP4VkPV/f604WHjPxC3na/r0mjLEdsVpo7Y
+3Ef8tHc8kE8ha6qiuJ4mo76nYsNA5HyfH2q3H9l6jrf9n6daZK6lYqqz3393I/gwOvqaSeT4gwk6
+QdbtIdJQF21+VF88R4xsKk4D5/irr6x/Ftv9q8Ga3BsD7rOT5ScZwM/0prE1G9yZYeCjdHI60q+D
+dI/4SDTPGuoXV9GymOG6vBPHenOGTYPXPUdK9rt5GltopHTY7oGZT/CSOlcP4F8G+FBoGi65a6HZ
+rdy2kUol2EkMUGSAScHmu8r0acHFWbucM5JvRWCiiitCAooooAKKKKACuA8UFI/ij4bYKd81heRk
+57AxkV39cF4nP/Fz/DispI+wXhU9QGzH/Ssq/wDDZpS+NGpRRRXjHrhUF9F9o028gxnzIJE6eqmp
+6cnDr9aEKSuin8KLs3fwy0QsctDD5DexQlcfpXZ1wHwrk8qw17TCNpstXuBt9A7bx/Ou/r3Yu6ue
+M1Z2CiiimIKKKKACiiigArz/AMVsV+KPhbBI3Wd4D7jCV6BXA+IQ0vxT0Rd2PJ026dVA5clkB/AY
+rKv/AA2aUvjRq9qKdsf+435UeW/9xvyrxj1robSgE9AT9KXy3/uN+Vcoun6j428U6rpp1K80vR9H
+ZIi1k4WS4nKhiSxBwFBHHvWlKk6krIzq1VBXLHhK4OnfFbxNpkjKkV9BBfQgnGWxsbHqeK9Krw+0
+8N6PN4p8TaR4q1ppdctxCdO1a5nEUkcZTKFACBuVuvrXo3w88RT+JvCFvd3bxvewu9tctEcqzodp
+Yex6/jXr004xUWeXN3baOqoooqyQooooAKKKKACvE/iZcWmo+Omaa9u7Sy0OwH2x7OTbLcNMw2QJ
+ju2Oa9srwfxzpC2fjTXLe9vYbH+12tr/AE65um2wSSQH5oXPbqPzFZ1L8pUNy5b+Cry+bT7q11fx
+BpWmzRsbnTprsmWBsfLgnnGc5Faw+HtgE2/234hzj739ov19etLYeN4prixsr5rGfVb+fYlvpNx9
+oWJMcvI3YCusry51KkXqehTp05I5L/hX2n551nxB/wCDF/8AGn+AdQ0jwbf+IfD+paiLVlvftVtJ
+fy4aeFkX5gzfewVIrqqp6jpGm6uiJqWn214sZygnjD7fpmqpYiUJXlqFTDqS905LTrDSfGvjTxJ4
+iuLK31DSn8qzsZJogySbF+dkJ7Z4yKuXHgW308tf+EZZdF1WM+ZGsUjGCYgfckjJxg9Mjmupijgt
+LdIYlht4IxhEGEVR6AVnar4q0PQLd7m/1S1TylLiIShncjsFHJJodacp80Q9lCMLSN/wX4k/4Svw
+va6q0H2edt0c8Oc+XIpKsPzFb9cP8J9MutO8DRSXsTwzXtxLeeS+QYw7ZAwenGD+NdxXqrY85hRX
+A6l8U7Ox1a+t4NF1O+sdOl8q9v7aMNHA38XHVtvfHSu3s7y21CzhvLOdJ7aZA8cqHIZT0IoTTCxP
+RRRTEFec+NbK2vPiP4bgu7WG4t5rK8SRJl3KfuEcHvXo1eeeNW2fEfwaSrEMLpcjnBKr1/Ks638N
+l0/iRZ0zQdG0Ys2l6VaWbMMM0MYBI9M9a0aKK8VtvVnrpJaIKKKKBmRrnhfR/Ept/wC1rVpxbkmM
+CQr16g46isH4deD/AA3beK/EtpNpNrLe6ferNayS5cxwyLlAAfTBGa7WuahddF+MGnXIQiPXLB7V
+2zx5sRDLn/gIIrrwk3z8rOTFQXLzI9Oooor0zzzzPwmRpXibxT4ZlYExXhvogf44Z/mP1weDVr4b
+N/ZOp+JPCgBWHTrsXFoC2dsEwyFHsCG/Oo9XVbT42afJGuWvdGkSX/gEgIP64qzptobP4tz3ZYAa
+hpQUD1MTjP8A6EK44+5iGu5u9adzvaKKK7DAK8s1/R9U8T/FK6htdbk0240ewim08rGroWlLB96n
+7wO0CvU68t+JVoYfGPhi60zULrS9V1Cf7DJeQjKmHlsMDwSGxge5pNXWo0Tyr8QtIANzo2l63EFy
+z2ExhlJ/3X4P0FUx8QrK2BXWdF1zSZVPKzWTSKfcMoxW4tl8StMlYxarouswDol1A1vIR9UyM02X
+4hXenMsfiLwdrFmp4M0EYuovzQkgfhXPLDU30sbRr1F1KVr498JXjlIvEFkrg42yv5Z/WtqC9s7p
+d1ve2swzjMcyt/Wq0XiX4e+J4ja3Mumkt1gv4RC5P0cA/lRcfCfwHqUayR6Lbxr1D2rlAf8Avk1k
+8FHozRYuS3RpBGPQZrjfiL5un6fo2vowT+yNTimkJ7xsdjfzrXHwa8Mx48i61mAAYAi1Fxivnz4h
+2TQeK9QttHbU59O0+XyGkuZ2mPmL945PbNEMK4SUrjlXdSLikfXNjqun6nYi+sb2C4tSCfOikDLx
+15rz+88dar4jN0fC0lpYaRauVl1q+Xcku373lL3A5+Y8V5N4P8R3fiJp9N0+GKx1K90+a1vHVvLi
+vnwPKAHRZsBxnjNdFq+qWt34asLP+y9St/D2lRRf2lbyQmFppc7Y7YE4zl+WYdq0xEqvuwpLfd9k
+c8FHVsk03xTrOpfEO2ktDF4lltNOkj+0RR/ZQVdgwLbvlI4ABXrWfr/xGvtd8R+H30exvNOkgllR
+rryvPfcBiRVRfvAYz74rpdPGq23xQa41t7UXMmiPI0FmmyOGNXBVAT97A7muMsNFQeCNP1DTrLS3
+1S5We5jeW4MF6WVyQ8LdDtwOO9c8Zp1mnrZKz663+XTsa2fLY9f0nx6bbS4L3WLqzvNNldYk1OxD
+bVJ4zKv8PPUjgV3oIYAg5B6EV4nHbzroNt4rtdOk1LS9fsfL1uxsYtx+0Yx5yIPU5DAfWvQPhpDq
+9v8AD/SoNbjeO8ji2hJD84jB+Td77cV1UXVTcamttn3/AOCjGXLujra8++KZjQeFpHOAutwjPpkN
+XoNed/GaPb4OtL7vZanbT/hvx/Wt2Sj0SikVg6K6nKsMg0tMRnanoWkavC8ep6daXKMMHzogT+fU
+VzA+FXhy2kM2kvqOky4+V7K8dQv0DZH6V2V3axXtnNazqWhmQxuASCQRg8jkVxJ8Caxoq58JeKLu
+0jBBFlqH+kwfQE/OPwNJjA+DvF9pMZNO8fXTqPux39okw/Ejaa8j8YaL4g+H6T6nrRtL+LUrt3El
+sSm2VuSCpH3TgmvW08R+PNJQnWvCUGoID/rtIuMnH/XN+f1qlrWqaN8TvD2peGo0ubHW0i8+Gz1C
+DypQ68qQDwRng47GplFSVmbUK9ShPnpuzPHvhdeaf4j1LV/DepeXZy6qUubG4i+QwXUeShQ+vJOO
++D616hd+N7ef4eatpHiy0Fzrtq/9nT2KHDXMrcRuns3DZHT8q8qigsJ7FpZ4ItPvYmKSOAI5IJlP
+OD2IIzXaeBoL/wAZeKF8W62trONNh+x211FHtN1IM/vCPUA9fWsnWUYt9jqxGClBxlzKSlr/AEjQ
+1Xwtr/8AZFnf3eu21vdx6W1lrNzKuSIM7mKH+8ANue9cf4r8XaA2gWdvZ2TyaZFALeDTb63MMgGD
+tuYZRz16jvmu++ITvqZ0nwpbuBLqVwJbsE4C2sZy5J7cjHvXFeO7uy8UeJm06z8qaw0uya3VkGVW
+VsYC/QLXDTqe+k1vdvyXT8dgjQdSfs4bnNeG/G2taraW/h2TUZbPTraDbHb2f7oSAHJ3kcnPJ4I7
+17X8FbqQ+HdT06WeaVrK+ZVErbtqMNygE8kY9a+VrS5l07UI504khfPPt1FfS/wUvY7i98QCI7km
+NvOGHIHyYxn1r0tVPyMr05YS1veUvvTX6WPX64n4t25uPhfreOsUSzD/AICwP9Kn/wCFn+Ev+ghc
+f+AFx/8AEVS1f4geD9T0a+sJL6dkuIHiINhPzlSP7lVzx7nJZnWaDc/bfD2m3QXb51rFJjGMZUGt
+CvMPBHxA0HS/BelWGp3t0l3bQiJ1axnyApIHRPQCug/4Wf4S/wCghcf+AFx/8RQpx7hys6+ivLov
+ixb2XiWeK9mN3oUx3Q3kNlNGbMZA2zblA25/iH4ivTopUmiSWJ1eN1DK6nIYHoQaaaewNWH15b8Q
+L29HxK8Kro+nR6hf6fFPeSwmQRnymAT7x6dSQD3FepV4dp3jDQX+JnibV9SvhaiRksLKSRG8p0j4
+Yh8YHzAd6irJxi2tyqaTlZnOePPDtv4112G7sNC1rS9durhI7uGe3zAU6GUyD5eAB0PNevaPpNno
+Oj22l2eEtbWPaGPfuzH6nJqW11Oxvow1nqNrcIehinVh+hrlvH/iJrGxXw/preZreqjyIkTkwxn7
+0jY5GB0rzp1J1mo2O2MIUk5XPFPiDr8Gu65f6tFKx86X7PZ4bGIE4LH/AHjWZ4O1aHTp7pLmYRwu
+gYAgklge2O/New3fgr4UX+lQW0dzeW91DB5f2mG2nBdsffZSmCc89q6rwz/wrbwrbRR6fEPPRArX
+MlhM0jnuSSn8q7/c5eW5jSxE6VVVYLVHlPhr4O6j4x1t9Smin03Q5JN++ddssoPJ2KeQCc8mvo/w
+/wCHdL8L6VHpukWiW9unYcsx9WPUn3rO/wCE+8N9r2X/AMBJv/iKZ/wsPwx5oj+3y7j0H2Ob/wCI
+q1KO1zGblOTk1uRebJ/fb86PNk/vt+dNor409myH+bJ/fb86TzZP77fnTaKAshJlFzC8M4EsUilX
+R+VYHqCK5ywfVPAEzHT4ZtS8MM2XsVJaex9TFn76f7PUdq6SiujDYqeHleO3Yzq0Y1FZkfiXxvp8
+fgmTUdFvobm4vMWtgIzktO/yqCOowTk59Ky9B8O2uieG7PRnSO5SBcyGVAweQ8s2D6mnjw1oo1ka
+uNOhF8MkSAYGf723pu9+tatdOMx7rpKGi/UyoYbkbctTDu/B3h29cvNpFuGJzmEGHn/gBFSaZ4V0
+PRr43thp6RXZXYZi7O+PTLEmtiiuN16rVnJ/eb+zhvYdvb+8350b3/vN+dNorEuyF3t/eb86fHI4
+cYdvzqOnR/6wVUPiQmlYXym9qPKb2oorTlQrh5Te1HlN7UUUcqC4eU3tR5Te1FFHKguHlN7UeU3t
+RRRyoLh5Te1HlN7UUUcqC4eU3tR5Te1FFHKguHlN7UqxsGB4oopqKuFz/9k=
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450
+Content-Type: image/jpeg;
+	name="image007.jpg"
+Content-Transfer-Encoding: base64
+Content-ID: <001701c68a59$4f153470$6401a8c0 at madhouse>
+
+/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
+HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCACGANgBAREA/8QAHwAAAQUBAQEB
+AQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1Fh
+ByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZ
+WmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG
+x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APfaKKzNZ8Q6P4etxcav
+qMFnESADK2M59utTx6tpstqLmPULVoDj94JV289Oc1Il/ZywGeO7gaEcGQSAqPxzU0ciTIHidXQ9
+GU5B/GnUUUUUUUUUUUUUUUUUUUUUUVyHizwd/bWrWGs2kOny39ojRFNQQvDJG2eCB0IJzms7wh4Y
+8O6/o1pr9x4fsoJ7uLEtrGM25KkgMI/u568kZ5p998KdEvtVmLb4dGnAkl0y2YxRPMBgOduOwHHr
+UNt8OtT0nULm10DxHPpXh6aAKLVP30iSdypfO0EHtSrpvjzRreWzt/EGmy2UDq8N3qanznjVQWVt
+vGM55611HhHWpvEXhXT9WuIEhluY9zIhJXOcZGe1bVFFFFFFMlmigj8yWRI0yBuZsDJOAPzp9VJ9
+U0+2mMM99bRSjGUeUAjPTioF8RaK6B01axZDnDCdcH9avxyxzRJLHIjxuAVdTkEHuDT6KKKKKKKK
+ZK6xwvI5AVVJJJxgVzPw4x/wr3RivQwk/wDjzV1NFeXeK9JttZ+NWgWWp27XGnzaZN+6ZmCF1LHn
+HXivTbe3htLeO3t41ihjUKiKMBQOwqSiiiiuN8ba/qVvd6f4b0EBNY1XdsuHGUtol+/IfUjoB6ms
+mX4O6bqJW41nX9dvb4qBJOLrYGPsoHFOtvgp4WgnEkk+rXKgH91PdlkORjOAByOo9wK20+G3hJY0
+X+yFbaANzTSZP1+akb4ZeC3bc/h+2ZvVmcn+dNHwt8EAYHhyzA9Bu/xqUfDfwgqhV0SIAdAJHAH/
+AI9R/wAK58I/9AaP/v7J/wDFUf8ACuPCOc/2NH/39k/+KqC5+F/hK4t5Ihpzwl12+ZFO4ZfcHPWq
+lp8MLfSLS4h0TxJr9i0oJXF0HVWxwSCvP0zV3wR4lvdUfUdF1mNV1nSJFiuZIwfLmUj5ZFz64OR7
+V11FFFYHjhivgPX2HUWE2P8Avg1H4B0+fS/AOh2VzH5c8Nogdc5wevX8a6OiuX13/ke/CPpuvP8A
+0TXUUUUUUVxFkL+9+MepzPsOn6dpscCdMh5SHP8A6DXb0UUVl+JNYXw/4b1HVnjeQWkDSbExk46Y
+zXnqWnxPk8L22tQeJoGmazNzLZTWC7i2NwRcDOccfWtXwLqXijVNUMt9LfvpogHm/b7RLdhMeyAA
+Egepr0GiiuHuLO4s/jPZXq3R+z6hpUkTwDpuiYEE/wDfZruKKKK4j4sa3Do3w71bc0Zlnh8hYzIF
+YhztyB1OM106XkGneHkvLlwkEFqsjsT0AXNcjD428QtpcGvz+HIbfQZWV2kku/30cBb/AFzIFxjb
+82M9KRviBqv9mtryeHg/hwTYW7FxmVoc487y9v3fxzUnirV7OHxR4H1ASb7W4mmEcqkAEPENrZOO
+Oc13KOkiB42V0YZDKcginUUUUVxPhDUBqPjrxs4Tb5Fxb2/3s52IwzSeOH1i58QeF9H0vUZ7GK9n
+la7kgYK5iRVJAJBweavHwU54PivxJ/4GL/8AEVz3hL4k6BZ+HobXXvEsTajFNLC/nZMnyyMAGwOT
+jFbafFLwO7qi+I7TccYyGHXp2rnrjVvFXxF8G6jBp+gWVvY3nmW8NzPfEF1DY8xVCHjj1rovAfiO
+bWbO+067tHtr3R5hZzhpfM3kDhg2BnOM9KteNdW1XS9JtF0QW51C8vYrSJrgEopfPJx9KoaBqnia
+18VyaJ4mmsJlmt2ntJrWIx7tr7dpyT82OcViTeIvG2t+L/EOk+HpdMt10mWJFS7gZjIrgktuB7Y4
+GK6HwB4lvPEGnahDqZjbUtNvZLS4eGPZGxVjgrye1P1T/kpfh3P/AD5XmPzirqqKKiup1tbSa4cE
+pFG0jAegGa8W0PSY/H+uakuvWrvNqNgbhZrpDvtIWciFYP4cbdrE+pIrovGnhvWLXwTe/aPE95fW
+kSxeZayWkIV0DrkEqucY5P0rZ8farpdj8O7uCKVNt/aG1sIYBuMzOuEVFHUcjp0FZ994g0rTfg4t
+xoTwPE9qtnaQu23dI3ybMHncMk49qztU+Hkr+EbObxDqT6oNHsvMh0+4EcMCyCMDDOoBKjHc1ofC
+q6UWt9p1qSdLRILyxR3LNFHMGPl5PZSvH1r0SiiijvXDfDvTmttQ8XX5ZSLzWpgAByNhI5/OtLxR
+Y6qNY0XWtKs0vn08zJJamQRs6yADKseARjvTf+Eh8TZ/5Em5/wDBhB/jWd4D8GHTdFL6/penm/a6
+lnj/AHKO8KsxIDOB8zcnn3rpW8M6C4YNounkMgjYG2TlR0HToPSuNi8H+ONItRpfh/xJp1ppUUzv
+B5lrulWNjnYeNvBLY+tdT4d8OTaJc6jd3WqTajd37o0sskSR42LtAAUAdKd4s8NxeKNENi9zcWsk
+cizwz2zbZEkXOCD+NcF8OPCt/qE1p4j1nXtTuLvT7q5hWzndWjUgtHk++O9bXjvTb3R4NW8W6Trc
+1hcraxpLEsMbo4RjgncMj75rX8FeFbfw1b39xBqc+oHVJ/tkk0oUAsw5I28YPWqniC8hs/iZ4TEz
+lTPBdwpgE5Y+WQP0NdnRRTJYknhkhlXdHIpVlPcEYNeMazZ+JPB/ifw/D9psJLCXUIrOzugCLsWx
+cMYPTaBkZ9BXtEio0bLIFKEEMG6Y96828KadZar4sOs6P4bsrPSLSaaJL2UlpZ3GVLRrnCruyM98
+Vfh0jQovidNbT+HoEuHhF/Z3YQ4Zx8spPONw3Ljjua1PH9zND4aW3h+z/wCnXUNlJ9pi8xNkrBWy
+uRng+tO8I+E28M/apJruOeWdY4wsMPlRxRxghVVcn+8e9dNRRRSEhVLHoBk1x3w2vYdS0TU723DC
+GfV7t03DBwX712VFFFYOv+LtN8P3FtaTLPdX9ywWGztU3yvnvjgAe5NM8PeMtL8R3M9nAtzbahb7
+vNs7uIpKgDbSfQjPcGuhrm7jwB4Vubma5m0WBppnaSRgzDcxOSeD1JrmPBPgTwzq3guwub/SIria
+XzN7SO53YkYDPPPAH5V6La2sFjaQ2ltEsUEKCOONeiqBgAV5746fZ8UPAHvPcD/x1a9Iooorh/G+
+mJq3izwVA7sojv5bjK46pHuA5+ldlewtc2NxAjBWliZAT0BIIryzwr4os/hn4bj8O+KoLuymtJpE
+juVgaSG5BJfcjAeh5B5Fbejat/wmHjqz1vTbK8TR7OwkjF5PGY1naRlICKeSAEOT06U/4uXz6Z4K
+jvokV5LfULWRVboSJBwa7iFzJBG5GCygkfUU+iiio5+LeX/cP8q88+B+T8N43Y5Z7ydj+L16PRRW
+ZqviPRdDkij1XVLWzeXmNZ5QpYevPauJv9Vj8K+Or3xNqMVxeaJf2CCHULeLzVtQhJKnaMhTuBzS
+W8uo+OPGK6xodxqGkaXb6f5AvntlBui7BwFSQfdGPvYrYuPD/imCOSYeN7opGjMQbKDJwM/3awfA
++sePvEvhe01aLUdElSUtn7RbyK+Q2CDtwPxFdP4B8Naj4V0CXT9Svo7uRrqSZDFu2xq2DtGe2c/n
+XU15r8QMr8TPh6+AV+1zKfxVa9Kooorh9d1B5Pi14V0tYCVit7m6aUdgUKAEf1ruKZLDFOAJYkkA
+6B1B/nTlVUQIihVAwABgCvPPjeAfhhe5GcTQkf8AfYrvrP8A48bf/rkv8hU1FFFQ3TBLOdmOAI2J
+P4Vz3w6RY/h5oQQAA2iscDua6euB8cfEGHRZJdKsAZLoRn7Vcg/LZqRgHp80mSMIOp64p3w00jVr
+SyuNT1G4v1W/Cutrezea4YdZTwNpYY+TnGOtZ/xe0SwuLKx1a5W7dknitpUiXfG0JlVn8wAZxx1F
+Jq3iXwJeeCtQ8MaZq0VrEbZ4Uijt5G8rPI4xxz6113gZnfwHoLSElzYxbieudorS1e7tbHR7y5vZ
+hDaxwsZJD/CMda8/+D98LDQY/Dt1BNayLvubH7SAj3NszZD7cnBGQCK9NorhfHdmJPFHgq82yZh1
+UJkKNo3KepzweOK7qiiivMtQ1XxHcfEy6vfDOi2+o22nwR6feNLcqhJLeadnPUBsc960r3x9rOm3
+ccN54F1gIxG6W2dJwoPf5M1HffGXwdpl01rf3F9a3C4LRTWUisM9OCKfp/xe8KatI0emvqN469Vg
+sJXI/IVkfETXLbxT4Jv9Ls9N1v7S214w2lzAFlOcZxxXoWg6hbatoFhf2jFreaBWQspU4x3B6Vo0
+UUVieMZL+LwZrD6WjvfC0k8hUXcxfHGB3rnNF8T6Z4Q8HaHpOpys2rpaRodPgUyTltucbF5HTrXO
+aob8Wi+KfGUGsG2unKraafO8S6XCudrOqkFmOck9q5vw1pi2Or+GgdJ1ebWJL972eC6Lsr27Bgsz
+k/JvG5ckc5r3bW/s40S9+1Xhsrfym8y5VtpiH97PauF8H+M/EGoaQyWvhu/1S3t3KQahNKlv9pi/
+gfD4ySOuOKxfDmqa1pnj7xhcHwjfS3l00M0kAuYgEj24Ugn7+SG6VU134k+J454jFp0vhiyjj3Wq
+XlqX+2SLz5JIGEyAcYwa3/GuoyatfaJp2qafq66IbcX2oGytnkSR8ArESoyADuJ/CqnijxLZeILP
+T9c8N2Wq/wBqac3nWM39kyNHOpGDGWx91gT+NepWE01zp9tPcQGCeSNWkiJ+4xHIqxXL+M/9d4Z/
+7DcH/oL11FFFcb4q8UXg1BPDHhlFn164XdJI3MdlF/z0f39B3qhD8L9P0mwkuLLXdTsNTMDfaNRj
+n2+c5JYySKeDz2444qpZ+N/EVjobX9xZLrunSRyG31LTVG4EYCCSLPHOckE1x/hX4caNraay/jqQ
+w63LdCVz5wi2B1D4TPUfNg+nTtWXofgvUfBnxAuj4Z8Qw3S2dgbyUhMq6hhmJ8EgZXJBz1HavTY/
+iPc+KHS08FaW17I8O+S8u8xW8GV4GcEsQeCB6dadpHg/xd4e0yS10nxDpqI8jz+Q2nnYjtyVU7+F
+zVUW/wAYsc33hoH/AK5PWfqPiT4j+EGsr/xHJoU+nSXcdvJHbBlch+M5PTHX8K9HuvEuh2VrJc3G
+r2KQxKWdvPU4H0BzXP3PxM0WSKNdCS61u8nyIYLSFgCcE5LMAAvHWo10rxp4iXdquqRaHZu6t9k0
+8b5tmOVMxxg5z0BqxFZ+DvhvYo7CK2klwolkBluLhlB+pJxnpXA3Nt4o+IGrJfS6VJLpiSubO01G
+HyreSBlAJZwxYPkcDbXfeC/BH/COwWV3e315danFYi0cSXHmRRrkEqgwCBkCuudFkQo6qykYKsMg
+0qqqKFVQqgYAAwBXlOi61rLfEP7RKpkvrtvsd7p32UobWFGYpKJckMMNn3z7V6pJFHMAJY0cA5G5
+QcGor6F7jTrmCJtryRMikdiRgVxngnXp7C30nwlqmi6hZ6hDa7BK0YMEgjGNwcHvjoRSR/FTS5PF
+F1oS2F9NNDeLaCe3VXiLMPly2eM4b8q7yuV8aMoufDClgGOtwkDPJ+V66qiuc8beKk8JeHpL1Ihc
+3sjCGztQfmmlbgADqeuTjtUPgnwu+g2dzfX85udZ1NxPfTldoLY4UDsB0rkfjl42TQfC76Jay/8A
+Ex1JdhC4OyI8NkH1GRXGfCqDxh4H0+XWdShe28MmVVuoLkEOin/lsi9RglR7g+1bPxP8MQ+O/ibo
+Wmw3qxLdaTJJBOmGUkFmUn1U+1avwc8JXfg/VPFWhaiYpmU27Bk5WRGD4OPfng16va2tvZWyW9pB
+FBAnCxxIFVfoBUtFcN8V9Mi1HwfG8xO22vreXZgFX/eKpDZ7Yat4eEPC4YkaBpOSc/8AHrH/AIVU
+1Dxt4T8OwPbvqdnGbciMWdsQ0gOcBRGvPfpiuc1Pxl4n1DR7690/SToOm2ySGXUdUQmRQBwyQjk/
+iMVueFvCulwvF4ha9n1jULhTJHf3TZIV+cIv3UH0ArraKKKKKKK8Q8a/DnxMutf2noVtZTRb42H2
+Z2t3QoSQzKpAZjvPIGQF9zXrHhmz1jT9Chttd1GPUL9C2+4jj2BhngY9hXI/ECUDx54Bh4y2oO3v
+wv8A9evRaCQASSABySe1ee+H7ceMvHF14ruAxsNMdrLS0Kja5HEkucnPzZArf8c69L4e8LzXVpLG
+l/K6QWgeMuGlZhxtHXjJ/CuS8eaPBZ+J/B/iPUbOO/eG4SzvJXwsS7uFkKnphzkVb8efE3w9pekX
+umWl1DqOrTD7NHZxHcNz8Ak9MDNeR+LtXf4a+I/DcGhTLJqGl6X5Vwt0DIY5JCWYHp2bjHQGvSfh
+x4xuvEq+KfFs+mG3RbeFVRX3CQxI5ODj3H0rR0S48f3NzPr4tLCez1KCKW1spNRYLbqUB4Hl9T1N
+Q+D/ABN4t0y8stH8YaLcL9sneOHUfODgyEFghHYYU8+1dtrfiSw0CfTILzzDJqN0trAqDOXPr7Vi
+/FR0j+G+rPIgkRfKLITgMBKmR+NPs/APhG7sre5/sG2Xzo1kxuY4yM+ta2k+FNB0MSf2ZpNrbeaw
+ZyqZLEdDk1f1Gxg1PTbmxuY1khuI2jdG6EEVxXgTXotJsk8Ia2E0/VNKiEaiV8JcwjhZI2PUdMjq
+K74EMAQcg8giiiuI8X+OL7QPFGk6Bp+mW93c6lFI8bT3PlAFf4ehyTjj3xVe88ZeKLEwpNoujiSY
+DYg1JskngL/q8ZyCOuBjmq0XxI122+0z6v4OuItPti/nXVtOrhdv3uG2k4PH8s11nhTxTY+L9FXU
+rFZI13mOSKVdrxsOcEfQg/jW5RRXn/iyyOpfFLwYkTRF7MXF1IrNyFAQA4+p/SvQK5L4lavc6N4G
+vp7USiWXbAZY03eSrHDOc9gM/nUeh+JPBGg6JaaVZeItLWC1jEa/v0BbA5Y47nqazLnXdN8X/EbQ
+9N0vVRc2umxyahP9mw8ZkGFjBf6M/AruNV0qx1vTJ9O1G2S4tJ12vG46/wCB968B8S/s8ajaSm58
+L6gLhQQUguGCSA55IbgYHHvVab4M+LtctrWK/wBPt7a/V83OpzXxmecHgZXJxtGOnpXf3OgW3gT4
+Q3PhddRL6ndxOYlhz5k8rYyI1HJFXdJ1Dx7p3hi0n/4R+xW0sreFPsTSFrqWNY13EEHaG64UjNZf
+xD8S2mueDPDOt6VcMofWbfbtOGRuQyNjoQCciug+J9jD9n0LXZjKF0fU4p38tdwEZYBmI9ABmsy/
+8EeNvE0c9nrXjC2OjXWC8FpaAMVyGXBI9hXpFnbizsbe1DlxDGsYZurYGMmpqKydd8M6N4ltDbax
+p8F0hGAzr86jOflbqOnaufvvhjpNxYG3stR1nT34CywajKSoHYBmIpumeAtV0iForXxxrRVsZ89Y
+pTx7spNO1Dwx4yKx/wBm+OZ1OTv+02cJ47Y2qK4XxjoOpMt1B4i1JdQ1C20Wa5hvIYRGyFZ0ZdvH
+B4wSKzoLPx7JpH20eIrFbW3RNyyaep8qF1BY8r1zjcvU8HvU2v6brh1nw5beItbi1W3vdRVLk2du
+xEhQ5CP/AAgAjBUAZ6npmuv8L22qJF4isNBvLe0v7bXjK8V4fNBhKL8pxyAexHTGK6PZ49/57+G/
++/U//wAVRs8e/wDPbw3/AN+p/wD4qs+80f4iX97bt/wkml6dbKcSrZ2pZnGeSPMzg1r+H/CNtod/
+e6nPdz6jqt4R5l7c43hB0RQAAqjngDvXRUjIrqUdQynggjINeeeBItNh1rxBp2oW5TXHv5J3iukX
+54iSI2i/2dmBx3rQu/CuoaJrD6t4Pj0+J7kot7Z3CbElVd2CrgEqeeeDn8KdH4s8R2k88Oq+Db1v
+LPyzadKs0bLjOfmKnP4VGPihostnBJa2Wq3N3LnNlHaMJo8Ak7s4XjHrWVffEw61fWmk+FyltczI
+s097qcflR26dxtbBd+2BxnvWpb6VoXgkPr+t6rLf6pJCE+2XTb5HA52xIOgPHAz2qGH4jXaXkVxq
+Phm+sNDuZI4re/nZQdz4ALpn5VyetZ2s2dh4U8YQz6pF5/hjVLj7R+9iDR2V9/C4OflDDPbrivQd
+U0+31rRrvT7jL293C0b7GxlWHY1znwzubmXwVBZ3kTRXWmyvYyhm3EmM4zn8q7CiiiiiivLPiqsu
+k3g8RzaYb3Tk0u4sXkjPz2rycLJjuCSFPpmofD2pNqfhrSJ7/XxHaz2scc0ME0cT5BIyyknaoAG4
+8lgRwMVg+OP7KXToTpt1FZDSdYgmMrSrKQmdoJUH7gByAM5A5xXZ/DuzmvPEXiLxWltJBYasYhAZ
+jh5ygIMu3+FWzwPavRKKKKKK898ZaRH4p8d6Po4ilha2tJrqa/t5vLliRgUQKRz97Bx0qxbaH8Qd
+O1F2g8UWF/YqNsUV/akPjjBZkxk1QvvHHi7wtDc3XijQdM+xoD5MtrfqjSkeiuckkdutbvhjx5D4
+iuo7K40nUtKvpImmSG8hKh0UgEhsYP3h+dZnxG1HSSg06TTbbUdUEH2oW8sILSWyt+9CORw2AcY5
+rJ+F+kWWoapqWvLp92+nrIBo0+oO7skZHzbAxO0ZAweteh6nYaX4j0+90m9SG6hI8ueInJQkZH0P
+IIrjfD8Z1XTNV+HnikxTXdpCFEiyZNzbt9yQA85GBn3xV34e61NtvfCepM7arobCJnbB82A/6p8j
+jO3AI9RR4WSDTPiF4t0xbws1w0N+kEj8guG3lR6Z2129FFFFFFRXVrb3ttJbXUMc0Egw8cigqw9x
+Xj3xp8KaRYeG9N1DT9LsLZoL+NG8uAKXDHocdRx3rmdHsvCcGp+KIdS0OHULz+3Vg0+xiIjdsk8D
+sFHU9uK9t8H+JrPxTof2uzge38iVraW3bB8p04K5HBHTkVv0UUUUVxHhiGC7+I3i7VMymeJobNQz
+fKqCNWOB/vZNanjPxLJ4Z0iKe3t1nurmZbeAO2EDtnBY9ccdhWNa+GodDtJPFfii6m1rVra2aR2O
+DHCOWKwoeB1xk1gNbeK/Fcem+MYL6wgVfNii047lQ28i4IeQAknIU424460/wp8NNUFlBaa9rRMF
+gHFl/ZrtHIvmZMm52GSOSAPSuo8S2d34b8IWK+HblbRNNmi/dyDcJYs7Sh/76z9RUd9bS6H8RLLV
+LaVVs9YT7PeW+3lpVHySA/TAPsKq/Eq3uNJhtPGOmz+Re6WwSYdVnt3YB0I7nOCMkdKg8T6gukaz
+4e8a2ayeRd7LK8ty+0yRyHKHAGCylietXtbtJrP4l+HdYtFt1S7iksrosD5jqRvXH02/rXb0UUUU
+UUV5r8chnwBD/wBhG3/ma4rxTJBafGu20+GziTzL+1vDMpw2fL2lce5Oc16L8M7WOxTxNaRMzLHr
+Ux3FQM5VT0ruqKKKK//Z
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450
+Content-Type: image/jpeg;
+	name="image008 1.jpg"
+Content-Transfer-Encoding: base64
+Content-ID: <001801c68a59$4f153470$6401a8c0 at madhouse>
+
+/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
+HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
+MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABvAMADASIA
+AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
+AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
+ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm
+p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA
+AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx
+BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK
+U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3
+uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iii
+gAooooAKKKKACiiigAooooAKKKKACiiigAqC9vbfTrGe9u5VhtreNpZZG6KoGSanriviEPt7eHtA
+k/49NV1NI7of34o1aUp/wIoB9M0AZFzrHirU/Dt54sk1aPw5pMMLT2dq1skskyAZVpi3TdxhV55H
+OazrjWfiPc2unX+tvbeHdGuHSK4eyjEtzDv4V335CqWIB7rnmun8RxjXvHOj+GJedNgt21S7iHSU
+o6rCjf7O7LY77RR8Vb21g8FPZXVwkA1G6t7NXdgoXdKpY5PTChjn2oAlHw/LDM3i7xVI/dhqWwfk
+qgU2TwdrtkRJo3jbVFcf8s9SRLuNh6HhWH13V1NzqFpZaZLqE9xGlnDEZXmLZUIBknP0qPRtRbVt
+HtdQa1ltftMYkWGUjeqn7ucdCRg47ZxQBzR8U634cbHi7TYRY/8AQW0zc8Kf9dYz88Y/2vmHuK6+
+3uILu3juLaaOaCRQySRsGVge4I6iqZ1fTn1ttCadTf8A2b7SYCp5iLbc5xg88Yrjry1Pw21A6rp6
+H/hFrqUf2hZr0sXY48+MdkyfmUdOooA9BopFYMoZSCpGQR0NLQAUUUUAFFFFABRRRQAUUUUAFFFF
+ABRRRQAUUUUAFecfFvVtIt7LRdM1C/js5LnUoX+0B8S2saEs0qEcqeNoP+1Xo54HrXwv4o1K/wBW
+8T6leam8rXb3DhxJ1TBI2+wHTHtQB9M6Hp81tfy+KvCOtHxYbiMWt3HfXih8KcrscLhSMn5SMHOf
+ruWHh3Udd19Ne8V21rGLeJorHS0fzkh3cO7sQAzkccDAHrmvG/2cLm6Txfqlqm82sllvkA+6GDrt
+J9+W/WvpWSRIYnlkYJGilmZjgADqTQB5T4p8H6PL400PQdHSez+2ubrU7W3mZbZrSM5IaLO0bn2q
+MAd69YAAAAGAO1cT4Bt5NUl1Lxjdg+brEn+hhusVmnEQ9t3Ln/eFdtQBxeuK1r8VfCt2NoS6tbyz
+Y9ydqyKPp8h/ya6+4t4bu1ltriNZYJkMciMMhlIwQfwrkfF7f8Vn4HQAknUJzx6C3f8Axrs6AOP8
+BXE1lDqPha8laS50OYQxO5y0lqw3Qsf+A/L9UrsK4zUQum/FnRLpOP7WsLizlHYmIrKh+uC4rs6A
+CiiigAooooAKKKKACiiigAooooAKKKZNNFbwvNNIkcSDLO7AKo9ST0oAfRXE3Pxc8E28piTWPtLg
+4P2S3kmA/FVIqKP4weDWkKy3t3AufvzWMyr+e3+dK62K5ZNXsd3Xh3hj4XeG/H+mahr2qrdpeXWq
+Xbebbzbcr5pAGCCPXtXpMfj3wxqdhdNpviHT5ZUhdgomAYYBOdpwaw/gfEyfCzTpXYs88s0rEnqT
+Iw/pTJOi8IeCNE8EafJaaNA6+awaWaVt0khHTJ9vQYFVfiWLhvh5q4thIcxqJfLzu8nevm4xz9zd
+XWUUAVdNlsZtMtpNNeF7ExL5DQkFNmONuO2KtVyk/gDS1uXudJutQ0SaRi8n9mXHlxux7mMgpn/g
+NQHQvHFqR9k8ZW1yo/hv9LUk/Vo2X+VACa032z4q+F7SLlrG1u72b2VlWJfzJP5V2dc74Z8MSaLP
+eajqN+2pazfFftF2yBAFX7saLztQZPHcnJroqAOK8ckW2v8Agq9/iTWRb474likU/wBK7WuH8cyI
+fFHge3fo+rNIB7rC+OPqRXcUAFFFFABRRRQAUUUUAFFFFABRRRQAdK+dfFOv33xF8TJa2ML3No0z
+W+maeXIjm2n57iXHVR2z0A9TXsHxH11/D3gPVLyHP2l4/s9uB18yQ7FI+mc/hXF/BHQooU1TVSoY
+wlNNt29FjAaQj6u3P+7Wc/eagbUvdTqNbbepoaX8GNPjt1/tjV9QvJccx20n2aFT6Kqc4+prQk+D
+nhJkIiTUoGPV49Qlz+rEV31FUoRWiRLqzbu5M8Z8Q/BUray3Gm6ol2I0LfZ9Ut1kLADoJUAYH8DX
+PeFdS+IHhrw1ZajplhI/h+WPzY7eQC6jjQknjYfNQdT0YCvocgEEEZBrifhsTp2n6p4XlY+dol9J
+CgPUwOfMib6FWx/wGl7OK+HQbrSektfX/Pc5Gy+O5lKW0/huSW9kOUFndo8RUfeJY4KkehH5V1Wm
+/FnwzdLt1KWbRp842X6bVPuHGUP55qXxh8O7TxJPHqNhNHpurxgqblYA6zKeqyLxnkZBzkV5tq3g
+DxBBqmm6Fql5pn2HV5GtzfRK48shS2NjcbmAIXnrWcnWUlZJo1isPKDbbUvvR32reI4fHBh8PeGb
+i5eKeRW1C/ijkjSC3U5IVyBlnwFG3PBJ7V0Hi7xC/hrSIJbW3W6vrq5itLS2Zsea7sBjPsu4/hWx
+Y2iWGn21nGztHbxLErOcsQoABJ7nivOJPEOg/wDC575db1aBDptrFHpyTPtjilkB83npvxsHJ6Ei
+tzlPT6KQEEAg5B6EUpOBk0AcPrxGo/FXwtp6jP2C3udRl46AgRJ+rN+VdxXC+B2XX/EHiDxePmgu
+ZhYWLDoYIcgsP95yx/AV3VABRVHV9Z07QdNk1DVbyK0tI/vSyHAz2A9T7DmuAvPjbosQJstJ1W6T
+tK8a28bemDIwP6UnJR3ZUYSl8Kuem0V5Mnx0sfM2v4fvD/1yuoHP5b61rT4zeGZf+Py31XTx3e4s
+2KD/AIEm6pVSD2ZTpVFvF/ceh0VT0zVtO1qzW80y9gu7dukkLhh+nQ+1XKszCiiigAooozigDyD4
+26qon0PSPvJG0mpzqD/DEpCAj0LE/lXbfDjSzpPw+0eBwvnSQC4lI7vId5/9C/SvFvGN6fGnjG9u
+LH5kvJI9FsGU58xN/wC8kHsSX/AV9HQQJbW8UEQxHEgRR6ADArKD5pyfyN6i5KcYvrr9+35ElFFF
+amAVxvirRtRstXg8W+HozLqFvGIb2yBwL63znaP+mi8lT9RXZUUAZHh/xNpPieyNzpd0smw7ZYW+
+WWFu6uh5Uj3q7qOm2WrWMllf20dxbSD5o5Bkex9iOxHIrG1zwTo2uXQv2jmstTUYTULGQwzr9WH3
+h7MCK5jR5fG0fji80O31+01LTdNSB7ma/tAsp8zJ2Ax4BYKM5PqOKANeXwXrcam307xxq1rYngRS
+RRTyIPRZWG4fjk+9eVaj4N17ww8unz6NdawkzsUu7SIyi6LHrLnJVvXdx6GvcdE1+DXLjVY7aKRU
+068azaRukjqqltvsC2PqKq+KfF1r4XWzie0u76+vnaO0tLWPc8rAZPPQAZGSazq0o1FaRtQrzoy5
+oEHw90TUvD/gqx0/VpjJdruZk37xCCSRGD3CjA/+tXN+PfGi3VynhXRrpojdTpaajqqIWisFfjYW
+HAkboM9M/lebRfGfi6IrruoJ4f02T71hpj77h19HnPA/4CPxqgmjJ4G0a68P6jpr6p4NuS5E8MO+
+e23HLCZVGXXPIkXkYGegNaGJ6FpemWmjaVbabYRCK1toxHGg7Af196t15p4J+ImkSayfCUutJqEq
+/wDIOvTnNxF2SQkcSrgg/wB4AHqSK9LoA82+MGg6nq2m6XeafbSXSafNJJNDEu9xuQqsip/FtPOO
+vPFeZ+GPF/w60ZfI8R+GbmfVlULNd3CfavNboSFfGz/d28V7xqvjTwzod21pqeu2FrcqAxhkmAcA
+9MjrWFf+Pfhve71vtW0e6wMMJIxLkenQ5qeVc3MXzvl5OhzyeLfhFfRgXWkWVsrcD7ToxQf99BMf
+rU9t4X+Emv7k0m4sIpyetjftFIM+i7v6VmXC/BG8dwl3bWchP37eSe3x9MYFUZPhz4Q15CfD/jWz
+n2f8sr3yrnH4/K4/M0nzdrjXInu0XNQ+BdzBcm78OeJJIXPI+0Blf/v7EVJ/EGqx8LfF2EmFdWup
+F5Xeuqrgj2LR7hWHd6T4k+HOo2T2WsWkZuXKwiyuneKRgu4CSB8/KQMZU8cc17t4U15PE/hbTtaS
+PyvtcIdo852N0YfgQaUbPTYqXNFc100/66njZ+Ffjq7cNcXEJb+/c61cyH/x0Cp1+HvxM0ELcaXq
+4dl/5Y2upykf98zqVNe60U+Ref3sl1ZPt9y/yPAH8dfEjSnCXgvlMfDC80Isp/4HEcH8KztU8beN
+vFsD6e0t7HBICkkGj6VKryg8EF3+76cGvpCilyP+Z/h/kP2kf5V+P+Z5N8N/h9fWmp2+u65aizWz
+i8vTrDcGaPIwZHxxuxwB2ye9es0UVUYqKsiZzlOXNLcKKKKogKKKKACuG8AkTS+LNdkbcbvWJlBx
+j93CBGv/AKCatal47QapNpHh3S7jXtSg4nW3dUhtz6SSt8oPsMms/S9PvvCPwg1Ias8Md+tteXU2
+x8qruXcAHv1A+tAFr4UB3+HljdyptmvZZ7uQ4+8ZJnbP5EUzxCnnfFnwYuciG3v5Svp8iKD/AOPV
+teB7dLTwH4fhjYsq6fBgnvlAaxZiLn43WqqCfsegyM57KZJlA/RTQB3FFFFAEX2aDzBJ5Me8HIba
+Mj8aloooA4LV/hLoOs69favcXmqRz3rK8qQXARchQox8ueg9ahX4LeEhksdUdj1Y38mf0Neh0VPL
+HexXPK1rnAN8HfCrAgNqqjsBqMvH5msu9+APg+9yxn1VJSMb/tIY/wDjymvU6Kailsgc5PRs8Zg+
+AUdlMPsfiNoosbS39nxmcL3AkzwffFes6RpVpoekWml2MZjtbWMRRqTk4Hqe571dooUUtUDnKSSb
+2CiiimSFFFFABRRRQAUUUUAFUNbNyNB1E2W77X9ll8nb137Ttx75xV+igDj/AIXjS1+HukrpbRH9
+wrXW0gv55A8zf33bs5zVC2sIfH3inVLnV4hPo2i3bWVpYyD93JOoHmSyL0bBO1QeAMnvW3qfgLwz
+q13Jdz6YsV3IcvcWsjwSMfUtGQT+NY9n4M1nwe0x8H6jDLa3DmWex1dncNIerpKvzKSAAchhxQB3
+SIkUaxxqqIoCqqjAAHQAVwviyP8A4RvxdpHim0mxJf3MGkXls/3Zo3Y7WX+6ynn0IzVp/EPjaDCP
+4HinkP3Xt9Xj2fjvUEfka5TxX8PfGPxKEDa7qVhotrbsWhsbZWuMEj7zvlQW7ccAUAeuAg9CDS14
+RB+zvfWq5g8azxSdjHbMo/SSph8H/H1lj7B8RLjj+/JMn/sxoA9xorifh9oPjDQlv4/FWux6qshQ
+2xDMxTGd2SQDzx+VdtQB/9k=
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450
+Content-Type: image/jpeg;
+	name="image009 1.jpg"
+Content-Transfer-Encoding: base64
+Content-ID: <001901c68a59$4f153470$6401a8c0 at madhouse>
+
+/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
+HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
+MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAB1AJwDASIA
+AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
+AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
+ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm
+p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA
+AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx
+BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK
+U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3
+uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iii
+gAorN1bXLPSIj58mZipaOFQSz/gOnPes/RdS1K5vvLuWjkjZCzbV2+WewHqO3PNRKcYtRe7LjTlK
+LktkdFRRRVkBRRQaAGs2FJwTgZ4ri7bxffGOZfIiubqTEsEIO3ZEem4jPOeB6nPpW7r+lyahAjxz
+KrQgnZIzKh9yV5BHrXH2wtho8bPAIYGTJQnOBnjnqc54+tYVqrp20OihRVS+p6HBcR3CZjkjcjhg
+jhtp9OKmrnPCthdWKXf2m0ihEjqyOqhWcYxgqOmBgV0dbJ3VzBqzsFFFFMQUUE4Gaw9T8YeHNGyN
+Q1uygYfwtKC35DmgDlPjhcGD4bzqGI865ijOPTOf6VkfDfUPN+HWgXrsSdO1I25x1CuSn5fOD+FR
+/FXxHpHin4Z3kml3Rl+zzwzAtGyb0LFdy5A3LnIyO4rj/hb4htLfwl4j0i7uI4ZcLd2+7q5Xkgep
+yooA+kqKhtLhLu0huYyCksaupHoRmpqACszW9TOnWf7kxtdSMEjRj3PcjrgDmptT1GPTbXzXVpHY
+7I416u3p7fWuO2mS4mupUXz5nLE53YHYA+gHFYV66pLzOjD0HVl5C5me5nubiUSzTMCWCbcADAHX
+p/jUsVzc2lwtxayAMBhom+5IPQ+h9DTKXjHSvKVWXPz31PXdKHJyW0OostbtLuzkuGcQeSMzJKQG
+i+vt6HvWirBlDA5BGQa86u0klUvZRNLexH90qpuDuBnaRkBgOM54FW4PEN9bzxra3MupSf8AL7a3
+UYha2Yj+8Bxz/Dg5HINetSq80OaSsePVo8k+WLud3Qelc3Z+KG+1RQajarbrKwSOaOTem49FbIBU
+nseldGSApJOAOpNaRkpK8WZSjKLtJWOf8UXbeRFpkTEPdZMhHaIfe/PIH4msvTLYX2sRWxQGG3An
+l44BB+Rfz5/4DXCfEzU7m/0iW4t5DG19cLHbuGIKwx5IPHTccn8RWL4H+I2teGpXg1WJdRtJnDST
+F8TLwB1P3gAOhrmlKnKqnKW3Q9ClhMVLDt0qbae7SPoqimRyLLEkiHKuoYH2NPrrPNCuP8dfETSP
+A1mDdMZ76UHybSM/M3uf7q+9bHijX7bwx4cvdXuiNlvGSqk/ffoq/icCvjHXdbvNe1e51PUJTJc3
+DlmJOQPQD0A6UAdN4q+KnijxRLIs1+9pZvwLW1YomPQnq341xe4ncx5Yjr1zU+maZfazqEVjp9tL
+dXUpwkUS5J/+t716Vp3wG8Y3UKvOtjabh9yWbLD6hQaAO/1zwZps/wAGo7xbi4mmttLWS282bCR5
+CswAGAc475rzP4Ua3baJ40he8/49rqJ7eRtu7aCMg4HuMfjXsXgbwBf6aILbxHbWtzHZQvHE4maV
+ZtzAjKNwu0DA471s+J7nQfh14cuNYstHsY7jISFI4lUu56DIGcdfyoA6Hw4k0Xh3T47hSsiwKCrD
+BA7Z/DFalcd4B8S6n4hsGl1aK3jmeKO5iEIIHlvnAOT1+U/nXY0AUdS0yPUY41d2jaNtysuOOMHr
+7Vl3vh0paCSxcvdJyRI3Ew/u+i+xroqKiVOEtWi41JxVos4KNxIpO1lIJVlYYZGHUEdjTulb2uaQ
+8pa+slH2naBJH0E6joP94dj+HSuZkvYY7YzluAGO08HKjJGOxHpXl1sO4StHVM9ahiY1I3lo0Olu
+7iyu7W5s0WW7Riqws20SIcbgT29c+v1qe8vP7S1WO8SxktdsJikMpGZTkEcAngc8+9QRWrRTSzSs
+HmkxyBwq9lHt/M1NQ60oQdIFQjOaqlW9AnEVgrKJryQRR5OOc5J/ADP5V0WpjUdb+16fpd1FbwQr
+5U00kZfzHPVBgjAxwT1yfasSWKOeMxyKGU9j/ng1Y0/Xo/DdgYb1JHsIgSs6KXdcno46nk/e/P1r
+fB1YJcj3MMbSm3zrY4zxx4f1K/msLYW0dlNEHWN5nP2V+BhRIPuk4AAYCvIdSutV0q+lsL/Tjb3M
+fDxuDn6+496+pZPFGjyMLPUR5CTocLchCjgYyOCR3715D8Q5dETTW1KyuI2VL77NbQLLuYRBTvKg
+8hSw4HQY4610Tw9OzfLdl4TM8VBxoqq4Qb18vM9Q+GWu/wBveA9Omc/6RAn2eYE87l4z+IwfxrsK
+8j+B1211aauYizWoePBI4D4OR+WK9cJraEnKKbVjhxVKFKtKEJcyXXueEftE+ICsel6BFJgNm6mU
+Hrj5UB/8eNeHWvh7V7+0N7b6fO9rk/viNqH6MeDXdfE27g1j4u6ob9ytlY4R1BwWWNR8o92Jx+Ne
+e6hql1qUgM8jeUvEUIPyRL2VR0AqjA95+BFvo2h6bqN7qd9Y2+qSz+SEmmQOkagHjnuT+le0Razp
+c2PK1KzfP92dT/WvhNcZ5xip4yR04+lAH3krK6hlYMp6EHIrwn9oTVG+16PpaN8qo9wy57k7R/Wu
+K+F97epq9xcDVryBbK3M0UQZ3jlkzwjAZGCMio/i1rsXiDxq13bs3ki0iRVdSpQ7cspB7gmgD3zw
+RCttJbQjjbotnjnOfvZ/nXa1598PNYt9VuYzG+JE0i1Ro2BBBG4N19Dj869BoAKKKKACuU8UeHnn
+D39gGE2Q0scYGWI/jUd2xwR0YceldXRSaTVmNNp3R5xZRMUjlZkKAExiJ2KgEY4z0Ht2q5V/xBYx
+6WW1GPcLeRwJY1GdrscBlHuTyPxqvb6bqd4QUtvs0R6y3PBH0Qc/nivLqYerKpax61LE0o002yuz
+BRliAPU1Q8T6Pql/4J1iS0EkLC2YxqBh5QOox2BGfc10VsNPtZ9llDNq96hwXXGyM+7fdX9TV86Z
+f6jk6neNFE3/AC62h2rj0Z/vN+GK6KOEUHzS3OavjHNcsNEfMWhXOreGov7T0XzGvQNjSLCZV2n+
+EjBGK6ePw54m+Id3G95A7sVAN1LF5UcQ744H5DrX0RZ2Frp9sltaW8cMKAKqIuAAKnxW/sm95Pe5
+oswhFtwpRXu8uuvz9TktF8G+F9A06DSVjt3niQb3kfbJIT1Y4Nab+G9B2/vLOHB5yzn/ABrTuLC0
+u/8Aj5toZv8Arogb+dVP+Ed0bJP9mWpz1zGDWx5p4r8dfC/h3R/DFpqGm6ZBDeXF2Ea4jJJZdpJz
+zz2rwCvon9olIrTwzoNpbxrFD9pkIRBgDC+n4187UAKBzViNT6c16z8BfDWleINQ1o6tp8F7FFDG
+EWZdwUknJH5V7Hd/CLwNdxlToMMR/vQuyEfkaAPK/gTrdvoy6+ZbW5mby0lJt4t5VF3Zz6CuT+Kr
+vc+Pb69a3mgju4o5olnGGKFAAcZPpXuOmfB3RtE1CS40rUdQt4p4zDcQM6uskZIJXJGRnHWr/jT4
+YaN41ltp7mWe0ubdPKWSDHKf3SD6dqAJ/DUiSP4ckjKndovO3sP3eP1zXYVz3hXwjaeFLFLeC6ub
+pkjESyXDglUBJ2qBwBkk4roaACiiigAooooAztZntItPeO7i88T/ALtLcctKx6KPf37dazrHQbua
+yij1q/muVUf8e4bCgdg7DmTAwMnr6VkReIZYvFV0up6dJJNCzLEsB3m3h4w5U4+/6jJ7Y4NdhZX9
+rqEHnWsyyJnBxwVPoR1B+tF+gW6ksMMUESxwxpHGvARBgD8BUlQXd3DZW7XE77Y1xzjOSTgADuan
+ByM0AFFFFABRRRQB4Z+0kR/ZegjPPny/+givnccmvdv2kbzdqGh2QPKRSTEfUgD+RrwpBlqAPoz9
+nC3C6JrdxgbnuI0zjnhf/r17dXnvwX0NtF+HNk8q4mvmN0wxyA33R+QH516FQAUUUUAFFFFABRRR
+QAVnaxqiaVZiTb5k8jbIIs/ff09h3J7Crd1dQ2VtJc3EgjhjUs7HsK4i6vXu531K8BjABEUeMmJP
+TH948Z/AVlWqqnG/U2o0nUlbp1IwJRISxNzfXT/MRwZH9B6KB+QFSfZLrQ5GupY2t9SLbmvEJe2u
+h2jk4ygA4BI4656it/w/pMkAN9eIFupVwqdfJT+79T1P5dq3cVNGk4+9LdlV6qnaMfhRyKX99rDW
+2uRWMj6dbn5bSRcSsf4pVHcryAO/JHaumsr+11G2W4tJlliPGVPQ+hHUH2NWMVmXujRzTNd2crWV
+8R/r4hw/s69GH15963Oc1KKxIdbezlW21uIWspO1LleYJT7N/CfZvwJraByM/lQAtFFZ+taxaaDo
+11ql9IEtraMu5Pf0A9yeKAPmL476ouofEieBX3JZwJBj0b7x/U1zHgPwnceMfFNrpUQIiJ8y4k7J
+EPvH8eg+tVbxtQ8YeK7ma3tZbi91CdpFhjG5uT0+gr6h+F3w/j8DaCftCo+q3eGupF5C+iA+g/U0
+AdzbwR2tvFbwqEiiQIijsAMAVJRRQAUUUUAFFFFABUP2qD7R9m8+Pz9u7ytw3Y9cdamPSvL52a68
+Tyxau1otzMvzWZiYSArkK6tnlSuM+uKmUuVXKhHmdje1bUf7YuRHEQbCB8gjpM47/wC6O3qee1S6
+Bp/9ozrqMy/6LE2bdT/y0Yf8tPoO35+lY9yESOGJo3a13AXEcH3xF/sr1xnAOOcZxXfWU9tcWUMt
+m8b2zIPLaP7u3tiuWgvay9rL5eR1137KPso/N9yfFFFFdhxBRRRQAyWKOaNo5UV42GGVhkEe4rGO
+hT2R3aLfvaL1+zSr5kH0APK/gfwrcooAxFu/EaDZJpVnI4/jjuyFP4FcisPxH4Iu/G8cMGv6k1vY
+xNv+x6fwHPq7sMkj2FdvRQBz3hjwR4f8IQFNIsEikYfPO3zSP9WPP4V0OKKKACiiigAooooAKKKK
+ACuD1zw79h00xveyym+uVheRRsf5iSSzDluOMZAooqZbFQeqLmg6FZ6npZvpQ6TSsVieM4aBUJUB
+T+BJz1zXS6bp0OlWEdpAWKISdzdWJJJJ+pJooogkkrBNtydy3RRRVEhRRRQAUUUUAFFFFABRRRQA
+UUUUAFFFFABRRRQB/9k=
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450
+Content-Type: image/gif;
+	name="image010 1.gif"
+Content-Transfer-Encoding: base64
+Content-ID: <001a01c68a59$4f153470$6401a8c0 at madhouse>
+
+R0lGODlhyACvANUAACgvK/rWpP///3SPrcpORffwepuQZs7UzkpSS3qbw4uTjayzrVJLMmpyahwn
+JzlHUQcZDywpG/74gxMiGGB2kEk2J+fs5yk1RXhvUFZlcPnVnjdBOEVTa8u2kv//+4Kfx/7/97mp
+inyCeNXHqlhiW9jIkqCpp2dWQZuim/rdsOXMpbnAuuTm3u3x7drg2/T283+cvPb79vDVq/P17v7j
+sCYeF8LJxOHm5Pv/+763ae/28uzXtPv///f8+62dffv7+yH5BAAAAAAALAAAAADIAK8AAAb/QNTC
+ZjsciMhV0XhcrRaoaFRBpU6rWIVI1OA2vg2SeExCIDYbs1pNCpPfcLHIpHDH73Bz3G3/1sEiWmBd
+gQpRJiiCYV+FhohZWIVdNgtQhokiUlJUMSACn6ChoqOkpaOepj2qFjc2KzesLgc3LhamtwI9OjG4
+vZ+8AjigODEvP6IeAh4eqLkvpx7Cv8UvMcCgyQI/wtmfwjotMTjNoNfTPd3K2S9HB+a+pB4tLTrS
+P8ce7/D7/P3++8twBRyVz4WLF8vSKfu30AaCCRAmkDjAMJmNMmhIoLCF44UIBBRvpVM4DARJXysE
+KVihj6FLgT9uHKhk48anAxsAmHhZygaA/wkIPkLY4MIUDmneRCmA4MDMBKAUW2yAsPMoQZPqBmK7
+QUXdsGBISz10sGGCAxI2Q0kTdjRsKR6g4OLiIbdXCwQAHDzdICLGgZ8oeI66O+FBCwEuAEBocPRF
+tY6OhfVoYUGHgLoCUJg9gAOFAwgIZiC2oSPbjHceZnCT9gJusgaLBWANdVIUicIWUPwUsZC24N8C
+LJTdsECEXhGJJwQG/mnFUwWgbgO4sSANixgNNgRegPEBirCaHdj41ODpihZbVgg4QCKNgsMtFLQn
+YULYgQYPSCyIoSAv38MrMFKUBwf8IYItoLzwEALylIUALy6QtkBaiGmxAjrBmTAHCwK88P9EUeud
+F1wlKxwDwgyULLCCBQYBw2IL3QgHlCcPbbDCT9AJ0AIlnIHCYhEI9iJCRAuAosBTNizlgAsgTKVA
+DFORsAJZz4AiglnjCbAARAocwOULZSmAAAQK4EACaOU5cICMIkxlggk/IYBCDCY4AIBiCLTAAp5j
+5viJjAiAIFVsAihgAk4IcHijA3pBd8ADE/h3gFQTNCCADnixcAACelX6gwUkkLVBUzkV6QEJAGT5
+p4Oi3bYBnBNAVx2jADRQTZt3AvCqL7BNUOQnmvm6FAAu4PAAmTqUxZsToqSZpQ3HHaAXCi5EyiIC
+C+BwRmWKOTEUDjbYaOwEvAmnXX++Qjv/wYpShgKoDiZEagMOVDwxpAIKpurcBi3c1oAFsD1YHgI9
+SEuCghFs8dMCFvxkAgt8PWRpYvy66yAOLjjok3JgQiDEU7P81IAN5U3XS3m+GmnesC4MqkCylZbi
+bHMQiSCtxw0XZoJlOFDmgmfreinRCqIJB8GyE2zQ3mco2PDUr6LIqCtZ47lw1hOakeA0CZ8YklyR
+W6q5gJ0umECmtHw1oNi/Dgf3w5UbwHt01KPWWpYDCySngAdaIMaoDcnttCWxvRyZMnmbHTmd0S8r
+KzOWwD4nrXJaTgVUUewB8IBeRSrwWaWUTcXblkpnct6Uh9OddI22QAsAF1QcgEJsxwiA/3qRt1O6
+QHkuTKkrAiSIYMOeE+x009/lqbqqnRs80IB6f8X6iQti/h24lpGCeIvThOoA6QYeQQCABcQ3Tu7j
+agoQw1hGTBscV2sn5rH8RbZw32eNz70lAqy14FzqFgOKunjjOu29QDOGmd7YUnY7AZypPfzb0gNu
+cI3r/UJiaXgHoG5QpfUABgfG4cvfoie47PXCTExRAMmeEhglFQF/MOONKISRphXcp2YCUJcJnMOb
+IWkkUuDo1gIAUCTYNIBSvJGWA4S3AgSo8GmkABQOSnaAGZSlATe4gQi0dpzcbGBj0IlX+sQovb84
+YGfxUcANymK8rplFeqKgFAIsk43oNf9tMzewXtsGp71bWGBMEYmIDH0ivp/4qmGEUosDI/ITpogA
+QBC5Y6WmgoLJdQFkZnOAAtzUgzERpwW96tQB/lckt1jgAhDgGrRSWShGKkYBnYxIlKY4FBSMiQQQ
+yosD1POD2zjgAZTMWRs9yKiQBDCB2vCgclYgPoPo5YV4wx7hcCGM3DQAAQ3IFigCZIZs9owL6plh
+D7ijB+GBwgVfsIEHTHCGDbxMS2fQHCxfsEmyiOAZK3gAABDQMrXpCndoCGcc28MbEKLBBi9QG6OO
+uJ7NXU4ANwhVREhQlG0M7DCI4dRTGqCDNRYvFDG4DQI66KOpVCyZN0PBDY6VhqHIAiL/O8lkH03R
+DWDgIB09uAY5xDkNUPxAKwuZjGXKQRleZKMFtfhEMuyHUQFo6jAgiIEOdkESD4CjSrpoQZUidIAe
+BENHRLDFMcBlAhvw4qfBOQCHjgoFlnTICEECFplIgYMVoKBEoWgBFIpyAxT4ISqIoMjPUNBU5hj2
+sIhNbDx+EIPrXMmY/XCLYieb2Nr1AzOUFYjt0iARy/KjNofFbGZHGwrRklYkWopTRf0BWoZs4xMz
+YIFoEOvZpFA2Bh/qDXCAioxPcXAfoxxqKW562mS6AFd8oRBz4FWGbIqDsjKCjlV6ZsOX/IAdNkBQ
+MmThgYzpJJnwiAE9ZkCPXSwAeBRB/4p4vapYnAxFogiIq2BAKD5IwRGxrtCRky4DitmdlCHRk25w
+RgU4wPRDN2hIMDaRJAoRAMBPh7UAS22yJQgI1CqfuIdtZaPUUkQvW0PaAHF/k40r8WZQywHFpu75
+EqH5qV8bOIDeNBsKFKBBL79rgJ2U94PyyBCx8bovCh6pPhSUQQQ2OcZ9sEkRD1hAPvQhqe2eshNQ
+LucFxRFBOJ28ACuwIhFdyoWOErEzD6ygLFrzaJcUsB8nF4EX9uvyKxJEieySNx2Ty9ExaIExHMHW
+AlWyX49EUYyMVcox4XGHC4zKAhEpYx7sFUyvoOZT2DTPpbYjy5kAcAAFQSAD+w3F5P8eLNx+ia9R
+Th5T0pKmS/FRBCdPkcgNdKxpWOclItCBm/3G8hMbQTRUvcYmSfOs4jOsYMZnTlTlIvWvKF4xcrXC
+C0VBcE3ozDojynPtmdT0Ay1QwQL/I43otBW3RTagWuPDCYSDMaSnPOBXLNvSBABXMx1kgClE+IwI
+tEUuB3ssBseCDqXoM5UHCMDSOlBS3m4pgCGd+0z8FMXN/OQcCOQNMDLCnUTOuxjJetRSmTGLGRqF
+gygd/GghlrI/1ockKEHg5QcYEgBEE7C/aEdti8mjAFuginTQs1PF+8GYLLWno1nNY63cgKAUg5yk
+hWFtxporihsOGqqDT3FFCRgKtwP/GrdMfJucS84WKWcmNdF3fKP4eOTUhERtpdLtLVw3QyYN0SMt
+ydKHsTTqsMlmm3guIljUrYpvkzT3Wgrgi6nWXJcCPkTazCwbYMAkOiZwSlKdQbABAD0jRRGIXz7m
+rJQ4l8Duq8TYCSjf2Fw8N8DRtD875Jzu2L4ZDhsHNKDJgjHcIJmCTvHZ4t42KuY51Xe/uYXCBRrR
+RppMcCxLDerckUx6DBzvpQvcwLIuGzDSh8QgmW+e04vk3w3GpJcYj4J7FA97XnRZpBlASnguEK4o
+1B5yNSXraPzmWkI/o8nfJAcA6jE7E1A2EbEC90cCRoMARCAGOBEYQ/IA5jAsFBEe/xcBAQ/QA0en
+AIoHHYw3fUxnNbEiXlvgctABMdtngR6Qed/XeaAhDtW2M18VCk5zX7cjdp5kAetjfE8mX4jxeok2
+KPt2LFwDC+xhQjoQJPMQDT3Dg6OgGRGxOeJzA4OiNExBEUsRETDFTLFyJiCnYp/xAJvUgvIWBkNh
+AV5CFVbngXNzJklDST0QJWaoGA4IGikoPvTkagIwJgjQSnLiBIMGCjNIAlqgIuq3TE/BG0oiiDnB
+g8kBcj84bkJoLmZYTH/0RcFxBhQxfuaHC+e1flpzE6jSFFkSAw5mJyKQU+hyFsr1CdUBEWcRErrx
+hONhRuNxJBDIJhkFERJhGYbzKv+Wx320BAAJ10x5WHUog4VLZA4zCBGgUXF5M3psuCIP8XJIpxBH
+B3JLMQFrsjYuRwKYMhR62AM28HKBUXGBgX6+EBNZ5A2SkUW1xSI2ERAWADiRFkdP4A7g5QIqMlQv
+wAIsYAxIdX0/YBAtUE0k8gxH8QTn4QqYMwQFoyIxoI8r8Ax1lmnNkxcg4xUWUAkcWROVEH9DRhEs
+MIjBIR/eRArxIQK/YgNbQEF1sAA9UAeBcVxocG4CMANbVCzoQVE6EgYzVRE0NRIKwQzI0AtasVO1
+JVlfsWFh0Q0vgCo2sZHCBw9I0ZQb1lpA1Q1IwV7WkGHd4FnZ0FrwIJb+UFvKMBv/8cAPP8VbqPUJ
+N5AXGngf+Ecb3TASt1A7bOkLYTmWRdlhLyEXraAELAAXcGEBGtIGJtBU/qMFJgAinuAXiGADXgUC
+tRORSvBbppVYpNgpdoIvxfWZgkEyAFADpAkAaJEZo6krP/EA49GKERABNRABDNVEpEmaPFkhCACb
+NbBPAjVa2zBKZRWPoDmc/uARu4kBPuADBkACNRAUNXACITACKjACBnAnJBABDOADHdABIYABNSCI
+ZGEAIRACIhABNtIfzykCyokBr9mbiFUXZil4xDmfppBQNYABJZACAbCfO+ADsIkBO7Cf+5kCHXAC
+97kD+hkAKbADBlADqZSfCpoC/yEwmhGAAR0gAymQoQSKBoVFn7uVlf2QDHmZWSZQAwYQoBogAzKg
+ASmqnCqwoizKogGgAj6gogEQoy2KASqQAjGqoD5wAj6AoirKoilQnqvooRmGpPOZghugAjE6pDKq
+nxpwo1MqoDxapVQ6oPuJoyqKoVkKoynAnkeqpMHhj2Z6pmhKPhawpmzaphagVS8AAnIqpwlRpwlx
+Gh7AWHaaEIrVABHQATwqoDjaowIqqDIaADKQpYOKo1tqpQraARVAAvE5nFhhmNlxAQmWqZq6qZya
+BnqAB2+gB5/6Bg1QL7OllP5gA+bpA9KpAhcKo4TaqIgqqEMqqFQaq/spAyUQAv8dYAAVsIlkigMm
+MCoXwAEUcKzImqzKuqzMiqwZ8KzQGq3SCq0cUK3WygHAdAGMggAwiKr7IAxnFpsMsAER4AOBmqWF
+mq6FiqXquq6I6p13cntkOj2owgEDAAMfkK8fkAD7yq/6+q8AG7ACO7AE+wH4qq8wAAMDMAAUoHrZ
+9hJ6tUWcIgLpiqVVOqWHeqs32q6GKgMnQERj+pl7uQAXcAEUkLAJkLIqq7IwsLL8qrALi68DYK8u
+W7M2e7Mq268ua7AUcAFEhFiJYQBSqq7surEca6tIG6Zoh6TNUCccgK84a7MfMLMlW6wL6wAZoLNR
+u7Vcm7JTuzk7MakAYRU2YKL/Q3u0aIu2VVqkEQBZSOq0KNu1KtuzxZoBHAAAT/sAHCC3fLu1BssB
+0USW8FC25pq27mq4hqqgDUpp83kMifEAUBu1WpsAMPAAFzAA+QoDCHABMMABl9u3oHuzlXsBP+kS
+qlq4FYu4hhulPlADjEufOoa5OJu5MZuzPYu5U3sBD/ABFOAAFDC5oQu6uUsC3toPqhoCCaq6ymu0
+BFoDKeah0JK1N5uv91q5kLuyA1CsFJABPvu7AwAA0hu8oduy/Nq7D8sQx7u8RJu2VToCFfBj9Hkq
+lwu8POu5Wcu9suu1gAsAunuyCZC9DyC+wRu32duFPLECf6q+CryfKlABliK4/5MlLeHbsvsKAw17
+Jw/gvRcQvvz6vQ9wr/0KA88KvALMtx/AARvAAhB8CwqQwAusvjLAAFyDpJ6Rv5Q7ACm7ORmAu5Rr
+uTi8sg9wvSursORbwuPbu27LEP1RAi8MwycwUkgqAvO7r7xrsh+QAQCAuyDcs79ru76rs1WcAUVs
+xCb8va/7DwpQASrQxMsbpuCDpCRwuTucstnLAblrrPZ7xxS8sHXcshTcu3ZMxqH7vXL3DyKgxmys
+vClgABvAhJ9JAhmMtVSMvydMKxmcr/jLsCU7AM/qxylrwT8syH0LAxdQyP4gAgywxomMuCngA9NE
+n5A8AEGMryIsyb37wf46tf/8q60m+7I1m6+iDLqkbMqfRQIMkKirbLgSCn4eGse1fKz69EstO8v7
+eqydq71xW7MK67/BjLNjXLnQscKi4BokcALInLjJXKgEGgGmAsucm715scEZ8MW9C80O8LQJG7k5
+a7Bei78s281FPMYG+wDw6w/kfALJm85HWwIVEBjifFgNML+Au8MGW6wKq638O8dSa8HPusVWbLPZ
+PMBjzLIfkB8PXVqygQAYkNAK3a4q4E7y+ZlSjLn1TMWei7kZkMEgLLUNW7IOYMXZ28WUG7U7vbX5
+zLD8+ssckAEnHRcpvdItjbYxbMDE2R84TMrXW8W/a7BaO7mdi7WafLmk/LT/IH2vlMu9NMvPIN3R
+JUsB1VvEJZ0Bf9khCCC0UX20KXACM0yfVs2v89zFCouzofzHWZyvgIu5N/3LPfvB2YsXT1u7LlvL
+/AsA42qaIgDXSy0Yb2nXd92uYUoC9TicnoPDU2uv/erV+bzUWpu9Yky3OP3FOwtMG1CsANABGFCs
+P33VLHu3OUHZFYCdDEDQfly5cs0Tm93Z7aoBRdrIHjraLEu+YKywOf27ic2ylrs5H83JZv3J/MoB
+DBACo5LKxoGd4KvWCcDbd8IAv80ADBABFXACImCwxC0YiYG6yC2oi8zc9GkcNryzDHu3mkPTsN3P
+P22s5EvLv/y9BuCfKy0C/985AsENwrKsmr5N2e393r+KuxxAAk19fAAQAvetrsucxJ+pNjZcwQnL
+uz+9w+TL2mDcu1n74qa9syjMnflpACcwApDKv8YKTNeJnevd3htwAhXgAA7c3Rx+wBEA4iGO3x0Q
+Ae4JmhF94P0qyxqMAAjbw5B72i6+siU94Coryw6AATSQAl2qAgaaBndSAdFpABjQ3uyNnUQu5wyQ
+tRve4aCwAC7c5DeaAiPAzs3MuTf8w9Zr2Jc7s0/Lu4VNuQP9uSu7vfrcwwDw2xgQAgg6o+w9ntj5
+qimgAjgO53POAHP+vnfOE0PExApctAPK0urawMRMWpDsx57rtbdbxbMNvv8yu8E8e7I1vbNDbMEA
+YAAlYADtDaQ7Kp2QygCACqMqatui/tsnQORGrtdKIxgmUAGorsyd/qIsnaEqwO1HqwIMUNCgGevd
+7QBarOvwPMfyDUw5ndsMG8qz690FIAESUADEjp3mGgIVoOxm3qU2WgIYUAHvHeonwAB5sdcucciq
+vL5WatsEzwAGsKNTKqED3+8iMAKsjqiSNwrFe1jmruJZy7D8i9jzC8pXzCjYDMx++70+IAE5gJ8S
+UAI5UaH9rvGw2qVTWqDRDu2jbpqCgcoN7/CL/JrBk5tsXuYGEAG1skXubd8bm9f8UyBalpmKZe7/
+i6ncaycA8Lsw3rD3PLX/GeDWke639D7zJ4ABBYABTWNjDKDxi4rMzc6eEdDzcg70n3UMZsghDXDM
+advKEQASv3BmFcCdgR8S4JKbUK+gbeKnr1kDfVFcWP/V2gvAF00rNJvLfavLBmDv947vAgcCRnal
+W0qoKxoAJRDtF37wP5Hk/AACcCI+bWLODr+f7htfsiGn65FgqZL7yQAqf5rQi0yaFjoCGEA5p4Uf
+0A3jB/vXV/wAFD3c2hy1+Apq9e75a+8CvXQoJ7DGKroDUDqoAdABq3/hprlTvWA2G7CcT0ECGrrx
+Ra8ec0qUY7NEWQECXpUxK62hMgAEKlGNoaKldqeNRdB0PqFR6bTZuMAS/9nBhfPRXigfGOxTzp4T
+WPQ66/1sMZKChF7A3Dy21uKUGolOMEpSNAo1AgIKZQwYTioiKhwRZqikXAAYRpAwagAwDHxCOlRU
+ZGRSkE4QXjxAPF5dY0gcFgRebz0ERABCQgwwHCMcFHY6Smh8JlYqmZuhrNBgOC4GsmAGqhPeODKy
+2b7XPig2SujMSxhIGlYOTnxGThpQGhg6ZAwRE099HhsZIiY5czIkRIpSHQA4iFCjRgQAFRoFMrBL
+hAAQrm7hEGACgA1buHLZABCBZCQDBnh1iFCkBICKAmFOEXEBjTgHYc6ogfHAgQMOWNSA+7Yzjjk5
+DCoAA+BpB4aXIBpgkP+RD9GhQypOZH0EsAXMFwgY7GDEIMQGDB1C+JgIjAFSkg5QWMTYCoQAkctA
+vrKwoYKBUTJoqOgrg5OIHQwQ9Ii5+Ak0NAM4UGDzBoAqal6ErhkjDkAOoxL4FdzBz8AIBgdskLBg
+owjVqvlC/KuAYMMSmDc8hYCEIURfGgFQoTKlYkQHERHiXpxb9+5HXCBabBBxJJ8KBtMPMyC84QZj
+7yQesBkzOQMAA0qCZs5J5kFRowY2qEjkR0UHBjcOKGjBWn6+Q1U1QCcSBgCwTaADIvglgg5SKKEC
+H1J4zTU/KlBArucEWAEAE5zDhYUNDIjwPxkCQQWDCErwAYADvGMMPPX/cnrgQQYeSA9GMgbYwDOj
+0IlAKkQiRKeWJkSQ6r9EXFMBmEcKZEKgBSbwQQkVUlDJh0QMweeqdHBo5ZaLBFBggorysisCCKlK
+AZhTDFhQt2VajAk8zDKj7JMKMvDCxjozYGCOc9o6IYIT+tNgEQZQsEGEerBE8sgSTliqwCZhWqCG
+EKYMQLcQsDwygHs0SGEXFpWjKwYEJtjABVsueiXMCDQ5Uk3tUvDhUpU4jBOmOTPDgrOTAMAJxmja
+M6qAtkpoKoKC8hntBAbOEvG/QoBDJgISNnCowO4EMqGGDjINAYAOOrUKQApViwKFazd4wKMnXNjg
+hB0ABM6ACqj04UwV/yJ4SVdneFXvAw4exOCyYc/gbEc6MBj3Nxn+wicFGfrz77UOQGlTBEyd4g4m
+bzs4sQNkKiDXKmrrrRWgFW5oYbXj5u2t3xVccGEFBEomRFZ+BjkuBBU2aOBfgQIW6o0LTsC0RoQT
+7vNPOgQ9C7gI63XNtUMgfUTrEUzxYQMWYFrh0hCI6IBnCT2ltlYmayPpBE0axIDJkSooCOV8OihZ
+N+1aInNoZooGhzMM+OmCaW22MOCzEuROikEk/fOUqkMgHqHNkUigEj4nnXGh3x1EePDeEiS0Oh+D
+fsHAqRCm+q9BtUDRBHKqHPQrWlxt+bsSEgzfM2GC1QIgz8PFIeczOv8gdcAsKiU3PR/CDLBuqUEt
+N5CZXF7YAIEdKG6qCGrvbn5qVGj4DeUIg0PFeQ2ArmCE30St4V3dqQh8KHl9aHgAOoeV5oTjzYGS
+pZxgEFa722tS8KwOZOskK6EN5yrhKgXUwAD7WAmo8FG6yYVKBT64EiJkUIJBZClt05IBAojwM3Eh
+IAb021146jQAT0jpYEzbgg/kAMATTY9QzruaCsqivQTRIQcAqIH1nPGVGiBAUBM4QevEFzkkwaMG
+GEASiR5EtQNOLgCR2sARHTI/F0oBPL5LGAXM4wMaBcWM49FGBjbwtM8UIFKS6lenDDi1HY5EcQWY
+Qw4YgERnWEABbRH/gbwwuEWLIQIrCZIP5fiRIKr5EDgYUM08GsCiMdZvaUKRBgPUgif+gcONRAHg
+HyUlqdZssDpn8ZoD+sKwB0kAPl1hzAteIAAS9CFLlATScUI0SeDY50zCNJ2oELBJosHQd0cjHEoo
+YMZotEGGC8thHeqYyg08joSHoJA7+OIZP9rBR9iypXdwQAIM6GxalMwbCaZyNT8gZQSUDJXXIKjM
+KZCAJkZDIygMtj+mfQCOcnza5VJZIHLVq3WfQslKyvGZNh0xnzGJzjozaLojnchuGqwVBQmxPk0B
+AGz6rIRjBAc8KXUSYaYEID8SupQKkI4qpqhKCsTFgIgeD5CCFEgu/6ITIi1VjSrWeeIGH5UUjV4M
+AHAy6RRQ+o0tuKNwdJImNTtTgBzslJYxnd6PnFcliHC1Dn+qZZz2EqJG+bJvs4Pclo661AA4aEhP
+lYIVzDi44Amrf3BkHEkE8VevPuRxXAyVfXR6SrOyME64+aAi3doSjEYuSyTSjkgDIBgL2VUKCriC
+4MoD0GDpyY1GewABIxAVSJBksJI0YKhMk1gA5pCOJGhhi0TyQbc6TzC8XGRVZNCIeObRUNfhbGc/
+O5QHgJKG3hhDGxOQuBwsKwUI9aqP7nFMxJL1eD3yadh4YbEoAklupGsnVVQigpBezXXxOG4UPOuN
+NcjwmRV4QBmsOv+UMVRzugWpbmsx8MhFVglZswVUu74rEA2ZrJfrw6mPjAkkLC50qaHCAALq8l4n
+KAAA8j1jGtvUDQoM4KppIKgn5GYywmhLUjUg1HDTtF0DI48B1MgAAnQQpwU7ardWU5Nr06QkIFOy
+ul/T8IY7/I2B9SV/DkglBwQqOApcYHrbRFIj7RhgLMGYwLI1MDo2sL8b57JFJphpucYLJKxUkXTC
+UWOC6OVL4KhIk0fmsIevMWUmM4AIPsAYAH5CyvKQpQFLYdZVTgQJETzygF3m7hxPQA0yZIAEP4iT
+AvCFxzxOSMgoxsA/yBJhLgLpTbnTsAIcEOUscMCOkKgMlSopafH/oFEQDaPyg04ByWgBaFqOnvFR
+wiwGgq4iTodkdJp5DZwQNM4ksIas5FQSlyMLAAWpxow0XNIBbd8LpIVQEzUmswWynMDJHHgAlZNG
+JfVJC4RAypuXZ0vH0ZqYAyTQ1aISOa0SopmRpACOpolbnQpNm9pJ1gYFHBCiqaBigUVg+AYCHQ40
+SuoB577AuRUCrZ+pL3xiJWAd4t0wYZGh3vfWTkYzqlFk+3JEDBDatKudjZ20Bnw0aIADTjCRDdxk
+lNbggJMB8AAOmBvd+QM1b2B9urydQI6nFLlVpWHvODExkeViebLlzF4SkUAjRxYJTmCANFAFxzqQ
+qABEAO07adQG/wAXcHvFz1SHHHwaItEjX2+YDvLZPj09A5O6dzxA9V6iTHL7HjXAVa6mDZzzvQeY
+d9gREE+znaeKxUkWP51r4vLkoE0XP3eByvE0rQoqKR6MxByaLlHhuaEmJW9RDNrzqcHbc+VZBxJK
+mJCLxj+eA8UkzNlHwiyDIIClm0F4HDRAoItfwAF+OuXcCbSS1B8PJRkorTV28nfG4MaKVk/5pkdd
++5vqyyO6P+5ehieNZTFS2+ISwQhK0AESzDthMsw7OhJagRxMH3kbgPdsQ6wMnuvasi9OLsEAZK+b
+xM/2fOjB8ELDouMn7ARUEIEGdMPshMH60iAoHsB4QCPopoEB7v9lJXJuq0RPbqzpeFBJAp8rGnbi
+5bzjABPwahiQBmuwBCLAQsyPs06lRmauFKilg0qvSA7JcNLgjTojgEBQRkTI6LSmEXDoRMRpxnKg
+XZ7r+jbwAmCQMRzvShRwAWuQtyrAbzTMCgagPAoiu7CCj44gFVjKTt6DxSJgYQqgBDjv0wxguhTn
+mgAIzEgMC7HvAjbLOxbAATjlC8MwEWsqHUztvUzAAR7AJdarupaFBJblFMRleKyhA0NvDvSl4nbO
+PeZIDvaPD1WwxlQN+9ZDEOPEBNbvZNYKshRR5SzsAWLAAyztvVoAhb7nUypJO0zjWhom2DRvDvWu
+iITu1nbkT/j/L94iJQOiiX90Ig22YBAZQwEWBODOaxZpz5vUpAbiIhePywMssaPuQfGoREkmANBI
+bAPpq7sqoO0qDhNS8NfkwI8EaykeIBpdMAvQyKkYowFghZ3AR4Nsr8Fey5sgZodo4chWYMjm4zhE
+QNsiZX+ubQCWi7uOBdCI7iFyLg9zICRFUiRPQnWeBSlSCeP2kQysoQ0y4AEYLyYcbwLO4hQoSxG7
+CeCCI0UEZQMSpTYqapNy4UOe6IDW0Mkcgq/SYPNMkQ467+2oLCGmR1tYi7WWwgHcru3MDQSjEhJH
+zI22wF8YQwQcAAHcxs9OYZLAcH28MYTOwyFIAAVKygQmoK5M/8oDZCFnjiRUqo8CuMHDBkfvjEID
+yC3ozm0rhU4r387ihs7ttrIxueDnPi8hfsL4VkQAui4msocE9kMEzHIlCMce1Af8fut0ggNijA4u
+UeAAbusi9mILlakuUKAGIGRErsIK8UtPYsT55sgA5iB59DEDHDMSIfMxpyEyL24aONIx3Y7KwuC5
+tLAJMtMZcuEAhsEJZuAA5gFnTEIUSCEt0yc8J2Y40EIt6K5A5OEAFINVlAMEsCUoXegSMGAHqGXs
+dkGgSskljZH6ZqoORrA5uWA4l5MLiFM5h44rAY0nsHLkyqPOGKPaVoAuXKEJZsAFUABbZKoRVOck
+YEctigQYTv8yHhdiiRbgAFpA9yTUS+wCAFIFARpABFBgAdiBBeDzpywtL+vJNqtkA/KEAI8QDk+x
+KP6kBM5jK3oC6LCS+S5OHyMxQA1zKZS0GzDDJsRyLAHAAiQUBH5gQjFzNRYABUSgARCANmqjTGuj
+Bo40Ta8SAbiFLmABTARgAYJOAUSABGhjepZCexBAHRSgTxVgAWwgUFdgBcRRCmazNpOE3KzPDGpi
+J/oT9QLIGFGPGe3wDk2yLWojHrdCW9L0SLlA1WAA4RqAzFqELE2gLrI0RVEUBGLgBSyABWAVVltA
+Qzq1JyTFAUggl9xURVuALElgVWwhBlqABVDjS8O0AeyUTFP/yVa5RQpsALvkaRcQwCtJLDcJaj95
+ag/t0RzGqQ5FSCQbBhopIAMy4C/JQADP0AFGFRcZA3tmAQBIYAFsqT3ptVXy4hYaYAJstVNvNS68
+BExwYAEQAAAU4LZ2UAp6oFVdxgVQYwUWoNCANQoOwP+Yxz+qJAdnQAF2DhLFdQCmrAi8dSRFdmRJ
+diRF6GRPFpqwYWVZlgL88gJ8soUO9qfCZAJidP4eQAHUswlAIgp6ViTeolb3FQGYAE5dYP5IQJPu
+9V7nIgpWAC4O4AAsAD+ilsNyhotIJCAEYDUUAAGozMl6YiXOriSokiT44uzMNG3V1kzbIpDKtANr
+AxTdTnsU/6A7XIUxLA1BRKAucEBRNgBeV5MSmoBes3RCBZIACOARhPYqawGoUKBAFiAXlnZp7XUu
+QmIk8vRvR2IlCutc2uRddhA/BnUFTEAE/nR0B9UGRtcGboAFbuB1Wxd2Y1d2afd1YVV2YxVWa+YA
+XIAFWvNuGWMXHwBL4ZQFLvRvEUABbACC6tUV4qUCEJcAHAFN1TQhKuIFBNYlahQKJrdnHY83YIdD
+N87H8qZKCe58B8IBlqE9M/MGFkAEIjFoAtcJJHQjagB6o1d6FbdT43JgMykmuvcWmuAGQKR8xNMX
+6yUJEgx9jwxKLKRUlKNLnGA/FABDEUAEVoAFMqwJSIAhTv8gfxHXEa4yIZysAWxgg/8FF5ogrUQN
+bewlAhqXgRl4L3I1VZ+DSwUgBlzgYf92A0gARm1ATu00AkA4hB1iA0zgSw9gZv9G94Kqhe/mYmFT
+ho8sF0ZFLkrFVd5UhVdYO8X0b50sarMlErIiGJbCLpmYflg4J2dnnhaYijnLOh/YFewVRb3kOVrh
+CWKABWzABGzA0hqgIRTiSBkXi+2KhYmMwDpCAAoVjt/rK5ZAVXu2S/D4boGXZ3VBTYEuIXTwkpXp
+iU3zNOtDbjYAIB35yB6xFrL4XnFgg8uEaTOZX6+STDx5k6JDvcjTFy7VIRogYk/5yLKnAVqZcEGi
+VQ5ABBb/YD07JC/q4uZq9SoboGmfqgWWiy3isUC054dNAFjT+JdNCgVUBYtXGSR6IJBTqzt4gFWY
+1j0XNyFsqxFNygLil09L1AIsIMfot5u9WZlwY46J+U01QkMaASBsIJ23lJk9YAam9ZkTIiD0eWhy
+gYBFQHClQID3+ch2wQUKd2l54AcOF3HPbkgs117luZ2Dbnt1Jxf2Ilcu+pTlOEXrGEOelQHy9xEm
++kLqN16ClpCXAgFiUpkiGolb+pcb4Gu+hJhbRSMCuYgF5VexWEWf9YPPjnrBlthqeYwImKWHWobl
++EKaFxY0wvHwF4QFBQFIpT3jtAZAeGzdWWYfemguQau3//p8ZcGn/zWLh9lLYmCpixikladxlSNM
+1JqpH6EBJPet/yWu51qGC7FxM6IuVqABiNdVHnKs19ohnKxg5UIXiLivCaBfeBaxpeAHTLQZHE+u
+FxsCH2AV7thLvsKuYUEWOruIr/lWG4AFXkGhLRuEkeMj4uQrrHEKRMIuU1vDUhmn87gQOaRVVnS3
+EVcYrhJJGyBvMcGzBaX8RBuqiK0S5NRBi/u4TsW23rRVfuA9GRkEcGCvBzt/BYWqCbksKWGCPriv
+K8BjQGIGUDoKunsKXOVxfZl+DqABBJwESCADBPzAETzBE1wEGNx0UQAF+vTBH9xPFUDCiZsQG7Je
+BcDxdP8QTJ51t9t7cSGxBXbxfud7rcVbgH/AM+3WAyxgVbr5EqRtCjwaAJrVhVZgAtaRwHlCX8uS
+RWtDx9dxTDfAx/V0YIc8EnXcMNslISZA+7wjOsS7VQKbI866LuSbvYVBxMP4EcM2ErR8uTFia3ni
+ATV2VVD4CX7ARadgD0hgAhBgOunHBnrCp1tABx5XeQ4gA2ih2hKiAXTgBiyALDfEVW/gzQG9BVyA
+z0XAZezZmTPgXx7XI+o1F8T0RKt8Asa6AtxbaHsCW9K0JOa7vmH8CfaiITk4AsRICg6JVLfWb5VH
+BLx7zuv80Bv95lRlFr4UbEXABRAABeJFfQWWnxyg10n/gB0KhARUV0wTItLjJDoMu3kFgJppuRVw
+oFchYXo9PU0ZwsdrFQOjeWspfBfKcsJ3TgRMAEwbXb8BoEQXoIJ7eB3wWZ+etixd4AHqki434ADe
+fNet1zrZdFpXQEx4nc4DvifePXk5DMoXo9ooHSPGXEPWNxfS29IWgNPdm4Q79X4rYNsHeZEzpBPe
+dkyJD8E0VyEAMhfiRVJ8+E9/WpnqHQHufUzoPNeVwc+L3fEe4GjVF9UKPuh4vs8BYExxNU7C+xbr
+eEIPCWwwopV/IG9RxeMdQNOll1M3eV+FORc0xAQc3QJIfAYcvXVrxgY2ILgFQKE3oERjMrtbJObv
+XV0d/y/Xe57XHU/mBR7VZpnOH+AGFnrXj9TZveNpVRmPp53N6fioLW3QWdTT7zd6O17EZd4i4hTk
+nYHNo0BM0dfteSKTYJbnB77g4Z75Bl5frZfOG4CAnczfmz1ObgzTy+S0LeKOlePpW2EFZqFWGz9/
+t3yQwXYDHn7yWSSAXUVMCzUX/Pt86/1XN98FOn8WPt96LWABXODmmuoAFsAEzj36LYAjzhjvV79F
+yh65BXi/6TimS6UFTGBafRwSmLrTlefh62K/hT8XFOABKNpVntWU30vz1RUIXJeNi+RYKRwAh6i1
+uikAgJVrtXgwezrFRjpFKZcNAblsPqM3NgHI43aDQP8CEaLlacfj73xM3lqQAEzUVJwQHCJWOCwu
+Pqyw5QksbBwIvF1iegigbFiQvQmwbCiglZqeopatLJK4YDUIPRQdJS2J2Dhk3CDQhjkoHBwYSfVK
+TWSkopLo3GUKxCCMNefp3eX9YAu82NAB1BBWhIfXKD2IuLDtCZgAVGa+rxN9vkGPJd/jq7K6OjQc
+AMgygkQJExtSDogotkTBChMmwkyptQRZvjOkqsGR42IDinTW8mSkBiLGDzcWbKBogOCClw0kRCxg
+0eZHGzjr2ll6h0nACpwZNanUVHGoqVUOWmG55SBgsYJSbCSB6othhgNdpAwkRpEoT4975CwAsAbH
+V2r/ZUXWBNHChQ0bB1jM0PTxkhwT8nSGFGCwksg5G1oI+CEAh2CuQ40idWBiwdJZUm0ZbJfw8cIV
+lBqEyTrRsADAmeII4AK45keQIdGapYvHtE126PB+5EkJUiQUANC9oML58L4ND24klMUL6oRFCnAh
+uIGZW/HKDlAwxiqxH+cDMcrs8dCDBInPIrOjDh+nBTBIdCX59E5NNt/YPR/98bQ7H2InN6wu3eXA
+LYooIqC4YJVYUHHxCy4k3ICFWNNtRdQGCCiwgAvXlWHBKJaQhtZPpZ1lligdNaNOWO58RlYkPfG1
+nkELkPGWUPMlY9QDC6yAAi8ObGACFsfZYFkGbZnA/wsAKARjQ1JgALBABkqgkBAx9nAlQiAAPCiC
+CQfo0BOLIZZWjZdcWqOaBy8gIIJ5l/AkVk6fxbYXGziA5MKQZKywBoz3rFCcnhMUx4iffzrAJ6CL
+EOMLQYwcsxsOsyAAQAQAbXCXaqlh5N2kIHDXA5hyGPQIbJEYtAYIcOrRwgZm8oQCDncmc0AGDTSQ
+gayzzkpCBtxxdyuusuJKAgK+IoBApMMSGymqu5Fwwg4jhIABLyTEME2lmEyr03oqRUutXkl6pV6a
+oopEpj0KiLAqq6jgwMIB8p1xgwvmpqKJDj30EIMTFrTQAr756rtvNoZZaEAKAaSQwgin0saapbCd
+Jv+ASi/Mdce2JiQsHnrgiuRrDDOYIAIL56JiAQIotGLJYJKIIMIj0VqyalsH2OlBEYB11gCFn5hc
+RmGG2RCBDwNrEEAJAFCsh8LUkoZ0WiA9PJce/3Qk3nqToKNhAxtsvIIIlYBsCgskHNDAAijEYMJ1
+CsDSAlQosKAAMLCK0EA2tj2yQANg98dCf/2tcECE86EQQQcBBBB0B2p0y+aGp4nngUozhDdDmRWH
+t0knlPv1A3k2vNh1uySY4A8JC5AyJh3cBKOACSs0YKUJHT3TAAMNsFBmKzY0oADYDXATOue7iVCB
+CgHIQLAPlzMstfJ60BEXah7QYYfyHkADLVpnA3D/wzPoeF6KC2OI0B8C7sSENu8sWIm767DjHuQC
+CBgAukq6u7D1OWjTzBUOycqggQwypAAD1kve8qQ2BwRA7nkGUYCJRNIHPEThEddbhwPWFQx2da9C
+uVOABYRhrgWkzAaAIFLKDqA1JLxgE5WAjpRUxx0QukABMSSdCFJoGB1sAAMp0AAPZXACEXApaeAp
+4DV+0IcDtgA1D4yCP1h2hhjgLgIKUGK0RjSDFViAexk0wwsAA4VHlGEGMyDDvAQwA8DgwAI4aEEM
+cGBDHMQgBhMSgAss0AM2tuAHL4jBAfLHFTkJrH8BUAEDokapSjWOcetRQB1AgI1HUuMHdgFAmaDz
+ejpyBQIBC6AJWmjigVA94wYY3KIZDmCCnZHyTivwGfEI1oEKeMo0QmQYLTdRh02BRAAWsJuwhhWs
+BpjAE2HSkJxAlMpjItMyHfgfAEPAAO0pTSSkWlp4IAma91ngDpB8Q0ncYIkXWIAFLMDXC+QwEmt+
+50M5QyY7PRcEADs=
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450
+Content-Type: image/gif;
+	name="image011.gif"
+Content-Transfer-Encoding: base64
+Content-ID: <001b01c68a59$4f153470$6401a8c0 at madhouse>
+
+R0lGODlhywDLAPcAAAAAAAEBAQICAgMDAwQEBAUFBQYGBgcHBwgICAkJCQoKCgsLCwwMDA0NDQ4O
+Dg8PDxAQEBERERISEhMTExQUFBUVFRYWFhcXFxgYGBkZGRoaGhsbGxwcHB0dHR4eHh8fHyAgICEh
+ISIiIiMjIyQkJCUlJSYmJicnJygoKCkpKSoqKisrKywsLC0tLS4uLi8vLzAwMDExMTIyMjMzMzQ0
+NDU1NTY2Njc3Nzg4ODk5OTo6Ojs7Ozw8PD09PT4+Pj8/P0BAQEFBQUJCQkNDQ0REREVFRUZGRkdH
+R0hISElJSUpKSktLS0xMTE1NTU5OTk9PT1BQUFFRUVJSUlNTU1RUVFVVVVZWVldXV1hYWFlZWVpa
+WltbW1xcXF1dXV5eXl9fX2BgYGFhYWJiYmNjY2RkZGVlZWZmZmdnZ2hoaGlpaWpqamtra2xsbG1t
+bW5ubm9vb3BwcHFxcXJycnNzc3R0dHV1dXZ2dnd3d3h4eHl5eXp6ent7e3x8fH19fX5+fn9/f4CA
+gIGBgYKCgoODg4SEhIWFhYaGhoeHh4iIiImJiYqKiouLi4yMjI2NjY6Ojo+Pj5CQkJGRkZKSkpOT
+k5SUlJWVlZaWlpeXl5iYmJmZmZqampubm5ycnJ2dnZ6enp+fn6CgoKGhoaKioqOjo6SkpKWlpaam
+pqenp6ioqKmpqaqqqqurq6ysrK2tra6urq+vr7CwsLGxsbKysrOzs7S0tLW1tba2tre3t7i4uLm5
+ubq6uru7u7y8vL29vb6+vr+/v8DAwMHBwcLCwsPDw8TExMXFxcbGxsfHx8jIyMnJycrKysvLy8zM
+zM3Nzc7Ozs/Pz9DQ0NHR0dLS0tPT09TU1NXV1dbW1tfX19jY2NnZ2dra2tvb29zc3N3d3d7e3t/f
+3+Dg4OHh4eLi4uPj4+Tk5OXl5ebm5ufn5+jo6Onp6erq6uvr6+zs7O3t7e7u7u/v7/Dw8PHx8fLy
+8vPz8/T09PX19fb29vf39/j4+Pn5+fr6+vv7+/z8/P39/f7+/v///yH5BAEAAP8ALAAAAADLAMsA
+QAj/AP8JHEiwoMGDCBMqXMiwocOHECNKnEixosWLClft2UhuYogCHQWu0rgnBICTKFMCKIBwD4BV
+B13uwUjz4aqVIRHeBNBxZ86DJmceZMJT4k6YCW+y/EeUScKgCckBCAFR5tCXNbNmxLkVgFCmAJwe
+9JnQJVKITcueFCtyas6dX6MWABDxJ8E9bLXq3cu3r0Ryq+xaJIeXydmFOwvsWZWWINHDFckJJqjU
+7p65K+P+Mwm5bV6GN6kWJMekwNnHiKf+I1cA88y5OeeKLujS6VGBtQdyPgj442SCczsLhApWM82m
+REEWbDwa9uaiMVU7zG0weUipS3mf/N12Jvac5Ex6/x3IGjplzEhrXycalqFLlYoNjvRLnLZXySVP
+GicPmLtfmoyJp5JKMLGmnGMrqTUbQVKZ959fgGnUk3D/lPSTa+d9BhaFrIUwGXXLjceQSf4V1JpC
+DQqW4oNVidiQVJ+RmBBqAhG1WGALWYWQjQa9pyFYPxp0EoVjScdbAT/etB+LE92koYwE+WaQSQfW
+6KJONwZWIpNcdunllzsqNhJM843UGpFgpqlml4wxcSOSkhEmGY6E/RMYTHuEt+SafPZJUwh5Vrga
+YHZ21Nt9Hc10p50wmRQCEyE4uqWflFbKlG2SCTrnagUSuthL3tHZqGFMDXrZpJamyiKPFRYQQmeA
+lf8WaZx4SuZWf5K5GpiOYzk2UElt2qmYh6oW+xBpWJnlkFSELTachjettlFJxC70Knmm2TnbqQIB
+Bqyx4Bb0aLcOgkZXTGJexgSkBrG2H6GrXbtatuV5Vy2j4OEYbqryVhdkpgyxp9KPJUlb2klImiQW
+UcS6uZrD+0Z85E+rLCiShXwBOtAq8c17WpUSh4wYpHMFmbHJIqccEZIjPcodadlGdBmcKtdMacU7
+JnmuzTyDGWGADfVbEMc9F2300UgnrfTSTDct30lCV9weeUMmNNdXJI3pakXsCcccc82ViyCazVns
+WcoNkl2hdPVd9e/UECnMUNXlCUfWU2IrBOVyahf/K/Wj07IHMoMHpxQzhJfBt6fTCEW47kdQM84Q
+zAPqR3VYOb2XXbdzgbybnWsZOS/IYDfEaohI7YTwq6geee9qazFoOWVTnx5265+PluBwK7mpb5RX
+2kdm1T1WfbV9hp2UY/AmDg46VqCbnZXt5G6+8XYiuWoZ8Q5BDTnUk7U5UuuTk29UVH17uTel3kKK
+UpWJGabRwSjnrtbiuLUnN95ew12p4ICLmZtCsr7nUIhXvGpL8KQivfw1MDTtUp65rIeiE2UEIQX0
+20eEk0AQFY8t2HmISfSGsJQEiWOA0lKcJHcRgN0FYZMhiooE5hYW2pBpLiOUljQ1nw7d8Ic9okqg
+/3C1Ea8oKlOBmo+g1gXEH0KqTGRCoqmElaf55ClRoFNUgUYCvSb2TF1z0tIRsTinMkZqJleskJLi
+VBqUedFvpUEKpLYEseJBjSNldNLkRIOzCollI9hK3xsnwkSOka9gy9kPE6uzJMaQ515MLI9iDEWt
+xZhvkNoRzGXwNy//EMZ33RpT6iiom5BgDIUiqRbGMKkXjS3ndXiJTIkOtzHfrVJorPQSIsFkyLtE
+qoa59FPFXPkrWtZkmIIMpsr62KMkNVCZksNlMQM1NOpBM2lzGuAmubOu33UrjtcMpzjHSc5yhkyJ
+1XGeyD75kUdxiEibJM/jWlM5GDqEYwjbyMGE5q9B2s0Gn0jaCJJatB89qswlr2NQcMiVt7aoM4SE
+xN6Oauc/cTHvVxedURejREpw1WtE47lbSyqKUU5Wh6S6w4pS8LY459wTpQmMWNsmKhqEknBPMpSZ
+6IoEPZuGDX8x9SLHjInR4OFTM3Cp4DMzcrzzcI8yAlpJ+kjTOh+2i5o8i9BGkmlOrQSIVFMyHODG
+V067yEk+SxLYL5kAHpTExaoMEo9hZoYmA0GGRmuzTX5S/8LVvUhzbSZ16vvyqdCX+GcnqNlJ26yT
+0p4MyUBvqajg2NqQp1LtQAvFiLIieCUfmRJu9nthYGHXURqFBi9R/YpPi3O25xV0O2l7ZLJQWlKF
+9FM3IrqtRXjlKPuILTcQnOhorSmQzAYVWxttzlJC+7ya7vR5EtXJ7hoHTAXmhbk0eY9xVmsilT7X
+gTaZ7sPABzySpcQ7c3FPbksYu9HUcWiQkRpKEroQF34JoiFCasmGRqXCERU00+qrLn+DXdCpc6Z8
+4i5/WwNWSxEmUimUbj1FRJosFTiV1RJpWPej2zeGZ2DXoRLk0oi66KQ1uUVy40AE5h/L8k7ATBoT
+ePYKn/8BEheuBiweUjOaVwyiOLjLG61BteM8/N6svQHbaGwRYkHSfg9hwskgQz8kQYuqbUUOwevR
+5HtHEv6EuK0FnYrJ9cyVypZ5sVLcRJPJmEvWLFJPs5iUnxOXC+PmlwPjDVm7uheG6bh4SCEMkhnk
+Zj77BZ8Dom/IkAUovGSm0IZO2TbJSCgd/jfSRYMsruq0wysKGsaY5tMTtbQuy3W6jNIqVLBCLTKc
+bUqFWpqVoBaFI1IvldWWSqwUXx2YSNWK0jCJzw4hNWZcM4mJ3tFhp/A0KF9rqUz4YQmviWbsBFOW
+07uutKeHuRoeCvqIZhpttfWC2DmhNjO7UnWFDNVrTx//sdG5UvS4H+TreMm7W+CR1S8lxKmO+CY8
+92aKUPpIcGDGct56+yOKY2I2jjlrbV5BGD1p6xihsIZzvbsOSB4M6XA+TljJ7Nh4f8SsoamzW/c6
+uJg1PhVQk3Nc/7j0UzqzS5STXJ2AxA1bMJYcMgGq4+JcZPZa996AgRBSNW+mboSio5xr6ydAx6TQ
+rxop341PIzCXsEpe22D50AsqpElPsUPNGrtZ7OHHiup3Bb6QdWXW5y43tMp13i528cXhIiZ2L6MU
+d2MnHWbrKsnYJWJ3beHWMIGPOsL33iVuIZxLespe33Mk88drBS/5auOdRL5bXVl+X3O/S0E7+nlw
+UVvp//K5delTFfoVv3b1i27oiv9FTNhDSO0TTonqN0Oh09veWIzp3TyvPaYbKf73yE++8pfP/OY7
+//mRbj30B/OyNkEYwgNFF5Unb0NzP+6MEEGW7o1TMQoxB/dTWZeb8IJ2+7xW3JZCNPanYhwwVwbj
+iVb/tJblmhlzxUpvI3sfARFDRjuDxz77dRVfgWVu0zjp1SSDVlhIsT9AsXBWIm4ZxEAq81EaJRYa
+ZhCZFVYTUR4oQx2lgyB7UoDqFWWyVyy9tRAL9YH5NVJ9pWCchSdrR2cK8YAvpUgWWCxLZltTE4IN
+WCTw9xwqZjkMKDs/GHMtqDvSo4Lh0iCc5BJLcYIIYrwyWxMRWMiEQoFgYEF6VsJmBwguXVheDMUh
+RFhi4ediwAMdHwYZ71EiQDZIYIhb5vFhPrhUSmIUa6hAg2OF6tc5k5JTL8VBTeg3TUU71bUxCnMj
++1QiU0eAjhJ4ArI4I8ER/2FffNIfmoV7lIUiJNF+LDKK3jRIjzNhATd9fvEeCPMkYYFOzid+9NdM
+NBc+mEFebSdV15MXCRQrXcdK7TNfbZVQCPYeqgQ3qrNRMaVd5EGKQ0NSGuhQNOQqoP9kLPBSFwLj
+KljFUCsxVt6kOmwhIIfxHnIoHUdhO1qmHrizcMHVID9Hb410iv/gYnHYIpMUJ/lRZ08YGuEBEo5S
+h1QiGFBxG/6IcVDnX1vihk44gYnYEBxDJKUzWWBTYHYGha5TWyJBbC/kgeRFI1RYJCBxG7yzMDyG
+YwroY0IBZoRHVIyFW6/zOXdYhwzhUtEoFg1iOJa0Yp2VEwP4PHbzWEQ4VIAhXgfRGtxBkwNBPDZY
+EX1YVIchg7vRYTmWZRboUizZkEnRHkEIPFdYUXoYXUWyVNb0kuVxfBfoWvYRhQnyHSM1dsd1N1J4
+OWiCGqUjSalTZW8IPXMUImKYV3f/IjhRSXFcgxIa0pRaCWaIOZYndSUyYm6BJpZHSSzsmDiSdVEk
+CRZT8T2VV0uviJYOwVxNWTe8MxkUODnYQxiYMTiI9j6u5EigcRby9VcUIWPL9F02yZPmgUJngYyH
+pBK1JzJOF0Fp1Zle4mJ1+GFERTm62DO0AimR0jGyFo0WaGZC8pBdopgDcoTsg1rQSYxWMiDWuFWy
+iZSXg1MoZZ1HdnLsw2+OmIvzxWGBFxwrtGapoXBLhV1UqSZ18iWmCFX11C+kySBUeZE9lmRdoxBu
+eIdNVDiP4j7V4omG+DRBImVZWT0PkRwoIpkCwZD70j5RBRJadj38SHPJtVkVKBxn//lBpsNjJ0Uk
+SzhlxWKZvAhx39hyP1FgeDWiSHiTahEkt6WUKXYsOQgWKsKhorYWM3YVkPGH5MIWBpVm/4ctpCeD
+z9MuuSlh7Shg2UgpCIUqMXVhE6p2k0SDVrNwVJKSc/OEopUUitalwsSNe7aDFsOSTwlYL2UyCiZJ
+VOYh9ZmiEGGeOnFA3Pkg7BSQ9qmR0QGlRSo7z7SiqhmBxVVPD0WbwYSivahQzwQ2SKqAJGFWhROL
+0IepsLMz3cFTh3Gh8LkS1siKqUFBI6qC7KFfheqqQiiNz/Vhj7KaoGmrTME6cyIelxZ5egaNbAKd
+A2R5D9YaLPNFx+MUh2Kpvgomcf8EbZQGZ9PKJxDkiTrkKaRRhtlaE/GUKKiGbVzUq+EaMH46RoJS
+KPhBRenqF/pGjpvGrlc0Pu4Sr3shFcmGJ8FHWSoEbutmJ5OorxghJsBGsF5Ra1JEa9lnsMchP/ii
+KYKSQwx7rYASeNyXrTdBa1tErraCr4zirkwBJ2QyTOj6fGVXKrzGKf4KKhMLRTD7amwKsac6bINy
+si47Kx0BrZZmWJSGnRAbkRNCsv06sh27bmQkPlE0KjYLGiARKluUs5pSJ+7yapliIz30KRursqZx
+atx6tJ72c6KiLUKEGw/7tGPxKMKaMFYURpxCtdt0r/hBFZsHrr5aHpjzMFiTH0j/Qnzvmit4JCdr
+dI86FYqE0bXlhBf08kT1xbjy0ybA0q2VASN6E2hLsbJSUTGJUquRFpE1sopF92D5ZLUVwhGXQTYH
+10cHt0p+lHz8irZXRlSM4Sq5mDBxciaToxx9dLWv5DKrx06J4qJRohkr6xivAp87mRELQiyGVLuB
+5nqrpzGp+xAFU7uAUmQOEh5uNHcQw0wlqxEBlbJvhBrBiRiDU3SpBBQSeRbhEWJux7jxaDB4C033
+qL5tV3/GwRox9C6Q9BV9yVi1G4zz1ku+9yIodrzjJZ+8EaEZxrt0s4p+Zx74WxZ6qn5kkr6NCjHE
+yioNNkwfwawSPE7B6brWkkwdouI+tlFms7FIDkd3d0a+QvVA9dY4BftCJqQT7JlKhrJB8WJKoVh6
+FUwZqBXCtXireeZ1DGNJ3hJu8VI7Yod8l2acyzMgHPQZntgqgpYtsUSsyPdX7/W+fyEwQSwu+BNA
+QdyNyFd0jFcjZawVDIRVHfKNvem5xga+bHcQNUt4UJoW4UEbu2d7Rbcu4OF5+3ogoPvEATWdrBge
+sKJPimsiWKMcfq+mr17cJZecSm8cr44LeZyntt3iaIJ7bDsMsSsqefJKxfFqwpwiHhuLLJsMyk5S
+dVUXjjQzgpUEylpRwbJINXasyzoBpAUVyMAcEXj8K85UzIfcEsmszJcXJPgbLc48PWnFdTL8tDKH
+smORttNsFKrHvy1BzAabid83f5WzJbR5wMWcuKI0P9+3qomozismzt2ces1KOHjmKhC2t/VME+2j
+if0c0AI90ARd0AadEAEBADs=
+
+------=_NextPart_000_001C_01C68A1E.A2C4B450--
diff --git a/lib/tests/input/sacCerTest.gff3 b/lib/tests/input/sacCerTest.gff3
new file mode 100644
index 0000000..0675ef6
--- /dev/null
+++ b/lib/tests/input/sacCerTest.gff3
@@ -0,0 +1,43 @@
+##gff-version 3
+#date Wed Apr  1 19:50:12 2009
+#
+# Saccharomyces cerevisiae S288C genome
+#
+# has empty Alias with multiple values:
+chrI	SGD	chromosome	1	230208	.	.	.	ID=chrI;dbxref=NCBI:NC_001133
+chrI	SGD	repeat_region	1	62	.	-	.	ID=TEL01L-TR;Name=TEL01L-TR;Note=Terminal%20stretch%20of%20telomeric%20repeats%20on%20the%20left%20arm%20of%20Chromosome%20I;dbxref=SGD:S000028864
+chrI	SGD	telomere	1	801	.	-	.	ID=TEL01L;Name=TEL01L;Note=Telomeric%20region%20on%20the%20left%20arm%20of%20Chromosome%20I%3B%20composed%20of%20an%20X%20element%20core%20sequence%2C%20X%20element%20combinatorial%20repeats%2C%20and%20a%20short%20terminal%20stretch%20of%20telomeric%20repeats;dbxref=SGD:S000028862
+chrI	SGD	repeat_region	63	336	.	-	.	ID=TEL01L-XR;Name=TEL01L-XR;Note=Telomeric%20X%20element%20combinatorial%20Repeat%20region%20on%20the%20left%20arm%20of%20Chromosome%20I%3B%20contains%20repeats%20of%20the%20D%2C%20C%2C%20B%20and%20A%20types%2C%20as%20well%20as%20Tbf1p%20binding%20sites%3B%20formerly%20called%20SubTelomeric%20Repeats;dbxref=SGD:S000028866
+chrI	SGD	gene	335	649	.	+	.	ID=YAL069W;Name=YAL069W;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Dubious%20open%20reading%20frame%20unlikely%20to%20encode%20a%20protein%2C%20based%20on%20available%20experimental%20and%20comparative%20sequence%20data;dbxref=SGD:S000002143;orf_classification=Dubious
+chrI	SGD	CDS	335	649	.	+	0	Parent=YAL069W;Name=YAL069W;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Dubious%20open%20reading%20frame%20unlikely%20to%20encode%20a%20protein%2C%20based%20on%20available%20experimental%20and%20comparative%20sequence%20data;dbxref=SGD:S000002143;orf_classification=Dubious
+chrI	SGD	repeat_region	337	801	.	-	.	ID=TEL01L-XC;Name=TEL01L-XC;Note=Telomeric%20X%20element%20Core%20sequence%20on%20the%20left%20arm%20of%20Chromosome%20I%3B%20contains%20an%20ARS%20consensus%20sequence%2C%20an%20Abf1p%20binding%20site%20consensus%20sequence%20and%20two%20small%20overlapping%20ORFs%20(YAL068W-A%20and%20YAL069W);dbxref=SGD:S000028865
+chrI	SGD	nucleotide_match	753	763	.	-	.	Parent=TEL01L-XC;Name=TEL01L-XC;Note=Telomeric%20X%20element%20Core%20sequence%20on%20the%20left%20arm%20of%20Chromosome%20I%3B%20contains%20an%20ARS%20consensus%20sequence%2C%20an%20Abf1p%20binding%20site%20consensus%20sequence%20and%20two%20small%20overlapping%20ORFs%20(YAL068W-A%20and%20YAL069W);dbxref=SGD:S000028865
+chrI	SGD	binding_site	532	544	.	-	.	Parent=TEL01L-XC;Name=TEL01L-XC;Note=Telomeric%20X%20element%20Core%20sequence%20on%20the%20left%20arm%20of%20Chromosome%20I%3B%20contains%20an%20ARS%20consensus%20sequence%2C%20an%20Abf1p%20binding%20site%20consensus%20sequence%20and%20two%20small%20overlapping%20ORFs%20(YAL068W-A%20and%20YAL069W);dbxref=SGD:S000028865
+chrI	SGD	gene	538	792	.	+	.	ID=YAL068W-A;Name=YAL068W-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Dubious%20open%20reading%20frame%20unlikely%20to%20encode%20a%20protein%3B%20identified%20by%20gene-trapping%2C%20microarray-based%20expression%20analysis%2C%20and%20genome-wide%20homology%20searching;dbxref=SGD:S000028594;orf_classification=Dubious
+chrI	SGD	CDS	538	792	.	+	0	Parent=YAL068W-A;Name=YAL068W-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Dubious%20open%20reading%20frame%20unlikely%20to%20encode%20a%20protein%3B%20identified%20by%20gene-trapping%2C%20microarray-based%20expression%20analysis%2C%20and%20genome-wide%20homology%20searching;dbxref=SGD:S000028594;orf_classification=Dubious
+chrI	SGD	ARS	650	1791	.	.	.	ID=ARS102;Name=ARS102;Alias=ARSI-1;Note=Autonomously%20Replicating%20Sequence;dbxref=SGD:S000121252
+chrI	SGD	gene	1807	2169	.	-	.	ID=YAL068C;Name=YAL068C;gene=PAU8;Alias=PAU8;Ontology_term=GO:0003674,GO:0005575,GO:0030437,GO:0045944;Note=Hypothetical%20protein%20of%20unknown%20function%3B%20YAL068C%20is%20not%20an%20essential%20gene;dbxref=SGD:S000002142;orf_classification=Uncharacterized
+chrI	SGD	CDS	1807	2169	.	-	0	Parent=YAL068C;Name=YAL068C;gene=PAU8;Alias=PAU8;Ontology_term=GO:0003674,GO:0005575,GO:0030437,GO:0045944;Note=Hypothetical%20protein%20of%20unknown%20function%3B%20YAL068C%20is%20not%20an%20essential%20gene;dbxref=SGD:S000002142;orf_classification=Uncharacterized
+chrI	SGD	gene	2480	2707	.	+	.	ID=YAL067W-A;Name=YAL067W-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative%20protein%20of%20unknown%20function%3B%20identified%20by%20gene-trapping%2C%20microarray-based%20expression%20analysis%2C%20and%20genome-wide%20homology%20searching;dbxref=SGD:S000028593;orf_classification=Uncharacterized
+chrI	SGD	CDS	2480	2707	.	+	0	Parent=YAL067W-A;Name=YAL067W-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative%20protein%20of%20unknown%20function%3B%20identified%20by%20gene-trapping%2C%20microarray-based%20expression%20analysis%2C%20and%20genome-wide%20homology%20searching;dbxref=SGD:S000028593;orf_classification=Uncharacterized
+chrI	SGD	gene	7236	9017	.	-	.	ID=YAL067C;Name=YAL067C;gene=SEO1;Alias=SEO1;Ontology_term=GO:0005215,GO:0006810,GO:0016020;Note=Putative%20permease%2C%20member%20of%20the%20allantoate%20transporter%20subfamily%20of%20the%20major%20facilitator%20superfamily%3B%20mutation%20confers%20resistance%20to%20ethionine%20sulfoxide;dbxref=SGD:S000000062;orf_classification=Verified
+chrI	SGD	CDS	7236	9017	.	-	0	Parent=YAL067C;Name=YAL067C;gene=SEO1;Alias=SEO1;Ontology_term=GO:0005215,GO:0006810,GO:0016020;Note=Putative%20permease%2C%20member%20of%20the%20allantoate%20transporter%20subfamily%20of%20the%20major%20facilitator%20superfamily%3B%20mutation%20confers%20resistance%20to%20ethionine%20sulfoxide;dbxref=SGD:S000000062;orf_classification=Verified
+chrI	SGD	ARS	7998	8548	.	.	.	ID=ARS103;Name=ARS103;Alias=ARSI-8;Note=Autonomously%20Replicating%20Sequence;dbxref=SGD:S000121253
+chrI	SGD	gene	10092	10400	.	+	.	ID=YAL066W;Name=YAL066W;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Dubious%20open%20reading%20frame%20unlikely%20to%20encode%20a%20protein%2C%20based%20on%20available%20experimental%20and%20comparative%20sequence%20data;dbxref=SGD:S000000061;orf_classification=Dubious
+chrI	SGD	CDS	10092	10400	.	+	0	Parent=YAL066W;Name=YAL066W;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Dubious%20open%20reading%20frame%20unlikely%20to%20encode%20a%20protein%2C%20based%20on%20available%20experimental%20and%20comparative%20sequence%20data;dbxref=SGD:S000000061;orf_classification=Dubious
+chrI	SGD	gene	11566	11952	.	-	.	ID=YAL065C;Name=YAL065C;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative%20protein%20of%20unknown%20function%3B%20has%20homology%20to%20FLO1%3B%20possible%20pseudogene;dbxref=SGD:S000001817;orf_classification=Uncharacterized
+chrI	SGD	CDS	11566	11952	.	-	0	Parent=YAL065C;Name=YAL065C;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative%20protein%20of%20unknown%20function%3B%20has%20homology%20to%20FLO1%3B%20possible%20pseudogene;dbxref=SGD:S000001817;orf_classification=Uncharacterized
+chrI	SGD	gene	12047	12427	.	+	.	ID=YAL064W-B;Name=YAL064W-B;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Fungal-specific%20protein%20of%20unknown%20function;dbxref=SGD:S000002141;orf_classification=Uncharacterized
+chrI	SGD	CDS	12047	12427	.	+	0	Parent=YAL064W-B;Name=YAL064W-B;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Fungal-specific%20protein%20of%20unknown%20function;dbxref=SGD:S000002141;orf_classification=Uncharacterized
+chrI	SGD	gene	13364	13744	.	-	.	ID=YAL064C-A;Name=YAL064C-A;gene=TDA8;Alias=TDA8,YAL065C-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative%20protein%20of%20unknown%20function%3B%20YAL064C-A%20is%20not%20an%20essential%20gene;dbxref=SGD:S000002140;orf_classification=Uncharacterized
+chrI	SGD	CDS	13364	13744	.	-	0	Parent=YAL064C-A;Name=YAL064C-A;gene=TDA8;Alias=TDA8,YAL065C-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative%20protein%20of%20unknown%20function%3B%20YAL064C-A%20is%20not%20an%20essential%20gene;dbxref=SGD:S000002140;orf_classification=Uncharacterized
+chrI	SGD	gene	21526	21852	.	+	.	ID=YAL064W;Name=YAL064W;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Protein%20of%20unknown%20function%3B%20may%20interact%20with%20ribosomes%2C%20based%20on%20co-purification%20experiments;dbxref=SGD:S000000060;orf_classification=Verified
+chrI	SGD	CDS	21526	21852	.	+	0	Parent=YAL064W;Name=YAL064W;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Protein%20of%20unknown%20function%3B%20may%20interact%20with%20ribosomes%2C%20based%20on%20co-purification%20experiments;dbxref=SGD:S000000060;orf_classification=Verified
+chrI	SGD	long_terminal_repeat	22232	22554	.	+	.	ID=YALWdelta1;Name=YALWdelta1;Ontology_term=SO:0000286;Note=Ty1%20LTR;dbxref=SGD:S000006787
+chrI	SGD	gene	22397	22687	.	-	.	ID=YAL063C-A;Name=YAL063C-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative%20protein%20of%20unknown%20function%3B%20identified%20by%20expression%20profiling%20and%20mass%20spectrometry;dbxref=SGD:S000028813;orf_classification=Uncharacterized
+chrI	SGD	CDS	22397	22687	.	-	0	Parent=YAL063C-A;Name=YAL063C-A;Ontology_term=GO:0003674,GO:0005575,GO:0008150;Note=Putative%20protein%20of%20unknown%20function%3B%20identified%20by%20expression%20profiling%20and%20mass%20spectrometry;dbxref=SGD:S000028813;orf_classification=Uncharacterized
+chrI	landmark	region	24001	27969	.	-	.	ID=FLO9
+# has empty Note:
+chrXVI	SGD	gene	101608	102702	.	-	.	ID=YPL236C;Name=YPL236C;gene=ENV7;Alias=ENV7;Ontology_term=GO:0000329,GO:0004674,GO:0008150;Note=;dbxref=SGD:S000006157;orf_classification=Uncharacterized
+chrXVI	SGD	CDS	101608	102702	.	-	0	Parent=YPL236C;Name=YPL236C;gene=ENV7;Alias=ENV7;Ontology_term=GO:0000329,GO:0004674,GO:0008150;Note=;dbxref=SGD:S000006157;orf_classification=Uncharacterized
+
diff --git a/lib/tests/input/simple1.txt b/lib/tests/input/simple1.txt
new file mode 100644
index 0000000..b566061
--- /dev/null
+++ b/lib/tests/input/simple1.txt
@@ -0,0 +1,6 @@
+one
+two
+three
+four
+five
+six
diff --git a/lib/tests/input/specialCasesTest.gff3 b/lib/tests/input/specialCasesTest.gff3
new file mode 100644
index 0000000..b3b6b25
--- /dev/null
+++ b/lib/tests/input/specialCasesTest.gff3
@@ -0,0 +1,11 @@
+##gff-version 3
+##sequence-region 2L 1 23011544
+##organism 2L Drosophila melanogaster
+# Target attribute
+2L	blastx_masked_aa_SPTR.dmel	match	22229583	22229699	.	-	.	ID=:1577877_blastx_masked_aa_SPTR.dmel;Name=Q9VKH2-AE003783.4-aa_SPTR.dmel-blastx_masked;program=blastx_masked;programversion=1.0;sourcename=aa_SPTR.dmel;Target=Q9VKH2 596 629 +
+2L	blastx_masked_aa_SPTR.dmel	match	22229583	22229699	.	-	.	ID=:1577939_blastx_masked_aa_SPTR.dmel;Name=P39770-AE003783.4-aa_SPTR.dmel-blastx_masked;program=blastx_masked;programversion=1.0;sourcename=aa_SPTR.dmel;Target=P39770 596 629 +
+2L	blastx_masked_aa_SPTR.dmel	match_part	22229583	22229699	48	-	.	Name=:5411425;Parent=:1577877_blastx_masked_aa_SPTR.dmel;target_type=protein;Target=Q9VKH2 596 629
+2L	blastx_masked_aa_SPTR.dmel	match_part	22229583	22229699	48	-	.	Name=:5411530;Parent=:1577939_blastx_masked_aa_SPTR.dmel;target_type=protein;Target=P39770 596 629
+
+# empty attr value
+chr	RNA	RNA	788298	788656	.	+	.	ID=tmRNA;Name=;Note=regulatory ncRNA
diff --git a/lib/tests/makefile b/lib/tests/makefile
new file mode 100644
index 0000000..4825796
--- /dev/null
+++ b/lib/tests/makefile
@@ -0,0 +1,309 @@
+include ../../inc/common.mk
+
+ifeq (${USE_TABIX},1)
+    TABIX_TESTS=tabixTest vcfTest
+else
+    TABIX_TESTS=
+endif
+
+MYLIBDIR = ../../lib/${MACHTYPE}
+MYLIBS = ${MYLIBDIR}/jkweb.a
+BIN_DIR = bin/${MACHTYPE}
+
+test: errCatchTest htmlPageTest htmlExpandUrlTest pipelineTests dyStringTest \
+    mimeTests base64Tests quotedPTests safeTest hashTest fetchUrlTest gff3Test \
+    ${TABIX_TESTS} hacTreeTest
+	rm -r output fetchUrlTest
+	@echo tested all
+
+
+mkdirs:
+	${MKDIR} output ${BIN_DIR}
+
+errCatchTest: errCatchTest.o ${MYLIBS} mkdirs
+	${CC} ${COPT} -o ${BIN_DIR}/errCatchTest errCatchTest.o ${MYLIBS} ${L}
+	${STRIP} ${BIN_DIR}/errCatchTest${EXE}
+	${BIN_DIR}/errCatchTest secret > output/errCatch.good
+	diff expected/errCatch.good output/errCatch.good
+	${BIN_DIR}/errCatchTest bad > output/errCatch.bad
+	diff expected/errCatch.bad output/errCatch.bad
+
+htmlExpandUrlTest: htmlExpandUrlTest.o ${MYLIBS} mkdirs
+	${CC} ${COPT} -o ${BIN_DIR}/htmlExpandUrlTest htmlExpandUrlTest.o ${MYLIBS} ${L}
+	${STRIP} ${BIN_DIR}/htmlExpandUrlTest${EXE}
+	${BIN_DIR}/htmlExpandUrlTest > output/htmlExpandUrlTest 2>&1
+	diff expected/htmlExpandUrlTest output/htmlExpandUrlTest
+
+htmlPageTest: htmlPageTest.o ${MYLIBS} mkdirs
+	${CC} ${COPT} -o ${BIN_DIR}/htmlPageTest htmlPageTest.o ${MYLIBS} ${L}
+	${STRIP} ${BIN_DIR}/htmlPageTest${EXE}
+	${BIN_DIR}/htmlPageTest input/google.html > output/google.out
+	diff expected/google.out output/google.out
+
+pipelineTests: 	pipelineWrite pipelineWriteMult pipelineWriteFd \
+		pipelineRead pipelineReadMult pipelineReadFd pipelineReadMem \
+		pipelineExitCode pipelineWriteErr pipelineExecError
+
+pipelineWrite: ${BIN_DIR}/pipelineTester mkdirs
+	${BIN_DIR}/pipelineTester -write -pipeData=input/simple1.txt -otherEnd=output/$@.out.gz "gzip -1"
+	gunzip -c output/$@.out.gz > output/$@.out
+	diff -b input/simple1.txt output/$@.out
+
+# add come junk to make sure output gets truncated
+pipelineWriteMult: ${BIN_DIR}/pipelineTester mkdirs
+	cat input/google.html > output/$@.wc
+	${BIN_DIR}/pipelineTester -write -pipeData=input/simple1.txt -otherEnd=output/$@.wc "gzip -1" "gzip -dc" "wc"
+	diff -b expected/simple1.wc output/$@.wc
+
+pipelineWriteFd: ${BIN_DIR}/pipelineTester mkdirs
+	${BIN_DIR}/pipelineTester -fdApi -write -pipeData=input/simple1.txt -otherEnd=output/$@.out.gz "gzip -1"
+	gunzip -c output/$@.out.gz > output/$@.out
+	diff -b input/simple1.txt output/$@.out
+
+pipelineRead: ${BIN_DIR}/pipelineTester mkdirs
+	gzip -1c input/simple1.txt >output/$@.in.gz
+	${BIN_DIR}/pipelineTester -otherEnd=output/$@.in.gz -pipeData=output/$@.out "gzip -dc"
+	diff -b input/simple1.txt output/$@.out
+
+pipelineReadMult: ${BIN_DIR}/pipelineTester mkdirs
+	${BIN_DIR}/pipelineTester -pipeData=output/$@.wc -otherEnd=input/simple1.txt "gzip -1" "gzip -dc" "wc"
+	diff -b expected/simple1.wc output/$@.wc
+
+pipelineReadFd: ${BIN_DIR}/pipelineTester mkdirs
+	gzip -1c input/simple1.txt >output/$@.in.gz
+	${BIN_DIR}/pipelineTester -fdApi -otherEnd=output/$@.in.gz -pipeData=output/$@.out "gzip -dc"
+	diff -b input/simple1.txt output/$@.out
+
+pipelineReadMem: ${BIN_DIR}/pipelineTester mkdirs
+	gzip -1c input/simple1.txt >output/$@.in.gz
+	${BIN_DIR}/pipelineTester -memApi -otherEnd=output/$@.in.gz -pipeData=output/$@.out "gzip -dc"
+	diff -b input/simple1.txt output/$@.out
+
+# make sure pipe exit code makes it back
+pipelineExitCode: ${BIN_DIR}/pipelineTester
+	${BIN_DIR}/pipelineTester -exitCode=13 "sh -c 'exit 13'"
+
+# test redirecting stderr, see that two process can write stderr, but only
+# the second's stdout should make it to the end of the pipe.  Since order
+# of writes to stderr is determined by process scheduling and when a process
+# terminates due to SIGPIPE, just check that stderr was not empty, don't
+# check contents.
+pipelineWriteErr: ${BIN_DIR}/pipelineTester mkdirs
+	${BIN_DIR}/pipelineTester -write -otherEnd=output/$@.out -stderr=output/$@.err "sh -c 'echo OUT; echo ERR >&2'"  "sh -c 'echo OUT2; echo ERR2 >&2'"
+	diff -b expected/$@.out output/$@.out
+	test -s output/$@.err
+
+# exec a non-existent program
+pipelineExecError: ${BIN_DIR}/pipelineTester mkdirs
+	if ${BIN_DIR}/pipelineTester -write -stderr=output/$@.err "./thatDoesNotCompute" 2> output/$@.parent.err ; then false else true ; fi
+	diff -b expected/$@.err output/$@.err
+	diff -b expected/$@.parent.err output/$@.parent.err
+
+${BIN_DIR}/pipelineTester:  mkdirs pipelineTester.o ${MYLIBS}
+	${CC} ${COPT} -o ${BIN_DIR}/pipelineTester pipelineTester.o ${MYLIBS} ${L}
+
+
+dyStringTest: ${BIN_DIR}/dyStringTester mkdirs
+	${BIN_DIR}/dyStringTester
+
+${BIN_DIR}/dyStringTester:  mkdirs dyStringTester.o ${MYLIBS}
+	${CC} ${COPT} -o ${BIN_DIR}/dyStringTester dyStringTester.o ${MYLIBS} ${L}
+
+
+mimeTests: mime1 mime2 mime3 mime4 mimeBin mime5 mimeAltHead mimeAutoBoundary mimeBlat
+
+${BIN_DIR}/mimeTester:  mkdirs mimeTester.o ${MYLIBS}
+	${CC} ${COPT} -o ${BIN_DIR}/mimeTester mimeTester.o ${MYLIBS} ${L}
+
+
+mime1: ${BIN_DIR}/mimeTester mkdirs
+	${BIN_DIR}/mimeTester < input/$@.txt > output/$@.out
+	diff expected/$@.out output/$@.out
+
+mime2: ${BIN_DIR}/mimeTester mkdirs
+	${BIN_DIR}/mimeTester < input/$@.txt > output/$@.out
+	diff expected/$@.out output/$@.out
+
+mime3: ${BIN_DIR}/mimeTester mkdirs
+	${BIN_DIR}/mimeTester < input/$@.txt > output/$@.out
+	diff expected/$@.out output/$@.out
+
+mime4: ${BIN_DIR}/mimeTester mkdirs
+	${BIN_DIR}/mimeTester < input/$@.txt > output/$@.out
+	diff expected/$@.out output/$@.out
+
+mimeBin: ${BIN_DIR}/mimeTester mkdirs
+	${BIN_DIR}/mimeTester < input/$@.txt > output/$@.out
+	diff expected/$@.out output/$@.out
+
+mime5: ${BIN_DIR}/mimeTester mkdirs
+	${BIN_DIR}/mimeTester < input/$@.txt > output/$@.out
+	diff expected/$@.out output/$@.out
+
+mimeAltHead: ${BIN_DIR}/mimeTester mkdirs
+	${BIN_DIR}/mimeTester -altHeader='CONTENT_TYPE=multipart/form-data; boundary=----------0xKhTmLbOuNdArY' < input/$@.txt > output/$@.out
+	diff expected/$@.out output/$@.out
+
+mimeAutoBoundary: ${BIN_DIR}/mimeTester mkdirs
+	${BIN_DIR}/mimeTester -autoBoundary < input/$@.txt > output/$@.out
+	diff expected/$@.out output/$@.out
+
+mimeBlat: ${BIN_DIR}/mimeTester mkdirs
+	${BIN_DIR}/mimeTester -altHeader='CONTENT_TYPE=multipart/form-data; boundary=----------0xKhTmLbOuNdArY' < input/$@.txt > output/$@.out
+	diff expected/$@.out output/$@.out
+
+mimeSeries: ${BIN_DIR}/mimeTester mkdirs
+	${BIN_DIR}/mimeTester -sizeSeries=3000
+
+${BIN_DIR}/htmlMimeTest:  mkdirs htmlMimeTest.o ${MYLIBS}
+	${CC} ${COPT} -o ${BIN_DIR}/htmlMimeTest htmlMimeTest.o ${MYLIBS} ${L}
+
+htmlMime1: ${BIN_DIR}/htmlMimeTest mkdirs
+	${BIN_DIR}/htmlMimeTest http://hgwdev.cse.ucsc.edu/cgi-bin/hgBlat input/htmlMime.txt 3490 3502 > output/$@.out
+	diff expected/$@.out output/$@.out
+
+
+base64Tests: base64Encode base64Decode
+
+${BIN_DIR}/testBase64:  mkdirs testBase64.o ${MYLIBS}
+	${CC} ${COPT} -o ${BIN_DIR}/testBase64 testBase64.o ${MYLIBS} ${L}
+
+base64Encode: ${BIN_DIR}/testBase64 mkdirs
+	${BIN_DIR}/testBase64 'My Test String' > output/$@.out
+	diff expected/$@.out output/$@.out
+
+base64Decode: ${BIN_DIR}/testBase64 mkdirs
+	${BIN_DIR}/testBase64 'TXkgVGVzdCBTdHJpbmc=' > output/$@.out
+	diff expected/$@.out output/$@.out
+
+
+
+quotedPTests: quotedPEncode quotedPDecode
+
+${BIN_DIR}/testQuotedP:  mkdirs testQuotedP.o ${MYLIBS}
+	${CC} ${COPT} -o ${BIN_DIR}/testQuotedP testQuotedP.o ${MYLIBS} ${L}
+
+quotedPEncode: ${BIN_DIR}/testQuotedP mkdirs
+	${BIN_DIR}/testQuotedP 'taxes are quite high ' > output/$@.out
+	diff expected/$@.out output/$@.out
+
+quotedPDecode: ${BIN_DIR}/testQuotedP mkdirs
+	${BIN_DIR}/testQuotedP 'taxes=20are=20quite=20high=20=' > output/$@.out
+	diff expected/$@.out output/$@.out
+
+${BIN_DIR}/mimeDecodeTest:  mkdirs mimeDecodeTest.o ${MYLIBS}
+	${CC} ${COPT} -o ${BIN_DIR}/mimeDecodeTest mimeDecodeTest.o ${MYLIBS} ${L}
+
+mimeDecodeTest: ${BIN_DIR}/mimeDecodeTest mkdirs
+	${BIN_DIR}/mimeDecodeTest -cid -autoBoundary output < input/$@.txt
+	diff expected/noName1.html output/noName1.html
+
+${BIN_DIR}/safeTester:  mkdirs safeTester.o ${MYLIBS}
+	${CC} ${COPT} -o ${BIN_DIR}/safeTester safeTester.o ${MYLIBS} ${L}
+
+safeTest: ${BIN_DIR}/safeTester mkdirs
+	${BIN_DIR}/safeTester
+
+hashTest: hashTest1
+
+${BIN_DIR}/testHash:  mkdirs testHash.o ${MYLIBS}
+	${CC} ${COPT} -o ${BIN_DIR}/testHash testHash.o ${MYLIBS} ${L}
+
+hashTest1: ${BIN_DIR}/testHash mkdirs
+	${BIN_DIR}/testHash input/$@.txt > output/$@.out
+	diff expected/$@.out output/$@.out
+
+${BIN_DIR}/testQuotedString: mkdirs testQuotedString.o ${MYLIBS}
+	${CC} ${COPT} -o ${BIN_DIR}/testQuotedString testQuotedString.o ${MYLIBS} ${L}
+
+testQuotedString:	${BIN_DIR}/testQuotedString mkdirs
+	${BIN_DIR}/testQuotedString -verbose=2 quote this\\ following
+
+miniBlat:  mkdirs miniBlat.o ${MYLIBS}
+	${CC} ${COPT} -o miniBlat miniBlat.o ${MYLIBS} ${L}
+
+fetchUrlTest:  mkdirs fetchUrlTest.o ${MYLIBS}
+	${CC} ${COPT} -o fetchUrlTest fetchUrlTest.o ${MYLIBS} ${L}
+
+##
+# gff3 tests
+##
+gff3Tester=${BIN_DIR}/gff3Tester
+gff3Test: gff3SacCerTest gff3ErrorCasesTest gff3DiscontiousTest
+
+# FIXME: doesn't work yet
+# gff3SpecialCasesTest
+
+gff3SacCerTest: ${gff3Tester} mkdirs
+	${gff3Tester} input/sacCerTest.gff3 output/$@.out
+	diff expected/$@.out output/$@.out
+gff3SpecialCasesTest: ${gff3Tester} mkdirs
+	${gff3Tester} input/specialCasesTest.gff3 output/$@.out
+	diff expected/$@.out output/$@.out
+gff3ErrorCasesTest: ${gff3Tester} mkdirs
+	if ${gff3Tester} input/errorCasesTest.gff3 /dev/null >output/$@.err 2>&1 ; then exit 0 else exit 1; fi
+	diff expected/$@.err output/$@.err
+gff3DiscontiousTest: ${gff3Tester} mkdirs
+	${gff3Tester} input/discontinuous.gff3 output/$@.out
+	diff expected/$@.out output/$@.out
+
+${BIN_DIR}/gff3Tester: gff3Tester.o ${MYLIBS}
+	${MKDIR} ${BIN_DIR}
+	${CC} ${COPT} -o ${BIN_DIR}/gff3Tester gff3Tester.o ${MYLIBS} ${L}
+
+
+# lineFile's tabix support:
+tabixTester=${BIN_DIR}/tabixFetch
+tabixTest: tabixFetch1kGNoGenotypes tabixFetch1kGWithGenotypes
+
+tabixFetch1kGNoGenotypes: ${tabixTester} mkdirs
+	${tabixTester} input/YRI.trio.2010_06.novelsequences.sites.vcf.gz 2:26790860-194631353 > output/$@.out
+	diff expected/$@.out output/$@.out
+
+tabixFetch1kGWithGenotypes: ${tabixTester} mkdirs
+	${tabixTester} input/YRI.low_coverage.2010_07_excerpt.genotypes.vcf.gz 2:26793738-26794385 > output/$@.out
+	diff expected/$@.out output/$@.out
+
+${BIN_DIR}/tabixFetch: tabixFetch.o ${MYLIBS}
+	${MKDIR} ${BIN_DIR}
+	${CC} ${COPT} -o ${BIN_DIR}/tabixFetch tabixFetch.o ${MYLIBS} ${L}
+
+
+# vcf:
+vcfTester=${BIN_DIR}/vcfParseTest
+vcfTest: vcfParse1kGNoGenotypes vcfParse1kGWithGenotypes vcfParseOldV3
+
+vcfParse1kGNoGenotypes: ${vcfTester} mkdirs
+	${vcfTester} input/YRI.trio.2010_06.novelsequences.sites.vcf.gz 2 26790859 194631353 > output/$@.out
+	diff expected/$@.out output/$@.out
+
+vcfParse1kGWithGenotypes: ${vcfTester} mkdirs
+	${vcfTester} input/YRI.low_coverage.2010_07_excerpt.genotypes.vcf.gz 2 26793737 26794385 > output/$@.out
+	diff expected/$@.out output/$@.out
+
+vcfParseOldV3:
+	${vcfTester} input/20091110_pilot1_vcf_merged_call_sets_YRI.2and3_way.vcf.gz 1 3000 50000 >& output/$@.out
+	diff expected/$@.out output/$@.out
+
+${BIN_DIR}/vcfParseTest: vcfParseTest.o ${MYLIBS}
+	${MKDIR} ${BIN_DIR}
+	${CC} ${COPT} -o ${BIN_DIR}/vcfParseTest vcfParseTest.o ${MYLIBS} ${L}
+
+
+# hacTree:
+hacTreeTester=${BIN_DIR}/hacTreeTest
+hacTreeTest: ${hacTreeTester} mkdirs
+	${hacTreeTester} input/$@.txt output/$@.out
+	diff expected/$@.out output/$@.out
+
+${BIN_DIR}/hacTreeTest: hacTreeTest.o ${MYLIBS}
+	${MKDIR} ${BIN_DIR}
+	${CC} ${COPT} -o ${BIN_DIR}/hacTreeTest hacTreeTest.o ${MYLIBS} ${L}
+
+# udc (not part of the top-level test target at this point):
+udcTest: udcTest.o ${MYLIBS} mkdirs
+	${CC} ${COPT} -o ${BIN_DIR}/udcTest udcTest.o ${MYLIBS} ${L}
+	${BIN_DIR}/udcTest
+
+clean:
+	rm -rf *.o bin output *.tmp mimeTester.tmp mimeTester.out fetchUrlTest
diff --git a/lib/tests/mimeDecodeTest.c b/lib/tests/mimeDecodeTest.c
new file mode 100644
index 0000000..d3aa6fd
--- /dev/null
+++ b/lib/tests/mimeDecodeTest.c
@@ -0,0 +1,368 @@
+/* mimeDecodeTest.c for parsing MIME from a descriptor (stdin).
+ *
+ * This file is copyright 2006 Galt Barber, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "options.h"
+#include "dystring.h"
+#include "errabort.h"
+#include "hash.h"
+#include "cheapcgi.h"
+#include "mime.h"
+#include "base64.h"
+#include "quotedP.h"
+
+/* 
+ * Note: MIME is a nested structure that makes a tree that streams in depth-first.
+ */
+
+int noNameCount = 0;
+char noName[256];
+char outPath[256];
+
+char *altHeader = NULL;
+boolean cidPass = FALSE;
+struct hash *cidHash = NULL;
+struct dyString *dy = NULL;
+char *outDir = ".";
+
+void usage(char *msg)
+/* Explain usage and exit. */
+{
+errAbort(
+    "%s\n\n"
+    "mimeDecode - parse and decode mime input on stdin\n"
+    "\n"
+    "Usage:\n"
+    "   mimeDecode [options] outDir\n"
+    "where outDir is the output directory.\n"
+    "Options:\n"
+    "  -altHeader='CONTENT_TYPE=\"multipart/form-data, boundary=AaB03x\"'\n"
+    "    be sure to specify the same boundary pattern that is used \n"
+    "    in the stdin input.\n"
+    "  -autoBoundary - no boundary given, scan for --.\n"
+    "  -cid - process html replacing cid urls with filenames.\n"
+    "  -noNames - ignore given filenames, use noNames for all.\n"
+    "  --help - this help screen\n",
+    msg);
+}
+
+static struct optionSpec options[] =
+{
+    {"altHeader", OPTION_STRING},
+    {"autoBoundary", OPTION_BOOLEAN},
+    {"cid", OPTION_BOOLEAN},
+    {"noNames", OPTION_BOOLEAN},
+    {"-help", OPTION_BOOLEAN},
+    {NULL, 0},
+};
+
+
+static void handleCID(char **html, char *ctMain)
+/* Handle CID replacements if needed */
+{
+if (optionExists("cid") && ctMain && sameWord(ctMain,"text/html"))
+    {
+    struct hashEl *el, *list = hashElListHash(cidHash);
+    for(el=list;el;el=el->next)
+	{
+	char *cid=addSuffix("cid:",el->name);
+	if (stringIn(cid,*html))
+	    {
+	    char *new = replaceChars(*html, cid, el->val);
+	    freez(html);
+	    *html = new;
+	    }
+	freez(&cid);
+	// support for content-location
+	if (stringIn(el->name,*html))
+	    {
+	    char *new = replaceChars(*html, el->name, el->val);
+	    freez(html);
+	    *html = new;
+	    }
+	}
+    hashElFreeList(&list);
+    }
+}
+		
+
+void printMimeInfo(struct mimePart *mp, FILE *out, int level)
+/* print mimeParts info and decode and detach recursively if needed */
+{
+
+char *cd = NULL, *cdMain = NULL, *cdName = NULL, *cdFileName = NULL, 
+ *ct = NULL, *ctMain = NULL, *ctCharset = NULL, *ctName = NULL,
+ *ce = NULL, *ceMain = NULL, *cid = NULL, *cidMain = NULL, *cl = NULL, *clMain = NULL;
+char *margin = needMem(level+1);
+int i = 0;
+for(i=0;i<level;++i)
+    margin[i] = ' ';
+margin[level] = 0;    
+
+cd = hashFindVal(mp->hdr,"content-disposition");
+ct = hashFindVal(mp->hdr,"content-type");
+ce = hashFindVal(mp->hdr,"content-transfer-encoding");
+cid = hashFindVal(mp->hdr,"content-id");
+cl = hashFindVal(mp->hdr,"content-location");
+
+if (cd)
+    {
+    dyStringPrintf(dy,"%scontent-disposition: %s\n",margin,cd);
+    cdMain=getMimeHeaderMainVal(cd);
+    cdName=getMimeHeaderFieldVal(cd,"name");
+    dyStringPrintf(dy,"%smain:[%s]\n",margin,cdMain);
+    dyStringPrintf(dy,"%sname:[%s]\n",margin,cdName);
+    cdFileName=getMimeHeaderFieldVal(cd,"filename");
+    if (cdFileName)
+    	dyStringPrintf(dy,"%sfilename:[%s]\n",margin,cdFileName);
+    }
+if (ct)
+    {
+    dyStringPrintf(dy,"%scontent-type: %s\n",margin,ct);
+    ctMain=getMimeHeaderMainVal(ct);
+    ctCharset=getMimeHeaderFieldVal(ct,"charset");
+    ctName=getMimeHeaderFieldVal(ct,"name");
+    }
+if (ce)
+    {
+    dyStringPrintf(dy,"%scontent-transer-encoding: %s\n",margin,ce);
+    ceMain=getMimeHeaderMainVal(ce);
+    }
+if (cid)
+    {
+    dyStringPrintf(dy,"%scontent-id: %s\n",margin,cid);
+    if (cid[0]=='<' && lastChar(cid)=='>')
+	cidMain = cloneStringZ(cid+1,strlen(cid)-2);
+    else    
+	cidMain = cloneString(cid);
+    }
+if (cl)
+    {  // this is a url and needs decoding
+    cgiDecode(cl, cl, strlen(cl));
+    dyStringPrintf(dy,"%scontent-location: %s\n",margin,cl);
+    clMain=getMimeHeaderMainVal(cl);
+    }
+
+if (cd)
+    {
+    dyStringPrintf(dy,"%ssize:[%llu]\n",margin,(unsigned long long) mp->size);
+    if (mp->binary)
+    	dyStringPrintf(dy,"%sbinary (contains zeros)\n",margin);
+    if (mp->fileName)
+	dyStringPrintf(dy,"%sfileName=[%s]\n",margin, mp->fileName);
+    if (!cidPass)
+    	dyStringPrintf(dy,"%sdata:[%s]\n",margin,
+	    mp->binary && mp->data ? "<binary data not safe to print>" : mp->data);
+    dyStringPrintf(dy,"\n");
+    }
+
+
+if (mp->data) /* typical case in ram */
+    {
+    char *outName = NULL;
+    char *ext = "";
+    if (ctMain)
+	{
+	if (sameWord(ctMain,"text/plain"))
+	    ext = ".txt";
+	if (sameWord(ctMain,"text/html"))
+	    ext = ".html";
+	if (sameWord(ctMain,"image/jpeg"))
+	    ext = ".jpg";
+	}
+    safef(noName, sizeof(noName), "noName%d%s", noNameCount, ext);
+    if (cdFileName) 
+	outName = cdFileName;
+    else if (ctName) 
+	outName = ctName;
+    if (optionExists("noNames") || outName==NULL)
+	{
+	outName = noName;
+	++noNameCount;
+	}
+    if (cidPass)
+	{
+	if (cidMain)
+    	    hashAdd(cidHash,cidMain,cloneString(outName));
+	if (clMain)
+    	    hashAdd(cidHash,clMain,cloneString(outName));
+	}
+    else
+	{
+	FILE *f = NULL;
+	safef(outPath, sizeof(outPath), "%s/%s", outDir, outName);
+	f = mustOpen(outPath,"w");
+	if (ceMain && sameWord(ceMain,"base64"))
+	    {
+	    size_t newSize = 0;
+	    char *decoded = NULL;
+	    boolean base64Ok = base64Validate(mp->data); /* also removes whitespace */
+	    if (!base64Ok)
+		dyStringPrintf(dy,"%swarning: base64Validate failed on mp->data\n",margin);
+	    decoded = base64Decode((char *)mp->data, &newSize);
+	    mustWrite(f, decoded, newSize);
+	    freez(&decoded);
+	    }
+	else if (ceMain && sameWord(ceMain,"quoted-printable"))
+	    {
+	    char *decoded = quotedPrintableDecode((char *)mp->data);
+	    handleCID(&decoded, ctMain);
+	    mustWrite(f, decoded, strlen(decoded));
+	    freez(&decoded);
+	    }
+	else
+	    {
+	    handleCID(&mp->data, ctMain);
+	    mustWrite(f, mp->data, mp->size);
+	    }
+	carefulClose(&f);
+	}
+    	
+    }	    
+else if (mp->fileName)  /* huge file triggers tempfile */
+    {
+    }
+else if (mp->multi)
+    {
+    dyStringPrintf(dy,"%snested MIME structure\n\n",margin);
+    for(mp=mp->multi;mp;mp=mp->next)
+	printMimeInfo(mp, out, level+1);
+    }
+else
+    {
+    errAbort("mp-> type not data,fileName, or multi - unexpected MIME structure");
+    }
+
+
+freez(&cidMain);
+freez(&ceMain);
+freez(&ctName);
+freez(&ctCharset);
+freez(&ctMain);
+
+freez(&cdName);
+freez(&cdFileName);
+freez(&margin);
+
+}
+
+
+
+
+static struct mimePart * cgiParseMultipart(int fd, FILE *out, boolean autoBoundary)
+/* process a multipart form */
+{
+char h[1024];  /* hold mime header line */
+char *s = NULL;
+struct mimeBuf *mb = NULL;
+struct mimePart *mp = NULL;
+char **env = NULL;
+
+if (altHeader)
+    {
+    /* find the CONTENT_ environment strings, use to make Alternate Header string for MIME */
+    for(env=environ; *env; env++)
+	if (startsWith("CONTENT_",*env))
+	    {
+	    //debug
+	    //fprintf(stderr,"%s\n",*env);  //debug
+	    safef(h,sizeof(h),"%s",*env);
+	    /* change env syntax to MIME style header, from _ to - */
+	    s = strchr(h,'_');    
+	    if (!s)
+		errAbort("expecting '_' parsing env var %s for MIME alt header", *env);
+	    *s = '-';
+	    /* change env syntax to MIME style header, from = to : */
+	    s = strchr(h,'=');
+	    if (!s)
+		errAbort("expecting '=' parsing env var %s for MIME alt header", *env);
+	    *s = ':';
+	    dyStringPrintf(dy,"%s\r\n",h);
+	    }
+    dyStringAppend(dy,"\r\n"); /* blank line at end means end of headers */
+    fprintf(out,"Alternate Header Text:\n%s",dy->string);
+    }
+
+mb = initMimeBuf(fd);
+
+if (altHeader)
+	/* The Alternate Header will get freed */
+    mp = parseMultiParts(mb, cloneString(dy->string)); 
+else if (autoBoundary)
+    mp = parseMultiParts(mb, "autoBoundary"); 
+else    
+    mp = parseMultiParts(mb, NULL); 
+
+if(!mp->multi) /* expecting multipart child parts */
+    errAbort("Malformatted multipart-form.");
+
+
+freez(&mb);
+
+
+if (optionExists("cid"))
+    { /* make a preliminary pass to populate cid hash */
+    noNameCount = 0;
+    cidPass = TRUE;
+    dyStringClear(dy);
+    printMimeInfo(mp, out, 0);
+    }
+noNameCount = 0;
+cidPass = FALSE;
+dyStringClear(dy);
+printMimeInfo(mp, out, 0);
+fprintf(out,"%s",dy->string);
+
+return mp;
+}
+
+
+static void freeMimeParts(struct mimePart **pMp)
+/* free struct mimePart* recursively if needed */
+{
+struct mimePart *next = NULL, *mp = *pMp; 
+
+while (mp)
+    {
+    next = mp->next;
+    if (mp->multi)
+	freeMimeParts(&mp->multi);
+    freeHashAndVals(&mp->hdr);
+    freez(&mp->data);
+    freez(&mp->fileName);
+    freez(pMp);
+    mp = next;
+    pMp = ∓
+    }
+
+}
+
+int main(int argc, char *argv[])
+{
+struct mimePart *mp = NULL;
+optionInit(&argc, argv, options);
+if (argc != 2)
+    usage("wrong number of args");
+if (optionExists("-help"))
+    usage("help");
+if (optionExists("altHeader") && optionExists("autoBoundary"))
+    usage("-altHeader and -autoBoundary may not be used together");    
+altHeader  = optionVal("altHeader",altHeader);
+outDir = argv[1];
+
+if (altHeader)
+    putenv(altHeader);
+
+cidHash = hashNew(5);
+dy = dyStringNew(0);
+
+mp = cgiParseMultipart(STDIN_FILENO, stdout, optionExists("autoBoundary"));
+freeMimeParts(&mp);
+
+hashFree(&cidHash);
+freeDyString(&dy);
+return 0;
+}
+
diff --git a/lib/tests/mimeTester.c b/lib/tests/mimeTester.c
new file mode 100644
index 0000000..fa133a8
--- /dev/null
+++ b/lib/tests/mimeTester.c
@@ -0,0 +1,317 @@
+/* mimeTester - test program for mime parser */
+#include "common.h"
+#include "options.h"
+#include "pipeline.h"
+#include "linefile.h"
+#include "dystring.h"
+#include "mime.h"
+extern char **environ;
+
+
+char *altHeader = NULL;
+
+void usage(char *msg)
+/* Explain usage and exit. */
+{
+errAbort(
+    "%s\n\n"
+    "mimeTester - test program for mime parser\n"
+    "\n"
+    "Usage:\n"
+    "   mimeTester [options]\n"
+    "Options:\n"
+    "  -altHeader='CONTENT_TYPE=\"multipart/form-data, boundary=AaB03x\"'\n"
+    "    be sure to specify the same boundary pattern that is used \n"
+    "    in the stdin input.\n"
+    "  -autoBoundary - no boundary given, scan for --.\n"
+    "  -sizeSeries=n - run a series of mime messages to parse of increasing size\n"
+    "    with dna field size 0 to n\n"
+    "  --help - this help screen\n",
+    msg);
+}
+
+int sizeSeries = -1;
+
+static struct optionSpec options[] =
+{
+    {"altHeader", OPTION_STRING},
+    {"autoBoundary", OPTION_BOOLEAN},
+    {"sizeSeries", OPTION_INT},
+    {"-help", OPTION_BOOLEAN},
+    {NULL, 0},
+};
+
+
+
+void printMimeInfo(struct mimePart *mp, FILE *out, int level)
+/* print mimeParts recursively if needed */
+{
+
+char *cd = NULL, *cdMain = NULL, *cdName = NULL, *cdFileName = NULL, 
+ *ct = NULL, *ce = NULL;
+char *margin = needMem(level+1);
+int i = 0;
+for(i=0;i<level;++i)
+    margin[i] = ' ';
+margin[level] = 0;    
+
+
+cd = hashFindVal(mp->hdr,"content-disposition");
+ct = hashFindVal(mp->hdr,"content-type");
+ce = hashFindVal(mp->hdr,"content-transfer-encoding");
+
+if (cd)
+    {
+    fprintf(out,"%scontent-disposition: %s\n",margin,cd);
+    cdMain=getMimeHeaderMainVal(cd);
+    cdName=getMimeHeaderFieldVal(cd,"name");
+    fprintf(out,"%smain:[%s]\n",margin,cdMain);
+    fprintf(out,"%sname:[%s]\n",margin,cdName);
+    cdFileName=getMimeHeaderFieldVal(cd,"filename");
+    if (cdFileName)
+    	fprintf(out,"%sfilename:[%s]\n",margin,cdFileName);
+    }
+if (ct)
+    fprintf(out,"%scontent-type: %s\n",margin,ct);
+if (ce)
+    fprintf(out,"%scontent-transer-encoding: %s\n",margin,ce);
+
+if (cd)
+    {
+    fprintf(out,"%ssize:[%llu]\n",margin,(unsigned long long) mp->size);
+    if (mp->binary)
+    	fprintf(out,"%sbinary (contains zeros)\n",margin);
+    if (mp->fileName)
+	fprintf(out,"%sfileName=[%s]\n",margin, mp->fileName);
+    fprintf(out,"%sdata:[%s]\n",margin,
+    	mp->binary && mp->data ? "<binary data not safe to print>" : mp->data);
+    fprintf(out,"\n");
+    }
+
+if (mp->data) 
+    {
+    }	    
+else if (mp->fileName)
+    {
+    }
+else if (mp->multi)
+    {
+    fprintf(out,"%snested MIME structure\n\n",margin);
+    for(mp=mp->multi;mp;mp=mp->next)
+	printMimeInfo(mp, out, level+1);
+    }
+else
+    {
+    errAbort("mp-> type not data,fileName, or multi - unexpected MIME structure");
+    }
+
+freez(&cdMain);
+freez(&cdName);
+freez(&cdFileName);
+freez(&margin);
+
+}
+
+
+
+
+static struct mimePart * cgiParseMultipart(int fd, FILE *out, boolean autoBoundary)
+/* process a multipart form */
+{
+char h[1024];  /* hold mime header line */
+char *s = NULL;
+struct dyString *dy = newDyString(256);
+struct mimeBuf *mb = NULL;
+struct mimePart *mp = NULL;
+char **env = NULL;
+
+if (altHeader)
+    {
+    /* find the CONTENT_ environment strings, use to make Alternate Header string for MIME */
+    for(env=environ; *env; env++)
+	if (startsWith("CONTENT_",*env))
+	    {
+	    //debug
+	    //fprintf(stderr,"%s\n",*env);  //debug
+	    safef(h,sizeof(h),"%s",*env);
+	    /* change env syntax to MIME style header, from _ to - */
+	    s = strchr(h,'_');    
+	    if (!s)
+		errAbort("expecting '_' parsing env var %s for MIME alt header", *env);
+	    *s = '-';
+	    /* change env syntax to MIME style header, from = to : */
+	    s = strchr(h,'=');
+	    if (!s)
+		errAbort("expecting '=' parsing env var %s for MIME alt header", *env);
+	    *s = ':';
+	    dyStringPrintf(dy,"%s\r\n",h);
+	    }
+    dyStringAppend(dy,"\r\n"); /* blank line at end means end of headers */
+    fprintf(out,"Alternate Header Text:\n%s",dy->string);
+    }
+
+mb = initMimeBuf(fd);
+
+if (altHeader)
+    mp = parseMultiParts(mb, cloneString(dy->string)); /* The Alternate Header will get freed */
+else if (autoBoundary)    
+    mp = parseMultiParts(mb, "autoBoundary"); 
+else    
+    mp = parseMultiParts(mb, NULL); 
+
+if(!mp->multi) /* expecting multipart child parts */
+    errAbort("Malformatted multipart-form.");
+
+freeDyString(&dy);
+
+freez(&mb);
+
+
+printMimeInfo(mp, out, 0);
+
+return mp;
+}
+
+
+static void freeMimeParts(struct mimePart **pMp)
+/* free struct mimePart* recursively if needed */
+{
+struct mimePart *next = NULL, *mp = *pMp; 
+
+while (mp)
+    {
+    next = mp->next;
+    if (mp->multi)
+	freeMimeParts(&mp->multi);
+    freeHashAndVals(&mp->hdr);
+    freez(&mp->data);
+    freez(&mp->fileName);
+    freez(pMp);
+    mp = next;
+    pMp = ∓
+    }
+
+}
+
+#define TESTFILENAME "mimeTester.tmp"
+#define TESTFILEOUT "mimeTester.out"
+
+static void makeTestFile(int size)
+/* make a tmp test file as input to mime parser */
+{
+int i = 0;
+FILE *f = mustOpen(TESTFILENAME,"w");
+char *dna = NULL;
+fprintf(f,"%s",
+"Content-type: multipart/form-data; boundary=----------0xKhTmLbOuNdArY\r\n"
+"\r\n"
+"------------0xKhTmLbOuNdArY\r\n"
+"Content-Disposition: form-data; name=\"hgsid\"\r\n"
+"\r\n"
+"63932244\r\n"
+"------------0xKhTmLbOuNdArY\r\n"
+"Content-Disposition: form-data; name=\"org\"\r\n"
+"\r\n"
+"Human\r\n"
+"------------0xKhTmLbOuNdArY\r\n"
+"Content-Disposition: form-data; name=\"db\"\r\n"
+"\r\n"
+"hg17\r\n"
+"------------0xKhTmLbOuNdArY\r\n"
+"Content-Disposition: form-data; name=\"type\"\r\n"
+"\r\n"
+"BLAT's guess\r\n"
+"------------0xKhTmLbOuNdArY\r\n"
+"Content-Disposition: form-data; name=\"sort\"\r\n"
+"\r\n"
+"query,score\r\n"
+"------------0xKhTmLbOuNdArY\r\n"
+"Content-Disposition: form-data; name=\"output\"\r\n"
+"\r\n"
+"hyperlink\r\n"
+"------------0xKhTmLbOuNdArY\r\n"
+"Content-Disposition: form-data; name=\"userSeq\"\r\n"
+"\r\n"
+">NM_000230 (LEP)\n"
+);
+
+dna = needMem(size+1);
+for(i=0;i<size;++i)
+    {
+    dna[i] = 'A';
+    }
+dna[size] = 0;    
+fprintf(f,"%s",dna);
+freez(&dna);
+
+fprintf(f,"%s",
+"\r\n"
+"------------0xKhTmLbOuNdArY\r\n"
+"Content-Disposition: form-data; name=\"Submit\"\r\n"
+"\r\n"
+"Submit\r\n"
+"------------0xKhTmLbOuNdArY\r\n"
+"Content-Disposition: form-data; name=\"seqFile\"; filename=\"\"\r\n"
+"\r\n"
+"\r\n"
+"------------0xKhTmLbOuNdArY--\r\n"
+);
+
+carefulClose(&f);
+}
+
+
+static void doSizeSeries()
+/* test a range of increasing sizes for the mime parser */
+{
+int fd = -1;
+FILE *out = NULL;
+struct mimePart *mp = NULL; 
+int i = 0;
+for (i=0;i<sizeSeries;++i)
+    {
+    out = mustOpen(TESTFILEOUT, "w");
+    makeTestFile(i);
+    fd = open(TESTFILENAME, O_RDONLY);
+    mp = cgiParseMultipart(fd, out, FALSE);
+    fprintf(stderr,"ouput %d ok\n",i);
+    close(fd);
+    fd = -1;
+    carefulClose(&out);
+    freeMimeParts(&mp);
+    }
+}
+
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, options);
+if (argc != 1)
+    usage("wrong number of args");
+if (optionExists("-help"))
+    usage("help");
+if (optionExists("altHeader") && optionExists("sizeSeries"))
+    usage("-altHeader and -sizeSeries may not be used together");
+if (optionExists("altHeader") && optionExists("autoBoundary"))
+    usage("-altHeader and -autoBoundary may not be used together");
+if (optionExists("autoBoundary") && optionExists("sizeSeries"))
+    usage("-autoBoundary and -sizeSeries may not be used together");
+altHeader  = optionVal("altHeader",altHeader);
+sizeSeries = optionInt("sizeSeries",sizeSeries);
+
+if (altHeader)
+    putenv(altHeader);
+
+if (optionExists("sizeSeries"))
+    {
+    doSizeSeries();
+    }
+else    
+    {
+    struct mimePart *mp = cgiParseMultipart(STDIN_FILENO, stdout, optionExists("autoBoundary"));
+    freeMimeParts(&mp);
+    }
+
+return 0;
+}
diff --git a/lib/tests/miniBlat.c b/lib/tests/miniBlat.c
new file mode 100644
index 0000000..e17d141
--- /dev/null
+++ b/lib/tests/miniBlat.c
@@ -0,0 +1,26 @@
+#include "common.h"
+#include "htmlPage.h"
+#include "qa.h"
+int main(int argc, char *argv[])
+{
+char *url, *dnaFileName;
+struct htmlPage *rootPage, *page;
+struct htmlForm *mainForm;
+struct qaStatus *qs;
+if (argc != 3) errAbort("usage: %s url file", argv[0]);
+url = argv[1]; dnaFileName = argv[2];
+qs = qaPageGet(url, &rootPage);
+if (qs->errMessage) errAbort("%s",qs->errMessage);
+if (qs->hardError) errAbort("hard error");
+if ((mainForm = htmlFormGet(rootPage, "mainForm")) == NULL)
+    errAbort("Couldn't get main form");
+htmlPageSetVar(rootPage, mainForm, "seqFile", dnaFileName);
+qs = qaPageFromForm(rootPage, mainForm,
+                "Submit", "submit", &page);
+if (qs->errMessage) errAbort("%s",qs->errMessage);
+if (qs->hardError) errAbort("hard error");
+fprintf(stdout,"%s ok\n",page->fullText);
+htmlPageFree(&page);
+htmlPageFree(&rootPage);
+return 0;
+}
diff --git a/lib/tests/pipelineTester.c b/lib/tests/pipelineTester.c
new file mode 100644
index 0000000..fba32a8
--- /dev/null
+++ b/lib/tests/pipelineTester.c
@@ -0,0 +1,274 @@
+/* pipelineTester - test program for pipeline object */
+#include "common.h"
+#include "pipeline.h"
+#include "linefile.h"
+#include "options.h"
+
+
+void usage(char *msg)
+/* Explain usage and exit. */
+{
+errAbort(
+    "%s\n\n"
+    "pipelineTester - test program for pipeline object\n"
+    "\n"
+    "Usage:\n"
+    "   pipelineTester [options] cmdArgs1 [cmdArgs2 ..]\n"
+    "\n"
+    "Each cmdArgs are a command and whitespace separated\n"
+    "arguments to pipe together.  Within a cmdArgs, single or\n"
+    "double quote maybe used to quote words.\n"
+    "\n"
+    "Options:\n"
+    "  -exitCode=n - run with no-abort and expect this error code,\n"
+    "   which can be zero.\n"
+    "  -write - create a write pipeline\n"
+    "  -memApi - test memory buffer API\n"
+    "  -pipeData=file - for a read pipeline, data read from the pipeline is copied\n"
+    "   to this file for verification.  For a write pipeline, data from this\n"
+    "   file is written to the pipeline.\n"
+    "  -otherEnd=file - file for other end of pipeline\n"
+    "  -stderr=file - file for stderr of pipeline\n"
+    "  -fdApi - use the file descriptor API\n",
+    msg);
+}
+
+static struct optionSpec options[] =
+{
+    {"exitCode", OPTION_INT},
+    {"write", OPTION_BOOLEAN},
+    {"memApi", OPTION_BOOLEAN},
+    {"pipeData", OPTION_STRING},
+    {"otherEnd", OPTION_STRING},
+    {"stderr", OPTION_STRING},
+    {"fdApi", OPTION_BOOLEAN},
+    {NULL, 0},
+};
+
+/* options from command line */
+boolean noAbort = FALSE;  /* don't abort, check exit code */
+int expectExitCode = 0;   /* expected exit code */
+boolean fdApi = FALSE; /* use the file descriptor API */
+boolean isWrite = FALSE; /* make a write pipeline */
+boolean memApi = FALSE; /* test memory buffer API */
+char *pipeDataFile = NULL;   /* use for input or output to the pipeline */
+char *otherEndFile = NULL;   /* file for other end of pipeline */
+char *stderrFile = NULL;   /* file for other stderr of pipeline */
+
+int countOpenFiles()
+/* count the number of opens.  This is used to make sure no stray
+ * pipes have been left open. */
+{
+int cnt = 0;
+int fd;
+struct stat statBuf;
+for (fd = 0; fd < 64; fd++)
+    {
+    if (fstat(fd, &statBuf) == 0)
+        cnt++;
+    }
+return cnt;
+}
+
+char *parseQuoted(char **spPtr, char *cmdArgs)
+/* parse a quoted string */
+{
+char *start = *spPtr;
+char quote = *start++;
+char *end = strchr(start, quote);
+if (end == NULL)
+    errAbort("no closing quote in: %s", cmdArgs);
+*spPtr = end+1;
+return cloneStringZ(start, end-start);
+}
+
+char **splitCmd(char *cmdArgs)
+/* split a command and arguments into null termiated list, handling quoting */
+{
+// this will get the maximum number of words, as it doesn't consider quoting
+int maxNumWords = chopByWhite(cmdArgs, NULL, 0);
+char **words = needMem((maxNumWords+1)*sizeof(char*));
+int iWord = 0;
+char *sp = skipLeadingSpaces(cmdArgs);
+
+while (*sp != '\0')
+    {
+    assert(iWord < maxNumWords);
+    if ((*sp == '"') || (*sp == '\''))
+        words[iWord++] = parseQuoted(&sp, cmdArgs);
+    else
+        {
+        char *end = skipToSpaces(sp);
+        if (end == NULL)
+            end = sp + strlen(sp);
+        words[iWord++] = cloneStringZ(sp, (end - sp));
+        sp = end;
+        }
+    sp = skipLeadingSpaces(sp);
+    }
+return words;
+}
+
+char ***splitCmds(int nCmdsArgs, char **cmdsArgs)
+/* split all commands into a pipeline */
+{
+char ***cmds = needMem((nCmdsArgs+1)*sizeof(char**));
+int i;
+for (i = 0; i < nCmdsArgs; i++)
+    cmds[i] = splitCmd(cmdsArgs[i]);
+return cmds;
+}
+
+void readTest(struct pipeline *pl)
+/* test a read pipeline */
+{
+struct lineFile *pipeLf = pipelineLineFile(pl);
+FILE *dataFh = mustOpen(pipeDataFile, "w");
+char *line;
+
+while (lineFileNext(pipeLf, &line, NULL))
+    {
+    fputs(line, dataFh);
+    fputc('\n', dataFh);
+    if (ferror(dataFh))
+        errnoAbort("error writing data from pipeline to: %s", pipeDataFile);
+    }
+
+carefulClose(&dataFh);
+}
+
+void writeTest(struct pipeline *pl)
+/* test a write pipeline */
+{
+FILE *pipeFh = pipelineFile(pl);
+struct lineFile *dataLf = lineFileOpen(pipeDataFile, TRUE);
+char *line;
+
+while (lineFileNext(dataLf, &line, NULL))
+    {
+    fputs(line, pipeFh);
+    fputc('\n', pipeFh);
+    if (ferror(pipeFh))
+        errnoAbort("error writing data to pipeline: %s", pipelineDesc(pl));
+    }
+
+lineFileClose(&dataLf);
+}
+
+void *loadMemData(char *dataFile, size_t *dataSizeRet)
+/* load a file into memory */
+{
+off_t dataSize = fileSize(dataFile);
+void *buf = needLargeMem(dataSize);
+FILE *fh = mustOpen(dataFile, "r");
+
+mustRead(fh, buf, dataSize);
+carefulClose(&fh);
+*dataSizeRet = dataSize;
+return buf;
+}
+
+void runPipelineTest(struct pipeline *pl)
+/* execute and validate test once pipeline has been created */
+{
+/* if no data file is specified, we just let the pipeline run without
+ * interacting with it */
+if (pipeDataFile != NULL)
+    {
+    if (isWrite)
+        writeTest(pl);
+    else
+        readTest(pl);
+    }
+int exitCode = pipelineWait(pl);
+if (exitCode != expectExitCode)
+    errAbort("expected exitCode %d, got %d", expectExitCode, exitCode);
+}
+
+void pipelineTestFd(char ***cmds, unsigned options)
+/* test for file descriptor API */
+{
+int mode = (isWrite ? O_WRONLY|O_CREAT|O_TRUNC : O_RDONLY);
+int otherEndFd = mustOpenFd(otherEndFile, mode);
+int stderrFd = (stderrFile == NULL) ? STDERR_FILENO
+    : mustOpenFd(stderrFile, O_WRONLY|O_CREAT|O_TRUNC);
+struct pipeline *pl = pipelineOpenFd(cmds, options, otherEndFd, stderrFd);
+runPipelineTest(pl);
+pipelineFree(&pl);
+mustCloseFd(&otherEndFd);
+if (stderrFile != NULL)
+    mustCloseFd(&stderrFd);
+}
+
+void pipelineTestMem(char ***cmds, unsigned options)
+/* test for memory buffer API */
+{
+int stderrFd = (stderrFile == NULL) ? STDERR_FILENO
+    : mustOpenFd(stderrFile, O_WRONLY|O_CREAT|O_TRUNC);
+size_t otherEndBufSize = 0;
+void *otherEndBuf = loadMemData(otherEndFile, &otherEndBufSize);
+struct pipeline *pl = pipelineOpenMem(cmds, options, otherEndBuf, otherEndBufSize, stderrFd);
+runPipelineTest(pl);
+pipelineFree(&pl);
+freeMem(otherEndBuf);
+if (stderrFile != NULL)
+    mustCloseFd(&stderrFd);
+}
+
+void pipelineTestFName(char ***cmds, unsigned options)
+/* test for file name API */
+{
+struct pipeline *pl = pipelineOpen(cmds, options, otherEndFile, stderrFile);
+runPipelineTest(pl);
+pipelineFree(&pl);
+}
+
+void pipelineTester(int nCmdsArgs, char **cmdsArgs)
+/* pipeline tester */
+{
+unsigned options = (isWrite ? pipelineWrite : pipelineRead);
+if (noAbort)
+    options |= pipelineNoAbort;
+int startOpenCnt = countOpenFiles();
+char ***cmds = splitCmds(nCmdsArgs, cmdsArgs);
+
+if (fdApi)
+    pipelineTestFd(cmds, options);
+else if (memApi)
+    pipelineTestMem(cmds, options);
+else
+    pipelineTestFName(cmds, options);
+
+/* it's ok to have less open, as would happen if we read from stdin */
+int endOpenCnt = countOpenFiles();
+if (endOpenCnt > startOpenCnt)
+    errAbort("started with %d files open, now have %d open", startOpenCnt,
+             endOpenCnt);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, options);
+if (argc < 2)
+    usage("wrong number of args");
+if (optionExists("exitCode"))
+    {
+    noAbort = TRUE;
+    expectExitCode = optionInt("exitCode", 0);
+    }
+isWrite = optionExists("write");
+memApi = optionExists("memApi");
+fdApi = optionExists("fdApi");
+if (fdApi && memApi)
+    errAbort("can't specify both -fdApi and -memApi");
+pipeDataFile = optionVal("pipeData", NULL);
+otherEndFile = optionVal("otherEnd", NULL);
+if (fdApi && (otherEndFile == NULL))
+    errAbort("-fdApi requires -otherEndFile");
+if (memApi && (otherEndFile == NULL))
+    errAbort("-memApi requires -otherEndFile");
+stderrFile = optionVal("stderr", NULL);
+pipelineTester(argc-1, argv+1);
+return 0;
+}
diff --git a/lib/tests/safeTester.c b/lib/tests/safeTester.c
new file mode 100644
index 0000000..2d56535
--- /dev/null
+++ b/lib/tests/safeTester.c
@@ -0,0 +1,174 @@
+/* safeTester - tests for safe* functions */
+
+#include "common.h"
+#include "errCatch.h"
+
+static void usage()
+/* Print usage message */
+{
+errAbort(
+   "safeTester - tests for safe* functions\n"
+   "usage:\n"
+   "   safeTester\n"
+   "\n");
+}
+int errCount = 0;  /* count of errors */
+
+static void shouldHaveFailed(char *testId)
+/* output test failure for case that should fail and didn't  */
+{
+fprintf(stderr, "Error: test %s should have failed\n", testId);
+errCount++;
+}
+static void checkStr(char *testId, char *got, char *expect)
+/* copy strings and generate error if they don't match */
+{
+if (!sameString(got, expect))
+    {
+    fprintf(stderr, "Error: test %s failed, got \"%s\", expected \"%s\"\n",
+            testId, got, expect);
+    errCount++;
+    }
+}
+
+static void testSafecpy()
+/* test safecpy */
+{
+struct errCatch *errCatch = errCatchNew();
+char buf4[4];
+
+safecpy(buf4, sizeof(buf4), "abc");
+checkStr("safecpy len 3 to buf 4", buf4, "abc");
+
+if (errCatchStart(errCatch))
+    {
+    safecpy(buf4, sizeof(buf4), "abcde");
+    shouldHaveFailed("safecpy of len 5 to buf of 4");
+    }
+errCatchEnd(errCatch);
+if (errCatchStart(errCatch))
+    {
+    /* no room for EOLN */
+    safecpy(buf4, sizeof(buf4), "abcd");
+    shouldHaveFailed("safecpy of len 4 to buf of 4");
+    }
+errCatchEnd(errCatch);
+
+errCatchFree(&errCatch);
+}
+
+static void testSafencpy()
+/* test safencpy */
+{
+struct errCatch *errCatch = errCatchNew();
+char buf4[4];
+
+safencpy(buf4, sizeof(buf4), "abc", 2);
+checkStr("safencpy len 2 to buf 4", buf4, "ab");
+
+if (errCatchStart(errCatch))
+    {
+    safencpy(buf4, sizeof(buf4), "abcdefgh", 5);
+    shouldHaveFailed("safencpy of len 5 to buf of 4");
+    }
+errCatchEnd(errCatch);
+if (errCatchStart(errCatch))
+    {
+    /* no room for EOLN */
+    safencpy(buf4, sizeof(buf4), "abcd", 4);
+    shouldHaveFailed("safencpy of len 4 to buf of 4");
+    }
+errCatchEnd(errCatch);
+
+if (errCatchStart(errCatch))
+    {
+    safencpy(buf4, sizeof(buf4), "ab", 6);
+    shouldHaveFailed("safencpy of len 6 with short string to buf of 4");
+    }
+errCatchEnd(errCatch);
+
+errCatchFree(&errCatch);
+}
+
+static void testSafecat()
+/* test safecat */
+{
+struct errCatch *errCatch = errCatchNew();
+char buf6[6];
+
+buf6[0] = '\0';
+safecat(buf6, sizeof(buf6), "ab");
+safecat(buf6, sizeof(buf6), "cd");
+checkStr("safecat len 4 to buf of 6", buf6, "abcd");
+
+if (errCatchStart(errCatch))
+    {
+    buf6[0] = '\0';
+    safecat(buf6, sizeof(buf6), "abcdef");
+    shouldHaveFailed("safecat of len 6 to buf of 6");
+    }
+errCatchEnd(errCatch);
+
+if (errCatchStart(errCatch))
+    {
+    buf6[0] = '\0';
+    safecat(buf6, sizeof(buf6), "abc");
+    safecat(buf6, sizeof(buf6), "def");
+    shouldHaveFailed("safecat of len 3, then 3 more to buf of 6");
+    }
+errCatchEnd(errCatch);
+
+errCatchFree(&errCatch);
+}
+
+static void testSafencat()
+/* test safencat */
+{
+struct errCatch *errCatch = errCatchNew();
+char buf6[6];
+
+buf6[0] = '\0';
+safencat(buf6, sizeof(buf6), "abxyz", 2);
+safencat(buf6, sizeof(buf6), "cdAABCD", 2);
+checkStr("safencat len 4 to buf of 6", buf6, "abcd");
+
+if (errCatchStart(errCatch))
+    {
+    buf6[0] = '\0';
+    safencat(buf6, sizeof(buf6), "abcd", 6);
+    shouldHaveFailed("safencat of len 6 to buf of 6");
+    }
+errCatchEnd(errCatch);
+
+if (errCatchStart(errCatch))
+    {
+    buf6[0] = '\0';
+    safencat(buf6, sizeof(buf6), "abcAAA", 3);
+    safencat(buf6, sizeof(buf6), "defBBB", 3);
+    shouldHaveFailed("safencat of len 3, then 3 more to buf of 6");
+    }
+errCatchEnd(errCatch);
+
+errCatchFree(&errCatch);
+}
+
+static void safeTester()
+/* tests for safe* functions */
+{
+testSafecpy();
+testSafencpy();
+testSafecat();
+testSafencat();
+if (errCount > 0)
+    errAbort("%d tests failed", errCount);
+}
+
+int main(int argc, char *argv[])
+{
+if (argc != 1)
+    usage();
+safeTester();
+return 0;
+}
+
+
diff --git a/lib/tests/tabixFetch.c b/lib/tests/tabixFetch.c
new file mode 100644
index 0000000..fef9fb8
--- /dev/null
+++ b/lib/tests/tabixFetch.c
@@ -0,0 +1,114 @@
+/* tabixFetch - Test lineFileTabixMayOpen and lineFileSetTabixRegion (compare with cmd line tabix output). */
+#include "common.h"
+#include "linefile.h"
+#include "options.h"
+
+#ifdef USE_TABIX
+
+#include "sqlNum.h"
+#include "udc.h"
+#include "knetUdc.h"
+
+void usage()
+/* Explain usage and exit. */
+{
+errAbort(
+
+  "tabixFetch - Test lineFileTabixMayOpen and lineFileSetTabixRegion (compare\n"
+  "             with command-line tabix output)\n"
+
+  "usage:\n"
+  "   tabixFetch fileOrUrl chrom:start-end\n"
+  "Fetch lines from the specified position range from a line-based file\n"
+  "with genomic positions that has been compressed and indexed by tabix.\n"
+  "This duplicates the fetching functionality of the tabix program -- it\n"
+  "was written solely to test lib/lineFile.c's tabix-wrapper mode.\n"
+  );
+}
+
+static struct optionSpec options[] = {
+   {NULL, 0},
+};
+
+#define BAD_POS_FORMAT "Expecting position format: chrom:N-M where N and M are integers.  " \
+		       "\"%s\" doesn't match."
+static void parsePosition(const char *position, char **retChrom, int *retStart, int *retEnd)
+/* Do we have a lib routine for this somewhere?  Too lazy to look. */
+{
+char *posDupe = cloneString(position);
+char *words[3];
+int wordCount = chopByChar(posDupe, ':', words, ArraySize(words));
+if (wordCount != 2)
+    errAbort(BAD_POS_FORMAT, position);
+*retChrom = posDupe;
+
+stripChar(words[1], ',');
+char *range = cloneString(words[1]);
+wordCount = chopByChar(range, '-', words, ArraySize(words));
+if (wordCount != 2)
+    errAbort(BAD_POS_FORMAT, position);
+*retStart = sqlUnsigned(words[0]) - 1;
+*retEnd = sqlUnsigned(words[1]);
+}
+
+void tabixFetch(char *fileOrUrl, char *position)
+/* tabixFetch - Test lineFileTabixMayOpen and lineFileSetTabixRegion
+ * (compare with cmd line tabix output). */
+{
+udcSetDefaultDir("/data/tmp/angie/udcCache");
+knetUdcInstall();
+struct lineFile *lf = lineFileTabixMayOpen(fileOrUrl, TRUE);
+if (lf == NULL)
+    exit(1);
+int lineSize;
+char *line = NULL;
+boolean gotLine = FALSE;
+if (0)
+do
+    {
+    gotLine = lineFileNext(lf, &line, &lineSize);
+    puts(line);
+    }
+while (gotLine && (line[0] == '#' || isEmpty(line)));
+
+char *chrom = NULL;
+int start, end;
+parsePosition(position, &chrom, &start, &end);
+boolean success = lineFileSetTabixRegion(lf, chrom, start, end);
+if (!success)
+    printf("*** Could not set position to %s\n", position);
+else
+    {
+    printf("*** First (up to) 10 lines from query on %s:\n", position);
+    int i;
+    for (i=0;  i < 10;  i++)
+	{
+	if (lineFileNext(lf, &line, &lineSize))
+	    puts(line);
+	else break;
+	}
+    if (i == 0)
+	printf("*** No lines returned from query on %s\n", position);
+    }
+lineFileClose(&lf);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, options);
+if (argc != 3)
+    usage();
+tabixFetch(argv[1], argv[2]);
+return 0;
+}
+
+#else // no USE_TABIX
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+errAbort(COMPILE_WITH_TABIX, "tabixFetch");
+return 1;
+}
+
+#endif // no USE_TABIX
diff --git a/lib/tests/testBase64.c b/lib/tests/testBase64.c
new file mode 100644
index 0000000..bbd2c64
--- /dev/null
+++ b/lib/tests/testBase64.c
@@ -0,0 +1,44 @@
+#include "common.h"
+#include "base64.h"
+
+void binary(unsigned int b, int width, int group) {
+int g=1;
+b <<= (32-width);
+while (width--) 
+    {
+    printf("%d", b & 0x80000000 ? 1 : 0);
+    b <<= 1;
+    if (g++ >= group)
+	{
+	printf(" ");
+	g = 1;
+	}
+    }
+}
+
+int main(int argc, char *argv[])
+{
+char *encoded = NULL;
+char *decoded = NULL;
+char *input = cloneString(argv[1]);
+boolean validB64 = TRUE;
+if (argc != 2)
+errAbort("%s: Specify a string to encode/decode on commandline using quotes.\n"
+       , argv[0]);
+	    
+encoded = base64Encode(argv[1], strlen(argv[1]));
+
+validB64 = base64Validate(input);  /* removes whitespace */
+
+if (validB64)
+    decoded = base64Decode(input, NULL);
+
+printf("original input: [%s]\nbase-64 encoding: [%s]\nbase-64 decoding: [%s]\n", argv[1], encoded, decoded);
+
+freez(&encoded);
+freez(&decoded);
+
+return 0;
+
+}
+
diff --git a/lib/tests/testHash.c b/lib/tests/testHash.c
new file mode 100644
index 0000000..45787a4
--- /dev/null
+++ b/lib/tests/testHash.c
@@ -0,0 +1,81 @@
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "obscure.h"
+
+int main(int argc, char *argv[])
+{
+if (argc != 2)
+    errAbort("%s: Specify an input file with strings key<space>value on commandline.\n"
+       , argv[0]);
+
+struct lineFile * lf = lineFileOpen(argv[1], TRUE); 
+char *line = NULL;
+char *row[2];
+int wordCount;
+struct hash *hash = newHash(0);
+struct slName *keyList = NULL, *node = NULL; 
+char *key, *val;
+while (lineFileNext(lf, &line, NULL))
+    {
+    wordCount = chopLine(line, row);
+    if (wordCount == 0 || row[0][0] == '#')
+	continue;
+    if (wordCount != 2)
+	 {
+	 warn("Invalid line %d of %s", lf->lineIx, lf->fileName);
+	 continue;
+	 }
+    key = row[0];
+    val = row[1];
+    printf("%s=%s\n", key, val);
+    if (!hashLookup(hash, key))
+	{
+	node = newSlName(key);
+	slAddHead(&keyList, node);
+	}
+    hashAdd(hash, key, cloneString(val));
+    }
+lineFileClose(&lf);
+slReverse(&keyList);
+
+printf("-----------\n");
+printf("keys and values:\n");
+/* read and print the hash values in keyList order */
+for(node=keyList; node; node=node->next)
+    {
+    key = node->name; 
+    printf("%s", key);
+    struct hashEl *hel;
+    for (hel = hashLookup(hash, key); hel; hel = hashLookupNext(hel))
+	{
+	printf(" %s", (char *)hel->val);
+	}
+    printf("\n");
+    }
+
+/* double the size */
+hashResize(hash, digitsBaseTwo(hash->size));
+
+printf("----RESIZED HASH-------\n");
+printf("keys and values:\n");
+/* read and print the hash values in keyList order */
+for(node=keyList; node; node=node->next)
+    {
+    key = node->name; 
+    printf("%s", key);
+    struct hashEl *hel;
+    for (hel = hashLookup(hash, key); hel; hel = hashLookupNext(hel))
+	{
+	printf(" %s", (char *)hel->val);
+	}
+    printf("\n");
+    }
+
+
+slFreeList(&keyList);
+freeHash(&hash);
+return 0;
+
+}
+
diff --git a/lib/tests/testQuotedP.c b/lib/tests/testQuotedP.c
new file mode 100644
index 0000000..7825e74
--- /dev/null
+++ b/lib/tests/testQuotedP.c
@@ -0,0 +1,22 @@
+#include "common.h"
+#include "quotedP.h"
+
+int main(int argc, char *argv[])
+{
+char *encoded = NULL;
+char *decoded = NULL;
+if (argc != 2)
+errAbort("%s: Specify a string to encode/decode on commandline using quotes.\n"
+       , argv[0]);
+	    
+encoded = quotedPrintableEncode(argv[1]);
+decoded = quotedPrintableDecode(argv[1]);
+
+printf("original input: [%s]\nquoted-printable encoding: [%s]\nquoted-p decoding: [%s]\n", argv[1], encoded, decoded);
+
+freez(&encoded);
+freez(&decoded);
+
+return 0;
+}
+
diff --git a/lib/tests/testQuotedString.c b/lib/tests/testQuotedString.c
new file mode 100644
index 0000000..1415f81
--- /dev/null
+++ b/lib/tests/testQuotedString.c
@@ -0,0 +1,57 @@
+/* testQuotedString - test the parseQuotedString function */
+#include "common.h"
+#include "options.h"
+#include "obscure.h"
+#include "dystring.h"
+
+void usage()
+/* Explain usage and exit */
+{
+errAbort(
+"testQuotedString - test the parseQuotedString() function\n"
+"usage:\n"
+"   testQuotedString <some quote char>[any characters]<some quote char>\n"
+"   whatever is given on the command line: [any characters] will be parsed\n"
+"   the first character encountered will be the quote character\n"
+"   the string must end with that quote character\n"
+"   beware of your shell consuming your quote characters if you want\n"
+"   to use \" or \'\n"
+"   -verbose=2 to mirror [any characters]\n"
+);
+}
+
+static struct optionSpec options[] = {
+   {NULL, 0},
+};
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, options);
+if (argc < 2)
+    usage();
+int i;
+struct dyString *cmdArgs = newDyString(0);
+for (i = 1; i < argc; ++i)
+    {
+    if (i > 1)
+	dyStringPrintf(cmdArgs, " %s", argv[i]);
+    else
+	dyStringPrintf(cmdArgs, "%s", argv[i]);
+    }
+
+char *dupe = cloneString(cmdArgs->string);
+verbose(2, "command line: '%s'\n", cmdArgs->string);
+verbose(1,"============  parseQuotedStringNoEscapes\n");
+if (!parseQuotedStringNoEscapes(cmdArgs->string, dupe, NULL))
+    verbose(1, "can not parse: '%s'\n", cmdArgs->string);
+else
+    verbose(1, "parsed to: '%s'\n", dupe);
+verbose(1,"============  parseQuotedString\n");
+if (!parseQuotedString(cmdArgs->string, dupe, NULL))
+    errAbort("can not parse: '%s'", cmdArgs->string);
+else
+    verbose(1, "parsed to: '%s'\n", dupe);
+freeDyString(&cmdArgs);
+return 0;
+}
diff --git a/lib/tests/udcTest.c b/lib/tests/udcTest.c
new file mode 100644
index 0000000..41d4663
--- /dev/null
+++ b/lib/tests/udcTest.c
@@ -0,0 +1,466 @@
+/* udcTest -- test the URL data cache */
+
+// suggestions from Mark: 1. try setvbuf, to make FILE * unbuffered -- does that help?
+//                        2. *if* need to do own buffering, consider mmap()
+//                           (kernel handles buffering)
+
+#include <sys/wait.h>
+#include "common.h"
+#include "errabort.h"
+#include "options.h"
+#include "portable.h"
+#include "udc.h"
+
+
+static struct optionSpec options[] = {
+    {"raBuf",    OPTION_BOOLEAN},
+    {"fork",     OPTION_BOOLEAN},
+    {"protocol", OPTION_STRING},
+    {"seed",     OPTION_INT},
+    {NULL, 0},
+};
+
+boolean raBuf = FALSE;   /* exercise the read-ahead buffer */
+boolean doFork = FALSE;
+char *protocol = "ftp";
+unsigned int seed = 0;
+
+// Local copy (reference file) and URL for testing:
+#define THOUSAND_HIVE "/hive/data/outside/1000genomes/ncbi/ftp-trace.ncbi.nih.gov/1000genomes/"
+#define THOUSAND_FTP "ftp://ftp-trace.ncbi.nih.gov/1000genomes/ftp/pilot_data/data/"
+#define CHR3_SLX_BAM "NA12878/alignment/NA12878.chrom3.SLX.maq.SRP000032.2009_07.bam"
+#define CHR4_SLX_BAM "NA12878/alignment/NA12878.chrom4.SLX.maq.SRP000032.2009_07.bam"
+
+// Use typical size range of bgzip-compressed data blocks:
+#define MIN_BLK_SIZE 20000
+#define MAX_BLK_SIZE 30000
+
+// Read at most this many consecutive blocks:
+#define MAX_BLOCKS 100
+
+void openSeekRead(char *filename, bits64 offset, bits64 len, char *buf)
+/* Read len bits starting at offset from filename into buf or die. */
+{
+int fd = mustOpenFd(filename, O_RDONLY);
+mustLseek(fd, offset, SEEK_SET);
+mustReadFd(fd, buf, len);
+mustCloseFd(&fd);
+}
+
+boolean compareBytes(char *bufTest, char *bufRef, bits64 len, char *testName, char *refName,
+		     char *testDesc, bits64 offset)
+/* Report any differences between bufTest and bufRef (don't errAbort). */
+{
+boolean gotError = FALSE;
+bits64 i, difCount = 0, nonZeroDifCount = 0;
+for (i=0;  i < len;  i++)
+    {
+    if (bufTest[i] != bufRef[i])
+	{
+	if (difCount == 0)
+	    warn("*** %s%s and ref first differ at offset %lld + %lld = %lld [0x%02x != 0x%02x]",
+		 (bufTest[i] != '\0' ? "NONZERO " : ""),
+		 testDesc, offset, i, offset+i, (bits8)bufTest[i], (bits8)bufRef[i]);
+	if (bufTest[i] != '\0')
+	    nonZeroDifCount++;
+	difCount++;
+	}
+    }
+if (difCount == 0)
+    verbose(3, "Success: %s = ref, %lld bytes @%lld\n", testDesc, len, offset);
+else
+    {
+    warn("--> %lld different bytes (%lld %s) total in block of %lld bytes starting at %lld",
+	 difCount, nonZeroDifCount, (nonZeroDifCount ? "NONZERO" : "nonzero"), len, offset);
+    gotError = TRUE;
+    }
+return gotError;
+}
+
+char *getSparseFileName(char *url)
+/* Return the path to sparseData cache file for url. */
+{
+struct slName *sl, *cacheFiles = udcFileCacheFiles(url, udcDefaultDir());
+char *sparseFileName = NULL;
+for (sl = cacheFiles; sl != NULL; sl = sl->next)
+    if (endsWith(sl->name, "sparseData"))
+	sparseFileName = sl->name;
+if (sparseFileName == NULL)
+    errAbort("can't find sparseData file in udcFileCacheFiles(%s) results", url);
+return sparseFileName;
+}
+
+boolean readAndTest(struct udcFile *udcf, bits64 offset, bits64 len, char *localCopy, char *url)
+/* Read len bytes starting at offset in udcf.  Compare both the bytes returned,
+ * and bytes directly read from the sparseData file, with data from the same 
+ * location in our local copy of the URL data. */
+{
+boolean gotError = FALSE;
+static char *bufRef = NULL, *bufTest = NULL;
+static bits64 bufSize = 0;
+if (bufRef != NULL && bufSize < len)
+    {
+    freez(&bufRef);
+    freez(&bufTest);
+    }
+if (bufRef == NULL)
+    {
+    bufSize = ((len >> 10) + 1) << 10;  // round up to next kB
+    bufRef = needMem(bufSize);
+    bufTest = needMem(bufSize);
+    }
+
+// Check offset + len against size of reference file:
+bits64 size = fileSize(localCopy);
+if (offset > size)
+    errAbort("readAndTest: Size of %s is %lld, but offset given is %lld", localCopy, size, offset);
+if (offset + len > size)
+    {
+    bits64 newSize = size - offset;
+    warn("readAndTest: Size of %s is %lld, offset %lld + len %lld = %lld exceeds that; "
+	 "reducing len to %lld", localCopy, size, offset, len, offset+len, newSize);
+    len = newSize;
+    }
+verbose(2, "0x%08llx: %lldB @%lld\n", (bits64)udcf, len, offset);
+
+// Get data from the reference file:
+openSeekRead(localCopy, offset, len, bufRef);
+
+// Get data from udcFile object and compare to reference:
+udcSeek(udcf, offset);
+bits64 bytesRead = udcRead(udcf, bufTest, len);
+
+// udcRead does a mustRead, and we have checked offset+len, so this should never happen,
+// but test anyway:
+if (bytesRead < len)
+    errAbort("Got %lld bytes instead of %lld from %s @%lld", bytesRead, len, url, offset);
+gotError |= compareBytes(bufTest, bufRef, len, url, localCopy, "url", offset);
+
+if (0) // -- Check sparseData after the dust settles.
+    {
+    // Get data from udcf's sparse data file and compare to reference:
+    char *sparseFileName = getSparseFileName(url);
+    openSeekRead(sparseFileName, offset, len, bufTest);
+    gotError |= compareBytes(bufTest, bufRef, len, sparseFileName, localCopy, "sparse", offset);
+    }
+return gotError;
+}
+
+INLINE double myDrand()
+/* Return something from [0.0,1.0). */
+{
+return (double)(rand() / (RAND_MAX + 1.0));
+}
+
+INLINE bits64 randomStartOffset(bits64 max)
+/* Return something from [0,max-MAX_BLOCKS*MAX_BLK_SIZE) */
+{
+bits64 maxStart = max - (MAX_BLOCKS * MAX_BLK_SIZE);
+return (bits64)(maxStart * myDrand());
+}
+
+INLINE bits64 randomBlockSize()
+/* Return something from [MIN_BLK_SIZE,MAX_BLK_SIZE) */
+{
+return MIN_BLK_SIZE + (bits64)((MAX_BLK_SIZE - MIN_BLK_SIZE) * myDrand());
+}
+
+boolean readAndTestBlocks(struct udcFile *udcf, bits64 *retOffset, int numBlks, int *retBlksRead,
+			 char *localCopy, char *url)
+/* Read numBlks randomly sized blocks from udcf starting at *retOffset and compare
+ * to localCopy.  *retBlksRead starts as the number of randomly sized blocks we have
+ * already read, and is incremented by the number of blocks we read. 
+ * If numBlks is 0, use the number of remaining blocks before *retBlksRead reaches
+ * MAX_BLOCKS.  Update *retOffset to the final offset. Return TRUE if errors. */
+{
+boolean gotError = FALSE;
+if (*retBlksRead >= MAX_BLOCKS)
+    errAbort("readAndTestBlocks: exceeded MAX_BLOCKS (%d) -- increase it?", MAX_BLOCKS);
+int blksLeft = MAX_BLOCKS - *retBlksRead;
+if (numBlks == 0)
+    numBlks = blksLeft;
+if (numBlks > blksLeft)
+    {
+    warn("readAndTestBlocks: %d blocks requested but we have already read %d -- "
+	 "increase MAX_BLOCKS (%d)?  truncating to %d",
+	 numBlks, *retBlksRead, MAX_BLOCKS, blksLeft);
+    numBlks = blksLeft;
+    }
+int i;
+for (i = 0;  i < numBlks;  i++)
+    {
+    int size = randomBlockSize();
+    gotError |= readAndTest(udcf, *retOffset, size, localCopy, url);
+    *retOffset += size;
+    (*retBlksRead)++;
+    }
+return gotError;
+}
+
+// These are defined in udc.c but not udc.h:
+#define udcBlockSize (8*1024)
+boolean udcCheckCacheBits(struct udcFile *file, int startBlock, int endBlock);
+/* Warn and return TRUE (error) if any bit in (startBlock,endBlock] is not set. */
+
+boolean checkCacheFiles(bits64 accessStart, bits64 accessEnd, char *url, char *localCopy)
+/* Given a range of byte offsets accessed via udc, translate those into udc block
+ * coords.  Check that all bytes in the sparseData offsets corresponding to the 
+ * block coords are equal to the reference (very important!) and that all blocks'
+ * bits are set in bitmap (not as important). */
+{
+boolean gotError = FALSE;
+char *bufRef = needMem(udcBlockSize), *bufSparse = needMem(udcBlockSize);
+int startBlock = (int)(accessStart / udcBlockSize);
+int endBlock = (int)((accessEnd + udcBlockSize-1) / udcBlockSize);
+bits64 startOffset = (bits64)startBlock * udcBlockSize;
+verbose(1, "checking sparseData (%lld..%lld] blocks (%d..%d].\n",
+	startOffset, ((bits64)endBlock*udcBlockSize), startBlock, endBlock);
+int fdLocal = mustOpenFd(localCopy, O_RDONLY);
+mustLseek(fdLocal, startOffset, SEEK_SET);
+char *sparseFileName = getSparseFileName(url);
+int fdSparse = mustOpenFd(sparseFileName, O_RDONLY);
+mustLseek(fdSparse, startOffset, SEEK_SET);
+int i;
+for (i = startBlock;  i < endBlock;  i++)
+    {
+    bits64 offset = ((bits64)i * udcBlockSize);
+    memset(bufRef, 0x59, udcBlockSize);
+    memset(bufSparse, 0xae, udcBlockSize);
+    mustReadFd(fdLocal, bufRef, udcBlockSize);
+    mustReadFd(fdSparse, bufSparse, udcBlockSize);
+    char testDesc[64];
+    safef(testDesc, sizeof(testDesc), "SPARSE %lld blk %d", offset, i);
+    gotError |= compareBytes(bufSparse, bufRef, udcBlockSize, sparseFileName, localCopy,
+			     testDesc, offset);
+    }
+mustCloseFd(&fdLocal);
+mustCloseFd(&fdSparse);
+// Check bitmap bits too:
+struct udcFile *udcf = udcFileOpen(url, udcDefaultDir());
+verbose(1, "checking bitmap bits (%d..%d].\n", startBlock, endBlock);
+udcCheckCacheBits(udcf, startBlock, endBlock);
+udcFileClose(&udcf);
+return gotError;
+}
+
+boolean testReadAheadBufferMode(char *url, char *localCopy, int mode)
+/* Open a udcFile, read different random locations, and check for errors. */
+{
+boolean gotError = FALSE;
+bits64 fSize = fileSize(localCopy);
+
+struct udcFile *udcf = udcFileOpen(url, udcDefaultDir());
+bits64 offset = 0;
+if (mode == -1)
+   offset = 0 + 8192 * myDrand();
+if (mode == 0)
+   offset = (bits64)(fSize * myDrand());
+if (mode == 1)
+   offset = fSize - 8192 * myDrand();
+
+
+int delta = 0;
+int i;
+for(i=0; i<100; ++i)
+    {
+
+    int size = 8192 * myDrand();
+
+    if ((offset + size) > fSize)
+	size = fSize - offset;
+
+    gotError |= readAndTest(udcf, offset, size, localCopy, url);
+
+    delta = -6000 + (12000 * myDrand());   // -6000 to +6000
+
+    if (delta < 0)  // do not let unsigned offset go below 0
+	if (-delta > offset)
+    	    delta = -offset;  
+
+    offset += delta;
+
+    if (offset > fSize)
+	offset = fSize;
+
+    }
+
+udcFileClose(&udcf);
+return gotError;
+
+}
+boolean testReadAheadBuffer(char *url, char *localCopy)
+/* Open a udcFile, read different random locations, and check for errors. */
+{
+boolean gotError = FALSE;
+gotError |= testReadAheadBufferMode(url, localCopy, -1);  // near beginning of file
+gotError |= testReadAheadBufferMode(url, localCopy, 0);   // anywherer in file
+gotError |= testReadAheadBufferMode(url, localCopy, 1);   // near end of file
+return gotError;
+}
+
+
+boolean testInterleaved(char *url, char *localCopy)
+/* Open two udcFile handles to the same file, read probably-different random locations,
+ * read from probably-overlapping random locations, and check for errors. */
+{
+boolean gotError = FALSE;
+bits64 size = fileSize(localCopy);
+
+
+// First, read some bytes from udcFile udcf1.
+struct udcFile *udcf1 = udcFileOpen(url, udcDefaultDir());
+int blksRead1 = 0;
+bits64 offset1 = randomStartOffset(size);
+
+gotError |= readAndTestBlocks(udcf1, &offset1, 2, &blksRead1, localCopy, url);
+
+// While keeping udcf1 open, create udcf2 on the same URL, and read from a 
+// (probably) different location:
+struct udcFile *udcf2 = udcFileOpen(url, udcDefaultDir());
+int blksRead2 = 0;
+bits64 offset2 = randomStartOffset(size);
+
+gotError |= readAndTestBlocks(udcf2, &offset2, 2, &blksRead2, localCopy, url);
+// Interleave some successive-location reads:
+int i;
+for (i = 0;  i < 10;  i++)
+    {
+    gotError |= readAndTestBlocks(udcf1, &offset1, 1, &blksRead1, localCopy, url);
+    gotError |= readAndTestBlocks(udcf2, &offset2, 1, &blksRead2, localCopy, url);
+    }
+
+// Unevenly interleave reads starting from the same new random location:
+bits64 sameOffset = randomStartOffset(size);
+blksRead1 = 0;
+offset1 = sameOffset;
+blksRead2 = 0;
+offset2 = sameOffset;
+gotError |= readAndTestBlocks(udcf1, &offset1, 1, &blksRead1, localCopy, url);
+gotError |= readAndTestBlocks(udcf2, &offset2, 3, &blksRead2, localCopy, url);
+while (blksRead1 < MAX_BLOCKS || blksRead2 < MAX_BLOCKS)
+    {
+    if (blksRead1 < MAX_BLOCKS)
+	{
+	int n = 1 + (int)(5 * myDrand());
+	n = min(MAX_BLOCKS - blksRead1, n);
+	gotError |= readAndTestBlocks(udcf1, &offset1, n, &blksRead1, localCopy, url);
+	}
+    if (blksRead2 < MAX_BLOCKS)
+	{
+	int n = 1 + (int)(5 * myDrand());
+	n = min(MAX_BLOCKS - blksRead2, n);
+	gotError |= readAndTestBlocks(udcf2, &offset2, n, &blksRead2, localCopy, url);
+	}
+    }
+udcFileClose(&udcf1);
+udcFileClose(&udcf2);
+verbose(1,"checkCacheFiles\n");
+gotError |= checkCacheFiles(sameOffset, max(offset1, offset2), url, localCopy);
+return gotError;
+}
+
+boolean testConcurrent(char *url, char *localCopy)
+/* Fork; then parent and child access the same locations (hopefully) concurrently. */
+{
+boolean gotErrorParent = FALSE, gotErrorChild = FALSE;
+bits64 size = fileSize(localCopy);
+bits64 sameOffset = randomStartOffset(size);
+bits64 offsetParent = sameOffset, offsetChild = sameOffset;
+
+pid_t kidPid = fork();
+if (kidPid < 0)
+    errnoAbort("testConcurrent: fork failed");
+else if (kidPid == 0)
+    {
+    // child: access url and then exit, to pass control back to parent.
+    struct udcFile *udcf = udcFileOpen(url, udcDefaultDir());
+    int blksRead = 0;
+    gotErrorChild = readAndTestBlocks(udcf, &offsetParent, MAX_BLOCKS, &blksRead, localCopy, url);
+    udcFileClose(&udcf);
+    exit(0);
+    }
+else
+    {
+    // parent: access url, wait for child, do post-checking.
+    struct udcFile *udcf = udcFileOpen(url, udcDefaultDir());
+    int blksRead = 0;
+    gotErrorParent = readAndTestBlocks(udcf, &offsetChild, MAX_BLOCKS, &blksRead, localCopy, url);
+    udcFileClose(&udcf);
+    // wait for child to finish:
+    int childStatus;
+    int retPid = waitpid(kidPid, &childStatus, 0);
+    if (retPid < 0)
+	errnoAbort("testConcurrent: waitpid(%d) failed", kidPid);
+    if (! WIFEXITED(childStatus))
+	warn("testConcurrent: child process did not exit() normally");
+    if (WEXITSTATUS(childStatus))
+	warn("testConcurrent: child exit status = %d)", WEXITSTATUS(childStatus));
+    if (gotErrorChild)
+	verbose(1, "Parent can see child got error.\n");
+    gotErrorParent |= checkCacheFiles(sameOffset, max(offsetParent, offsetChild), url, localCopy);
+    return (gotErrorParent || gotErrorChild);
+    }
+errAbort("testConcurrent: control should never reach this point.");
+return TRUE;
+}
+
+
+int main(int argc, char *argv[])
+/* Set up test params and run tests. */
+{
+boolean gotError = FALSE;
+optionInit(&argc, argv, options);
+raBuf = optionExists("raBuf");
+doFork = optionExists("fork");
+protocol = optionVal("protocol", protocol);
+seed = optionInt("seed", seed);
+
+char *host = getenv("HOST");
+if (host == NULL || !startsWith("hgwdev", host))
+    {
+    // So that we don't break "make test" on other machines, use stdout and exit 0:
+    puts("Sorry, this must be run on hgwdev (with HOST=hgwdev)");
+    exit(0);
+    }
+errAbortDebugnPushPopErr();
+char tmp[256];
+safef(tmp, sizeof tmp, "/data/tmp/%s/udcCache", getenv("USER"));
+udcSetDefaultDir(tmp);
+if (seed == 0)
+    {
+    long now = clock1();
+    printf("Seeding random with unix time %ld\n", now);
+    srand(now);
+    }
+else
+    {
+    printf("Seeding random with option -seed=%d\n", seed);
+    srand(seed);
+    }
+
+if (sameString(protocol, "http"))
+    {
+    char *httpUrl = "http://hgwdev.cse.ucsc.edu/~angie/wgEncodeCshlRnaSeqAlignmentsK562ChromatinShort.bb";
+    char *httpLocalCopy = "/gbdb/hg18/bbi/wgEncodeCshlRnaSeqAlignmentsK562ChromatinShort.bb";
+    if (raBuf)
+	gotError |= testReadAheadBuffer(httpUrl, httpLocalCopy);
+    else if (doFork)
+	gotError |= testConcurrent(httpUrl, httpLocalCopy);
+    else
+	gotError |= testInterleaved(httpUrl, httpLocalCopy);
+    }
+else if (sameString(protocol, "ftp"))
+    {
+    char *ftpUrl = THOUSAND_FTP CHR4_SLX_BAM;
+    char *ftpLocalCopy = THOUSAND_HIVE CHR4_SLX_BAM;
+    if (raBuf)
+	gotError |= testReadAheadBuffer(ftpUrl, ftpLocalCopy);
+    else if (doFork)
+	gotError |= testConcurrent(ftpUrl, ftpLocalCopy);
+    else
+	gotError |= testInterleaved(ftpUrl, ftpLocalCopy);
+    }
+else
+    errAbort("Unrecognized protocol '%s'", protocol);
+return gotError;
+}
diff --git a/lib/tests/udcTrials.csh b/lib/tests/udcTrials.csh
new file mode 100755
index 0000000..e217019
--- /dev/null
+++ b/lib/tests/udcTrials.csh
@@ -0,0 +1,22 @@
+#!/bin/csh -f
+set i = 0
+
+#echo === trial $i ===
+#make udcTest
+#echo ""
+#sleep 5
+#set i = 1
+
+while ($i < 1000)
+  echo === trial $i ===
+  # if you want to clear the cache before each trial
+  rm -fr /data/tmp/galt/udcCache
+  #./bin/x86_64/udcTest
+  ./bin/x86_64/udcTest -protocol=http
+  #./bin/x86_64/udcTest -protocol=http -raBuf
+  #./bin/x86_64/udcTest -protocol=http -fork
+  echo ""
+  #sleep 5
+  sleep 1
+  set i = `expr $i + 1`
+end
diff --git a/lib/tests/vcfParseTest.c b/lib/tests/vcfParseTest.c
new file mode 100644
index 0000000..c6a5fd1
--- /dev/null
+++ b/lib/tests/vcfParseTest.c
@@ -0,0 +1,59 @@
+/* vcfParseTest - Parse VCF header and data lines in given position range.. */
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "options.h"
+#include "sqlNum.h"
+#include "vcf.h"
+
+
+void usage()
+/* Explain usage and exit. */
+{
+errAbort(
+  "vcfParseTest - Parse VCF header and data lines in given position range.\n"
+  "usage:\n"
+  "   vcfParseTest fileOrUrl.vcf.gz seqName start end\n"
+  "\n"
+  "fileOrUrl.vcf.gz needs to have been compressed by tabix, and index file\n"
+  "fileOrUrl.vcf.gz.tbi must exist.\n"
+  );
+}
+
+static struct optionSpec options[] = {
+   {NULL, 0},
+};
+
+void vcfParseTest(char *fileOrUrl, char *seqName, int start, int end)
+/* vcfParseTest - Parse VCF header and data lines in given position range.. */
+{
+struct vcfFile *vcff = vcfTabixFileMayOpen(fileOrUrl, seqName, start, end, 100, -1);
+if (vcff == NULL)
+    errAbort("Failed to parse \"%s\" and/or its index file \"%s.tbi\"", fileOrUrl, fileOrUrl);
+int recCount = slCount(vcff->records);
+printf("Finished parsing \"%s\" items in %s:%d-%d, got %d data rows\n",
+       fileOrUrl, seqName, start+1, end, recCount);
+if (recCount > 0)
+    printf("First (up to) 100 rows in range:\n");
+int i = 0;
+struct vcfRecord *rec = vcff->records;
+while (rec != NULL && i < 100)
+    {
+    printf("%s\t%d\t%d\t%s:%s/%s\t%s\n",
+	   rec->chrom, rec->chromStart, rec->chromEnd,
+	   rec->name, rec->alleles[0], rec->alleles[1], rec->qual);
+    rec = rec->next;
+    i++;
+    }
+vcfFileFree(&vcff);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, options);
+if (argc != 5)
+    usage();
+vcfParseTest(argv[1], argv[2], sqlUnsigned(argv[3]), sqlUnsigned(argv[4]));
+return 0;
+}
diff --git a/lib/textOut.c b/lib/textOut.c
new file mode 100644
index 0000000..d2791b4
--- /dev/null
+++ b/lib/textOut.c
@@ -0,0 +1,163 @@
+/* textOut - set up stdout to be HTTP text, file or compressed file. */
+
+#include "common.h"
+#include "errabort.h"
+#include "cheapcgi.h"
+#include "pipeline.h"
+#include "textOut.h"
+
+
+static void textOutWarnHandler(char *format, va_list args)
+/* Text mode error message handler. */
+{
+char *hLine =
+"---------------------------------------------------------------------------\n";
+if (format != NULL) {
+    fflush(stdout);
+    fprintf(stdout, "%s", hLine);
+    vfprintf(stdout, format, args);
+    fprintf(stdout, "\n");
+    fprintf(stdout, "%s", hLine);
+    }
+}
+
+static void textOutAbortHandler()
+/* Text mode abort handler. */
+{
+exit(-1);
+}
+
+static char *getCompressSuffix(char *compressType)
+/* Return the file dot-suffix (including the dot) for compressType. */
+{
+static char *gzipSuffix = ".gz";
+static char *compressSuffix = ".Z";
+static char *bz2Suffix = ".bz2";
+static char *zipSuffix = ".zip";
+if (sameWord(compressType, textOutCompressGzip))
+    return gzipSuffix;
+else if (sameWord(compressType, textOutCompressCompress))
+    return compressSuffix;
+else if (sameWord(compressType, textOutCompressBzip2))
+    return bz2Suffix;
+else if (sameWord(compressType, textOutCompressZip))
+    return zipSuffix;
+else
+    errAbort("getCompressSuffix: Unsupported textOutCompress type %s",
+	     compressType);
+return NULL;
+}
+
+static char **getCompressor(char *compressType)
+/* Return a compressor specification for pipelineOpen1(). */
+{
+static char *GZ_WRITE[] = {"gzip", "-qc", NULL};
+static char *Z_WRITE[] = {"compress", "-c", NULL};
+static char *BZ2_WRITE[] = {"bzip2", "-qzc", NULL};
+static char *ZIP_WRITE[] = {"zip", "-q", NULL};
+
+if (sameWord(compressType, textOutCompressGzip))
+    return GZ_WRITE;
+else if (sameWord(compressType, textOutCompressCompress))
+    return Z_WRITE;
+else if (sameWord(compressType, textOutCompressBzip2))
+    return BZ2_WRITE;
+else if (sameWord(compressType, textOutCompressZip))
+    return ZIP_WRITE;
+else
+    errAbort("getCompressor: Unsupported textOutCompress type %s",
+	     compressType);
+return NULL;
+}
+
+static void cleanEnvVars(char *compressType)
+/* Ensure vanilla behavior of compressors by removing environment variables 
+ * that they read for option settings. */
+{
+if (sameWord(compressType, textOutCompressGzip))
+    {
+    unsetenv("GZIP");
+    unsetenv("GZIP_OPT");
+    }
+else if (sameWord(compressType, textOutCompressCompress))
+    {
+    /* No environment variables mentioned in man page. */
+    }
+else if (sameWord(compressType, textOutCompressBzip2))
+    {
+    unsetenv("BZIP");
+    unsetenv("BZIP2");
+    }
+else if (sameWord(compressType, textOutCompressZip))
+    {
+    unsetenv("ZIPOPT");
+    }
+else
+    {
+    errAbort("cleanEnvVars: Unsupported textOutCompress type %s",
+	     compressType);
+    }
+}
+
+
+struct pipeline *textOutInit(char *fileName, char *compressType)
+/* Set up stdout to be HTTP text, file (if fileName is specified), or 
+ * compressed file (if both fileName and compressType are specified -- 
+ * see textOut.h for supported compression types).  
+ * Return NULL if no compression, otherwise a pipeline handle on which 
+ * textOutClose should be called when we're done writing stdout. */
+{
+struct pipeline *compressPipeline = NULL;
+
+trimSpaces(fileName);
+if (isEmpty(fileName))
+    {
+    printf("Content-Type: text/plain\n\n");
+    }
+else if (isEmpty(compressType) || sameWord(compressType, textOutCompressNone))
+    {
+    printf("Content-Type: application/octet-stream\n");
+    printf("Content-Disposition: attachment; filename=%s\n\n", fileName);
+    }
+else
+    {
+    char *suffix = getCompressSuffix(compressType);
+
+    printf("Content-Type: application/x-%s\n", compressType);
+    if (endsWith(fileName, suffix))
+	printf("Content-Disposition: attachment; filename=%s\n\n", fileName);
+    else
+	printf("Content-Disposition: attachment; filename=%s%s\n\n",
+	       fileName, suffix);
+
+    /* Send the Content header uncompressed! */
+    fflush(stdout);
+
+    /* Make sure no environment variables interfere with compressor. */
+    cleanEnvVars(compressType);
+
+    /* Redirect stdout to compressor pipeline object. */
+    compressPipeline = pipelineOpen1(getCompressor(compressType),
+				     pipelineWrite, NULL, NULL);
+    if (-1 == dup2(pipelineFd(compressPipeline), STDOUT_FILENO))
+	errnoAbort("dup2(pipelineFd %d, stdout %d) failed in textOpen()",
+		   pipelineFd(compressPipeline), STDOUT_FILENO);
+    }
+pushWarnHandler(textOutWarnHandler);
+pushAbortHandler(textOutAbortHandler);
+return(compressPipeline);
+}
+
+void textOutClose(struct pipeline **pCompressPipeline)
+/* Flush and close stdout, wait for the pipeline to finish, and then free 
+ * the pipeline object. */
+{
+if (pCompressPipeline && *pCompressPipeline)
+    {
+    fflush(stdout);
+    fclose(stdout);
+    pipelineWait(*pCompressPipeline);
+    pipelineFree(pCompressPipeline);
+    }
+}
+
diff --git a/lib/tokenizer.c b/lib/tokenizer.c
new file mode 100644
index 0000000..8b8e188
--- /dev/null
+++ b/lib/tokenizer.c
@@ -0,0 +1,213 @@
+/* tokenizer - A tokenizer structure that will chop up file into
+ * tokens.  It is aware of quoted strings and otherwise tends to return
+ * white-space or punctuated-separated words, with punctuation in
+ * a separate token.  This is used by autoSql. */
+
+#include "common.h"
+#include "errabort.h"
+#include "linefile.h"
+#include "tokenizer.h"
+
+
+struct tokenizer *tokenizerOnLineFile(struct lineFile *lf)
+/* Create a new tokenizer on open lineFile. */
+{
+struct tokenizer *tkz;
+AllocVar(tkz);
+tkz->sAlloc = 128;
+tkz->string = needMem(tkz->sAlloc);
+tkz->lf = lf;
+tkz->curLine = tkz->linePt = "";
+return tkz;
+}
+
+struct tokenizer *tokenizerNew(char *fileName)
+/* Return a new tokenizer. */
+{
+return tokenizerOnLineFile(lineFileOpen(fileName, TRUE));
+}
+
+void tokenizerFree(struct tokenizer **pTkz)
+/* Tear down a tokenizer. */
+{
+struct tokenizer *tkz;
+if ((tkz = *pTkz) != NULL)
+    {
+    freeMem(tkz->string);
+    lineFileClose(&tkz->lf);
+    freez(pTkz);
+    }
+}
+
+void tokenizerReuse(struct tokenizer *tkz)
+/* Reuse token. */
+{
+if (!tkz->eof)
+    tkz->reuse = TRUE;
+}
+
+int tokenizerLineCount(struct tokenizer *tkz)
+/* Return line of current token. */
+{
+return tkz->lf->lineIx;
+}
+
+char *tokenizerFileName(struct tokenizer *tkz)
+/* Return name of file. */
+{
+return tkz->lf->fileName;
+}
+
+char *tokenizerNext(struct tokenizer *tkz)
+/* Return token's next string (also available as tkz->string) or
+ * NULL at EOF. */
+{
+char *start, *end;
+char c, *s;
+int size;
+if (tkz->reuse)
+    {
+    tkz->reuse = FALSE;
+    return tkz->string;
+    }
+tkz->leadingSpaces = 0;
+for (;;)	/* Skip over white space and comments. */
+    {
+    int lineSize;
+    s = start = skipLeadingSpaces(tkz->linePt);
+    tkz->leadingSpaces += s - tkz->linePt;
+    if ((c = start[0]) != 0)
+	{
+	if (tkz->uncommentC && c == '/')
+	     {
+	     if (start[1] == '/')
+		 ;  /* Keep going in loop effectively ignoring rest of line. */
+	     else if (start[1] == '*')
+		 {
+		 start += 2;
+		 for (;;)
+		     {
+		     char *end = stringIn("*/", start);
+		     if (end != NULL)
+			  {
+			  tkz->linePt = end+2;
+			  break;
+			  }
+		     if (!lineFileNext(tkz->lf, &tkz->curLine, &lineSize))
+			  errAbort("End of file (%s) in comment", tokenizerFileName(tkz));
+		     start = tkz->curLine;
+		     }
+		 continue;
+		 }
+	     else
+		 break;
+	     }
+	else if (tkz->uncommentShell && c == '#')
+	     ;  /* Keep going in loop effectively ignoring rest of line. */
+	else
+	    break;	/* Got something real. */
+	}
+    if (!lineFileNext(tkz->lf, &tkz->curLine, &lineSize))
+	{
+	tkz->eof = TRUE;
+	return NULL;
+	}
+    tkz->leadingSpaces += 1;
+    tkz->linePt = tkz->curLine;
+    }
+if (isalnum(c) || (c == '_'))
+    {
+    for (;;)
+	{
+        s++;
+	if (!(isalnum(*s) || (*s == '_')))
+	    break;
+	}
+    end = s;
+    }
+else if (c == '"' || c == '\'')
+    {
+    char quot = c;
+    if (tkz->leaveQuotes)
+	start = s++;
+    else
+	start = ++s;
+    for (;;)
+	{
+	c = *s;
+	if (c == quot)
+	    {
+	    if (s[-1] == '\\')
+		{
+		if (s >= start+2 && s[-2] == '\\')
+		    break;
+		}
+	    else
+		break;
+	    }
+	else if (c == 0)
+	    {
+	    break;
+	    }
+	++s;
+	}
+    end = s;
+    if (c != 0)
+	++s;
+    if (tkz->leaveQuotes)
+	end += 1;
+    }
+else
+    {
+    end = ++s;
+    }
+tkz->linePt = s;
+size = end - start;
+if (size >= tkz->sAlloc)
+    {
+    tkz->sAlloc = size+128;
+    tkz->string = needMoreMem(tkz->string, 0, tkz->sAlloc);
+    }
+memcpy(tkz->string, start, size);
+tkz->string[size] = 0;
+return tkz->string;
+}
+
+
+void tokenizerErrAbort(struct tokenizer *tkz, char *format, ...)
+/* Print error message followed by file and line number and
+ * abort. */
+{
+va_list args;
+va_start(args, format);
+vaWarn(format, args);
+errAbort("line %d of %s:\n%s", 
+	tokenizerLineCount(tkz), tokenizerFileName(tkz), tkz->curLine);
+}
+
+void tokenizerNotEnd(struct tokenizer *tkz)
+/* Squawk if at end. */
+{
+if (tkz->eof)
+    errAbort("Unexpected end of file");
+}
+
+char *tokenizerMustHaveNext(struct tokenizer *tkz)
+/* Get next token, which must be there. */
+{
+char *s = tokenizerNext(tkz);
+if (s == NULL)
+    errAbort("Unexpected end of file");
+return s;
+}
+
+void tokenizerMustMatch(struct tokenizer *tkz, char *string)
+/* Require next token to match string.  Return next token
+ * if it does, otherwise abort. */
+{
+if (sameWord(tkz->string, string))
+    tokenizerMustHaveNext(tkz);
+else
+    tokenizerErrAbort(tkz, "Expecting %s got %s", string, tkz->string);
+}
+
diff --git a/lib/trix.c b/lib/trix.c
new file mode 100644
index 0000000..a2a8999
--- /dev/null
+++ b/lib/trix.c
@@ -0,0 +1,718 @@
+/* trix - text retrieval index.  Stuff for fast two level index
+ * of text for fast word searches. */
+
+#include "common.h"
+#include "hash.h"
+#include "linefile.h"
+#include "trix.h"
+#include "sqlNum.h"
+
+
+/* Some local structures for the search. */
+struct trixHitPos 
+/* A hit to the index. */
+    {
+    struct trixHitPos *next;	/* Next in list */
+    char *itemId;		/* Associated itemId */
+    int wordIx;			/* Which word this is part of. */
+    int leftoverLetters;	/* Number of letters at end of word not matched */
+    };
+
+struct trixWordResult
+/* Results of a search on one word. */
+    {
+    struct trixWordResult *next;
+    char *word;			/* Word name. */
+    struct trixHitPos *hitList;	/* Hit list.  May be shared (not allocated here). */
+    struct trixHitPos *hit;	/* Current position while iterating through hit list. */
+    struct trixHitPos *iHit;	/* Current position during an inner iteration. */
+    };
+
+struct trixIxx
+/* A prefix and */
+    {
+    off_t pos;	   /* Position where prefix first occurs in file. */
+    char prefix[trixPrefixSize];/* Space padded first five letters of what we're indexing. */
+    };
+
+/* Some cleanup code. */
+
+static void trixHitPosFree(struct trixHitPos **pPos)
+/* Free up trixHitPos. */
+{
+struct trixHitPos *pos = *pPos;
+if (pos != NULL)
+    {
+    freeMem(pos->itemId);
+    freez(pPos);
+    }
+}
+
+static void trixHitPosFreeList(struct trixHitPos **pList)
+/* Free up a list of trixHitPoss. */
+{
+struct trixHitPos *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    trixHitPosFree(&el);
+    }
+*pList = NULL;
+}
+
+static void trixWordResultFree(struct trixWordResult **pTwr)
+/* Free up a trixWordResult */
+{
+struct trixWordResult *twr = *pTwr;
+if (twr != NULL)
+    {
+    freeMem(twr->word);
+    freez(pTwr);
+    }
+}
+
+static void trixWordResultFreeList(struct trixWordResult **pList)
+/* Free up a list of trixWordResults. */
+{
+struct trixWordResult *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    trixWordResultFree(&el);
+    }
+*pList = NULL;
+}
+
+static void freeHitCallback(void *val)
+/* Val is actually list trixHitPos.  This called to free stuff in hash. */
+{
+struct trixHitPos *posList = val;
+trixHitPosFreeList(&posList);
+}
+
+void trixClose(struct trix **pTrix)
+/* Close up index and free up associated resources. */
+{
+struct trix *trix = *pTrix;
+if (trix != NULL)
+    {
+    freeMem(trix->ixx);
+    hashTraverseVals(trix->wordHitHash, freeHitCallback);
+    hashFree(&trix->wordHitHash);	/* Need to free items? */
+    freez(pTrix);
+    }
+}
+
+void trixSearchResultFree(struct trixSearchResult **pTsr)
+/* Free up data associated with trixSearchResult. */
+{
+struct trixSearchResult *tsr = *pTsr;
+if (tsr != NULL)
+    {
+    freeMem(tsr->itemId);
+    freez(pTsr);
+    }
+}
+
+void trixSearchResultFreeList(struct trixSearchResult **pList)
+/* Free up a list of trixSearchResults. */
+{
+struct trixSearchResult *el, *next;
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    trixSearchResultFree(&el);
+    }
+*pList = NULL;
+}
+
+
+/* Code that makes, rather than cleans up. */
+
+static char unhexTable[128];	/* Lookup table to help with hex conversion. */
+
+static void initUnhexTable()
+/* Initialize a table for fast unhexing of numbers. */
+{
+unhexTable['0'] = 0;
+unhexTable['1'] = 1;
+unhexTable['2'] = 2;
+unhexTable['3'] = 3;
+unhexTable['4'] = 4;
+unhexTable['5'] = 5;
+unhexTable['6'] = 6;
+unhexTable['7'] = 7;
+unhexTable['8'] = 8;
+unhexTable['9'] = 9;
+unhexTable['A'] = 10;
+unhexTable['B'] = 11;
+unhexTable['C'] = 12;
+unhexTable['D'] = 13;
+unhexTable['E'] = 14;
+unhexTable['F'] = 15;
+}
+
+static off_t unhex(char hex[10])
+/* Convert 10 character hex string to off_t */
+{
+off_t  x = 0;
+int i;
+
+for (i=0; i<10; ++i)
+   {
+   x <<= 4;
+   x += unhexTable[(unsigned)hex[i]];
+   }
+return x;
+}
+
+struct trix *trixNew()
+/* Create a new empty trix index. */
+{
+struct trix *trix;
+AllocVar(trix);
+trix->ixxAlloc = 8*1024;
+AllocArray(trix->ixx, trix->ixxAlloc);
+trix->wordHitHash = newHash(8);
+return trix;
+}
+
+void trixAddToIxx(struct trix *trix, off_t pos, char *prefix)
+/* Add to trix->ixx. */
+{
+struct trixIxx *ixx;
+if (trix->ixxSize >= trix->ixxAlloc)
+     {
+     trix->ixxAlloc += trix->ixxAlloc;	/* Double allocation. */
+     ExpandArray(trix->ixx, trix->ixxSize, trix->ixxAlloc);
+     }
+ixx = trix->ixx + trix->ixxSize;
+ixx->pos = pos;
+memcpy(ixx->prefix, prefix, sizeof(ixx->prefix));
+trix->ixxSize += 1;
+}
+
+struct trix *trixOpen(char *ixFile)
+/* Open up index.  Load second level index in memory. */
+{
+char ixxFile[PATH_LEN];
+struct trix *trix;
+struct lineFile *lf;
+char *line;
+
+initUnhexTable();
+safef(ixxFile, sizeof(ixxFile), "%sx", ixFile);
+lf = lineFileOpen(ixxFile, TRUE);
+trix = trixNew();
+while (lineFileNext(lf, &line, NULL))
+    {
+    off_t pos = unhex(line+trixPrefixSize);
+    trixAddToIxx(trix, pos, line);
+    }
+lineFileClose(&lf);
+trix->lf = lineFileOpen(ixFile, TRUE);
+return trix;
+}
+
+void trixCopyToPrefix(char *word, char *prefix)
+/* Copy first part of word to prefix.  If need be end pad with spaces. */
+{
+int len = strlen(word);
+if (len >= trixPrefixSize)
+    memcpy(prefix, word, trixPrefixSize);
+else
+    {
+    memset(prefix, ' ', trixPrefixSize);
+    memcpy(prefix, word, len);
+    }
+}
+
+static off_t trixFindIndexStartLine(struct trix *trix, char *word)
+/* Find start position of line we want to start at in the first level
+ * index. */
+{
+char wordPrefix[trixPrefixSize];
+int i;
+off_t pos = 0;
+
+trixCopyToPrefix(word, wordPrefix);
+toLowerN(wordPrefix, trixPrefixSize);
+for (i=0; i<trix->ixxSize; ++i)
+    {
+    struct trixIxx *ixx = trix->ixx + i;
+    if (memcmp(wordPrefix, ixx->prefix, trixPrefixSize) < 0)
+       break;
+    pos = ixx->pos;
+    }
+return pos;
+}
+
+static struct trixHitPos *trixParseHitList(char *hitWord, char *hitString,
+	int leftoverLetters)
+/* Parse out hit string, inserting zeroes in it during process.
+ * Return result as list of trixHitPos. */
+{
+struct trixHitPos *hit, *hitList = NULL;
+char *word;
+while ((word = nextWord(&hitString)) != NULL)
+    {
+    char *parts[3];
+    int partCount;
+    partCount = chopByChar(word, ',', parts, ArraySize(parts));
+    if (partCount != 2)
+        errAbort("Error in index format at word %s", hitWord);
+    AllocVar(hit);
+    hit->itemId = cloneString(parts[0]);
+    hit->wordIx = sqlUnsigned(parts[1]);
+    hit->leftoverLetters = leftoverLetters;
+    slAddHead(&hitList, hit);
+    }
+slReverse(&hitList);
+return hitList;
+}
+
+int trixHitPosCmp(struct trixHitPos *a, struct trixHitPos *b)
+/* Compare function to sort trixHitPos. */
+{
+int diff = strcmp(a->itemId, b->itemId);
+if (diff == 0)
+    {
+    diff = a->wordIx - b->wordIx;
+    if (diff == 0)
+        diff = a->leftoverLetters - b->leftoverLetters;
+    }
+return diff;
+}
+
+
+struct trixHitPos *mergeHits(struct trixHitPos *aList, struct trixHitPos *bList)
+/* Return hit list that merges aList and bList.  The input is sorted,
+ * and so is the output. */
+{
+struct trixHitPos *a, *b, *aNext, *bNext, *newList = NULL;
+
+a = aList;
+b = bList;
+for (;;)
+    {
+    if (a == NULL)
+        {
+	if (b == NULL)
+	    break;
+	bNext = b->next;
+	slAddHead(&newList, b);
+	b = bNext;
+	}
+    else if (b == NULL)
+        {
+	aNext = a->next;
+	slAddHead(&newList, a);
+	a = aNext;
+	}
+    else if (trixHitPosCmp(a, b) < 0)
+        {
+	aNext = a->next;
+	slAddHead(&newList, a);
+	a = aNext;
+	}
+    else
+        {
+	bNext = b->next;
+	slAddHead(&newList, b);
+	b = bNext;
+	}
+    }
+slReverse(&newList);
+return newList;
+}
+
+static int reasonablePrefix(char *prefix, char *word, boolean expand)
+/* Return non-negative if prefix is reasonable for word.
+ * Returns number of letters left in word not matched by
+ * prefix. */
+{
+int prefixLen = strlen(prefix);
+int wordLen = strlen(word);
+int suffixLen = wordLen - prefixLen;
+if (suffixLen == 0)
+   return 0;
+else if (expand && prefixLen >= 3)
+    {
+    int wordEnd;
+    char *suffix = word + prefixLen;
+    boolean prefixEndsInDigit = isdigit(word[prefixLen-1]);
+    /* Find a word marker - either end of string, '-', '.', or '_'
+     * or a number. */
+    for (wordEnd=0; wordEnd < suffixLen; ++wordEnd)
+        {
+	char c = suffix[wordEnd];
+	if (c == '-' || c == '.' || c == '_' || (!prefixEndsInDigit && isdigit(c)))
+	    break;
+	}
+    if (wordEnd <= 2)
+       return wordEnd;
+    if (wordEnd == 3 && startsWith("ing", suffix))
+       return wordEnd;
+    }
+return -1;
+}
+
+
+struct trixWordResult *trixSearchWordResults(struct trix *trix, 
+	char *searchWord, boolean expand)
+/* Get results for single word from index.  Returns NULL if no matches. */
+{
+char *line, *word;
+struct trixWordResult *twr = NULL;
+struct trixHitPos *hitList = hashFindVal(trix->wordHitHash, searchWord);
+
+if (hitList == NULL)
+    {
+    struct trixHitPos *oneHitList;
+    off_t ixPos = trixFindIndexStartLine(trix, searchWord);
+    lineFileSeek(trix->lf, ixPos, SEEK_SET);
+    while (lineFileNext(trix->lf, &line, NULL))
+	{
+	word = nextWord(&line);
+	if (startsWith(searchWord, word))
+	    {
+	    int leftoverLetters = reasonablePrefix(searchWord, word, expand);
+	    /* uglyf("reasonablePrefix(%s,%s)=%d<BR>\n", searchWord, word, leftoverLetters); */
+	    if (leftoverLetters >= 0)
+		{
+		oneHitList = trixParseHitList(searchWord, line, 
+			leftoverLetters);
+		hitList = mergeHits(hitList, oneHitList);
+		}
+	    }
+	else if (strcmp(searchWord, word) < 0)
+	    break;
+	}
+    hashAdd(trix->wordHitHash, searchWord, hitList);
+    }
+if (hitList != NULL)
+    {
+    AllocVar(twr);
+    twr->word = cloneString(searchWord);
+    twr->hitList = hitList;
+    }
+return twr;
+}
+
+
+#ifdef DEBUG
+void trwDump(struct trixWordResult *twr)
+/* Dump out one trixWordResult to stdout. */
+{
+struct trixHitPos *hit;
+int hitIx, maxHits = 8;
+
+printf("%d matches to %s:", slCount(twr->hitList), twr->word);
+for (hit=twr->hitList, hitIx=0; hit != NULL && hitIx < maxHits; hit=hit->next, hitIx+=1)
+    printf(" %s@%d", hit->itemId, hit->wordIx);
+if (hit != NULL)
+    printf(" ...");
+printf("<BR>\n");
+}
+#endif /* DEBUG */
+
+static char *highestId(struct trixWordResult *twrList)
+/* Return highest itemId at current twr->hit */
+{
+char *itemId = twrList->hit->itemId;
+struct trixWordResult *twr;
+
+for (twr = twrList->next; twr != NULL; twr = twr->next)
+    {
+    if (strcmp(itemId, twr->hit->itemId) < 0)
+        itemId = twr->hit->itemId;
+    }
+return itemId;
+}
+
+static boolean seekOneToId(struct trixWordResult *twr, char *itemId)
+/* Move twr->hit forward until it hits itemId.  Return FALSE if
+ * moved past where itemId would be without hitting it. */
+{
+struct trixHitPos *hit;
+int diff = -1;
+for (hit = twr->hit; hit != NULL; hit = hit->next)
+    {
+    diff = strcmp(itemId, hit->itemId);
+    if (diff <= 0)
+        break;
+    }
+twr->hit = hit;
+return diff == 0;
+}
+
+static boolean seekAllToId(struct trixWordResult *twrList, char *itemId)
+/* Try to seek all twr's in list to the same itemId */
+{
+struct trixWordResult *twr;
+boolean allHit = TRUE;
+for (twr = twrList; twr != NULL; twr = twr->next)
+    {
+    if (!seekOneToId(twr, itemId))
+        allHit = FALSE;
+    }
+return allHit;
+}
+
+static void seekAllPastId(struct trixWordResult *twrList, char *itemId)
+/* Try to seek all twr's in list to past the itemId. */
+{
+struct trixWordResult *twr;
+for (twr = twrList; twr != NULL; twr = twr->next)
+    {
+    struct trixHitPos *hit;
+    for (hit = twr->hit; hit != NULL; hit = hit->next)
+	if (!sameString(hit->itemId, itemId))
+	    break;
+    twr->hit = hit;
+    }
+}
+
+static boolean anyTwrDone(struct trixWordResult *twrList)
+/* Return TRUE if any of the items in list are done */
+{
+struct trixWordResult *twr;
+for (twr = twrList; twr != NULL; twr = twr->next)
+    if (twr->hit == NULL)
+        return TRUE;
+return FALSE;
+}
+
+static void findUnorderedSpan(struct trixWordResult *twrList,
+	char *itemId, int *retSpan, int *retLeftoverLetters)
+/* Find out smallest number of words in doc that will cover
+ * all words in search. */
+{
+int minSpan = BIGNUM;
+int leftoverLetters = 0;
+struct trixWordResult *twr;
+
+/* Set up iHit pointers we use to keep track of our 
+ * search.  Don't want to mess with hit pointers as they
+ * will be used later. */
+for (twr = twrList; twr != NULL; twr = twr->next)
+    twr->iHit = twr->hit;
+
+for (;;)
+    {
+    int minWord = BIGNUM, maxWord=0, span;
+    int curLeftover = 0;
+
+    /* Figure out current span and save as min if it's smallest so far. */
+    for (twr = twrList; twr != NULL; twr = twr->next)
+        {
+	int curWord = twr->iHit->wordIx;
+	if (curWord < minWord)
+	    minWord = curWord;
+	if (curWord > maxWord)
+	    maxWord = curWord;
+	curLeftover += twr->iHit->leftoverLetters;
+	}
+    span = maxWord - minWord;
+    if (span < minSpan)
+	{
+        minSpan = span;
+	leftoverLetters = curLeftover;
+	}
+
+    /* Advance iHit past minWord.  Break if we go outside of our doc or item. */
+    for (twr = twrList; twr != NULL; twr = twr->next)
+        {
+	if (twr->iHit->wordIx == minWord)
+	    {
+	    struct trixHitPos *hit = twr->iHit = twr->iHit->next;
+	    if (hit == NULL || !sameString(hit->itemId, itemId))
+	        {
+		*retSpan = minSpan+1;
+		*retLeftoverLetters = leftoverLetters;
+		return;
+		}
+	    }
+	}
+    }
+} 
+
+static int findWordPos(struct trixWordResult *twrList, char *itemId)
+/* Figure out the first word position.  For multiple words, this
+ * will be the maximimum first word position of all words. 
+ * This assumes that the hits are sorted by word position
+ * within a document. */
+{
+int firstWordPos = 0;
+struct trixWordResult *twr;
+for (twr = twrList; twr != NULL; twr = twr->next)
+    {
+    int pos = twr->hit->wordIx;
+    if (firstWordPos < pos)
+        firstWordPos = pos;
+    }
+return firstWordPos;
+}
+
+static int findOrderedSpan(struct trixWordResult *twrList,
+	char *itemId)
+/* Find out smallest number of words in doc that will cover
+ * all words in search. */
+{
+int minSpan = BIGNUM - 1;  // subtract 1 to accomodate adding 1 below
+struct trixWordResult *twr;
+
+/* Set up iHit pointers we use to keep track of our 
+ * search.  Don't want to mess with hit pointers as they
+ * will be used later. */
+for (twr = twrList; twr != NULL; twr = twr->next)
+    twr->iHit = twr->hit;
+
+for (;;)
+    {
+    int startWord = twrList->iHit->wordIx;
+    int endWord = startWord;
+    int span;
+    struct trixHitPos *hit;
+
+    /* Set up twr->iHit to be closest one past hit of previous twr. */
+    for (twr = twrList->next; twr != NULL; twr = twr->next)
+        {
+	for (hit = twr->iHit; ; hit = hit->next)
+	    {
+	    if (hit == NULL || !sameString(hit->itemId, itemId))
+	        return minSpan + 1;
+	    if (hit->wordIx > endWord)
+	        break;
+	    }
+	twr->iHit = hit;
+	endWord = hit->wordIx;
+	}
+    span = endWord - startWord;
+    if (span < minSpan)
+        minSpan = span;
+
+    /* Advance to next occurence of first word. */
+    hit = twrList->iHit = twrList->iHit->next;
+    if (hit == NULL || !sameString(hit->itemId, itemId))
+	return minSpan+1;
+    }
+}
+
+
+static struct trixSearchResult *findMultipleWordHits(struct trixWordResult *twrList)
+/* Return list of items that are hit by all words. */
+{
+struct trixWordResult *twr;
+struct trixSearchResult *tsList = NULL, *ts;
+
+/* Initially set hit position to start on all words. */
+for (twr = twrList; twr != NULL; twr = twr->next)
+    twr->hit = twr->hitList;
+
+for (;;)
+    {
+    char *itemId = highestId(twrList);
+    if (seekAllToId(twrList, itemId))
+        {
+	AllocVar(ts);
+	ts->itemId = cloneString(itemId);
+	findUnorderedSpan(twrList, itemId, 
+		&ts->unorderedSpan, &ts->leftoverLetters);
+	ts->orderedSpan = findOrderedSpan(twrList, itemId);
+	ts->wordPos = findWordPos(twrList, itemId);
+	slAddHead(&tsList, ts);
+	}
+    seekAllPastId(twrList, itemId);
+    if (anyTwrDone(twrList))
+        break;
+    }
+slReverse(&tsList);
+return tsList;
+}
+
+int trixSearchResultCmp(const void *va, const void *vb)
+/* Compare two trixSearchResult by itemId. */
+{
+const struct trixSearchResult *a = *((struct trixSearchResult **)va);
+const struct trixSearchResult *b = *((struct trixSearchResult **)vb);
+int dif;
+dif = a->unorderedSpan - b->unorderedSpan;
+if (dif == 0)
+   {
+   dif = a->orderedSpan - b->orderedSpan;
+   if (dif == 0)
+       {
+       dif = a->leftoverLetters - b->leftoverLetters;
+       if (dif == 0)
+	   dif = a->wordPos - b->wordPos;
+       }
+   }
+       
+return dif;
+}
+
+struct trixSearchResult *trixSearch(struct trix *trix, int wordCount, char **words,
+	boolean expand)
+/* Return a list of items that match all words.  This will be sorted so that
+ * multiple-word matches where the words are closer to each other and in the
+ * right order will be first.  Do a trixSearchResultFreeList when done. 
+ * If expand is TRUE then this will match not only the input words, but also
+ * additional words that start with the input words. */
+{
+struct trixWordResult *twr, *twrList = NULL;
+struct trixSearchResult *ts, *tsList = NULL;
+int wordIx;
+boolean gotMiss = FALSE;
+
+if (wordCount == 1)
+    {
+    struct trixHitPos *hit;
+    char *lastId = "";
+    twr = twrList = trixSearchWordResults(trix, words[0], expand);
+    if (twr == NULL)
+        return NULL;
+    for (hit = twr->hitList; hit != NULL; hit = hit->next)
+        {
+	if (!sameString(lastId, hit->itemId))
+	    {
+	    lastId = hit->itemId;
+	    AllocVar(ts);
+	    ts->itemId = hit->itemId;	/* Transfer itemId */
+	    hit->itemId = NULL;
+	    ts->orderedSpan = 1;
+	    ts->unorderedSpan = 1;
+	    ts->wordPos = hit->wordIx;
+	    ts->leftoverLetters = hit->leftoverLetters;
+	    slAddHead(&tsList, ts);
+	    }
+	}
+    }
+else
+    {
+    for (wordIx=0; wordIx<wordCount; ++wordIx)
+	{
+	char *searchWord = words[wordIx];
+	twr = trixSearchWordResults(trix, searchWord, expand);
+	if (twr == NULL)
+	    {
+	    gotMiss = TRUE;
+	    break;
+	    }
+	slAddHead(&twrList, twr);
+#ifdef DEBUG
+	trwDump(twr);
+#endif /* DEBUG */
+	}
+    if (!gotMiss)
+	{
+	slReverse(&twrList);
+	tsList = findMultipleWordHits(twrList);
+	}
+    }
+trixWordResultFreeList(&twrList);
+slSort(&tsList, trixSearchResultCmp);
+return tsList;
+}
+
+
diff --git a/lib/twoBit.c b/lib/twoBit.c
new file mode 100644
index 0000000..008b2d6
--- /dev/null
+++ b/lib/twoBit.c
@@ -0,0 +1,1074 @@
+#include "common.h"
+#include "hash.h"
+#include "dnaseq.h"
+#include "dnautil.h"
+#include "sig.h"
+#include "localmem.h"
+#include "linefile.h"
+#include "obscure.h"
+#include "bPlusTree.h"
+#include "twoBit.h"
+#include <limits.h>
+
+
+static int countBlocksOfN(char *s, int size)
+/* Count number of blocks of N's (or n's) in s. */
+{
+int i;
+boolean isN, lastIsN = FALSE;
+char c;
+int blockCount = 0;
+
+for (i=0; i<size; ++i)
+    {
+    c = s[i];
+    isN = (c == 'n' || c == 'N');
+    if (isN && !lastIsN)
+	++blockCount;
+    lastIsN = isN;
+    }
+return blockCount;
+}
+
+static int countBlocksOfLower(char *s, int size)
+/* Count number of blocks of lower case letters. */
+{
+int i;
+boolean isLower, lastIsLower = FALSE;
+int blockCount = 0;
+
+for (i=0; i<size; ++i)
+    {
+    isLower = islower(s[i]);
+    if (isLower && !lastIsLower)
+	++blockCount;
+    lastIsLower = isLower;
+    }
+return blockCount;
+}
+
+static void storeBlocksOfN(char *s, int size, bits32 *starts, bits32 *sizes)
+/* Store starts and sizes of blocks of N's. */
+{
+int i;
+boolean isN, lastIsN = FALSE;
+int startN = 0;
+char c;
+
+for (i=0; i<size; ++i)
+    {
+    c = s[i];
+    isN = (c == 'n' || c == 'N');
+    if (isN)
+        {
+	if (!lastIsN)
+	    startN = i;
+	}
+    else
+        {
+	if (lastIsN)
+	    {
+	    *starts++ = startN;
+	    *sizes++ = i - startN;
+	    }
+	}
+    lastIsN = isN;
+    }
+if (lastIsN)
+    {
+    *starts = startN;
+    *sizes = i - startN;
+    }
+}
+
+static void storeBlocksOfLower(char *s, int size, bits32 *starts, bits32 *sizes)
+/* Store starts and sizes of blocks of lower case letters. */
+{
+int i;
+boolean isLower, lastIsLower = FALSE;
+int startLower = 0;
+
+for (i=0; i<size; ++i)
+    {
+    isLower = islower(s[i]);
+    if (isLower)
+        {
+	if (!lastIsLower)
+	    startLower = i;
+	}
+    else
+        {
+	if (lastIsLower)
+	    {
+	    *starts++ = startLower;
+	    *sizes++ = i - startLower;
+	    }
+	}
+    lastIsLower = isLower;
+    }
+if (lastIsLower)
+    {
+    *starts = startLower;
+    *sizes = i - startLower;
+    }
+}
+
+static int packedSize(int unpackedSize)
+/* Return size when packed, rounding up. */
+{
+return ((unpackedSize + 3) >> 2);
+}
+
+struct twoBit *twoBitFromDnaSeq(struct dnaSeq *seq, boolean doMask)
+/* Convert dnaSeq representation in memory to twoBit representation.
+ * If doMask is true interpret lower-case letters as masked. */
+{
+int ubyteSize = packedSize(seq->size);
+UBYTE *pt;
+struct twoBit *twoBit;
+DNA last4[4];	/* Holds few bases. */
+DNA *dna;
+int i, end;
+
+/* Allocate structure and fill in name. */
+AllocVar(twoBit);
+pt = AllocArray(twoBit->data, ubyteSize);
+twoBit->name = cloneString(seq->name);
+twoBit->size = seq->size;
+
+/* Convert to 4-bases per byte representation. */
+dna = seq->dna;
+end = seq->size - 4;
+for (i=0; i<end; i += 4)
+    {
+    *pt++ = packDna4(dna+i);
+    }
+
+/* Take care of conversion of last few bases. */
+last4[0] = last4[1] = last4[2] = last4[3] = 'T';
+memcpy(last4, dna+i, seq->size-i);
+*pt = packDna4(last4);
+
+/* Deal with blocks of N. */
+twoBit->nBlockCount = countBlocksOfN(dna, seq->size);
+if (twoBit->nBlockCount > 0)
+    {
+    AllocArray(twoBit->nStarts, twoBit->nBlockCount);
+    AllocArray(twoBit->nSizes, twoBit->nBlockCount);
+    storeBlocksOfN(dna, seq->size, twoBit->nStarts, twoBit->nSizes);
+    }
+
+/* Deal with masking */
+if (doMask)
+    {
+    twoBit->maskBlockCount = countBlocksOfLower(dna, seq->size);
+    if (twoBit->maskBlockCount > 0)
+        {
+	AllocArray(twoBit->maskStarts, twoBit->maskBlockCount);
+	AllocArray(twoBit->maskSizes, twoBit->maskBlockCount);
+	storeBlocksOfLower(dna, seq->size, 
+		twoBit->maskStarts, twoBit->maskSizes);
+	}
+    }
+return twoBit;
+}
+
+
+static int twoBitSizeInFile(struct twoBit *twoBit)
+/* Figure out size structure will take in file. */
+{
+return packedSize(twoBit->size) 
+	+ sizeof(twoBit->size)
+	+ sizeof(twoBit->nBlockCount)
+	+ sizeof(twoBit->nStarts[0]) * twoBit->nBlockCount
+	+ sizeof(twoBit->nSizes[0]) * twoBit->nBlockCount
+	+ sizeof(twoBit->maskBlockCount)
+	+ sizeof(twoBit->maskStarts[0]) * twoBit->maskBlockCount
+	+ sizeof(twoBit->maskSizes[0]) * twoBit->maskBlockCount
+	+ sizeof(twoBit->reserved);
+}
+
+void twoBitWriteOne(struct twoBit *twoBit, FILE *f)
+/* Write out one twoBit sequence to binary file. 
+ * Note this does not include the name, which is
+ * stored only in index. */
+{
+writeOne(f, twoBit->size);
+writeOne(f, twoBit->nBlockCount);
+if (twoBit->nBlockCount > 0)
+    {
+    fwrite(twoBit->nStarts, sizeof(twoBit->nStarts[0]), 
+    	twoBit->nBlockCount, f);
+    fwrite(twoBit->nSizes, sizeof(twoBit->nSizes[0]), 
+    	twoBit->nBlockCount, f);
+    }
+writeOne(f, twoBit->maskBlockCount);
+if (twoBit->maskBlockCount > 0)
+    {
+    fwrite(twoBit->maskStarts, sizeof(twoBit->maskStarts[0]), 
+    	twoBit->maskBlockCount, f);
+    fwrite(twoBit->maskSizes, sizeof(twoBit->maskSizes[0]), 
+    	twoBit->maskBlockCount, f);
+    }
+writeOne(f, twoBit->reserved);
+mustWrite(f, twoBit->data, packedSize(twoBit->size));
+}
+
+void twoBitWriteHeader(struct twoBit *twoBitList, FILE *f)
+/* Write out header portion of twoBit file, including initial
+ * index */
+{
+bits32 sig = twoBitSig;
+bits32 version = 0;
+bits32 seqCount = slCount(twoBitList);
+bits32 reserved = 0;
+bits32 offset = 0;
+struct twoBit *twoBit;
+long long counter = 0; /* check for 32 bit overflow */
+
+/* Write out fixed parts of header. */
+writeOne(f, sig);
+writeOne(f, version);
+writeOne(f, seqCount);
+writeOne(f, reserved);
+
+/* Figure out location of first byte past index.
+ * Each index entry contains 4 bytes of offset information
+ * and the name of the sequence, which is variable length. */
+offset = sizeof(sig) + sizeof(version) + sizeof(seqCount) + sizeof(reserved);
+for (twoBit = twoBitList; twoBit != NULL; twoBit = twoBit->next)
+    {
+    int nameLen = strlen(twoBit->name);
+    if (nameLen > 255)
+        errAbort("name %s too long", twoBit->name);
+    offset += nameLen + 1 + sizeof(bits32);
+    }
+
+/* Write out index. */
+for (twoBit = twoBitList; twoBit != NULL; twoBit = twoBit->next)
+    {
+    int size = twoBitSizeInFile(twoBit);
+    writeString(f, twoBit->name);
+    writeOne(f, offset);
+    offset += size;
+    counter += (long long)size;
+    if (counter > UINT_MAX )
+        errAbort("Error in faToTwoBit, index overflow at %s. The 2bit format "
+                "does not support indexes larger than %dGb, \n"
+                "please split up into smaller files.\n", 
+                twoBit->name, UINT_MAX/1000000000);
+    }
+}
+
+void twoBitClose(struct twoBitFile **pTbf)
+/* Free up resources associated with twoBitFile. */
+{
+struct twoBitFile *tbf = *pTbf;
+if (tbf != NULL)
+    {
+    freez(&tbf->fileName);
+    carefulClose(&tbf->f);
+    hashFree(&tbf->hash);
+    /* The indexList is allocated out of the hash's memory pool. */
+    bptFileClose(&tbf->bpt);
+    freez(pTbf);
+    }
+}
+
+static struct twoBitFile *twoBitOpenReadHeader(char *fileName)
+/* Open file, read in header but not index.  
+ * Squawk and die if there is a problem. */
+{
+bits32 sig;
+struct twoBitFile *tbf;
+boolean isSwapped = FALSE;
+FILE *f = mustOpen(fileName, "rb");
+
+/* Allocate header verify signature, and read in
+ * the constant-length bits. */
+AllocVar(tbf);
+mustReadOne(f, sig);
+if (sig == twoBitSwapSig)
+    isSwapped = tbf->isSwapped = TRUE;
+else if (sig != twoBitSig)
+    errAbort("%s doesn't have a valid twoBitSig", fileName);
+tbf->fileName = cloneString(fileName);
+tbf->f = f;
+tbf->version = readBits32(f, isSwapped);
+if (tbf->version != 0)
+    {
+    errAbort("Can only handle version 0 of this file. This is version %d",
+    	(int)tbf->version);
+    }
+tbf->seqCount = readBits32(f, isSwapped);
+tbf->reserved = readBits32(f, isSwapped);
+return tbf;
+}
+
+struct twoBitFile *twoBitOpen(char *fileName)
+/* Open file, read in header and index.  
+ * Squawk and die if there is a problem. */
+{
+struct twoBitFile *tbf = twoBitOpenReadHeader(fileName);
+struct twoBitIndex *index;
+boolean isSwapped = tbf->isSwapped;
+int i;
+struct hash *hash;
+FILE *f = tbf->f;
+
+/* Read in index. */
+hash = tbf->hash = hashNew(digitsBaseTwo(tbf->seqCount));
+for (i=0; i<tbf->seqCount; ++i)
+    {
+    char name[256];
+    if (!fastReadString(f, name))
+        errAbort("%s is truncated", fileName);
+    lmAllocVar(hash->lm, index);
+    index->offset = readBits32(f, isSwapped);
+    hashAddSaveName(hash, name, index, &index->name);
+    slAddHead(&tbf->indexList, index);
+    }
+slReverse(&tbf->indexList);
+return tbf;
+}
+
+struct twoBitFile *twoBitOpenExternalBptIndex(char *twoBitName, char *bptName)
+/* Open file, read in header, but not regular index.  Instead use
+ * bpt index.   Beware if you use this the indexList field will be NULL
+ * as will the hash. */
+{
+struct twoBitFile *tbf = twoBitOpenReadHeader(twoBitName);
+tbf->bpt = bptFileOpen(bptName);
+if (tbf->seqCount != tbf->bpt->itemCount)
+    errAbort("%s and %s don't have same number of sequences!", twoBitName, bptName);
+return tbf;
+}
+
+
+static int findGreatestLowerBound(int blockCount, bits32 *pos, 
+	int val)
+/* Find index of greatest element in posArray that is less 
+ * than or equal to val using a binary search. */
+{
+int startIx=0, endIx=blockCount-1, midIx;
+int posVal;
+
+for (;;)
+    {
+    if (startIx == endIx)
+        {
+	posVal = pos[startIx];
+	if (posVal <= val || startIx == 0)
+	    return startIx;
+	else
+	    return startIx-1;
+	}
+    midIx = ((startIx + endIx)>>1);
+    posVal = pos[midIx];
+    if (posVal < val)
+        startIx = midIx+1;
+    else
+        endIx = midIx;
+    }
+}
+
+static void twoBitSeekTo(struct twoBitFile *tbf, char *name)
+/* Seek to start of named record.  Abort if can't find it. */
+{
+if (tbf->bpt)
+    {
+    bits32 offset;
+    if (!bptFileFind(tbf->bpt, name, strlen(name), &offset, sizeof(offset)))
+	 errAbort("%s is not in %s", name, tbf->bpt->fileName);
+    fseek(tbf->f, offset, SEEK_SET);
+    }
+else
+    {
+    struct twoBitIndex *index = hashFindVal(tbf->hash, name);
+    if (index == NULL)
+	 errAbort("%s is not in %s", name, tbf->fileName);
+    fseek(tbf->f, index->offset, SEEK_SET);
+    }
+}
+
+static void readBlockCoords(FILE *f, boolean isSwapped, bits32 *retBlockCount,
+			    bits32 **retBlockStarts, bits32 **retBlockSizes)
+/* Read in blockCount, starts and sizes from file. (Same structure used for
+ * both blocks of N's and masked blocks.) */
+{
+bits32 blkCount = readBits32(f, isSwapped);
+*retBlockCount = blkCount;
+if (blkCount == 0)
+    {
+    *retBlockStarts = NULL;
+    *retBlockSizes = NULL;
+    }
+else
+    {
+    bits32 *nStarts, *nSizes;
+    AllocArray(nStarts, blkCount);
+    AllocArray(nSizes, blkCount);
+    mustRead(f, nStarts, sizeof(nStarts[0]) * blkCount);
+    mustRead(f, nSizes, sizeof(nSizes[0]) * blkCount);
+    if (isSwapped)
+	{
+	int i;
+	for (i=0; i<blkCount; ++i)
+	    {
+	    nStarts[i] = byteSwap32(nStarts[i]);
+	    nSizes[i] = byteSwap32(nSizes[i]);
+	    }
+	}
+    *retBlockStarts = nStarts;
+    *retBlockSizes = nSizes;
+    }
+}
+
+struct twoBit *twoBitOneFromFile(struct twoBitFile *tbf, char *name)
+/* Get single sequence as two bit. */
+{
+bits32 packByteCount;
+boolean isSwapped = tbf->isSwapped;
+struct twoBit *twoBit;
+AllocVar(twoBit);
+twoBit->name = cloneString(name);
+FILE *f = tbf->f;
+
+/* Find offset in index and seek to it */
+twoBitSeekTo(tbf, name);
+
+/* Read in seqSize. */
+twoBit->size = readBits32(f, isSwapped);
+
+/* Read in blocks of N. */
+readBlockCoords(f, isSwapped, &(twoBit->nBlockCount),
+		&(twoBit->nStarts), &(twoBit->nSizes));
+
+/* Read in masked blocks. */
+readBlockCoords(f, isSwapped, &(twoBit->maskBlockCount),
+		&(twoBit->maskStarts), &(twoBit->maskSizes));
+
+/* Reserved word. */
+twoBit->reserved = readBits32(f, isSwapped);
+
+/* Read in data. */
+packByteCount = packedSize(twoBit->size);
+twoBit->data = needLargeMem(packByteCount);
+mustRead(f, twoBit->data, packByteCount);
+
+return twoBit;
+}
+
+struct twoBit *twoBitFromFile(char *fileName)
+/* Get twoBit list of all sequences in twoBit file. */
+{
+struct twoBitFile *tbf = twoBitOpen(fileName);
+struct twoBitIndex *index;
+struct twoBit *twoBitList = NULL;
+
+for (index = tbf->indexList; index != NULL; index = index->next)
+    {
+    struct twoBit *twoBit = twoBitOneFromFile(tbf, index->name);
+    slAddHead(&twoBitList, twoBit);
+    }
+
+twoBitClose(&tbf);
+slReverse(&twoBitList);
+return twoBitList;
+}
+
+
+void twoBitFree(struct twoBit **pTwoBit)
+/* Free up a two bit structure. */
+{
+struct twoBit *twoBit = *pTwoBit;
+if (twoBit != NULL)
+    {
+    freeMem(twoBit->nStarts);
+    freeMem(twoBit->nSizes);
+    freeMem(twoBit->maskStarts);
+    freeMem(twoBit->maskSizes);
+    freeMem(twoBit->data);
+    freez(pTwoBit);
+    }
+}
+
+void twoBitFreeList(struct twoBit **pList)
+/* Free a list of dynamically allocated twoBit's */
+{
+struct twoBit *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    twoBitFree(&el);
+    }
+*pList = NULL;
+}
+
+
+struct dnaSeq *twoBitReadSeqFragExt(struct twoBitFile *tbf, char *name,
+	int fragStart, int fragEnd, boolean doMask, int *retFullSize)
+/* Read part of sequence from .2bit file.  To read full
+ * sequence call with start=end=0.  Sequence will be lower
+ * case if doMask is false, mixed case (repeats in lower)
+ * if doMask is true. */
+{
+struct dnaSeq *seq;
+bits32 seqSize;
+bits32 nBlockCount, maskBlockCount;
+bits32 *nStarts = NULL, *nSizes = NULL;
+bits32 *maskStarts = NULL, *maskSizes = NULL;
+boolean isSwapped = tbf->isSwapped;
+FILE *f = tbf->f;
+int i;
+int packByteCount, packedStart, packedEnd, remainder, midStart, midEnd;
+int outSize;
+UBYTE *packed, *packedAlloc;
+DNA *dna;
+
+/* Find offset in index and seek to it */
+dnaUtilOpen();
+twoBitSeekTo(tbf, name);
+
+/* Read in seqSize. */
+seqSize = readBits32(f, isSwapped);
+if (fragEnd == 0)
+    fragEnd = seqSize;
+if (fragEnd > seqSize)
+    errAbort("twoBitReadSeqFrag in %s end (%d) >= seqSize (%d)", name, fragEnd, seqSize);
+outSize = fragEnd - fragStart;
+if (outSize < 1)
+    errAbort("twoBitReadSeqFrag in %s start (%d) >= end (%d)", name, fragStart, fragEnd);
+
+/* Read in blocks of N. */
+readBlockCoords(f, isSwapped, &nBlockCount, &nStarts, &nSizes);
+
+/* Read in masked blocks. */
+readBlockCoords(f, isSwapped, &maskBlockCount, &maskStarts, &maskSizes);
+
+/* Skip over reserved word. */
+readBits32(f, isSwapped);
+
+/* Allocate dnaSeq, and fill in zero tag at end of sequence. */
+AllocVar(seq);
+if (outSize == seqSize)
+    seq->name = cloneString(name);
+else
+    {
+    char buf[256*2];
+    safef(buf, sizeof(buf), "%s:%d-%d", name, fragStart, fragEnd);
+    seq->name = cloneString(buf);
+    }
+seq->size = outSize;
+dna = seq->dna = needLargeMem(outSize+1);
+seq->dna[outSize] = 0;
+
+
+/* Skip to bits we need and read them in. */
+packedStart = (fragStart>>2);
+packedEnd = ((fragEnd+3)>>2);
+packByteCount = packedEnd - packedStart;
+packed = packedAlloc = needLargeMem(packByteCount);
+fseek(f, packedStart, SEEK_CUR);
+mustRead(f, packed, packByteCount);
+
+/* Handle case where everything is in one packed byte */
+if (packByteCount == 1)
+    {
+    int pOff = (packedStart<<2);
+    int pStart = fragStart - pOff;
+    int pEnd = fragEnd - pOff;
+    UBYTE partial = *packed;
+    assert(pEnd <= 4);
+    assert(pStart >= 0);
+    for (i=pStart; i<pEnd; ++i)
+	*dna++ = valToNt[(partial >> (6-i-i)) & 3];
+    }
+else
+    {
+    /* Handle partial first packed byte. */
+    midStart = fragStart;
+    remainder = (fragStart&3);
+    if (remainder > 0)
+	{
+	UBYTE partial = *packed++;
+	int partCount = 4 - remainder;
+	for (i=partCount-1; i>=0; --i)
+	    {
+	    dna[i] = valToNt[partial&3];
+	    partial >>= 2;
+	    }
+	midStart += partCount;
+	dna += partCount;
+	}
+
+    /* Handle middle bytes. */
+    remainder = fragEnd&3;
+    midEnd = fragEnd - remainder;
+    for (i=midStart; i<midEnd; i += 4)
+        {
+	UBYTE b = *packed++;
+	dna[3] = valToNt[b&3];
+	b >>= 2;
+	dna[2] = valToNt[b&3];
+	b >>= 2;
+	dna[1] = valToNt[b&3];
+	b >>= 2;
+	dna[0] = valToNt[b&3];
+	dna += 4;
+	}
+
+    if (remainder >0)
+	{
+	UBYTE part = *packed;
+	part >>= (8-remainder-remainder);
+	for (i=remainder-1; i>=0; --i)
+	    {
+	    dna[i] = valToNt[part&3];
+	    part >>= 2;
+	    }
+	}
+    }
+freez(&packedAlloc);
+
+if (nBlockCount > 0)
+    {
+    int startIx = findGreatestLowerBound(nBlockCount, nStarts, fragStart);
+    for (i=startIx; i<nBlockCount; ++i)
+        {
+	int s = nStarts[i];
+	int e = s + nSizes[i];
+	if (s >= fragEnd)
+	    break;
+	if (s < fragStart)
+	   s = fragStart;
+	if (e > fragEnd)
+	   e = fragEnd;
+	if (s < e)
+	    memset(seq->dna + s - fragStart, 'n', e - s);
+	}
+    }
+
+if (doMask)
+    {
+    toUpperN(seq->dna, seq->size);
+    if (maskBlockCount > 0)
+	{
+	int startIx = findGreatestLowerBound(maskBlockCount, maskStarts, 
+		fragStart);
+	for (i=startIx; i<maskBlockCount; ++i)
+	    {
+	    int s = maskStarts[i];
+	    int e = s + maskSizes[i];
+	    if (s >= fragEnd)
+		break;
+	    if (s < fragStart)
+		s = fragStart;
+	    if (e > fragEnd)
+		e = fragEnd;
+	    if (s < e)
+		toLowerN(seq->dna + s - fragStart, e - s);
+	    }
+	}
+    }
+freez(&nStarts);
+freez(&nSizes);
+freez(&maskStarts);
+freez(&maskSizes);
+if (retFullSize != NULL)
+    *retFullSize = seqSize;
+return seq;
+}
+
+struct dnaSeq *twoBitReadSeqFrag(struct twoBitFile *tbf, char *name,
+	int fragStart, int fragEnd)
+/* Read part of sequence from .2bit file.  To read full
+ * sequence call with start=end=0.  Note that sequence will
+ * be mixed case, with repeats in lower case and rest in
+ * upper case. */
+{
+return twoBitReadSeqFragExt(tbf, name, fragStart, fragEnd, TRUE, NULL);
+}
+
+struct dnaSeq *twoBitReadSeqFragLower(struct twoBitFile *tbf, char *name,
+	int fragStart, int fragEnd)
+/* Same as twoBitReadSeqFrag, but sequence is returned in lower case. */
+{
+return twoBitReadSeqFragExt(tbf, name, fragStart, fragEnd, FALSE, NULL);
+}
+
+int twoBitSeqSize(struct twoBitFile *tbf, char *name)
+/* Return size of sequence in two bit file in bases. */
+{
+twoBitSeekTo(tbf, name);
+return readBits32(tbf->f, tbf->isSwapped);
+}
+
+long long twoBitTotalSize(struct twoBitFile *tbf)
+/* Return total size of all sequences in two bit file. */
+{
+struct twoBitIndex *index;
+long long totalSize = 0;
+for (index = tbf->indexList; index != NULL; index = index->next)
+    {
+    fseek(tbf->f, index->offset, SEEK_SET);
+    totalSize += readBits32(tbf->f, tbf->isSwapped);
+    }
+return totalSize;
+}
+
+struct dnaSeq *twoBitLoadAll(char *spec)
+/* Return list of all sequences matching spec, which is in
+ * the form:
+ *
+ *    file/path/input.2bit[:seqSpec1][,seqSpec2,...]
+ *
+ * where seqSpec is either
+ *     seqName
+ *  or
+ *     seqName:start-end */
+{
+struct twoBitSpec *tbs = twoBitSpecNew(spec);
+struct twoBitFile *tbf = twoBitOpen(tbs->fileName);
+struct dnaSeq *list = NULL;
+if (tbs->seqs != NULL)
+    {
+    struct twoBitSeqSpec *tbss;
+    for (tbss = tbs->seqs; tbss != NULL; tbss = tbss->next)
+        slSafeAddHead(&list, twoBitReadSeqFrag(tbf, tbss->name,
+                                               tbss->start, tbss->end));
+    }
+else
+    {
+    struct twoBitIndex *index;
+    for (index = tbf->indexList; index != NULL; index = index->next)
+	slSafeAddHead(&list, twoBitReadSeqFrag(tbf, index->name, 0, 0));
+    }
+slReverse(&list);
+twoBitClose(&tbf);
+twoBitSpecFree(&tbs);
+return list;
+}
+
+struct slName *twoBitSeqNames(char *fileName)
+/* Get list of all sequences in twoBit file. */
+{
+struct twoBitFile *tbf = twoBitOpen(fileName);
+struct twoBitIndex *index;
+struct slName *name, *list = NULL;
+for (index = tbf->indexList; index != NULL; index = index->next)
+    {
+    name = slNameNew(index->name);
+    slAddHead(&list, name);
+    }
+twoBitClose(&tbf);
+slReverse(&list);
+return list;
+}
+
+boolean twoBitIsFile(char *fileName)
+/* Return TRUE if file is in .2bit format. */
+{
+return endsWith(fileName, ".2bit");
+}
+
+boolean twoBitParseRange(char *rangeSpec, char **retFile, 
+	char **retSeq, int *retStart, int *retEnd)
+/* Parse out something in format
+ *    file/path/name:seqName:start-end
+ * or
+ *    file/path/name:seqName
+ * or
+ *    file/path/name:seqName1,seqName2,seqName3,...
+ * This will destroy the input 'rangeSpec' in the process.  Returns FALSE if
+ * it doesn't fit this format, setting retFile to rangeSpec, and retSet to
+ * null.  If it is the shorter form then start and end will both be returned
+ * as zero, which is ok by twoBitReadSeqFrag.  Any of the return arguments
+ * maybe NULL.
+ */
+{
+char *s, *e;
+int n;
+
+/* default returns */
+if (retFile != NULL)
+    *retFile = rangeSpec;
+if (retSeq != NULL)
+    *retSeq = NULL;
+if (retStart != NULL)
+    *retStart = 0;
+if (retEnd != NULL)
+    *retEnd = 0;
+
+/* start with final name  */
+s = strrchr(rangeSpec, '/');
+if (s == NULL)
+    s = rangeSpec;
+else
+    s++;
+
+/* Grab seqName, zero terminate fileName. */
+s = strchr(s, ':');
+if (s == NULL)
+    return FALSE;
+*s++ = 0;
+if (retSeq != NULL)
+    *retSeq = s;
+
+/* Grab start, zero terminate seqName. */
+s = strchr(s, ':');
+if (s == NULL)
+    return TRUE;  /* no range spec */
+*s++ = 0;
+n = strtol(s, &e, 0);
+if (*e != '-')
+    return FALSE; /* not a valid range */
+if (retStart != NULL)
+    *retStart = n;
+s = e+1;
+
+/* Grab end. */
+n = strtol(s, &e, 0);
+if (*e != '\0')
+    return FALSE; /* not a valid range */
+if (retEnd != NULL)
+    *retEnd = n;
+return TRUE;
+}
+
+boolean twoBitIsRange(char *rangeSpec)
+/* Return TRUE if it looks like a two bit range specifier. */
+{
+char *dupe = cloneString(rangeSpec);
+char *file, *seq;
+int start, end;
+boolean isRange = twoBitParseRange(dupe, &file, &seq, &start, &end);
+if (isRange)
+    isRange = twoBitIsFile(file);
+freeMem(dupe);
+return isRange;
+}
+
+boolean twoBitIsFileOrRange(char *spec)
+/* Return TRUE if it is a two bit file or subrange. */
+{
+return twoBitIsFile(spec) || twoBitIsRange(spec);
+}
+
+static struct twoBitSeqSpec *parseSeqSpec(char *seqSpecStr)
+/* parse one sequence spec */
+{
+boolean isOk = TRUE;
+char *s, *e;
+struct twoBitSeqSpec *seq;
+AllocVar(seq);
+seq->name = cloneString(seqSpecStr);
+
+/* Grab start */
+s = strchr(seq->name, ':');
+if (s == NULL)
+    return seq;  /* no range spec */
+*s++ = 0;
+seq->start = strtol(s, &e, 0);
+if (*e != '-')
+    isOk = FALSE;
+else
+    {
+    /* Grab end */
+    s = e+1;
+    seq->end = strtol(s, &e, 0);
+    if (*e != '\0')
+        isOk = FALSE;
+    }
+if (!isOk || (seq->end < seq->start))
+    errAbort("invalid twoBit sequence specification: \"%s\"", seqSpecStr);
+return seq;
+}
+
+boolean twoBitIsSpec(char *spec)
+/* Return TRUE spec is a valid 2bit spec (see twoBitSpecNew) */
+{
+struct twoBitSpec *tbs = twoBitSpecNew(spec);
+boolean isSpec = (tbs != NULL);
+twoBitSpecFree(&tbs);
+return isSpec;
+}
+
+struct twoBitSpec *twoBitSpecNew(char *specStr)
+/* Parse a .2bit file and sequence spec into an object.
+ * The spec is a string in the form:
+ *
+ *    file/path/input.2bit[:seqSpec1][,seqSpec2,...]
+ *
+ * where seqSpec is either
+ *     seqName
+ *  or
+ *     seqName:start-end
+ *
+ * free result with twoBitSpecFree().
+ */
+{
+char *s, *e;
+int i, numSeqs;
+char **seqSpecs;
+struct twoBitSpec *spec;
+AllocVar(spec);
+spec->fileName = cloneString(specStr);
+
+/* start with final file name  */
+s = strrchr(spec->fileName, '/');
+if (s == NULL)
+    s = spec->fileName;
+else
+    s++;
+
+/* find end of file name and zero-terminate */
+e = strchr(s, ':');
+if (e == NULL)
+    s = NULL; /* just file name */
+else
+    {
+    *e++ = '\0';
+    s = e;
+    }
+if (!endsWith(spec->fileName, ".2bit"))
+    {
+    twoBitSpecFree(&spec);
+    return NULL; /* not a 2bit file */
+    }
+
+if (s != NULL)
+    {
+    /* chop seqs at commas and parse */
+    numSeqs = chopString(s, ",", NULL, 0);
+    AllocArray(seqSpecs, numSeqs);
+    chopString(s, ",", seqSpecs, numSeqs);
+    for (i = 0; i< numSeqs; i++)
+        slSafeAddHead(&spec->seqs, parseSeqSpec(seqSpecs[i]));
+    slReverse(&spec->seqs);
+    }
+return spec;
+}
+
+struct twoBitSpec *twoBitSpecNewFile(char *twoBitFile, char *specFile)
+/* parse a file containing a list of specifications for sequences in the
+ * specified twoBit file. Specifications are one per line in forms:
+ *     seqName
+ *  or
+ *     seqName:start-end
+ */
+{
+struct lineFile *lf = lineFileOpen(specFile, TRUE);
+char *line;
+struct twoBitSpec *spec;
+AllocVar(spec);
+spec->fileName = cloneString(twoBitFile);
+while (lineFileNextReal(lf, &line))
+    slSafeAddHead(&spec->seqs, parseSeqSpec(trimSpaces(line)));
+slReverse(&spec->seqs);
+lineFileClose(&lf);
+return spec;
+}
+
+void twoBitSpecFree(struct twoBitSpec **specPtr)
+/* free a twoBitSpec object */
+{
+struct twoBitSpec *spec = *specPtr;
+if (spec != NULL)
+    {
+    struct twoBitSeqSpec *seq;
+    while ((seq = slPopHead(&spec->seqs)) != NULL)
+        {
+        freeMem(seq->name);
+        freeMem(seq);
+        }
+    freeMem(spec->fileName);
+    freeMem(spec);
+    *specPtr = NULL;
+    }
+}
+
+void twoBitOutNBeds(struct twoBitFile *tbf, char *seqName, FILE *outF)
+/* output a series of bed3's that enumerate the number of N's in a sequence*/
+{
+int nBlockCount;
+
+twoBitSeekTo(tbf, seqName);
+
+readBits32(tbf->f, tbf->isSwapped);
+
+/* Read in blocks of N. */
+nBlockCount = readBits32(tbf->f, tbf->isSwapped);
+
+if (nBlockCount > 0)
+    {
+    bits32 *nStarts = NULL, *nSizes = NULL;
+    int i;
+
+    AllocArray(nStarts, nBlockCount);
+    AllocArray(nSizes, nBlockCount);
+    mustRead(tbf->f, nStarts, sizeof(nStarts[0]) * nBlockCount);
+    mustRead(tbf->f, nSizes, sizeof(nSizes[0]) * nBlockCount);
+    if (tbf->isSwapped)
+	{
+	for (i=0; i<nBlockCount; ++i)
+	    {
+	    nStarts[i] = byteSwap32(nStarts[i]);
+	    nSizes[i] = byteSwap32(nSizes[i]);
+	    }
+	}
+
+    for (i=0; i<nBlockCount; ++i)
+	{
+	fprintf(outF, "%s\t%d\t%d\n", seqName, nStarts[i], nStarts[i] + nSizes[i]);
+	}
+
+    freez(&nStarts);
+    freez(&nSizes);
+    }
+}
+
+int twoBitSeqSizeNoNs(struct twoBitFile *tbf, char *seqName)
+/* return the size of the sequence, not counting N's*/
+{
+int nBlockCount;
+int size;
+
+twoBitSeekTo(tbf, seqName);
+
+size = readBits32(tbf->f, tbf->isSwapped);
+
+/* Read in blocks of N. */
+nBlockCount = readBits32(tbf->f, tbf->isSwapped);
+
+if (nBlockCount > 0)
+    {
+    bits32 *nStarts = NULL, *nSizes = NULL;
+    
+    int i;
+
+    AllocArray(nStarts, nBlockCount);
+    AllocArray(nSizes, nBlockCount);
+    mustRead(tbf->f, nStarts, sizeof(nStarts[0]) * nBlockCount);
+    mustRead(tbf->f, nSizes, sizeof(nSizes[0]) * nBlockCount);
+    if (tbf->isSwapped)
+	{
+	for (i=0; i<nBlockCount; ++i)
+	    {
+	    nStarts[i] = byteSwap32(nStarts[i]);
+	    nSizes[i] = byteSwap32(nSizes[i]);
+	    }
+	}
+
+    for (i=0; i<nBlockCount; ++i)
+	{
+	size -= nSizes[i];
+	}
+
+    freez(&nStarts);
+    freez(&nSizes);
+    }
+
+return(size);
+}
diff --git a/lib/udc.c b/lib/udc.c
new file mode 100644
index 0000000..3697678
--- /dev/null
+++ b/lib/udc.c
@@ -0,0 +1,1596 @@
+/* udc - url data cache - a caching system that keeps blocks of data fetched from URLs in
+ * sparse local files for quick use the next time the data is needed. 
+ *
+ * This cache is enormously simplified by there being no local _write_ to the cache,
+ * just reads.  
+ *
+ * The overall strategy of the implementation is to have a root cache directory
+ * with a subdir for each file being cached.  The directory for a single cached file
+ * contains two files - "bitmap" and "sparseData" that contains information on which
+ * parts of the URL are cached and the actual cached data respectively. The subdirectory name
+ * associated with the file is constructed from the URL in a straightforward manner.
+ *     http://genome.ucsc.edu/cgi-bin/hgGateway
+ * gets mapped to:
+ *     rootCacheDir/http/genome.ucsc.edu/cgi-bin/hgGateway/
+ * The URL protocol is the first directory under the root, and the remainder of the
+ * URL, with some necessary escaping, is used to define the rest of the cache directory
+ * structure, with each '/' after the protocol line translating into another directory
+ * level.
+ *    
+ * The bitmap file contains time stamp and size data as well as an array with one bit
+ * for each block of the file that has been fetched.  Currently the block size is 8K. */
+
+#include <sys/file.h>
+#include "common.h"
+#include "hash.h"
+#include "obscure.h"
+#include "bits.h"
+#include "linefile.h"
+#include "portable.h"
+#include "sig.h"
+#include "net.h"
+#include "cheapcgi.h"
+#include "udc.h"
+
+
+#define udcBlockSize (8*1024)
+/* All fetch requests are rounded up to block size. */
+
+#define udcMaxBytesPerRemoteFetch (udcBlockSize * 32)
+/* Very large remote reads are broken down into chunks this size. */
+
+struct connInfo
+/* Socket descriptor and associated info, for keeping net connections open. */
+    {
+    int socket;                 /* Socket descriptor for data connection (or 0). */
+    bits64 offset;		/* Current file offset of socket. */
+    int ctrlSocket;             /* (FTP only) Control socket descriptor or 0. */
+    };
+
+typedef int (*UdcDataCallback)(char *url, bits64 offset, int size, void *buffer,
+			       struct connInfo *ci);
+/* Type for callback function that fetches file data. */
+
+struct udcRemoteFileInfo
+/* Information about a remote file. */
+    {
+    bits64 updateTime;	/* Last update in seconds since 1970 */
+    bits64 size;	/* Remote file size */
+    struct connInfo ci; /* Connection info for open net connection */
+    };
+
+typedef boolean (*UdcInfoCallback)(char *url, struct udcRemoteFileInfo *retInfo);
+/* Type for callback function that fetches file timestamp and size. */
+
+struct udcProtocol
+/* Something to handle a communications protocol like http, https, ftp, local file i/o, etc. */
+    {
+    struct udcProtocol *next;	/* Next in list */
+    UdcDataCallback fetchData;	/* Data fetcher */
+    UdcInfoCallback fetchInfo;	/* Timestamp & size fetcher */
+    };
+
+struct udcFile
+/* A file handle for our caching system. */
+    {
+    struct udcFile *next;	/* Next in list. */
+    char *url;			/* Name of file - includes protocol */
+    char *protocol;		/* The URL up to the first colon.  http: etc. */
+    struct udcProtocol *prot;	/* Protocol specific data and methods. */
+    time_t updateTime;		/* Last modified timestamp. */
+    bits64 size;		/* Size of file. */
+    bits64 offset;		/* Current offset in file. */
+    char *cacheDir;		/* Directory for cached file parts. */
+    char *bitmapFileName;	/* Name of bitmap file. */
+    char *sparseFileName;	/* Name of sparse data file. */
+    int fdSparse;		/* File descriptor for sparse data file. */
+    boolean sparseReadAhead;    /* Read-ahead has something in the buffer */
+    char *sparseReadAheadBuf;   /* Read-ahead buffer, if any */
+    bits64 sparseRAOffset;      /* Read-ahead buffer offset */
+    struct udcBitmap *bits;     /* udcBitMap */
+    bits64 startData;		/* Start of area in file we know to have data. */
+    bits64 endData;		/* End of area in file we know to have data. */
+    bits32 bitmapVersion;	/* Version of associated bitmap we were opened with. */
+    struct connInfo connInfo;   /* Connection info for open net connection. */
+    };
+
+struct udcBitmap
+/* The control structure including the bitmap of blocks that are cached. */
+    {
+    struct udcBitmap *next;	/* Next in list. */
+    bits32 blockSize;		/* Number of bytes per block of file. */
+    bits64 remoteUpdate;	/* Remote last update time. */
+    bits64 fileSize;		/* File size */
+    bits32 version;		/* Version - increments each time cache is stale. */
+    bits64 localUpdate;		/* Time we last fetched new data into cache. */
+    bits64 localAccess;		/* Time we last accessed data. */
+    boolean isSwapped;		/* If true need to swap all bytes on read. */
+    int fd;			/* File descriptor for file with current block. */
+    };
+static char *bitmapName = "bitmap";
+static char *sparseDataName = "sparseData";
+#define udcBitmapHeaderSize (64)
+static int cacheTimeout = 0;
+
+#define MAX_SKIP_TO_SAVE_RECONNECT (udcMaxBytesPerRemoteFetch / 2)
+
+static void readAndIgnore(int sd, bits64 size)
+/* Read size bytes from sd and return. */
+{
+static char *buf = NULL;
+if (buf == NULL)
+    buf = needMem(udcBlockSize);
+bits64 remaining = size, total = 0;
+while (remaining > 0)
+    {
+    bits64 chunkSize = min(remaining, udcBlockSize);
+    bits64 rd = read(sd, buf, chunkSize);
+    if (rd < 0)
+	errnoAbort("readAndIgnore: error reading socket after %lld bytes", total);
+    remaining -= rd;
+    total += rd;
+    }
+if (total < size)
+    errAbort("readAndIgnore: got EOF at %lld bytes (wanted %lld)", total, size);
+}
+
+static int connInfoGetSocket(struct connInfo *ci, char *url, bits64 offset, int size)
+/* If ci has an open socket and the given offset matches ci's current offset,
+ * reuse ci->socket.  Otherwise close the socket, open a new one, and update ci,
+ * or return -1 if there is an error opening a new one. */
+{
+if (ci != NULL && ci->socket > 0 && ci->offset != offset)
+    {
+    bits64 skipSize = (offset - ci->offset);
+    if (skipSize > 0 && skipSize <= MAX_SKIP_TO_SAVE_RECONNECT)
+	{
+	verbose(2, "!! skipping %lld bytes @%lld to avoid reconnect\n", skipSize, ci->offset);
+	readAndIgnore(ci->socket, skipSize);
+	ci->offset = offset;
+	}
+    else
+	{
+	verbose(2, "Offset mismatch (ci %lld != new %lld), reopening.\n", ci->offset, offset);
+	mustCloseFd(&(ci->socket));
+	if (ci->ctrlSocket > 0)
+	    mustCloseFd(&(ci->ctrlSocket));
+	ZeroVar(ci);
+	}
+    }
+int sd;
+if (ci == NULL || ci->socket <= 0)
+    {
+    char rangeUrl[2048];
+    if (ci == NULL)
+	{
+	safef(rangeUrl, sizeof(rangeUrl), "%s;byterange=%lld-%lld",
+	      url, offset, (offset + size - 1));
+	sd = netUrlOpen(rangeUrl);
+	}
+    else
+	{
+	safef(rangeUrl, sizeof(rangeUrl), "%s;byterange=%lld-", url, offset);
+	sd = ci->socket = netUrlOpenSockets(rangeUrl, &(ci->ctrlSocket));
+	ci->offset = offset;
+	}
+    if (sd < 0)
+	return -1;
+    if (startsWith("http", url))
+	{
+	char *newUrl = NULL;
+	int newSd = 0;
+	if (!netSkipHttpHeaderLinesHandlingRedirect(sd, rangeUrl, &newSd, &newUrl))
+	    return -1;
+	if (newUrl)
+	    {
+	    freeMem(newUrl); 
+	    sd = newSd;
+	    if (ci != NULL)
+		ci->socket = newSd;
+	    }
+	}
+    }
+else
+    sd = ci->socket;
+return sd;
+}
+
+/********* Section for local file protocol **********/
+
+static char *assertLocalUrl(char *url)
+/* Make sure that url is local and return bits past the protocol. */
+{
+if (startsWith("local:", url))
+    url += 6;
+if (url[0] != '/')
+    errAbort("Local urls must start at /");
+if (stringIn("..", url) || stringIn("~", url) || stringIn("//", url) ||
+    stringIn("/./", url) || endsWith("/.", url))
+    {
+    errAbort("relative paths not allowed in local urls (%s)", url);
+    }
+return url;
+}
+
+static int udcDataViaLocal(char *url, bits64 offset, int size, void *buffer, struct connInfo *ci)
+/* Fetch a block of data of given size into buffer using the http: protocol.
+* Returns number of bytes actually read.  Does an errAbort on
+* error.  Typically will be called with size in the 8k - 64k range. */
+{
+/* Need to check time stamp here. */
+verbose(2, "reading remote data - %d bytes at %lld - on %s\n", size, offset, url);
+url = assertLocalUrl(url);
+FILE *f = mustOpen(url, "rb");
+fseek(f, offset, SEEK_SET);
+int sizeRead = fread(buffer, 1, size, f);
+if (ferror(f))
+    {
+    warn("udcDataViaLocal failed to fetch %d bytes at %lld", size, offset);
+    errnoAbort("file %s", url);
+    }
+carefulClose(&f);
+return sizeRead;
+}
+
+static boolean udcInfoViaLocal(char *url, struct udcRemoteFileInfo *retInfo)
+/* Fill in *retTime with last modified time for file specified in url.
+ * Return FALSE if file does not even exist. */
+{
+verbose(2, "checking remote info on %s\n", url);
+url = assertLocalUrl(url);
+struct stat status;
+int ret = stat(url, &status);
+if (ret < 0)
+    return FALSE;
+retInfo->updateTime = status.st_mtime;
+retInfo->size = status.st_size;
+return TRUE;
+}
+
+/********* Section for transparent file protocol **********/
+
+static int udcDataViaTransparent(char *url, bits64 offset, int size, void *buffer,
+				 struct connInfo *ci)
+/* Fetch a block of data of given size into buffer using the http: protocol.
+* Returns number of bytes actually read.  Does an errAbort on
+* error.  Typically will be called with size in the 8k - 64k range. */
+{
+internalErr();	/* Should not get here. */
+return size;
+}
+
+static boolean udcInfoViaTransparent(char *url, struct udcRemoteFileInfo *retInfo)
+/* Fill in *retInfo with last modified time for file specified in url.
+ * Return FALSE if file does not even exist. */
+{
+internalErr();	/* Should not get here. */
+return FALSE;
+}
+
+/********* Section for slow local file protocol - simulates network... **********/
+
+static int udcDataViaSlow(char *url, bits64 offset, int size, void *buffer, struct connInfo *ci)
+/* Fetch a block of data of given size into buffer using the http: protocol.
+* Returns number of bytes actually read.  Does an errAbort on
+* error.  Typically will be called with size in the 8k - 64k range. */
+{
+verbose(2, "slow reading remote data - %d bytes at %lld - on %s\n", size, offset, url);
+sleep1000(500);
+char *fileName = url + 5;  /* skip over 'slow:' */
+FILE *f = mustOpen(fileName, "rb");
+fseek(f, offset, SEEK_SET);
+char *pt = buffer;
+int i, step=1024;
+int sizeRead = 0;
+for (i=0; i<size; i += step)
+    {
+    sleep1000(250);
+    int readChunk = size - i;
+    if (readChunk > step)
+        readChunk = step;
+    int oneReadSize = fread(pt, 1, readChunk, f);
+    verbose(2, "slowly read %d bytes\n", oneReadSize);
+    if (ferror(f))
+	{
+	warn("udcDataViaSlow failed to fetch %d bytes at %lld", size, offset);
+	errnoAbort("file %s", fileName);
+	}
+    pt += step;
+    sizeRead += oneReadSize;
+    }
+carefulClose(&f);
+return sizeRead;
+}
+
+static boolean udcInfoViaSlow(char *url, struct udcRemoteFileInfo *retInfo)
+/* Fill in *retTime with last modified time for file specified in url.
+ * Return FALSE if file does not even exist. */
+{
+char *fileName = url + 5;  /* skip over 'slow:' */
+verbose(2, "slow checking remote info on %s\n", url);
+sleep1000(500);
+struct stat status;
+int ret = stat(fileName, &status);
+if (ret < 0)
+    return FALSE;
+retInfo->updateTime = status.st_mtime;
+retInfo->size = status.st_size;
+return TRUE;
+}
+
+/********* Section for http protocol **********/
+
+int udcDataViaHttpOrFtp(char *url, bits64 offset, int size, void *buffer, struct connInfo *ci)
+/* Fetch a block of data of given size into buffer using url's protocol,
+ * which must be http, https or ftp.  Returns number of bytes actually read.
+ * Does an errAbort on error.
+ * Typically will be called with size in the 8k-64k range. */
+{
+if (startsWith("http://",url) || startsWith("https://",url) || startsWith("ftp://",url))
+    verbose(2, "reading http/https/ftp data - %d bytes at %lld - on %s\n", size, offset, url);
+else
+    errAbort("Invalid protocol in url [%s] in udcDataViaFtp, only http, https, or ftp supported",
+	     url); 
+int sd = connInfoGetSocket(ci, url, offset, size);
+if (sd < 0)
+    errAbort("Can't get data socket for %s", url);
+int rd = 0, total = 0, remaining = size;
+char *buf = (char *)buffer;
+while ((remaining > 0) && ((rd = read(sd, buf, remaining)) > 0))
+    {
+    total += rd;
+    buf += rd;
+    remaining -= rd;
+    }
+if (rd == -1)
+    errnoAbort("udcDataViaHttpOrFtp: error reading socket");
+if (ci == NULL)
+    mustCloseFd(&sd);
+else
+    ci->offset += total;
+return total;
+}
+
+boolean udcInfoViaHttp(char *url, struct udcRemoteFileInfo *retInfo)
+/* Gets size and last modified time of URL
+ * and returns status of HEAD GET. */
+{
+verbose(2, "checking http remote info on %s\n", url);
+struct hash *hash = newHash(0);
+int status = netUrlHead(url, hash);
+if (status != 200) // && status != 302 && status != 301)
+    return FALSE;
+char *sizeString = hashFindValUpperCase(hash, "Content-Length:");
+if (sizeString == NULL)
+    {
+    /* try to get remote file size by an alternate method */
+    retInfo->size = netUrlSizeByRangeResponse(url);
+    if (retInfo->size < 0)
+	{
+    	hashFree(&hash);
+	errAbort("No Content-Length: returned in header for %s, can't proceed, sorry", url);
+	}
+    }
+else
+    {
+    retInfo->size = atoll(sizeString);
+    }
+
+char *lastModString = hashFindValUpperCase(hash, "Last-Modified:");
+if (lastModString == NULL)
+    {
+    // Date is a poor substitute!  It will always appear that the cache is stale.
+    // But at least we can read files from dropbox.com.
+    lastModString = hashFindValUpperCase(hash, "Date:");
+    if (lastModString == NULL)
+	{
+	hashFree(&hash);
+	errAbort("No Last-Modified: or Date: returned in header for %s, can't proceed, sorry", url);
+	}
+    }
+struct tm tm;
+time_t t;
+// Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
+// This will always be GMT
+if (strptime(lastModString, "%a, %d %b %Y %H:%M:%S %Z", &tm) == NULL)
+    { /* Handle error */;
+    hashFree(&hash);
+    errAbort("unable to parse last-modified string [%s]", lastModString);
+    }
+t = mktimeFromUtc(&tm);
+if (t == -1)
+    { /* Handle error */;
+    hashFree(&hash);
+    errAbort("mktimeFromUtc failed while converting last-modified string [%s] from UTC time", lastModString);
+    }
+retInfo->updateTime = t;
+
+hashFree(&hash);
+return status;
+}
+
+
+/********* Section for ftp protocol **********/
+
+// fetchData method: See udcDataViaHttpOrFtp above.
+
+boolean udcInfoViaFtp(char *url, struct udcRemoteFileInfo *retInfo)
+/* Gets size and last modified time of FTP URL */
+{
+verbose(2, "checking ftp remote info on %s\n", url);
+long long size = 0;
+time_t t, tUtc;
+struct tm *tm = NULL;
+// TODO: would be nice to add int *retCtrlSocket to netGetFtpInfo so we can stash 
+// in retInfo->connInfo and keep socket open.
+boolean ok = netGetFtpInfo(url, &size, &tUtc);
+if (!ok)
+    return FALSE;
+// Convert UTC to localtime
+tm = localtime(&tUtc);
+t = mktimeFromUtc(tm);
+if (t == -1)
+    { /* Handle error */;
+    errAbort("mktimeFromUtc failed while converting FTP UTC last-modified time %ld to local time", (long) tUtc);
+    }
+retInfo->size = size;
+retInfo->updateTime = t;
+return TRUE;
+}
+
+
+/********* Non-protocol-specific bits **********/
+
+
+static char *fileNameInCacheDir(struct udcFile *file, char *fileName)
+/* Return the name of a file in the cache dir, from the cache root directory on down.
+ * Do a freeMem on this when done. */
+{
+int dirLen = strlen(file->cacheDir);
+int nameLen = strlen(fileName);
+char *path = needMem(dirLen + nameLen + 2);
+memcpy(path, file->cacheDir, dirLen);
+path[dirLen] = '/';
+memcpy(path+dirLen+1, fileName, nameLen);
+return path;
+}
+
+static void udcNewCreateBitmapAndSparse(struct udcFile *file, 
+	bits64 remoteUpdate, bits64 remoteSize, bits32 version)
+/* Create a new bitmap file around the given remoteUpdate time. */
+{
+int fd = mustOpenFd(file->bitmapFileName, O_WRONLY | O_CREAT | O_TRUNC);
+bits32 sig = udcBitmapSig;
+bits32 blockSize = udcBlockSize;
+bits64 reserved64 = 0;
+bits32 reserved32 = 0;
+int blockCount = (remoteSize + udcBlockSize - 1)/udcBlockSize;
+int bitmapSize = bitToByteSize(blockCount);
+
+/* Write out fixed part of header. */
+writeOneFd(fd, sig);
+writeOneFd(fd, blockSize);
+writeOneFd(fd, remoteUpdate);
+writeOneFd(fd, remoteSize);
+writeOneFd(fd, version);
+writeOneFd(fd, reserved32);
+writeOneFd(fd, reserved64);
+writeOneFd(fd, reserved64);
+writeOneFd(fd, reserved64);
+writeOneFd(fd, reserved64);
+long long offset = mustLseek(fd, 0, SEEK_CUR);
+if (offset != udcBitmapHeaderSize)
+    errAbort("offset in fd=%d, f=%s is %lld, not expected udcBitmapHeaderSize %d",
+	     fd, file->bitmapFileName, offset, udcBitmapHeaderSize);
+
+/* Write out initial all-zero bitmap, using sparse-file method: write 0 to final address. */
+unsigned char zero = 0;
+mustLseek(fd, bitmapSize-1, SEEK_CUR);
+mustWriteFd(fd, &zero, 1);
+
+/* Clean up bitmap file and name. */
+mustCloseFd(&fd);
+
+/* Create an empty data file. */
+fd = mustOpenFd(file->sparseFileName, O_WRONLY | O_CREAT | O_TRUNC);
+mustCloseFd(&fd);
+}
+
+static struct udcBitmap *udcBitmapOpen(char *fileName)
+/* Open up a bitmap file and read and verify header.  Return NULL if file doesn't
+ * exist, abort on error. */
+{
+/* Open file, returning NULL if can't. */
+int fd = open(fileName, O_RDWR);
+if (fd < 0)
+    {
+    if (errno == ENOENT)
+	return NULL;
+    else
+	errnoAbort("Can't open(%s, O_RDWR)", fileName);
+    }
+
+/* Get status info from file. */
+struct stat status;
+fstat(fd, &status);
+
+/* Read signature and decide if byte-swapping is needed. */
+// TODO: maybe buffer the I/O for performance?  Don't read past header - 
+// fd offset needs to point to first data block when we return.
+bits32 magic;
+boolean isSwapped = FALSE;
+mustReadOneFd(fd, magic);
+if (magic != udcBitmapSig)
+    {
+    magic = byteSwap32(magic);
+    isSwapped = TRUE;
+    if (magic != udcBitmapSig)
+       errAbort("%s is not a udcBitmap file", fileName);
+    }
+
+/* Allocate bitmap object, fill it in, and return it. */
+bits32 reserved32;
+bits64 reserved64;
+struct udcBitmap *bits;
+AllocVar(bits);
+bits->blockSize = fdReadBits32(fd, isSwapped);
+bits->remoteUpdate = fdReadBits64(fd, isSwapped);
+bits->fileSize = fdReadBits64(fd, isSwapped);
+bits->version = fdReadBits32(fd, isSwapped);
+reserved32 = fdReadBits32(fd, isSwapped);
+reserved64 = fdReadBits64(fd, isSwapped);
+reserved64 = fdReadBits64(fd, isSwapped);
+reserved64 = fdReadBits64(fd, isSwapped);
+reserved64 = fdReadBits64(fd, isSwapped);
+bits->localUpdate = status.st_mtime;
+bits->localAccess = status.st_atime;
+bits->isSwapped = isSwapped;
+bits->fd = fd;
+
+return bits;
+}
+
+static void udcBitmapClose(struct udcBitmap **pBits)
+/* Free up resources associated with udcBitmap. */
+{
+struct udcBitmap *bits = *pBits;
+if (bits != NULL)
+    {
+    mustCloseFd(&(bits->fd));
+    freez(pBits);
+    }
+}
+
+static struct udcProtocol *udcProtocolNew(char *upToColon)
+/* Build up a new protocol around a string such as "http" or "local" */
+{
+struct udcProtocol *prot;
+AllocVar(prot);
+if (sameString(upToColon, "local"))
+    {
+    prot->fetchData = udcDataViaLocal;
+    prot->fetchInfo = udcInfoViaLocal;
+    }
+else if (sameString(upToColon, "slow"))
+    {
+    prot->fetchData = udcDataViaSlow;
+    prot->fetchInfo = udcInfoViaSlow;
+    }
+else if (sameString(upToColon, "http") || sameString(upToColon, "https"))
+    {
+    prot->fetchData = udcDataViaHttpOrFtp;
+    prot->fetchInfo = udcInfoViaHttp;
+    }
+else if (sameString(upToColon, "ftp"))
+    {
+    prot->fetchData = udcDataViaHttpOrFtp;
+    prot->fetchInfo = udcInfoViaFtp;
+    }
+else if (sameString(upToColon, "transparent"))
+    {
+    prot->fetchData = udcDataViaTransparent;
+    prot->fetchInfo = udcInfoViaTransparent;
+    }
+else
+    {
+    errAbort("Unrecognized protocol %s in udcProtNew", upToColon);
+    }
+return prot;
+}
+
+static void udcProtocolFree(struct udcProtocol **pProt)
+/* Free up protocol resources. */
+{
+freez(pProt);
+}
+
+static void setInitialCachedDataBounds(struct udcFile *file, boolean useCacheInfo)
+/* Open up bitmap file and read a little bit of it to see if cache is stale,
+ * and if not to see if the initial part is cached.  Sets the data members
+ * startData, and endData.  If the case is stale it makes fresh empty
+ * cacheDir/sparseData and cacheDir/bitmap files. */
+{
+bits32 version = 0;
+
+/* Get existing bitmap, and if it's stale clean up. */
+struct udcBitmap *bits = udcBitmapOpen(file->bitmapFileName);
+if (bits != NULL)
+    {
+    if (useCacheInfo)
+	{
+	file->size = bits->fileSize;
+	file->updateTime = bits->remoteUpdate;
+	}
+    version = bits->version;
+    if (bits->remoteUpdate != file->updateTime || bits->fileSize != file->size ||
+	!fileExists(file->sparseFileName))
+	{
+	verbose(2, "removing stale version (%lld! = %lld or %lld! = %lld or %s doesn't exist), "
+		"new version %d\n",
+		bits->remoteUpdate, (long long)file->updateTime, bits->fileSize, file->size,
+		file->sparseFileName, version);
+        udcBitmapClose(&bits);
+	remove(file->bitmapFileName);
+	remove(file->sparseFileName);
+	++version;
+	}
+    }
+else
+    verbose(2, "bitmap file %s does not already exist, creating.\n", file->bitmapFileName);
+
+/* If no bitmap, then create one, and also an empty sparse data file. */
+if (bits == NULL)
+    {
+    udcNewCreateBitmapAndSparse(file, file->updateTime, file->size, version);
+    bits = udcBitmapOpen(file->bitmapFileName);
+    if (bits == NULL)
+        errAbort("Unable to open bitmap file %s", file->bitmapFileName);
+    }
+
+file->bitmapVersion = bits->version;
+
+/* Read in a little bit from bitmap while we have it open to see if we have anything cached. */
+if (file->size > 0)
+    {
+    Bits b;
+    off_t wasAt = lseek(bits->fd, 0, SEEK_CUR);
+    mustReadOneFd(bits->fd, b);
+    int endBlock = (file->size + udcBlockSize - 1)/udcBlockSize;
+    if (endBlock > 8)
+        endBlock = 8;
+    int initialCachedBlocks = bitFindClear(&b, 0, endBlock);
+    file->endData = initialCachedBlocks * udcBlockSize;
+    mustLseek(bits->fd, wasAt, SEEK_SET);
+    } 
+
+file->bits = bits;
+
+}
+
+static boolean qEscaped(char c)
+/* Returns TRUE if character needs to be escaped in q-encoding. */
+{
+if (isalnum(c))
+    return c == 'Q';
+else
+    return c != '_' && c != '-' && c != '/' && c != '.';
+}
+
+static char *qEncode(char *input)
+/* Do a simple encoding to convert input string into "normal" characters.
+ * Abnormal letters, and '!' get converted into Q followed by two hexadecimal digits. */
+{
+/* First go through and figure out encoded size. */
+int size = 0;
+char *s, *d, c;
+s = input;
+while ((c = *s++) != 0)
+    {
+    if (qEscaped(c))
+	size += 3;
+    else
+	size += 1;
+    }
+
+/* Allocate and fill in output. */
+char *output = needMem(size+1);
+s = input;
+d = output;
+while ((c = *s++) != 0)
+    {
+    if (qEscaped(c))
+        {
+	sprintf(d, "Q%02X", (unsigned)c);
+	d += 3;
+	}
+    else
+        *d++ = c;
+    }
+return output;
+}
+
+void udcParseUrlFull(char *url, char **retProtocol, char **retAfterProtocol, char **retColon,
+		     char **retAuth)
+/* Parse the URL into components that udc treats separately.
+ * *retAfterProtocol is Q-encoded to keep special chars out of filenames.  
+ * Free all *ret's except *retColon when done. */
+{
+char *protocol, *afterProtocol;
+char *colon = strchr(url, ':');
+if (!colon)
+    {
+    *retColon = NULL;
+    return;
+    }
+int colonPos = colon - url;
+protocol = cloneStringZ(url, colonPos);
+afterProtocol = url + colonPos + 1;
+while (afterProtocol[0] == '/')
+   afterProtocol += 1;
+char *userPwd = strchr(afterProtocol, '@');
+if (userPwd)
+    {
+    if (retAuth)
+	{
+	char auth[1024];
+	safencpy(auth, sizeof(auth), afterProtocol, userPwd+1-afterProtocol);
+	*retAuth = qEncode(auth);
+	}
+    char *afterHost = strchr(afterProtocol, '/');
+    if (!afterHost)
+	{
+	afterHost = afterProtocol+strlen(afterProtocol);
+	}
+    if (userPwd < afterHost)
+	afterProtocol = userPwd + 1;
+    }
+else if (retAuth)
+    *retAuth = NULL;
+afterProtocol = qEncode(afterProtocol);
+*retProtocol = protocol;
+*retAfterProtocol = afterProtocol;
+*retColon = colon;
+}
+
+void udcParseUrl(char *url, char **retProtocol, char **retAfterProtocol, char **retColon)
+/* Parse the URL into components that udc treats separately.
+ * *retAfterProtocol is Q-encoded to keep special chars out of filenames.  
+ * Free  *retProtocol and *retAfterProtocol but not *retColon when done. */
+{
+udcParseUrlFull(url, retProtocol, retAfterProtocol, retColon, NULL);
+}
+
+void udcPathAndFileNames(struct udcFile *file, char *cacheDir, char *protocol, char *afterProtocol)
+/* Initialize udcFile path and names */
+{
+int len = strlen(cacheDir) + 1 + strlen(protocol) + 1 + strlen(afterProtocol) + 1;
+file->cacheDir = needMem(len);
+safef(file->cacheDir, len, "%s/%s/%s", cacheDir, protocol, afterProtocol);
+
+/* Create file names for bitmap and data portions. */
+file->bitmapFileName = fileNameInCacheDir(file, bitmapName);
+file->sparseFileName = fileNameInCacheDir(file, sparseDataName);
+}
+
+static long long int udcSizeAndModTimeFromBitmap(char *bitmapFileName, time_t *retTime)
+/* Look up the file size from the local cache bitmap file, or -1 if there
+ * is no cache for url. If retTime is non-null, store the remote update time in it. */
+{
+long long int ret = -1;
+struct udcBitmap *bits = udcBitmapOpen(bitmapFileName);
+if (bits != NULL)
+    {
+    ret = bits->fileSize;
+    if (retTime)
+	*retTime = bits->remoteUpdate;
+    }
+else
+    warn("Can't open bitmap file %s: %s\n", bitmapFileName, strerror(errno));
+udcBitmapClose(&bits);
+return ret;
+}
+
+struct udcFile *udcFileMayOpen(char *url, char *cacheDir)
+/* Open up a cached file. cacheDir may be null in which case udcDefaultDir() will be
+ * used.  Return NULL if file doesn't exist. */
+{
+if (cacheDir == NULL)
+    cacheDir = udcDefaultDir();
+verbose(2, "udcfileOpen(%s, %s)\n", url, cacheDir);
+/* Parse out protocol.  Make it "transparent" if none specified. */
+char *protocol = NULL, *afterProtocol = NULL, *colon;
+boolean isTransparent = FALSE;
+udcParseUrl(url, &protocol, &afterProtocol, &colon);
+if (!colon)
+    {
+    freeMem(protocol);
+    protocol = cloneString("transparent");
+    freeMem(afterProtocol);
+    afterProtocol = cloneString(url);
+    isTransparent = TRUE;
+    }
+struct udcProtocol *prot;
+prot = udcProtocolNew(protocol);
+
+/* Figure out if anything exists. */
+boolean useCacheInfo = FALSE;
+struct udcRemoteFileInfo info;
+ZeroVar(&info);
+if (!isTransparent)
+    {
+    useCacheInfo = (udcCacheAge(url, cacheDir) < udcCacheTimeout());
+    if (!useCacheInfo)
+	{
+	if (!prot->fetchInfo(url, &info))
+	    {
+	    udcProtocolFree(&prot);
+	    freeMem(protocol);
+	    freeMem(afterProtocol);
+	    return NULL;
+	    }
+	}
+    }
+
+/* Allocate file object and start filling it in. */
+struct udcFile *file;
+AllocVar(file);
+file->url = cloneString(url);
+file->protocol = protocol;
+file->prot = prot;
+if (isTransparent)
+    {
+    /* If transparent dummy up things so that the "sparse" file pointer is actually
+     * the file itself, which appears to be completely loaded in cache. */
+    int fd = file->fdSparse = mustOpenFd(url, O_RDONLY);
+    struct stat status;
+    fstat(fd, &status);
+    file->startData = 0;
+    file->endData = file->size = status.st_size;
+    }
+else
+    {
+    udcPathAndFileNames(file, cacheDir, protocol, afterProtocol);
+    if (!useCacheInfo)
+	{
+	file->updateTime = info.updateTime;
+	file->size = info.size;
+	memcpy(&(file->connInfo), &(info.ci), sizeof(struct connInfo));
+	// update cache file mod times, so if we're caching we won't do this again
+	// until the timeout has expired again:
+	if (udcCacheTimeout() > 0 && fileExists(file->bitmapFileName))
+	    (void)maybeTouchFile(file->bitmapFileName);
+	}
+
+    /* Make directory. */
+    makeDirsOnPath(file->cacheDir);
+
+    /* Figure out a little bit about the extent of the good cached data if any. Open bits bitmap. */
+    setInitialCachedDataBounds(file, useCacheInfo);
+
+    file->fdSparse = mustOpenFd(file->sparseFileName, O_RDWR);
+
+    }
+freeMem(afterProtocol);
+return file;
+}
+
+struct udcFile *udcFileOpen(char *url, char *cacheDir)
+/* Open up a cached file.  cacheDir may be null in which case udcDefaultDir() will be
+ * used.  Abort if if file doesn't exist. */
+{
+struct udcFile *udcFile = udcFileMayOpen(url, cacheDir);
+if (udcFile == NULL)
+    errAbort("Couldn't open %s", url);
+return udcFile;
+}
+
+
+struct slName *udcFileCacheFiles(char *url, char *cacheDir)
+/* Return low-level list of files used in cache. */
+{
+char *protocol, *afterProtocol, *colon;
+struct udcFile *file;
+udcParseUrl(url, &protocol, &afterProtocol, &colon);
+if (colon == NULL)
+    return NULL;
+AllocVar(file);
+udcPathAndFileNames(file, cacheDir, protocol, afterProtocol);
+struct slName *list = NULL;
+slAddHead(&list, slNameNew(file->bitmapFileName));
+slAddHead(&list, slNameNew(file->sparseFileName));
+slReverse(&list);
+freeMem(file->cacheDir);
+freeMem(file->bitmapFileName);
+freeMem(file->sparseFileName);
+freeMem(file);
+freeMem(protocol);
+freeMem(afterProtocol);
+return list;
+}
+
+void udcFileClose(struct udcFile **pFile)
+/* Close down cached file. */
+{
+struct udcFile *file = *pFile;
+if (file != NULL)
+    {
+    if (file->connInfo.socket != 0)
+	mustCloseFd(&(file->connInfo.socket));
+    if (file->connInfo.ctrlSocket != 0)
+	mustCloseFd(&(file->connInfo.ctrlSocket));
+    freeMem(file->url);
+    freeMem(file->protocol);
+    udcProtocolFree(&file->prot);
+    freeMem(file->cacheDir);
+    freeMem(file->bitmapFileName);
+    freeMem(file->sparseFileName);
+    freeMem(file->sparseReadAheadBuf);
+    mustCloseFd(&(file->fdSparse));
+    udcBitmapClose(&file->bits);
+    }
+freez(pFile);
+}
+
+static void qDecode(const char *input, char *buf, size_t size)
+/* Reverse the qEncode performed on afterProcotol above into buf or abort. */
+{
+safecpy(buf, size, input);
+char c, *r = buf, *w = buf;
+while ((c = *r++) != '\0')
+    {
+    if (c == 'Q')
+	{
+	int q;
+	if (sscanf(r, "%02X", &q))
+	    {
+	    *w++ = (char)q;
+	    r += 2;
+	    }
+	else
+	    errAbort("qDecode: input \"%s\" does not appear to be properly formatted "
+		     "starting at \"%s\"", input, r);
+	}
+    else
+	*w++ = c;
+    }
+*w = '\0';
+}
+
+char *udcPathToUrl(const char *path, char *buf, size_t size, char *cacheDir)
+/* Translate path into an URL, store in buf, return pointer to buf if successful
+ * and NULL if not. */
+{
+if (cacheDir == NULL)
+    cacheDir = udcDefaultDir();
+int offset = 0;
+if (startsWith(cacheDir, (char *)path))
+    offset = strlen(cacheDir);
+if (path[offset] == '/')
+    offset++;
+char protocol[16];
+strncpy(protocol, path+offset, sizeof(protocol));
+protocol[ArraySize(protocol)-1] = '\0';
+char *p = strchr(protocol, '/');
+if (p == NULL)
+    {
+    errAbort("unable to parse protocol (first non-'%s' directory) out of path '%s'\n",
+	     cacheDir, path);
+    return NULL;
+    }
+*p++ = '\0';
+char afterProtocol[4096];
+qDecode(path+1+strlen(protocol)+1, afterProtocol, sizeof(afterProtocol));
+safef(buf, size, "%s://%s", protocol, afterProtocol);
+return buf;
+}
+
+long long int udcSizeFromCache(char *url, char *cacheDir)
+/* Look up the file size from the local cache bitmap file, or -1 if there
+ * is no cache for url. */
+{
+long long int ret = -1;
+if (cacheDir == NULL)
+    cacheDir = udcDefaultDir();
+struct slName *sl, *slList = udcFileCacheFiles(url, cacheDir);
+for (sl = slList;  sl != NULL;  sl = sl->next)
+    if (endsWith(sl->name, bitmapName))
+	{
+	ret = udcSizeAndModTimeFromBitmap(sl->name, NULL);
+	break;
+	}
+slNameFreeList(&slList);
+return ret;
+}
+
+unsigned long udcCacheAge(char *url, char *cacheDir)
+/* Return the age in seconds of the oldest cache file.  If a cache file is
+ * missing, return the current time (seconds since the epoch). */
+{
+unsigned long now = clock1(), oldestTime = now;
+if (cacheDir == NULL)
+    cacheDir = udcDefaultDir();
+struct slName *sl, *slList = udcFileCacheFiles(url, cacheDir);
+if (slList == NULL)
+    return now;
+for (sl = slList;  sl != NULL;  sl = sl->next)
+    if (endsWith(sl->name, bitmapName))
+	{
+	if (fileExists(sl->name))
+	    oldestTime = min(fileModTime(sl->name), oldestTime);
+	else
+	    return now;
+	}
+return (now - oldestTime);
+}
+
+static void readBitsIntoBuf(int fd, int headerSize, int bitStart, int bitEnd,
+	Bits **retBits, int *retPartOffset)
+/* Do some bit-to-byte offset conversions and read in all the bytes that
+ * have information in the bits we're interested in. */
+{
+int byteStart = bitStart/8;
+int byteEnd = bitToByteSize(bitEnd);
+int byteSize = byteEnd - byteStart;
+Bits *bits = needLargeMem(byteSize);
+mustLseek(fd, headerSize + byteStart, SEEK_SET);
+mustReadFd(fd, bits, byteSize);
+*retBits = bits;
+*retPartOffset = byteStart*8;
+}
+
+static boolean allBitsSetInFile(int bitStart, int bitEnd, int partOffset, Bits *bits)
+/* Return TRUE if all bits in file between start and end are set. */
+{
+int partBitStart = bitStart - partOffset;
+int partBitEnd = bitEnd - partOffset;
+int nextClearBit = bitFindClear(bits, partBitStart, partBitEnd);
+boolean allSet = (nextClearBit >= partBitEnd);
+return allSet;
+}
+
+// For tests/udcTest.c debugging: not declared in udc.h, but not static either:
+boolean udcCheckCacheBits(struct udcFile *file, int startBlock, int endBlock)
+/* Warn and return TRUE if any bit in (startBlock,endBlock] is not set. */
+{
+boolean gotUnset = FALSE;
+struct udcBitmap *bitmap = udcBitmapOpen(file->bitmapFileName);
+int partOffset;
+Bits *bits;
+readBitsIntoBuf(bitmap->fd, udcBitmapHeaderSize, startBlock, endBlock, &bits, &partOffset);
+
+int partBitStart = startBlock - partOffset;
+int partBitEnd = endBlock - partOffset;
+int nextClearBit = bitFindClear(bits, partBitStart, partBitEnd);
+while (nextClearBit < partBitEnd)
+    {
+    int clearBlock = nextClearBit + partOffset;
+    warn("... udcFile 0x%04lx: bit for block %d (%lld..%lld] is not set",
+	 (unsigned long)file, clearBlock,
+	 ((long long)clearBlock * udcBlockSize), (((long long)clearBlock+1) * udcBlockSize));
+    gotUnset = TRUE;
+    int nextSetBit = bitFindSet(bits, nextClearBit, partBitEnd);
+    nextClearBit = bitFindClear(bits, nextSetBit, partBitEnd);
+    }
+return gotUnset;
+}
+
+static void fetchMissingBlocks(struct udcFile *file, struct udcBitmap *bits, 
+	int startBlock, int blockCount, int blockSize)
+/* Fetch missing blocks from remote and put them into file.  errAbort if trouble. */
+{
+bits64 startPos = (bits64)startBlock * blockSize;
+bits64 endPos = startPos + (bits64)blockCount * blockSize;
+if (endPos > file->size)
+    endPos = file->size;
+if (endPos > startPos)
+    {
+    bits64 readSize = endPos - startPos;
+    void *buf = needLargeMem(readSize);
+    
+    int actualSize = file->prot->fetchData(file->url, startPos, readSize, buf, &(file->connInfo));
+    if (actualSize != readSize)
+	errAbort("unable to fetch %lld bytes from %s @%lld (got %d bytes)",
+		 readSize, file->url, startPos, actualSize);
+    mustLseek(file->fdSparse, startPos, SEEK_SET);
+    mustWriteFd(file->fdSparse, buf, readSize);
+    freez(&buf);
+    }
+}
+
+static boolean fetchMissingBits(struct udcFile *file, struct udcBitmap *bits,
+	bits64 start, bits64 end, bits64 *retFetchedStart, bits64 *retFetchedEnd)
+/* Scan through relevant parts of bitmap, fetching blocks we don't already have. */
+{
+/* Fetch relevant part of bitmap into memory */
+int partOffset;
+Bits *b;
+int startBlock = start / bits->blockSize;
+int endBlock = (end + bits->blockSize - 1) / bits->blockSize;
+readBitsIntoBuf(bits->fd, udcBitmapHeaderSize, startBlock, endBlock, &b, &partOffset);
+if (allBitsSetInFile(startBlock, endBlock, partOffset, b))
+    {  // it is already in the cache
+    freeMem(b);
+    return TRUE;
+    }
+
+/* Loop around first skipping set bits, then fetching clear bits. */
+boolean dirty = FALSE;
+int s = startBlock - partOffset;
+int e = endBlock - partOffset;
+for (;;)
+    {
+    int nextClearBit = bitFindClear(b, s, e);
+    if (nextClearBit >= e)
+        break;
+    int nextSetBit = bitFindSet(b, nextClearBit, e);
+    int clearSize =  nextSetBit - nextClearBit;
+
+    fetchMissingBlocks(file, bits, nextClearBit + partOffset, clearSize, bits->blockSize);
+    bitSetRange(b, nextClearBit, clearSize);
+
+    dirty = TRUE;
+    if (nextSetBit >= e)
+        break;
+    s = nextSetBit;
+    }
+
+if (dirty)
+    {
+    /* Update bitmap on disk.... */
+    int byteStart = startBlock/8;
+    int byteEnd = bitToByteSize(endBlock);
+    int byteSize = byteEnd - byteStart;
+    mustLseek(bits->fd, byteStart + udcBitmapHeaderSize, SEEK_SET);
+    mustWriteFd(bits->fd, b, byteSize);
+    }
+
+freeMem(b);
+*retFetchedStart = startBlock * bits->blockSize;
+*retFetchedEnd = endBlock * bits->blockSize;
+return FALSE;
+}
+
+static boolean rangeIntersectOrTouch64(bits64 start1, bits64 end1, bits64 start2, bits64 end2)
+/* Return true if two 64-bit ranges intersect or touch. */
+{  // cannot use the version of this function that is in common.c since it only handles integers.
+bits64 s = max(start1,start2);
+bits64 e = min(end1,end2);
+return e >= s;
+}
+
+
+static void udcFetchMissing(struct udcFile *file, struct udcBitmap *bits, bits64 start, bits64 end)
+/* Fetch missing pieces of data from file */
+{
+/* Call lower level routine fetch remote data that is not already here. */
+bits64 fetchedStart, fetchedEnd;
+if (fetchMissingBits(file, bits, start, end, &fetchedStart, &fetchedEnd))
+    return;
+
+/* Update file startData/endData members to include new data (and old as well if
+ * the new data overlaps the old). */
+if (rangeIntersectOrTouch64(file->startData, file->endData, fetchedStart, fetchedEnd))
+    {
+    if (fetchedStart > file->startData)
+        fetchedStart = file->startData;
+    if (fetchedEnd < file->endData)
+        fetchedEnd = file->endData;
+    }
+file->startData = fetchedStart;
+file->endData = fetchedEnd;
+}
+
+static boolean udcCachePreload(struct udcFile *file, bits64 offset, bits64 size)
+/* Make sure that given data is in cache - fetching it remotely if need be. 
+ * Return TRUE on success. */
+{
+boolean ok = TRUE;
+/* We'll break this operation into blocks of a reasonable size to allow
+ * other processes to get cache access, since we have to lock the cache files. */
+bits64 s,e, endPos=offset+size;
+for (s = offset; s < endPos; s = e)
+    {
+    /* Figure out bounds of this section. */
+    e = s + udcMaxBytesPerRemoteFetch;
+    if (e > endPos)
+	e = endPos;
+
+    struct udcBitmap *bits = file->bits;
+    if (bits->version == file->bitmapVersion)
+	{
+        udcFetchMissing(file, bits, s, e);
+	}
+    else
+	{
+	ok = FALSE;
+	verbose(2, "udcCachePreload version check failed %d vs %d", 
+		bits->version, file->bitmapVersion);
+	}
+    if (!ok)
+        break;
+    }
+return ok;
+}
+
+#define READAHEADBUFSIZE 4096
+bits64 udcRead(struct udcFile *file, void *buf, bits64 size)
+/* Read a block from file.  Return amount actually read. */
+{
+
+/* Figure out region of file we're going to read, and clip it against file size. */
+bits64 start = file->offset;
+if (start > file->size)
+    return 0;
+bits64 end = start + size;
+if (end > file->size)
+    end = file->size;
+size = end - start;
+char *cbuf = buf;
+
+/* use read-ahead buffer if present */
+bits64 bytesRead = 0;
+
+bits64 raStart;
+bits64 raEnd;
+while(TRUE)
+    {
+    if (file->sparseReadAhead)
+	{
+	raStart = file->sparseRAOffset;
+	raEnd = raStart+READAHEADBUFSIZE;
+	if (start >= raStart && start < raEnd)
+	    {
+	    // copy bytes out of rabuf
+	    bits64 endInBuf = min(raEnd, end);
+	    bits64 sizeInBuf = endInBuf - start;
+	    memcpy(cbuf, file->sparseReadAheadBuf + (start-raStart), sizeInBuf);
+	    cbuf += sizeInBuf;
+	    bytesRead += sizeInBuf;
+	    start = raEnd;
+	    size -= sizeInBuf;
+	    file->offset += sizeInBuf;
+	    if (size == 0)
+		break;
+	    }
+	file->sparseReadAhead = FALSE;
+	mustLseek(file->fdSparse, start, SEEK_SET);
+	}
+
+    bits64 saveEnd = end;
+    if (size < READAHEADBUFSIZE)
+	{
+	file->sparseReadAhead = TRUE;
+	if (!file->sparseReadAheadBuf)
+	    file->sparseReadAheadBuf = needMem(READAHEADBUFSIZE);
+	file->sparseRAOffset = start;
+	size = READAHEADBUFSIZE;
+	end = start + size;
+	if (end > file->size)
+	    {
+	    end = file->size;
+	    size = end - start;
+	    }
+	}
+
+
+    /* If we're outside of the window of file we already know is good, then have to
+     * consult cache on disk, and maybe even fetch data remotely! */
+    if (start < file->startData || end > file->endData)
+	{
+
+	if (!udcCachePreload(file, start, size))
+	    {
+	    verbose(2, "udcCachePreload failed");
+	    bytesRead = 0;
+	    break;
+	    }
+
+	/* Currently only need fseek here.  Would be safer, but possibly
+	 * slower to move fseek so it is always executed in front of read, in
+	 * case other code is moving around file pointer. */
+
+	mustLseek(file->fdSparse, start, SEEK_SET);
+	}
+
+    if (file->sparseReadAhead)
+	{
+	mustReadFd(file->fdSparse, file->sparseReadAheadBuf, size);
+	end = saveEnd;
+	size = end - start;
+	}
+    else
+	{
+	mustReadFd(file->fdSparse, cbuf, size);
+	file->offset += size;
+	bytesRead += size;
+	break;
+	}
+    }
+
+return bytesRead;
+}
+
+void udcMustRead(struct udcFile *file, void *buf, bits64 size)
+/* Read a block from file.  Abort if any problem, including EOF before size is read. */
+{
+bits64 sizeRead = udcRead(file, buf, size);
+if (sizeRead < size)
+    errAbort("udc couldn't read %llu bytes from %s, did read %llu", size, file->url, sizeRead);
+}
+
+int udcGetChar(struct udcFile *file)
+/* Get next character from file or die trying. */
+{
+UBYTE b;
+udcMustRead(file, &b, 1);
+return b;
+}
+
+bits64 udcReadBits64(struct udcFile *file, boolean isSwapped)
+/* Read and optionally byte-swap 64 bit entity. */
+{
+bits64 val;
+udcMustRead(file, &val, sizeof(val));
+if (isSwapped)
+    val = byteSwap64(val);
+return val;
+}
+
+bits32 udcReadBits32(struct udcFile *file, boolean isSwapped)
+/* Read and optionally byte-swap 32 bit entity. */
+{
+bits32 val;
+udcMustRead(file, &val, sizeof(val));
+if (isSwapped)
+    val = byteSwap32(val);
+return val;
+}
+
+bits16 udcReadBits16(struct udcFile *file, boolean isSwapped)
+/* Read and optionally byte-swap 16 bit entity. */
+{
+bits16 val;
+udcMustRead(file, &val, sizeof(val));
+if (isSwapped)
+    val = byteSwap16(val);
+return val;
+}
+
+float udcReadFloat(struct udcFile *file, boolean isSwapped)
+/* Read and optionally byte-swap floating point number. */
+{
+float val;
+udcMustRead(file, &val, sizeof(val));
+if (isSwapped)
+    val = byteSwapFloat(val);
+return val;
+}
+
+double udcReadDouble(struct udcFile *file, boolean isSwapped)
+/* Read and optionally byte-swap double-precision floating point number. */
+{
+double val;
+udcMustRead(file, &val, sizeof(val));
+if (isSwapped)
+    val = byteSwapDouble(val);
+return val;
+}
+
+char *udcReadStringAndZero(struct udcFile *file)
+/* Read in zero terminated string from file.  Do a freeMem of result when done. */
+{
+char shortBuf[2], *longBuf = NULL, *buf = shortBuf;
+int i, bufSize = sizeof(shortBuf);
+for (i=0; ; ++i)
+    {
+    /* See if need to expand buffer, which is initially on stack, but if it gets big goes into 
+     * heap. */
+    if (i >= bufSize)
+        {
+	int newBufSize = bufSize*2;
+	char *newBuf = needLargeMem(newBufSize);
+	memcpy(newBuf, buf, bufSize);
+	freeMem(longBuf);
+	buf = longBuf = newBuf;
+	bufSize = newBufSize;
+	}
+    char c = udcGetChar(file);
+    buf[i] = c;
+    if (c == 0)
+        break;
+    }
+char *retString = cloneString(buf);
+freeMem(longBuf);
+return retString;
+}
+
+char *udcFileReadAll(char *url, char *cacheDir, size_t maxSize, size_t *retSize)
+/* Read a complete file via UDC. The cacheDir may be null in which case udcDefaultDir()
+ * will be used.  If maxSize is non-zero, check size against maxSize
+ * and abort if it's bigger.  Returns file data (with an extra terminal for the
+ * common case where it's treated as a C string).  If retSize is non-NULL then
+ * returns size of file in *retSize. Do a freeMem or freez of the returned buffer
+ * when done. */
+{
+struct udcFile  *file = udcFileOpen(url, cacheDir);
+size_t size = file->size;
+if (maxSize != 0 && size > maxSize)
+    errAbort("%s is %lld bytes, but maxSize to udcFileReadAll is %lld",
+    	url, (long long)size, (long long)maxSize);
+char *buf = needLargeMem(size+1);
+udcMustRead(file, buf, size);
+buf[size] = 0;	// add trailing zero for string processing
+udcFileClose(&file);
+if (retSize != NULL)
+    *retSize = size;
+return buf;
+}
+
+struct lineFile *udcWrapShortLineFile(char *url, char *cacheDir, size_t maxSize)
+/* Read in entire short (up to maxSize) url into memory and wrap a line file around it.
+ * The cacheDir may be null in which case udcDefaultDir() will be used.  If maxSize
+ * is zero then a default value (currently 64 meg) will be used. */
+{
+if (maxSize == 0) maxSize = 64 * 1024 * 1024;
+char *buf = udcFileReadAll(url, cacheDir, maxSize, NULL);
+return lineFileOnString(url, TRUE, buf);
+}
+
+void udcSeek(struct udcFile *file, bits64 offset)
+/* Seek to a particular position in file. */
+{
+file->offset = offset;
+mustLseek(file->fdSparse, offset, SEEK_SET);
+}
+
+bits64 udcTell(struct udcFile *file)
+/* Return current file position. */
+{
+return file->offset;
+}
+
+static long bitRealDataSize(char *fileName)
+/* Return number of real bytes indicated by bitmaps */
+{
+struct udcBitmap *bits = udcBitmapOpen(fileName);
+int blockSize = bits->blockSize;
+long byteSize = 0;
+int blockCount = (bits->fileSize + blockSize - 1)/blockSize;
+if (blockCount > 0)
+    {
+    int bitmapSize = bitToByteSize(blockCount);
+    Bits *b = needLargeMem(bitmapSize);
+    mustReadFd(bits->fd, b, bitmapSize);
+    int bitsSet = bitCountRange(b, 0, blockCount);
+    byteSize = (long)bitsSet*blockSize;
+    freez(&b);
+    }
+udcBitmapClose(&bits);
+return byteSize;
+}
+
+static bits64 rCleanup(time_t deleteTime, boolean testOnly)
+/* Delete any bitmap or sparseData files last accessed before deleteTime */
+{
+struct fileInfo *file, *fileList = listDirX(".", "*", FALSE);
+bits64 results = 0;
+for (file = fileList; file != NULL; file = file->next)
+    {
+    if (file->isDir)
+        {
+	setCurrentDir(file->name);
+	bits64 oneResult = rCleanup(deleteTime, testOnly);
+	setCurrentDir("..");
+	if (oneResult > 0)
+	    {
+	    if (!testOnly)
+		remove(file->name);
+	    results += oneResult;
+	    results += file->size;
+	    }
+	}
+    else if (sameString(file->name, bitmapName))
+        {
+	if (file->size > udcBitmapHeaderSize) /* prevent failure on bitmap files of size 0 or less than header size */
+	    verbose(2, "%ld (%ld) %s/%s\n", bitRealDataSize(file->name), (long)file->size, getCurrentDir(), file->name);
+	if (file->lastAccess < deleteTime)
+	    {
+	    /* Remove all files when get bitmap, so that can ensure they are deleted in 
+	     * right order. */
+	    results += file->size;
+	    if (!testOnly)
+		{
+		remove(bitmapName);
+		remove(sparseDataName);
+		}
+	    }
+	}
+    else if (sameString(file->name, sparseDataName))
+        {
+	if (results > 0)
+	    results += file->size;
+	}
+    }
+return results;
+}
+
+bits64 udcCleanup(char *cacheDir, double maxDays, boolean testOnly)
+/* Remove cached files older than maxDays old. If testOnly is set
+ * no clean up is done, but the size of the files that would be
+ * cleaned up is still. */
+
+{
+time_t maxSeconds = maxDays * 24 * 60 * 60;
+char *curPath = cloneString(getCurrentDir());
+setCurrentDir(cacheDir);
+time_t deleteTime = time(NULL) - maxSeconds;
+bits64 result = rCleanup(deleteTime, testOnly);
+setCurrentDir(curPath);
+return result;
+}
+
+static char *defaultDir = "/tmp/udcCache";
+
+char *udcDefaultDir()
+/* Get default directory for cache */
+{
+return defaultDir;
+}
+
+void udcSetDefaultDir(char *path)
+/* Set default directory for cache */
+{
+defaultDir = path;
+}
+
+
+int udcCacheTimeout()
+/* Get cache timeout (if local cache files are newer than this many seconds,
+ * we won't ping the remote server to check the file size and update time). */
+{
+return cacheTimeout;
+}
+
+void udcSetCacheTimeout(int timeout)
+/* Set cache timeout (if local cache files are newer than this many seconds,
+ * we won't ping the remote server to check the file size and update time). */
+{
+cacheTimeout = timeout;
+}
+
+time_t udcUpdateTime(struct udcFile *udc)
+/* return udc->updateTime */
+{
+if (sameString("transparent", udc->protocol))
+    {
+    struct stat status;
+    int ret = stat(udc->url, &status);
+    if (ret < 0)
+	return 0;
+    else
+	return  status.st_mtime;
+    }
+return udc->updateTime;
+}
+
+#ifdef PROGRESS_METER
+off_t remoteFileSize(char *url)
+/* fetch remote file size from given URL */
+{
+off_t answer = 0;
+struct udcRemoteFileInfo info;
+
+if (startsWith("http://",url) || startsWith("https://",url))
+    {
+    if (udcInfoViaHttp(url, &info))
+	answer = info.size;
+    }
+else if (startsWith("ftp://",url))
+    {
+    if (udcInfoViaFtp(url, &info))
+	answer = info.size;
+    }
+
+return answer;
+}
+#endif
diff --git a/lib/vGfx.c b/lib/vGfx.c
new file mode 100644
index 0000000..846bddd
--- /dev/null
+++ b/lib/vGfx.c
@@ -0,0 +1,50 @@
+/* vGfx - interface to polymorphic graphic object
+ * that currently can either be a memory buffer or
+ * a postScript file. */
+
+#include "common.h"
+#include "vGfx.h"
+
+
+
+/* Most of the implementation of this is in macros in vGfx.h. */
+
+void vgClose(struct vGfx **pVg)
+/* Close down virtual graphics object, and finish writing it to file. */
+{
+struct vGfx *vg = *pVg;
+if (vg != NULL)
+    {
+    vg->close(&vg->data);
+    freez(pVg);
+    }
+}
+
+struct vGfx *vgHalfInit(int width, int height)
+/* Close down virtual graphics object, and finish writing it to file. */
+{
+struct vGfx *vg;
+AllocVar(vg);
+vg->width = width;
+vg->height = height;
+return vg;
+}
+
+int vgFindRgb(struct vGfx *vg, struct rgbColor *rgb)
+/* Find color index corresponding to rgb color. */
+{
+return vgFindColorIx(vg, rgb->r, rgb->g, rgb->b);
+}
+
+Color vgContrastingColor(struct vGfx *vg, int backgroundIx)
+/* Return black or white whichever would be more visible over
+ * background. */
+{
+struct rgbColor c = vgColorIxToRgb(vg, backgroundIx);
+int val = (int)c.r + c.g + c.g + c.b;
+if (val > 512)
+    return MG_BLACK;
+else
+    return MG_WHITE;
+}
+
diff --git a/lib/vGfxPrivate.h b/lib/vGfxPrivate.h
new file mode 100644
index 0000000..5fd456a
--- /dev/null
+++ b/lib/vGfxPrivate.h
@@ -0,0 +1,44 @@
+/* vGfx private - stuff that the implementers of 
+ * a vGfx need to know about, but not the clients. */
+
+
+struct vGfx *vgHalfInit(int width, int height);
+/* Return a partially initialized vGfx structure. 
+ * Generally not called by clients.*/
+
+void vgMgMethods(struct vGfx *vg);
+/* Fill in virtual graphics methods for memory based drawing. */
+
+/* A bunch of things to make the type-casting easier.
+ * This is a price you pay for object oriented
+ * polymorphism in C... */
+
+typedef void (*vg_close)(void **pV);
+typedef void (*vg_dot)(void *v, int x, int y, int colorIx);
+typedef int (*vg_getDot)(void *v, int x, int y);
+typedef void (*vg_box)(void *v, int x, int y, 
+	int width, int height, int colorIx);
+typedef void (*vg_line)(void *v, 
+	int x1, int y1, int x2, int y2, int colorIx);
+typedef void (*vg_text)(void *v, int x, int y, int colorIx, void *font,
+	char *text);
+typedef void (*vg_textRight)(void *v, int x, int y, int width, int height,
+	int colorIx, void *font, char *text);
+typedef void (*vg_textCentered)(void *v, int x, int y, int width, int height,
+	int colorIx, void *font, char *text);
+typedef int (*vg_findColorIx)(void *v, int r, int g, int b);
+typedef struct rgbColor (*vg_colorIxToRgb)(void *v, int colorIx);
+typedef void (*vg_setClip)(void *v, int x, int y, int width, int height);
+typedef void (*vg_setWriteMode)(void *v, unsigned int writeMode);
+typedef void (*vg_unclip)(void *v);
+typedef void (*vg_verticalSmear)(void *v,
+	    int xOff, int yOff, int width, int height, 
+	    Color *dots, boolean zeroClear);
+typedef void (*vg_fillUnder)(void *v, int x1, int y1, 
+	int x2, int y2, int bottom, Color color);
+typedef void (*vg_drawPoly)(void *v, struct gfxPoly *poly, Color color, boolean filled);
+typedef void (*vg_setHint)(void *v, char *hint, char *value);
+typedef char * (*vg_getHint)(void *v, char *hint);
+typedef int (*vg_getFontPixelHeight)(void *v, void *font);
+typedef int (*vg_getFontStringWidth)(void *v, void *font, char *string);
+
diff --git a/lib/vGif.c b/lib/vGif.c
new file mode 100644
index 0000000..d26f950
--- /dev/null
+++ b/lib/vGif.c
@@ -0,0 +1,63 @@
+/* vGif - a virtual graphic object wrapper around
+ * an in-memory buffer destined to become a 
+ * 256-color GIF file. */
+
+#include "common.h"
+#include "memgfx.h"
+#include "vGfx.h"
+#include "vGfxPrivate.h"
+
+
+#ifndef COLOR32
+
+struct memGif
+/* Something that handles a gif. */
+    {
+    struct memGfx mg;	/* Memory form.  This needs to be first field. */
+    char *fileName;	/* Gif file name. */
+    boolean useTransparency;
+    };
+
+void memGifClose(struct memGif **pG)
+/* Write out and close and free. */
+{
+struct memGif *g = *pG;
+if (g != NULL)
+    {
+    struct memGfx *mg = (struct memGfx *)g;
+    mgSaveGif(mg, g->fileName, g->useTransparency);
+    freez(&g->fileName);
+    mgFree(&mg);
+    *pG = NULL;
+    }
+}
+
+struct vGfx *vgOpenGif(int width, int height, char *fileName, boolean useTransparency)
+/* Open up something that will someday be a PostScript file. */
+{
+struct memGif *gif;
+struct memGfx *mg;
+struct vGfx *vg;
+
+/* Set up virtual graphics with memory methods. */
+vg = vgHalfInit(width, height);
+vgMgMethods(vg);
+vg->close = (vg_close)memGifClose;
+
+/* Get our mg + fileName structure.  We're forcing
+ * inheritence from mg essentially. */
+AllocVar(gif);
+gif->fileName = cloneString(fileName);
+gif->useTransparency = useTransparency;
+
+/* Fill in the mg part of this structure with normal memGfx. */
+mg = mgNew(width, height);
+mgClearPixels(mg);
+gif->mg = *mg;
+freez(&mg);	/* We don't need this copy any more. */
+
+vg->data = gif;
+return vg;
+}
+
+#endif
diff --git a/lib/vPng.c b/lib/vPng.c
new file mode 100644
index 0000000..300e1f6
--- /dev/null
+++ b/lib/vPng.c
@@ -0,0 +1,65 @@
+/* vPng - a virtual graphic object wrapper around an in-memory buffer destined to become a 256-color PNG file. */
+
+
+#include "common.h"
+#include "memgfx.h"
+#include "vGfx.h"
+#include "vGfxPrivate.h"
+
+
+struct memPng
+/* Something that handles a PNG. */
+    {
+    struct memGfx mg;	/* Memory form.  This needs to be first field. */
+    char *fileName;	/* PNG file name. */
+    boolean useTransparency;   /* Make background color transparent if TRUE. */
+    };
+
+void memPngClose(struct memPng **pG)
+/* Write out and close and free. */
+{
+struct memPng *g = *pG;
+if (g != NULL)
+    {
+    struct memGfx *mg = (struct memGfx *)g;
+    mgSavePng(mg, g->fileName, g->useTransparency);
+    freez(&g->fileName);
+    mgFree(&mg);
+    *pG = NULL;
+    }
+}
+
+struct vGfx *vgOpenPng(int width, int height, char *fileName, boolean useTransparency)
+/* Open up something that will write out a PNG file upon vgClose.  
+ * If useTransparency, then the first color in memgfx's colormap/palette is
+ * assumed to be the image background color, and pixels of that color
+ * are made transparent. */
+{
+struct memPng *png;
+struct memGfx *mg;
+struct vGfx *vg;
+
+/* Set up virtual graphics with memory methods. */
+vg = vgHalfInit(width, height);
+vgMgMethods(vg);
+vg->close = (vg_close)memPngClose;
+
+/* Get our mg + fileName structure.  We're forcing
+ * inheritence from mg essentially. */
+AllocVar(png);
+png->fileName = cloneString(fileName);
+png->useTransparency = useTransparency;
+
+/* Fill in the mg part of this structure with normal memGfx. */
+mg = mgNew(width, height);
+if (png->useTransparency)
+    mgClearPixelsTrans(mg);
+else
+    mgClearPixels(mg);
+png->mg = *mg;
+freez(&mg);	/* We don't need this copy any more. */
+
+vg->data = png;
+return vg;
+}
+
diff --git a/lib/valgrind.suppress b/lib/valgrind.suppress
new file mode 100644
index 0000000..44c76fe
--- /dev/null
+++ b/lib/valgrind.suppress
@@ -0,0 +1,106 @@
+# valgrind uppressions for expected memory leaks from kent/src/lib modules.
+# specify this file to  valgrind with something like:
+#    --suppressions=../lib/valgrind.suppress
+# if you need to create new suppressions, run your program with valgrind using
+# the --gen-suppressions=yes option.  This will interactive prompt you to
+# and output the suppressions that you must edit and add to this file.
+# Name the option and delete lower-level calling context entries so that
+# the last function in the list the the particular library entry point.
+# 
+#  valgrind --tool=memcheck --suppressions=../lib/valgrind.suppress --num-callers=100 --leak-check=full --leak-resolution=high --show-reachable=yes  yourProg yourArgs ...
+#
+{
+   options1
+   Memcheck:Leak
+   fun:malloc
+   fun:defaultAlloc
+   fun:needMem
+   fun:lmInit
+   fun:newHashExt
+   fun:parseOptions
+   fun:optionInit
+}
+{
+   options2
+   Memcheck:Leak
+   fun:malloc
+   fun:defaultAlloc
+   fun:needMem
+   fun:newHashExt
+   fun:parseOptions
+   fun:optionInit
+}
+{
+   options3
+   Memcheck:Leak
+   fun:malloc
+   fun:defaultAlloc
+   fun:needLargeMem
+   fun:needLargeZeroedMem
+   fun:newBlock
+   fun:lmAlloc
+   fun:hashAddN
+   fun:hashAdd
+   fun:parseAnOption
+   fun:parseOptions
+   fun:optionInit
+}
+{
+   options4
+   Memcheck:Leak
+   fun:malloc
+   fun:defaultAlloc
+   fun:needLargeMem
+   fun:needLargeZeroedMem
+   fun:newBlock
+   fun:lmInit
+   fun:newHash
+   fun:parseOptions
+   fun:optionInit
+}
+{
+   options5
+   Memcheck:Leak
+   fun:malloc
+   fun:defaultAlloc
+   fun:needLargeMem
+   fun:needLargeZeroedMem
+   fun:newBlock
+   fun:lmAlloc
+   fun:newHashExt
+   fun:parseOptions
+   fun:optionInit
+}
+{
+   sqlUnsignedArray
+   Memcheck:Leak
+   fun:malloc
+   fun:realloc
+   fun:defaultRealloc
+   fun:needLargeMemResize
+   fun:needLargeZeroedMemResize
+   fun:needMoreMem
+   fun:sqlUnsignedStaticArray
+}
+{
+   sqlSignedArray   
+   Memcheck:Leak
+   fun:malloc
+   fun:realloc
+   fun:defaultRealloc
+   fun:needLargeMemResize
+   fun:needLargeZeroedMemResize
+   fun:needMoreMem
+   fun:sqlSignedStaticArray
+}
+{
+   sqlFloatArray
+   Memcheck:Leak
+   fun:malloc
+   fun:realloc
+   fun:defaultRealloc
+   fun:needLargeMemResize
+   fun:needLargeZeroedMemResize
+   fun:needMoreMem
+   fun:sqlFloatStaticArray
+}
diff --git a/lib/vcf.c b/lib/vcf.c
new file mode 100644
index 0000000..8cc0cd8
--- /dev/null
+++ b/lib/vcf.c
@@ -0,0 +1,954 @@
+/* VCF: Variant Call Format, version 4.0 / 4.1
+ * http://www.1000genomes.org/wiki/Analysis/Variant%20Call%20Format/vcf-variant-call-format-version-40
+ * http://www.1000genomes.org/wiki/Analysis/Variant%20Call%20Format/vcf-variant-call-format-version-41
+ */
+
+#include "common.h"
+#include "dnautil.h"
+#include "errabort.h"
+#include <limits.h>
+#include "localmem.h"
+#include "net.h"
+#include "regexHelper.h"
+#include "vcf.h"
+
+/* Reserved but optional INFO keys: */
+const char *vcfInfoAncestralAllele = "AA";
+const char *vcfInfoPerAlleleGtCount = "AC";	// allele count in genotypes, for each ALT allele,
+						// in the same order as listed
+const char *vcfInfoAlleleFrequency = "AF";	// allele frequency for each ALT allele in the same
+						// order as listed: use this when estimated from
+						// primary data, not called genotypes
+const char *vcfInfoNumAlleles = "AN";		// total number of alleles in called genotypes
+const char *vcfInfoBaseQuality = "BQ";		// RMS base quality at this position
+const char *vcfInfoCigar = "CIGAR";		// cigar string describing how to align an
+						// alternate allele to the reference allele
+const char *vcfInfoIsDbSnp = "DB";		// dbSNP membership
+const char *vcfInfoDepth = "DP";		// combined depth across samples, e.g. DP=154
+const char *vcfInfoEnd = "END";			// end position of the variant described in this
+						// record (esp. for CNVs)
+const char *vcfInfoIsHapMap2 = "H2";		// membership in hapmap2
+const char *vcfInfoIsHapMap3 = "H3";		// membership in hapmap3
+const char *vcfInfoIs1000Genomes = "1000G";	// membership in 1000 Genomes
+const char *vcfInfoMappingQuality = "MQ";	// RMS mapping quality, e.g. MQ=52
+const char *vcfInfoMapQual0Count = "MQ0";	// number of MAPQ == 0 reads covering this record
+const char *vcfInfoNumSamples = "NS";		// Number of samples with data
+const char *vcfInfoStrandBias = "SB";		// strand bias at this position
+const char *vcfInfoIsSomatic = "SOMATIC";	// indicates that the record is a somatic mutation,
+						// for cancer genomics
+const char *vcfInfoIsValidated = "VALIDATED";	// validated by follow-up experiment
+
+/* Reserved but optional per-genotype keys: */
+const char *vcfGtGenotype = "GT";	// Integer allele indices separated by "/" (unphased)
+					// or "|" (phased). Allele values are 0 for
+					// reference allele, 1 for the first allele in ALT,
+					// 2 for the second allele in ALT and so on.
+const char *vcfGtDepth = "DP";		// Read depth at this position for this sample
+const char *vcfGtFilter = "FT";		// Analogous to variant's FILTER field
+const char *vcfGtLikelihoods = "GL";	// Three floating point log10-scaled likelihoods for
+					// AA,AB,BB genotypes where A=ref and B=alt;
+					// not applicable if site is not biallelic.
+const char *vcfGtPhred = "PL";		// Phred-scaled genotype likelihoods rounded to closest int
+const char *vcfGtConditionalQual = "GQ";// Conditional genotype quality
+					// i.e. phred quality -10log_10 P(genotype call is wrong,
+					// conditioned on the site's being variant)
+const char *vcfGtHaplotypeQualities = "HQ";	// two phred qualities comma separated
+const char *vcfGtPhaseSet = "PS";	// Set of phased genotypes to which this genotype belongs
+const char *vcfGtPhasingQuality = "PQ";	// Phred-scaled P(alleles ordered wrongly in heterozygote)
+const char *vcfGtExpectedAltAlleleCount = "EC";	// Typically used in association analyses
+
+
+// Make definitions of reserved INFO and genotype keys, in case people take them for
+// granted and don't make ##INFO headers for them:
+static struct vcfInfoDef *vcfSpecInfoDefs = NULL;
+static struct vcfInfoDef *vcfSpecGtFormatDefs = NULL;
+
+static void addInfoDef(struct vcfInfoDef **pList,
+		       const char *key, int fieldCount, enum vcfInfoType type, char *description)
+/* Allocate and initialize an info def and add it to pList. */
+{
+struct vcfInfoDef *def;
+AllocVar(def);
+def->key = (char *)key;
+def->fieldCount = fieldCount;
+def->type = type;
+def->description = description;
+slAddHead(pList, def);
+}
+
+static void initVcfSpecInfoDefs()
+/* Make linked list of INFO defs reserved in the spec. */
+{
+if (vcfSpecInfoDefs != NULL)
+    return;
+addInfoDef(&vcfSpecInfoDefs, vcfInfoAncestralAllele, 1, vcfInfoString, "Ancestral allele");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoPerAlleleGtCount, 1, vcfInfoInteger,
+	   "Allele count in genotypes, for each ALT allele, in the same order as listed");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoAlleleFrequency, -1, vcfInfoFloat,
+	   "Allele frequency for each ALT allele in the same order as listed: "
+	   "use this when estimated from primary data, not called genotypes");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoNumAlleles, 1, vcfInfoInteger,
+	   "Total number of alleles in called genotypes");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoBaseQuality, 1, vcfInfoFloat,
+	   "RMS base quality at this position");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoCigar, 1, vcfInfoString,
+	   "CIGAR string describing how to align an alternate allele to the reference allele");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoIsDbSnp, 0, vcfInfoFlag, "dbSNP membership");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoDepth, 1, vcfInfoString,
+	   "Combined depth across samples, e.g. DP=154");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoEnd, 1, vcfInfoInteger,
+	   "End position of the variant described in this record "
+	   "(especially for structural variants)");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoIsHapMap2, 1, vcfInfoFlag, "Membership in HapMap 2");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoIsHapMap3, 1, vcfInfoFlag, "Membership in HapMap 3");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoIs1000Genomes, 1, vcfInfoFlag, "Membership in 1000 Genomes");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoMappingQuality, 1, vcfInfoFloat,
+	   "RMS mapping quality, e.g. MQ=52");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoMapQual0Count, 1, vcfInfoInteger,
+	   "Number of MAPQ == 0 reads covering this record");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoNumSamples, 1, vcfInfoInteger, "Number of samples with data");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoStrandBias, 1, vcfInfoString, "Strand bias at this position");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoIsSomatic, 1, vcfInfoFlag,
+	   "Indicates that the record is a somatic mutation, for cancer genomics");
+addInfoDef(&vcfSpecInfoDefs, vcfInfoIsValidated, 1, vcfInfoFlag,
+	   "Validated by follow-up experiment");
+}
+
+
+static void initVcfSpecGtFormatDefs()
+/* Make linked list of genotype info defs reserved in spec. */
+{
+if (vcfSpecGtFormatDefs != NULL)
+    return;
+addInfoDef(&vcfSpecGtFormatDefs, vcfGtGenotype, 1, vcfInfoString,
+	   "Integer allele indices separated by \"/\" (unphased) "
+	   "or \"|\" (phased). Allele values are 0 for "
+	   "reference allele, 1 for the first allele in ALT, "
+	   "2 for the second allele in ALT and so on, or \".\" for unknown");
+addInfoDef(&vcfSpecGtFormatDefs, vcfGtDepth, 1, vcfInfoInteger,
+	   "Read depth at this position for this sample");
+addInfoDef(&vcfSpecGtFormatDefs, vcfGtFilter, 1, vcfInfoString,
+	   "PASS to indicate that all filters have been passed, "
+	   "a semi-colon separated list of codes for filters that fail, "
+	   "or \".\" to indicate that filters have not been applied");
+addInfoDef(&vcfSpecGtFormatDefs, vcfGtLikelihoods, -1, vcfInfoFloat,
+	   "Genotype likelihoods comprised of comma separated floating point "
+	   "log10-scaled likelihoods for all possible genotypes given the set "
+	   "of alleles defined in the REF and ALT fields. ");
+addInfoDef(&vcfSpecGtFormatDefs, vcfGtPhred, -1, vcfInfoInteger,
+	   "Phred-scaled genotype likelihoods rounded to the closest integer "
+	   "(and otherwise defined precisely as the genotype likelihoods (GL) field)");
+addInfoDef(&vcfSpecGtFormatDefs, vcfGtConditionalQual, -1, vcfInfoFloat,
+	   "phred-scaled genotype posterior probabilities "
+	   "(and otherwise defined precisely as the genotype likelihoods (GL) field)"
+	   "; intended to store imputed genotype probabilities");
+addInfoDef(&vcfSpecGtFormatDefs, vcfGtHaplotypeQualities, 2, vcfInfoFloat,
+	   "Two comma-separated phred-scaled haplotype qualities");
+addInfoDef(&vcfSpecGtFormatDefs, vcfGtPhaseSet, 1, vcfInfoFloat,
+	   "A set of phased genotypes to which this genotype belongs");
+addInfoDef(&vcfSpecGtFormatDefs, vcfGtPhasingQuality, 1, vcfInfoFloat,
+	   "Phasing quality, the phred-scaled probability that alleles are ordered "
+	   "incorrectly in a heterozygote (against all other members in the phase set)");
+addInfoDef(&vcfSpecGtFormatDefs, vcfGtExpectedAltAlleleCount, 1, vcfInfoFloat,
+	   "Expected alternate allele count (typically used in association analyses)");
+}
+
+static bool vcfFileStopDueToErrors(struct vcfFile *vcff)
+/* determine if we should stop due to the number of errors */
+{
+return vcff->errCnt > vcff->maxErr;
+}
+
+static void vcfFileErr(struct vcfFile *vcff, char *format, ...)
+#if defined(__GNUC__)
+__attribute__((format(printf, 2, 3)))
+#endif
+;
+
+static void vcfFileErr(struct vcfFile *vcff, char *format, ...)
+/* Send error message to errabort stack's warn handler and abort */
+{
+va_list args;
+va_start(args, format);
+char formatPlus[1024];
+if (vcff->lf != NULL)
+    sprintf(formatPlus, "%s:%d: %s", vcff->lf->fileName, vcff->lf->lineIx, format);
+else
+    strcpy(formatPlus, format);
+vaWarn(formatPlus, args);
+va_end(args);
+vcff->errCnt++;
+if (vcfFileStopDueToErrors(vcff))
+    errAbort("VCF: %d parser errors, quitting", vcff->errCnt);
+}
+
+static void *vcfFileAlloc(struct vcfFile *vcff, size_t size)
+/* allocate memory from the memory pool */
+{
+return lmAlloc(vcff->pool->lm, size);
+}
+
+static char *vcfFileCloneStrZ(struct vcfFile *vcff, char *str, size_t size)
+/* allocate memory for a string and copy it */
+{
+return lmCloneStringZ(vcff->pool->lm, str, size);
+}
+
+static char *vcfFileCloneStr(struct vcfFile *vcff, char *str)
+/* allocate memory for a string and copy it */
+{
+return vcfFileCloneStrZ(vcff, str, strlen(str));
+}
+
+static char *vcfFileCloneSubstr(struct vcfFile *vcff, char *line, regmatch_t substr)
+/* Allocate memory for and copy a substring of line. */
+{
+return vcfFileCloneStrZ(vcff, line+substr.rm_so, (substr.rm_eo - substr.rm_so));
+}
+
+#define vcfFileCloneVar(var) lmCloneMem(vcff->pool->lm, var, sizeof(var));
+
+static char *vcfFilePooledStr(struct vcfFile *vcff, char *str)
+/* allocate memory for a string from the shared string pool */
+{
+return hashStoreName(vcff->pool, str);
+}
+
+static enum vcfInfoType vcfInfoTypeFromSubstr(struct vcfFile *vcff, char *line, regmatch_t substr)
+/* Translate substring of line into vcfInfoType or complain. */
+{
+char typeWord[16];
+int substrLen = substr.rm_eo - substr.rm_so;
+if (substrLen > sizeof(typeWord) - 1)
+    {
+    vcfFileErr(vcff, "substring passed to vcfInfoTypeFromSubstr is too long.");
+    return vcfInfoNoType;
+    }
+safencpy(typeWord, sizeof(typeWord), line + substr.rm_so, substrLen);
+if (sameString("Integer", typeWord))
+    return vcfInfoInteger;
+if (sameString("Float", typeWord))
+    return vcfInfoFloat;
+if (sameString("Flag", typeWord))
+    return vcfInfoFlag;
+if (sameString("Character", typeWord))
+    return vcfInfoCharacter;
+if (sameString("String", typeWord))
+    return vcfInfoString;
+vcfFileErr(vcff, "Unrecognized type word \"%s\" in metadata line \"%s\"", typeWord, line);
+return vcfInfoNoType;
+}
+
+// Regular expressions to check format and extract information from header lines:
+static const char *fileformatRegex = "^##(file)?format=VCFv([0-9]+)(\\.([0-9]+))?$";
+static const char *infoOrFormatRegex =
+    "^##(INFO|FORMAT)="
+    "<ID=([A-Za-z0-9_:-]+),"
+    "Number=(\\.|A|G|[0-9-]+),"
+    "Type=([A-Za-z]+),"
+    "Description=\"?(.*)\"?>$";
+static const char *filterOrAltRegex =
+    "^##(FILTER|ALT)="
+    "<ID=([^,]+),"
+    "(Description|Type)=\"?(.*)\"?>$";
+// VCF version 3.3 was different enough to warrant separate regexes:
+static const char *infoOrFormatRegex3_3 =
+    "^##(INFO|FORMAT)="
+    "([A-Za-z0-9_:-]+),"
+    "(\\.|A|G|[0-9-]+),"
+    "([A-Za-z]+),"
+    "\"?(.*)\"?$";
+static const char *filterRegex3_3 =
+    "^##(FILTER)="
+    "([^,]+),"
+    "()\"?(.*)\"?$";
+
+INLINE void nonAsciiWorkaround(char *line)
+// Workaround for annoying 3-byte quote marks included in some 1000 Genomes files:
+{
+(void)strSwapStrs(line, strlen(line)+1, "\342\200\234", "\"");
+(void)strSwapStrs(line, strlen(line)+1, "\342\200\235", "\"");
+}
+
+static void parseMetadataLine(struct vcfFile *vcff, char *line)
+/* Parse a VCF header line beginning with "##" that defines a metadata. */
+{
+char *ptr = line;
+if (ptr == NULL && !startsWith(ptr, "##"))
+    errAbort("Bad line passed to parseMetadataLine");
+ptr += 2;
+char *firstEq = strchr(ptr, '=');
+if (firstEq == NULL)
+    {
+    vcfFileErr(vcff, "Metadata line lacks '=': \"%s\"", line);
+    return;
+    }
+regmatch_t substrs[8];
+// Some of the metadata lines are crucial for parsing the rest of the file:
+if (startsWith("##fileformat=", line) || startsWith("##format", line))
+    {
+    if (regexMatchSubstr(line, fileformatRegex, substrs, ArraySize(substrs)))
+	{
+	// substrs[2] is major version #, substrs[3] is set only if there is a minor version,
+	// and substrs[4] is the minor version #.
+	vcff->majorVersion = atoi(line + substrs[2].rm_so);
+	if (substrs[3].rm_so != -1)
+	    vcff->minorVersion = atoi(line + substrs[4].rm_so);
+	}
+    else
+	vcfFileErr(vcff, "##fileformat line does not match expected pattern /%s/: \"%s\"",
+		   fileformatRegex, line);
+    }
+else if (startsWith("##INFO=", line) || startsWith("##FORMAT=", line))
+    {
+    boolean isInfo = startsWith("##INFO=", line);
+    nonAsciiWorkaround(line);
+    if (regexMatchSubstr(line, infoOrFormatRegex, substrs, ArraySize(substrs)) ||
+	regexMatchSubstr(line, infoOrFormatRegex3_3, substrs, ArraySize(substrs)))
+	// substrs[2] is ID/key, substrs[3] is Number, [4] is Type and [5] is Description.
+	{
+	struct vcfInfoDef *def = vcfFileAlloc(vcff, sizeof(struct vcfInfoDef));
+	def->key = vcfFileCloneSubstr(vcff, line, substrs[2]);
+	char *number = vcfFileCloneSubstr(vcff, line, substrs[3]);
+	if (sameString(number, ".") || sameString(number, "A") || sameString(number, "G"))
+	    // A is #alts which varies line-to-line; "G" is #genotypes which we haven't
+	    // yet seen.  Why is there a G here -- shouldn't such attributes go in the
+	    // genotype columns?
+	    def->fieldCount = -1;
+	else
+	    def->fieldCount = atoi(number);
+	def->type = vcfInfoTypeFromSubstr(vcff, line, substrs[4]);
+	// greedy regex pulls in end quote, trim if found:
+	if (line[substrs[5].rm_eo-1] == '"')
+	    line[substrs[5].rm_eo-1] = '\0';
+	def->description = vcfFileCloneSubstr(vcff, line, substrs[5]);
+	slAddHead((isInfo ? &(vcff->infoDefs) : &(vcff->gtFormatDefs)), def);
+	}
+    else
+	vcfFileErr(vcff, "##%s line does not match expected pattern /%s/ or /%s/: \"%s\"",
+		   (isInfo ? "INFO" : "FORMAT"), infoOrFormatRegex, infoOrFormatRegex3_3, line);
+    }
+else if (startsWith("##FILTER=", line) || startsWith("##ALT=", line))
+    {
+    boolean isFilter = startsWith("##FILTER", line);
+    if (regexMatchSubstr(line, filterOrAltRegex, substrs, ArraySize(substrs)) ||
+	regexMatchSubstr(line, filterRegex3_3, substrs, ArraySize(substrs)))
+	{
+	// substrs[2] is ID/key, substrs[4] is Description.
+	struct vcfInfoDef *def = vcfFileAlloc(vcff, sizeof(struct vcfInfoDef));
+	def->key = vcfFileCloneSubstr(vcff, line, substrs[2]);
+	def->description = vcfFileCloneSubstr(vcff, line, substrs[4]);
+	slAddHead((isFilter ? &(vcff->filterDefs) : &(vcff->altDefs)), def);
+	}
+    else
+	{
+	if (isFilter)
+	    vcfFileErr(vcff, "##FILTER line does not match expected pattern /%s/ or /%s/: \"%s\"",
+		       filterOrAltRegex, filterRegex3_3, line);
+	else
+	    vcfFileErr(vcff, "##ALT line does not match expected pattern /%s/: \"%s\"",
+		       filterOrAltRegex, line);
+	}
+    }
+}
+
+static void expectColumnName2(struct vcfFile *vcff, char *exp1, char *exp2, char *words[], int ix)
+/* Every file must include a header naming the columns, though most column names are
+ * fixed; make sure the names of fixed columns are as expected. */
+{
+if (! sameString(exp1, words[ix]))
+    {
+    if (exp2 == NULL)
+	vcfFileErr(vcff, "Expected column %d's name in header to be \"%s\" but got \"%s\"",
+		   ix+1, exp1, words[ix]);
+    else if (! sameString(exp2, words[ix]))
+	vcfFileErr(vcff, "Expected column %d's name in header to be \"%s\"  or \"%s\" "
+		   "but got \"%s\"", ix+1, exp1, exp2, words[ix]);
+    }
+}
+
+#define expectColumnName(vcff, exp, words, ix) expectColumnName2(vcff, exp, NULL, words, ix)
+
+// There might be a whole lot of genotype columns...
+#define VCF_MAX_COLUMNS 16 * 1024
+
+static void parseColumnHeaderRow(struct vcfFile *vcff, char *line)
+/* Make sure column names are as we expect, and store genotype sample IDs if any are given. */
+{
+if (line[0] != '#')
+    {
+    vcfFileErr(vcff, "Expected to find # followed by column names (\"#CHROM POS ...\"), "
+	       "not \"%s\"", line);
+    lineFileReuse(vcff->lf);
+    return;
+    }
+char *words[VCF_MAX_COLUMNS];
+int wordCount = chopLine(line+1, words);
+if (wordCount >= VCF_MAX_COLUMNS)
+    vcfFileErr(vcff, "header contains at least %d columns; "
+	       "VCF_MAX_COLUMNS may need to be increased in vcf.c!", VCF_MAX_COLUMNS);
+expectColumnName(vcff, "CHROM", words, 0);
+expectColumnName(vcff, "POS", words, 1);
+expectColumnName(vcff, "ID", words, 2);
+expectColumnName(vcff, "REF", words, 3);
+expectColumnName(vcff, "ALT", words, 4);
+expectColumnName2(vcff, "QUAL", "PROB", words, 5);
+expectColumnName(vcff, "FILTER", words, 6);
+expectColumnName(vcff, "INFO", words, 7);
+if (wordCount > 8)
+    {
+    expectColumnName(vcff, "FORMAT", words, 8);
+    if (wordCount < 10)
+	vcfFileErr(vcff, "FORMAT column is given, but no sample IDs for genotype columns...?");
+    vcff->genotypeCount = (wordCount - 9);
+    vcff->genotypeIds = vcfFileAlloc(vcff, vcff->genotypeCount * sizeof(char *));
+    int i;
+    for (i = 9;  i < wordCount;  i++)
+	vcff->genotypeIds[i-9] = vcfFileCloneStr(vcff, words[i]);
+    }
+}
+
+static struct vcfFile *vcfFileNew()
+/* Return a new, empty vcfFile object. */
+{
+struct vcfFile *vcff = NULL;
+AllocVar(vcff);
+vcff->pool = hashNew(0);
+return vcff;
+}
+
+static struct vcfFile *vcfFileHeaderFromLineFile(struct lineFile *lf, int maxErr)
+/* Parse a VCF file into a vcfFile object.  If maxErr not zero, then
+ * continue to parse until this number of error have been reached.  A maxErr
+ * less than zero does not stop and reports all errors. */
+{
+initVcfSpecInfoDefs();
+initVcfSpecGtFormatDefs();
+if (lf == NULL)
+    return NULL;
+struct vcfFile *vcff = vcfFileNew();
+vcff->lf = lf;
+vcff->fileOrUrl = vcfFileCloneStr(vcff, lf->fileName);
+vcff->maxErr = (maxErr < 0) ? INT_MAX : maxErr;
+
+struct dyString *dyHeader = dyStringNew(1024);
+char *line = NULL;
+// First, metadata lines beginning with "##":
+while (lineFileNext(lf, &line, NULL) && startsWith("##", line))
+    {
+    dyStringAppend(dyHeader, line);
+    dyStringAppendC(dyHeader, '\n');
+    parseMetadataLine(vcff, line);
+    }
+slReverse(&(vcff->infoDefs));
+slReverse(&(vcff->filterDefs));
+slReverse(&(vcff->gtFormatDefs));
+// Did we get the bare minimum VCF header with supported version?
+if (vcff->majorVersion == 0)
+    vcfFileErr(vcff, "missing ##fileformat= header line?  Assuming 4.1.");
+if ((vcff->majorVersion != 4 || (vcff->minorVersion != 0 && vcff->minorVersion != 1)) &&
+    (vcff->majorVersion != 3))
+    vcfFileErr(vcff, "VCFv%d.%d not supported -- only v3.*, v4.0 or v4.1",
+	       vcff->majorVersion, vcff->minorVersion);
+// Next, one header line beginning with single "#" that names the columns:
+if (line == NULL)
+    // EOF after metadata
+    return vcff;
+dyStringAppend(dyHeader, line);
+dyStringAppendC(dyHeader, '\n');
+parseColumnHeaderRow(vcff, line);
+vcff->headerString = dyStringCannibalize(&dyHeader);
+return vcff;
+}
+
+
+#define VCF_MAX_INFO 512
+
+static void parseRefAndAlt(struct vcfFile *vcff, struct vcfRecord *record, char *ref, char *alt)
+/* Make an array of alleles, ref first, from the REF and comma-sep'd ALT columns.
+ * Use the length of the reference sequence to set record->chromEnd.
+ * Note: this trashes the alt argument, since this is expected to be its last use. */
+{
+char *altAlleles[VCF_MAX_INFO];
+int altCount = chopCommas(alt, altAlleles);
+record->alleleCount = 1 + altCount;
+record->alleles = vcfFileAlloc(vcff, record->alleleCount * sizeof(record->alleles[0]));
+record->alleles[0] = vcfFilePooledStr(vcff, ref);
+int i;
+for (i = 0;  i < altCount;  i++)
+    record->alleles[1+i] = vcfFilePooledStr(vcff, altAlleles[i]);
+int refLen = strlen(ref);
+if (refLen == dnaFilteredSize(ref))
+    record->chromEnd = record->chromStart + refLen;
+}
+
+static void parseFilterColumn(struct vcfFile *vcff, struct vcfRecord *record, char *filterStr)
+/* Transform ;-separated filter codes into count + string array. */
+{
+// We don't want to modify something allocated with vcfFilePooledStr because that uses
+// hash element names for storage!  So don't make a vcfFilePooledStr copy of filterStr and
+// chop that; instead, chop a temp string and pool the words separately.
+static struct dyString *tmp = NULL;
+if (tmp == NULL)
+    tmp = dyStringNew(0);
+dyStringClear(tmp);
+dyStringAppend(tmp, filterStr);
+record->filterCount = countChars(filterStr, ';') + 1;
+record->filters = vcfFileAlloc(vcff, record->filterCount * sizeof(char **));
+(void)chopByChar(tmp->string, ';', record->filters, record->filterCount);
+int i;
+for (i = 0;  i < record->filterCount;  i++)
+    record->filters[i] = vcfFilePooledStr(vcff, record->filters[i]);
+}
+
+struct vcfInfoDef *vcfInfoDefForKey(struct vcfFile *vcff, const char *key)
+/* Return infoDef for key, or NULL if it wasn't specified in the header or VCF spec. */
+{
+struct vcfInfoDef *def;
+// I expect there to be fairly few definitions (less than a dozen) so
+// I'm just doing a linear search not hash:
+for (def = vcff->infoDefs;  def != NULL;  def = def->next)
+    {
+    if (sameString(key, def->key))
+	return def;
+    }
+for (def = vcfSpecInfoDefs;  def != NULL;  def = def->next)
+    {
+    if (sameString(key, def->key))
+	return def;
+    }
+return NULL;
+}
+
+static enum vcfInfoType typeForInfoKey(struct vcfFile *vcff, const char *key)
+/* Look up the type of INFO component key, in the definitions from the header,
+ * and failing that, from the keys reserved in the spec. */
+{
+struct vcfInfoDef *def = vcfInfoDefForKey(vcff, key);
+if (def == NULL)
+    {
+    vcfFileErr(vcff, "There is no INFO header defining \"%s\"", key);
+    // default to string so we can display value as-is:
+    return vcfInfoString;
+    }
+return def->type;
+}
+
+static int parseInfoValue(struct vcfRecord *record, char *infoKey, enum vcfInfoType type,
+			  char *valStr, union vcfDatum **pData, bool **pMissingData)
+/* Parse a comma-separated list of values into array of union vcfInfoDatum and return count. */
+{
+char *valWords[VCF_MAX_INFO];
+int count = chopCommas(valStr, valWords);
+struct vcfFile *vcff = record->file;
+union vcfDatum *data = vcfFileAlloc(vcff, count * sizeof(union vcfDatum));
+bool *missingData = vcfFileAlloc(vcff, count * sizeof(*missingData));
+int j;
+for (j = 0;  j < count;  j++)
+    {
+    if (type != vcfInfoString && type != vcfInfoCharacter && sameString(valWords[j], "."))
+	missingData[j] = TRUE;
+    switch (type)
+	{
+	case vcfInfoInteger:
+	    data[j].datInt = atoi(valWords[j]);
+	    break;
+	case vcfInfoFloat:
+	    data[j].datFloat = atof(valWords[j]);
+	    break;
+	case vcfInfoFlag:
+	    // Flag key might have a value in older VCFs e.g. 3.2's DB=0, DB=1
+	    data[j].datString = vcfFilePooledStr(vcff, valWords[j]);
+	    break;
+	case vcfInfoCharacter:
+	    data[j].datChar = valWords[j][0];
+	    break;
+	case vcfInfoString:
+	    data[j].datString = vcfFilePooledStr(vcff, valWords[j]);
+	    break;
+	default:
+	    errAbort("invalid vcfInfoType (uninitialized?) %d", type);
+	    break;
+	}
+    }
+// If END is given, use it as chromEnd:
+if (sameString(infoKey, vcfInfoEnd))
+    record->chromEnd = data[0].datInt;
+*pData = data;
+*pMissingData = missingData;
+return count;
+}
+
+static void parseInfoColumn(struct vcfFile *vcff, struct vcfRecord *record, char *string)
+/* Translate string into array of vcfInfoElement. */
+{
+if (sameString(string, "."))
+    {
+    record->infoCount = 0;
+    return;
+    }
+char *elWords[VCF_MAX_INFO];
+record->infoCount = chopByChar(string, ';', elWords, ArraySize(elWords));
+if (record->infoCount >= VCF_MAX_INFO)
+    vcfFileErr(vcff, "INFO column contains at least %d elements; "
+	       "VCF_MAX_INFO may need to be increased in vcf.c!", VCF_MAX_INFO);
+record->infoElements = vcfFileAlloc(vcff, record->infoCount * sizeof(struct vcfInfoElement));
+char *emptyString = vcfFilePooledStr(vcff, "");
+int i;
+for (i = 0;  i < record->infoCount;  i++)
+    {
+    char *elStr = elWords[i];
+    char *eq = strchr(elStr, '=');
+    struct vcfInfoElement *el = &(record->infoElements[i]);
+    if (eq == NULL)
+	{
+	el->key = vcfFilePooledStr(vcff, elStr);
+	enum vcfInfoType type = typeForInfoKey(vcff, el->key);
+	if (type != vcfInfoFlag)
+	    {
+	    vcfFileErr(vcff, "Missing = after key in INFO element: \"%s\" (type=%d)",
+		       elStr, type);
+	    if (type == vcfInfoString)
+		{
+		el->values = vcfFileAlloc(vcff, sizeof(union vcfDatum));
+		el->values[0].datString = emptyString;
+		}
+	    }
+	continue;
+	}
+    *eq = '\0';
+    el->key = vcfFilePooledStr(vcff, elStr);
+    enum vcfInfoType type = typeForInfoKey(vcff, el->key);
+    char *valStr = eq+1;
+    el->count = parseInfoValue(record, el->key, type, valStr, &(el->values), &(el->missingData));
+    if (el->count >= VCF_MAX_INFO)
+	vcfFileErr(vcff, "A single element of the INFO column has at least %d values; "
+	       "VCF_MAX_INFO may need to be increased in vcf.c!", VCF_MAX_INFO);
+    }
+}
+
+struct vcfRecord *vcfRecordFromRow(struct vcfFile *vcff, char **words)
+/* Parse words from a VCF data line into a VCF record structure. */
+{
+struct vcfRecord *record = vcfFileAlloc(vcff, sizeof(struct vcfRecord));
+record->file = vcff;
+record->chrom = vcfFilePooledStr(vcff, words[0]);
+record->chromStart = lineFileNeedNum(vcff->lf, words, 1) - 1;
+// chromEnd may be overwritten by parseRefAndAlt and parseInfoColumn.
+record->chromEnd = record->chromStart+1;
+record->name = vcfFilePooledStr(vcff, words[2]);
+parseRefAndAlt(vcff, record, words[3], words[4]);
+record->qual = vcfFilePooledStr(vcff, words[5]);
+parseFilterColumn(vcff, record, words[6]);
+parseInfoColumn(vcff, record, words[7]);
+if (vcff->genotypeCount > 0)
+    {
+    record->format = vcfFilePooledStr(vcff, words[8]);
+    record->genotypeUnparsedStrings = vcfFileAlloc(vcff,
+						   vcff->genotypeCount * sizeof(char *));
+    int i;
+    // Don't bother actually parsing all these until & unless we need the info:
+    for (i = 0;  i < vcff->genotypeCount;  i++)
+	record->genotypeUnparsedStrings[i] = vcfFileCloneStr(vcff, words[9+i]);
+    }
+return record;
+}
+
+struct vcfRecord *vcfNextRecord(struct vcfFile *vcff)
+/* Parse the words in the next line from vcff into a vcfRecord. Return NULL at end of file.
+ * Note: this does not store record in vcff->records! */
+{
+char *words[VCF_MAX_COLUMNS];
+int wordCount;
+if ((wordCount = lineFileChop(vcff->lf, words)) <= 0)
+    return NULL;
+int expected = 8;
+if (vcff->genotypeCount > 0)
+    expected = 9 + vcff->genotypeCount;
+lineFileExpectWords(vcff->lf, expected, wordCount);
+return vcfRecordFromRow(vcff, words);
+}
+
+static void vcfParseData(struct vcfFile *vcff, int maxRecords)
+/* Given a vcfFile into which the header has been parsed, and whose lineFile is positioned
+ * at the beginning of a data row, parse and store all data rows from lineFile. */
+{
+if (vcff == NULL)
+    return;
+int recCount = 0;
+struct vcfRecord *record;
+while ((record = vcfNextRecord(vcff)) != NULL)
+    {
+    if (maxRecords >= 0 && recCount >= maxRecords)
+	break;
+    slAddHead(&(vcff->records), record);
+    recCount++;
+    }
+slReverse(&(vcff->records));
+lineFileClose(&(vcff->lf));
+}
+
+struct vcfFile *vcfFileMayOpen(char *fileOrUrl, int maxErr, int maxRecords, boolean parseAll)
+/* Open fileOrUrl and parse VCF header; return NULL if unable.
+ * If parseAll, then read in all lines, parse and store in
+ * vcff->records; if maxErr >= zero, then continue to parse until
+ * there are maxErr+1 errors.  A maxErr less than zero does not stop
+ * and reports all errors. */
+{
+struct lineFile *lf = NULL;
+if (startsWith("http://", fileOrUrl) || startsWith("ftp://", fileOrUrl) ||
+    startsWith("https://", fileOrUrl))
+    lf = netLineFileOpen(fileOrUrl);
+else
+    lf = lineFileMayOpen(fileOrUrl, TRUE);
+struct vcfFile *vcff = vcfFileHeaderFromLineFile(lf, maxErr);
+if (parseAll)
+    vcfParseData(vcff, maxRecords);
+return vcff;
+}
+
+struct vcfFile *vcfTabixFileMayOpen(char *fileOrUrl, char *chrom, int start, int end,
+				    int maxErr, int maxRecords)
+/* Open a VCF file that has been compressed and indexed by tabix and
+ * parse VCF header, or return NULL if unable.  If chrom is non-NULL,
+ * seek to the position range and parse all lines in range into
+ * vcff->records.  If maxErr >= zero, then continue to parse until
+ * there are maxErr+1 errors.  A maxErr less than zero does not stop
+ * and reports all errors. */
+{
+struct lineFile *lf = lineFileTabixMayOpen(fileOrUrl, TRUE);
+struct vcfFile *vcff = vcfFileHeaderFromLineFile(lf, maxErr);
+if (vcff == NULL)
+    return NULL;
+if (isNotEmpty(chrom) && start != end)
+    {
+    if (lineFileSetTabixRegion(lf, chrom, start, end))
+	vcfParseData(vcff, maxRecords);
+    }
+return vcff;
+}
+
+void vcfFileFree(struct vcfFile **pVcff)
+/* Free a vcfFile object. */
+{
+if (pVcff == NULL || *pVcff == NULL)
+    return;
+struct vcfFile *vcff = *pVcff;
+freez(&(vcff->headerString));
+hashFree(&(vcff->pool));
+hashFree(&(vcff->byName));
+lineFileClose(&(vcff->lf));
+freez(pVcff);
+}
+
+const struct vcfRecord *vcfFileFindVariant(struct vcfFile *vcff, char *variantId)
+/* Return all records with name=variantId, or NULL if not found. */
+{
+struct vcfRecord *varList = NULL;
+if (vcff->byName == NULL)
+    {
+    vcff->byName = hashNew(0);
+    struct vcfRecord *rec;
+    for (rec = vcff->records;  rec != NULL;  rec = rec->next)
+	{
+	if (sameString (rec->name, variantId))
+	    {
+	    // Make shallow copy of rec so we can alter ->next:
+	    struct vcfRecord *newRec = vcfFileCloneVar(rec);
+	    slAddHead(&varList, newRec);
+	    }
+	hashAdd(vcff->byName, rec->name, rec);
+	}
+    slReverse(&varList);
+    }
+else
+    {
+    struct hashEl *hel = hashLookup(vcff->byName, variantId);
+    while (hel != NULL)
+	{
+	if (sameString(hel->name, variantId))
+	    {
+	    struct vcfRecord *rec = hel->val;
+	    struct vcfRecord *newRec = vcfFileCloneVar(rec);
+	    slAddHead(&varList, newRec);
+	    }
+	hel = hel->next;
+	}
+    // Don't reverse varList -- hash element list was already reversed
+    }
+return varList;
+}
+
+const struct vcfInfoElement *vcfRecordFindInfo(const struct vcfRecord *record, char *key)
+/* Find an INFO element, or NULL. */
+{
+int i;
+for (i = 0;  i < record->infoCount;  i++)
+    {
+    if (sameString(key, record->infoElements[i].key))
+	return &(record->infoElements[i]);
+    }
+return NULL;
+}
+
+struct vcfInfoDef *vcfInfoDefForGtKey(struct vcfFile *vcff, const char *key)
+/* Look up the type of genotype FORMAT component key, in the definitions from the header,
+ * and failing that, from the keys reserved in the spec. */
+{
+struct vcfInfoDef *def;
+// I expect there to be fairly few definitions (less than a dozen) so
+// I'm just doing a linear search not hash:
+for (def = vcff->gtFormatDefs;  def != NULL;  def = def->next)
+    {
+    if (sameString(key, def->key))
+	return def;
+    }
+for (def = vcfSpecGtFormatDefs;  def != NULL;  def = def->next)
+    {
+    if (sameString(key, def->key))
+	return def;
+    }
+return NULL;
+}
+
+static enum vcfInfoType typeForGtFormat(struct vcfFile *vcff, const char *key)
+/* Look up the type of FORMAT component key, in the definitions from the header,
+ * and failing that, from the keys reserved in the spec. */
+{
+struct vcfInfoDef *def = vcfInfoDefForGtKey(vcff, key);
+if (def == NULL)
+    {
+    vcfFileErr(vcff, "There is no FORMAT header defining \"%s\"", key);
+    // default to string so we can display value as-is:
+    return vcfInfoString;
+    }
+return def->type;
+}
+
+#define VCF_MAX_FORMAT VCF_MAX_INFO
+#define VCF_MAX_FORMAT_LEN (VCF_MAX_FORMAT * 4)
+
+void vcfParseGenotypes(struct vcfRecord *record)
+/* Translate record->genotypesUnparsedStrings[] into proper struct vcfGenotype[].
+ * This destroys genotypesUnparsedStrings. */
+{
+if (record->genotypeUnparsedStrings == NULL)
+    return;
+struct vcfFile *vcff = record->file;
+record->genotypes = vcfFileAlloc(vcff, vcff->genotypeCount * sizeof(struct vcfGenotype));
+char format[VCF_MAX_FORMAT_LEN];
+safecpy(format, sizeof(format), record->format);
+char *formatWords[VCF_MAX_FORMAT];
+int formatWordCount = chopByChar(format, ':', formatWords, ArraySize(formatWords));
+if (formatWordCount >= VCF_MAX_FORMAT)
+    {
+    vcfFileErr(vcff, "The FORMAT column has at least %d words; "
+	       "VCF_MAX_FORMAT may need to be increased in vcf.c!", VCF_MAX_FORMAT);
+    formatWordCount = VCF_MAX_FORMAT;
+    }
+if (differentString(formatWords[0], vcfGtGenotype))
+    vcfFileErr(vcff, "FORMAT column should begin with \"%s\" but begins with \"%s\"",
+	       vcfGtGenotype, formatWords[0]);
+int i;
+// Store the pooled format word pointers and associated types for use in inner loop below.
+enum vcfInfoType formatTypes[VCF_MAX_FORMAT];
+for (i = 0;  i < formatWordCount;  i++)
+    {
+    formatTypes[i] = typeForGtFormat(vcff, formatWords[i]);
+    formatWords[i] = vcfFilePooledStr(vcff, formatWords[i]);
+    }
+for (i = 0;  i < vcff->genotypeCount;  i++)
+    {
+    char *string = record->genotypeUnparsedStrings[i];
+    struct vcfGenotype *gt = &(record->genotypes[i]);
+    // Each genotype can have multiple :-separated info elements:
+    char *gtWords[VCF_MAX_FORMAT];
+    int gtWordCount = chopByChar(string, ':', gtWords, ArraySize(gtWords));
+    if (gtWordCount != formatWordCount)
+	vcfFileErr(vcff, "The FORMAT column has %d words but the genotype column for %s "
+		   "has %d words", formatWordCount, vcff->genotypeIds[i], gtWordCount);
+    if (gtWordCount > formatWordCount)
+	gtWordCount = formatWordCount;
+    gt->id = vcff->genotypeIds[i];
+    gt->infoCount = gtWordCount;
+    gt->infoElements = vcfFileAlloc(vcff, gtWordCount * sizeof(struct vcfInfoElement));
+    int j;
+    for (j = 0;  j < gtWordCount;  j++)
+	{
+	// Special parsing of genotype:
+	if (sameString(formatWords[j], vcfGtGenotype))
+	    {
+	    char *genotype = gtWords[j];
+	    char *sep = strchr(genotype, '|');
+	    if (sep != NULL)
+		gt->isPhased = TRUE;
+	    else
+		sep = strchr(genotype, '/');
+	    if (genotype[0] == '.')
+		gt->hapIxA = -1;
+	    else
+		gt->hapIxA = atoi(genotype);
+	    if (sep == NULL)
+		gt->isHaploid = TRUE;
+	    else if (sep[1] == '.')
+		gt->hapIxB = -1;
+	    else
+		gt->hapIxB = atoi(sep+1);
+	    }
+	struct vcfInfoElement *el = &(gt->infoElements[j]);
+	el->key = formatWords[j];
+	el->count = parseInfoValue(record, formatWords[j], formatTypes[j], gtWords[j],
+				   &(el->values), &(el->missingData));
+	if (el->count >= VCF_MAX_INFO)
+	    vcfFileErr(vcff, "A single element of the genotype column for \"%s\" "
+		       "has at least %d values; "
+		       "VCF_MAX_INFO may need to be increased in vcf.c!",
+		       gt->id, VCF_MAX_INFO);
+	}
+    }
+record->genotypeUnparsedStrings = NULL;
+}
+
+const struct vcfGenotype *vcfRecordFindGenotype(struct vcfRecord *record, char *sampleId)
+/* Find the genotype and associated info for the individual, or return NULL.
+ * This calls vcfParseGenotypes if it has not already been called. */
+{
+struct vcfFile *vcff = record->file;
+if (sampleId == NULL || vcff->genotypeCount == 0)
+    return NULL;
+vcfParseGenotypes(record);
+int ix = stringArrayIx(sampleId, vcff->genotypeIds, vcff->genotypeCount);
+if (ix >= 0)
+    return &(record->genotypes[ix]);
+return NULL;
+}
+
+static char *vcfDataLineAutoSqlString =
+        "table vcfDataLine"
+        "\"The fields of a Variant Call Format data line\""
+        "    ("
+        "    string chrom;      \"An identifier from the reference genome\""
+        "    uint pos;          \"The reference position, with the 1st base having position 1\""
+        "    string id;         \"Semi-colon separated list of unique identifiers where available\""
+        "    string ref;                \"Reference base(s)\""
+        "    string alt;                \"Comma separated list of alternate non-reference alleles "
+                                         "called on at least one of the samples\""
+        "    string qual;       \"Phred-scaled quality score for the assertion made in ALT. i.e. "
+                                 "give -10log_10 prob(call in ALT is wrong)\""
+        "    string filter;     \"PASS if this position has passed all filters. Otherwise, a "
+                                  "semicolon-separated list of codes for filters that fail\""
+        "    string info;       \"Additional information encoded as a semicolon-separated series "
+                                 "of short keys with optional comma-separated values\""
+        "    string format;     \"If genotype columns are specified in header, a "
+                                 "semicolon-separated list of of short keys starting with GT\""
+        "    string genotypes;  \"If genotype columns are specified in header, a tab-separated "
+                                 "set of genotype column values; each value is a colon-separated "
+                                 "list of values corresponding to keys in the format column\""
+        "    )";
+
+struct asObject *vcfAsObj()
+// Return asObject describing fields of VCF
+{
+return asParseText(vcfDataLineAutoSqlString);
+}
+
diff --git a/lib/verbose.c b/lib/verbose.c
new file mode 100644
index 0000000..b8b8be2
--- /dev/null
+++ b/lib/verbose.c
@@ -0,0 +1,128 @@
+/* verbose.c - write out status messages according to the
+ * current verbosity level.  These messages go to stderr. */
+
+#include "common.h"
+#include "portable.h"
+#include "verbose.h"
+
+
+static int logVerbosity = 1;	/* The level of log verbosity.  0 is silent. */
+static FILE *logFile;	/* File to log to. */
+
+static boolean checkedDotsEnabled = FALSE;  /* have we check for dot output
+                                             * being enabled? */
+static boolean dotsEnabled = FALSE;         /* is dot output enabled? */
+
+void verboseVa(int verbosity, char *format, va_list args)
+/* Log with at given verbosity vprintf formatted args. */
+{
+if (verbosity <= logVerbosity)
+    {
+    if (logFile == NULL)
+        logFile = stderr;
+    vfprintf(logFile, format, args);
+    fflush(logFile);
+    }
+}
+
+void verbose(int verbosity, char *format, ...)
+/* Write printf formatted message to log (which by
+ * default is stderr) if global verbose variable
+ * is set to verbosity or higher. */
+{
+va_list args;
+va_start(args, format);
+verboseVa(verbosity, format, args);
+va_end(args);
+}
+
+static long lastTime = -1;  // previous call time.
+
+void verboseTimeInit(void)
+/* Initialize or reinitialize the previous time for use by verboseTime. */
+{
+lastTime = clock1000();
+}
+
+void verboseTime(int verbosity, char *label, ...)
+/* Print label and how long it's been since last call.  Start time can be
+ * initialized with verboseTimeInit, otherwise the elapsed time will be
+ * zero. */
+{
+assert(label != NULL);  // original version allowed this, but breaks some GCCs
+if (lastTime < 0)
+    verboseTimeInit();
+long time = clock1000();
+va_list args;
+va_start(args, label);
+verboseVa(verbosity, label, args);
+verbose(verbosity, ": %ld millis\n", time - lastTime);
+lastTime = time;
+va_end(args);
+}
+
+
+boolean verboseDotsEnabled()
+/* check if outputting of happy dots are enabled.  They will be enabled if the
+ * verbosity is > 0, stderr is a tty and we don't appear to be running an
+ * emacs shell. */
+{
+if (!checkedDotsEnabled)
+    {
+    if (logFile == NULL)
+        logFile = stderr;
+    dotsEnabled = (logVerbosity > 0) && isatty(fileno(logFile));
+    if (dotsEnabled)
+        {
+        /* check for an possible emacs shell */
+        char *emacs = getenv("emacs");
+        char *term = getenv("TERM");
+        if ((emacs != NULL) && (emacs[0] == 't'))
+            dotsEnabled = FALSE;
+        else if ((term != NULL) && sameString(term, "dumb"))
+            dotsEnabled = FALSE;
+        }
+    checkedDotsEnabled = TRUE;
+    }
+return dotsEnabled;
+}
+
+void verboseDot()
+/* Write I'm alive dot (at verbosity level 1) */
+{
+if (verboseDotsEnabled())
+    verbose(1, ".");
+}
+
+void verboseSetLevel(int verbosity)
+/* Set verbosity level in log.  0 for no logging,
+ * higher number for increasing verbosity. */
+{
+logVerbosity = verbosity;
+checkedDotsEnabled = FALSE; /* force rechecking of dots enabled */
+}
+
+int verboseLevel(void)
+/* Get verbosity level. */
+{
+return logVerbosity;
+}
+
+void verboseSetLogFile(char *name)
+/* Set logFile for verbose messages overrides stderr. */
+{
+if (sameString(name, "stdout"))
+    logFile = stdout;
+else if (sameString(name, "stderr"))
+    logFile = stderr;
+else
+    logFile = mustOpen(name, "w");
+}
+
+FILE *verboseLogFile()
+/* Get the verbose log file. */
+{
+if (logFile == NULL)
+    logFile = stderr;
+return logFile;
+}
diff --git a/lib/wildcmp.c b/lib/wildcmp.c
new file mode 100644
index 0000000..1fa1309
--- /dev/null
+++ b/lib/wildcmp.c
@@ -0,0 +1,116 @@
+/* Wildcard matching. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+
+
+static int subMatch(const char *str, const char *wild, char single, char multi)
+/* Returns number of characters that match between str and wild up
+ * to the next wildcard in wild (or up to end of string.). */
+{
+int len = 0;
+
+for(;;)
+    {
+    if(toupper(*str++) != toupper(*wild++) )
+        return(0);
+    ++len;
+    char c = *wild;
+    if (c == 0 || c == single || c == multi)
+       return len;
+    }
+}
+
+boolean anyWild(const char *string)
+/* Return TRUE if any wild card characters in string. */
+{
+char c;
+while ((c = *string++) != 0)
+    {
+    if (c == '?' || c == '*')
+        return TRUE;
+    }
+return FALSE;
+}
+
+static boolean globMatch(const char *wildCard, const char *string, char single, char multi)
+/* does a case sensitive wild card match with a string.
+ * * matches any string or no character.
+ * ? matches any single character.
+ * anything else etc must match the character exactly. */
+{
+boolean matchStar = 0;
+int starMatchSize;
+char c;
+
+for(;;)
+    {
+NEXT_WILD:
+    c = *wildCard;
+    if (c == 0)
+	{
+	if(matchStar)
+	    {
+	    while(*string++)
+		;
+	    return TRUE;
+	    }
+	else if(*string)
+	    return FALSE;
+	else
+	    return TRUE;
+	}
+    else if (c == multi)
+	{
+	matchStar = TRUE;
+	}
+    else if (c == single)
+	{
+	if(*string == 0)
+	    return FALSE; /* out of string, no match for ? */
+	++string;
+	}
+    else
+	{
+	if(matchStar)
+	    {
+	    for(;;)
+		{
+		if(*string == 0) /* if out of string no match */
+		    return FALSE;
+
+		/* note matchStar is re-used here for substring
+		 * after star match length */
+		if((starMatchSize = subMatch(string,wildCard,single,multi)) != 0)
+		    {
+		    string += starMatchSize;
+		    wildCard += starMatchSize;
+		    matchStar = FALSE;
+		    goto NEXT_WILD;
+		    }
+		++string;
+		}
+	    }
+
+	/* default: they must be equal or no match */
+	if(toupper(*string) != toupper(*wildCard))
+	    return FALSE;
+	++string;
+	}
+    ++wildCard;
+    }
+}
+
+boolean wildMatch(const char *wildCard, const char *string)
+/* Match using * and ? wildcards. */
+{
+return globMatch(wildCard, string, '?', '*');
+}
+
+boolean sqlMatchLike(char *wildCard, char *string)
+/* Match using % and _ wildcards. */
+{
+return globMatch(wildCard, string, '_', '%');
+}
diff --git a/lib/wormdna.c b/lib/wormdna.c
new file mode 100644
index 0000000..ad50ca8
--- /dev/null
+++ b/lib/wormdna.c
@@ -0,0 +1,1212 @@
+/* wormDna - Stuff for finding worm DNA and annotation features.
+ * This is pretty much the heart of the cobbled-together 'database'
+ * behind the intronerator. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "dnautil.h"
+#include "dnaseq.h"
+#include "fa.h"
+#include "gdf.h"
+#include "nt4.h"
+#include "snof.h"
+#include "wormdna.h"
+#include "cda.h"
+#include "sig.h"
+#include "dystring.h"
+
+
+static char *jkwebDir = NULL;
+
+static char *cdnaDir = NULL;
+static char *featDir = NULL;
+static char *nt4Dir = NULL;
+static char *sangerDir = NULL;
+static char *genieDir = NULL;
+static char *xenoDir = NULL;
+
+static void getDirs()
+/* Look up the directories where our data is stored. */
+{
+if (jkwebDir == NULL)
+    {
+    char buf[512];
+    
+    /* Look up directory where directory pointer files are stored
+     * in environment string if it's there. */
+    if ((jkwebDir = getenv("JKWEB")) == NULL)
+        jkwebDir = "";
+
+    sprintf(buf, "%scdna.dir", jkwebDir);
+    firstWordInFile(buf, buf, sizeof(buf));
+    cdnaDir = cloneString(buf);
+
+    sprintf(buf, "%sfeat.dir", jkwebDir);
+    firstWordInFile(buf, buf, sizeof(buf));
+    featDir = cloneString(buf);
+
+    sprintf(buf, "%snt4.dir", jkwebDir);
+    firstWordInFile(buf, buf, sizeof(buf));
+    nt4Dir = cloneString(buf);
+
+    sprintf(buf, "%ssanger/", featDir); 
+    sangerDir = cloneString(buf);
+
+    sprintf(buf, "%sgenie/", featDir);
+    genieDir = cloneString(buf);
+
+    sprintf(buf, "%sxeno.dir", jkwebDir);
+    firstWordInFile(buf, buf, sizeof(buf));
+    xenoDir = cloneString(buf);
+    }
+}
+
+char *wormFeaturesDir()
+/* Return the features directory. (Includes trailing slash.) */
+{
+getDirs();
+return featDir;
+}
+
+char *wormChromDir()
+/* Return the directory with the chromosomes. */
+{
+getDirs();
+return nt4Dir;
+}
+
+char *wormCdnaDir()
+/* Return directory with cDNA data. */
+{
+getDirs();
+return cdnaDir;
+}
+
+char *wormSangerDir()
+/* Return directory with Sanger specific gene predictions. */
+{
+getDirs();
+return sangerDir;
+}
+
+char *wormGenieDir()
+/* Return directory with Genie specific gene predictions. */
+{
+getDirs();
+return genieDir;
+}
+
+char *wormXenoDir()
+/* Return directory with cross-species alignments. */
+{
+getDirs();
+return xenoDir;
+}
+
+static char *chromIds[] = {"i", "ii", "iii", "iv", "v", "x", "m", };
+
+void wormChromNames(char ***retNames, int *retNameCount)
+/* Get list of worm chromosome names. */
+{
+*retNames = chromIds;
+*retNameCount = ArraySize(chromIds);
+}
+
+int wormChromIx(char *name)
+/* Return index of worm chromosome. */
+{
+return stringIx(name, chromIds);
+}
+
+char *wormChromForIx(int ix)
+/* Given ix, return worm chromosome official name. */
+{
+assert(ix >= 0 && ix <= ArraySize(chromIds));
+return chromIds[ix];
+}
+
+char *wormOfficialChromName(char *name)
+/* This returns a pointer to our official string for the chromosome name.
+ * (This allows some routines to do direct pointer comparisons rather
+ * than string comparisons.) */
+{
+int ix = wormChromIx(name);
+if (ix < 0) return NULL;
+return chromIds[ix];
+}
+
+
+static struct snof *cdnaSnof = NULL;
+static FILE *cdnaFa = NULL;
+
+static void wormCdnaCache()
+/* Set up to read cDNAs */
+{
+getDirs();
+if (cdnaSnof == NULL)
+    {
+    char buf[512];
+
+    sprintf(buf, "%s%s", cdnaDir, "allcdna");
+    cdnaSnof = snofMustOpen(buf);
+    sprintf(buf, "%s%s", cdnaDir, "allcdna.fa");
+    cdnaFa = mustOpen(buf, "rb");
+    }
+}
+
+void wormCdnaUncache()
+/* Tear down structure for reading cDNAs. */
+{
+snofClose(&cdnaSnof);
+carefulClose(&cdnaFa);
+freez(&cdnaDir);
+}
+
+void wormFreeCdnaInfo(struct wormCdnaInfo *ci)
+/* Free the mother string in the cdnaInfo.  (The info structure itself normally isn't
+ * dynamically allocated. */
+{
+freeMem(ci->motherString);
+zeroBytes(ci, sizeof(*ci));
+}
+
+static char *realInfoString(char *s)
+/* Returns NULL if s is just "?", the NULL placeholder. */
+{
+if (s[0] == '?' && s[1] == 0) return NULL;
+return s;
+}
+
+static void parseRestOfCdnaInfo(char *textInfo, struct wormCdnaInfo *retInfo)
+/* Parse text info string into a binary structure retInfo. */
+{
+int wordCount;
+char *words[32];
+char *s;
+
+wordCount = chopString(textInfo, "|", words, ArraySize(words));
+if (wordCount < 8)
+    errAbort("Expecting at least 8 fields in cDNA database, got %d", wordCount);
+if ((s = realInfoString(words[0])) != NULL)
+    retInfo->orientation = s[0];
+retInfo->gene = realInfoString(words[1]);
+retInfo->product = realInfoString(words[2]);
+if ((s = realInfoString(words[3])) != NULL)
+    {
+    char *parts[2];
+    int partCount;
+    partCount = chopString(s, ".", parts, ArraySize(parts));
+    if (partCount == 2)
+        {
+        retInfo->knowStart = retInfo->knowEnd = TRUE;
+        if (parts[0][0] == '<')
+            {
+            retInfo->knowStart = FALSE;
+            parts[0] += 1;
+            }
+        if (parts[1][0] == '>')
+            {
+            retInfo->knowEnd = FALSE;
+            parts[1] += 1;
+            }
+        retInfo->cdsStart = atoi(parts[0]);
+        retInfo->cdsEnd = atoi(parts[1]);
+        }
+    }
+if ((s = realInfoString(words[4])) != NULL)
+    {
+    if (sameString("embryo", s))
+        retInfo->isEmbryonic = TRUE;
+    else if (sameString("adult", s))
+        retInfo->isAdult = TRUE;
+    }
+if ((s = realInfoString(words[5])) != NULL)
+    {
+    if (sameString("herm", s))
+        retInfo->isHermaphrodite = TRUE;
+    else if (sameString("male", s))
+        retInfo->isMale = TRUE;
+    }
+
+if ((s = realInfoString(words[6])) != NULL)
+    {
+    /* Reserved. Unused currently */
+    }
+retInfo->description = realInfoString(words[7]);
+}
+
+void wormFaCommentIntoInfo(char *faComment, struct wormCdnaInfo *retInfo)
+/* Process line from .fa file containing information about cDNA into binary
+ * structure. */
+{
+if (retInfo)
+    {
+    char *s;
+    zeroBytes(retInfo, sizeof(*retInfo));
+    /* Separate out first word and use it as name. */
+    s = strchr(faComment, ' ');
+    if (s == NULL)
+        errAbort("Expecting lots of info, just got %s", faComment);
+    *s++ = 0;
+    retInfo->name = faComment+1;
+    retInfo->motherString = faComment;
+
+    parseRestOfCdnaInfo(s, retInfo);
+    }
+}
+
+boolean wormCdnaInfo(char *name, struct wormCdnaInfo *retInfo)
+/* Get info about cDNA sequence. */
+{
+char commentBuf[512];
+char *comment;
+long offset;
+
+wormCdnaCache();
+if (!snofFindOffset(cdnaSnof, name, &offset))
+    return FALSE;
+fseek(cdnaFa, offset, SEEK_SET);
+mustGetLine(cdnaFa, commentBuf, sizeof(commentBuf));
+if (commentBuf[0] != '>')
+    errAbort("Expecting line starting with > in cDNA fa file.\nGot %s", commentBuf);
+comment = cloneString(commentBuf);
+wormFaCommentIntoInfo(comment, retInfo);
+return TRUE;
+}
+
+boolean wormCdnaSeq(char *name, struct dnaSeq **retDna, struct wormCdnaInfo *retInfo)
+/* Get a single worm cDNA sequence. Optionally (if retInfo is non-null) get additional
+ * info about the sequence. */
+{
+long offset;
+char *faComment;
+char **pFaComment = (retInfo == NULL ? NULL : &faComment);
+
+wormCdnaCache();
+if (!snofFindOffset(cdnaSnof, name, &offset))
+    return FALSE;
+fseek(cdnaFa, offset, SEEK_SET);
+if (!faReadNext(cdnaFa, name, TRUE, pFaComment, retDna))
+    return FALSE;
+wormFaCommentIntoInfo(faComment, retInfo);
+return TRUE;
+}
+
+struct wormFeature *newWormFeature(char *name, char *chrom, int start, int end, char typeByte)
+/* Allocate a new feature. */
+{
+int size = sizeof(struct wormFeature) + strlen(name);
+struct wormFeature *feat = needMem(size);
+feat->chrom = chrom;
+feat->start = start;
+feat->end = end;
+feat->typeByte = typeByte;
+strcpy(feat->name, name);
+return feat;
+}
+
+
+static struct wormFeature *scanChromOffsetFile(char *dir, char *suffix, 
+    bits32 signature, int nameOffset, char *chromId, int start, int end,
+    int addEnd)
+/* Scan a chrom.pgo or chrom.cdo file for names of things that are within
+ * range. */
+{
+FILE *f;
+char fileName[512];
+bits32 sig, nameSize, entryCount;
+int entrySize;
+int *entry;
+char *name;
+bits32 i;
+struct wormFeature *list = NULL, *el;
+char *typePt;
+char typeByte;
+
+sprintf(fileName, "%s%s%s", dir, chromId, suffix);
+f = mustOpen(fileName, "rb");
+mustReadOne(f, sig);
+if (sig != signature)
+    errAbort("Bad signature on %s", fileName);
+mustReadOne(f, entryCount);
+mustReadOne(f, nameSize);
+entrySize = nameSize + nameOffset;
+entry = needMem(entrySize + 1);
+name = (char *)entry;
+name += nameOffset;
+typePt = name-1;
+for (i=0; i<entryCount; ++i)
+    {
+    mustRead(f, entry, entrySize);
+    if (entry[0] > end)
+        break;
+    if (entry[1] < start)
+        continue;
+    typeByte = *typePt;
+    el = newWormFeature(name, chromId, entry[0], entry[1]+addEnd, typeByte);
+    slAddHead(&list, el);
+    }
+slReverse(&list);
+fclose(f);
+freeMem(entry);
+return list;
+}
+
+struct wormFeature *wormCdnasInRange(char *chromId, int start, int end)
+/* Get all cDNAs that overlap the range. freeDnaSeqList the returned
+ * list when you are through with it. */
+{
+/* This routine looks through the .CDO files made by cdnaOff
+ */
+getDirs();
+return scanChromOffsetFile(cdnaDir, ".cdo", cdoSig, 2*sizeof(int)+1, 
+    chromId, start, end, 0);
+}
+
+struct wormFeature *wormSomeGenesInRange(char *chromId, int start, int end, char *gdfDir)
+/* Get info on genes that overlap range in a particular set of gene predictions. */
+{
+return scanChromOffsetFile(gdfDir, ".pgo", pgoSig, 2*sizeof(int)+1,
+    chromId, start, end, 0);
+}
+
+struct wormFeature *wormGenesInRange(char *chromId, int start, int end)
+/* Get names of all genes that overlap the range. */
+{
+/* This routine looks through the .PGO files made by makePgo
+ */
+getDirs();
+return wormSomeGenesInRange(chromId, start, end, sangerDir);
+}
+
+struct wormFeature *wormCosmidsInRange(char *chromId, int start, int end)
+/* Get names of all genes that overlap the range. */
+{
+/* This routine looks through the .COO files made by makePgo
+ */
+getDirs();
+return scanChromOffsetFile(featDir, ".coo", pgoSig, 2*sizeof(int)+1,
+    chromId, start, end, 1);
+}
+
+FILE *wormOpenGoodAli()
+/* Opens good alignment file and reads signature. 
+ * (You can then cdaLoadOne() it.) */
+{
+char fileName[512];
+getDirs();
+sprintf(fileName, "%sgood.ali", cdnaDir);
+return cdaOpenVerify(fileName);
+}
+
+struct cdaAli *wormCdaAlisInRange(char *chromId, int start, int end)
+/* Return list of cdna alignments that overlap range. */
+{
+struct cdaAli *list = NULL, *el;
+char fileName[512];
+FILE *ixFile, *aliFile;
+bits32 sig;
+int s, e;
+long fpos;
+
+aliFile = wormOpenGoodAli();
+
+sprintf(fileName, "%s%s.alx", cdnaDir, chromId);
+ixFile = mustOpen(fileName, "rb");
+mustReadOne(ixFile, sig);
+if (sig != alxSig)
+    errAbort("Bad signature on %s", fileName);
+
+for (;;)
+    {
+    if (!readOne(ixFile, s))
+        break;
+    mustReadOne(ixFile, e);
+    mustReadOne(ixFile, fpos);
+    if (e <= start)
+        continue;
+    if (s >= end)
+        break;
+    AllocVar(el);
+    fseek(aliFile, fpos, SEEK_SET);
+    el = cdaLoadOne(aliFile);
+    if (el == NULL)
+        errAbort("Truncated cdnaAli file");
+    slAddHead(&list, el);
+    }
+slReverse(&list);
+fclose(aliFile);
+fclose(ixFile);
+return list;
+}
+
+boolean nextWormCdnaAndInfo(struct wormCdnaIterator *it, struct dnaSeq **retSeq, 
+    struct wormCdnaInfo *retInfo)
+/* Return next sequence and associated info from database. */
+{
+char *faComment;
+
+if (!faReadNext(it->faFile, "unknown", TRUE, &faComment, retSeq))
+    return FALSE;
+wormFaCommentIntoInfo(faComment, retInfo);
+return TRUE;
+}
+
+struct dnaSeq *nextWormCdna(struct wormCdnaIterator *it)
+/* Return next sequence in database */
+{
+return faReadOneDnaSeq(it->faFile, "unknown", TRUE);
+}
+
+boolean wormSearchAllCdna(struct wormCdnaIterator **retSi)
+/* Set up to search entire database or worm cDNA */
+{
+char buf[512];
+struct wormCdnaIterator *it;
+
+it = needMem(sizeof(*it));
+getDirs();
+sprintf(buf, "%s%s", cdnaDir, "allcdna.fa");
+it->faFile = mustOpen(buf, "rb");
+*retSi = it;
+return TRUE;
+}
+
+void freeWormCdnaIterator(struct wormCdnaIterator **pIt)
+/* Free up iterator returned by wormSearchAllCdna() */
+{
+struct wormCdnaIterator *it = *pIt;
+if (it != NULL)
+    {
+    carefulClose(&it->faFile);
+    freez(pIt);
+    }
+}
+
+static boolean isAllAlpha(char *s)
+/* Returns TRUE if every character in string is a letter. */
+{
+char c;
+while ((c = *s++) != 0)
+    {
+    if (!isalpha(c)) return FALSE;
+    }
+return TRUE;
+}
+
+static boolean isAllDigit(char *s)
+/* Returns TRUE if every character in string is a digit. */
+{
+char c;
+while ((c = *s++) != 0)
+    {
+    if (!isdigit(c)) return FALSE;
+    }
+return TRUE;
+}
+
+boolean wormIsOrfName(char *in)
+/* Check to see if the input is formatted correctly to be
+ * an ORF. */
+{
+return strchr(in, '.') != NULL;
+}
+
+boolean wormIsGeneName(char *name)
+/* See if it looks like a worm gene name - that is
+ *   abc-12
+ * letters followed by a dash followed by a number. */
+{
+char buf[128];
+int partCount;
+strncpy(buf, name, sizeof(buf));
+partCount = chopString(buf, "-", NULL, 0);
+if (partCount == 2)
+    {
+    char *parts[2];
+    chopString(buf, "-", parts, 2);
+    return isAllAlpha(parts[0]) && isAllDigit(parts[1]);
+    }
+else
+    {
+    return FALSE;
+    }
+}
+
+struct slName *wormGeneToOrfNames(char *name)
+/* Returns list of cosmid.N type ORF names that are known by abc-12 type name. */
+{
+struct slName *synList = NULL;
+char synFileName[512];
+FILE *synFile;
+char lineBuf[128];
+int nameLen = strlen(name);
+
+/* genes are supposed to be lower case. */
+tolowers(name);
+
+/* Open synonym file and loop through each line of it */
+sprintf(synFileName, "%ssyn", wormFeaturesDir());
+if ((synFile = fopen(synFileName, "r")) == NULL)
+    errAbort("Can't find synonym file '%s'. (errno: %d)\n", synFileName, errno);
+while (fgets(lineBuf, ArraySize(lineBuf), synFile))
+    {
+    /* If first part of line matches chop up line. */
+    if (strncmp(name, lineBuf, nameLen) == 0)
+	{
+	char *syns[32];
+	int count;
+	count = chopString(lineBuf, whiteSpaceChopper, syns, ArraySize(syns));
+
+	/* Looks like we got a synonym.  Add all the aliases. */
+	if (strcmp(name, syns[0]) == 0)
+	    {
+	    int i;
+	    for (i=1; i<count; ++i)
+                slAddTail(&synList, newSlName(syns[i]));
+	    break;
+	    }
+	}
+    }
+fclose(synFile);
+return synList;
+}
+
+char *wormGeneFirstOrfName(char *geneName)
+/* Return first ORF synonym to gene. */
+{
+struct slName *synList = wormGeneToOrfNames(geneName);
+char *name;
+if (synList == NULL)
+    return NULL;
+name = cloneString(synList->name);
+slFreeList(&synList);
+return name;
+}
+
+boolean wormGeneForOrf(char *orfName, char *geneNameBuf, int bufSize)
+/* Look for gene type (unc-12 or something) synonym for cosmid.N name. */
+{
+FILE *f;
+char fileName[512];
+char lineBuf[512];
+int nameLen = strlen(orfName);
+boolean ok = FALSE;
+
+sprintf(fileName, "%sorf2gene", wormFeaturesDir());
+f = mustOpen(fileName, "r");
+while (fgets(lineBuf, sizeof(lineBuf), f))
+    {
+    if (strncmp(lineBuf, orfName, nameLen) == 0 && lineBuf[nameLen] == ' ')
+        {
+        char *words[2];
+        int wordCount;
+        wordCount = chopLine(lineBuf, words);
+        assert((int)strlen(words[1]) < bufSize);
+        strncpy(geneNameBuf, words[1], bufSize);
+        ok = TRUE;
+        break;
+        }
+    }
+fclose(f);
+return ok;
+}
+
+boolean wormInfoForGene(char *orfName, struct wormCdnaInfo *retInfo)
+/* Return info if any on ORF, or NULL if none exists. freeMem() return value. */
+{
+FILE *f;
+char fileName[512];
+char lineBuf[512];
+int nameLen;
+char *info = NULL;
+char *synName = NULL;
+int lineCount = 0;
+
+/* Make this one work for orfs as well as gene names */
+if (wormIsGeneName(orfName))
+    {
+    synName = wormGeneFirstOrfName(orfName);
+    if (synName != NULL)
+        orfName = synName;
+    }
+sprintf(fileName, "%sorfInfo", wormFeaturesDir());
+nameLen = strlen(orfName);
+f = mustOpen(fileName, "r");
+while (fgets(lineBuf, sizeof(lineBuf), f))
+    {
+    ++lineCount;
+    if (strncmp(lineBuf, orfName, nameLen) == 0 && lineBuf[nameLen] == ' ')
+        {
+        info = cloneString(lineBuf);
+        break;
+        }
+    }
+freeMem(synName);
+fclose(f);
+if (info == NULL)
+    return FALSE;
+wormFaCommentIntoInfo(info, retInfo);
+return TRUE;;
+}
+
+boolean getWormGeneDna(char *name, DNA **retDna, boolean upcExons)
+/* Get the DNA associated with a gene.  Optionally upper case exons. */
+{
+struct gdfGene *g;
+struct slName *syn = NULL;
+long lstart, lend;
+int start, end;
+int dnaSize;
+DNA *dna;
+struct wormGdfCache *gdfCache;
+
+/* Translate biologist type name to cosmid.N name */
+if (wormIsGeneName(name))
+    {
+    syn = wormGeneToOrfNames(name);
+    if (syn != NULL)
+        name = syn->name;
+    }
+if (strncmp(name, "g-", 2) == 0)
+    gdfCache = &wormGenieGdfCache;
+else
+    gdfCache = &wormSangerGdfCache;
+if ((g = wormGetSomeGdfGene(name, gdfCache)) == NULL)
+    return FALSE;
+gdfGeneExtents(g, &lstart, &lend);
+start = lstart;
+end = lend;
+/* wormClipRangeToChrom(chromIds[g->chromIx], &start, &end); */
+dnaSize = end-start;
+*retDna = dna = wormChromPart(chromIds[g->chromIx], start, dnaSize);
+
+gdfOffsetGene(g, -start);
+if (g->strand == '-')
+    {
+    reverseComplement(dna, dnaSize);
+    gdfRcGene(g, dnaSize);
+    }
+if (upcExons)
+    {
+    int i;
+    struct gdfDataPoint *pt = g->dataPoints;
+    for (i=0; i<g->dataCount; i += 2)
+        {
+        toUpperN(dna + pt[i].start, pt[i+1].start - pt[i].start);
+        }
+    }
+gdfFreeGene(g);
+return TRUE;
+}
+
+boolean getWormGeneExonDna(char *name, DNA **retDna)
+/* Get the DNA associated with a gene, without introns.  */
+{
+struct gdfGene *g;
+struct slName *syn = NULL;
+long lstart, lend;
+int start, end;
+int dnaSize;
+DNA *dna;
+int i;
+struct gdfDataPoint *pt = NULL;
+struct wormGdfCache *gdfCache;
+struct dyString *dy = newDyString(1000);
+/* Translate biologist type name to cosmid.N name */
+if (wormIsGeneName(name))
+    {
+    syn = wormGeneToOrfNames(name);
+    if (syn != NULL)
+        name = syn->name;
+    }
+if (strncmp(name, "g-", 2) == 0)
+    gdfCache = &wormGenieGdfCache;
+else
+    gdfCache = &wormSangerGdfCache;
+if ((g = wormGetSomeGdfGene(name, gdfCache)) == NULL)
+    return FALSE;
+gdfGeneExtents(g, &lstart, &lend);
+start = lstart;
+end = lend;
+/*wormClipRangeToChrom(chromIds[g->chromIx], &start, &end);*/
+dnaSize = end-start;
+dna = wormChromPart(chromIds[g->chromIx], start, dnaSize);
+
+gdfOffsetGene(g, -start);
+if (g->strand == '-')
+    {
+    reverseComplement(dna, dnaSize);
+    gdfRcGene(g, dnaSize);
+    }
+pt = g->dataPoints;
+for (i=0; i<g->dataCount; i += 2)
+    {
+    dyStringAppendN(dy, (dna+pt[i].start), (pt[i+1].start - pt[i].start));
+    }
+*retDna = cloneString(dy->string);
+dyStringFree(&dy);
+gdfFreeGene(g);
+return TRUE;
+}
+
+static void makeChromFileName(char *chromId, char *buf)
+{
+getDirs();
+sprintf(buf, "%s%s.nt4", nt4Dir, chromId);
+}
+
+void wormLoadNt4Genome(struct nt4Seq ***retNt4Seq, int *retNt4Count)
+/* Load up entire packed worm genome into memory. */
+{
+int count = ArraySize(chromIds);
+struct nt4Seq **nt4s = needMem(count*sizeof(*nt4s));
+int i;
+char fileName[512];
+
+for (i=0; i<count; ++i)
+    {
+    makeChromFileName(chromIds[i], fileName);
+    nt4s[i] = loadNt4(fileName, chromIds[i]);
+    }
+*retNt4Seq = nt4s;
+*retNt4Count = count;
+}
+
+void wormFreeNt4Genome(struct nt4Seq ***pNt4Seq)
+/* Free up packed worm genome. */
+{
+struct nt4Seq **seqs;
+int i;
+if ((seqs = *pNt4Seq) == NULL)
+    return;
+for (i=0; i<ArraySize(chromIds); ++i)
+    freeNt4(&seqs[i]);
+freez(pNt4Seq);
+}
+
+int wormChromSize(char *chrom)
+/* Return size of worm chromosome. */
+{
+static int sizes[ArraySize(chromIds)];
+int ix;
+int size;
+
+if ((ix = wormChromIx(chrom)) < 0)
+    errAbort("%s isn't a chromosome", chrom);
+size = sizes[ix];
+
+/* If we don't know it already have to get it from file. */
+if (size == 0)
+    {
+    char fileName[512];
+    makeChromFileName(chromIds[ix], fileName);
+    size = sizes[ix] = nt4BaseCount(fileName);
+    }
+return size;
+}
+
+
+DNA *wormChromPart(char *chromId, int start, int size)
+/* Return part of a worm chromosome. */
+{
+char fileName[512];
+makeChromFileName(chromId, fileName);
+return nt4LoadPart(fileName, start, size);
+}
+
+DNA *wormChromPartExonsUpper(char *chromId, int start, int size)
+/* Return part of a worm chromosome with exons in upper case. */
+{
+DNA *dna = wormChromPart(chromId, start, size);
+struct wormFeature *geneFeat = wormGenesInRange(chromId, start, start+size);
+struct wormFeature *feat;
+
+for (feat = geneFeat; feat != NULL; feat = feat->next)
+    {
+    char *name = feat->name;
+    if (!wormIsNamelessCluster(name))
+        {
+        struct gdfGene *gene = wormGetGdfGene(name);
+        gdfUpcExons(gene, feat->start, dna, size, start);
+        gdfFreeGene(gene);
+        }
+    }
+slFreeList(&geneFeat);
+return dna;
+}
+
+void wormClipRangeToChrom(char *chrom, int *pStart, int *pEnd)
+/* Make sure that we stay inside chromosome. */
+{
+int chromEnd = wormChromSize(chrom);
+int temp;
+
+/* Swap ends if reversed. */
+if (*pStart > *pEnd)
+    {
+    temp = *pEnd;
+    *pEnd = *pStart;
+    *pStart = temp;
+    }
+/* Generally speaking try to slide the range covered by
+ * start-end inside the chromosome rather than just
+ * truncating an end. */
+if (*pStart < 0)
+    {
+    *pEnd -= *pStart;
+    *pStart = 0;
+    }
+if (*pEnd > chromEnd)
+    {
+    *pStart -= *pEnd - chromEnd;
+    *pEnd = chromEnd;
+    }
+/* This handles case where the range is larger than the chromosome. */
+if (*pStart < 0)
+    *pStart = 0;
+}
+
+boolean wormParseChromRange(char *in, char **retChromId, int *retStart, int *retEnd)
+/* Chop up a string representation of a range within a chromosome and put the
+ * pieces into the return variables. Return FALSE if it isn't formatted right. */
+{
+char *words[5];
+int wordCount;
+char *chromId;
+char buf[128];
+
+strncpy(buf, in, sizeof(buf));
+wordCount = chopString(buf, "- \t\r\n:", words, ArraySize(words));
+if (wordCount != 3)
+    return FALSE;
+chromId = wormOfficialChromName(words[0]);
+if (chromId == NULL)
+    return FALSE;
+if (!isdigit(words[1][0]) || !isdigit(words[2][0]))
+    return FALSE;
+*retChromId = chromId;
+*retStart = atoi(words[1]);
+*retEnd = atoi(words[2]);
+wormClipRangeToChrom(chromId, retStart, retEnd);
+return TRUE;
+}
+
+boolean wormIsChromRange(char *in)
+/* Check to see if the input is formatted correctly to be
+ * a range of a chromosome. */
+{
+char *chromId;
+int start, end;
+boolean ok;
+ok =  wormParseChromRange(in, &chromId, &start, &end);
+return ok;
+}
+
+boolean wormFixupOrfName(char *name)
+/* Turn something into a proper cosmid.# style name. Return FALSE if it can't be done. */
+{
+char *dot = strrchr(name, '.');
+if (dot == NULL)
+    return FALSE;
+toUpperN(name, dot-name);   /* First part always upper case. */
+if (!isdigit(dot[1]))          /* Nameless cluster - just leave following digits be. */
+    return TRUE;
+else
+    tolowers(dot+1);        /* Suffix is lower case. */
+return TRUE;
+}
+
+boolean wormIsAltSplicedName(char *name)
+/* Is name in right form to be an isoform? */
+{
+char *dot = strrchr(name, '.');
+if (dot == NULL)
+    return FALSE;
+if (!isdigit(dot[1]))
+    return FALSE;
+return isalpha(dot[strlen(dot)-1]);
+}
+
+static void makeIsoformBaseName(char *name)
+{
+if (wormIsAltSplicedName(name))
+    name[strlen(name)-1] = 0;
+}
+
+static boolean findAltSpliceRange(char *name, struct snof *snof, FILE *f, 
+    char **retChrom, int *retStart, int *retEnd, char *retStrand)
+/* Return range of chromosome covered by a gene and all of it's isoforms. */
+{
+char baseName[64];
+char bName[64];
+int snIx, maxIx;
+int start = 0x7fffffff;
+int end = -start;
+char lineBuf[128];
+char *words[3];
+int wordCount;
+int baseNameSize;
+
+strcpy(baseName, name);
+makeIsoformBaseName(baseName);
+baseNameSize = strlen(baseName);
+if (!snofFindFirstStartingWith(snof, baseName, baseNameSize, &snIx))
+    return FALSE;
+maxIx = snofElementCount(snof);
+for (;snIx < maxIx; ++snIx)
+    {
+    long offset;
+    char *geneName;
+
+    snofNameOffsetAtIx(snof, snIx, &geneName, &offset);
+    if (strncmp(geneName, baseName, baseNameSize) != 0)
+        break;
+    strcpy(bName, geneName);
+    makeIsoformBaseName(bName);
+    if (sameString(baseName, bName))
+        {
+        int s, e;
+        fseek(f, offset, SEEK_SET);
+        mustGetLine(f, lineBuf, sizeof(lineBuf));
+        wordCount = chopLine(lineBuf, words);
+        assert(wordCount == 3);
+        wormParseChromRange(words[0], retChrom, &s, &e);
+        *retStrand = words[1][0];
+        if (start > s)
+            start = s;
+        if (end < e)
+            end = e;
+        }
+    }
+*retStart = start;
+*retEnd = end;
+return TRUE;
+}
+
+
+boolean wormGeneRange(char *name, char **retChrom, char *retStrand, int *retStart, int *retEnd)
+/* Return chromosome position of a chrom range, gene, ORF, cosmid, or nameless cluster. */
+{
+static struct snof *c2gSnof = NULL, *c2cSnof = NULL;
+static FILE *c2gFile = NULL, *c2cFile = NULL;
+long offset;
+char fileName[512];
+struct slName *syn = NULL;
+boolean ok;
+
+if (wormIsChromRange(name))
+    {
+    *retStrand = '.';
+    return wormParseChromRange(name, retChrom, retStart, retEnd);
+    }
+
+getDirs();
+
+/* Translate biologist type name to cosmid.N name */
+if (wormIsGeneName(name))
+    {
+    syn = wormGeneToOrfNames(name);
+    if (syn != NULL)
+	{
+        name = syn->name;
+	}
+    }
+if (wormFixupOrfName(name)) /* See if ORF, and if so make nice. */
+    {
+    if (c2gSnof == NULL)
+        {
+        sprintf(fileName, "%sc2g", featDir);
+        c2gSnof = snofMustOpen(fileName);
+        sprintf(fileName, "%sc2g", featDir);
+        c2gFile = mustOpen(fileName, "rb");
+        }
+    ok = findAltSpliceRange(name, c2gSnof, c2gFile, retChrom, retStart, retEnd, retStrand);
+    }
+else    /* Lets say it's a cosmid. */
+    {
+    char lineBuf[128];
+    char *words[3];
+    int wordCount;
+    touppers(name);
+    if (c2cSnof == NULL)
+        {
+        sprintf(fileName, "%sc2c", featDir);
+        c2cSnof = snofMustOpen(fileName);
+        sprintf(fileName, "%sc2c", featDir);
+        c2cFile = mustOpen(fileName, "rb");
+        }
+    if (!snofFindOffset(c2cSnof, name, &offset) )
+        return FALSE;
+    fseek(c2cFile, offset, SEEK_SET);
+    mustGetLine(c2cFile, lineBuf, sizeof(lineBuf));
+    wordCount = chopLine(lineBuf, words);
+    assert(wordCount == 3);
+    assert(strcmp(words[2], name) == 0);
+    assert(wormIsChromRange(words[0]));
+    *retStrand = words[1][0];
+    ok = wormParseChromRange(words[0], retChrom, retStart, retEnd);
+    }
+slFreeList(&syn);
+return ok;
+}
+
+boolean wormIsNamelessCluster(char *name)
+/* Returns true if name is of correct format to be a nameless cluster. */
+{
+char *e = strrchr(name, '.');
+if (e == NULL)
+    return FALSE;
+if (e[1] != 'N')
+    return FALSE;
+if (!isdigit(e[2]))
+    return FALSE;
+return TRUE;
+}
+
+DNA *wormGetNamelessClusterDna(char *name)
+/* Get DNA associated with nameless cluster */
+{
+char *chrom;
+int start, end;
+char strand;
+if (!wormGeneRange(name, &chrom, &strand, &start, &end))
+    errAbort("Can't find %s in database", name);
+return wormChromPart(chrom, start, end-start);
+}
+
+struct wormGdfCache wormSangerGdfCache = {&sangerDir,NULL,NULL};
+struct wormGdfCache wormGenieGdfCache = {&genieDir,NULL,NULL};
+struct wormGdfCache *defaultGdfCache = &wormSangerGdfCache;
+
+
+static void wormCacheSomeGdf(struct wormGdfCache *cache)
+/* Cache one gene prediction set. */
+{
+if (cache->snof == NULL)
+    {
+    char fileName[512];
+    char *dir;
+    bits32 sig;
+    getDirs();
+    dir = *(cache->pDir);
+    sprintf(fileName, "%sgenes", dir);
+    cache->snof = snofMustOpen(fileName);
+    sprintf(fileName, "%sgenes.gdf", dir);
+    cache->file = mustOpen(fileName, "rb");
+    mustReadOne(cache->file, sig);
+    if (sig != glSig)
+        errAbort("%s is not a good file", fileName);
+    }
+}
+
+#if 0 /* unused */
+static void wormCacheGdf()
+/* Set up for fast access to GDF file entries. */
+{
+wormCacheSomeGdf(defaultGdfCache);
+}
+#endif
+
+void wormUncacheSomeGdf(struct wormGdfCache *cache)
+/* Uncache some gene prediction set. */
+{
+snofClose(&cache->snof);
+carefulClose(&cache->file);
+}
+
+void wormUncacheGdf()
+/* Free up resources associated with fast GDF access. */
+{
+wormUncacheSomeGdf(defaultGdfCache);
+}
+
+struct gdfGene *wormGetSomeGdfGene(char *name, struct wormGdfCache *cache)
+/* Get a single gdfGene of given name. */
+{
+long offset;
+
+wormCacheSomeGdf(cache);
+if (!snofFindOffset(cache->snof, name, &offset) )
+    return NULL;
+fseek(cache->file, offset, SEEK_SET);
+return gdfReadOneGene(cache->file);
+}
+
+struct gdfGene *wormGetGdfGene(char *name)
+/* Get a single gdfGene of given name. */
+{
+return wormGetSomeGdfGene(name, defaultGdfCache);
+}
+
+struct gdfGene *wormGetSomeGdfGeneList(char *baseName, int baseNameSize, struct wormGdfCache *cache)
+/* Get all gdfGenes that start with a given name. */
+{
+int snIx;
+int maxIx;
+struct snof *snof;
+FILE *f;
+struct gdfGene *list = NULL, *el;
+
+wormCacheSomeGdf(cache);
+snof = cache->snof;
+f = cache->file;
+if (!snofFindFirstStartingWith(snof, baseName, baseNameSize, &snIx))
+    return NULL;
+
+maxIx = snofElementCount(snof);
+for (;snIx < maxIx; ++snIx)
+    {
+    long offset;
+    char *geneName;
+
+    snofNameOffsetAtIx(snof, snIx, &geneName, &offset);
+    if (strncmp(geneName, baseName, baseNameSize) != 0)
+        break;
+    fseek(f, offset, SEEK_SET);
+    el = gdfReadOneGene(f);
+    slAddTail(&list, el);
+    }
+slReverse(&list);
+return list;
+}
+
+struct gdfGene *wormGetGdfGeneList(char *baseName, int baseNameSize)
+/* Get all gdfGenes that start with a given name. */
+{
+return wormGetSomeGdfGeneList(baseName, baseNameSize, defaultGdfCache);
+}
+
+struct gdfGene *wormGdfGenesInRange(char *chrom, int start, int end, 
+    struct wormGdfCache *geneFinder)
+/* Get list of genes in range according to given gene finder. */
+{
+char *dir = NULL;
+struct gdfGene *gdfList = NULL, *gdf;
+struct wormFeature *nameList, *name;
+
+if (geneFinder == &wormSangerGdfCache)
+    dir = wormSangerDir();
+else if (geneFinder == &wormGenieGdfCache)
+    dir = wormGenieDir();
+else
+    errAbort("Unknown geneFinder line %d of %s", __LINE__, __FILE__);
+
+nameList = wormSomeGenesInRange(chrom, start, end, dir);
+for (name = nameList; name != NULL; name = name->next)
+    {
+    char *n = name->name;
+    if (!wormIsNamelessCluster(n))
+        {
+        gdf = wormGetSomeGdfGene(n, geneFinder);
+        slAddHead(&gdfList, gdf);
+        }
+    }
+slFreeList(&nameList);
+slReverse(&gdfList);
+return gdfList;
+}
+
+
diff --git a/lib/x86_64/placeHolder.c b/lib/x86_64/placeHolder.c
new file mode 100755
index 0000000..e69de29
diff --git a/lib/xAli.as b/lib/xAli.as
new file mode 100644
index 0000000..c737f7b
--- /dev/null
+++ b/lib/xAli.as
@@ -0,0 +1,27 @@
+table xAli
+"An alignment - like psl but includes the sequence itself"
+    (
+    uint match;  "Number of bases that match that aren't repeats"
+    uint misMatch; "Number of bases that don't match"
+    uint repMatch; "Number of bases that match but are part of repeats"
+    uint nCount;  "Number of 'N' bases"
+    uint qNumInsert; "Number of inserts in query"
+    int qBaseInsert; "Number of bases inserted in query"
+    uint tNumInsert; "Number of inserts in target"
+    int tBaseInsert; "Number of bases inserted in target"
+    char[2] strand; "+ or - for strand. First character query, second target (optional)"
+    string qName; "Query sequence name"
+    uint qSize; "Query sequence size"
+    uint qStart; "Alignment start position in query"
+    uint qEnd; "Alignment end position in query"
+    string tName; "Target sequence name"
+    uint tSize; "Target sequence size"
+    uint tStart; "Alignment start position in target"
+    uint tEnd; "Alignment end position in target"
+    uint blockCount; "Number of blocks in alignment"
+    uint[blockCount] blockSizes; "Size of each block"
+    uint[blockCount] qStarts; "Start of each block in query."
+    uint[blockCount] tStarts; "Start of each block in target."
+    lstring[blockCount] qSeq; "Query sequence for each block."
+    lstring[blockCount] tSeq; "Target sequence for each block."
+    )
diff --git a/lib/xAli.c b/lib/xAli.c
new file mode 100644
index 0000000..1ec181d
--- /dev/null
+++ b/lib/xAli.c
@@ -0,0 +1,280 @@
+/* xAli.c was originally generated by the autoSql program, which also 
+ * generated xAli.h and xAli.sql.  This module links the database and
+ * the RAM representation of objects. */
+
+#include "common.h"
+#include "linefile.h"
+#include "dystring.h"
+#include "sqlNum.h"
+#include "sqlList.h"
+#include "xAli.h"
+
+
+struct xAli *xAliLoad(char **row)
+/* Load a xAli from row fetched with select * from xAli
+ * from database.  Dispose of this with xAliFree(). */
+{
+struct xAli *ret;
+int sizeOne;
+
+AllocVar(ret);
+ret->blockCount = sqlUnsigned(row[17]);
+ret->match = sqlUnsigned(row[0]);
+ret->misMatch = sqlUnsigned(row[1]);
+ret->repMatch = sqlUnsigned(row[2]);
+ret->nCount = sqlUnsigned(row[3]);
+ret->qNumInsert = sqlUnsigned(row[4]);
+ret->qBaseInsert = sqlSigned(row[5]);
+ret->tNumInsert = sqlUnsigned(row[6]);
+ret->tBaseInsert = sqlSigned(row[7]);
+strcpy(ret->strand, row[8]);
+ret->qName = cloneString(row[9]);
+ret->qSize = sqlUnsigned(row[10]);
+ret->qStart = sqlUnsigned(row[11]);
+ret->qEnd = sqlUnsigned(row[12]);
+ret->tName = cloneString(row[13]);
+ret->tSize = sqlUnsigned(row[14]);
+ret->tStart = sqlUnsigned(row[15]);
+ret->tEnd = sqlUnsigned(row[16]);
+sqlUnsignedDynamicArray(row[18], &ret->blockSizes, &sizeOne);
+assert(sizeOne == ret->blockCount);
+sqlUnsignedDynamicArray(row[19], &ret->qStarts, &sizeOne);
+assert(sizeOne == ret->blockCount);
+sqlUnsignedDynamicArray(row[20], &ret->tStarts, &sizeOne);
+assert(sizeOne == ret->blockCount);
+sqlStringDynamicArray(row[21], &ret->qSeq, &sizeOne);
+assert(sizeOne == ret->blockCount);
+sqlStringDynamicArray(row[22], &ret->tSeq, &sizeOne);
+assert(sizeOne == ret->blockCount);
+return ret;
+}
+
+struct xAli *xAliLoadAll(char *fileName) 
+/* Load all xAli from a tab-separated file.
+ * Dispose of this with xAliFreeList(). */
+{
+struct xAli *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[23];
+
+while (lineFileRow(lf, row))
+    {
+    el = xAliLoad(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct xAli *xAliCommaIn(char **pS, struct xAli *ret)
+/* Create a xAli out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new xAli */
+{
+char *s = *pS;
+int i;
+
+if (ret == NULL)
+    AllocVar(ret);
+ret->match = sqlUnsignedComma(&s);
+ret->misMatch = sqlUnsignedComma(&s);
+ret->repMatch = sqlUnsignedComma(&s);
+ret->nCount = sqlUnsignedComma(&s);
+ret->qNumInsert = sqlUnsignedComma(&s);
+ret->qBaseInsert = sqlSignedComma(&s);
+ret->tNumInsert = sqlUnsignedComma(&s);
+ret->tBaseInsert = sqlSignedComma(&s);
+sqlFixedStringComma(&s, ret->strand, sizeof(ret->strand));
+ret->qName = sqlStringComma(&s);
+ret->qSize = sqlUnsignedComma(&s);
+ret->qStart = sqlUnsignedComma(&s);
+ret->qEnd = sqlUnsignedComma(&s);
+ret->tName = sqlStringComma(&s);
+ret->tSize = sqlUnsignedComma(&s);
+ret->tStart = sqlUnsignedComma(&s);
+ret->tEnd = sqlUnsignedComma(&s);
+ret->blockCount = sqlUnsignedComma(&s);
+s = sqlEatChar(s, '{');
+AllocArray(ret->blockSizes, ret->blockCount);
+for (i=0; i<ret->blockCount; ++i)
+    {
+    ret->blockSizes[i] = sqlUnsignedComma(&s);
+    }
+s = sqlEatChar(s, '}');
+s = sqlEatChar(s, ',');
+s = sqlEatChar(s, '{');
+AllocArray(ret->qStarts, ret->blockCount);
+for (i=0; i<ret->blockCount; ++i)
+    {
+    ret->qStarts[i] = sqlUnsignedComma(&s);
+    }
+s = sqlEatChar(s, '}');
+s = sqlEatChar(s, ',');
+s = sqlEatChar(s, '{');
+AllocArray(ret->tStarts, ret->blockCount);
+for (i=0; i<ret->blockCount; ++i)
+    {
+    ret->tStarts[i] = sqlUnsignedComma(&s);
+    }
+s = sqlEatChar(s, '}');
+s = sqlEatChar(s, ',');
+s = sqlEatChar(s, '{');
+AllocArray(ret->qSeq, ret->blockCount);
+for (i=0; i<ret->blockCount; ++i)
+    {
+    ret->qSeq[i] = sqlStringComma(&s);
+    }
+s = sqlEatChar(s, '}');
+s = sqlEatChar(s, ',');
+s = sqlEatChar(s, '{');
+AllocArray(ret->tSeq, ret->blockCount);
+for (i=0; i<ret->blockCount; ++i)
+    {
+    ret->tSeq[i] = sqlStringComma(&s);
+    }
+s = sqlEatChar(s, '}');
+s = sqlEatChar(s, ',');
+*pS = s;
+return ret;
+}
+
+void xAliFree(struct xAli **pEl)
+/* Free a single dynamically allocated xAli such as created
+ * with xAliLoad(). */
+{
+struct xAli *el;
+
+if ((el = *pEl) == NULL) return;
+freeMem(el->qName);
+freeMem(el->tName);
+freeMem(el->blockSizes);
+freeMem(el->qStarts);
+freeMem(el->tStarts);
+/* All strings in qSeq are allocated at once, so only need to free first. */
+if (el->qSeq != NULL)
+    freeMem(el->qSeq[0]);
+freeMem(el->qSeq);
+/* All strings in tSeq are allocated at once, so only need to free first. */
+if (el->tSeq != NULL)
+    freeMem(el->tSeq[0]);
+freeMem(el->tSeq);
+freez(pEl);
+}
+
+void xAliFreeList(struct xAli **pList)
+/* Free a list of dynamically allocated xAli's */
+{
+struct xAli *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    xAliFree(&el);
+    }
+*pList = NULL;
+}
+
+void xAliOutput(struct xAli *el, FILE *f, char sep, char lastSep) 
+/* Print out xAli.  Separate fields with sep. Follow last field with lastSep. */
+{
+int i;
+fprintf(f, "%u", el->match);
+fputc(sep,f);
+fprintf(f, "%u", el->misMatch);
+fputc(sep,f);
+fprintf(f, "%u", el->repMatch);
+fputc(sep,f);
+fprintf(f, "%u", el->nCount);
+fputc(sep,f);
+fprintf(f, "%u", el->qNumInsert);
+fputc(sep,f);
+fprintf(f, "%d", el->qBaseInsert);
+fputc(sep,f);
+fprintf(f, "%u", el->tNumInsert);
+fputc(sep,f);
+fprintf(f, "%d", el->tBaseInsert);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->strand);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->qName);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%u", el->qSize);
+fputc(sep,f);
+fprintf(f, "%u", el->qStart);
+fputc(sep,f);
+fprintf(f, "%u", el->qEnd);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->tName);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+fprintf(f, "%u", el->tSize);
+fputc(sep,f);
+fprintf(f, "%u", el->tStart);
+fputc(sep,f);
+fprintf(f, "%u", el->tEnd);
+fputc(sep,f);
+fprintf(f, "%u", el->blockCount);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->blockCount; ++i)
+    {
+    fprintf(f, "%u", el->blockSizes[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->blockCount; ++i)
+    {
+    fprintf(f, "%u", el->qStarts[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->blockCount; ++i)
+    {
+    fprintf(f, "%u", el->tStarts[i]);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->blockCount; ++i)
+    {
+    if (sep == ',') fputc('"',f);
+    fprintf(f, "%s", el->qSeq[i]);
+    if (sep == ',') fputc('"',f);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+fputc(sep,f);
+if (sep == ',') fputc('{',f);
+for (i=0; i<el->blockCount; ++i)
+    {
+    if (sep == ',') fputc('"',f);
+    fprintf(f, "%s", el->tSeq[i]);
+    if (sep == ',') fputc('"',f);
+    fputc(',', f);
+    }
+if (sep == ',') fputc('}',f);
+fputc(lastSep,f);
+}
+
+/* --------------------Start of human generated code. -------------------- */
+
+struct xAli *xAliNext(struct lineFile *lf)
+/* Read next line from file and convert it to xAli.  Return
+ * NULL at eof. */
+{
+char *row[23];
+if (!lineFileRow(lf, row))
+    return NULL;
+return xAliLoad(row);
+}
diff --git a/lib/xAli.sql b/lib/xAli.sql
new file mode 100644
index 0000000..a0a54f5
--- /dev/null
+++ b/lib/xAli.sql
@@ -0,0 +1,33 @@
+# xAli.sql was originally generated by the autoSql program, which also 
+# generated xAli.c and xAli.h.  This creates the database representation of
+# an object which can be loaded and saved from RAM in a fairly 
+# automatic way.
+
+#An alignment - like psl but includes the sequence itself
+CREATE TABLE xAli (
+    match int unsigned not null,	# Number of bases that match that aren't repeats
+    misMatch int unsigned not null,	# Number of bases that don't match
+    repMatch int unsigned not null,	# Number of bases that match but are part of repeats
+    nCount int unsigned not null,	# Number of 'N' bases
+    qNumInsert int unsigned not null,	# Number of inserts in query
+    qBaseInsert int not null,	# Number of bases inserted in query
+    tNumInsert int unsigned not null,	# Number of inserts in target
+    tBaseInsert int not null,	# Number of bases inserted in target
+    strand char(2) not null,	# + or - for strand. First character query, second target (optional)
+    qName varchar(255) not null,	# Query sequence name
+    qSize int unsigned not null,	# Query sequence size
+    qStart int unsigned not null,	# Alignment start position in query
+    qEnd int unsigned not null,	# Alignment end position in query
+    tName varchar(255) not null,	# Target sequence name
+    tSize int unsigned not null,	# Target sequence size
+    tStart int unsigned not null,	# Alignment start position in target
+    tEnd int unsigned not null,	# Alignment end position in target
+    blockCount int unsigned not null,	# Number of blocks in alignment
+    blockSizes longblob not null,	# Size of each block
+    qStarts longblob not null,	# Start of each block in query.
+    tStarts longblob not null,	# Start of each block in target.
+    qSeq longblob not null,	# Query sequence for each block.
+    tSeq longblob not null,	# Target sequence for each block.
+              #Indices
+    PRIMARY KEY(match)
+);
diff --git a/lib/xa.c b/lib/xa.c
new file mode 100644
index 0000000..eb78982
--- /dev/null
+++ b/lib/xa.c
@@ -0,0 +1,229 @@
+/* xao.c - Manage cross-species alignments in Intronerator database. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+#include "common.h"
+#include "sig.h"
+#include "xa.h"
+
+
+void xaAliFree(struct xaAli *xa)
+/* Free up a single xaAli. */
+{
+freeMem(xa->name);
+freeMem(xa->query);
+freeMem(xa->target);
+freeMem(xa->qSym);
+freeMem(xa->tSym);
+freeMem(xa->hSym);
+freeMem(xa);
+}
+
+void xaAliFreeList(struct xaAli **pXa)
+/* Free up a list of xaAlis. */
+{
+struct xaAli *xa, *next;
+for (xa = *pXa; xa != NULL; xa = next)
+    {
+    next = xa->next;
+    xaAliFree(xa);
+    }
+*pXa = NULL;
+}
+
+int xaAliCmpTarget(const void *va, const void *vb)
+/* Compare two xaAli's to sort by ascending target positions. */
+{
+const struct xaAli *a = *((struct xaAli **)va);
+const struct xaAli *b = *((struct xaAli **)vb);
+int diff;
+if ((diff = strcmp(a->target, b->target)) == 0)
+    diff = a->tStart - b->tStart;
+return diff;
+}
+
+
+FILE *xaOpenVerify(char *fileName)
+/* Open file, verify it's the right type, and
+ * position file pointer for first xaReadNext(). */
+{
+FILE *f = mustOpen(fileName, "rb");
+return f;
+}
+
+FILE *xaIxOpenVerify(char *fileName)
+/* Open file, verify that it's a good xa index. */
+{
+FILE *f;
+bits32 sig;
+f = mustOpen(fileName, "rb");
+mustReadOne(f, sig);
+if (sig != xaoSig)
+    errAbort("Bad signature on %s", fileName);
+return f;
+}
+
+static void eatLf(FILE *f)
+/* Read next char and make sure it's a lf. */
+{
+int c;
+c = fgetc(f);
+if (c == '\r')
+    c = fgetc(f);
+if (c != '\n')
+    errAbort("Expecting new line in cross-species alignment file.");
+}
+
+static void eatThroughLf(FILE *f)
+/* Read through next lf (discarding results). */
+{
+int c;
+while ((c = fgetc(f)) != EOF)
+    if (c == '\n')
+        break;
+}
+
+/* An example line from .st file. 
+   G11A11.SEQ.c1 align 53.9% of 6096 ACTIN2~1\G11A11.SEQ:0-4999 - v:9730780-9736763 +
+         0         1     2    3   4             5               6        7          8
+ */
+
+struct xaAli *xaReadNext(FILE *f, boolean condensed)
+/* Read next xaAli from file. If condensed
+ * don't fill int query, target, qSym, tSym, or hSym. */
+{
+char line[512];
+char *words[16];
+int wordCount;
+struct xaAli *xa;
+char *parts[5];
+int partCount;
+double percentScore;
+int symCount;
+int newOffset = 0;
+char *s, *e;
+
+/* Get first line and parse out everything but the sym lines. */
+if (fgets(line, sizeof(line), f) == NULL)
+    return NULL;
+wordCount = chopLine(line, words);
+if (wordCount < 9)
+    errAbort("Short line in cross-species alignment file");
+if (wordCount == 10)
+    newOffset = 1;
+if (!sameString(words[1], "align"))
+    errAbort("Bad line in cross-species alignment file");
+AllocVar(xa);
+xa->name = cloneString(words[0]);
+s = words[5+newOffset];
+e = strrchr(s, ':');
+if (e == NULL)
+    errAbort("Bad line (no colon) in cross-species alignment file");
+*e++ = 0;
+partCount = chopString(e, "-", parts, ArraySize(parts));
+if (partCount != 2)
+    errAbort("Bad range format in cross-species alignment file");
+if (!condensed)
+    xa->query = cloneString(s);
+xa->qStart = atoi(parts[0]);
+xa->qEnd = atoi(parts[1]);
+xa->qStrand = words[6+newOffset][0];
+partCount = chopString(words[7+newOffset], ":-", parts, ArraySize(parts));
+if (!condensed)
+    xa->target = cloneString(parts[0]);
+xa->tStart = atoi(parts[1]);
+xa->tEnd = atoi(parts[2]);
+xa->tStrand = words[8+newOffset][0];
+percentScore = atof(words[2]);
+xa->milliScore = round(percentScore*10);    
+xa->symCount = symCount = atoi(words[4]);
+
+/* Get symbol lines. */
+if (condensed)
+    {
+    eatThroughLf(f);
+    eatThroughLf(f);
+    eatThroughLf(f);
+    }
+else
+    {
+    xa->qSym = needMem(symCount+1);
+    mustRead(f, xa->qSym, symCount);
+    eatLf(f);
+
+    xa->tSym = needMem(symCount+1);
+    mustRead(f, xa->tSym, symCount);
+    eatLf(f);
+
+    xa->hSym = needMem(symCount+1);
+    mustRead(f, xa->hSym, symCount);
+    eatLf(f);
+    }
+return xa;
+}
+
+struct xaAli *xaRdRange(FILE *ix, FILE *data, 
+    int start, int end, boolean condensed)
+/* Return list of all xaAlis that range from start to end.  
+ * Assumes that ix and data files are open. If condensed
+ * don't fill int query, target, qSym, tSym, or hSym. */
+{
+int s, e;
+int maxS, minE;
+long offset;
+struct xaAli *list = NULL, *xa;
+
+
+/* Scan through index file looking for things in range.
+ * When find one read it from data file and add it to list. */
+fseek(ix, sizeof(bits32), SEEK_SET);
+for (;;)
+    {
+    if (!readOne(ix, s))
+        break;
+    mustReadOne(ix, e);
+    mustReadOne(ix, offset);
+    if (s >= end)
+        break;
+    maxS = max(s, start);
+    minE = min(e, end);
+    if (minE - maxS > 0)
+        {
+        fseek(data, offset, SEEK_SET);
+        xa = xaReadNext(data, condensed);
+        slAddHead(&list, xa);
+        }
+    }
+
+slReverse(&list);
+return list;
+}
+
+struct xaAli *xaReadRange(char *rangeIndexFileName, char *dataFileName, 
+    int start, int end, boolean condensed)
+/* Return list of all xaAlis that range from start to end.  If condensed
+ * don't fill int query, target, qSym, tSym, or hSym. */
+{
+FILE *ix = xaIxOpenVerify(rangeIndexFileName);
+FILE *data = xaOpenVerify(dataFileName);
+struct xaAli *xa = xaRdRange(ix, data, start, end, condensed);
+fclose(data);
+fclose(ix);
+return xa;
+}
+
+
+char *xaAlignSuffix()
+/* Return suffix of file with actual alignments. */
+{
+return ".st";
+}
+
+char *xaChromIxSuffix()
+/* Return suffix of files that index xa's by chromosome position. */
+{
+return ".xao";
+}
+
+
+
diff --git a/lib/xap.c b/lib/xap.c
new file mode 100644
index 0000000..1da6d0c
--- /dev/null
+++ b/lib/xap.c
@@ -0,0 +1,182 @@
+/* xap - XML Automatic Parser - together with autoXml this helps automatically
+ * read in automatically generated data structures.  Calls lower level routine
+ * in xp module, which originally was just a thin shell around expat. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "xap.h"
+#include "errabort.h"
+#include "xp.h"
+
+
+void xapError(struct xap *xap, char *format, ...)
+/* Issue an error message and abort*/
+{
+va_list args;
+va_start(args, format);
+vaWarn(format, args);
+errAbort("line %d of %s", xpLineIx(xap->xp), xap->fileName);
+va_end(args);
+}
+
+static void xapStartTag(void *userData, char *name, char **atts)
+/* Handle beginning of a tag. */
+{
+struct xap *xap = userData;
+struct xapStack *stack;
+
+stack = --xap->stack;
+if (stack < xap->stackBuf)
+    xapError(xap, "xap stack overflow");
+++xap->stackDepth;
+if (stack->text == NULL)
+    stack->text = newDyString(256);
+stack->elName = (char*)name;
+if (xap->skipDepth == 0)
+    stack->object = xap->startHandler(xap, (char*)name, (char**)atts);
+if (xap->stackDepth == 1)
+    {
+    freeMem(xap->topType);
+    xap->topType = cloneString(stack->elName);
+    xap->topObject = stack->object;
+    }
+}
+
+static void xapEndTag(void *userData, char *name, char *text)
+/* Handle end of tag. */
+{
+struct xap *xap = userData;
+struct xapStack *stack;
+
+dyStringAppend(xap->stack->text, text);
+if (xap->skipDepth == 0 || xap->skipDepth <= xap->stackDepth)
+    {
+    xap->skipDepth = 0;
+    if (xap->endHandler)
+	xap->endHandler(xap, (char*)name);
+    }
+stack = xap->stack++;
+if (xap->stack > xap->endStack)
+    xapError(xap, "xap stack underflow");
+--xap->stackDepth;
+dyStringClear(stack->text);
+}
+
+#ifdef EXPAT
+static void xapText(void *userData, char *s, int len)
+/* Handle some text. */
+{
+struct xap *xap = userData;
+if (xap->skipDepth == 0)
+    dyStringAppendN(xap->stack->text, (char *)s, len);
+}
+#endif /* EXPAT */
+
+static int xapRead(void *userData, char *buf, int bufSize)
+/* Read some text. */
+{
+struct xap *xap = userData;
+return fread(buf, 1, bufSize, xap->f);
+}
+
+struct xap *xapNew(void *(*startHandler)(struct xap *xap, char *name, char **atts),
+	void (*endHandler)(struct xap *xap, char *name) , char *fileName)
+/* Create a new parse stack. */
+{
+struct xap *xap;
+AllocVar(xap);
+xap->endStack = xap->stack = xap->stackBuf + ArraySize(xap->stackBuf) - 1;
+xap->startHandler = startHandler;
+xap->endHandler = endHandler;
+xap->xp = xpNew(xap, xapStartTag, xapEndTag, xapRead, fileName);
+xap->fileName = cloneString(fileName);
+return xap;
+}
+
+void xapFree(struct xap **pXp)
+/* Free up a parse stack. */
+{
+struct xap *xap = *pXp;
+if (xap != NULL)
+    {
+    struct xapStack *stack;
+    for (stack = xap->stackBuf; stack < xap->endStack; ++stack)
+        {
+	if (stack->text != NULL)
+	   freeDyString(&stack->text);
+	}
+    xpFree(&xap->xp);
+    freeMem(xap->fileName);
+    freeMem(xap->topType);
+    freez(pXp);
+    }
+}
+
+void xapParseFile(struct xap *xap, char *fileName)
+/* Open up file and parse it all. */
+{
+xap->f = mustOpen(fileName, "r");
+xpParse(xap->xp);
+carefulClose(&xap->f);
+}
+
+void xapIndent(int count, FILE *f)
+/* Write out some spaces. */
+{
+int i;
+for (i=0; i<count; ++i)
+    {
+    fputc(' ', f);
+    }
+}
+
+void xapSkip(struct xap *xap)
+/* Skip current tag and any children.  Called from startHandler. */
+{
+xap->skipDepth = xap->stackDepth;
+}
+
+void xapParseAny(char *fileName, char *type, 
+	void *(*startHandler)(struct xap *xap, char *name, char **atts),
+	void (*endHandler)(struct xap *xap, char *name),
+	char **retType, void *retObj)
+/* Parse any object out of an XML file. 
+ * If type parameter is non-NULL, force type.
+ * example:
+ *     xapParseAny("file.xml", "das", dasStartHandler, dasEndHandler, &type, &obj); */
+{
+struct xap *xap = xapNew(startHandler, endHandler, fileName);
+void **pObj = retObj;
+xapParseFile(xap, fileName);
+if (type != NULL && !sameString(xap->topType, type))
+    xapError(xap, "Got %s, expected %s\n", xap->topType, type);
+if (retType != NULL)
+    *retType = cloneString(xap->topType);
+*pObj = xap->topObject;
+xapFree(&xap);
+}
+
+struct xap *xapOpen(char *fileName, 
+	void *(*startHandler)(struct xap *xap, char *name, char **atts),
+	void (*endHandler)(struct xap *xap, char *name))
+/* Open up an xml file, but don't start parsing it yet.
+ * Instead call xapNext to get the elements you want out of
+ * the file.  When all done call xapFree. */
+{
+struct xap *xap = xapNew(startHandler, endHandler, fileName);
+xap->f =  mustOpen(fileName, "r");
+return xap;
+}
+
+void *xapNext(struct xap *xap, char *tag)
+/* Return next item matching tag (and all of it's children). */
+{
+if (!xpParseNext(xap->xp, tag))
+    return NULL;
+if (!sameString(xap->topType, tag))
+    errAbort("Expecting %s tag, got %s tag", tag, xap->topType);
+return xap->topObject;
+}
+
diff --git a/lib/xenshow.c b/lib/xenshow.c
new file mode 100644
index 0000000..8b1bc08
--- /dev/null
+++ b/lib/xenshow.c
@@ -0,0 +1,64 @@
+/* xenshow - show a cross-species alignment. 
+ *
+ * This file is copyright 2002 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+#include "common.h"
+#include "nt4.h"
+#include "xenalign.h"
+
+
+static void printMatchers(char *a, char *b, int lineSize, FILE *f)
+/* Print '|' where a[i] and b[i] match, ' ' where they don't */
+{
+int i;
+for (i=0; i<lineSize; ++i)
+   {
+   char c = ((a[i] == b[i]) ? '|' : ' ');
+   fputc(c, f);
+   }
+}
+
+static int nonDashCount(char *s, int size)
+/* Return number of characters in s[0] to s[size-1] that
+ * aren't dashes. */
+{
+int count = 0;
+int i;
+for (i=0; i<size; ++i)
+    if (s[i] != '-')
+        ++count;
+return count;
+}
+
+void xenShowAli(char *qSym, char *tSym, char *hSym, int symCount, FILE *f,
+   int qOffset, int tOffset, char qStrand, char tStrand, int maxLineSize)
+/* Print alignment and HMM symbols maxLineSize bases at a time to file. */
+{
+int i;
+int lineSize;
+int count;
+
+for (i=0; i<symCount; i += lineSize)
+    {
+    lineSize = symCount - i;
+    if (lineSize > maxLineSize) lineSize = maxLineSize;
+    mustWrite(f, qSym+i, lineSize);
+    count = nonDashCount(qSym+i, lineSize);
+    if (qStrand == '-')
+        count = -count;
+    qOffset += count;
+    fprintf(f, " %9d\n", qOffset);
+    printMatchers(qSym+i, tSym+i, lineSize, f);
+    fputc('\n', f);
+    mustWrite(f, tSym+i, lineSize);
+    count = nonDashCount(tSym+i, lineSize);
+    if (tStrand == '-')
+        count = -count;
+    tOffset += count;
+    fprintf(f, " %9d\n", tOffset);
+    mustWrite(f, hSym+i, lineSize);
+    fputc('\n', f);
+    fputc('\n', f);
+    }
+}
+
diff --git a/lib/xmlEscape.c b/lib/xmlEscape.c
new file mode 100644
index 0000000..ba077f1
--- /dev/null
+++ b/lib/xmlEscape.c
@@ -0,0 +1,79 @@
+/* Handle escaping for XML files.  Deal with things like
+ * & and &quot. */
+
+#include "common.h"
+#include "hash.h"
+#include "xmlEscape.h"
+
+
+struct hash *xmlEscapeSymHash()
+/* Return hash of predefined xml character symbols to lookup. */
+{
+struct hash *symHash = newHash(6);
+hashAdd(symHash, "lt", "<");
+hashAdd(symHash, "gt", ">");
+hashAdd(symHash, "amp", "&");
+hashAdd(symHash, "apos", "'");
+hashAdd(symHash, "quot", "\"");
+return symHash;
+}
+
+void xmlEscapeBytesToFile(unsigned char *buffer, int len, FILE *f)
+/* Write buffer of given length to file, escaping as need be. */
+{
+unsigned char c;
+int i;
+for (i=0; i<len; ++i)
+    {
+    c = buffer[i];
+    if (isalnum(c))
+        fputc(c, f);
+    else
+        {
+	switch (c)
+	    {
+	    case '&':
+	        fputs("&", f);
+		break;
+	    case '\'':
+	        fputs("'", f);
+		break;
+	    case '"':
+	        fputs(""", f);
+		break;
+	    case '<':
+	        fputs("<", f);
+		break;
+	    case '>':
+	        fputs(">", f);
+		break;
+	    case ' ':
+	    case '-':
+	    case '\t':
+	    case '\n':
+	    case ',':
+	    case '.':
+	    case ';':
+	    case ':':
+	    case '(':
+	    case ')':
+	    case '[':
+	    case ']':
+	    case '#':
+	    case '/':
+	        fputc(c, f);
+		break;
+	    default:
+	        fprintf(f, "&#%d;", c);
+		break;
+	    }
+	}
+    }
+}
+
+void xmlEscapeStringToFile(char *s, FILE *f)
+/* Write escaped zero-terminated string to file. */
+{
+int len = strlen(s);
+xmlEscapeBytesToFile((unsigned char *)s, len, f);
+}
diff --git a/lib/xp.c b/lib/xp.c
new file mode 100644
index 0000000..50803cb
--- /dev/null
+++ b/lib/xp.c
@@ -0,0 +1,553 @@
+/* xp - A minimal non-verifying xml parser.  It's
+ * stream oriented much like expas.  It's a bit faster
+ * and smaller than expas.  I'm not sure it handles unicode
+ * as well.
+ *
+ * This file is copyright 2002-2005 Jim Kent, but license is hereby
+ * granted for all use - public, private or commercial. */
+
+#include "common.h"
+#include "dystring.h"
+#include "errabort.h"
+#include "hash.h"
+#include "xp.h"
+#include "xmlEscape.h"
+
+
+
+char xpNextBuf(struct xp *xp)
+/* Fetch a new buffer and return first char.  Return 0 at EOF. */
+{
+int size = xp->read(xp->userData, xp->inBuf, sizeof(xp->inBuf));
+if (size <= 0)
+    return 0;
+xp->inBufEnd = xp->inBuf + size;
+xp->in = xp->inBuf+1;
+return xp->inBuf[0];
+}
+
+#define xpGetChar(xp) \
+    (xp->in < xp->inBufEnd ? *xp->in++ : xpNextBuf(xp))
+/* Macro to quickly fetch next char. */
+
+#define xpUngetChar(xp) \
+    (--xp->in)
+/* Oops, don't fetch that after all. */
+
+struct xp *xpNew(void *userData, 
+   void (*atStartTag)(void *userData, char *name, char **atts),
+   void (*atEndTag)(void *userData, char *name, char *text),
+   int (*read)(void *userData, char *buf, int bufSize),
+   char *fileName)
+/* Form a new xp parser.  File name may be NULL - just used for
+ * error reporting. */
+{
+struct xp *xp;
+AllocVar(xp);
+xp->stack = xp->stackBufEnd = xp->stackBuf + ArraySize(xp->stackBuf);
+xp->userData = userData;
+xp->atStartTag = atStartTag;
+xp->atEndTag = atEndTag;
+xp->read = read;
+xp->lineIx = 1;
+xp->endTag = newDyString(64);
+if (fileName)
+    xp->fileName = cloneString(fileName);
+else
+    xp->fileName = cloneString("XML");
+xp->inBufEnd = xp->in = xp->inBuf;		
+xp->symHash = xmlEscapeSymHash();
+return xp;
+}
+
+int xpReadFromFile(void *userData, char *buf, int bufSize)
+/* Read some text assuming a file was passed in as user data. */
+{
+FILE *f = userData;
+return fread(buf, 1, bufSize, f);
+}
+
+
+
+void xpFree(struct xp **pXp)
+/* Free up an xp parser. */
+{
+int i;
+struct xp *xp = *pXp;
+if (xp != NULL)
+    {
+    struct xpStack *stack;
+    for (stack = xp->stackBufEnd; --stack >= xp->stackBuf; )
+        {
+	if (stack->tag == NULL)
+	    break;
+	freeDyString(&stack->tag);
+	freeDyString(&stack->text);
+	}
+    for (i=0; i<ArraySize(xp->attDyBuf); ++i)
+        {
+	if (xp->attDyBuf[i] == NULL)
+	    break;
+	freeDyString(&xp->attDyBuf[i]);
+	}
+    freeDyString(&xp->endTag);
+    freeMem(xp->fileName);
+    hashFree(&xp->symHash);
+    freez(pXp);
+    }
+}
+
+int xpLineIx(struct xp *xp)
+/* Return current line number. */
+{
+return xp->lineIx;
+}
+
+char *xpFileName(struct xp *xp)
+/* Return current file name. */
+{
+return xp->fileName;
+}
+
+void xpError(struct xp *xp, char *format, ...)
+/* Output an error message with filename and line number included. */
+{
+va_list args;
+va_start(args, format);
+vaWarn(format, args);
+errAbort("line %d of %s", xpLineIx(xp), xpFileName(xp));
+va_end(args);
+}
+
+static void xpUnexpectedEof(struct xp *xp)
+/* Squawk and die about EOF. */
+{
+xpError(xp, "Unexpected end of file.");
+}
+
+static void xpEatComment(struct xp *xp, char commentC)
+/* Skip characters until comment end. */
+{
+int startLine = xp->lineIx;
+char lastC = 0;
+char c;
+for (;;)
+    {
+    if ((c = xpGetChar(xp)) == 0)
+        xpError(xp, "End of file in comment that started line %d", startLine);
+    if (c == '\n')
+        ++xp->lineIx;
+    if (c == '>')
+        {
+	if (lastC == commentC || commentC == '!')
+	break;
+	}
+    lastC = c;
+    }
+}
+
+static void xpLookup(struct xp *xp, struct dyString *temp, struct dyString *text)
+/* Parse after '&' until ';' and look up symbol.  Put result into text. */
+{
+char c;
+char *s;
+dyStringClear(temp);
+for (;;)
+    {
+    if ((c = xpGetChar(xp)) == 0)
+	xpError(xp, "End of file in after & and before ;");
+    if (isspace(c))
+        xpError(xp, "& without ;");
+    if (c == ';')
+        break;
+    dyStringAppendC(temp, c);
+    }
+s = temp->string;
+if (s[0] == '#')
+    {
+    c = atoi(s+1);
+    dyStringAppendC(text, c);
+    }
+else if ((s = hashFindVal(xp->symHash, s)) == NULL)
+    {
+    dyStringAppendC(text, '&');
+    dyStringAppend(text, temp->string);
+    dyStringAppendC(text, ';');
+    }
+else
+    {
+    dyStringAppend(text, s);
+    }
+}
+
+void xpForceMatch(struct xp *xp, char *matchString)
+/* Make sure that the next characters are match, and eat them. */
+{
+char *match = matchString, m;
+while ((m = *match++) != 0)
+    {
+    if (m != xpGetChar(xp))
+        xpError(xp, "Expecting %s", matchString);
+    }
+}
+
+void xpTextUntil(struct xp *xp, char *endPattern)
+/* Stuff xp->text with everything up to endPattern. */
+{
+int endSize = strlen(endPattern);
+int endPos = 0;
+char c;
+struct dyString *dy = xp->stack->text;
+for (;;)
+    {
+    if ((c = xpGetChar(xp)) == 0)
+	xpUnexpectedEof(xp);
+    if (c == endPattern[endPos])
+        {
+	endPos += 1;
+	if (endPos == endSize)
+	    return;
+	}
+    else
+        {
+	if (endPos > 0)
+	    dyStringAppendN(dy, endPattern, endPos);
+	dyStringAppendC(dy, c);
+	endPos = 0;
+	}
+    }
+}
+
+
+void xpParseStartTag(struct xp *xp, 
+	int maxAttCount,		  /* Maximum attribute count. */
+	struct dyString *retName, 	  /* Returns tag name */
+	int *retAttCount, 		  /* Returns attribute count. */
+	struct dyString **retAttributes,  /* Name, value, name, value... */
+	boolean *retClosed)	  /* If true then is self-closing (ends in />) */
+/* Call this after the first '<' in a tag has been read.  It'll
+ * parse out until the '>' tag. */
+{
+char c, quotC;
+int attCount = 0;
+struct dyString *dy;
+int lineStart;
+
+dyStringClear(retName);
+
+/* Skip white space after '<' and before tag name. */
+for (;;)
+    {
+    if ((c = xpGetChar(xp)) == 0)
+	xpUnexpectedEof(xp);
+    if (isspace(c))
+        {
+	if (c == '\n')
+	    ++xp->lineIx;
+        }
+    else
+        break;
+    }
+
+/* Read in tag name. */
+for (;;)
+    {
+    dyStringAppendC(retName, c);
+    if ((c = xpGetChar(xp)) == 0)
+	xpUnexpectedEof(xp);
+    if (c == '>' || c == '/' || isspace(c))
+        break;
+    }
+if (c == '\n')
+    ++xp->lineIx;
+
+/* Parse attributes. */
+if (c != '>' && c != '/')
+    {
+    for (;;)
+	{
+	/* Skip leading white space. */
+	for (;;)
+	    {
+	    if ((c = xpGetChar(xp)) == 0)
+		xpUnexpectedEof(xp);
+	    if (isspace(c))
+		{
+		if (c == '\n')
+		    ++xp->lineIx;
+		}
+	    else
+		break;
+	    }
+	if (c == '>' || c == '/')
+	    break;
+
+	/* Allocate space in attribute table. */
+	if (attCount >= maxAttCount - 2)
+	    xpError(xp, "Attribute stack overflow");
+	dy = retAttributes[attCount];
+	if (dy == NULL)
+	    dy = retAttributes[attCount] = newDyString(64);
+	else
+	    dyStringClear(dy);
+	++attCount;
+
+	/* Read until not a label character. */
+	for (;;)
+	    {
+	    dyStringAppendC(dy, c);
+	    if ((c = xpGetChar(xp)) == 0)
+		xpUnexpectedEof(xp);
+	    if (isspace(c))
+		{
+		if (c == '\n')
+		    ++xp->lineIx;
+		break;
+		}
+	    if (c == '=')
+		break;
+	    if (c == '/' || c == '>')
+		xpError(xp, "Expecting '=' after attribute name");
+	    }
+
+	/* Skip white space until '=' */
+	if (c != '=')
+	    {
+	    for (;;)
+		{
+		if ((c = xpGetChar(xp)) == 0)
+		    xpUnexpectedEof(xp);
+		if (isspace(c))
+		    {
+		    if (c == '\n')
+			++xp->lineIx;
+		    }
+		else
+		    break;
+		}
+	    if (c != '=')
+		xpError(xp, "Expecting '=' after attribute name");
+	    }
+
+	/* Skip space until quote. */
+	for (;;)
+	    {
+	    if ((c = xpGetChar(xp)) == 0)
+		xpUnexpectedEof(xp);
+	    else if (isspace(c))
+		{
+		if (c == '\n')
+		    ++xp->lineIx;
+		}
+	    else
+		break;
+	    }
+	if (c != '\'' && c != '"')
+	    xpError(xp, "Expecting quoted string after =");
+
+	/* Allocate space in attribute table. */
+	if (attCount >= maxAttCount - 2)
+	    xpError(xp, "Attribute stack overflow");
+	dy = retAttributes[attCount];
+	if (dy == NULL)
+	    dy = retAttributes[attCount] = newDyString(64);
+	else
+	    dyStringClear(dy);
+	++attCount;
+
+	/* Read until next quote. */
+	quotC = c;
+	lineStart = xp->lineIx;
+	for (;;)
+	    {
+	    if ((c = xpGetChar(xp)) == 0)
+	       xpError(xp, "End of file inside literal string that started at line %d", lineStart);
+	    if (c == quotC)
+		break;
+	    if (c == '&')
+	       xpLookup(xp, xp->endTag, dy);
+	    else
+		{
+		if (c == '\n')
+		    ++xp->lineIx;
+		dyStringAppendC(dy, c);
+		}
+	    }
+	}
+    }
+if (c == '/')
+    {
+    *retClosed = TRUE;
+    c = xpGetChar(xp);
+    if (c != '>')
+        xpError(xp, "Expecting '>' after '/'");
+    }
+else
+    *retClosed = FALSE;
+*retAttCount = attCount;
+}
+
+void xpParseEndTag(struct xp *xp, char *tagName)
+/* Call this after have seen </.  It will parse through
+ * > and make sure that the tagName matches. */
+{
+struct dyString *dy = xp->endTag;
+char c;
+
+dyStringClear(dy);
+
+/* Skip leading space. */
+for (;;)
+    {
+    if ((c = xpGetChar(xp)) == 0)
+	xpUnexpectedEof(xp);
+    if (isspace(c))
+	{
+	if (c == '\n')
+	    ++xp->lineIx;
+	}
+    else
+	break;
+    }
+
+/* Read end tag. */
+for (;;)
+    {
+    dyStringAppendC(dy, c);
+    if ((c = xpGetChar(xp)) == 0)
+	xpUnexpectedEof(xp);
+    if (isspace(c))
+	{
+	if (c == '\n')
+	    ++xp->lineIx;
+	break;
+	}
+    if (c == '>')
+	break;
+    }
+
+/* Skip until '>' */
+while (c != '>')
+    {
+    dyStringAppendC(dy, c);
+    if ((c = xpGetChar(xp)) == 0)
+	xpUnexpectedEof(xp);
+    if (isspace(c))
+	{
+	if (c == '\n')
+	    ++xp->lineIx;
+	}
+    else if (c != '>')
+	xpError(xp, "Unexpected characters past first word in /%s tag", dy->string);
+    }
+
+if (!sameString(dy->string, tagName))
+    xpError(xp, "Mismatch between start tag %s and end tag %s",  tagName, dy->string);
+}
+
+boolean xpParseNext(struct xp *xp, char *tag)
+/* Skip through file until get given tag.  Then parse out the
+ * tag and all of it's children (calling atStartTag/atEndTag).
+ * You can call this repeatedly to process all of a given tag
+ * in file. */
+
+{
+char c;
+int i, attCount = 0;
+struct dyString *text = NULL;
+boolean isClosed;
+boolean inside = (tag == NULL);
+struct xpStack *initialStack = xp->stack;
+
+for (;;)
+    {
+    /* Load up text until next tag. */
+    for (;;)
+        {
+	if ((c = xpGetChar(xp)) == 0)
+	    return FALSE;
+	if (c == '<')
+	    break;
+	if (c == '&')
+	   xpLookup(xp, xp->endTag, text);
+	else 
+	    {
+	    if (c == '\n')
+		++xp->lineIx;
+	    if (text != NULL)
+		dyStringAppendC(text, c);
+	    }
+	}
+
+    /* Get next character to figure out what type of tag. */
+    c = xpGetChar(xp);
+    if (c == 0)
+       xpError(xp, "End of file inside tag");
+    else if (c == '?' || c == '!')
+        xpEatComment(xp, c);
+    else if (c == '/')  /* Closing tag. */
+        {
+	struct xpStack *stack = xp->stack;
+	if (stack >= xp->stackBufEnd)
+	    xpError(xp, "Extra end tag");
+	xpParseEndTag(xp, stack->tag->string);
+	if (inside)
+	    xp->atEndTag(xp->userData, stack->tag->string, stack->text->string);
+	xp->stack += 1;
+	if (xp->stack == initialStack)
+	    return TRUE;
+	}
+    else	/* Start tag. */
+        {
+	/* Push new frame on stack and check for overflow and unallocated strings. */
+	struct xpStack *stack = --xp->stack;
+	if (stack < xp->stackBuf)
+	    xpError(xp, "Stack overflow");
+	if (stack->tag == NULL)
+	    stack->tag = newDyString(32);
+	else
+	    dyStringClear(stack->tag);
+	if (stack->text == NULL)
+	    stack->text = newDyString(256);
+	else
+	    dyStringClear(stack->text);
+	text = stack->text;
+
+	/* Parse the start tag. */
+	xpUngetChar(xp);
+	xpParseStartTag(xp, ArraySize(xp->attDyBuf), stack->tag, 
+		&attCount, xp->attDyBuf, &isClosed);
+
+	if (!inside && sameString(stack->tag->string, tag))
+	    {
+	    inside = TRUE;
+	    initialStack = xp->stack + 1;
+	    }
+
+	/* Call user start function, and if closed tag, end function too. */
+	if (inside)
+	    {
+	    /* Unpack attributes into simple array of strings. */
+	    for (i=0; i<attCount; ++i)
+		xp->attBuf[i] = xp->attDyBuf[i]->string;
+	    xp->attBuf[attCount] = NULL;
+	    xp->atStartTag(xp->userData, stack->tag->string, xp->attBuf);
+	    }
+	if (isClosed)
+	    {
+	    if (inside)
+		xp->atEndTag(xp->userData, stack->tag->string, stack->text->string);
+	    xp->stack += 1;
+	    if (xp->stack == initialStack)
+		return TRUE;
+	    }
+	}
+    }
+}
+
+void xpParse(struct xp *xp)
+/* Parse from start tag to end tag.  Throw error if a problem. */
+{
+xpParseNext(xp, NULL);
+}
+
diff --git a/lib/zlibFace.c b/lib/zlibFace.c
new file mode 100644
index 0000000..fb9642d
--- /dev/null
+++ b/lib/zlibFace.c
@@ -0,0 +1,91 @@
+/* Wrappers around zlib to make interfacing to it a bit easier. */
+
+#include "common.h"
+#include <zlib.h>
+
+static char *zlibErrorMessage(int err)
+/* Convert error code to errorMessage */
+{
+switch (err)
+    {
+    case Z_STREAM_END:
+        return "zlib stream end";
+    case Z_NEED_DICT:
+        return "zlib need dictionary";
+    case Z_ERRNO:
+        return "zlib errno";
+    case Z_STREAM_ERROR:
+        return "zlib data error";
+    case Z_DATA_ERROR:
+        return "zlib data error";
+    case Z_MEM_ERROR:
+        return "zlib mem error";
+    case Z_BUF_ERROR:
+        return "zlib buf error";
+    case Z_VERSION_ERROR:
+        return "zlib version error";
+    case Z_OK:
+        return NULL;
+    default:
+	{
+	static char msg[128];
+	safef(msg, sizeof(msg), "zlib error code %d", err);
+        return msg;
+	}
+    }
+}
+
+size_t zCompress(
+	void *uncompressed, 	/* Start of area to compress. */
+	size_t uncompressedSize,  /* Size of area to compress. */
+	void *compBuf,       /* Where to put compressed bits */
+	size_t compBufSize) /* Size of compressed bits - calculate using zCompBufSize */
+/* Compress data from memory to memory.  Returns size after compression. */
+{
+uLongf compSize = compBufSize;
+int err = compress((Bytef*)compBuf, &compSize, (Bytef*)uncompressed, (uLong)uncompressedSize);
+if (err != 0)
+    errAbort("Couldn't zCompress %lld bytes: %s", 
+    	(long long)uncompressedSize, zlibErrorMessage(err));
+return compSize;
+}
+
+size_t zCompBufSize(size_t uncompressedSize)
+/* Return size of buffer needed to compress something of given size uncompressed. */
+{
+return 1.001*uncompressedSize + 13;
+}
+
+size_t zUncompress(
+        void *compressed,	/* Compressed area */
+	size_t compressedSize,	/* Size after compression */
+	void *uncompBuf,	/* Where to put uncompressed bits */
+	size_t uncompBufSize)	/* Max size of uncompressed bits. */
+/* Uncompress data from memory to memory.  Returns size after decompression. */
+{
+uLongf uncSize = uncompBufSize;
+int err = uncompress(uncompBuf,  &uncSize, compressed, compressedSize);
+if (err != 0)
+    errAbort("Couldn't zUncompress %lld bytes: %s", 
+    	(long long)compressedSize, zlibErrorMessage(err));
+return uncSize;
+}
+
+void zSelfTest(int count)
+/* Run an internal diagnostic. */
+{
+bits32 testData[count];
+int uncSize = count*sizeof(bits32);
+int i;
+for (i=0; i<count; ++i)
+    testData[i] = i;
+int compBufSize = zCompBufSize(uncSize);
+char compBuf[compBufSize];
+int compSize = zCompress(testData, uncSize, compBuf, compBufSize);
+char uncBuf[uncSize];
+zUncompress(compBuf, compSize, uncBuf, uncSize);
+if (memcmp(uncBuf, testData, uncSize) != 0)
+    errAbort("zSelfTest %d failed", count);
+else
+    verbose(2, "zSelfTest %d passed, compression ratio %3.1f\n", count, (double)compSize/uncSize);
+}
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..12bbe1a
--- /dev/null
+++ b/makefile
@@ -0,0 +1,18 @@
+all:
+	cd lib && ${MAKE}
+	cd jkOwnLib && ${MAKE}
+	cd blat && $(MAKE)
+	cd gfClient && $(MAKE)
+	cd gfServer && $(MAKE)
+	cd hg/pslPretty && $(MAKE)
+	cd hg/pslReps && $(MAKE)
+	cd hg/pslSort && $(MAKE)
+	cd utils/nibFrag && $(MAKE)
+	cd utils/faToNib && $(MAKE)
+	cd utils/faToTwoBit && $(MAKE)
+	cd utils/twoBitToFa && $(MAKE)
+	cd utils/twoBitInfo && $(MAKE)
+	cd webBlat && $(MAKE)
+
+clean:
+	rm -f */*.o */*/*.o lib/*/*.a
diff --git a/utils/faToNib/faToNib.c b/utils/faToNib/faToNib.c
new file mode 100644
index 0000000..ca6eded
--- /dev/null
+++ b/utils/faToNib/faToNib.c
@@ -0,0 +1,58 @@
+/* faToNib - Convert from .fa to .nib format. */
+#include "common.h"
+#include "options.h"
+#include "nib.h"
+#include "fa.h"
+
+
+void usage()
+/* Explain usage and exit. */
+{
+errAbort(
+  "faToNib - Convert from .fa to .nib format\n"
+  "usage:\n"
+  "   faToNib [options] in.fa out.nib\n"
+  "options:\n"
+  "   -softMask - create nib that soft-masks lower case sequence\n"
+  "   -hardMask - create nib that hard-masks lower case sequence\n");
+}
+
+void maskLower(struct dnaSeq *seq)
+/* Convert upper case to lower case and lower case to 'n' */
+{
+DNA *dna = seq->dna, base;
+int i, size = seq->size;
+for (i=0; i<size; ++i)
+    {
+    base = dna[i];
+    if (isupper(base))
+	base = tolower(base);
+    else
+        base = 'n';
+    dna[i] = base;
+    }
+}
+
+void faToNib(int options, char *in, char *out)
+/* faToNib - Convert from .fa to .nib format. */
+{
+struct dnaSeq *seq = faReadAllMixed(in);
+if (slCount(seq) > 1)
+    errAbort("faToNib only works on fa files containing a single sequence.");
+if (optionExists("hardMask"))
+    maskLower(seq);
+nibWriteMasked(options, seq, out);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+int options = 0;
+optionHash(&argc, argv);
+if (optionExists("softMask"))
+    options = NIB_MASK_MIXED;
+if (argc != 3)
+    usage();
+faToNib(options, argv[1], argv[2]);
+return 0;
+}
diff --git a/utils/faToNib/makefile b/utils/faToNib/makefile
new file mode 100644
index 0000000..fc46922
--- /dev/null
+++ b/utils/faToNib/makefile
@@ -0,0 +1,16 @@
+include ../../inc/common.mk
+
+L += -lm
+MYLIBDIR = ../../lib/${MACHTYPE}
+MYLIBS = ${MYLIBDIR}/jkweb.a
+
+A = faToNib
+O = faToNib.o
+
+faToNib: ${O}
+	@${MKDIR} "${DESTDIR}${BINDIR}"
+	${CC} ${COPT} ${CFLAGS} -o ${DESTDIR}${BINDIR}/${A}${EXE} $O ${MYLIBS} ${L}
+	${STRIP} ${DESTDIR}${BINDIR}/${A}${EXE}
+
+clean::
+	rm -f ${O}
diff --git a/utils/faToTwoBit/faToTwoBit.c b/utils/faToTwoBit/faToTwoBit.c
new file mode 100644
index 0000000..67dd919
--- /dev/null
+++ b/utils/faToTwoBit/faToTwoBit.c
@@ -0,0 +1,127 @@
+/* faToTwoBit - Convert DNA from fasta to 2bit format. */
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "options.h"
+#include "dnaseq.h"
+#include "dnautil.h"
+#include "fa.h"
+#include "twoBit.h"
+
+
+void usage()
+/* Explain usage and exit. */
+{
+errAbort(
+  "faToTwoBit - Convert DNA from fasta to 2bit format\n"
+  "usage:\n"
+  "   faToTwoBit in.fa [in2.fa in3.fa ...] out.2bit\n"
+  "options:\n"
+  "   -noMask       - Ignore lower-case masking in fa file.\n"
+  "   -stripVersion - Strip off version number after . for genbank accessions.\n"
+  "   -ignoreDups   - only convert first sequence if there are duplicates\n"
+  );
+}
+
+boolean noMask = FALSE;
+boolean stripVersion = FALSE;
+boolean ignoreDups = FALSE;
+
+static struct optionSpec options[] = {
+   {"noMask", OPTION_BOOLEAN},
+   {"stripVersion", OPTION_BOOLEAN},
+   {"ignoreDups", OPTION_BOOLEAN},
+   {NULL, 0},
+};
+
+static void unknownToN(char *s, int size)
+/* Convert non ACGT characters to N. */
+{
+char c;
+int i;
+for (i=0; i<size; ++i)
+    {
+    c = s[i];
+    if (ntChars[(int)c] == 0)
+        {
+	if (isupper(c))
+	    s[i] = 'N';
+	else
+	    s[i] = 'n';
+	}
+    }
+}
+
+	    
+void faToTwoBit(char *inFiles[], int inFileCount, char *outFile)
+/* Convert inFiles in fasta format to outfile in 2 bit 
+ * format. */
+{
+struct twoBit *twoBitList = NULL, *twoBit;
+int i;
+struct hash *uniqHash = newHash(18);
+FILE *f;
+
+for (i=0; i<inFileCount; ++i)
+    {
+    char *fileName = inFiles[i];
+    struct lineFile *lf = lineFileOpen(fileName, TRUE);
+    struct dnaSeq seq;
+    ZeroVar(&seq);
+    while (faMixedSpeedReadNext(lf, &seq.dna, &seq.size, &seq.name))
+        {
+	if (seq.size == 0)
+	    {
+	    warn("Skipping item %s which has no sequence.\n",seq.name);
+	    continue;
+	    }
+	    
+        /* strip off version number */
+        if (stripVersion)
+            {
+            char *sp = NULL;
+            sp = strchr(seq.name,'.');
+            if (sp != NULL)
+                *sp = '\0';
+            }
+
+        if (hashLookup(uniqHash, seq.name))
+            {
+            if (!ignoreDups)
+                errAbort("Duplicate sequence name %s", seq.name);
+            else
+                continue;
+            }
+	hashAdd(uniqHash, seq.name, NULL);
+	if (noMask)
+	    faToDna(seq.dna, seq.size);
+	else
+	    unknownToN(seq.dna, seq.size);
+	twoBit = twoBitFromDnaSeq(&seq, !noMask);
+	slAddHead(&twoBitList, twoBit);
+	}
+    lineFileClose(&lf);
+    }
+slReverse(&twoBitList);
+f = mustOpen(outFile, "wb");
+twoBitWriteHeader(twoBitList, f);
+for (twoBit = twoBitList; twoBit != NULL; twoBit = twoBit->next)
+    {
+    twoBitWriteOne(twoBit, f);
+    }
+carefulClose(&f);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, options);
+if (argc < 3)
+    usage();
+noMask = optionExists("noMask");
+stripVersion = optionExists("stripVersion");
+ignoreDups = optionExists("ignoreDups");
+dnaUtilOpen();
+faToTwoBit(argv+1, argc-2, argv[argc-1]);
+return 0;
+}
diff --git a/utils/faToTwoBit/makefile b/utils/faToTwoBit/makefile
new file mode 100644
index 0000000..9822051
--- /dev/null
+++ b/utils/faToTwoBit/makefile
@@ -0,0 +1,33 @@
+include ../../inc/common.mk
+
+L += -lm ${SOCKETLIB}
+MYLIBDIR = ../../lib/${MACHTYPE}
+MYLIBS = ${MYLIBDIR}/jkweb.a
+
+A = faToTwoBit
+O = faToTwoBit.o
+
+faToTwoBit: ${O} ${MYLIBS}
+	@${MKDIR} "${DESTDIR}${BINDIR}"
+	${CC} ${COPT} ${CFLAGS} -o ${DESTDIR}${BINDIR}/${A}${EXE} $O ${MYLIBS} ${L}
+	${STRIP} ${DESTDIR}${BINDIR}/${A}${EXE}
+
+clean::
+	rm -f ${O}
+
+test:
+	${MKDIR} tests/output
+	faToTwoBit tests/input/noDna.fa tests/output/noDna.2bit 2> tests/output/noDna.out
+	diff tests/expected/noDna.out tests/output/noDna.out
+	twoBitToFa tests/output/noDna.2bit tests/output/noDna.fa
+	diff tests/expected/noDna.fa tests/output/noDna.fa
+	faToTwoBit tests/input/testN.fa tests/output/testN.2bit
+	twoBitToFa tests/output/testN.2bit tests/output/testN.fa
+	diff tests/input/testN.fa tests/output/testN.fa
+	faToTwoBit tests/input/testMask.fa tests/output/testMask.2bit
+	twoBitToFa tests/output/testMask.2bit tests/output/testMask.fa
+	diff tests/input/testMask.fa tests/output/testMask.fa
+	faToTwoBit -stripVersion tests/input/genbank.fa tests/output/genbank.2bit
+	twoBitToFa tests/output/genbank.2bit tests/output/genbank.strip.fa
+	diff tests/expected/genbank.fa tests/output/genbank.strip.fa
+#	rm -r tests/output
diff --git a/utils/faToTwoBit/tests/expected/genbank.fa b/utils/faToTwoBit/tests/expected/genbank.fa
new file mode 100644
index 0000000..0219380
--- /dev/null
+++ b/utils/faToTwoBit/tests/expected/genbank.fa
@@ -0,0 +1,4 @@
+>AC03030
+NANNAANNNAAA
+>AF030303
+ANAANNAAANNN
diff --git a/utils/faToTwoBit/tests/expected/noDna.fa b/utils/faToTwoBit/tests/expected/noDna.fa
new file mode 100644
index 0000000..e69de29
diff --git a/utils/faToTwoBit/tests/expected/noDna.out b/utils/faToTwoBit/tests/expected/noDna.out
new file mode 100644
index 0000000..f92353f
--- /dev/null
+++ b/utils/faToTwoBit/tests/expected/noDna.out
@@ -0,0 +1,3 @@
+Invalid fasta format: sequence size == 0 for element NM_empty
+Skipping item NM_empty which has no sequence.
+
diff --git a/utils/faToTwoBit/tests/input/genbank.fa b/utils/faToTwoBit/tests/input/genbank.fa
new file mode 100644
index 0000000..23e88ee
--- /dev/null
+++ b/utils/faToTwoBit/tests/input/genbank.fa
@@ -0,0 +1,4 @@
+>AC03030.3
+NANNAANNNAAA
+>AF030303
+ANAANNAAANNN
diff --git a/utils/faToTwoBit/tests/input/noDna.fa b/utils/faToTwoBit/tests/input/noDna.fa
new file mode 100644
index 0000000..a757471
--- /dev/null
+++ b/utils/faToTwoBit/tests/input/noDna.fa
@@ -0,0 +1 @@
+>NM_empty
diff --git a/utils/faToTwoBit/tests/input/testMask.fa b/utils/faToTwoBit/tests/input/testMask.fa
new file mode 100644
index 0000000..1fc92cb
--- /dev/null
+++ b/utils/faToTwoBit/tests/input/testMask.fa
@@ -0,0 +1,10 @@
+>startLower
+aaacagtaaAAAACCC
+>endLower
+AAAACCCaaacagtaa
+>manyLower
+aaCCggTTaCgT
+>allLower
+taaaacaaaaag
+>noLower
+ACGTTTACT
diff --git a/utils/faToTwoBit/tests/input/testN.fa b/utils/faToTwoBit/tests/input/testN.fa
new file mode 100644
index 0000000..56c7d64
--- /dev/null
+++ b/utils/faToTwoBit/tests/input/testN.fa
@@ -0,0 +1,4 @@
+>startN
+NANNAANNNAAA
+>startNonN
+ANAANNAAANNN
diff --git a/utils/nibFrag/makefile b/utils/nibFrag/makefile
new file mode 100755
index 0000000..5cc0b06
--- /dev/null
+++ b/utils/nibFrag/makefile
@@ -0,0 +1,15 @@
+include ../../inc/common.mk
+
+MYLIBDIR = ../../lib/${MACHTYPE}
+MYLIBS = ${MYLIBDIR}/jkweb.a
+
+A = nibFrag
+O = nibFrag.o
+
+nibFrag: ${O}
+	@${MKDIR} "${DESTDIR}${BINDIR}"
+	${CC} ${COPT} ${CFLAGS} -o ${DESTDIR}${BINDIR}/${A}${EXE} $O ${MYLIBS} ${L}
+	${STRIP} ${DESTDIR}${BINDIR}/${A}${EXE}
+
+clean::
+	rm -f ${O}
diff --git a/utils/nibFrag/nibFrag.c b/utils/nibFrag/nibFrag.c
new file mode 100644
index 0000000..f842f54
--- /dev/null
+++ b/utils/nibFrag/nibFrag.c
@@ -0,0 +1,107 @@
+/* nibFrag - Extract part of a nib file as .fa. */
+#include "common.h"
+#include "dnaseq.h"
+#include "nib.h"
+#include "options.h"
+#include "fa.h"
+
+
+static struct optionSpec optionSpecs[] = {
+    {"masked", OPTION_BOOLEAN},
+    {"hardMasked", OPTION_BOOLEAN},
+    {"upper", OPTION_BOOLEAN},
+    {"name", OPTION_STRING},
+    {"dbHeader", OPTION_STRING},
+    {"tbaHeader", OPTION_STRING},
+    {NULL, 0}
+};
+void usage()
+/* Explain usage and exit. */
+{
+errAbort(
+  "nibFrag - Extract part of a nib file as .fa (all bases/gaps lower case by default)\n"
+  "usage:\n"
+  "   nibFrag [options] file.nib start end strand out.fa\n"
+  "where strand is + (plus) or m (minus)\n"
+  "options:\n"
+  "   -masked - use lower case characters for bases meant to be masked out\n"
+  "   -hardMasked - use upper case for not masked-out and 'N' characters for masked-out bases\n"
+  "   -upper - use upper case characters for all bases\n"
+  "   -name=name Use given name after '>' in output sequence\n"
+  "   -dbHeader=db Add full database info to the header, with or without -name option\n"
+  "   -tbaHeader=db Format header for compatibility with tba, takes database name as argument\n"
+  );
+}
+
+void nibFrag(int options, char *nibFile, int start, int end, char strand, 
+	     char *faFile, int optUpper, boolean hardMask)
+/* nibFrag - Extract part of a nib file as .fa. */
+{
+struct dnaSeq *seq;
+char header[255];
+char name[128];
+int chromLength;
+
+if (strand != '+' && strand != '-' && strand != 'm')
+   usage();
+if (strand == 'm')
+    strand = '-';
+if (start >= end)
+   usage();
+seq = nibLoadPartMasked(options, nibFile, start, end-start);
+if (strand == '-')
+    reverseComplement(seq->dna, seq->size);
+if (optUpper == 1)
+    touppers(seq->dna);
+if (hardMask)
+    lowerToN(seq->dna, seq->size);
+if (optionExists("dbHeader"))
+    {
+    chromLength = nibGetSize(nibFile);
+    splitPath(nibFile, NULL, name, NULL);
+    safef(header,sizeof(header),"%s:%s.%s:%d-%d:%c:%d", 
+	  optionVal("name", seq->name), optionVal("dbHeader", "db"),
+	  name, start, end, strand, chromLength);
+    }
+else if (optionExists("tbaHeader"))
+    {
+    chromLength = nibGetSize(nibFile);
+    splitPath(nibFile, NULL, name, NULL);
+    safef(header,sizeof(header),"%s.%s:%d-%d of %d", 
+	  optionVal("tbaHeader", "tba"),
+	  name, start, end, chromLength);
+    }
+else
+    safef(header,sizeof(header),"%s",optionVal("name", seq->name));
+faWrite(faFile, header, seq->dna, seq->size);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+int options = 0;
+int optUpper = 0;
+boolean hardMask = FALSE;
+
+optionInit(&argc, argv, optionSpecs);
+if(optionExists("masked") && optionExists("hardMasked"))
+    {
+    warn("\nError: Must choose 'masked' or 'hardMasked' but not both.\n");
+    usage();
+    }
+if (optionExists("masked"))
+    options = NIB_MASK_MIXED;
+if(optionExists("hardMasked"))
+    {
+    /* setup to read out of nib in mixed case and then
+       convert all lower case to 'N' */
+    options = NIB_MASK_MIXED;
+    hardMask = TRUE;
+    }
+if (optionExists("upper"))
+    optUpper = 1;
+if (argc != 6 || !isdigit(argv[2][0]) || !isdigit(argv[3][0]))
+    usage();
+nibFrag(options, argv[1], atoi(argv[2]), atoi(argv[3]), argv[4][0], argv[5], optUpper, hardMask);
+return 0;
+}
diff --git a/utils/twoBitInfo/makefile b/utils/twoBitInfo/makefile
new file mode 100644
index 0000000..bd12031
--- /dev/null
+++ b/utils/twoBitInfo/makefile
@@ -0,0 +1,29 @@
+include ../../inc/common.mk
+
+L += -lm ${SOCKETLIB}
+MYLIBDIR = ../../lib/${MACHTYPE}
+MYLIBS = ${MYLIBDIR}/jkweb.a
+
+A = twoBitInfo
+O = twoBitInfo.o
+
+twoBitInfo: ${O} ${MYLIBS}
+	@${MKDIR} "${DESTDIR}${BINDIR}"
+	${CC} ${COPT} ${CFLAGS} -o ${DESTDIR}${BINDIR}/${A}${EXE} $O ${MYLIBS} ${L}
+	${STRIP} ${DESTDIR}${BINDIR}/${A}${EXE}
+
+clean::
+	rm -f ${O}
+
+# reuse twoFitToFa input files. for tests
+TEST_IN = ../twoBitToFa/tests/input
+
+test:
+	${MKDIR} tests/output
+	twoBitInfo ${TEST_IN}/testN.2bit tests/output/testN.info
+	twoBitInfo ${TEST_IN}/testMask.2bit tests/output/testMask.info
+	twoBitInfo ${TEST_IN}/testMask.2bit:manyLower tests/output/ml.info
+	twoBitInfo ${TEST_IN}/testMask.2bit:manyLower:2-10 tests/output/ml_sub.info
+	twoBitInfo ${TEST_IN}/testMask.2bit:noLower,startLower tests/output/ml_multiple.info
+	diff -r -x CVS tests/expected tests/output
+	rm -r tests/output
diff --git a/utils/twoBitInfo/tests/expected/ml.info b/utils/twoBitInfo/tests/expected/ml.info
new file mode 100644
index 0000000..a44f40e
--- /dev/null
+++ b/utils/twoBitInfo/tests/expected/ml.info
@@ -0,0 +1 @@
+manyLower	12
diff --git a/utils/twoBitInfo/tests/expected/ml_multiple.info b/utils/twoBitInfo/tests/expected/ml_multiple.info
new file mode 100644
index 0000000..8982d77
--- /dev/null
+++ b/utils/twoBitInfo/tests/expected/ml_multiple.info
@@ -0,0 +1,2 @@
+noLower	9
+startLower	16
diff --git a/utils/twoBitInfo/tests/expected/ml_sub.info b/utils/twoBitInfo/tests/expected/ml_sub.info
new file mode 100644
index 0000000..a44f40e
--- /dev/null
+++ b/utils/twoBitInfo/tests/expected/ml_sub.info
@@ -0,0 +1 @@
+manyLower	12
diff --git a/utils/twoBitInfo/tests/expected/testMask.info b/utils/twoBitInfo/tests/expected/testMask.info
new file mode 100644
index 0000000..fb9fd01
--- /dev/null
+++ b/utils/twoBitInfo/tests/expected/testMask.info
@@ -0,0 +1,5 @@
+startLower	16
+endLower	16
+manyLower	12
+allLower	12
+noLower	9
diff --git a/utils/twoBitInfo/tests/expected/testN.info b/utils/twoBitInfo/tests/expected/testN.info
new file mode 100644
index 0000000..c820402
--- /dev/null
+++ b/utils/twoBitInfo/tests/expected/testN.info
@@ -0,0 +1,2 @@
+startN	12
+startNonN	12
diff --git a/utils/twoBitInfo/twoBitInfo.c b/utils/twoBitInfo/twoBitInfo.c
new file mode 100644
index 0000000..50b1b79
--- /dev/null
+++ b/utils/twoBitInfo/twoBitInfo.c
@@ -0,0 +1,86 @@
+/* twoBitInfo - get information about sequences in a .2bit file. */
+#include "common.h"
+#include "options.h"
+#include "twoBit.h"
+
+
+void usage()
+/* Explain usage and exit. */
+{
+errAbort(
+  "twoBitInfo - get information about sequences in a .2bit file\n"
+  "usage:\n"
+  "   twoBitInfo input.2bit output.tab\n"
+  "options:\n"
+  "   -nBed   instead of seq sizes, output BED records that define \n"
+  "           areas with N's in sequence\n"
+  "   -noNs   outputs the length of each sequence, but does not count Ns \n"
+  "Output file has the columns::\n"
+  "   seqName size\n"
+  "\n"
+  "The 2bit file may be specified in the form path:seq or path:seq1,seq2,seqN...\n"
+  "so that information is returned only on the requested sequence(s).\n"
+  "If the form path:seq:start-end is used, start-end is ignored.\n"
+  );
+}
+
+static struct optionSpec options[] = {
+   {"nBed", OPTION_BOOLEAN},
+   {"noNs", OPTION_BOOLEAN},
+   {NULL, 0},
+};
+
+
+void twoBitInfo(char *inName, char *outName)
+/* twoBitInfo - get information about sequences in a .2bit file. */
+{
+struct twoBitFile *tbf;
+FILE *outFile;
+char *seqName = NULL;
+
+twoBitParseRange(inName, &inName, &seqName, NULL, NULL);
+tbf = twoBitOpen(inName);
+outFile = mustOpen(outName, "w");
+
+if (seqName != NULL)
+    {
+    char *seqArray[1023];
+    int i;
+    int seqCount = chopString(seqName, ",", seqArray, ArraySize(seqArray));
+    for (i = 0 ; i < seqCount ; i++)
+	{
+	if (optionExists("nBed"))
+	    twoBitOutNBeds(tbf, seqArray[i], outFile);
+	else if(optionExists("noNs"))
+	    fprintf(outFile, "%s\t%d\n", seqArray[i], twoBitSeqSizeNoNs(tbf, seqArray[i]));
+	else
+	    fprintf(outFile, "%s\t%d\n", seqArray[i], twoBitSeqSize(tbf, seqArray[i]));
+	}
+	
+    }
+else
+    {
+    struct twoBitIndex *index;
+    for (index = tbf->indexList; index != NULL; index = index->next)
+	{
+	if (optionExists("nBed"))
+	    twoBitOutNBeds(tbf, index->name, outFile);
+	else if(optionExists("noNs"))
+	    fprintf(outFile, "%s\t%d\n", index->name, twoBitSeqSizeNoNs(tbf, index->name));
+	else
+	    fprintf(outFile, "%s\t%d\n", index->name, twoBitSeqSize(tbf, index->name));
+	}
+    }
+twoBitClose(&tbf);
+carefulClose(&outFile); 
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, options);
+if (argc != 3)
+    usage();
+twoBitInfo(argv[1], argv[2]);
+return 0;
+}
diff --git a/utils/twoBitToFa/makefile b/utils/twoBitToFa/makefile
new file mode 100644
index 0000000..d7e227d
--- /dev/null
+++ b/utils/twoBitToFa/makefile
@@ -0,0 +1,37 @@
+include ../../inc/common.mk
+
+L += -lm ${SOCKETLIB}
+MYLIBDIR = ../../lib/${MACHTYPE}
+MYLIBS = ${MYLIBDIR}/jkweb.a
+
+A = twoBitToFa
+O = twoBitToFa.o
+
+twoBitToFa: ${O}
+	@${MKDIR} "${DESTDIR}${BINDIR}"
+	${CC} ${COPT} ${CFLAGS} -o ${DESTDIR}${BINDIR}/${A}${EXE} $O ${MYLIBS} ${L}
+	${STRIP} ${DESTDIR}${BINDIR}/${A}${EXE}
+
+clean::
+	rm -f ${O}
+
+test:
+	rm -fr tests/output
+	${MKDIR} tests/output
+	twoBitToFa tests/input/testN.2bit tests/output/testN.fa
+	twoBitToFa tests/input/testMask.2bit tests/output/testMask.fa
+	twoBitToFa tests/input/testMask.2bit -seq=manyLower -start=1 -end=11 tests/output/ml_1_11.fa
+	twoBitToFa tests/input/testMask.2bit -seq=manyLower -start=2 -end=10 tests/output/ml_2_10.fa
+	twoBitToFa tests/input/testMask.2bit -seq=manyLower -start=3 -end=9 tests/output/ml_3_9.fa
+	twoBitToFa tests/input/testMask.2bit -seq=manyLower -start=4 -end=8 tests/output/ml_4_8.fa
+	twoBitToFa tests/input/testMask.2bit -seq=manyLower -start=5 -end=7 tests/output/ml_5_7.fa
+	twoBitToFa tests/input/testMask.2bit -seq=manyLower -start=5 -end=6 tests/output/ml_5_6.fa
+	twoBitToFa tests/input/testMask.2bit -seq=manyLower -start=6 -end=7 tests/output/ml_6_7.fa
+	twoBitToFa tests/input/testMask.2bit -seq=manyLower -start=7 -end=8 tests/output/ml_7_8.fa
+	twoBitToFa tests/input/testMask.2bit -seq=manyLower -start=8 -end=9 tests/output/ml_8_9.fa
+	twoBitToFa tests/input/testMask.2bit:manyLower tests/output/spec_ml.fa
+	twoBitToFa tests/input/testMask.2bit:manyLower:2-10 tests/output/spec_ml_2_10.fa
+	twoBitToFa tests/input/testMask.2bit tests/output/spec_ml_no_start_end.fa -seqList=tests/input/seqlist1
+	twoBitToFa tests/input/testMask.2bit tests/output/spec_ml_partial_list.fa -seqList=tests/input/seqlist2
+	diff -r -x CVS tests/expected tests/output
+	rm -r tests/output
diff --git a/utils/twoBitToFa/tests/expected/ml_1_11.fa b/utils/twoBitToFa/tests/expected/ml_1_11.fa
new file mode 100644
index 0000000..6e4b2d5
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/ml_1_11.fa
@@ -0,0 +1,2 @@
+>manyLower:1-11
+aCCggTTaCg
diff --git a/utils/twoBitToFa/tests/expected/ml_2_10.fa b/utils/twoBitToFa/tests/expected/ml_2_10.fa
new file mode 100644
index 0000000..5790d72
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/ml_2_10.fa
@@ -0,0 +1,2 @@
+>manyLower:2-10
+CCggTTaC
diff --git a/utils/twoBitToFa/tests/expected/ml_3_9.fa b/utils/twoBitToFa/tests/expected/ml_3_9.fa
new file mode 100644
index 0000000..77770ba
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/ml_3_9.fa
@@ -0,0 +1,2 @@
+>manyLower:3-9
+CggTTa
diff --git a/utils/twoBitToFa/tests/expected/ml_4_8.fa b/utils/twoBitToFa/tests/expected/ml_4_8.fa
new file mode 100644
index 0000000..42c5c08
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/ml_4_8.fa
@@ -0,0 +1,2 @@
+>manyLower:4-8
+ggTT
diff --git a/utils/twoBitToFa/tests/expected/ml_5_6.fa b/utils/twoBitToFa/tests/expected/ml_5_6.fa
new file mode 100644
index 0000000..9e64f0a
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/ml_5_6.fa
@@ -0,0 +1,2 @@
+>manyLower:5-6
+g
diff --git a/utils/twoBitToFa/tests/expected/ml_5_7.fa b/utils/twoBitToFa/tests/expected/ml_5_7.fa
new file mode 100644
index 0000000..bd67d27
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/ml_5_7.fa
@@ -0,0 +1,2 @@
+>manyLower:5-7
+gT
diff --git a/utils/twoBitToFa/tests/expected/ml_6_7.fa b/utils/twoBitToFa/tests/expected/ml_6_7.fa
new file mode 100644
index 0000000..790365b
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/ml_6_7.fa
@@ -0,0 +1,2 @@
+>manyLower:6-7
+T
diff --git a/utils/twoBitToFa/tests/expected/ml_7_8.fa b/utils/twoBitToFa/tests/expected/ml_7_8.fa
new file mode 100644
index 0000000..8f2227a
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/ml_7_8.fa
@@ -0,0 +1,2 @@
+>manyLower:7-8
+T
diff --git a/utils/twoBitToFa/tests/expected/ml_8_9.fa b/utils/twoBitToFa/tests/expected/ml_8_9.fa
new file mode 100644
index 0000000..16cf913
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/ml_8_9.fa
@@ -0,0 +1,2 @@
+>manyLower:8-9
+a
diff --git a/utils/twoBitToFa/tests/expected/spec_ml.fa b/utils/twoBitToFa/tests/expected/spec_ml.fa
new file mode 100644
index 0000000..e1c2840
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/spec_ml.fa
@@ -0,0 +1,2 @@
+>manyLower
+aaCCggTTaCgT
diff --git a/utils/twoBitToFa/tests/expected/spec_ml_2_10.fa b/utils/twoBitToFa/tests/expected/spec_ml_2_10.fa
new file mode 100644
index 0000000..5790d72
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/spec_ml_2_10.fa
@@ -0,0 +1,2 @@
+>manyLower:2-10
+CCggTTaC
diff --git a/utils/twoBitToFa/tests/expected/spec_ml_no_start_end.fa b/utils/twoBitToFa/tests/expected/spec_ml_no_start_end.fa
new file mode 100644
index 0000000..ef2f4ea
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/spec_ml_no_start_end.fa
@@ -0,0 +1,6 @@
+>noLower
+ACGTTTACT
+>startLower
+aaacagtaaAAAACCC
+>endLower
+AAAACCCaaacagtaa
diff --git a/utils/twoBitToFa/tests/expected/spec_ml_partial_list.fa b/utils/twoBitToFa/tests/expected/spec_ml_partial_list.fa
new file mode 100644
index 0000000..29a3c98
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/spec_ml_partial_list.fa
@@ -0,0 +1,6 @@
+>noLower
+ACGTTTACT
+>startLower:0-5
+aaaca
+>endLower:2-8
+AACCCa
diff --git a/utils/twoBitToFa/tests/expected/testMask.fa b/utils/twoBitToFa/tests/expected/testMask.fa
new file mode 100644
index 0000000..1fc92cb
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/testMask.fa
@@ -0,0 +1,10 @@
+>startLower
+aaacagtaaAAAACCC
+>endLower
+AAAACCCaaacagtaa
+>manyLower
+aaCCggTTaCgT
+>allLower
+taaaacaaaaag
+>noLower
+ACGTTTACT
diff --git a/utils/twoBitToFa/tests/expected/testN.fa b/utils/twoBitToFa/tests/expected/testN.fa
new file mode 100644
index 0000000..56c7d64
--- /dev/null
+++ b/utils/twoBitToFa/tests/expected/testN.fa
@@ -0,0 +1,4 @@
+>startN
+NANNAANNNAAA
+>startNonN
+ANAANNAAANNN
diff --git a/utils/twoBitToFa/tests/input/seqlist1 b/utils/twoBitToFa/tests/input/seqlist1
new file mode 100644
index 0000000..49a9f6d
--- /dev/null
+++ b/utils/twoBitToFa/tests/input/seqlist1
@@ -0,0 +1,3 @@
+noLower
+startLower
+endLower
diff --git a/utils/twoBitToFa/tests/input/seqlist2 b/utils/twoBitToFa/tests/input/seqlist2
new file mode 100644
index 0000000..aecbe13
--- /dev/null
+++ b/utils/twoBitToFa/tests/input/seqlist2
@@ -0,0 +1,3 @@
+noLower
+startLower:0-5
+endLower:2-8
diff --git a/utils/twoBitToFa/tests/input/testMask.2bit b/utils/twoBitToFa/tests/input/testMask.2bit
new file mode 100644
index 0000000..4b8a03c
Binary files /dev/null and b/utils/twoBitToFa/tests/input/testMask.2bit differ
diff --git a/utils/twoBitToFa/tests/input/testN.2bit b/utils/twoBitToFa/tests/input/testN.2bit
new file mode 100644
index 0000000..63db13c
Binary files /dev/null and b/utils/twoBitToFa/tests/input/testN.2bit differ
diff --git a/utils/twoBitToFa/twoBitToFa.c b/utils/twoBitToFa/twoBitToFa.c
new file mode 100644
index 0000000..b9785ab
--- /dev/null
+++ b/utils/twoBitToFa/twoBitToFa.c
@@ -0,0 +1,201 @@
+/* twoBitToFa - Convert all or part of twoBit file to fasta. */
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "options.h"
+#include "dnaseq.h"
+#include "fa.h"
+#include "twoBit.h"
+#include "bPlusTree.h"
+#include "basicBed.h"
+
+
+void usage()
+/* Explain usage and exit. */
+{
+errAbort(
+  "twoBitToFa - Convert all or part of .2bit file to fasta\n"
+  "usage:\n"
+  "   twoBitToFa input.2bit output.fa\n"
+  "options:\n"
+  "   -seq=name - restrict this to just one sequence\n"
+  "   -start=X  - start at given position in sequence (zero-based)\n"
+  "   -end=X - end at given position in sequence (non-inclusive)\n"
+  "   -seqList=file - file containing list of the desired sequence names \n"
+  "                    in the format seqSpec[:start-end], e.g. chr1 or chr1:0-189\n"
+  "                    where coordinates are half-open zero-based, i.e. [start,end)\n"
+  "   -noMask - convert sequence to all upper case\n"
+  "   -bpt=index.bpt - use bpt index instead of built in one\n"
+  "   -bed=input.bed - grab sequences specified by input.bed. Will exclude introns\n"
+  "\n"
+  "Sequence and range may also be specified as part of the input\n"
+  "file name using the syntax:\n"
+  "      /path/input.2bit:name\n"
+  "   or\n"
+  "      /path/input.2bit:name\n"
+  "   or\n"
+  "      /path/input.2bit:name:start-end\n"
+  );
+}
+
+char *clSeq = NULL;	/* Command line sequence. */
+int clStart = 0;	/* Start from command line. */
+int clEnd = 0;		/* End from command line. */
+char *clSeqList = NULL; /* file containing list of seq names */
+bool noMask = FALSE;  /* convert seq to upper case */
+char *clBpt = NULL;	/* External index file. */
+char *clBed = NULL;	/* Bed file that specifies bounds of sequences. */
+
+static struct optionSpec options[] = {
+   {"seq", OPTION_STRING},
+   {"seqList", OPTION_STRING},
+   {"start", OPTION_INT},
+   {"end", OPTION_INT},
+   {"noMask", OPTION_BOOLEAN},
+   {"bpt", OPTION_STRING},
+   {"bed", OPTION_STRING},
+   {NULL, 0},
+};
+
+void outputOne(struct twoBitFile *tbf, char *seqSpec, FILE *f, 
+	int start, int end)
+/* Output sequence. */
+{
+struct dnaSeq *seq = twoBitReadSeqFrag(tbf, seqSpec, start, end);
+if (noMask)
+    toUpperN(seq->dna, seq->size);
+faWriteNext(f, seq->name, seq->dna, seq->size);
+dnaSeqFree(&seq);
+}
+
+static void processAllSeqs(struct twoBitFile *tbf, FILE *outFile)
+/* get all sequences in a file */
+{
+struct twoBitIndex *index;
+for (index = tbf->indexList; index != NULL; index = index->next)
+    outputOne(tbf, index->name, outFile, 0, 0);
+}
+
+static void processSeqSpecs(struct twoBitFile *tbf, struct twoBitSeqSpec *tbss,
+                            FILE *outFile)
+/* process list of twoBitSeqSpec objects */
+{
+struct twoBitSeqSpec *s;
+for (s = tbss; s != NULL; s = s->next)
+    outputOne(tbf, s->name, outFile, s->start, s->end);
+}
+
+struct dnaSeq *twoBitAndBedToSeq(struct twoBitFile *tbf, struct bed *bed)
+/* Get sequence defined by bed.  Exclude introns. */
+{
+struct dnaSeq *seq;
+if (bed->blockCount <= 1)
+    {
+    seq = twoBitReadSeqFrag(tbf, bed->chrom, bed->chromStart, bed->chromEnd);
+    freeMem(seq->name);
+    seq->name = cloneString(bed->name);
+    }
+else
+    {
+    int totalBlockSize = bedTotalBlockSize(bed);
+    AllocVar(seq);
+    seq->name = cloneString(bed->name);
+    seq->dna = needMem(totalBlockSize+1);
+    seq->size = totalBlockSize;
+    int i;
+    int seqOffset = 0;
+    for (i=0; i<bed->blockCount; ++i)
+        {
+	int exonSize = bed->blockSizes[i];
+	int exonStart = bed->chromStart + bed->chromStarts[i];
+	struct dnaSeq *exon = twoBitReadSeqFrag(tbf, bed->chrom, exonStart, exonStart+exonSize);
+	memcpy(seq->dna + seqOffset, exon->dna, exonSize);
+	seqOffset += exonSize;
+	dnaSeqFree(&exon);
+	}
+    }
+if (bed->strand[0] == '-')
+    reverseComplement(seq->dna, seq->size);
+return seq;
+}
+
+static void processSeqsFromBed(struct twoBitFile *tbf, char *bedFileName, FILE *outFile)
+/* Get sequences defined by beds.  Exclude introns. */
+{
+struct bed *bed, *bedList = bedLoadAll(bedFileName);
+for (bed = bedList; bed != NULL; bed = bed->next)
+    {
+    struct dnaSeq *seq = twoBitAndBedToSeq(tbf, bed);
+    faWriteNext(outFile, seq->name, seq->dna, seq->size);
+    dnaSeqFree(&seq);
+    }
+}
+
+void twoBitToFa(char *inName, char *outName)
+/* twoBitToFa - Convert all or part of twoBit file to fasta. */
+{
+struct twoBitFile *tbf;
+FILE *outFile = mustOpen(outName, "w");
+struct twoBitSpec *tbs;
+
+if (clSeq != NULL)
+    {
+    char seqSpec[2*PATH_LEN];
+    if (clEnd > clStart)
+        safef(seqSpec, sizeof(seqSpec), "%s:%s:%d-%d", inName, clSeq, clStart, clEnd);
+    else
+        safef(seqSpec, sizeof(seqSpec), "%s:%s", inName, clSeq);
+    tbs = twoBitSpecNew(seqSpec);
+    }
+else if (clSeqList != NULL)
+    tbs = twoBitSpecNewFile(inName, clSeqList);
+else
+    tbs = twoBitSpecNew(inName);
+if (tbs->seqs != NULL && clBpt != NULL)
+    tbf = twoBitOpenExternalBptIndex(tbs->fileName, clBpt);
+else
+    tbf = twoBitOpen(tbs->fileName);
+if (clBed != NULL)
+    {
+    processSeqsFromBed(tbf, clBed, outFile);
+    }
+else
+    {
+    if (tbs->seqs == NULL)
+	processAllSeqs(tbf, outFile);
+    else
+	processSeqSpecs(tbf, tbs->seqs, outFile);
+    }
+twoBitSpecFree(&tbs);
+carefulClose(&outFile);
+twoBitClose(&tbf);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+optionInit(&argc, argv, options);
+if (argc != 3)
+    usage();
+clSeq = optionVal("seq", clSeq);
+clStart = optionInt("start", clStart);
+clEnd = optionInt("end", clEnd);
+clSeqList = optionVal("seqList", clSeqList);
+clBpt = optionVal("bpt", clBpt);
+clBed = optionVal("bed", clBed);
+if (clBed != NULL)
+    {
+    if (clSeqList != NULL)
+	errAbort("Can only have seqList or bed options, not both.");
+    if (clSeq != NULL)
+        errAbort("Can only have seq or bed options, not both.");
+    }
+if ((clStart > clEnd) && (clSeq == NULL))
+    errAbort("must specify -seq with -start and -end");
+if ((clSeq != NULL) && (clSeqList != NULL))
+    errAbort("can't specify both -seq and -seqList");
+noMask = optionExists("noMask");
+dnaUtilOpen();
+twoBitToFa(argv[1], argv[2]);
+return 0;
+}
diff --git a/webBlat/install.txt b/webBlat/install.txt
new file mode 100644
index 0000000..9032ce6
--- /dev/null
+++ b/webBlat/install.txt
@@ -0,0 +1,109 @@
+INSTALLING WEBBLAT
+
+Installing A Web-Based Blat Server involves four major steps:
+ 1) Creating sequence databases.
+ 2) Running the gfServer program to create in-memory indexes of the databases.
+ 3) Editing the webBlat.cfg file to tell it what machine and port the gfServer(s)
+    are running on, and optionally customizing the webBlat appearance to users.
+ 4) Copying the webBlat executable and webBlat.cfg to a directory where the web server can
+    execute webBlat as a CGI.
+
+CREATING SEQUENCE DATABASES
+
+You create databases with the program faToTwoBit. Typically you'll create
+a separate database for each genome you are indexing.  Each database can
+contain up to four billion bases of sequence in an unlimited number of
+records.  The databases for webPcr and webBlat are identical.
+
+The input to faToTwoBit is one or more fasta format files each of which
+can contain multiple records.  If the sequence contains repeat sequences,
+as is the case with vertebrates and many plants, the repeat sequences can
+be represented in lower case and the other sequence in upper case.  The gfServer
+program can be configured to ignore the repeat sequences.  The output of
+faToTwoBit is a file which is designed for fast random access and efficient
+storage.  The output files store four bases per byte.  They use a small amount
+of additional space to store the case of the DNA and to keep track of runs of
+N's in the input.  Non-N ambiguity codes such as Y and U in the input sequence
+will be converted to N.
+
+Here's how a typical installation might create a mouse and a human genome database:
+    cd /data/genomes
+    mkdir twoBit
+    faToTwoBit human/hg16/*.fa twoBit/hg16.2bit
+    faToTwoBit mouse/mm4/*.fa twoBit/mm4.2bit
+There's no need to put all of the databases in the same directory, but it can
+simplify bookkeeping.  
+
+The databases can also be in the .nib format which was used with blat and
+gfClient/gfServer until recently.  The .nib format only packed 2 bases per
+byte, and could only handle one record per nib file.  Recent versions of blat
+and related programs can use .2bit files as well.
+
+CREATING IN-MEMORY INDICES WITH GFSERVER
+
+The gfServer program creates an in-memory index of a nucleotide sequence database.  
+The index can either be for translated or untranslated searches.  Translated indexes
+enable protein-based blat queries and use approximately two bytes per unmasked base 
+in the database.  Untranslated indexes are used nucleotide-based blat queries as well
+as for In-silico PCR.  An index for normal blat uses approximately 1/4 byte per base.  For
+blat on smaller (primer-sized) queries or for In-silico PCR a more thorough index that
+requires 1/2 byte per base is recommended.  The gfServer is memory intensive but typically
+doesn not require a lot of CPU power.  Memory permitting multiple gfServers can be
+run on the same machine.  
+
+A typical installation might go:
+    ssh bigRamMachine
+    cd /data/genomes/twoBit
+    gfServer start bigRamMachine 17779 hg16.2bit &
+    gfServer -trans -mask start bigRamMachine 17778 hg16.2bit &
+the -trans flag makes a translated index.   It will take approximately
+15 minutes to build an untranslated index, and 45 minutes to build a
+translate index.  To build an untranslated index to be shared with 
+In-silico PCR do
+    gfServer -stepSize=5 bigRamMachine 17779 hg16.2bit &
+This index will be slightly more sensitive, noticeably so for small query sequences,
+with blat.
+
+EDITING THE WEBBLAT.CFG FILE
+
+The webBlat.cfg file tells the webBlat program where to look for gfServers and
+for sequence.  The basic format of the .cfg file is line oriented with the
+first word of the line being a command.  Blank lines and lines starting with #
+are ignored.  The webBlat.cfg and webPcr.cfg files are similar. The webBlat.cfg
+commands are:
+   gfServer  -  defines host and port a (untranslated) gfServer is running on, the 
+   		associated sequence directory, and the name of the database to display in
+                the webPcr web page.
+   gfServerTrans - defines location of a translated server.
+   background - defines the background image if any to display on web page
+   company    - defines company name to display on web page
+   tempDir    - where to put temporary files.  This path is relative to where the web
+                server executes CGI scripts.  It is good to remove files that haven't
+		been accessed for 24 hours from this directory periodically, 
+		via a cron job or similar mechanism.
+The background and company commands are optional.  The webBlat.cfg file must
+have at least one valid gfServer or gfServerTrans line, and a tempDir line.
+.  Here is a webBlat.cfg file that you
+might find at a typical installation:
+
+company Awesome Research Amalgamated
+background /images/dnaPaper.jpg
+gfServer bigRamMachine 17778 /data/genomes/2bit/hg16.2bit Human Genome
+gfServer bigRamMachine 17779 /data/genomes/2bit/hg16.2bit Human Genome
+gfServer mouseServer 17780 /data/genomes/2bit/mm4.2bit Mouse Genome
+gfServer mouseServer 17781 /data/genomes/2bit/mm4.2bit Mouse Genome
+tempDir ../tmp
+
+PUTTING WEBBLAT WHERE THE WEB SERVER CAN EXECUTE IT
+
+The details of this step vary highly from web server to web server.  On
+a typical Apache installation it might be:
+     ssh webServer
+     cd kent/webBlat
+     cp webBlat /usr/local/apache/cgi-bin
+     cp webBlat.cfg /usr/local/apache/cgi-bin
+assuming that you've put the executable and config file in kent/webBlat.
+On OS-X, instead of /usr/local/apache/cgi-bin typically you'll copy stuff
+to /LibraryWebServer/CGI-Executables.  Unless you are administering your
+own computer you will likely need to ask your local system administrators
+for help with this step.
diff --git a/webBlat/makefile b/webBlat/makefile
new file mode 100644
index 0000000..6956ad5
--- /dev/null
+++ b/webBlat/makefile
@@ -0,0 +1,27 @@
+include ../inc/common.mk
+
+L += -lm $(SOCKETLIB)
+MYLIBDIR = ../lib/${MACHTYPE}
+MYLIBS =  ${MYLIBDIR}/jkOwnLib.a ${MYLIBDIR}/jkweb.a
+
+O = webBlat.o
+
+webBlat: $O ${MYLIBS}
+	${CC} ${COPT} -o webBlat $O ${MYLIBS} ${L}
+	${STRIP} webBlat${EXE}
+
+installOsX: webBlat
+	cp webBlat /Library/WebServer/CGI-Executables
+	cp webBlat.cfg /Library/WebServer/CGI-Executables
+
+installUcsc: webBlat
+	cp webBlat /usr/local/apache/cgi-bin-$(USER)
+	cp webBlat.cfg /usr/local/apache/cgi-bin-$(USER)
+
+installAlpha: webBlat
+	cp webBlat /usr/local/apache/cgi-bin
+	cp webBlat.cfg /usr/local/apache/cgi-bin
+
+clean:
+	rm -f $O webBlat
+
diff --git a/webBlat/webBlat b/webBlat/webBlat
new file mode 100755
index 0000000..c69b895
Binary files /dev/null and b/webBlat/webBlat differ
diff --git a/webBlat/webBlat.c b/webBlat/webBlat.c
new file mode 100644
index 0000000..3edfe07
--- /dev/null
+++ b/webBlat/webBlat.c
@@ -0,0 +1,548 @@
+/* webBlat - CGI Applet for Blat. */
+/* Copyright 2004 Jim Kent.  All rights reserved. */
+
+#include "common.h"
+#include "linefile.h"
+#include "hash.h"
+#include "errabort.h"
+#include "errCatch.h"
+#include "portable.h"
+#include "htmshell.h"
+#include "dnautil.h"
+#include "dnaseq.h"
+#include "fa.h"
+#include "nib.h"
+#include "twoBit.h"
+#include "psl.h"
+#include "fuzzyFind.h"
+#include "cheapcgi.h"
+#include "genoFind.h"
+#include "gfPcrLib.h"
+#include "gfWebLib.h"
+
+
+void usage()
+/* Explain usage and exit. */
+{
+errAbort(
+  "webBlat - CGI Applet for Blat\n"
+  "This program is not generally meant to be run from the command line.\n"
+  );
+}
+
+struct gfWebConfig *cfg;	/* Our configuration. */
+
+struct gfServerAt *findServer(boolean txServer)
+/* Find gfServer. */
+{
+if (txServer)
+    return gfWebFindServer(cfg->transServerList, "wb_db");
+else
+    return gfWebFindServer(cfg->serverList, "wb_db");
+}
+
+void doHelp()
+/* Put up help page. */
+{
+uglyf("I'm just not very helpful");
+}
+
+char *protQueryMenu[] = {"Protein", "Translated DNA", "Translated RNA"};
+char *nucQueryMenu[] = {"DNA", "RNA", };
+char *bothQueryMenu[] = {"BLAT's Guess", "DNA", "RNA", 
+	"Protein", "Translated DNA", "Translated RNA"};
+char *sortMenu[] = {"query,score", "query,start", "chrom,score", "chrom,start", "score"};
+char *outputMenu[] = {"hyperlink", "psl", "psl no header"};
+
+boolean isTxType(char *type)
+/* Return TRUE if it's a query requiring a translated server type */
+{
+int i;
+for (i=0; i<ArraySize(protQueryMenu); ++i)
+    {
+    if (sameWord(type, protQueryMenu[i]))
+	 return TRUE;
+    }
+return FALSE;
+}
+
+int cmpSeqName(char *a, char *b)
+/* Compare two sequence names likely to be of form prefix followed by a number. */
+{
+char cA, cB;
+int cSame = countSame(a, b);
+
+a += cSame;
+b += cSame;
+cA = *a;
+cB = *b;
+if (isdigit(cA))
+    {
+    if (isdigit(cB))
+       return atoi(a) - atoi(b);
+    else
+       return -1;
+    }
+else if (isdigit(cB))
+    return 1;
+else
+    return strcmp(a, b);
+}
+
+int pslCmpTargetScore(const void *va, const void *vb)
+/* Compare to sort based on target then score. */
+{
+const struct psl *a = *((struct psl **)va);
+const struct psl *b = *((struct psl **)vb);
+int diff = cmpSeqName(a->tName, b->tName);
+if (diff == 0)
+    diff = pslScore(b) - pslScore(a);
+return diff;
+}
+
+int pslCmpTargetStart(const void *va, const void *vb)
+/* Compare to sort based on target start. */
+{
+const struct psl *a = *((struct psl **)va);
+const struct psl *b = *((struct psl **)vb);
+int diff = cmpSeqName(a->tName, b->tName);
+if (diff == 0)
+    diff = a->tStart - b->tStart;
+return diff;
+}
+
+char *skipFile(char *fileSeq)
+/* Skip over file: */
+{
+char *s = strchr(fileSeq, ':');
+if (s != NULL)
+    return s+1;
+else
+    {
+    internalErr();
+    return fileSeq;
+    }
+}
+
+void parseFileSeq(char *spec, char **retFile, char **retSeq)
+/* Parse out file:seq into file and seq. */
+{
+char *seq = skipFile(spec);
+*retSeq = cloneString(seq);
+*retFile = cloneStringZ(spec, seq - spec - 1);
+}
+
+
+void aliLines(char *pslName, char *faName, char *database,  char *type)
+/* Show all the places that align. */
+{
+char *url = "../cgi-bin/webBlat";
+char *sort = cgiUsualString("wb_sort", sortMenu[0]);
+char *output = cgiUsualString("wb_output", outputMenu[0]);
+boolean pslOut = startsWith("psl", output);
+struct lineFile *lf = pslFileOpen(pslName);
+struct psl *pslList = NULL, *psl, **pslArray;
+int i, pslCount = 0;
+
+while ((psl = pslNext(lf)) != NULL)
+    {
+    slAddHead(&pslList, psl);
+    ++pslCount;
+    }
+lineFileClose(&lf);
+slReverse(&pslList);
+
+if (pslList == NULL)
+    errAbort("Sorry, no matches found");
+
+/* Keep an array in unsorted order */
+AllocArray(pslArray, pslCount);
+for (psl = pslList, i=0; psl != NULL; psl = psl->next, ++i)
+    pslArray[i] = psl;
+
+
+if (sameString(sort, "query,start"))
+    {
+    slSort(&pslList, pslCmpQuery);
+    }
+else if (sameString(sort, "query,score"))
+    {
+    slSort(&pslList, pslCmpQueryScore);
+    }
+else if (sameString(sort, "score"))
+    {
+    slSort(&pslList, pslCmpScore);
+    }
+else if (sameString(sort, "chrom,start"))
+    {
+    slSort(&pslList, pslCmpTargetStart);
+    }
+else if (sameString(sort, "chrom,score"))
+    {
+    slSort(&pslList, pslCmpTargetScore);
+    }
+else
+    {
+    slSort(&pslList, pslCmpQueryScore);
+    }
+if (pslOut)
+    {
+    printf("<TT><PRE>");
+    if (!sameString(output, "psl no header"))
+	pslWriteHead(stdout);
+    for (psl = pslList; psl != NULL; psl = psl->next)
+	pslTabOut(psl, stdout);
+    }
+else
+    {
+    int lineIx = 0;
+    printf("<H2>Web BLAT Search Results</H2>");
+    printf("<TT><PRE>");
+    printf("QUERY           SCORE START  END QSIZE IDENTITY CHRO STRAND  START    END      SPAN\n");
+    printf("---------------------------------------------------------------------------------------------------\n");
+    for (psl = pslList; psl != NULL; psl = psl->next)
+	{
+	printf("<A HREF=\"%s?wb_qType=%s&wb_psl=%s&wb_fa=%s&wb_doDetailLine=%d&wb_db=%s\">",
+		url, type, pslName, faName, ptArrayIx(psl, pslArray, pslCount),
+		database);
+	printf("%-14s %5d %5d %5d %5d %5.1f%%  %4s  %2s  %9d %9d %6d",
+	    psl->qName, pslScore(psl), psl->qStart+1, psl->qEnd, psl->qSize,
+	    100.0 - pslCalcMilliBad(psl, TRUE) * 0.1,
+	    skipFile(psl->tName), psl->strand, psl->tStart+1, psl->tEnd,
+	    psl->tEnd - psl->tStart);
+	printf("</A>\n");
+	++lineIx;
+	}
+    }
+pslFreeList(&pslList);
+freez(&pslArray);
+printf("</TT></PRE>");
+}
+
+struct dnaSeq *faReadNamedSeq(char *fileName, char *name, boolean isProt)
+/* Return DNA sequence corresponding to named fasta record. */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+DNA *dna;
+int dnaSize;
+char *dnaName;
+struct dnaSeq *seq = NULL;
+while (faSomeSpeedReadNext(lf, &dna, &dnaSize, &dnaName, !isProt))
+    {
+    if (sameString(name, dnaName))
+        {
+	AllocVar(seq);
+	seq->name = cloneString(dnaName);
+	seq->size = dnaSize;
+	seq->dna = cloneStringZ(dna, dnaSize);
+	break;
+	}
+    }
+lineFileClose(&lf);
+return seq;
+}
+
+struct dnaSeq *readSeqFrag(char *seqDir, char *fileName, char *seqName, int start, int end)
+/* Read in fragment of sequence. */
+{
+char path[PATH_LEN];
+safef(path, sizeof(path), "%s/%s", seqDir, fileName);
+if (nibIsFile(path))
+    {
+    return nibLoadPart(path, start, end-start);
+    }
+else
+    {
+    struct twoBitFile *tbf = twoBitOpen(path);
+    struct dnaSeq *seq = twoBitReadSeqFragLower(tbf, seqName, start, end);
+    twoBitClose(&tbf);
+    return seq;
+    }
+}
+
+
+void doDetailLine()
+/* Show alignment details - creating a html frame with
+ * two pages: index and body. */
+{
+char *pslFileName = cgiString("wb_psl");
+char *faFileName = cgiString("wb_fa");
+char *type = cgiString("wb_qType");
+boolean isTx = isTxType(type);
+struct gfServerAt *server = findServer(isTx);
+int pslLineIx = cgiInt("wb_doDetailLine");
+int i;
+struct lineFile *lf = pslFileOpen(pslFileName);
+struct dnaSeq *qSeq = NULL, *tSeq = NULL;
+char *tFileName, *tSeqName;
+int blockCount;
+int tStart, tEnd;
+boolean protQuery = sameWord(type, "Protein");
+char *bodyName = cloneString(rTempName(cfg->tempDir, "body", ".html"));
+char *indexName = cloneString(rTempName(cfg->tempDir, "index", ".html"));
+FILE *f;
+
+/* Read in psl file and find the alignment line we're looking for. */
+struct psl *psl = NULL;
+for (i=0; i<=pslLineIx; ++i)
+    {
+    psl = pslNext(lf);
+    if (psl == NULL)
+        errAbort("Expecting at least %d lines, got %d in %s", pslLineIx+1, i+1, pslFileName);
+    }
+lineFileClose(&lf);
+
+/* Read in fa file and find the query sequence. */
+qSeq = faReadNamedSeq(faFileName, psl->qName, protQuery);
+if (qSeq == NULL)
+    errAbort("Couldn't find %s in %s", psl->qName, faFileName);
+
+
+/* Parse out file:seq into file and seq, and load needed part of target seq. */
+parseFileSeq(psl->tName, &tFileName, &tSeqName);
+
+int lineWidth = protQuery ? 60 : 50;
+int extraContext = 2 * lineWidth;  /* two lines before ... */
+tStart = psl->tStart - extraContext;
+if (tStart < 0) tStart = 0;
+tEnd = psl->tEnd + extraContext;   /* and two lines after */
+if (tEnd > psl->tSize)
+    tEnd = psl->tSize;
+tSeq = readSeqFrag(server->seqDir, tFileName, tSeqName, tStart, tEnd);
+
+
+/* Write out body. */
+f = mustOpen(bodyName, "w");
+htmStart(f, psl->qName);
+blockCount = pslShowAlignment(psl, protQuery, psl->qName, qSeq, 0, qSeq->size,
+	tSeqName, tSeq, tStart, tEnd, f);
+htmEnd(f);
+carefulClose(&f);
+chmod(bodyName, 0666);
+
+/* Write out index. */
+f = mustOpen(indexName, "w");
+htmStart(f, psl->qName);
+fprintf(f, "<H3>Alignment of %s</H3>", psl->qName);
+fprintf(f, "<A HREF=\"%s#cDNA\" TARGET=\"body\">%s</A><BR>\n", bodyName, psl->qName);
+fprintf(f, "<A HREF=\"%s#genomic\" TARGET=\"body\">%s</A><BR>\n", bodyName, tSeqName);
+for (i=1; i<=blockCount; ++i)
+    {
+    fprintf(f, "<A HREF=\"%s#%d\" TARGET=\"body\">block%d</A><BR>\n",
+	    bodyName, i, i);
+    }
+fprintf(f, "<A HREF=\"%s#ali\" TARGET=\"body\">together</A><BR>\n", bodyName);
+carefulClose(&f);
+chmod(indexName, 0666);
+
+/* Write (to stdout) the main html page containing just the frame info. */
+puts("<FRAMESET COLS = \"13%,87% \" >");
+printf("  <FRAME SRC=\"%s\" NAME=\"index\">\n", indexName);
+printf("  <FRAME SRC=\"%s\" NAME=\"body\">\n", bodyName);
+puts("<NOFRAMES><BODY></BODY></NOFRAMES>");
+puts("</FRAMESET>");
+puts("</HTML>\n");
+}
+
+
+void doBlat()
+/* Do actual blatting */
+{
+char *seqText = cgiString("wb_seq");
+bioSeq *seqList, *seq;
+char *type = NULL;
+boolean txServer = FALSE, protQuery = FALSE;
+struct gfServerAt *server;
+int conn;
+FILE *f;
+struct gfOutput *gvo;
+struct hash *tFileCache = gfFileCacheNew();
+char *pslName = cloneString(rTempName(cfg->tempDir, "wb", ".psl"));
+char *faName = cloneString(rTempName(cfg->tempDir, "wb", ".fa"));
+
+/* Figure out type and if it is a protein or a DNA based query */
+type = cgiUsualString("wb_qType", bothQueryMenu[0]);
+
+/* Get sequence from control into memory and also saved as fasta file. */
+if (sameWord(type, bothQueryMenu[0]))
+    {
+    seqList = faSeqListFromMemText(seqText, FALSE);
+    if (seqList == NULL)
+	errAbort("Please go back and paste in a sequence");
+    if (seqIsDna(seqList))
+        {
+	for (seq = seqList; seq != NULL; seq = seq->next)
+	    {
+	    toLowerN(seq->dna, seq->size);
+	    dnaFilterToN(seq->dna, seq->dna);
+	    }
+	}
+    else
+        {
+	protQuery = TRUE;
+	type = "Protein";
+	}
+    }
+else
+    {
+    protQuery = sameWord(type, "Protein");
+    seqList = faSeqListFromMemText(seqText, !protQuery);
+    if (seqList == NULL)
+	errAbort("Please go back and paste in a sequence");
+    }
+if (seqList->name == NULL || seqList->name[0] == 0)
+    {
+    freez(&seqList->name);
+    seqList->name = cloneString("query");
+    }
+faWriteAll(faName, seqList);
+
+/* Set up output for blat. */
+f = mustOpen(pslName, "w");
+gvo = gfOutputPsl(0, protQuery, FALSE, f, FALSE, TRUE);
+gvo->includeTargetFile = TRUE;
+
+txServer = isTxType(type);
+server = findServer(txServer);
+
+/* Loop through sequences doing alignments and saving to file. */
+for (seq = seqList; seq != NULL; seq = seq->next)
+    {
+    conn = gfConnect(server->host, server->port);
+    if (txServer)
+        {
+	gvo->reportTargetStrand = TRUE;
+	if (protQuery)
+	    {
+	    gfAlignTrans(&conn, server->seqDir, seq, 5, tFileCache, gvo);
+	    }
+	else
+	    {
+	    boolean isRna = sameWord(type, "RNA");
+	    gfAlignTransTrans(&conn, server->seqDir, seq, FALSE, 5,
+			    tFileCache, gvo, isRna);
+	    if (!isRna)
+	        {
+		reverseComplement(seq->dna, seq->size);
+		conn = gfConnect(server->host, server->port);
+		gfAlignTransTrans(&conn, server->seqDir, seq, TRUE, 5,
+		                        tFileCache, gvo, FALSE);
+		}
+	    }
+	}
+    else
+        {
+	gfAlignStrand(&conn, server->seqDir, seq, FALSE, 16, tFileCache, gvo);
+	reverseComplement(seq->dna, seq->size);
+	conn = gfConnect(server->host, server->port);
+	gfAlignStrand(&conn, server->seqDir, seq, TRUE, 16, tFileCache, gvo);
+	}
+    gfOutputQuery(gvo, f);
+    }
+carefulClose(&f);
+
+/* Display alignment results. */
+aliLines(pslName, faName, server->name, type);
+}
+
+void doGetSeq()
+/* Put up form that asks them to submit sequence. */
+{
+char *qType = NULL;
+char **queryMenu = NULL;
+int queryMenuSize = 0;
+struct gfServerAt *serverList = NULL, *server;
+
+
+printf("<H1>%s Web BLAT</H1>", cfg->company);
+printf("<FORM ACTION=\"../cgi-bin/webBlat\" METHOD=\"POST\">\n");
+
+/* Figure out whether we do nucleotide, translated, or both. */
+if (cfg->serverList != NULL && cfg->transServerList != NULL)
+    {
+    queryMenu = bothQueryMenu;
+    queryMenuSize = ArraySize(bothQueryMenu);
+    serverList = cfg->serverList;
+    }
+else if (cfg->serverList != NULL)
+    {
+    queryMenu = nucQueryMenu;
+    queryMenuSize = ArraySize(nucQueryMenu);
+    serverList = cfg->serverList;
+    }
+else if (cfg->transServerList != NULL)
+    {
+    queryMenu = protQueryMenu;
+    queryMenuSize = ArraySize(protQueryMenu);
+    serverList = cfg->transServerList;
+    }
+else
+    {
+    errAbort("No servers configured!");
+    }
+
+/* Put up database control */
+printf("Database: ");
+printf("<SELECT NAME=\"wb_db\">\n");
+printf("  <OPTION SELECTED>%s</OPTION>\n", serverList->name);
+for (server = serverList->next; server != NULL; server = server->next)
+    printf("  <OPTION>%s</OPTION>\n", server->name);
+printf("</SELECT>\n");
+
+/* Put up query type control. */
+qType = cgiUsualString("wb_qType", queryMenu[0]);
+printf("Query Type: ");
+cgiMakeDropList("wb_qType", queryMenu, queryMenuSize, qType);
+printf("<BR>\n");
+
+/* Put up sort and output type controls. */
+printf("Sort By: ");
+cgiMakeDropList("wb_sort", sortMenu, ArraySize(sortMenu), sortMenu[0]);
+printf("Output: ");
+cgiMakeDropList("wb_output", outputMenu, ArraySize(outputMenu), outputMenu[0]);
+cgiMakeButton("Submit", "Submit");
+printf("<BR>\n");
+
+cgiMakeTextArea("wb_seq", "", 10, 60);
+printf("<BR>\n");
+
+printf("Please paste in some sequence and press submit. You can submit multiple "
+       "sequences at once if they are in fasta format (where each sequence has "
+       "a header line that starts with > and contains the name of the sequence)");
+
+printf("</FORM>");
+}
+
+void webBlat()
+/* Parse out CGI variables and decide which page to put up. */
+{
+if (cgiVarExists("wb_help"))
+    htmShell("Web BLAT Help", doHelp, NULL);
+else if (cgiVarExists("wb_seq"))
+    htmShell("Web BLAT Results", doBlat, NULL);
+else if (cgiVarExists("wb_doDetailLine"))
+    {
+    puts("Content-Type:text/html");
+    puts("\n");
+    doDetailLine();
+    }
+else
+    htmShell("Web BLAT", doGetSeq, NULL);
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+boolean isFromWeb = cgiIsOnWeb();
+htmlPushEarlyHandlers();
+dnaUtilOpen();
+if (!isFromWeb && !cgiSpoof(&argc, argv))
+    usage();
+cfg = gfWebConfigRead("webBlat.cfg");
+if (cfg->tempDir == NULL)
+    errAbort("No tempDir set in webBlat.cfg");
+if (cfg->background != NULL)
+    htmlSetBackground(cfg->background);
+webBlat();
+return 0;
+}
diff --git a/webBlat/webBlat.cfg b/webBlat/webBlat.cfg
new file mode 100644
index 0000000..a95b270
--- /dev/null
+++ b/webBlat/webBlat.cfg
@@ -0,0 +1,16 @@
+# Web BLAT Configuration File
+
+# Company is displayed at the title.
+company Kent Informatics
+
+# Web page background,  ok to have none
+background ../images/floret.jpg
+
+# List of databases and where to find index server and DNA files.
+gfServer blat12 17779 /cluster/data/hg17/nib Human Genome (build 35)
+gfServerTrans blat12 17778 /cluster/data/hg17/nib Human Genome (build 35)
+gfServer blat10 17779 /cluster/data/mm4/nib Mouse Genome (mm4)
+gfServerTrans blat10 17778 /cluster/data/mm4/nib Mouse Genome (mm4)
+
+# Where to put temporary files relative to CGI
+tempDir ../trash

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/blat.git



More information about the debian-med-commit mailing list