summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Smedegaard <dr@jones.dk>2009-08-14 09:20:29 +0200
committerJonas Smedegaard <dr@jones.dk>2009-08-14 09:20:29 +0200
commit88b315ccee666385e1a4c52e2eb5fb0b0ffe8d60 (patch)
tree53a5d7e250479fb7e8b2a48dd75093d8c569b233
Imported Upstream version 1.2.1
-rw-r--r--BUGS2
-rw-r--r--COPYING340
-rw-r--r--COPYRIGHT97
-rw-r--r--INSTALL331
-rw-r--r--Makefile300
-rw-r--r--README1122
-rw-r--r--Setup.hs65
-rw-r--r--changelog1940
-rw-r--r--data/LaTeXMathML.js.comment16
-rw-r--r--data/LaTeXMathML.js.packed191
-rw-r--r--data/headers/ConTeXt.header70
-rw-r--r--data/headers/Docbook.header3
-rw-r--r--data/headers/LaTeX.header8
-rw-r--r--data/headers/OpenDocument.header1
-rw-r--r--data/headers/RTF.header4
-rw-r--r--data/headers/S5.header3
-rw-r--r--data/odt-styles/META-INF/manifest.xml22
-rw-r--r--data/odt-styles/Thumbnails/thumbnail.pngbin0 -> 1943 bytes
-rw-r--r--data/odt-styles/meta.xml1
-rw-r--r--data/odt-styles/mimetype1
-rw-r--r--data/odt-styles/settings.xml2
-rw-r--r--data/odt-styles/styles.xml2
-rw-r--r--data/ui/default/framing.css23
-rw-r--r--data/ui/default/opera.css7
-rw-r--r--data/ui/default/outline.css15
-rw-r--r--data/ui/default/pretty.css86
-rw-r--r--data/ui/default/print.css24
-rw-r--r--data/ui/default/s5-core.css9
-rw-r--r--data/ui/default/slides.js.comment4
-rw-r--r--data/ui/default/slides.js.packed74
-rwxr-xr-xhsmarkdown5
-rwxr-xr-xhtml2markdown221
-rw-r--r--man/man1/hsmarkdown.1.md42
-rw-r--r--man/man1/html2markdown.1.md95
-rw-r--r--man/man1/markdown2pdf.1.md69
-rw-r--r--man/man1/pandoc.1.md222
-rwxr-xr-xmarkdown2pdf140
-rw-r--r--pandoc.cabal245
-rw-r--r--src/Text/Pandoc.hs117
-rw-r--r--src/Text/Pandoc/Biblio.hs66
-rw-r--r--src/Text/Pandoc/Blocks.hs146
-rw-r--r--src/Text/Pandoc/CharacterReferences.hs327
-rw-r--r--src/Text/Pandoc/DefaultHeaders.hs69
-rw-r--r--src/Text/Pandoc/Definition.hs150
-rw-r--r--src/Text/Pandoc/Highlighting.hs67
-rw-r--r--src/Text/Pandoc/LaTeXMathML.hs14
-rw-r--r--src/Text/Pandoc/ODT.hs88
-rw-r--r--src/Text/Pandoc/Readers/HTML.hs677
-rw-r--r--src/Text/Pandoc/Readers/LaTeX.hs778
-rw-r--r--src/Text/Pandoc/Readers/Markdown.hs1245
-rw-r--r--src/Text/Pandoc/Readers/RST.hs706
-rw-r--r--src/Text/Pandoc/Readers/TeXMath.hs233
-rw-r--r--src/Text/Pandoc/Shared.hs1030
-rw-r--r--src/Text/Pandoc/TH.hs65
-rw-r--r--src/Text/Pandoc/Writers/ConTeXt.hs302
-rw-r--r--src/Text/Pandoc/Writers/Docbook.hs274
-rw-r--r--src/Text/Pandoc/Writers/HTML.hs493
-rw-r--r--src/Text/Pandoc/Writers/LaTeX.hs331
-rw-r--r--src/Text/Pandoc/Writers/Man.hs334
-rw-r--r--src/Text/Pandoc/Writers/Markdown.hs399
-rw-r--r--src/Text/Pandoc/Writers/MediaWiki.hs396
-rw-r--r--src/Text/Pandoc/Writers/OpenDocument.hs568
-rw-r--r--src/Text/Pandoc/Writers/RST.hs349
-rw-r--r--src/Text/Pandoc/Writers/RTF.hs291
-rw-r--r--src/Text/Pandoc/Writers/S5.hs157
-rw-r--r--src/Text/Pandoc/Writers/Texinfo.hs474
-rw-r--r--src/Text/Pandoc/XML.hs88
-rw-r--r--src/hsmarkdown.hs43
-rw-r--r--src/markdown2pdf.hs198
-rw-r--r--src/pandoc.hs652
-rw-r--r--tests/Diff.hs76
-rw-r--r--tests/RunTests.hs163
-rw-r--r--tests/bodybg.gifbin0 -> 10119 bytes
-rw-r--r--tests/html-reader.html463
-rw-r--r--tests/html-reader.native346
-rw-r--r--tests/insert1
-rw-r--r--tests/lalune.jpgbin0 -> 16270 bytes
-rw-r--r--tests/latex-reader.latex830
-rw-r--r--tests/latex-reader.native378
-rw-r--r--tests/lhs-test.fragment.html+lhs51
-rw-r--r--tests/lhs-test.html79
-rw-r--r--tests/lhs-test.html+lhs85
-rw-r--r--tests/lhs-test.latex38
-rw-r--r--tests/lhs-test.latex+lhs38
-rw-r--r--tests/lhs-test.markdown21
-rw-r--r--tests/lhs-test.markdown+lhs22
-rw-r--r--tests/lhs-test.native11
-rw-r--r--tests/lhs-test.rst26
-rw-r--r--tests/lhs-test.rst+lhs24
-rw-r--r--tests/markdown-reader-more.native17
-rw-r--r--tests/markdown-reader-more.txt49
-rw-r--r--tests/movie.jpgbin0 -> 1046 bytes
-rw-r--r--tests/rst-reader.native245
-rw-r--r--tests/rst-reader.rst448
-rw-r--r--tests/s5.basic.html343
-rw-r--r--tests/s5.fancy.html527
-rw-r--r--tests/s5.fragment.html45
-rw-r--r--tests/s5.inserts.html66
-rw-r--r--tests/s5.native9
-rw-r--r--tests/tables.context134
-rw-r--r--tests/tables.docbook287
-rw-r--r--tests/tables.html207
-rw-r--r--tests/tables.latex139
-rw-r--r--tests/tables.man207
-rw-r--r--tests/tables.markdown60
-rw-r--r--tests/tables.mediawiki123
-rw-r--r--tests/tables.native84
-rw-r--r--tests/tables.opendocument466
-rw-r--r--tests/tables.rst71
-rw-r--r--tests/tables.rtf281
-rw-r--r--tests/tables.texinfo124
-rw-r--r--tests/tables.txt57
-rw-r--r--tests/testsuite.native387
-rw-r--r--tests/testsuite.txt683
-rw-r--r--tests/writer.context884
-rw-r--r--tests/writer.docbook1368
-rw-r--r--tests/writer.html1184
-rw-r--r--tests/writer.latex802
-rw-r--r--tests/writer.man790
-rw-r--r--tests/writer.markdown709
-rw-r--r--tests/writer.mediawiki604
-rw-r--r--tests/writer.native387
-rw-r--r--tests/writer.opendocument1576
-rw-r--r--tests/writer.rst852
-rw-r--r--tests/writer.rtf431
-rw-r--r--tests/writer.texinfo960
126 files changed, 35187 insertions, 0 deletions
diff --git a/BUGS b/BUGS
new file mode 100644
index 000000000..5ed2c9a34
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,2 @@
+To view a list of known bugs, or to enter a bug report, please use
+Pandoc's issue tracker: <http://code.google.com/p/pandoc/issues/list>
diff --git a/COPYING b/COPYING
new file mode 100644
index 000000000..8bfde75cb
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 000000000..798a196c2
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,97 @@
+Pandoc
+Copyright (C) 2006-8 John MacFarlane <jgm at berkeley dot edu>
+
+This code is released under the [GPL], version 2 or later:
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+The GNU General Public License is available in the file COPYING in
+the source distribution. On Debian systems, the complete text of the
+GPL can be found in `/usr/share/common-licenses/GPL`.
+
+[GPL]: http://www.gnu.org/copyleft/gpl.html
+
+Pandoc's complete source code is available from the [Pandoc home page].
+
+[Pandoc home page]: http://johnmacfarlane.net/pandoc/
+
+Pandoc includes some code from other authors. The copyright and license
+statements for these sources are included below. All are GPL-compatible
+licenses.
+
+----------------------------------------------------------------------
+Text/Pandoc/Writers/Texinfo.hs
+Copyright (C) 2008 John MacFarlane and Peter Wang
+
+Released under the GPL.
+
+----------------------------------------------------------------------
+Text/Pandoc/Writers/OpenDocument.hs
+Copyright (C) 2008 Andrea Rossato
+
+Released under the GPL.
+
+----------------------------------------------------------------------
+ASCIIMathML.js
+Copyright 2005, Peter Jipsen, Chapman University
+<http://www1.chapman.edu/~jipsen/mathml/asciimath.html>
+
+Released under the GPL.
+
+----------------------------------------------------------------------
+S5 slides.js and css files
+by Eric A. Meyer
+<http://meyerweb.com/eric/tools/s5
+
+Released under an explicit Public Domain License
+
+------------------------------------------------------------------------
+Diff.hs in tests/
+from the Diff package v 0.1.2 (Data.Algorithm.Diff)
+Copyright (c) Stering Clover 2008
+
+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 of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form 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.
+3. Neither the name of the author nor the names of his contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS 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.
+
+------------------------------------------------------------------------
+windows/modpath.iss
+Copyright (c) 2007 Jared Breland
+http://legroom.net/software
+
+Released under the GPL.
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 000000000..b4f7d2a7b
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,331 @@
+% Installing pandoc
+
+Installing pandoc from Source
+=============================
+
+This method will work on all architectures for which the GHC compiler
+is available.
+
+Installing GHC
+--------------
+
+To compile Pandoc, you'll need [GHC] version 6.8 or greater. If you
+don't have GHC already, you can get it from the [GHC Download] page.
+If you're compiling GHC from source, be sure to get the `extralibs`
+in addition to the base tarball. Pandoc requires Cabal version 1.2 or
+greater. If your GHC comes with an older version of Cabal, you'll need
+to to [install Cabal] separately. You can check your Cabal version using
+`ghc-pkg list`.
+
+If you're running MacOS X, you can also install GHC using [MacPorts] or [Fink].
+
+If you're on a [debian]-based linux system (such as [Ubuntu]), you can get
+GHC and some required libraries using `apt-get`:
+
+ sudo apt-get install ghc6 libghc6-xhtml-dev libghc6-mtl-dev libghc6-network-dev
+
+[GHC]: http://www.haskell.org/ghc/
+[GHC Download]: http://www.haskell.org/ghc/download.html
+[Cabal]: http://www.haskell.org/cabal/
+[install Cabal]: http://www.haskell.org/cabal/download.html
+[MacPorts]: http://macports.org
+[Fink]: http://finkproject.org
+[Ubuntu]: http://www.ubuntu.com
+[debian]: http://www.debian.org/
+
+Installing prerequisites
+------------------------
+
+Pandoc needs the `utf8-string` and `zip-archive` to compile.
+Check your packaging system to see if they are included.
+If not, you will need to compile them from source.
+
+On \*nix systems, the easiest way to do this is to install
+the [cabal-install] tool. See the section [Quick Installation
+on Unix] for instructions. If you use [MacPorts], you can
+just install the `hs-cabal` port.
+
+[cabal-install]: http://hackage.haskell.org/trac/hackage/wiki/CabalInstall
+[Quick Installation on Unix]: http://hackage.haskell.org/trac/hackage/wiki/CabalInstall#QuickInstallationonUnix
+
+Once you've got `cabal-install` installed, you can install the
+needed libraries by doing
+
+ cabal install utf8-string
+ cabal install zip-archive
+
+Alternatively, you can install these libraries using the [standard
+Cabal method], but you will have to install their dependencies manually.
+
+[standard Cabal method]: http://haskell.org/haskellwiki/Cabal/How_to_install_a_Cabal_package
+
+Getting the source
+------------------
+
+Download the source tarball from [pandoc's google code site].
+Extract the contents into a subdirectory:
+
+ tar xvzf pandoc-x.y.tar.gz
+
+[pandoc's google code site]: http://pandoc.googlecode.com
+
+Now choose one of the following methods for compiling and installing
+pandoc. If you are on a linux or unix-based system, you can [install
+pandoc using Make]. If not, you should [install pandoc using Cabal].
+
+[install pandoc using Make]: #installing-pandoc-using-make
+[install pandoc using Cabal]: #installing-pandoc-using-cabal
+[build options]: #build-options
+
+Installing Pandoc using Make
+----------------------------
+
+1. Change to the directory containing the Pandoc distribution.
+
+2. Compile:
+
+ make
+
+ If you get "Unknown modifier" errors, it is probably because `make`
+ on your system is not [GNU `make`]. Try using `gmake` instead.
+
+ If you get a message saying that the `zip-archive` or `utf8-string`
+ libraries cannot be found, and you have installed these using
+ `cabal-install`, it is probably because by default `cabal-install`
+ installs libraries to the user's directory rather than globally.
+ Try again with
+
+ CABALOPTS=--user make
+
+3. See if it worked (optional, but recommended):
+
+ make test
+
+4. Install:
+
+ sudo make install
+
+ Note: This installs `pandoc`, together with its wrappers and
+ documentation, into the `/usr/local` directory. If you'd rather
+ install `pandoc` somewhere else--say, in `/opt/local`--you can
+ set the `PREFIX` environment variable:
+
+ PREFIX=/opt/local sudo make install
+
+ If you don't have root privileges or would prefer to install
+ `pandoc` and the associated wrappers into your `~/bin` directory,
+ type this instead:
+
+ PREFIX=~ make install-exec
+
+5. Build and install the Haskell libraries and library
+ documentation (optional--for Haskell programmers only):
+
+ make build-all
+ sudo make install-all
+
+ Note that building the library documentation requires [haddock].
+
+6. If you decide you don't want pandoc on your system, each of the
+ installation steps described above can be reversed:
+
+ sudo make uninstall
+
+ PREFIX=~ make uninstall-exec
+
+ sudo make uninstall-all
+
+[haddock]: http://www.haskell.org/haddock/
+
+Installing pandoc using Cabal
+-----------------------------
+
+Change to the directory containing the pandoc source, and type:
+
+ runhaskell Setup configure # add --user if you have installed prerequisites
+ # locally using cabal-install
+ runhaskell Setup build
+ runhaskell Setup haddock # optional, to build library documentation
+ runhaskell Setup test # optional, to run test suite
+ runhaskell Setup install # this one as root or sudo, or add --user
+
+This will install the pandoc executable and the Haskell libraries,
+but not the shell scripts, man pages, or other documentation.
+
+You may just want the executable, or just the libraries. This
+can be controlled with configuration flags (the `-` negates the
+flag):
+
+ runhaskell Setup configure -f-library # just the executable
+ runhaskell Setup configure -f-executable # just the libraries
+
+You can also specify the directory tree into which pandoc will be
+installed using the `--prefix=` option to `configure`. For more details,
+see the [Cabal User's Guide].
+
+[Cabal User's Guide]: http://www.haskell.org/cabal/release/latest/doc/users-guide/builders.html#setup-configure-paths
+
+Optional syntax highlighting support
+------------------------------------
+
+Pandoc can optionally be compiled with support for syntax highlighting of
+delimited code blocks. This feature requires the [`highlighting-kate` library].
+If you are using Cabal to compile pandoc, specify the `highlighting` flag in
+the configure step:
+
+ runhaskell Setup configure -fhighlighting
+
+If you are using the Makefile:
+
+ CABALOPTS=-fhighlighting make
+
+If you have already built pandoc, you may need to do a `make clean` or
+`runhaskell Setup clean` first.
+
+[`highlighting-kate` library]: http://johnmacfarlane.net/highlighting-kate
+
+Optional citeproc support
+-------------------------
+
+Pandoc can optionally be compiled with support for bibliographic citations
+using Andrea Rossato's [`citeproc-hs` library]. This allows you
+to specify citations in markdown using an intuitive syntax (for example,
+`[jones2005@p. 3; smith2006]`). These are automatically changed into
+appropriately styled citations in the output, and a bibliography is
+added. The bibliography data and style information are taken from XML
+files that must be specified on the command line. (Note: `citeproc-hs`
+support is experimental, and the interface may change in the future.)
+
+If you are using Cabal to compile pandoc, specify the `citeproc` flag in
+the configure step:
+
+ runhaskell Setup configure -fciteproc
+
+If you are using the Makefile:
+
+ CABALOPTS=-fciteproc make
+
+If you have already built pandoc, you may need to do a `make clean` or
+`runhaskell Setup clean` first.
+
+[`citeproc-hs` library]: http://code.haskell.org/citeproc-hs/
+
+Other targets
+-------------
+
+The following 'make' targets should not be needed by the average user,
+but are documented here for packagers and developers:
+
+### Building and installing
+
+* `configure`:
+ - Stores values of relevant environment variables in `vars` for
+ persistence.
+ - Runs Cabal's "configure" command.
+* `build-exec`: Builds `pandoc` executable (using Cabal's "build"
+ command).
+* `build-doc`: Builds program documentation (e.g. `README.html`).
+* `build-lib-doc`: Builds Haddock documentation for Pandoc libraries.
+* `install-doc`, `uninstall-doc`: Installs/uninstalls user documentation
+ and man pages.
+* `install-lib-doc`, `uninstall-lib-doc`: Installs/uninstalls library
+ documentation and man pages.
+* `install-exec`, `uninstall-exec`: Installs/uninstalls programs
+ (`pandoc` and wrappers).
+
+### Testing
+
+* `test`: Runs Pandoc's test suite. (All tests should pass.)
+* `test-markdown`: Runs the Markdown regression test suite, using
+ `pandoc --strict`. (One test will fail.)
+
+### Cleaning
+
+* `clean`: Restores directory to pre-build state, removing generated files.
+* `distclean`: Like clean, but also cleans up files created by `make deb`.
+
+### Packaging
+
+* `tarball`: Creates a source tarball for distribution.
+* `macport`: Creates MacPorts Portfile in `macports` directory.
+* `freebsd`: Creates freebsd Makefile and distinfo in `freebsd` directory.
+* `win-pkg`: Creates a Windows binary package (presupposes `pandoc.exe`,
+ which must be created by building Pandoc on a Windows machine).
+* `website`: Creates Pandoc's website in `web/pandoc` directory.
+
+Installing pandoc using MacPorts
+================================
+
+This is an alternative to compiling from source on MacOS X.
+[MacPorts] is a system for building and maintaining \*nix software
+on MacOS X computers. If you don't already have MacPorts, follow
+[these instructions for installing
+it](http://trac.macosforge.org/projects/macports/wiki/InstallingMacPorts).
+
+Once you've installed MacPorts, you can install pandoc by typing:
+
+ sudo port sync # to get the most recent ports
+ sudo port install pandoc
+
+Since pandoc depends on GHC, the process may take a long time.
+
+Note that the version of pandoc in MacPorts may not be the most recent.
+To get the most recent version, you can use `cabal-install`:
+
+ sudo port install hs-cabal
+ cabal install pandoc --user # optionally: -fciteproc -fhighlighting
+
+This will install the `pandoc` executable into `~/.cabal/bin`. This method
+will not install the wrapper scripts or man pages; if you want those, follow
+the instructions above for compiling from source.
+
+Installing the Windows binary
+=============================
+
+Simply download the Windows installer [pandoc's google code site]
+and run it. It will install `pandoc.exe` and ensure that it is
+in your system PATH.
+
+Note that the Windows binary distribution does not include the shell
+scripts `markdown2pdf`, `html2markdown`, or `hsmarkdown`.
+
+Installing pandoc on Debian
+===========================
+
+Pandoc is now in the debian archives, and can be installed using `apt-get` (as root):
+
+ apt-get install pandoc # the program, shell scripts, and docs
+ apt-get install libghc6-pandoc-dev # the libraries
+ apt-get install pandoc-doc # library documentation
+
+Thanks to Recai Oktaş for setting up the debian packages.
+
+Note that the version of pandoc in Debian may not be the most recent.
+
+Installing pandoc on FreeBSD
+============================
+
+Pandoc is in the FreeBSD ports repository (`textproc/pandoc`) and can be
+installed in the normal way:
+
+ cd /usr/ports/textproc/pandoc
+ make install clean # as root
+
+Alternatively, you can use `pkg_add`:
+
+ pkg_add -r pandoc
+
+Note that the version of pandoc in FreeBSD's official repository may be
+somewhat older than the most recent version.
+
+Installing pandoc on Arch linux
+===============================
+
+There are two `pandoc` packages in the Arch AUR repositories,
+`pandoc` (contributed by Abhishek Dasgupta) and `haskell-pandoc`
+(contributed by Dons Stewart). `haskell-pandoc` is more up-to-date,
+but does not install the man pages or wrapper scripts.
+
+ pacman -Sy pandoc
+ pacman -Sy haskell-pandoc
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000..e6972ac50
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,300 @@
+# Makefile for Pandoc.
+
+#-------------------------------------------------------------------------------
+# Constant names and commands in source tree
+#-------------------------------------------------------------------------------
+CABAL := pandoc.cabal
+SRCDIR := src
+MANDIR := man
+TESTDIR := tests
+BUILDDIR := dist
+BUILDCONF := $(BUILDDIR)/setup-config
+BUILDVARS := vars
+CONFIGURE := configure
+
+#-------------------------------------------------------------------------------
+# Cabal constants
+#-------------------------------------------------------------------------------
+PKG := $(shell sed -ne 's/^[Nn]ame:[[:space:]]*//p' $(CABAL) | tr A-Z a-z)
+VERSION := $(shell sed -ne 's/^[Vv]ersion:[[:space:]]*//p' $(CABAL))
+PKGID := $(PKG)-$(VERSION)
+EXECSBASE := $(shell sed -ne 's/^[Ee]xecutable:\{0,1\}[[:space:]]*//p' $(CABAL))
+
+#-------------------------------------------------------------------------------
+# Install targets
+#-------------------------------------------------------------------------------
+WRAPPERS := html2markdown hsmarkdown markdown2pdf
+# Add .exe extensions if we're running Windows/Cygwin.
+EXTENSION := $(shell uname | tr '[:upper:]' '[:lower:]' | \
+ sed -ne 's/^cygwin.*$$/\.exe/p')
+BUILDCMD := $(addsuffix $(EXTENSION), ./setup)
+EXECS := $(addsuffix $(EXTENSION),$(EXECSBASE))
+PROGS := $(EXECS) $(WRAPPERS)
+MAIN := $(firstword $(EXECS))
+DOCS := README.html README BUGS
+MANPAGES := $(patsubst %.md,%,$(wildcard $(MANDIR)/man?/*.?.md))
+
+#-------------------------------------------------------------------------------
+# Variables to setup through environment
+#-------------------------------------------------------------------------------
+
+# Specify default values.
+prefix := /usr/local
+destdir :=
+# Attempt to set variables from a previous make session.
+-include $(BUILDVARS)
+# Fallback to defaults but allow to get the values from environment.
+PREFIX ?= $(prefix)
+DESTDIR ?= $(destdir)
+DATADIR ?= $(PKGID)
+DOCDIR ?= $(PKGID)/doc
+
+#-------------------------------------------------------------------------------
+# Installation paths
+#-------------------------------------------------------------------------------
+DESTPATH := $(DESTDIR)$(PREFIX)
+BINPATH := $(DESTPATH)/bin
+DATAPATH := $(DESTPATH)/share
+MANPATH := $(DATAPATH)/man
+PKGDATAPATH := $(DATAPATH)/$(DATADIR)
+PKGDOCPATH := $(DATAPATH)/$(DOCDIR)
+
+#-------------------------------------------------------------------------------
+# Generic Makefile variables
+#-------------------------------------------------------------------------------
+INSTALL := install -c
+INSTALL_PROGRAM := $(INSTALL) -m 755
+INSTALL_DATA := $(INSTALL) -m 644
+STRIP := strip
+GHC ?= ghc
+GHC_VERSION := $(shell $(GHC) --version | sed -e 's/[^0-9]*//')
+
+#-------------------------------------------------------------------------------
+# Recipes
+#-------------------------------------------------------------------------------
+
+# Default target.
+.PHONY: all
+all: build-program
+
+# Document process rules.
+%.html: % $(MAIN)
+ ./$(MAIN) -s -S --toc $< >$@ || rm -f $@
+%.tex: % $(MAIN)
+ ./$(MAIN) -s -w latex $< >$@ || rm -f $@
+%.rtf: % $(MAIN)
+ ./$(MAIN) -s -w rtf $< >$@ || rm -f $@
+%.pdf: % $(MAIN) markdown2pdf
+ sh ./markdown2pdf $< || rm -f $@
+%.txt: %
+ perl -p -e 's/\n/\r\n/' $< > $@ || rm -f $@ # convert to DOS line endings
+
+.PHONY: configure
+cleanup_files+=Setup.hi Setup.o $(BUILDCMD) $(BUILDVARS)
+ifdef GHC_PKG
+ hc_pkg = --with-hc-pkg=$(GHC_PKG)
+else
+ hc_pkg =
+endif
+templates=$(wildcard templates/*.* templates/headers/*.* templates/ui/default/*.*)
+configure: $(BUILDCONF)
+$(BUILDCMD): Setup.hs
+ $(GHC) -package Cabal Setup.hs -o $(BUILDCMD)
+$(BUILDCONF): $(CABAL) $(CABAL_BACKUP) $(BUILDCMD) $(templates)
+ $(BUILDCMD) configure --prefix=$(PREFIX) --with-compiler=$(GHC) $(hc_pkg) $(CABALOPTS)
+ @# Make configuration time settings persistent (definitely a hack).
+ @echo "PREFIX?=$(PREFIX)" >$(BUILDVARS)
+ @echo "DESTDIR?=$(DESTDIR)" >>$(BUILDVARS)
+
+.PHONY: build
+build: configure
+ $(BUILDCMD) build
+
+.PHONY: build-exec
+build-exec: $(PROGS)
+cleanup_files+=$(EXECS)
+$(EXECS): build
+ for f in $@; do \
+ find $(BUILDDIR) -type f -name "$$f" -perm +a=x \
+ -exec ln -s -f {} . \; ; \
+ done
+
+.PHONY: build-doc
+cleanup_files+=README.html $(MANPAGES)
+build-doc: $(DOCS) $(MANPAGES)
+
+.PHONY: build-program
+build-program: build-exec build-doc
+
+.PHONY: build-lib-doc haddock
+build-lib-doc: html
+haddock: build-lib-doc
+cleanup_files+=html
+html/: configure
+ -rm -rf html
+ $(BUILDCMD) haddock && cp -r $(BUILDDIR)/doc/html .
+
+.PHONY: build-all
+build-all: build-program build-lib-doc
+
+# User documents installation.
+.PHONY: install-doc uninstall-doc
+man_all:=$(patsubst $(MANDIR)/%,%,$(MANPAGES))
+install-doc: build-doc
+ $(INSTALL) -d $(PKGDOCPATH) && $(INSTALL_DATA) $(DOCS) $(PKGDOCPATH)/
+ for f in $(man_all); do \
+ $(INSTALL) -d $(MANPATH)/$$(dirname $$f); \
+ $(INSTALL_DATA) $(MANDIR)/$$f $(MANPATH)/$$f; \
+ done
+uninstall-doc:
+ -for f in $(DOCS); do rm -f $(PKGDOCPATH)/$$f; done
+ -for f in $(man_all); do rm -f $(MANPATH)/$$f; done
+ rmdir $(PKGDOCPATH) 2>/dev/null ||:
+
+# Program only installation.
+.PHONY: install-exec uninstall-exec
+install-exec: build-exec
+ $(STRIP) $(EXECS)
+ $(INSTALL) -d $(BINPATH); \
+ for f in $(PROGS); do \
+ if [ -L $$f ]; then \
+ f=$$(readlink $$f); \
+ fi; \
+ $(INSTALL_PROGRAM) $$f $(BINPATH)/; \
+ done
+uninstall-exec:
+ -for f in $(notdir $(PROGS)); do rm -f $(BINPATH)/$$f; done
+
+# Program + user documents installation.
+.PHONY: install-program uninstall-program
+install-program: install-exec install-doc
+uninstall-program: uninstall-exec uninstall-doc
+
+.PHONY: install-all uninstall-all
+# Full installation through Cabal: main + wrappers + user docs + lib + lib docs
+install-all: build-all install-program
+ destdir=$(DESTDIR); \
+ # Older Cabal versions have no '--destdir' option.
+ if $(BUILDCMD) copy --help | grep -q '\-\-destdir'; then \
+ opt="--destdir=$${destdir-/}"; \
+ else \
+ opt="--copy-prefix=$${destdir}$(PREFIX)"; \
+ fi; \
+ $(BUILDCMD) copy $$opt; $(BUILDCMD) register
+# Cabal lacks an 'uninstall' command. We have to remove some cruft manually.
+uninstall-all: uninstall-program configure
+ @libdir=$$($(GHC_PKG) field $(PKGID) library-dirs 2>/dev/null | \
+ sed 's/^library-dirs: *//'); \
+ htmldir=$$($(GHC_PKG) field $(PKGID) haddock-html 2>/dev/null | \
+ sed 's/^haddock-html: *//'); \
+ if [ -d $$libdir ]; then \
+ $(BUILDCMD) unregister ||:; \
+ else \
+ echo >&2 "*** Couldn't locate library for pkgid: $(PKGID). ***"; \
+ fi; \
+ for d in $$libdir $$htmldir; do \
+ [ -d $$d ] && { \
+ rm -rf $$d; rmdir $$(dirname $$d) 2>/dev/null ||:; \
+ } \
+ done; \
+ rmdir $(PKGDOCPATH) $(PKGDATAPATH) 2>/dev/null ||:
+
+# Default installation recipe for a common deployment scenario.
+.PHONY: install uninstall
+install: install-program
+uninstall: uninstall-program
+
+# FreeBSD port
+.PHONY: freebsd
+freebsd_dest:=freebsd
+freebsd_makefile:=$(freebsd_dest)/Makefile
+freebsd_template:=$(freebsd_makefile).in
+cleanup_files+=$(freebsd_makefile)
+freebsd : $(freebsd_makefile)
+$(freebsd_makefile) : $(freebsd_template)
+ sed -e 's/@VERSION@/$(VERSION)/' $< > $@
+
+# MacPort
+.PHONY: macport
+macport_dest:=macports
+portfile:=$(macport_dest)/Portfile
+portfile_template:=$(portfile).in
+cleanup_files+=$(portfile)
+macport : $(portfile)
+$(portfile) : $(portfile_template) tarball
+ sed -e 's/@VERSION@/$(VERSION)/' $(portfile_template) | \
+ sed -e 's/@TARBALLMD5SUM@/$(word 2, $(shell openssl md5 $(tarball)))/' > \
+ $(portfile)
+
+.PHONY: win-pkg
+win_pkg_name:=$(PKGID).zip
+win_docs:=COPYING.txt COPYRIGHT.txt BUGS.txt README.txt README.html
+cleanup_files+=$(win_pkg_name) $(win_docs)
+win-pkg: $(win_pkg_name)
+$(win_pkg_name): $(PKG).exe $(win_docs)
+ zip -r $(win_pkg_name) $(PKG).exe $(win_docs)
+
+.PHONY: test test-markdown
+test: $(MAIN)
+ $(BUILDCMD) test
+compat:=$(PWD)/hsmarkdown
+markdown_test_dirs:=$(wildcard $(TESTDIR)/MarkdownTest_*)
+test-markdown: $(MAIN) $(compat)
+ @for suite in $(markdown_test_dirs); do \
+ ( \
+ suite_version=$$(echo $$suite | sed -e 's/.*_//');\
+ echo >&2 "-----------------------------------------";\
+ echo >&2 "Running Markdown test suite version $${suite_version}.";\
+ PATH=$(PWD):$$PATH; export PATH; cd $$suite && \
+ perl MarkdownTest.pl -s $(compat) -tidy ; \
+ ) \
+ done
+
+# Stolen and slightly improved from a GPLed Makefile. Credits to John Meacham.
+src_all:=$(shell find $(SRCDIR) -type f -name '*hs' | egrep -v '^\./(_darcs|lib|test)/')
+cleanup_files+=$(patsubst %,$(SRCDIR)/%,tags tags.sorted)
+tags: $(src_all)
+ cd $(SRCDIR) && hasktags -c $(src_all:$(SRCDIR)/%=%); \
+ LC_ALL=C sort tags >tags.sorted; mv tags.sorted tags
+
+.PHONY: tarball
+tarball:=$(PKGID).tar.gz
+cleanup_files+=$(tarball)
+tarball: $(tarball)
+$(tarball):
+ $(BUILDCMD) sdist
+ cp $(BUILDDIR)/$(tarball) .
+
+.PHONY: website
+web_src:=web
+web_dest:=pandoc-website
+make_page:=./$(MAIN) -s -S -B $(web_src)/header.html \
+ -A $(web_src)/footer.html \
+ -H $(web_src)/css
+cleanup_files+=$(web_dest)
+$(web_dest) : html $(wildcard $(web_src)/*) changelog \
+ INSTALL $(MANPAGES) $(MANDIR)/man1/pandoc.1.md README
+ rm -rf $(web_dest) && { \
+ mkdir $(web_dest); \
+ cp -r html $(web_dest)/doc; \
+ cp $(web_src)/* $(web_dest)/; \
+ sed -e 's#@VERSION@#$(VERSION)#g' $(web_src)/index.txt.in > \
+ $(web_dest)/index.txt; \
+ cp changelog $(web_dest)/changelog.txt ; \
+ cp README $(web_dest)/ ; \
+ cp INSTALL $(web_dest)/ ; \
+ cp $(MANDIR)/man1/pandoc.1.md $(web_dest)/ ; \
+ cp $(MANPAGES) $(web_dest)/ ; \
+ } || { rm -rf $(web_dest); exit 1; }
+website: $(MAIN) $(web_dest)
+ PANDOC_PATH=$(shell pwd) make -C $(web_dest)
+
+.PHONY: distclean clean
+distclean: clean
+ if [ -d debian ]; then \
+ chmod +x debian/rules; fakeroot debian/rules clean; \
+ fi
+
+clean:
+ -if [ -f $(BUILDCONF) ]; then $(BUILDCMD) clean; fi
+ -rm -rf $(cleanup_files)
diff --git a/README b/README
new file mode 100644
index 000000000..6ee7a96c1
--- /dev/null
+++ b/README
@@ -0,0 +1,1122 @@
+% Pandoc User's Guide
+% John MacFarlane
+% March 24, 2008
+
+Pandoc is a [Haskell] library for converting from one markup format to
+another, and a command-line tool that uses this library. It can read
+[markdown] and (subsets of) [reStructuredText], [HTML], and [LaTeX]; and
+it can write [markdown], [reStructuredText], [HTML], [LaTeX], [ConTeXt],
+[RTF], [DocBook XML], [OpenDocument XML], [ODT], [GNU Texinfo],
+[MediaWiki markup], [groff man] pages, and [S5] HTML slide shows.
+Pandoc's enhanced version of markdown includes syntax for footnotes,
+tables, flexible ordered lists, definition lists, delimited code blocks,
+superscript, subscript, strikeout, title blocks, automatic tables of
+contents, embedded LaTeX math, and markdown inside HTML block elements.
+(These enhancements can be disabled if a drop-in replacement for
+`Markdown.pl` is desired.)
+
+In contrast to most existing tools for converting markdown to HTML, which
+use regex substitutions, Pandoc has a modular design: it consists of a
+set of readers, which parse text in a given format and produce a native
+representation of the document, and a set of writers, which convert
+this native representation into a target format. Thus, adding an input
+or output format requires only adding a reader or writer.
+
+[markdown]: http://daringfireball.net/projects/markdown/
+[reStructuredText]: http://docutils.sourceforge.net/docs/ref/rst/introduction.html
+[S5]: http://meyerweb.com/eric/tools/s5/
+[HTML]: http://www.w3.org/TR/html40/
+[LaTeX]: http://www.latex-project.org/
+[ConTeXt]: http://www.pragma-ade.nl/
+[RTF]: http://en.wikipedia.org/wiki/Rich_Text_Format
+[DocBook XML]: http://www.docbook.org/
+[OpenDocument XML]: http://opendocument.xml.org/
+[ODT]: http://en.wikipedia.org/wiki/OpenDocument
+[MediaWiki markup]: http://www.mediawiki.org/wiki/Help:Formatting
+[groff man]: http://developer.apple.com/DOCUMENTATION/Darwin/Reference/ManPages/man7/groff_man.7.html
+[Haskell]: http://www.haskell.org/
+[GNU Texinfo]: http://www.gnu.org/software/texinfo/
+
+© 2006-8 John MacFarlane (jgm at berkeley dot edu). Released under the
+[GPL], version 2 or greater. This software carries no warranty of
+any kind. (See COPYRIGHT for full copyright and warranty notices.)
+Contributors: Recai Oktaş (build system, debian package, wrapper
+scripts), Peter Wang (Texinfo writer), Andrea Rossato (OpenDocument writer).
+
+[GPL]: http://www.gnu.org/copyleft/gpl.html "GNU General Public License"
+
+Using Pandoc
+============
+
+If you run `pandoc` without arguments, it will accept input from
+stdin. If you run it with file names as arguments, it will take input
+from those files. By default, `pandoc` writes its output to stdout.[^1]
+If you want to write to a file, use the `-o` option:
+
+ pandoc -o hello.html hello.txt
+
+[^1]: The exception is for `odt`. Since this is a binary output format,
+ an output file must be specified explicitly.
+
+Note that you can specify multiple input files on the command line.
+`pandoc` will concatenate them all (with blank lines between them)
+before parsing:
+
+ pandoc -s ch1.txt ch2.txt refs.txt > book.html
+
+(The `-s` option here tells `pandoc` to produce a standalone HTML file,
+with a proper header, rather than a fragment. For more details on this
+and many other command-line options, see below.)
+
+The format of the input and output can be specified explicitly using
+command-line options. The input format can be specified using the
+`-r/--read` or `-f/--from` options, the output format using the
+`-w/--write` or `-t/--to` options. Thus, to convert `hello.txt` from
+markdown to LaTeX, you could type:
+
+ pandoc -f markdown -t latex hello.txt
+
+To convert `hello.html` from html to markdown:
+
+ pandoc -f html -t markdown hello.html
+
+Supported output formats include `markdown`, `latex`, `context`
+(ConTeXt), `html`, `rtf` (rich text format), `rst`
+(reStructuredText), `docbook` (DocBook XML), `opendocument`
+(OpenDocument XML), `odt` (OpenOffice text document), `texinfo`, (GNU
+Texinfo), `mediawiki` (MediaWiki markup), `man` (groff man), and `s5`
+(which produces an HTML file that acts like powerpoint).
+
+Supported input formats include `markdown`, `html`, `latex`, and `rst`.
+Note that the `rst` reader only parses a subset of reStructuredText
+syntax. For example, it doesn't handle tables, option lists, or
+footnotes. But for simple documents it should be adequate. The `latex`
+and `html` readers are also limited in what they can do. Because the
+`html` reader is picky about the HTML it parses, it is recommended that
+you pipe HTML through [HTML Tidy] before sending it to `pandoc`, or use
+the `html2markdown` script described below.
+
+If you don't specify a reader or writer explicitly, `pandoc` will
+try to determine the input and output format from the extensions of
+the input and output filenames. Thus, for example,
+
+ pandoc -o hello.tex hello.txt
+
+will convert `hello.txt` from markdown to LaTeX. If no output file
+is specified (so that output goes to stdout), or if the output file's
+extension is unknown, the output format will default to HTML.
+If no input file is specified (so that input comes from stdin), or
+if the input files' extensions are unknown, the input format will
+be assumed to be markdown unless explicitly specified.
+
+Character encodings
+-------------------
+
+All input is assumed to be in the UTF-8 encoding, and all output
+is in UTF-8. If your local character encoding is not UTF-8 and you use
+accented or foreign characters, you should pipe the input and output
+through [`iconv`]. For example,
+
+ iconv -t utf-8 source.txt | pandoc | iconv -f utf-8 > output.html
+
+will convert `source.txt` from the local encoding to UTF-8, then
+convert it to HTML, then convert back to the local encoding,
+putting the output in `output.html`.
+
+The shell scripts (described below) automatically convert the input
+from the local encoding to UTF-8 before running them through `pandoc`,
+then convert the output back to the local encoding.
+
+Shell scripts
+=============
+
+Three shell scripts, `markdown2pdf`, `html2markdown`, and `hsmarkdown`,
+are included in the standard Pandoc installation. (They are not included
+in the Windows binary package, as they require a POSIX shell, but they
+may be used in Windows under Cygwin.)
+
+1. `markdown2pdf` produces a PDF file from markdown-formatted
+ text, using `pandoc` and `pdflatex`. The default
+ behavior of `markdown2pdf` is to create a file with the same
+ base name as the first argument and the extension `pdf`; thus,
+ for example,
+
+ markdown2pdf sample.txt endnotes.txt
+
+ will produce `sample.pdf`. (If `sample.pdf` exists already,
+ it will be backed up before being overwritten.) An output file
+ name can be specified explicitly using the `-o` option:
+
+ markdown2pdf -o book.pdf chap1 chap2
+
+ If no input file is specified, input will be taken from stdin.
+ All of `pandoc`'s options will work with `markdown2pdf` as well.
+
+ `markdown2pdf` assumes that `pdflatex` is in the path. It also
+ assumes that the following LaTeX packages are available:
+ `unicode`, `fancyhdr` (if you have verbatim text in footnotes),
+ `graphicx` (if you use images), `array` (if you use tables),
+ and `ulem` (if you use strikeout text). If they are not already
+ included in your LaTeX distribution, you can get them from
+ [CTAN]. A full [TeX Live] or [MacTeX] distribution will have all of
+ these packages.
+
+2. `html2markdown` grabs a web page from a file or URL and converts
+ it to markdown-formatted text, using `tidy` and `pandoc`.
+
+ All of `pandoc`'s options will work with `html2markdown` as well.
+ In addition, the following special options may be used.
+ The special options must be separated from the `html2markdown`
+ command and any regular Pandoc options by the delimiter `--`:
+
+ html2markdown -o out.txt -- -e latin1 -g curl google.com
+
+ The `-e` or `--encoding` option specifies the character encoding
+ of the HTML input. If this option is not specified, and input
+ is not from stdin, `html2markdown` will attempt to determine the
+ page's character encoding from the "Content-type" meta tag.
+ If this is not present, UTF-8 is assumed.
+
+ The `-g` or `--grabber` option specifies the command to be used to
+ fetch the contents of a URL:
+
+ html2markdown -g 'curl --user foo:bar' www.mysite.com
+
+ If this option is not specified, `html2markdown` searches for an
+ available program (`wget`, `curl`, or a text-mode browser) to fetch
+ the contents of a URL.
+
+ `html2markdown` requires [HTML Tidy], which must be in the path.
+ It uses [`iconv`] for character encoding conversions; if `iconv`
+ is absent, it will still work, but it will treat everything as UTF-8.
+
+3. `hsmarkdown` is designed to be used as a drop-in replacement for
+ `Markdown.pl`. It forces `pandoc` to convert from markdown to
+ HTML, and to use the `--strict` flag for maximal compliance with
+ official markdown syntax. (All of Pandoc's syntax extensions and
+ variants, described below, are disabled.) No other command-line
+ options are allowed. (In fact, options will be interpreted as
+ filenames.)
+
+ As an alternative to using the `hsmarkdown` shell script, the
+ user may create a symbolic link to `pandoc` called `hsmarkdown`.
+ When invoked under the name `hsmarkdown`, `pandoc` will behave
+ as if the `--strict` flag had been selected, and no command-line
+ options will be recognized. However, this approach does not work
+ under Cygwin, due to problems with its simulation of symbolic
+ links.
+
+[Cygwin]: http://www.cygwin.com/
+[HTML Tidy]: http://tidy.sourceforge.net/
+[`iconv`]: http://www.gnu.org/software/libiconv/
+[CTAN]: http://www.ctan.org "Comprehensive TeX Archive Network"
+[TeX Live]: http://www.tug.org/texlive/
+[MacTeX]: http://www.tug.org/mactex/
+
+Command-line options
+====================
+
+Various command-line options can be used to customize the output.
+For further documentation, see the `pandoc(1)` man page.
+
+`-f`, `--from`, `-r`, or `--read` *format*
+: specifies the input format (the format Pandoc will be converting
+ *from*). *format* can be `native`, `markdown`, `rst`, `html`, or
+ `latex`. (`+lhs` can be appended to indicate that the input should
+ be treated as literate Haskell source. See
+ [Literate Haskell support](#literate-haskell-support), below.)
+
+`-t`, `--to`, `-w`, or `--write` *format*
+: specifies the output format -- the format Pandoc will
+ be converting *to*. *format* can be `native`, `html`, `s5`,
+ `docbook`, `opendocument`, `latex`, `context`, `markdown`, `man`,
+ `rst`, and `rtf`. (`+lhs` can be appended to indicate that the
+ output should be treated as literate Haskell source. See
+ [Literate Haskell support](#literate-haskell-support), below.)
+
+`-s` or `--standalone`
+: indicates that a standalone document is to be produced (with
+ appropriate headers and footers), rather than a fragment.
+
+`-o` or `--output` *filename*
+: sends output to *filename*. If this option is not specified,
+ or if its argument is `-`, output will be sent to stdout.
+ (Exception: if the output format is `odt`, output to stdout
+ is disabled.)
+
+`-p` or `--preserve-tabs`
+: causes tabs in the source text to be preserved, rather than converted
+ to spaces (the default).
+
+`--tab-stop` *tabstop*
+: sets the number of spaces per tab to *tabstop* (defaults to 4).
+
+`--strict`
+: specifies that strict markdown syntax is to be used, without
+ pandoc's usual extensions and variants (described below). When the
+ input format is HTML, this means that constructs that have no
+ equivalents in standard markdown (e.g. definition lists or strikeout
+ text) will be parsed as raw HTML.
+
+`--reference-links`
+: causes reference-style links to be used in markdown
+ and reStructuredText output. By default inline links are used.
+
+`-R` or `--parse-raw`
+: causes the HTML and LaTeX readers to parse HTML codes and LaTeX
+ environments that it can't translate as raw HTML or LaTeX. Raw HTML can
+ be printed in markdown, reStructuredText, HTML, and S5 output; raw LaTeX
+ can be printed in markdown, reStructuredText, LaTeX, and ConTeXt output.
+ The default is for the readers to omit untranslatable HTML codes and
+ LaTeX environments. (The LaTeX reader does pass through untranslatable
+ LaTeX *commands*, even if `-R` is not specified.)
+
+`-C` or `--custom-header` *filename*
+: can be used to specify a custom document header. To see the headers
+ used by default, use the `-D` option: for example, `pandoc -D html`
+ prints the default HTML header. Implies `--standalone`.
+
+`--toc` or `--table-of-contents`
+: includes an automatically generated table of contents (or, in the
+ case of `latex`, `context`, and `rst`, an instruction to create
+ one) in the output document. This option has no effect with `man`,
+ `docbook`, or `s5` output formats.
+
+`-c` or `--css` *filename*
+: allows the user to specify a custom stylesheet that will be linked to
+ in HTML and S5 output. This option can be used repeatedly to include
+ multiple stylesheets. They will be included in the order specified.
+ Implies `--standalone`.
+
+`-H` or `--include-in-header` *filename*
+: includes the contents of *filename* (verbatim) at the end of the
+ document header. This can be used, for example, to include special
+ CSS or javascript in HTML documents. This option can be used
+ repeatedly to include multiple files in the header. They will be
+ included in the order specified. Implies `--standalone`.
+
+`-B` or `--include-before-body` *filename*
+: includes the contents of *filename* (verbatim) at the beginning of
+ the document body (e.g. after the `<body>` tag in HTML, or the
+ `\begin{document}` command in LaTeX). This can be used to include
+ navigation bars or banners in HTML documents. This option can be
+ used repeatedly to include multiple files. They will be included in
+ the order specified.
+
+`-A` or `--include-after-body` *filename*
+: includes the contents of *filename* (verbatim) at the end of
+ the document body (before the `</body>` tag in HTML, or the
+ `\end{document}` command in LaTeX). This option can be be used
+ repeatedly to include multiple files. They will be included in the
+ order specified.
+
+`-T` or `--title-prefix` *string*
+: includes *string* as a prefix at the beginning of the title that
+ appears in the HTML header (but not in the title as it appears at
+ the beginning of the HTML body). (See below on
+ [Title Blocks](#title-blocks).) Implies `--standalone`.
+
+`-S` or `--smart`
+: causes `pandoc` to produce typographically correct output, along the
+ lines of John Gruber's [Smartypants]. Straight quotes are converted
+ to curly quotes, `---` to dashes, and `...` to ellipses. Nonbreaking
+ spaces are inserted after certain abbreviations, such as "Mr."
+ (Note: This option is only significant when the input format is
+ `markdown`. It is selected automatically when the output format is
+ `latex` or `context`.)
+
+`-m`*[url]* or `--latexmathml`*[=url]*
+: causes `pandoc` to use the [LaTeXMathML] script to display
+ TeX math in HTML or S5. If a local copy of `LaTeXMathML.js` is
+ available on the webserver where the page will be viewed, provide a
+ *url* and a link will be inserted in the generated HTML or S5. If
+ no *url* is provided, the contents of the script will be inserted
+ directly; this provides portability at the price of efficiency. If
+ you plan to use math on several pages, it is much better to link to
+ a copy of `LaTeXMathML.js`, which can be cached. (See `--jsmath`,
+ `--gladtex`, and `--mimetex` for alternative ways of dealing with
+ math in HTML.)
+
+`--jsmath`*=[url]*
+: causes `pandoc` to use the [jsMath] script to display
+ TeX math in HTML or S5. The *url* should point to the jsMath load
+ script (e.g. `jsMath/easy/load.js`). If it is provided, a link to it
+ will be included in the header of standalone HTML documents.
+ (See `--latexmathml`, `--mimetex`, and `--gladtex` for alternative
+ ways of dealing with math in HTML.)
+
+`--gladtex`*[=url]*
+: causes TeX formulas to be enclosed in `<eq>` tags in HTML or S5 output.
+ This output can then be processed by [gladTeX] to produce links to
+ images with the typeset formulas. (See `--latexmathml`, `--jsmath`, and
+ `--mimetex` for alternative ways of dealing with math in HTML.)
+
+`--mimetex`*[=url]*
+: causes TeX formulas to be replaced by `<img>` tags linking to the
+ [mimeTeX] CGI script, which will produce images with the typeset
+ formulas. (See `--latexmathml`, `--jsmath`, and `--gladtex` for alternative
+ ways of dealing with math in HTML.)
+
+`-i` or `--incremental`
+: causes all lists in S5 output to be displayed incrementally by
+ default (one item at a time). The normal default is for lists to be
+ displayed all at once.
+
+`-N` or `--number-sections`
+: causes sections to be numbered in LaTeX or ConTeXt output. By default,
+ sections are not numbered.
+
+`--no-wrap`
+: disables text-wrapping in output. By default, text is wrapped
+ appropriately for the output format.
+
+`--sanitize-html`
+: sanitizes HTML (in markdown or HTML input) using a whitelist.
+ Unsafe tags are replaced by HTML comments; unsafe attributes
+ are omitted. URIs in links and images are also checked against a
+ whitelist of URI schemes.
+
+`--email-obfuscation`*=none|javascript|references*
+: specifies a method for obfuscating `mailto:` links in HTML documents.
+ *none* leaves `mailto:` links as they are. *javascript* obfuscates
+ them using javascript. *references* obfuscates them by printing their
+ letters as decimal or hexadecimal character references. If `--strict`
+ is specified, *references* is used regardless of the presence
+ of this option.
+
+`--dump-args`
+: is intended to make it easier to create wrapper scripts that use
+ Pandoc. It causes Pandoc to dump information about the arguments
+ with which it was called to stdout, then exit. The first line
+ printed is the name of the output file specified using the `-o`
+ or `--output` option, or `-` if output would go to stdout. The
+ remaining lines, if any, list command-line arguments. These will
+ include the names of input files and any special options passed
+ after ` -- ` on the command line. So, for example,
+
+: pandoc --dump-args -o foo.html -s foo.txt \
+ appendix.txt -- -e latin1
+
+: will cause the following to be printed to stdout:
+
+: foo.html foo.txt appendix.txt -e latin1
+
+`--ignore-args`
+: causes Pandoc to ignore all command-line arguments.
+ Regular Pandoc options are not ignored. Thus, for example,
+
+: pandoc --ignore-args -o foo.html -s foo.txt -- -e latin1
+
+: is equivalent to
+
+: pandoc -o foo.html -s
+
+`-v` or `--version`
+: prints the version number to STDERR.
+
+`-h` or `--help`
+: prints a usage message to STDERR.
+
+[Smartypants]: http://daringfireball.net/projects/smartypants/
+[LaTeXMathML]: http://math.etsu.edu/LaTeXMathML/
+[jsMath]: http://www.math.union.edu/~dpvc/jsmath/
+[gladTeX]: http://www.math.uio.no/~martingu/gladtex/index.html
+[mimeTeX]: http://www.forkosh.com/mimetex.html
+
+Pandoc's markdown vs. standard markdown
+=======================================
+
+In parsing markdown, Pandoc departs from and extends [standard markdown]
+in a few respects. (To run Pandoc on the official markdown test suite,
+type `make test-markdown`.) Except where noted, these differences can
+be suppressed by specifying the `--strict` command-line option or by
+using the `hsmarkdown` wrapper.
+
+[standard markdown]: http://daringfireball.net/projects/markdown/syntax
+ "Markdown syntax description"
+
+Backslash escapes
+-----------------
+
+Except inside a code block or inline code, any punctuation or space
+character preceded by a backslash will be treated literally, even if it
+would normally indicate formatting. Thus, for example, if one writes
+
+ *\*hello\**
+
+one will get
+
+ <em>*hello*</em>
+
+instead of
+
+ <strong>hello</strong>
+
+This rule is easier to remember than standard markdown's rule,
+which allows only the following characters to be backslash-escaped:
+
+ \`*_{}[]()>#+-.!
+
+A backslash-escaped space is parsed as a nonbreaking space. It will
+appear in TeX output as '~' and in HTML and XML as '\&#160;' or '\&nbsp;'.
+
+Subscripts and superscripts
+---------------------------
+
+Superscripts may be written by surrounding the superscripted text by `^`
+characters; subscripts may be written by surrounding the subscripted
+text by `~` characters. Thus, for example,
+
+ H~2~O is a liquid. 2^10^ is 1024.
+
+If the superscripted or subscripted text contains spaces, these spaces
+must be escaped with backslashes. (This is to prevent accidental
+superscripting and subscripting through the ordinary use of `~` and `^`.)
+Thus, if you want the letter P with 'a cat' in subscripts, use
+`P~a\ cat~`, not `P~a cat~`.
+
+Strikeout
+---------
+
+To strikeout a section of text with a horizontal line, begin and end it
+with `~~`. Thus, for example,
+
+ This ~~is deleted text.~~
+
+Nested Lists
+------------
+
+Pandoc behaves differently from standard markdown on some "edge
+cases" involving lists. Consider this source:
+
+ 1. First
+ 2. Second:
+ - Fee
+ - Fie
+ - Foe
+
+ 3. Third
+
+Pandoc transforms this into a "compact list" (with no `<p>` tags around
+"First", "Second", or "Third"), while markdown puts `<p>` tags around
+"Second" and "Third" (but not "First"), because of the blank space
+around "Third". Pandoc follows a simple rule: if the text is followed by
+a blank line, it is treated as a paragraph. Since "Second" is followed
+by a list, and not a blank line, it isn't treated as a paragraph. The
+fact that the list is followed by a blank line is irrelevant. (Note:
+Pandoc works this way even when the `--strict` option is specified. This
+behavior is consistent with the official markdown syntax description,
+even though it is different from that of `Markdown.pl`.)
+
+Ordered Lists
+-------------
+
+Unlike standard markdown, Pandoc allows ordered list items to be marked
+with uppercase and lowercase letters and roman numerals, in addition to
+arabic numerals. (This behavior can be turned off using the `--strict`
+option.) List markers may be enclosed in parentheses or followed by a
+single right-parentheses or period. They must be separated from the
+text that follows by at least one space, and, if the list marker is a
+capital letter with a period, by at least two spaces.[^2]
+
+[^2]: The point of this rule is to ensure that normal paragraphs
+ starting with people's initials, like
+
+ B. Russell was an English philosopher.
+
+ do not get treated as list items.
+
+ This rule will not prevent
+
+ (C) 2007 Joe Smith
+
+ from being interpreted as a list item. In this case, a backslash
+ escape can be used:
+
+ (C\) 2007 Joe Smith
+
+Pandoc also pays attention to the type of list marker used, and to the
+starting number, and both of these are preserved where possible in the
+output format. Thus, the following yields a list with numbers followed
+by a single parenthesis, starting with 9, and a sublist with lowercase
+roman numerals:
+
+ 9) Ninth
+ 10) Tenth
+ 11) Eleventh
+ i. subone
+ ii. subtwo
+ iii. subthree
+
+Note that Pandoc pays attention only to the *starting* marker in a list.
+So, the following yields a list numbered sequentially starting from 2:
+
+ (2) Two
+ (5) Three
+ 1. Four
+ * Five
+
+If default list markers are desired, use '`#.`':
+
+ #. one
+ #. two
+ #. three
+
+Definition lists
+----------------
+
+Pandoc supports definition lists, using a syntax inspired by
+[PHP Markdown Extra] and [reStructuredText]:
+
+ [PHP Markdown Extra]: http://www.michelf.com/projects/php-markdown/extra/
+
+ Term 1
+ : Definition 1
+
+ Term 2
+ : Definition 2
+
+ : Second paragraph of definition 2.
+
+Each term must fit on one line. The definition must begin on the line
+after the term. The definition consists of one or more block elements
+(paragraph, code block, list, etc.), each beginning with a colon and
+(aside from the colon) indented one tab stop.
+
+ Term *with inline markup*
+ : Here is the definition. It may contain multiple blocks.
+ Here is some code:
+
+ : {* my code *}
+
+ : Here is the third paragraph of this definition.
+
+If you leave space after the definition (as in the first example above),
+the definitions will be considered paragraphs. In some output formats,
+this will mean greater spacing between term/definition pairs. For a
+compact definition list, do not leave space between the definition and
+the next term:
+
+ Term 1
+ : Definition 1
+ Term 2
+ : Definition 2
+
+Reference links
+---------------
+
+Pandoc allows implicit reference links with just a single set of
+brackets. So, the following links are equivalent:
+
+ 1. Here's my [link]
+ 2. Here's my [link][]
+
+ [link]: linky.com
+
+(Note: Pandoc works this way even if `--strict` is specified, because
+`Markdown.pl` 1.0.2b7 allows single-bracket links.)
+
+Footnotes
+---------
+
+Pandoc's markdown allows footnotes, using the following syntax:
+
+ Here is a footnote reference,[^1] and another.[^longnote]
+
+ [^1]: Here is the footnote.
+
+ [^longnote]: Here's one with multiple blocks.
+
+ Subsequent paragraphs are indented to show that they
+ belong to the previous footnote.
+
+ { some.code }
+
+ The whole paragraph can be indented, or just the first
+ line. In this way, multi-paragraph footnotes work like
+ multi-paragraph list items.
+
+ This paragraph won't be part of the note, because it isn't indented.
+
+The identifiers in footnote references may not contain spaces, tabs,
+or newlines. These identifiers are used only to correlate the
+footnote reference with the note itself; in the output, footnotes
+will be numbered sequentially.
+
+The footnotes themselves need not be placed at the end of the
+document. They may appear anywhere except inside other block elements
+(lists, block quotes, tables, etc.).
+
+Inline footnotes are also allowed (though, unlike regular notes,
+they cannot contain multiple paragraphs). The syntax is as follows:
+
+ Here is an inline note.^[Inlines notes are easier to write, since
+ you don't have to pick an identifier and move down to type the
+ note.]
+
+Inline and regular footnotes may be mixed freely.
+
+Tables
+------
+
+Two kinds of tables may be used. Both kinds presuppose the use of
+a fixed-width font, such as Courier.
+
+Simple tables look like this:
+
+ Right Left Center Default
+ ------- ------ ---------- -------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+ Table: Demonstration of simple table syntax.
+
+The headers and table rows must each fit on one line. Column
+alignments are determined by the position of the header text relative
+to the dashed line below it:[^3]
+
+ - If the dashed line is flush with the header text on the right side
+ but extends beyond it on the left, the column is right-aligned.
+ - If the dashed line is flush with the header text on the left side
+ but extends beyond it on the right, the column is left-aligned.
+ - If the dashed line extends beyond the header text on both sides,
+ the column is centered.
+ - If the dashed line is flush with the header text on both sides,
+ the default alignment is used (in most cases, this will be left).
+
+[^3]: This scheme is due to Michel Fortin, who proposed it on the
+ [Markdown discussion list](http://six.pairlist.net/pipermail/markdown-discuss/2005-March/001097.html).
+
+The table must end with a blank line. Optionally, a caption may be
+provided (as illustrated in the example above). A caption is a paragraph
+beginning with the string `Table:`, which will be stripped off.
+
+The table parser pays attention to the widths of the columns, and
+the writers try to reproduce these relative widths in the output.
+So, if you find that one of the columns is too narrow in the output,
+try widening it in the markdown source.
+
+Multiline tables allow headers and table rows to span multiple lines
+of text. Here is an example:
+
+ -------------------------------------------------------------
+ Centered Default Right Left
+ Header Aligned Aligned Aligned
+ ----------- ------- --------------- -------------------------
+ First row 12.0 Example of a row that
+ spans multiple lines.
+
+ Second row 5.0 Here's another one. Note
+ the blank line between
+ rows.
+ -------------------------------------------------------------
+
+ Table: Here's the caption. It, too, may span
+ multiple lines.
+
+These work like simple tables, but with the following differences:
+
+ - They must begin with a row of dashes, before the header text.
+ - They must end with a row of dashes, then a blank line.
+ - The rows must be separated by blank lines.
+
+Delimited Code blocks
+---------------------
+
+In addition to standard indented code blocks, Pandoc supports
+*delimited* code blocks. These begin with a row of three or more
+tildes (`~`) and end with a row of tildes that must be at least
+as long as the starting row. Everything between the tilde-lines
+is treated as code. No indentation is necessary:
+
+ ~~~~~~~
+ {code here}
+ ~~~~~~~
+
+Like regular code blocks, delimited code blocks must be separated
+from surrounding text by blank lines.
+
+If the code itself contains a row of tildes, just use a longer
+row of tildes at the start and end:
+
+ ~~~~~~~~~~~~~~~~
+ ~~~~~~~~~~
+ code including tildes
+ ~~~~~~~~~~
+ ~~~~~~~~~~~~~~~~
+
+Optionally, you may specify the language of the code block using
+this syntax:
+
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.haskell .numberLines}
+ qsort [] = []
+ qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++
+ qsort (filter (>= x) xs)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some output formats can use this information to do syntax highlighting.
+Currently, the only output format that uses this information is HTML.
+
+If pandoc has been compiled with syntax highlighting support, then the
+code block above will appear highlighted, with numbered lines. (To see
+which languages are supported, do `pandoc --version`.)
+
+If pandoc has not been compiled with syntax highlighting support, the
+code block above will appear as follows:
+
+ <pre class="haskell">
+ <code>
+ ...
+ </code>
+ </pre>
+
+Title blocks
+------------
+
+If the file begins with a title block
+
+ % title
+ % author(s) (separated by commas)
+ % date
+
+it will be parsed as bibliographic information, not regular text. (It
+will be used, for example, in the title of standalone LaTeX or HTML
+output.) The block may contain just a title, a title and an author,
+or all three lines. Each must begin with a % and fit on one line.
+The title may contain standard inline formatting. If you want to
+include an author but no title, or a title and a date but no author,
+you need a blank line:
+
+ % My title
+ %
+ % June 15, 2006
+
+Titles will be written only when the `--standalone` (`-s`) option is
+chosen. In HTML output, titles will appear twice: once in the
+document head -- this is the title that will appear at the top of the
+window in a browser -- and once at the beginning of the document body.
+The title in the document head can have an optional prefix attached
+(`--title-prefix` or `-T` option). The title in the body appears as
+an H1 element with class "title", so it can be suppressed or
+reformatted with CSS. If a title prefix is specified with `-T` and no
+title block appears in the document, the title prefix will be used by
+itself as the HTML title.
+
+The man page writer extracts a title, man page section number, and
+other header and footer information from the title line. The title
+is assumed to be the first word on the title line, which may optionally
+end with a (single-digit) section number in parentheses. (There should
+be no space between the title and the parentheses.) Anything after
+this is assumed to be additional footer and header text. A single pipe
+character (`|`) should be used to separate the footer text from the header
+text. Thus,
+
+ % PANDOC(1)
+
+will yield a man page with the title `PANDOC` and section 1.
+
+ % PANDOC(1) Pandoc User Manuals
+
+will also have "Pandoc User Manuals" in the footer.
+
+ % PANDOC(1) Pandoc User Manuals | Version 4.0
+
+will also have "Version 4.0" in the header.
+
+Markdown in HTML blocks
+-----------------------
+
+While standard markdown leaves HTML blocks exactly as they are, Pandoc
+treats text between HTML tags as markdown. Thus, for example, Pandoc
+will turn
+
+ <table>
+ <tr>
+ <td>*one*</td>
+ <td>[a link](http://google.com)</td>
+ </tr>
+ </table>
+
+into
+
+ <table>
+ <tr>
+ <td><em>one</em></td>
+ <td><a href="http://google.com">a link</a></td>
+ </tr>
+ </table>
+
+whereas `Markdown.pl` will preserve it as is.
+
+There is one exception to this rule: text between `<script>` and
+`</script>` tags is not interpreted as markdown.
+
+This departure from standard markdown should make it easier to mix
+markdown with HTML block elements. For example, one can surround
+a block of markdown text with `<div>` tags without preventing it
+from being interpreted as markdown.
+
+Header identifiers in HTML
+--------------------------
+
+Each header element in pandoc's HTML output is given a unique
+identifier. This identifier is based on the text of the header. To
+derive the identifier from the header text,
+
+ - Remove all formatting, links, etc.
+ - Remove all punctuation, except dashes and hyphens.
+ - Replace all spaces, dashes, newlines, and hyphens with hyphens.
+ - Convert all alphabetic characters to lowercase.
+ - Remove everything up to the first letter (identifiers may
+ not begin with a number or punctuation mark).
+ - If nothing is left after this, use the identifier `section`.
+
+Thus, for example,
+
+ Header Identifier
+ ------------------------------------- ---------------------------
+ Header identifiers in HTML `header-identifiers-in-html`
+ *Dogs*?--in *my* house? `dogs--in-my-house`
+ [HTML], [S5], or [RTF]? `html-s5-or-rtf`
+ 3. Applications `applications`
+ 33 `section`
+
+These rules should, in most cases, allow one to determine the identifier
+from the header text. The exception is when several headers have the
+same text; in this case, the first will get an identifier as described
+above; the second will get the same identifier with `-1` appended; the
+third with `-2`; and so on.
+
+These identifiers are used to provide link targets in the table of
+contents generated by the `--toc|--table-of-contents` option. They
+also make it easy to provide links from one section of a document to
+another. A link to this section, for example, might look like this:
+
+ See the section on [header identifiers](#header-identifiers-in-html).
+
+Note, however, that this method of providing links to sections works
+only in HTML.
+
+Blank lines before headers and blockquotes
+------------------------------------------
+
+Standard markdown syntax does not require a blank line before a header
+or blockquote. Pandoc does require this (except, of course, at the
+beginning of the document). The reason for the requirement is that
+it is all too easy for a `>` or `#` to end up at the beginning of a
+line by accident (perhaps through line wrapping). Consider, for
+example:
+
+ I like several of their flavors of ice cream: #22, for example, and
+ #5.
+
+Math
+----
+
+Anything between two $ characters will be treated as TeX math. The
+opening $ must have a character immediately to its right, while the
+closing $ must have a character immediately to its left. Thus,
+`$20,000 and $30,000` won't parse as math. If for some reason
+you need to enclose text in literal $ characters, backslash-escape
+them and they won't be treated as math delimiters.
+
+TeX math will be printed in all output formats. In Markdown,
+reStructuredText, LaTeX, and ConTeXt output, it will appear verbatim
+between $ characters.
+
+In reStructuredText output, it will be rendered using an interpreted
+text role `:math:`, as described
+[here](http://www.american.edu/econ/itex2mml/mathhack.rst).
+
+In Texinfo output, it will be rendered inside a `@math` command.
+
+In groff man output, it will be rendered verbatim without $'s.
+
+In MediaWiki output, it will be rendered inside `<math>` tags.
+
+In RTF, Docbook, and OpenDocument output, it will be rendered, as far as
+possible, using unicode characters, and will otherwise appear verbatim.
+Unknown commands and symbols, and commands that cannot be dealt with
+this way (like `\frac`), will be rendered verbatim. So the results may
+be a mix of raw TeX code and properly rendered unicode math.
+
+In HTML and S5 output, the way math is rendered will depend on the
+command-line options selected:
+
+1. The default is to render TeX math as far as possible using unicode
+ characters, as with RTF, Docbook, and OpenDocument output. Formulas
+ are put inside a `span` with `class="math"`, so that they may be
+ styled differently from the surrounding text if needed.
+
+2. If the `--latexmathml` option is used, TeX math will be displayed
+ between $ or $$ characters and put in `<span>` tags with class `LaTeX`.
+ The [LaTeXMathML] script will be used to render it as formulas.
+ (This trick does not work in all browsers, but it works in Firefox.
+ In browsers that do not support LaTeXMathML, TeX math will appear
+ verbatim between $ characters.)
+
+3. If the `--jsmath` option is used, TeX math will be put inside
+ `<span>` tags (for inline math) or `<div>` tags (for display math)
+ with class `math`. The [jsMath] script will be used to render
+ it.
+
+4. If the `--mimetex` option is used, the [mimeTeX] CGI script will
+ be called to generate images for each TeX formula. This should
+ work in all browsers. The `--mimetex` option takes an optional URL
+ as argument. If no URL is specified, it will be assumed that the
+ mimeTeX CGI script is at `/cgi-bin/mimetex.cgi`.
+
+5. If the `--gladtex` option is used, TeX formulas will be enclosed
+ in `<eq>` tags in the HTML output. The resulting `htex` file may then
+ be processed by [gladTeX], which will produce image files for each
+ formula and an `html` file with links to these images. So, the
+ procedure is:
+
+ pandoc -s --gladtex myfile.txt -o myfile.htex
+ gladtex -d myfile-images myfile.htex # produces myfile.html
+ # and images in myfile-images
+
+Inline TeX
+----------
+
+Inline TeX commands will be preserved and passed unchanged to the
+LaTeX and ConTeXt writers. Thus, for example, you can use LaTeX to
+include BibTeX citations:
+
+ This result was proved in \cite{jones.1967}.
+
+Note that in LaTeX environments, like
+
+ \begin{tabular}{|l|l|}\hline
+ Age & Frequency \\ \hline
+ 18--25 & 15 \\
+ 26--35 & 33 \\
+ 36--45 & 22 \\ \hline
+ \end{tabular}
+
+the material between the begin and end tags will be interpreted as raw
+LaTeX, not as markdown.
+
+Inline LaTeX is ignored in output formats other than Markdown, LaTeX,
+and ConTeXt.
+
+Custom headers
+==============
+
+When run with the "standalone" option (`-s`), `pandoc` creates a
+standalone file, complete with an appropriate header. To see the
+default headers used for html and latex, use the following commands:
+
+ pandoc -D html
+
+ pandoc -D latex
+
+If you want to use a different header, just create a file containing
+it and specify it on the command line as follows:
+
+ pandoc --custom-header=MyHeaderFile
+
+Producing S5 with Pandoc
+========================
+
+Producing an [S5] web-based slide show with Pandoc is easy. A title
+page is constructed automatically from the document's title block (see
+above). Each section (with a level-one header) produces a single slide.
+(Note that if the section is too big, the slide will not fit on the page;
+S5 is not smart enough to produce multiple pages.)
+
+Here's the markdown source for a simple slide show, `eating.txt`:
+
+ % Eating Habits
+ % John Doe
+ % March 22, 2005
+
+ # In the morning
+
+ - Eat eggs
+ - Drink coffee
+
+ # In the evening
+
+ - Eat spaghetti
+ - Drink wine
+
+To produce the slide show, simply type
+
+ pandoc -w s5 -s eating.txt > eating.html
+
+and open up `eating.html` in a browser.
+
+Note that by default, the S5 writer produces lists that display
+"all at once." If you want your lists to display incrementally
+(one item at a time), use the `-i` option. If you want a
+particular list to depart from the default (that is, to display
+incrementally without the `-i` option and all at once with the
+`-i` option), put it in a block quote:
+
+ > - Eat spaghetti
+ > - Drink wine
+
+In this way incremental and nonincremental lists can be mixed in
+a single document.
+
+Note: the S5 file produced by pandoc with the `-s/--standalone` option
+embeds the javascript and CSS required to show the slides. Thus it
+does not depend on any additional files: you can send the HTML file to
+others, and they will be able to view the slide show just by opening
+it. However, if you intend to produce several S5 slide shows, and you
+are displaying them on your own website, it is better to keep the S5
+javascript and CSS files separate from the slide shows themselves, so
+that they may be cached. The best approach in this case is to use pandoc
+without the `-s` option to produce the body of the S5 document, which
+can then be inserted into an HTML template that links to the javascript
+and CSS files required by S5. (See the instructions on the S5 website.)
+Alternatively, you may use `-s` together with the `-C/--custom-header`
+option.
+
+Literate Haskell support
+========================
+
+If you append `+lhs` to an appropriate input or output format (`markdown`,
+`rst`, or `latex` for input or output; `html` for output only), pandoc
+will treat the document as literate Haskell source. This means that
+
+ - In markdown input, "bird track" sections will be parsed as Haskell
+ code rather than block quotations. Text between `\begin{code}`
+ and `\end{code}` will also be treated as Haskell code.
+
+ - In markdown output, code blocks with class `haskell` will be
+ rendered using bird tracks, and block quotations will be
+ indented one space, so they will not be treated as Haskell code.
+ In addition, headers will be rendered setext-style (with underlines)
+ rather than atx-style (with '#' characters). (This is because ghc
+ treats '#' characters in column 1 as introducing line numbers.)
+
+ - In restructured text input, "bird track" sections will be parsed
+ as Haskell code.
+
+ - In restructured text output, code blocks with class `haskell` will
+ be rendered using bird tracks.
+
+ - In LaTeX input, text in `code` environments will be parsed as
+ Haskell code.
+
+ - In LaTeX output, code blocks with class `haskell` will be rendered
+ inside `code` environments.
+
+ - In HTML output, code blocks with class `haskell` will be rendered
+ with class `literatehaskell` and bird tracks.
+
+Examples:
+
+ pandoc -f markdown+lhs -t html
+
+reads literate Haskell source formatted with markdown conventions and writes
+ordinary HTML (without bird tracks).
+
+ pandoc -f markdown+lhs -t html+lhs
+
+writes HTML with the Haskell code in bird tracks, so it can be copied
+and pasted as literate Haskell source.
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
index 000000000..d808a65b8
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,65 @@
+import Distribution.Simple
+import Control.Exception ( bracket_ )
+import Control.Monad ( unless )
+import System.Process ( runCommand, runProcess, waitForProcess )
+import System.FilePath ( (</>), (<.>) )
+import System.Directory
+import System.IO ( stderr, openTempFile )
+import System.Exit
+import System.Time
+import System.IO.Error ( isDoesNotExistError )
+import Data.Maybe ( fromJust, isNothing, catMaybes )
+import Data.List ( isInfixOf )
+
+main = do
+ defaultMainWithHooks $ simpleUserHooks { runTests = runTestSuite
+ , postBuild = makeManPages }
+ exitWith ExitSuccess
+
+-- | Run test suite.
+runTestSuite _ _ _ _ = do
+ tempPath <- catch getTemporaryDirectory (\_ -> return ".")
+ (outputPath, hOut) <- openTempFile tempPath "out"
+ runProcess "pandoc" ["--version"] Nothing Nothing Nothing (Just hOut) Nothing >>= waitForProcess
+ output <- readFile outputPath
+ let highlightingSupport = "with syntax highlighting" `isInfixOf` output
+ let testArgs = if highlightingSupport then ["lhs"] else []
+ let testCmd = "runhaskell -i.. RunTests.hs " ++ unwords testArgs
+ inDirectory "tests" $ runCommand testCmd >>= waitForProcess >>= exitWith
+
+-- | Build man pages from markdown sources in man/man1/.
+makeManPages _ _ _ _ = do
+ mapM_ makeManPage ["pandoc.1", "hsmarkdown.1", "html2markdown.1", "markdown2pdf.1"]
+
+-- | Build a man page from markdown source in man/man1.
+makeManPage manpage = do
+ let manDir = "man" </> "man1"
+ let pandoc = "dist" </> "build" </> "pandoc" </> "pandoc"
+ let page = manDir </> manpage
+ let source = manDir </> manpage <.> "md"
+ modifiedDeps <- modifiedDependencies page [source]
+ unless (null modifiedDeps) $ do
+ ec <- runProcess pandoc ["-s", "-S", "-r", "markdown", "-w", "man", "-o", page, source]
+ Nothing Nothing Nothing Nothing (Just stderr) >>= waitForProcess
+ case ec of
+ ExitSuccess -> putStrLn $ "Created " ++ manDir </> manpage
+ _ -> do putStrLn $ "Error creating " ++ manDir </> manpage
+ exitWith ec
+
+-- | Returns a list of 'dependencies' that have been modified after 'file'.
+modifiedDependencies :: FilePath -> [FilePath] -> IO [FilePath]
+modifiedDependencies file dependencies = do
+ fileModTime <- catch (getModificationTime file) $
+ \e -> if isDoesNotExistError e
+ then return (TOD 0 0) -- the minimum ClockTime
+ else ioError e
+ depModTimes <- mapM getModificationTime dependencies
+ let modified = zipWith (\dep time -> if time > fileModTime then Just dep else Nothing) dependencies depModTimes
+ return $ catMaybes modified
+
+-- | Perform an IO action in a directory.
+inDirectory :: FilePath -> IO a -> IO a
+inDirectory dir action = do
+ oldDir <- getCurrentDirectory
+ bracket_ (setCurrentDirectory dir) (setCurrentDirectory oldDir) action
+
diff --git a/changelog b/changelog
new file mode 100644
index 000000000..32df9cbe4
--- /dev/null
+++ b/changelog
@@ -0,0 +1,1940 @@
+pandoc (1.2.1)
+
+ [ John MacFarlane ]
+
+ * Fixed regression with --preserveTabs. Brought back optPreserveTabs.
+ The trick of setting tabStop to 0 to mean "preserve tabs" had a bad
+ side effect: strings of 0 spaces were interpreted as indentation.
+ So, with --preserve-tabs, unindented paragraphs were treated as
+ code. Resolves Issue #138.
+
+ * HTML writer: wrap sections in divs. Resolves Issue #70.
+
+ + hierarchicalize has been rationalized; it builds a hierarchical
+ representation of the document from the headers, and simultaneously
+ gives each section a unique identifier based on the heading title.
+ + Identifiers are now attached to the divs rather than
+ to the headers themselves.
+ + Table of content backlinks go to the beginning of the table, rather
+ than to the section reference that was clicked.
+ + Code for constructing identifiers has been moved to Text.Pandoc.Shared
+ from the HTML writer, since it is now consumed only by
+ hierarchicalize.
+ + In --strict mode, pandoc just prints bare headings, as before
+ (unless --toc has been specified).
+ + In s5 output, it does not wrap sections in divs, as that seems to
+ confuse the s5 javascript.
+
+ * Man writer: break lines at end of each sentence. groff expects this
+ and treats '.' and '?' differently when followed by line ending as
+ opposed to ordinary space. Also, don't escape periods. Instead, use
+ zero-width character \& to avoid unwanted interpretation of periods
+ at start of line. Resolves Issue #148.
+
+ * Markdown writer: Added '#' and '>' to list of characters to be
+ escaped in markdown output. Removed '<', as it is not an officially
+ escapable character. This partially resolves Issue #96.
+
+ * Make --smart the default for man output format. Otherwise we have
+ trouble dividing lists of endlines into sentences.
+
+ * DocBook writer: Use language attribute to indicate source language
+ in code blocks.
+
+ * RST reader:
+
+ + Allow # to continue list, even if the list was started with an
+ explicit marker. For example:
+
+ A. my list
+ #. continued
+
+ Resolves Issue #140.
+ + Allow continuation lines in line blocks. Also added test cases for
+ line blocks for RST reader. Resolves Issue #149.
+ + Allow explicit links with spaces in URL: `link <to this>`_
+
+ * Improved LaTeX reader's coverage of math modes. Remove displaymath*
+ (which is not in LaTeX) and recognize all the amsmath environments
+ that are alternatives to eqnarray, namely equation, equation*,
+ gather, gather*, gathered, multline, multline*, align, align*,
+ alignat, alignat*, aligned, alignedat, split. Resolves Issue #103.
+ Thanks to shreevatsa.public for the patch.
+
+ * Markdown reader:
+
+ + Allow -, _, :, . in markdown attribute names. These are legal in
+ XML attribute names.
+ + Use non-breaking spaces in abbreviations.
+ + Markdown reader: improved efficiency of abbreviation parsing.
+ Instead of a separate abbrev parser, we just check for
+ abbreviations each time we parse a string. This gives a huge
+ performance boost with -S. Resolves Issue #141.
+
+ * Improved efficiency of shared parsers: hexNum, htmlComment,
+ whitespace, indentSpaces.
+
+ * Export HTMLMathMethod in Text.Pandoc.
+
+ * Export languagesByExtension in Text.Pandoc.Highlighting.
+
+ * Added new Haskell version of markdown2pdf, due to
+ Paulo Tanimoto. This should be more portable than the old
+ shell script.
+
+ * Made 'pandoc -v' more explicit about compiler options.
+ Resolves Issue #139.
+
+ * pandoc.hs: Made --strict compatible with --standalone, --toc.
+
+ * Use Paths_pandoc to get version number, instead of hard-coding it
+ into Text/Pandoc.hs.
+
+pandoc (1.2)
+
+ [ John MacFarlane ]
+
+ * Added support for literate Haskell. lhs support is triggered by
+ '+lhs' suffixes in formats. For example, 'latex+lhs' is literate
+ Haskell LaTeX. '.lhs' files are treated by default as literate
+ markdown.
+
+ + Added stateLiterateHaskell to parser state.
+ + Added parser for lhsCodeBlock to Markdown, RST, LaTeX readers.
+ + Added parser for |inline lhs| to LaTeX reader.
+ + Added writerLiterateHaskell to WriterOptions.
+ + Added lhs support to Markdown, RST, LaTeX, HTML writers.
+ + Added definition of code environment to LaTeX header.
+ + Added tests (run only if highlighting support compiled in).
+ + Documented lhs features in man page and README.
+
+ * In Text.Pandoc.Definition, added processWith, processWithM,
+ and queryWith, and deprecated processPandoc and queryPandoc
+ for these more general functions.
+
+ * Fixed bug in mediawiki writer: improper closing tags in tables.
+ Thanks to Benct Philip Jonsson for reporting the bug.
+
+ * Added --email-obfuscation option.
+
+ + Added writer option for email obfuscation.
+ + Implemented email obfuscation options in HTML writer.
+ + Added option to option parser.
+ + Documented in README and pandoc man page.
+ + Resolves Issue #97.
+
+ * LaTeX writer: fixed bug with empty table cells.
+ Resolves Issue #107. Thanks to rodja.trappe for the patch.
+
+ * Fixed bug with header spacing in Markdown and RST writers.
+ A null header (Meta [] [] []) should not cause a blank line
+ at the beginning of output. But a blank line is needed between
+ a non-null header and the main text.
+
+ * Markdown reader: Relax spacing rules for $$ in display math. Now
+ space and newlines are allowed after the opening $$ and before the
+ closing $$. However, the display math cannot contain an entirely
+ blank line. Resolves Issue #105.
+
+ * Markdown reader: Gobble space after Plain blocks containing only
+ raw html inline. Otherwise following header blocks are not parsed
+ correctly, since the parser sees blank space before them. Resolves
+ Issue #124.
+
+ * Markdown reader: Allow " as well as '' to end a latex double-quote.
+
+ * Conditionally depend on syb and base >= 4 if ghc >= 6.10.
+ Resolves Issue #109.
+
+ * Fixed problems in RST and markdown output due to bug in pretty-1.0.1.0
+
+ + Added hang' function to Text.Pandoc.Shared; this will be used instead
+ of hang, which doesn't work properly in pretty-1.0.1.0. When pretty
+ is upgraded, we can go back to hang.
+ See http://article.gmane.org/gmane.comp.lang.haskell.general/16687
+ + Use hang' (and some different techniques) in RST and markdown writers.
+ Some output is now a bit different.
+
+ * Brought citeproc support up to date for citeproc-hs-0.2.
+ (Patch by Andrea Rossato.)
+
+ * Moved all haskell source to src subdirectory. Renamed Main.hs to
+ pandoc.hs.
+
+ * Rewrote hsmarkdown in Haskell for portability (src/hsmarkdown.hs).
+ For now, keeping the old shell script too.
+
+ * Added TemplateHaskell to Extensions for executable, removed
+ -threaded for library. Thanks to duncan.coutts for the bug report.
+ Resolves Issue #121.
+
+ * Moved some Extra-Source-Files to Data-Files.
+
+ * Moved tabFilter to Shared.
+
+ * In pandoc.hs, removed optPreserveTabs; instead, tabstop of 0 means
+ preserve tabs.
+
+ * Minor code cleanup based on hlint suggestions.
+
+pandoc (1.1)
+
+ [ John MacFarlane ]
+
+ * Main.hs:
+
+ + Changed date on copyright message in Main.hs.
+ + Have the '-v' option print syntax highlighting languages
+ separated by commas, and wrapped in lines, instead of in five
+ columns as before.
+
+ * Added --jsmath option. Resolves Issue #68.
+
+ + Added --jsmath option to Main.hs
+ + Added JsMath to HTMLMathMethod in Text.Pandoc.Shared.
+ + Handle math appropriately in HTML writer when JsMath selected.
+ + Documented the option in README and man page.
+
+ * Text.Pandoc.Shared: Changed compactify to use a better heuristic
+ for tight and loose lists. Final Para is changed to Plain if all
+ other list items *end* with a Plain block. Addresses Issue #99.
+
+ * HTML reader:
+
+ + Added colons to protocols in unsanitaryURI. Closes Issue #88.
+ + HTML reader: Don't interpret contents of <pre> blocks as markdown.
+ Added rawVerbatimBlock parser. Resolves Issue #94.
+
+ * Markdown reader:
+
+ + Allow URLs with spaces in them in links and references, but escape
+ them as "%20".
+ + Allow blank space at the end of horizontal rules.
+
+ * RST reader: Modified 'unknownDirective' parser to handle comment
+ blocks correctly, and added tests for comment blocks. Resolves Issue
+ #86. Closes Debian Bug #500662.
+
+ * HTML writer:
+
+ + Include classes on tr elements in HTML output:
+ "header", "odd", "even". This allows tables to be styled with
+ lines in alternating colors. Resolves Issue #91.
+ + Enclose all LaTeXMathML bits in <span class="LaTeX">.
+ This prevents parts of the document that are not math from being
+ interpreted as math by LaTeXMathML.js.
+
+ * OpenDocument and ODT writers: Added support for HorizontalRule elements,
+ which were formerly ignored. Resolves Issue #95.
+
+ * Text.Pandoc.Shared: Modified wrappedTeX to eliminate the line break
+ between a footnote and immediately following nonspace characters in
+ LaTeX and ConTeXt output. (This gets interpreted as a space, which
+ is not desired in cases like "text^[note]---".) Resolves Issue #93.
+
+ * Windows installer: Don't require admin privileges to run
+ installer. Modified pandoc-setup.iss, and changed modpath.iss to
+ modify HKCU path if user lacks admin privileges. Also fixed case
+ where oldpath is empty (previously this led to the new path
+ beginning with a semicolon).
+
+ * Updated INSTALL instructions for Arch packages and OS X install using
+ cabal-install.
+
+ * Removed the (now unneeded) debian directory.
+ Removed empty Codec and System directories.
+
+ * Moved odt-styles/ to data/. Removed unneeded variable in Makefile.
+
+ * Modified Setup.hs so that the "test" target returns an error status
+ when tests fail, and "build" returns a success status if
+ the build succeeds. Resolves Issue #100.
+
+ * Added BUGS to files in tarball.
+
+
+pandoc (1.0.0.1)
+
+ [ John MacFarlane ]
+
+ * Removed spurious reference to pdf output format from pandoc(1) man page.
+
+pandoc (1.0)
+
+ [ Andrea Rossato ]
+
+ * Added new OpenDocument writer.
+
+ * Added support for SmallCaps inline element.
+
+ * Added support for integrating pandoc with citeproc-hs.
+
+ + Added Cite element to definition and writers.
+ + Added Text.Pandoc.Biblio module
+ + Note: This support is included only if the 'citeproc'
+ Cabal configuration flag is set.
+
+ * Made Pandoc data structure an instance of Typeable.
+ Added new processPandoc and queryPandoc functions, to query
+ or transform matching elements in a Pandoc structure.
+
+ [ Peter Wang ]
+
+ * Added new Texinfo writer.
+
+ [ John MacFarlane ]
+
+ * Changes to Texinfo writer:
+
+ + No space between paragraph and following @verbatim (provides more
+ pleasing appearance in text formats)
+ + Blank line consistently after list environments.
+ + Removed deVerb.
+ + Use @code instead of @verb for inline code (this solves the character
+ escaping problem for texi2dvi and texi2pdf).
+ + Added news of Texinfo writer to README.
+ + Added Texinfo to list of formats in man page, and removed extra 'groff'.
+ + Added texi & texinfo extensions to Main.hs, and fixed bug in determining
+ default output extension.
+ + Modified disallowedInNode in Texinfo writer to correct list of disallowed characters.
+
+ * Added tests for OpenDocument writer.
+
+ * Added ODT writer (using zip-archive library to package output of
+ OpenDocument writer). Added odt-styles directory with default ODT styles.
+
+ * Added new mediawiki writer and tests.
+
+ * Markdown reader: Added support for delimited code blocks, with optional
+ syntax highlighting using highlighting-kate (if the 'highlighting'
+ configuration option is selected).
+
+ + Currently highlighting is supported only in the HTML writer.
+ + Delimited code blocks can have attributes; using the language name as
+ class triggers highlighting.
+ + New Attributes parameter in CodeBlock structure.
+ + --version now indicates whether syntax highlighting support is compiled
+ in, and prints a list of supported languages
+
+ * Removed debian directory. Pandoc is no longer a native debian package.
+
+ * Changes to build process: pandoc can now be built from the repository
+ using Cabal. No unix tools are needed (so, pandoc can be built on Windows
+ without Cygwin).
+
+ + Include shell scripts themselves in repo, rather than generating from wrappers.
+ Removed wrappers directory and wrappers Makefile target.
+ + Text/Pandoc/ASCIIMathML.hs, Text/Pandoc/DefaultHeaders.hs,
+ and Text/Pandoc/Writers/S5.hs are no longer built in Makefile
+ from templates in the templates/ directory. Instead, they use template
+ haskell to read data at compile time from the relevant files in data/.
+ Template haskell functions go in a new module, Text.Pandoc.TH.
+ + man pages are now generated in Setup.hs hook, not by Makefile
+ + Makefile 'tarball' target now calls Cabal's 'sdist'
+ + Added "Extra-Source-Files" to pandoc.cabal, so sdist contains everything needed
+ + Added "Build-Type" field to pandoc.cabal to avoid warning.
+ + Added to "Extra-source-files" and "Extra-tmp-files" in pandoc.cabal,
+ so 'sdist' and 'clean' will work properly.
+ + Setup.hs now generates man pages in a postbuild hook.
+ + Added dependency-checking to Setup.hs, so it only rebuilds things
+ that need rebuilding.
+ + Added 'library' and 'executable' configuration flags.
+ Cabal can now be told to build just the library or just the executable.
+ + CABALOPTS may now be specified with 'make' to pass Cabal configuration flags.
+ For example: CABALOPTS=-fhighlighting make
+
+ * Rewrote test suite so it doesn't depend on perl or unix tools.
+
+ + Replaced old runtests.pl with a Haskell script RunTests.hs.
+ + Added Diff.hs module to be used by RunTests.hs instead of unix 'diff'.
+ + Added test hook to Setup.hs, so tests may be run from cabal.
+ + Changed Makefile's 'test' target to run tests via cabal.
+ + Removed old generate.sh.
+ + Since we no longer have 'sed' to filter out raw HTML sections
+ from the docbook writer test, or raw LaTeX sections from the
+ context writer test, we now just include these sections.
+ They can be taken out if it is necessary to process the files.
+ + Updated latex and context writer tests to remove extra spaces
+ after '\\item'
+ + Added a markdown table reader test.
+ + Added markdown-reader-more.txt to test suite, for additional test cases
+ for raw ConTeXt environments and more.
+
+ * Compatibility fixes for CPP, Cabal, and haddock:
+
+ + Use CPP in "Extensions" field in pandoc.cabal.
+ + Removed use of backslash string continuations in source files.
+
+ * Removed pandoc.cabal.ghc66. We now require Cabal >= 1.2, GHC >= 6.8,
+ base >= 3.
+
+ * Require parsec < 3.
+ The compatibility module in parsec 3.0.0 gives far worse performance than
+ parsec 2.1. Eventually pandoc will be upgraded to use the new bytestring
+ version of parsec, and then we'll go to parsec 3.0.0.
+
+ * Removed Text.Regex dependencies by rewriting using plain Haskell
+ (Text.Pandoc.Writers.RTF, Text.Pandoc.Writers.HTML, Main.hs)
+
+ * Moved Text.Pandoc.Writers.DefaultHeaders -> Text.Pandoc.DefaultHeaders.
+
+ * Makefile:
+
+ + Added 'configure' as dependency of 'uninstall-all'.
+ (It uses the Cabal build program.)
+ + Makefile: only use --with-hc-pkg if GHC_PKG is defined.
+ Note that Cabal will automatically choose the ghc-pkg appropriate
+ for the compiler selected, so normally specifying GHC by itself
+ is sufficient.
+
+ * Removed Text.Pandoc.UTF8 module; instead, depend on utf8-string and use
+ its IO and conversion functions.
+
+ * Added -Wall to ghc-options in pandoc.cabal. Cleaned up modules so that
+ everything is -Wall clean.
+
+ + Added pragma to HTML writer to avoid deprecation warning for use of "start" attribute.
+ + Added pragma to Text/Pandoc/Shared.hs to get rid of "orphan instance" warnings.
+ (These are caused by the Lift instance for ByteString.)
+
+ * Changed the comment used to replace unsafe HTML if sanitize-html option
+ selected.
+
+ * Made -c/--css option repeatable on the command line (like -H, -A, -B).
+
+ * Moved XML-formatting functions to new unexported module Text.Pandoc.XML.
+
+ * Escape '\160' as "&#160;", not "&nbsp;" in XML.
+ "nbsp" isn't a predefined XML entity.
+
+ * Fixed bug in RST reader, which would choke on: "p. one\ntwo\n".
+ Added some try's in ordered list parsers.
+
+ * Man writer: don't escape " as \".
+
+ * Allow newline before URL in markdown link references. Resolves Issue #81.
+ Added tests for this issue in new "markdown-reader-more" tests.
+ Changed RunTests.hs to run these tests.
+
+ * Support for display math. Resolves Issue #47.
+
+ + Added a DisplayMath/InlineMath selector to Math inlines.
+ + Markdown parser yields DisplayMath for $$...$$.
+ + LaTeX parser yields DisplayMath when appropriate. Removed
+ mathBlock parsers, since the same effect is achieved by the math
+ inline parsers, now that they handle display math.
+ + Writers handle DisplayMath as appropriate for the format.
+ + Modified tests accordingly; added new tests for display math.
+
+ * Use LaTeXMathML instead of ASCIIMathML. LaTeXMathML is closer
+ to LaTeX in its display of math, and supports many non-math LaTeX environments.
+
+ + Changed -m option to use LaTeXMathML rather than ASCIIMathML.
+ + Modified HTML writer to print raw TeX when LaTeXMathML is
+ being used instead of suppressing it.
+ + Removed ASCIIMathML files from data/ and added LaTeXMathML.
+ + Replaced ASCIIMathML with LaTeXMathML in source files.
+ + Modified README and pandoc man page source.
+ + Added --latexmathml option (kept --asciimathml as a synonym
+ for backwards compatibility)
+
+ * Markdown reader: Parse setext headers before atx headers.
+ Test case:
+ # hi
+ ====
+ parsed by Markdown.pl as an H1 header with contents "# hi".
+
+ * Markdown reader: Treat "mixed" lists the same way as Markdown.pl does.
+ The marker on the first list item determines the type of the whole
+ list. Thus, a list like
+ 1. one
+ - two
+ * three
+ gets parsed as a single ordered list. (Previous versions of pandoc
+ treated this as an ordered list with an unordered sublist.)
+
+ * Markdown smart typography:
+
+ + Em dashes no longer eat surrounding whitespace. Resolves Issue #69.
+ + Use nonbreaking spaces after known abbreviations in markdown parser.
+ Thus, for example, "Mr. Brown" comes out as "Mr.~Brown" in LaTeX, and does
+ not produce a sentence-separating space. Resolves Issue #75.
+
+ * Markdown writer: Print unicode \160 literally, rather than as &nbsp;.
+
+ * Treat '\ ' in (extended) markdown as nonbreaking space.
+ Print nonbreaking space appropriately in each writer (e.g. ~ in LaTeX).
+
+ * The '--sanitize-html' option now examines URIs in markdown links
+ and images, and in HTML href and src attributes. If the URI scheme
+ is not on a whitelist of safe schemes, it is rejected. The main point
+ is to prevent cross-site scripting attacks using 'javascript:' URIs.
+ See http://www.mail-archive.com/markdown-discuss@six.pairlist.net/msg01186.html
+ and http://ha.ckers.org/xss.html. Resolves Issue #62.
+
+ * HTML writer:
+
+ + Override Text.XHtml's stringToHtml function,
+ so that characters below 0xff are not converted to numerical entity
+ references. Also convert '\160' to "&nbsp;". This should aid readability
+ and editability of the HTML source. It does presuppose that the HTML
+ will be served as UTF-8.
+ + In code blocks, change leading newlines to <br /> tags.
+ (Some browsers ignore them.) Resolves Issue #71.
+ See http://six.pairlist.net/pipermail/markdown-discuss/2008-May/001297.html
+ + Use style attributes rather than css classes for strikethrough
+ and ordered list styles. This works better when fragments, rather than
+ standalone documents, are generated.
+
+ * HTML reader: Count anything that isn't a known block (HTML) tag as an
+ inline tag (rather than the other way around). Added "html", "head", and
+ "body" to list of block tags. Resolves Issue #66, allowing
+ <lj> to count as an inline tag.
+
+ * RTF writer: Fixed bug. Extra spaces were being printed after emphasized,
+ boldface, and other inline elements. Resolves Issue #64.
+
+ * LaTeX reader: improvements in raw LaTeX parsing.
+
+ + "loose punctuation" (like {}) parsed as Space
+ + Para elements must contain more than Str "" and Space elements
+ + Added parser for "\ignore" command used in literate haskell.
+ + Reworked unknownCommand and rawLaTeXInline: when not in "parse raw"
+ mode, these parsers simply strip off the command part and allow
+ the arguments to be parsed normally. So, for example,
+ \blorg{\emph{hi}} will be parsed as Emph "hi" rather than
+ Str "{\\emph{hi}}".
+ + Parse lhs "code" environments as verbatim.
+ Refactored parsers for verbatim environments.
+ + Removed specialEnvironment parser.
+ + parse '{}', if present, after \textless, \textgreater,
+ \textbar, \textbackslash, \ldots.
+ + Parse unescaped special characters verbatim rather than
+ changing them to spaces. This way arguments of unknown
+ commands will appear in braces.
+
+ * Parse raw ConTeXt environments as TeX in markdown reader.
+ Resolves Issue #73.
+
+ * Moved BlockWrapper and wrappedBlocksToDoc from ConTeXt writer to Shared.
+
+ * Made some structural changes to parsing of raw LaTeX environments.
+ Previously there was a special block parser for LaTeX environments.
+ It returned a Para element containing the raw TeX inline. This has
+ been removed, and the raw LaTeX environment parser is now used in the
+ rawLaTeXInline parser. The effect is exactly the same, except that we
+ can now handle consecutive LaTeX and ConTeXt environments not separated
+ by spaces. This new flexibility is required by the example in
+ Issue #73:
+
+ \placeformula \startformula
+ L_{1} = L_{2}
+ \stopformula
+
+ API change: The LaTeX reader now exports rawLaTeXEnvironment' (which
+ returns a string) rather than rawLaTeXEnvironment (which returns a block
+ element). This is more likely to be useful in other applications.
+
+ * Use \textsubscr instead of \textsubscript for LaTeX subscript macro.
+ \textsubscript conflicts with a definition in the memoir class.
+ Resolves Issue #65.
+
+ * Removed unneeded space after "\\item" in LaTeX and ConTeXt output.
+
+ * Added amsmath package to default LaTeX header. Resolves Issue #48.
+
+ * Added \setupitemize[autointro] to ConTeXt header, to prevent orphaned
+ list introduction lines.
+
+ * Changed Float to Double in definition of Table element.
+ (Double is more efficient in GHC.)
+
+ * Fixed bug in Markdown parser: regular $s triggering math mode.
+ For example: "shoes ($20) and socks ($5)."
+ The fix consists in two new restrictions:
+
+ + the $ that ends a math span may not be directly followed by a digit.
+ + no blank lines may be included within a math span.
+
+ Thanks to Joseph Reagle for noticing the bug.
+
+ * Use Data.List's 'intercalate' instead of custom 'joinWithSep'.
+ Removed 'joinWithSep' from Text.Pandoc.Shared.
+
+ * Updated README and man pages. Acknowledge contributors in README.
+ Added paragraph to README about producing S5 with separate CSS/javascript.
+
+ * Updated INSTALL to reflect new build system (including configuration
+ options) and document new dependencies. Added note to INSTALL that
+ Cabal >= 1.2 is required for build. Resolves Issue #74.
+
+ * Fixed some haddock documentation errors.
+
+ * Small fix to markdown2pdf man page: only input needs to be piped through iconv.
+
+pandoc (0.46) unstable; urgency=low
+
+ [ John MacFarlane ]
+
+ * Made -H, -A, and -B options cumulative: if they are specified
+ multiple times, multiple files will be included.
+
+ * Added optional HTML sanitization using a whitelist.
+ When this option is specified (--sanitize-html on the command line),
+ unsafe HTML tags will be replaced by HTML comments, and unsafe HTML
+ attributes will be removed. This option should be especially useful
+ for those who want to use pandoc libraries in web applications, where
+ users will provide the input.
+
+ + Main.hs: Added --sanitize-html option.
+
+ + Text.Pandoc.Shared: Added stateSanitizeHTML to ParserState.
+
+ + Text.Pandoc.Readers.HTML:
+ - Added whitelists of sanitaryTags and sanitaryAttributes.
+ - Added parsers to check these lists (and state) to see if a given
+ tag or attribute should be counted unsafe.
+ - Modified anyHtmlTag and anyHtmlEndTag to replace unsafe tags
+ with comments.
+ - Modified htmlAttribute to remove unsafe attributes.
+ - Modified htmlScript and htmlStyle to remove these elements if
+ unsafe.
+
+ + Modified README and man pages to document new option.
+
+ * Improved handling of email addresses in markdown and reStructuredText.
+ Consolidated uri and email address parsers. (Resolves Issue #37.)
+
+ + New emailAddress and uri parsers in Text.Pandoc.Shared.
+ - uri parser uses parseURI from Network.URI.
+ - emailAddress parser properly handles email addresses with periods
+ in them.
+
+ + Removed uri and emailAddress parsers from Text.Pandoc.Readers.RST
+ and Text.Pandoc.Readers.Markdown.
+
+ * Markdown reader:
+
+ + Fixed emph parser so that "*hi **there***" is parsed as a Strong
+ nested in an Emph. (A '*' is only recognized as the end of the
+ emphasis if it's not the beginning of a strong emphasis.)
+
+ + Moved blockQuote parser before list parsers for performance.
+
+ + Modified 'source' parser to allow backslash-escapes in URLs.
+ So, for example, [my](/url\(1\)) yields a link to /url(1).
+ Resolves Issue #34.
+
+ + Disallowed links within links. (Resolves Issue #35.)
+ - Replaced inlinesInBalanced with inlinesInBalancedBrackets, which
+ instead of hard-coding the inline parser takes an inline parser
+ as a parameter.
+ - Modified reference and inlineNote to use inlinesInBalancedBrackets.
+ - Removed unneeded inlineString function.
+ - Added inlineNonLink parser, which is now used in the definition of
+ reference.
+ - Added inlineParsers list and redefined inline and inlineNonLink parsers
+ in terms of it.
+ - Added failIfLink parser.
+
+ + Better handling of parentheses in URLs and quotation marks in titles.
+ - 'source' parser first tries to parse URL with balanced parentheses;
+ if that doesn't work, it tries to parse everything beginning with
+ '(' and ending with ')'.
+ - source parser now uses an auxiliary function source'.
+ - linkTitle parser simplified and improved, under assumption that it
+ will be called in context of source'.
+
+ + Make 'block' conditional on strictness state, instead of using
+ failIfStrict in block parsers. Use a different ordering of parsers
+ in strict mode (raw HTML block before paragraph) for performance.
+ In non-strict mode use rawHtmlBlocks instead of htmlBlock.
+ Simplified htmlBlock, since we know it's only called in strict
+ mode.
+
+ + Improved handling of raw HTML. (Resolves Issue #36.)
+ - Tags that can be either block or inline (e.g. <ins>) should
+ be treated as block when appropriate and as inline when
+ appropriate. Thus, for example,
+ <ins>hi</ins>
+ should be treated as a paragraph with inline <ins> tags, while
+ <ins>
+ hi
+ </ins>
+ should be treated as a paragraph within <ins> tags.
+ - Moved htmlBlock after para in list of block parsers. This ensures
+ that tags that can be either block or inline get parsed as inline
+ when appropriate.
+ - Modified rawHtmlInline' so that block elements aren't treated as
+ inline.
+ - Modified para parser so that paragraphs containing only HTML tags and
+ blank space are not allowed. Treat these as raw HTML blocks instead.
+
+ + Fixed bug wherein HTML preceding a code block could cause it to
+ be parsed as a paragraph. The problem is that the HTML parser
+ used to eat all blank space after an HTML block, including the
+ indentation of the code block. (Resolves Issue #39.)
+ - In Text.Pandoc.Readers.HTML, removed parsing of following space
+ from rawHtmlBlock.
+ - In Text.Pandoc.Readers.Markdown, modified rawHtmlBlocks so that
+ indentation is eaten *only* on the first line after the HTML
+ block. This means that in
+ <div>
+ foo
+ <div>
+ the foo won't be treated as a code block, but in
+ <div>
+
+ foo
+
+ </div>
+ it will. This seems the right approach for least surprise.
+
+ * RST reader:
+
+ + Fixed bug in parsing explicit links (resolves Issue #44).
+ The problem was that we were looking for inlines until a '<' character
+ signaled the start of the URL; so, if you hit a reference-style link,
+ it would keep looking til the end of the document. Fix: change
+ inline => (notFollowedBy (char '`') >> inline). Note that this won't
+ allow code inlines in links, but these aren't allowed in resT anyway.
+
+ + Cleaned up parsing of reference names in key blocks and links.
+ Allow nonquoted reference links to contain isolated '.', '-', '_', so
+ so that strings like 'a_b_' count as links.
+
+ + Removed unnecessary check for following link in str.
+ This is unnecessary now that link is above str in the definition of
+ 'inline'.
+
+ * HTML reader:
+
+ + Modified rawHtmlBlock so it parses </html> and </body> tags.
+ This allows these tags to be handled correctly in Markdown.
+ HTML reader now uses rawHtmlBlock', which excludes </html> and </body>,
+ since these are handled in parseHtml. (Resolves Issue #38.)
+
+ + Fixed bug (emph parser was looking for <IT> tag, not <I>).
+
+ + Don't interpret contents of style tags as markdown.
+ (Resolves Issue #40.)
+ - Added htmlStyle, analagous to htmlScript.
+ - Use htmlStyle in htmlBlockElement and rawHtmlInline.
+ - Moved "script" from the list of tags that can be either block or
+ inline to the list of block tags.
+
+ + Modified rawHtmlBlock to use anyHtmlBlockTag instead of anyHtmlTag
+ and anyHtmlEndTag. This fixes a bug in markdown parsing, where
+ inline tags would be included in raw HTML blocks.
+
+ + Modified anyHtmlBlockTag to test for (not inline) rather than
+ directly for block. This allows us to handle e.g. docbook in
+ the markdown reader.
+
+ * LaTeX reader: Properly recognize --parse-raw in rawLaTeXInline.
+ Updated LaTeX reader test to use --parse-raw.
+
+ * HTML writer:
+
+ + Modified rules for automatic HTML header identifiers to
+ ensure that identifiers begin with an alphabetic character.
+ The new rules are described in README. (Resolves Issue #33.)
+
+ + Changed handling of titles in HTML writer so you don't get
+ "titleprefix - " followed by nothing.
+
+ * ConTeXt writer: Use wrappers around Doc elements to ensure proper
+ spacing. Each block element is wrapped with either Pad or Reg.
+ Pad'ed elements are guaranteed to have a blank line in between.
+
+ * RST writer:
+
+ + Refactored RST writer to use a record instead of a tuple for state,
+ and to include options in state so it doesn't need to be passed as
+ a parameter.
+
+ + Use an interpreted text role to render math in restructuredText.
+ See http://www.american.edu/econ/itex2mml/mathhack.rst for the
+ strategy.
+
+ [ Recai Oktaş ]
+
+ * Debian packaging changes:
+
+ + Remove the empty 'include' directory in -dev package, which lintian
+ complains about.
+ + Bump Standarts-Version to 3.7.3.
+ + Use new 'Homepage:' field to specify the upstream URL on suggestion of
+ lintian.
+
+ -- Recai Oktaş <roktas@debian.org> Tue, 08 Jan 2008 05:13:31 +0200
+
+pandoc (0.45) unstable; urgency=low
+
+ [ John MacFarlane ]
+
+ * Simplified parsing of reference keys and notes in markdown and RST
+ readers: The Reference data structure from Text.Pandoc.Shared is no
+ longer needed, since referenceKey and noteBlock parses return strings
+ (as many blank lines as were occupied by the key or note) and update
+ state themselves. getPosition and setPosition are now used to ensure
+ that error messages will give the correct line number. This yields
+ cleaner (and slightly faster) code, with more accurate parsing error
+ messages.
+
+ * Added new Math inline element:
+
+ + Markdown and LaTeX readers now convert TeX math into Math elements,
+ not TeX.
+ + This allows math to be treated differently from raw TeX in output.
+ TeX elements are no longer printed in output formats other than
+ Markdown, LaTeX, and ConTeXt. But Math elements are always printed.
+
+ * New default handling of math in writers:
+
+ + New module Text.Pandoc.Readers.TeXMath exports readTeXMath, which
+ parses raw TeX math and outputs a string of Pandoc inlines that
+ tries to render it as far as possible using unicode characters,
+ lapsing into literal TeX when needed.
+ + readTeXMath is now used for default HTML output in HTML, S5, RTF,
+ and Docbook, if no other method for displaying math in HTML is
+ specified. Enclosing $'s are no longer printed by default.
+ + By default, math is put inside <span class="math">. This way it can be
+ distinguished from the surrounding text, e.g. put in a different
+ font.
+
+ * New --gladtex and --mimetex options for display of math in HTML:
+
+ + If --gladtex is specified, math is output between <eq> tags, so
+ it can be processed by gladTeX.
+ + If --mimetex is specified, math is put in <img> tags with a link
+ to the mimetex CGI script (or any other script that takes TeX math
+ as input and outputs an image). The URL of the script may be
+ specified, but defaults to /cgi-bin/mimetex.cgi.
+ + HTMLMathMethod structure in WriterOptions keeps track of how to
+ display math in HTML output.
+ + Updated README with a description of the four options for displaying
+ math in HTML.
+
+ * HTML reader:
+
+ + Fixed bug: parser for minimized attributes should not swallow
+ trailing spaces.
+ + Simplified HTML attribute parsing.
+ + Changed parsing of code blocks in HTML reader: <code> tag is no
+ longer needed. <pre> suffices. All HTML tags in the code block
+ (e.g. for syntax highlighting) are skipped, because they are not
+ portable to other output formats. A <code>...</code> block not
+ surrounded by <pre> now counts as inline HTML, not a code block.
+ + Remove just one leading and one trailing newline from contents of
+ <pre>...</pre> in codeBlock parser.
+
+ * Markdown reader:
+
+ + Removed support for box-style block quotes.
+ + Require space before title in links and references.
+ This fixes a bug in parsing URLs like http://silly/url(withparen).
+ + Improved and simplified setextHeader parser.
+ + Fixed logic in smart quote parsing, adding some needed 'try'
+ statements.
+ + Fixed smart quote parsing so that unicode characters 8216 and 8217
+ are recognized as single quotes, and 8220 and 8221 as double quotes.
+
+ * RST reader:
+
+ + Fixed bug in parsing of code blocks. Previously a full tab indent
+ was required, but RST allows code to be indented any amount.
+ Resolves Issue #27.
+ + Allow field lists to be indented.
+ + Parse the contents of field lists instead of treating as a raw string.
+ + Represent field lists as definition lists instead of blockquotes.
+ + Fixed bug in which metadata would be overridden if the document
+ contained multiple field lists.
+ + Parse fields associated with '.. image::' blocks, and use 'alt'
+ field, if given, for image alt and title attributes.
+
+ * LaTeX reader:
+
+ + Modified specialChar so that '"' characters are parsed.
+ + Fixed a bug in parsing of \[ \] math blocks (thanks to Mark Kalderon).
+
+ * HTML writer:
+
+ + Changes in handling of math (see above).
+ + Don't produce HTML for table of contents if there are
+ no headers. (This would be an empty list, which is invalid XHTML.)
+
+ * Markdown writer:
+
+ + Don't print title attribute if title is empty. (This differs from
+ the behavior of Markdown.pl, and agrees with PHP Markdown. But John
+ Gruber has indicated that he prefers this behavior.) Adjusted test
+ suite accordingly.
+ + Fixed incorrect line wrapping in paragraphs including hard line
+ breaks. Resolves Issue #25.
+ + Fixed bug in markdown writer: If an ordered list item began with
+ a marker greater than 3 characters in width, and the item took more
+ than one line, it would appear on the line after the list marker,
+ e.g.:
+
+ (12)
+ My list item.
+ Multiline.
+
+ Now it works as follows:
+
+ (12) My list item.
+ Multiline.
+
+ * RST writer
+
+ + Fixed bug in RST writer's handling of ordered lists. Previously,
+ list items with multiple lines would not always line up with
+ single-line list items. Now, list items are nested the length of
+ the list marker + 1. This looks better and ensures that list items
+ all line up. (Note that list markers are padded to the length of
+ the longest list marker in the series.)
+ + Use 3-space indent for unordered lists.
+ + If label for a link reference contains a colon, surround it by `
+ signs so it won't be interpreted as the end of the link label.
+
+ * LaTeX writer:
+
+ + Cleaner output for footnotes. Footnotes now always begin on a new
+ line, and the final } is on a line by itself only when it needs to
+ be (i.e. only when the note ends with a Verbatim environment).
+ + Added writer options to state, so state doesn't need to be passed as
+ a parameter.
+ + Text wrapping now provided, using wrapTeXIfNeeded.
+
+ * ConTeXt writer: many improvements for more idiomatic ConTeXt output
+ (thanks to Idris Samawi Hamid for suggestions).
+
+ + PrettyPrint module now used for output.
+ + Writer options are now in state, so they don't have to be passed as
+ a parameter.
+ + Text wrapping now provided, using wrapTeXIfNeeded.
+ + Better treatment of footnotes: footnotes are always on lines by
+ themselves, and the final } is on a line by itself only when
+ it needs to be (after \stoptyping).
+ + Use \subject, \subsubject, ... or \section, \subsection, ... for headings,
+ depending on whether --number-sections option is selected.
+ + Extra blank line inserted after \stopitemize
+ + Use new, "official" definition of blockquote environment. Also, use
+ blank line after \startblockquote to balance blank line at the end.
+ + Both itemized and enumerated lists are now generated using
+ \start-stopitemize, with appropriate options. Removed definitions
+ of ltxenum and ltxitem, which are no longer needed. Provided
+ defaults for itemized lists in the preamble. State keeps track of
+ ordered list level, so that when default numbering is specified,
+ the appropriate scheme can be used.
+ + Changed \useurl to \useURL.
+ + Changed link color from red to blue.
+ + Use \subsubsubsubsection etc., since these are supported
+ (up to at least sub x 5).
+
+ * Text.Pandoc.Shared:
+
+ + Save and restore position in parseFromString, so that accurate
+ error messages can be given.
+ + Improved efficiency of romanNumeral parser.
+ + Added wrappedTeX and wrapTeXIfNeeded functions. These ensure
+ that footnotes occur on lines by themselves (to make them
+ easier to see and move) and do not screw up line wrapping.
+
+ * Text.Pandoc.UTF8: modified fromUTF8 to strip out the BOM
+ if present. Windows Notepad and other applications insert a
+ BOM at the beginning of a UTF8 file.
+
+ * Main.hs (tabFilter): Treat '\r' at end of line as newline (in
+ addition to "\r\n" and '\n').
+
+ * Added a writer option for wrapped text and a command-line option
+ '--no-wrap', which disables text wrapping and minimizes whitespace
+ in HTML. (Resolves Issue #26.)
+
+ + Added support for '--no-wrap' to Main.hs.
+ + Added wrapIfNeeded function to Text.Pandoc.Shared.
+ + Use wrapIfNeeded instead of wrapped in the RST, Man, Docbook, and
+ Markdown writers.
+ + Added render and renderFragment helpers to HTML writer.
+
+ * Modified html2markdown to run tidy only if the HTML cannot be
+ parsed. Previously html2markdown piped all input through tidy
+ before passing it to pandoc. This caused problems on certain pages
+ (e.g. http://daringfireball.com/markdown) which have well-formed
+ XHTML that causes tidy to choke. The solution is to pipe through
+ tidy only if pandoc cannot parse the input by itself. This means
+ that a temp file is now always used, even when input comes from a
+ local file or standard input.
+
+ * Removed 'version' constant from Main.hs; added 'pandocVersion' to
+ Text.Pandoc library.
+
+ * pandoc.cabal:
+
+ + Modified to work with GHC 6.8 and Cabal configurations. (For GHC
+ 6.8, pretty and containers must be added to Build-Depends, and it
+ is desirable to use the -O2 compiler option.) Cabal configurations
+ allows one to select options depending on the compiler version.
+ For GHC 6.6, the splitBase option can be disabled.
+ + pandoc.cabal.ghc66 is provided for users with older versions of
+ Cabal, which do not support configurations.
+ + Use Ghc-Prof-Options to ensure that '-auto-all' is used when
+ '--enable-(executable|library)-profiling' is specified. Updated
+ PROFILING instructions accordingly.
+
+ * Makefile:
+
+ + Makefile now checks GHC version. If GHC is 6.6, pandoc.cabal.ghc66
+ is copied to pandoc.cabal, and the old pandoc.cabal is copied
+ to pandoc.cabal.orig. Otherwise, pandoc.cabal is copied to
+ pandoc.cabal.orig but otherwise unmodified. This way, the Makefile
+ will work properly with either GHC 6.6 or 6.8.
+ + Changed BUILDCONF to point to dist/setup-config, not .setup-config.
+ This is where current versions of Cabal put it.
+ + Added $(BUILDCMD) target, so setup doesn't get compiled every time.
+ + Removed dependency of templates on ./templates, which is circular
+ now that templates is a subdirectory of the top-level.
+
+ * MacPorts Portfile:
+
+ + Modified to install the pandoc library in addition to programs.
+ + Installation must be done manually rather than using Makefile's
+ install-all.
+ + Note that the library must be registered in the activate phase,
+ after the library files have been copied out of the destroot.
+ Cabal generates a 'register.sh' script that will do this.
+
+ * debian/control: Added libghc6-network-dev, libghc6-xhtml-dev, and
+ libghc6-mtl-dev as dependencies for libghc6-pandoc-dev.
+ Closes: #445235
+
+ * debian/rules: Converted to UTF-8.
+
+ * Changed pandoc home page to http://johnmacfarlane.net/pandoc/.
+
+ * Updated ASCIIMathML.js to latest version.
+
+ * Directory structure:
+
+ + Moved everything from src into the top-level directory.
+ + Changed references to source directory in Makefile and
+ pandoc.cabal.*.
+ + Moved ASCIIMathML.js, headers, and ui into templates directory.
+ + Modified fillTemplates.pl to reflect new paths.
+
+ [ Recai Oktaş ]
+
+ * Makefile: Fixed the issue of having two copies of the library
+ documentation under some usage scenarios.
+
+ * Replaced 'ghc' with '$(GHC)' in Makefile, and made GHC
+ and GHC_PKG configurable through the environment, to support
+ unusual ghc installations. For example:
+ GHC=/opt/ghc/bin/ghc GHC_PKG=/opt/ghc/bin/ghc-pkg make
+
+ -- Recai Oktaş <roktas@debian.org> Sun, 07 Oct 2007 20:51:43 +0300
+
+pandoc (0.44) unstable; urgency=low
+
+ [ John MacFarlane ]
+
+ * Fixed bug in HTML writer: when --toc was used, anchors were put around
+ headers, which is invalid XHTML (block content within inline element).
+ Now the anchors are put inside the header tags. Resolves Issue #23.
+
+ * Added xmlns attribute to html element in html writer tests.
+ This attribute is added by more recent versions of the
+ xhtml library (>= 3000), and is required for valid XHTML.
+
+ [ Recai Oktaş ]
+
+ * On configure, compile 'Setup.hs' to 'setup' and use 'setup' as the build
+ command instead of 'runhaskell', which, on some platforms (such as s390,
+ alpha, m68k), throws the following error:
+
+ runhaskell Setup.hs configure --prefix=/usr
+ ghc-6.6.1: not built for interactive use
+
+ This causes a serious FTBFS bug. Closes: #440668.
+
+ -- Recai Oktaş <roktas@debian.org> Mon, 03 Sep 2007 18:24:02 +0300
+
+pandoc (0.43) unstable; urgency=low
+
+ [ John MacFarlane ]
+
+ * The focus of this release is performance. The markdown parser
+ is about five times faster than in 0.42, based on benchmarks
+ with the TextMate manual.
+
+ * Main.hs: Replaced CRFilter and tabFilter with single function
+ tabFilter, which operates on the whole string rather than breaking
+ it into lines, and handles dos-style line-endings as well as tabs.
+
+ * Added separate LaTeX reader and native reader tests; removed
+ round-trip tests.
+
+ * Text.Pandoc.Shared:
+
+ + Removed tabsToSpaces and tabsInLine (they were used only in Main.hs.)
+ + General code cleanup (to elimante warnings when compiling with -Wall.)
+ + Added 'wrapped' function, which helps wrap text into paragraphs,
+ using the prettyprinting library.
+ + Rewrote charsInBalanced and charsInBalanced'.
+ - Documented restriction: open and close must be distinct characters.
+ - Rearranged options for greater efficiency.
+ - Bug fix: Changed inner call to charsInBalanced inside
+ charsInBalanced' to charsInBalanced'.
+ + anyLine now requires that the line end with a newline (not eof).
+ This is a harmless assumption, since we always add newlines to the
+ end of a block before parsing with anyLine, and it yields a 10% speed
+ boost.
+ + Removed unnecessary 'try' in anyLine.
+ + Removed unneeded 'try' from romanNumeral parser.
+ + Use notFollowedBy instead of notFollowedBy' in charsInBalanced.
+ + Removed unneeded 'try' in parseFromString.
+ + Removed unneeded 'try' from stringAnyCase. (Now it behaves
+ like 'string'.)
+ + Changed definition of 'enclosed' in Text.Pandoc.Shared so that
+ 'try' is not automatically applied to the 'end' parser. Added
+ 'try' in calls to 'enclosed' where needed. Slight speed increase.
+
+ * Writers:
+
+ + Replaced individual wrapping routines in RST, Man, and Markdown
+ writers with 'wrapped' from Text.Pandoc.Shared.
+ + Rewrote LaTeX writer to use the prettyprinting library,
+ so we get word wrapping, etc.
+ + Modified latex writer tests for new latex writer using prettyprinter.
+ + Fixed bug in LaTeX writer: autolinks would not cause
+ '\usepackage{url}' to be put in the document header. Also, changes
+ to state in enumerated list items would be overwritten.
+ + In Markdown writer, escape paragraphs that begin with ordered list
+ markers, so they don't get interpreted as ordered lists.
+
+ * Text.Pandoc.Reades.LaTeX:
+
+ + Fixed bug in LaTeX reader, which wrongly assumed that the roman
+ numeral after "enum" in "setcounter" would consist entirely of
+ "i"s. 'enumiv' is legitimate.
+ + LaTeX command and environment names can't contain numbers.
+ + Rearranged order of parsers in inline for slight speed improvement.
+ + Added '`' to special characters and 'unescapedChar'.
+
+ * Text.Pandoc.Readers.RST:
+
+ + Removed unneeded try's in RST reader; also minor code cleanup.
+ + Removed tabchar.
+ + Rearranged parsers in inline (doubled speed).
+
+ * Text.Pandoc.Readers.Markdown:
+
+ + Skip notes parsing if running in strict mode. (This yields a nice
+ speed improvement in strict mode.)
+ + Simplify autolink parsing code, using Network.URI to test for
+ URIs. Added dependency on network library to debian/control and
+ pandoc.cabal.
+ + More perspicuous definition of nonindentSpaces.
+ + Removed unneeded 'try' in 'rawLine'.
+ + Combined linebreak and whitespace into a new whitespace parser, to
+ avoid unnecessary reparsing of space characters.
+ + Removed unnecessary 'try' in 'codeBlock', 'ellipses', 'noteMarker',
+ 'multilineRow', 'dashedLine', 'rawHtmlBlocks'.
+ + Use lookAhead in parsers for setext headers and definition lists
+ to see if the next line begins appropriately; if not, don't waste
+ any more time parsing.
+ + Don't require blank lines after code block. (It's sufficient to
+ end code block with a nonindented line.)
+ + Changed definition of 'emph': italics with '_' must not
+ be followed by an alphanumeric character. This is to help
+ prevent interpretation of e.g. [LC_TYPE]: my_type as
+ '[LC<em>TYPE]:my</em>type'.
+ + Improved Markdown.pl-compatibility in referenceLink: the two parts
+ of a reference-style link may be separated by one space, but not
+ more... [a] [link], [not] [a link].
+ + Fixed markdown inline code parsing so it better accords with
+ Markdown.pl: the marker for the end of the code section is a clump
+ of the same number of `'s with which the section began, followed
+ by a non-` character. So, for example,
+ ` h ``` i ` -> <code>h ``` i</code>.
+ + Split 'title' into 'linkTitle' and 'referenceTitle', since the
+ rules are slightly different.
+ + Rewrote 'para' for greater efficiency.
+ + Rewrote link parsers for greater efficiency.
+ + Removed redundant 'referenceLink' in definition of inline (it's
+ already in 'link').
+ + Refactored escapeChar so it doesn't need 'try'.
+ + Refactored hrule for performance in Markdown reader.
+ + More intelligent rearranging of 'inline' so that most frequently
+ used parsers are tried first.
+ + Removed tabchar parser, as whitespace handles tabs anyway.
+
+ * Text.Pandoc.CharacterReferences:
+
+ + Refactored.
+ + Removed unnecessary 'try's for a speed improvement.
+ + Removed unnecessary '&' and ';' from the entity table.
+
+ * Build process:
+
+ + Makefile: Get VERSION from cabal file, not Main.hs.
+ + Modified MacPorts Portfile:
+ - Depend on haddock
+ - Build and install libraries and library documentation in
+ addition to pandoc executable
+ - Added template item for md5 sum in Portfile.in.
+ - Incorporated changes from MacPorts repository (r28278).
+ + FreeBSD port: Don't try to generate distinfo in Makefile.
+ It can be made using 'make makesum' in FreeBSD.
+ + Make both freebsd and macports targets depend on tarball.
+
+ * Website and documentation:
+
+ + Updated INSTALL instructions.
+ + Added pandocwiki demo to website.
+ + Removed local references to Portfile, since pandoc is now in the
+ MacPorts repository.
+
+ -- Recai Oktaş <roktas@debian.org> Sun, 02 Sep 2007 15:50:11 +0300
+
+pandoc (0.42) unstable; urgency=low
+
+ [ John MacFarlane ]
+
+ * Main.hs: Use utf8 conversion on the extra files loaded with
+ the -H, -C, -B, and -A options. This fixes problems with unicode
+ characters in these files.
+
+ * Exposed Text.Pandoc.ASCIIMathML, since it is imported in
+ Text.Pandoc.Readers.HTML and without it we get a linking error when
+ using the library.
+
+ * Markdown reader:
+
+ + Added new rule for enhanced markdown ordered lists: if the list
+ marker is a capital letter followed by a period (including a
+ single-letter capital roman numeral), then it must be followed by
+ at least two spaces. The point of this is to avoid accidentally
+ treating people's initials as list markers: a paragraph might begin,
+ "B. Russell was an English philosopher," and this shouldn't be
+ treated as a list. Documented change in README.
+ + Blocks that start with "p. " and a digit are no longer treated
+ as ordered lists (it's a page number).
+ + Added a needed 'try' to listItem.
+ + Removed check for a following setext header in endline.
+ A full test is too inefficient (doubles benchmark time), and the
+ substitute we had before is not 100% accurate.
+ + Don't use Code elements for autolinks if --strict specified.
+
+ * LaTeX writer: When a footnote ends with a Verbatim environment, the
+ close } of the footnote cannot occur on the same line or an error occurs.
+ Fixed this by adding a newline before the closing } of every footnote.
+
+ * HTML writer:
+ + Removed incorrect "{}" around style information in HTML tables.
+ Column widths now work properly in HTML.
+ + If --strict option is specified (and --toc is not), don't include
+ identifiers in headers, for better Markdown compatibility.
+
+ * Build process:
+
+ + Separated $(web_dest) and website targets.
+ + In website, index.txt is now constructed from template index.txt.in.
+ + Added freebsd target to Markefile. This creates the freebsd Makefile
+ from Makefile.in, and creates distinfo. Removed Makefile and distinfo
+ from the repository.
+ + Added macport target to Makefile. Portfile is built from template
+ Portfile.in.
+ + Removed OSX package targets. (Too many difficulties involving
+ dependencies on dynamic libraries.)
+ + More complete INSTALL instructions for all architectures.
+
+ * Website:
+ + Added a programming demo, pandocwiki.
+
+ [ Recai Oktaş ]
+
+ * Do not forget to close pandoc's ITP. Closes: #391666
+
+ -- Recai Oktaş <roktas@debian.org> Sun, 26 Aug 2007 22:51:32 +0300
+
+pandoc (0.41) unstable; urgency=low
+
+ [ John MacFarlane ]
+
+ * Fixed bugs in HTML reader:
+ + Skip material at end *only if* </html> is present (previously,
+ only part of the document would be parsed if an error was
+ found; now a proper error message is given).
+ + Added new constant eitherBlockOrInline with elements that may
+ count either as block-level or as inline. Modified isInline and
+ isBlock to take this into account.
+ + Modified rawHtmlBlock to accept any tag (even an inline tag):
+ this is innocuous, because rawHtmlBlock is tried only if a regular
+ inline element can't be parsed.
+ + Added a necessary 'try' in definition of 'para'.
+
+ * Fixed bug in markdown ordered list parsing. The problem was that
+ anyOrderedListStart did not check for a space following the
+ ordered list marker. So in 'A.B. 2007' the parser would be
+ expecting a list item, but would not find one, causing an error.
+ Fixed a similar bug in the RST reader. Resolves Issue #22.
+
+ * Refactored RST and Markdown readers using parseFromString.
+
+ * LaTeX reader will now skip anything after \end{document}.
+
+ * Fixed blockquote output in markdown writer: previously, block
+ quotes in indented contexts would be indented only in the first
+ line.
+
+ * Added note to INSTALL about variations in versions of the xhtml
+ library that can lead to failed tests (thanks to Leif LeBaron).
+
+ -- Recai Oktaş <roktas@debian.org> Sun, 19 Aug 2007 23:26:07 +0300
+
+pandoc (0.4) unstable; urgency=low
+
+ [ John MacFarlane ]
+
+ * Added two new output formats: groff man pages and ConTeXt. By
+ default, output files with extensions ".ctx" and ".context" are
+ assumed to be ConTeXt, and output files with single-digit extensions
+ are assumed to be man pages.
+
+ * Enhanced ordered lists (documented in README, under Lists):
+ + The OrderedList block element now stores information about
+ list number style, list number delimiter, and starting number.
+ + The readers parse this information when possible.
+ + The writers use this information to style ordered lists.
+ + The enhancement can be disabled using the --strict option.
+
+ * Added support for tables (with a new Table block element). Two kinds
+ of tables are supported: a simple table with one-line rows, and a
+ more complex variety with multiline rows. All output formats are
+ supported, but only markdown tables are parsed at the moment. The
+ syntax is documented in README.
+
+ * Added support for definition lists (with a new DefinitionList block
+ element). All output and input formats are supported. The syntax is
+ documented in README.
+
+ * Added support for superscripts and subscripts (with new Superscript
+ and Subscript inline elements). All input and output
+ formats. The syntax is documented in README.
+
+ * Added support for strikeout (with a new Strikeout inline element).
+ All input and output formats are supported. Thanks to Bradley Kuhn,
+ who contributed a patch. The syntax is documented in README. Resolves
+ Issue #18.
+
+ * Added a --toc|--table-of-contents option. This causes an automatically
+ generated table of contents (or an instruction that creates one) to
+ be inserted at the beginning of the document. Not supported in S5,
+ DocBook, or man page writers.
+
+ * Modified the -m|--asciimathml option:
+
+ + If an optional URL argument is provided, a link is inserted
+ instead of the contents of the ASCIIMathML.js script.
+ + Nothing is inserted unless the document actually contains
+ LaTeX math.
+
+ * Removed Blank block element as unnecessary.
+
+ * Removed Key and Note blocks from the Pandoc data structure. All
+ links are now stored as explicit links, and note contents are
+ stored with the (inline) notes.
+
+ + All link Targets are now explicit (URL, title) pairs; there
+ is no longer a 'Ref' target.
+ + Markdown and RST parsers now need to extract data from key and
+ note blocks and insert them into the relevant inline elements.
+ Other parsers have been simplified, since there is no longer any need
+ to construct separate key and note blocks.
+ + Markdown, RST, and HTML writers need to construct lists of
+ notes; Markdown and RST writers need to construct lists of link
+ references (when the --reference-links option is specified); and
+ the RST writer needs to construct a list of image substitution
+ references. All writers have been rewritten to use the State monad
+ when state is required.
+ + Several functions (generateReference, keyTable,
+ replaceReferenceLinks, replaceRefLinksBlockList, and some auxiliaries
+ used by them) have been removed from Text.Pandoc.Shared, since
+ they are no longer needed. New functions and data structures
+ (Reference, isNoteBlock, isKeyBlock, isLineClump) have been
+ added. The functions inTags, selfClosingTag, inTagsSimple, and
+ inTagsIndented have been moved to the DocBook writer, since that
+ is now the only module that uses them. NoteTable is now exported
+ in Text.Pandoc.Shared.
+ + Added stateKeys and stateNotes to ParserState; removed stateKeyBlocks,
+ stateKeysUsed, stateNoteBlocks, stateNoteIdentifiers, stateInlineLinks.
+ + Added writerNotes and writerReferenceLinks to WriterOptions.
+
+ * Added Text.Pandoc module that exports basic readers, writers,
+ definitions, and utility functions. This should export everything
+ needed for most uses of Pandoc libraries. The haddock documentation
+ includes a short example program.
+
+ * Text.Pandoc.ASCIIMathML is no longer an exported module.
+
+ * Added Text.Pandoc.Blocks module to help in printing markdown
+ and RST tables. This module provides functions for working with
+ fixed-width blocks of text--e.g., placing them side by side, as
+ in a table row.
+
+ * Refactored to avoid reliance on Haskell's Text.Regex library, which
+ (a) is slow, and (b) does not properly handle unicode. This fixed
+ some strange bugs, e.g. in parsing S-cedilla, and improved performance.
+
+ + Replaced 'gsub' with a general list function 'substitute'
+ that does not rely on Text.Regex.
+ + Rewrote extractTagType in HTML reader so that it doesn't use
+ regexs.
+ + In Markdown reader, replaced email regex test with a custom email
+ autolink parser (autoLinkEmail). Also replaced selfClosingTag regex
+ with a custom function isSelfClosingTag.
+ + Modified Docbook writer so that it doesn't rely on Text.Regex for
+ detecting 'mailto' links.
+ + Removed escapePreservingRegex and reamped entity-handling
+ functions in Text.Pandoc.Shared and Text.Pandoc.CharacterReferences to
+ avoid reliance on Text.Regex (see below on character reference
+ handling changes).
+
+ * Renamed Text.Pandoc.Entities as Text.Pandoc.CharacterReferences.
+
+ * Changed handling of XML entities. Entities are now parsed (and unicode
+ characters returned) in the Markdown and HTML readers, rather than being
+ handled in the writers. In HTML and Docbook writers, UTF-8 is now used
+ instead of entities for characters above 128. This makes the HTML and
+ DocBook output much more readable and more easily editable.
+
+ + Removed sgmlHexEntity, sgmlDecimalEntity, sgmlNamedEntity, and
+ sgmlCharacterEntity regexes from Text.Pandoc.Shared.
+ + Renamed escapeSGMLChar to escapeCharForXML. Added escapeStringForXML.
+ Moved both functions to Text.Pandoc.Writers.Docbook.
+ + Added characterReference parser to Text.Pandoc.CharacterReferences.
+ This parses a string and return a unicode character.
+ + Rewrote decodeCharacterReferences to use the new parser instead of
+ Text.Regex.
+ + Added new charRef parser for Markdown and HTML, which replaces the
+ old 'entity' parser. Added '&' as a special character in Markdown reader.
+ + Modified HTML and Markdown readers to call decodeEntities on all raw
+ strings (e.g. authors, dates, link titles), to ensure that no
+ unprocessed entities are included in the native representation of
+ the document. (In the HTML reader, most of this work is done by a
+ change in extractAttributeName.)
+ + In XML and Markdown output, escape unicode nonbreaking space as '&nbsp;',
+ since a unicode non-breaking space is impossible to distinguish visually
+ from a regular space. (Resolves Issue #3.)
+ + Removed encodeEntitiesNumerical.
+ + Use Data.Map for entityTable and (new) reverseEntityTable, for a
+ slight performance boost over the old association list.
+ + Removed unneeded decodeEntities from 'str' parser in HTML and
+ Markdown readers.
+
+ * Text.Pandoc.UTF8: Renamed encodeUTF8 to toUTF8, decodeUTF8 to
+ fromUTF8, for clarity.
+
+ * Replaced old haskell98 module names replaced by hierarchical module
+ names, e.g. List by Data.List. Removed haskell98 from dependencies
+ in pandoc.cabal, and added mtl (needed for state monad). Substituted
+ xhtml for html.
+
+ * Refactored and cleaned up character escaping in writers, using
+ backslashEscapes and escapeStringUsing functions.
+
+ * Instead of adding "\n\n" to the end of an input string in Main.hs,
+ this is now done in the readers. This makes the libraries behave
+ the way you'd expect from the pandoc program. Resolves Issue #10.
+
+ * URLs and email addresses in autolinks are now typeset as Code.
+
+ * In Main.hs, changed putStr to putStrLn -- mainly because MacOS X
+ doesn't display the whole output unless there's a line ending.
+
+ * Major code cleanup in all modules, for greater consistency, concision,
+ and readability.
+
+ * HTML reader:
+
+ + Fixed several bugs (extractTagType, attribute parsing).
+ + Remove Null blocks in lists of blocks when possible.
+ + Allow HTML comments as raw HTML inline.
+
+ * Markdown reader:
+
+ + Ordered list items may no longer begin with uppercase letters, or
+ letters greater than 'n'. (This prevents first initials and page
+ reference, e.g. 'p. 400', from being parsed as beginning lists.)
+ Also, numbers beginning list items may no longer end with ')',
+ which is now allowed only after letters. Note: These changes
+ may cause documents to be parsed differently. Users should take
+ care in upgrading.
+ + Changed autoLink parsing to conform better to Markdown.pl's
+ behavior. <google.com> is not treated as a link, but
+ <http://google.com>, <ftp://google.com>, and <mailto:google@google.com>
+ are.
+ + Cleaned up handling of embedded quotes in link titles. Now these are
+ stored as a '"' character, not as '&quot;'.
+ + Use lookAhead parser for the 'first pass' (looking for reference keys),
+ instead of parsing normally, then using setInput to reset input. This
+ yields a slight performance boost.
+ + Fixed several bugs in smart quote recognition.
+ + Fixed bug in indentSpaces (which didn't properly handle
+ cases with mixed spaces and tabs).
+ + Consolidated 'text', 'special', and 'inline' into 'inline'.
+ + Fixed bug which allowed URL and title to be separated by multiple blank
+ lines in links and reference keys. They can be on separate lines but
+ can't have blank lines between them.
+ + Correctly handle bracketed text inside inline footnotes and links,using
+ new function inlinesInBalanced. Resolves Issue #14.
+ + Fixed bug in footnotes: links in footnotes were not being
+ processed. Solution: three-stage parse. First, get all the
+ reference keys and add information to state. Next, get all the
+ notes and add information to state. (Reference keys may be needed
+ at this stage.) Finally, parse everything else.
+ + Replaced named constants like 'emphStart' with literals.
+ + Removed an extra occurance of escapedChar in definition of inline.
+
+ * RST reader:
+
+ + Allow the URI in a RST hyperlink target to start on the line
+ after the reference key.
+ + Added 'try' in front of 'string', where needed, or used a different
+ parser. This fixes a bug where ````` would not be correctly parsed as
+ a verbatim `.
+ + Fixed slow performance in parsing inline literals in RST reader. The
+ problem was that ``#`` was seen by 'inline' as a potential link or image.
+ Fix: inserted 'notFollowedBy (char '`')' in link parsers.
+ Resolves Issue #8.
+ + Use lookAhead instead of getInput/setInput in RST reader. Removed
+ unneeded getState call, since lookAhead automatically saves and
+ restores the parser state.
+ + Allow hyperlink target URIs to be split over multiple lines, and
+ to start on the line after the reference. Resolves Issue #7.
+ + Fixed handling of autolinks.
+
+ * LaTeX reader:
+
+ + Replaced 'choice [(try (string ...), ...]' idiom with 'oneOfStrings',
+ for clarity.
+ + Added clauses for tilde and caret. Tilde is \ensuremath{\sim}, and
+ caret is \^{}, not \^ as before.
+ + Added parsing for \url.
+ + Parse \texttt{} as code, provided there's nothing fancy inside.
+
+ * HTML writer:
+
+ + Modified HTML writer to use the Text.XHtml library. This results
+ in cleaner, faster code, and it makes it easier to use Pandoc in
+ other projects, like wikis, which use Text.XHtml. Two functions are
+ now provided, writeHtml and writeHtmlString: the former outputs an
+ Html structure, the latter a rendered string. The S5 writer is also
+ changed, in parallel ways (writeS5, writeS5String).
+ + The Html header is now written programmatically, so it has been
+ removed from the 'headers' directory. The S5 header is still
+ needed, but the doctype and some of the meta declarations have
+ been removed, since they are written programatically. This change
+ introduces a new dependency on the xhtml package.
+ + Fixed two bugs in email obfuscation involving improper escaping
+ of '&' in the <noscript> section and in --strict mode. Resolves
+ Issue #9.
+ + Fixed another bug in email obfuscation: If the text to be obfuscated
+ contains an entity, this needs to be decoded before obfuscation.
+ Thanks to thsutton for the patch. Resolves Issue #15.
+ + Changed the way the backlink is displayed in HTML footnotes.
+ Instead of appearing on a line by itself, it now generally
+ appears on the last line of the note. (Exception: when the
+ note does not end with a Plain or Para block.) This saves space
+ and looks better.
+ + Added automatic unique identifiers to headers:
+ - The identifier is derived from the header via a scheme
+ documented in README.
+ - WriterState now includes a list of header identifiers and a table
+ of contents in addition to notes.
+ - The function uniqueIdentifiers creates a list of unique identifiers
+ from a list of inline lists (e.g. headers).
+ - This list is part of WriterState and gets consumed by blockToHtml
+ each time a header is encountered.
+ + Include CSS for .strikethrough class in header only if strikethrough
+ text appears in the document.
+ + If the 'strict' option is specified, elements that do not appear in
+ standard markdown (like definition lists) are passed through as
+ raw HTML.
+ + Simplified treatment of autolinks, using pattern matching instead of
+ conditionals.
+
+ * Markdown writer:
+
+ + Links in markdown output are now printed as inline links by default,
+ rather than reference links. A --reference-links option has been added
+ that forces links to be printed as reference links. Resolves Issue #4.
+ + Use autolinks when possible. Instead of [site.com](site.com),
+ use <site.com>.
+
+ * LaTeX writer:
+
+ + Rewrote to use the State monad. The preamble now includes only those
+ packages that are actually required, given the document's content.
+ Thus, for example, if strikeout is not used, ulem is not required.
+ Modified LaTeXHeader accordingly.
+ + Modified LaTeX writer to insert '\,' between consecutive quotes.
+ + Removed unused function tableRowColumnWidths.
+ + Simplified code for escaping special characters.
+ + Leave extra blank line after \maketitle.
+ + Include empty '\author{}' when no author specified to avoid LaTeX
+ errors.
+ + Include fancyvrb code in header only if needed -- that is, only
+ if there is actually code in a footnote.
+ + Use \url{} for autolinks.
+ + Include [mathletters] option in ucs package, so that basic unicode
+ Greek letters will work correctly.
+
+ * RST writer: Force blank line before lists, so that sublists will
+ be handled correctly.
+
+ * Docbook writer: Fixed a bug: email links with text, like
+ [foo](me@bar.baz), were being incorrectly treated as autolinks.
+
+ * Removed Text.ParserCombinators.Pandoc and moved all its functions to
+ Text.Pandoc.Shared.
+
+ * Text.Pandoc.Shared:
+
+ + Added defaultWriterOptions.
+ + Added writerTableOfContents to WriterOptions.
+ + Added writerIgnoreNotes option to WriterOptions. This is needed
+ for processing header blocks for a table of contents, since notes on
+ headers should not appear in the TOC.
+ + Added prettyprinting for native Table format.
+ + Removed some unneeded imports.
+ + Moved escape and nullBlock parsers from
+ Text.ParserCombinators.Pandoc, since the latter is for
+ general-purpose parsers that don't depend on Text.Pandoc.Definition.
+ + Moved isHeaderBlock from Text.Pandoc.Writers.HTML.
+ + Moved Element, headerAtLeast, and hierarchicalize from Docbook
+ writer, because HTML writer now uses these in constructing a table
+ of contents.
+ + Added clauses for new inline elements (Strikeout, Superscript,
+ Subscript) to refsMatch.
+ + Removed backslashEscape; added new functions escapeStringUsing and
+ backslashEscapes.
+ + Moved failIfStrict from markdown reader, since it is now used also
+ by the HTML reader.
+ + Added a 'try' to the definition of indentSpaces.
+ + In definition of 'reference', added check to make sure it's not a note
+ reference.
+ + Added functions: camelCaseToHyphenated, toRomanNumeral,
+ anyOrderedListMarker, orderedListmarker, orderedListMarkers,
+ charsInBalanced', withHorizDisplacement, romanNumeral
+ + Fixed a bug in the anyLine parser. Previously it would parse an empty
+ string "", but it should fail on an empty string, or we get an error
+ when it is used inside "many" combinators.
+ + Removed followedBy' parser, replacing it with the lookAhead parser from
+ Parsec.
+ + Added some needed 'try's before multicharacter parsers, especially in
+ 'option' contexts.
+ + Removed the 'try' from the 'end' parser in 'enclosed', so that
+ 'enclosed' behaves like 'option', 'manyTill', etc.
+ + Added lineClump parser, which parses a raw line block up to and
+ including any following blank lines.
+ + Renamed parseFromStr to parseFromString.
+ + Added a 'try' to the 'end' parser in 'enclosed'. This makes errors in
+ the use of 'enclosed' less likely. Removed some now-unnecessary 'try's
+ in calling code.
+ + Removed unneeded 'try' in blanklines.
+ + Removed endsWith function and rewrote calling functions to use
+ isSuffixOf instead.
+ + Added >>~ combinator.
+ + Fixed bug in normalizeSpaces: Space:Str "":Space should compress to
+ Space.
+
+ * Refactored runtests.pl; added separate tests for tables.
+
+ * Shell scripts:
+
+ + Added -asxhtml flag to tidy in html2markdown. This will
+ perhaps help the parser, which expects closing tags.
+ + Modified markdown2pdf to run pdflatex a second time if --toc or
+ --table-of-contents was specified; otherwise the table of
+ contents won't appear.
+ + Modified markdown2pdf to print a helpful message if the 'ulem'
+ LaTeX package is required and not found.
+
+ * Changes to build process:
+
+ + Dropped support for compilation with GHC 6.4. GHC 6.6 or higher
+ is now required.
+ + Removed cabalize and Pandoc.cabal.in. The repository now contains
+ pandoc.cabal itself.
+ + Pandoc.cabal has been changed to pandoc.cabal, because HackageDB
+ likes the cabal file to have the same name as the tarball.
+ + Expanded and revised the package description in pandoc.cabal.
+ Revised the package synopsis.
+ + The tarball built by 'make tarball' now contains files built from
+ templates (including man pages and shell scripts), so pandoc can
+ be built directly using Cabal tools, without preprocessing.
+ + Executable binaries are now stripped before installing.
+ + Man pages are now generated from markdown sources, using pandoc's
+ man page writer.
+ + Use HTML version of README (instead of RTF) in Mac OS X installer.
+ + Instead of testing for the existence of a pandoc symlink in build-exec,
+ use ln -f.
+
+ * Documentation:
+
+ + Updated README and man pages with information on new features.
+ + Updated INSTALL instructions with some useful clarifications and
+ links.
+ + Updated web content.
+
+ * Added FreeBSD port.
+
+ [ Recai Oktaş ]
+
+ * debian/control:
+
+ + Changed pandoc's Build-Depends to include libghc6-mtl-dev and
+ libghc6-xhtml-dev. Removed libghc6-html-dev.
+ + Suggest texlive-latex-recommended | tetex-extra instead of
+ tetex-bin. This brings in fancyvrb and unicode support.
+
+ -- Recai Oktaş <roktas@debian.org> Tue, 16 Jan 2007 00:37:21 +0200
+
+pandoc (0.3) unstable; urgency=low
+
+ [ John MacFarlane ]
+
+ * Changes in pandoc options:
+
+ + Allow options to follow or precede arguments.
+ + Changed '--smartypants' to '--smart' and adjusted symbols accordingly.
+ + Added '--strict' option.
+ + Added '-o/--output' option.
+ + Added '--dump-args' and '--ignore-args' options (for use in wrappers).
+ + Modified '-v' and '-h' output to go to STDERR, not STDOUT, and return
+ error conditions. This is helpful for writing wrappers.
+ + Added copyright message to '-v' output, modeled after FSF messages.
+ + Reformatted usage message so that it doesn't wrap illegibly.
+ + Removed extra blanks after '-h' and '-D' output.
+
+ * Added docbook writer.
+
+ * Added implicit setting of default input and output format based
+ on input and output filename extensions. These defaults are
+ overridden if explicit input and output formats are specified using
+ '-t', '-f', '-r', or '-w' options. Documented in pandoc(1) man page
+ and README.
+
+ * Allow ordered list items to begin with (single) letters, as well
+ as numbers. The list item marker may now be terminated either by
+ '.' or by ')'. This extension to standard markdown is documented
+ in README.
+
+ * Revised footnote syntax. (See README for full details.) The
+ '[^1]' format now standard in markdown extensions is supported,
+ as are inline footnotes with this syntax: '^[My note.]'.
+ The earlier footnote syntax '^(1)' is no longer supported.
+
+ * Improved HTML representation of footnotes. All footnotes
+ are now auto-numbered and appear in an ordered list at the
+ end of the HTML document. Since the default appearance is now
+ acceptable, the old footnote styles have been removed from the
+ HTML header.
+
+ * Bug fixes:
+
+ + Fixed a serious bug in the markdown, LaTeX, and RST readers.
+ These readers ran 'runParser' on processed chunks of text to handle
+ embedded block lists in lists and quotation blocks. But then
+ any changes made to the parser state in these chunks was lost,
+ as the state is local to the parser. So, for example, footnotes
+ didn't work in quotes or list items. The fix: instead of calling
+ runParser on some raw text, use setInput to make it the input, then
+ parse it, then use setInput to restore the input to what it was
+ before. This is shorter and more elegant, and it fixes the problem.
+ + Fixed bug in notFollowedBy' combinator (adding 'try' before
+ 'parser'). Adjusted code that uses this combinator accordingly.
+ + Fixed bug in RTF writer that caused improper indentation on
+ footnotes occurring in indented blocks like lists.
+ + Fixed parsing of metadata in LaTeX reader. Now the title, author,
+ and date are parsed correctly. Everything else in the preamble
+ is skipped.
+ + Modified escapedChar in LaTeX reader to allow a '\' at the end of a
+ line to count as escaped whitespace.
+ + Modified LaTeX reader to produce inline links rather than reference
+ links. Otherwise, links in footnotes aren't handled properly.
+ + Fixed handling of titles in links in Markdown reader, so that
+ embedded quotation marks are now handled properly.
+ + Fixed Markdown reader's handling of embedded brackets in links.
+ + Fixed Markdown reader so that it only parses bracketed material
+ as a reference link if there is actually a corresponding key.
+ + Revised inline code parsing in Markdown reader to conform to
+ markdown standard. Now any number of `s can begin inline code,
+ which will end with the same number of `s. For example, to
+ have two backticks as code, write ``` `` ```. Modified Markdown
+ writer accordingly.
+ + Fixed bug in text-wrapping routine in Markdown and RST writers.
+ Now LineBreaks no longer cause wrapping problems.
+ + Supported hexadecimal numerical entity references as well as
+ decimal ones.
+ + Fixed bug in Markdown reader's handling of underscores and other
+ inline formatting markers inside reference labels: for example,
+ in '[A_B]: /url/a_b', the material between underscores was being
+ parsed as emphasized inlines.
+ + Changed Markdown reader's handling of backslash escapes so that
+ only non-alphanumeric characters can be escaped. Strict mode
+ follows Markdown.pl in only allowing a select group of punctuation
+ characters to be escaped.
+ + Modified HTML reader to skip a newline following a <br> tag.
+ Otherwise the newline will be treated as a space at the beginning
+ of the next line.
+
+ * Made handling of code blocks more consistent. Previously, some
+ readers allowed trailing newlines, while others stripped them.
+ Now, all readers strip trailing newlines in code blocks. Writers
+ insert a newline at the end of code blocks as needed.
+
+ * Modified readers to make spacing at the end of output more consistent.
+
+ * Minor improvements to LaTeX reader:
+
+ + '\thanks' now treated like a footnote.
+ + Simplified parsing of LaTeX command arguments and options.
+ commandArgs now returns a list of arguments OR options (in
+ whatever order they appear). The brackets are included, and
+ a new stripFirstAndLast function is provided to strip them off
+ when needed. This fixes a problem in dealing with \newcommand
+ and \newenvironment.
+
+ * Revised RTF writer:
+
+ + Default font is now Helvetica.
+ + An '\f0' is added to each '\pard', so that font resizing works
+ correctly.
+
+ * Moved handling of "smart typography" from the writers to the Markdown
+ and LaTeX readers. This allows great simplification of the writers
+ and more accurate smart quotes, dashes, and ellipses. DocBook can
+ now use '<quote>'. The '--smart' option now toggles an option in
+ the parser state rather than a writer option. Several new kinds
+ of inline elements have been added: Quoted, Ellipses, Apostrophe,
+ EmDash, EnDash.
+
+ * Changes in HTML writer:
+
+ + Include title block in header even when title is null.
+ + Made javascript obfuscation of emails even more obfuscatory,
+ by combining it with entity obfuscation.
+
+ * Changed default ASCIIMathML text color to black.
+
+ * Test suite:
+
+ + Added --strip-trailing-cr option to diff in runtests.pl, for
+ compatibility with Windows.
+ + Added regression tests with footnotes in quote blocks and lists.
+
+ * Makefile changes:
+
+ + osx-pkg target creates a Mac OS X package (directory). New osx
+ directory contains files needed for construction of the package.
+ + osx-dmg target creates a compressed disk image containing the package.
+ + win-pkg target creates Windows binary package.
+ + tarball target creates distribution source tarball.
+ + website target generates pandoc's website automatically, including
+ demos. New 'web' directory containts files needed for construction
+ of the website (which will be created as the 'pandoc' subdirectory
+ of 'web').
+ + Makefile checks to see if we're running Windows/Cygwin; if so,
+ a '.exe' extension is added to each executable in EXECS.
+
+ * Removed all wrappers except markdown2pdf and html2markdown.
+
+ * Added new wrapper hsmarkdown, to be used as a drop-in replacement
+ for Markdown.pl. hsmarkdown calls pandoc with the '--strict'
+ option and disables other options.
+
+ * Added code to html2markdown that tries to determine the character
+ encoding of an HTML file, by parsing the "Content-type" meta tag.
+
+ + If the encoding can't be determined, then if the content is local,
+ the local encoding is used; if it comes from a URL, UTF-8 is used
+ by default.
+ + If input is from STDIN, don't try to determine character encoding.
+ + Encoding can be specified explicitly using '-e' option.
+
+ * Improved warning messages in wrappers:
+
+ + Print warning if iconv not available
+ + More user-friendly error messages in markdown2pdf, when
+ pdflatex fails.
+
+ * Code cleanup:
+
+ + Renamed 'Text/Pandoc/HtmlEntities' module to
+ 'Text/Pandoc/Entities'. Also changed function names so as
+ not to be HTML-specific.
+ + Refactored SGML string escaping functions from HTML and Docbook
+ writers into Text/Pandoc/Shared. (escapeSGML, stringToSGML)
+ + Removed 'BlockQuoteContext' from ParserContext, as it isn't
+ used anywhere.
+ + Removed splitBySpace and replaced it with a general, polymorphic
+ splitBy function.
+ + Refactored LaTeX reader for clarity (added isArg function).
+ + Converted some CR's to LF's in src/ui/default/print.css.
+ + Added license text to top of source files.
+ + Added module data for haddock to source files.
+ + Reformatted code for consistency.
+
+ * Rewrote documentation and man pages. Split README into INSTALL
+ and README.
+
+ * Split LICENSE into COPYING and COPYRIGHT.
+
+ * Removed TODO, since we now maintain ToDo on the wiki.
+
+ * Made COPYRIGHT in top level a symlink to debian/copyright, to avoid
+ duplication.
+
+ [ Recai Oktaş ]
+
+ * Revamped build process to conform to debian standards and created
+ a proper debian package. Closes: #391666.
+
+ * Modified build process to support GHC 6.6.
+
+ + The package can still be compiled using GHC 6.4.2, though because
+ of dependencies the "make deb" target works only with GHC 6.6+.
+ + The script 'cabalize' is used to create an appropriate
+ 'Pandoc.cabal' from 'Pandoc.cabal.in', depending on the GHC and
+ Cabal versions.
+
+ * Refactored template processing (fillTemplates.pl).
+
+ * Modified wrapper scripts to make them more robust and portable.
+ To avoid code duplication and ensure consistency, wrappers are
+ generated via a templating system from templates in src/wrappers.
+
+ + Wrappers now accept multiple filenames, when appropriate.
+ + Spaces and tabs allowed in filenames.
+ + getopts shell builtin is used for portable option parsing.
+ + Improved html2markdown's web grabber code, making it more robust,
+ configurable and verbose. Added '-e', '-g' options.
+
+ -- Recai Oktaş <roktas@debian.org> Fri, 05 Jan 2007 09:41:19 +0200
+
+pandoc (0.2) unstable; urgency=low
+
+ * Fixed unicode/utf-8 translation
+
+ -- John MacFarlane <jgm@berkeley.edu> Mon, 14 Aug 2006 00:00:00 -0400
+
+pandoc (0.1) unstable; urgency=low
+
+ * Initial creation of debian package
+
+ -- John MacFarlane <jgm@berkeley.edu> Mon, 14 Aug 2006 00:00:00 -0400
diff --git a/data/LaTeXMathML.js.comment b/data/LaTeXMathML.js.comment
new file mode 100644
index 000000000..fc60b1f74
--- /dev/null
+++ b/data/LaTeXMathML.js.comment
@@ -0,0 +1,16 @@
+/*
+LaTeXMathML.js from http://math.etsu.edu/LaTeXMathML/
+Adapted by Jeff Knisely and Douglas Woodall from ASCIIMathML.js v. 1.4.7,
+(c) 2005 Peter Jipsen http://www.chapman.edu/~jipsen.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License (at http://www.gnu.org/copyleft/gpl.html)
+for more details.
+*/
diff --git a/data/LaTeXMathML.js.packed b/data/LaTeXMathML.js.packed
new file mode 100644
index 000000000..6ed7447e1
--- /dev/null
+++ b/data/LaTeXMathML.js.packed
@@ -0,0 +1,191 @@
+
+var checkForMathML=true;var notifyIfNoMathML=true;var alertIfNoMathML=false;var mathcolor="";var mathfontfamily="";var showasciiformulaonhover=true;var isIE=document.createElementNS==null;if(document.getElementById==null)
+alert("This webpage requires a recent browser such as \nMozilla/Netscape 7+ or Internet Explorer 6+MathPlayer")
+function AMcreateElementXHTML(t){if(isIE)return document.createElement(t);else return document.createElementNS("http://www.w3.org/1999/xhtml",t);}
+function AMnoMathMLNote(){var nd=AMcreateElementXHTML("h3");nd.setAttribute("align","center")
+nd.appendChild(AMcreateElementXHTML("p"));nd.appendChild(document.createTextNode("To view the "));var an=AMcreateElementXHTML("a");an.appendChild(document.createTextNode("LaTeXMathML"));an.setAttribute("href","http://www.maths.nott.ac.uk/personal/drw/lm.html");nd.appendChild(an);nd.appendChild(document.createTextNode(" notation use Internet Explorer 6+"));an=AMcreateElementXHTML("a");an.appendChild(document.createTextNode("MathPlayer"));an.setAttribute("href","http://www.dessci.com/en/products/mathplayer/download.htm");nd.appendChild(an);nd.appendChild(document.createTextNode(" or Netscape/Mozilla/Firefox"));nd.appendChild(AMcreateElementXHTML("p"));return nd;}
+function AMisMathMLavailable(){if(navigator.appName.slice(0,8)=="Netscape")
+if(navigator.appVersion.slice(0,1)>="5")return null;else return AMnoMathMLNote();else if(navigator.appName.slice(0,9)=="Microsoft")
+try{var ActiveX=new ActiveXObject("MathPlayer.Factory.1");return null;}catch(e){return AMnoMathMLNote();}
+else return AMnoMathMLNote();}
+var AMcal=[0xEF35,0x212C,0xEF36,0xEF37,0x2130,0x2131,0xEF38,0x210B,0x2110,0xEF39,0xEF3A,0x2112,0x2133,0xEF3B,0xEF3C,0xEF3D,0xEF3E,0x211B,0xEF3F,0xEF40,0xEF41,0xEF42,0xEF43,0xEF44,0xEF45,0xEF46];var AMfrk=[0xEF5D,0xEF5E,0x212D,0xEF5F,0xEF60,0xEF61,0xEF62,0x210C,0x2111,0xEF63,0xEF64,0xEF65,0xEF66,0xEF67,0xEF68,0xEF69,0xEF6A,0x211C,0xEF6B,0xEF6C,0xEF6D,0xEF6E,0xEF6F,0xEF70,0xEF71,0x2128];var AMbbb=[0xEF8C,0xEF8D,0x2102,0xEF8E,0xEF8F,0xEF90,0xEF91,0x210D,0xEF92,0xEF93,0xEF94,0xEF95,0xEF96,0x2115,0xEF97,0x2119,0x211A,0x211D,0xEF98,0xEF99,0xEF9A,0xEF9B,0xEF9C,0xEF9D,0xEF9E,0x2124];var CONST=0,UNARY=1,BINARY=2,INFIX=3,LEFTBRACKET=4,RIGHTBRACKET=5,SPACE=6,UNDEROVER=7,DEFINITION=8,TEXT=9,BIG=10,LONG=11,STRETCHY=12,MATRIX=13;var AMsqrt={input:"\\sqrt",tag:"msqrt",output:"sqrt",ttype:UNARY},AMroot={input:"\\root",tag:"mroot",output:"root",ttype:BINARY},AMfrac={input:"\\frac",tag:"mfrac",output:"/",ttype:BINARY},AMover={input:"\\stackrel",tag:"mover",output:"stackrel",ttype:BINARY},AMatop={input:"\\atop",tag:"mfrac",output:"",ttype:INFIX},AMchoose={input:"\\choose",tag:"mfrac",output:"",ttype:INFIX},AMsub={input:"_",tag:"msub",output:"_",ttype:INFIX},AMsup={input:"^",tag:"msup",output:"^",ttype:INFIX},AMtext={input:"\\mathrm",tag:"mtext",output:"text",ttype:TEXT},AMmbox={input:"\\mbox",tag:"mtext",output:"mbox",ttype:TEXT};var AMsymbols=[{input:"\\alpha",tag:"mi",output:"\u03B1",ttype:CONST},{input:"\\beta",tag:"mi",output:"\u03B2",ttype:CONST},{input:"\\gamma",tag:"mi",output:"\u03B3",ttype:CONST},{input:"\\delta",tag:"mi",output:"\u03B4",ttype:CONST},{input:"\\epsilon",tag:"mi",output:"\u03B5",ttype:CONST},{input:"\\varepsilon",tag:"mi",output:"\u025B",ttype:CONST},{input:"\\zeta",tag:"mi",output:"\u03B6",ttype:CONST},{input:"\\eta",tag:"mi",output:"\u03B7",ttype:CONST},{input:"\\theta",tag:"mi",output:"\u03B8",ttype:CONST},{input:"\\vartheta",tag:"mi",output:"\u03D1",ttype:CONST},{input:"\\iota",tag:"mi",output:"\u03B9",ttype:CONST},{input:"\\kappa",tag:"mi",output:"\u03BA",ttype:CONST},{input:"\\lambda",tag:"mi",output:"\u03BB",ttype:CONST},{input:"\\mu",tag:"mi",output:"\u03BC",ttype:CONST},{input:"\\nu",tag:"mi",output:"\u03BD",ttype:CONST},{input:"\\xi",tag:"mi",output:"\u03BE",ttype:CONST},{input:"\\pi",tag:"mi",output:"\u03C0",ttype:CONST},{input:"\\varpi",tag:"mi",output:"\u03D6",ttype:CONST},{input:"\\rho",tag:"mi",output:"\u03C1",ttype:CONST},{input:"\\varrho",tag:"mi",output:"\u03F1",ttype:CONST},{input:"\\varsigma",tag:"mi",output:"\u03C2",ttype:CONST},{input:"\\sigma",tag:"mi",output:"\u03C3",ttype:CONST},{input:"\\tau",tag:"mi",output:"\u03C4",ttype:CONST},{input:"\\upsilon",tag:"mi",output:"\u03C5",ttype:CONST},{input:"\\phi",tag:"mi",output:"\u03C6",ttype:CONST},{input:"\\varphi",tag:"mi",output:"\u03D5",ttype:CONST},{input:"\\chi",tag:"mi",output:"\u03C7",ttype:CONST},{input:"\\psi",tag:"mi",output:"\u03C8",ttype:CONST},{input:"\\omega",tag:"mi",output:"\u03C9",ttype:CONST},{input:"\\Gamma",tag:"mo",output:"\u0393",ttype:CONST},{input:"\\Delta",tag:"mo",output:"\u0394",ttype:CONST},{input:"\\Theta",tag:"mo",output:"\u0398",ttype:CONST},{input:"\\Lambda",tag:"mo",output:"\u039B",ttype:CONST},{input:"\\Xi",tag:"mo",output:"\u039E",ttype:CONST},{input:"\\Pi",tag:"mo",output:"\u03A0",ttype:CONST},{input:"\\Sigma",tag:"mo",output:"\u03A3",ttype:CONST},{input:"\\Upsilon",tag:"mo",output:"\u03A5",ttype:CONST},{input:"\\Phi",tag:"mo",output:"\u03A6",ttype:CONST},{input:"\\Psi",tag:"mo",output:"\u03A8",ttype:CONST},{input:"\\Omega",tag:"mo",output:"\u03A9",ttype:CONST},{input:"\\frac12",tag:"mo",output:"\u00BD",ttype:CONST},{input:"\\frac14",tag:"mo",output:"\u00BC",ttype:CONST},{input:"\\frac34",tag:"mo",output:"\u00BE",ttype:CONST},{input:"\\frac13",tag:"mo",output:"\u2153",ttype:CONST},{input:"\\frac23",tag:"mo",output:"\u2154",ttype:CONST},{input:"\\frac15",tag:"mo",output:"\u2155",ttype:CONST},{input:"\\frac25",tag:"mo",output:"\u2156",ttype:CONST},{input:"\\frac35",tag:"mo",output:"\u2157",ttype:CONST},{input:"\\frac45",tag:"mo",output:"\u2158",ttype:CONST},{input:"\\frac16",tag:"mo",output:"\u2159",ttype:CONST},{input:"\\frac56",tag:"mo",output:"\u215A",ttype:CONST},{input:"\\frac18",tag:"mo",output:"\u215B",ttype:CONST},{input:"\\frac38",tag:"mo",output:"\u215C",ttype:CONST},{input:"\\frac58",tag:"mo",output:"\u215D",ttype:CONST},{input:"\\frac78",tag:"mo",output:"\u215E",ttype:CONST},{input:"\\pm",tag:"mo",output:"\u00B1",ttype:CONST},{input:"\\mp",tag:"mo",output:"\u2213",ttype:CONST},{input:"\\triangleleft",tag:"mo",output:"\u22B2",ttype:CONST},{input:"\\triangleright",tag:"mo",output:"\u22B3",ttype:CONST},{input:"\\cdot",tag:"mo",output:"\u22C5",ttype:CONST},{input:"\\star",tag:"mo",output:"\u22C6",ttype:CONST},{input:"\\ast",tag:"mo",output:"\u002A",ttype:CONST},{input:"\\times",tag:"mo",output:"\u00D7",ttype:CONST},{input:"\\div",tag:"mo",output:"\u00F7",ttype:CONST},{input:"\\circ",tag:"mo",output:"\u2218",ttype:CONST},{input:"\\bullet",tag:"mo",output:"\u2022",ttype:CONST},{input:"\\oplus",tag:"mo",output:"\u2295",ttype:CONST},{input:"\\ominus",tag:"mo",output:"\u2296",ttype:CONST},{input:"\\otimes",tag:"mo",output:"\u2297",ttype:CONST},{input:"\\bigcirc",tag:"mo",output:"\u25CB",ttype:CONST},{input:"\\oslash",tag:"mo",output:"\u2298",ttype:CONST},{input:"\\odot",tag:"mo",output:"\u2299",ttype:CONST},{input:"\\land",tag:"mo",output:"\u2227",ttype:CONST},{input:"\\wedge",tag:"mo",output:"\u2227",ttype:CONST},{input:"\\lor",tag:"mo",output:"\u2228",ttype:CONST},{input:"\\vee",tag:"mo",output:"\u2228",ttype:CONST},{input:"\\cap",tag:"mo",output:"\u2229",ttype:CONST},{input:"\\cup",tag:"mo",output:"\u222A",ttype:CONST},{input:"\\sqcap",tag:"mo",output:"\u2293",ttype:CONST},{input:"\\sqcup",tag:"mo",output:"\u2294",ttype:CONST},{input:"\\uplus",tag:"mo",output:"\u228E",ttype:CONST},{input:"\\amalg",tag:"mo",output:"\u2210",ttype:CONST},{input:"\\bigtriangleup",tag:"mo",output:"\u25B3",ttype:CONST},{input:"\\bigtriangledown",tag:"mo",output:"\u25BD",ttype:CONST},{input:"\\dag",tag:"mo",output:"\u2020",ttype:CONST},{input:"\\dagger",tag:"mo",output:"\u2020",ttype:CONST},{input:"\\ddag",tag:"mo",output:"\u2021",ttype:CONST},{input:"\\ddagger",tag:"mo",output:"\u2021",ttype:CONST},{input:"\\lhd",tag:"mo",output:"\u22B2",ttype:CONST},{input:"\\rhd",tag:"mo",output:"\u22B3",ttype:CONST},{input:"\\unlhd",tag:"mo",output:"\u22B4",ttype:CONST},{input:"\\unrhd",tag:"mo",output:"\u22B5",ttype:CONST},{input:"\\sum",tag:"mo",output:"\u2211",ttype:UNDEROVER},{input:"\\prod",tag:"mo",output:"\u220F",ttype:UNDEROVER},{input:"\\bigcap",tag:"mo",output:"\u22C2",ttype:UNDEROVER},{input:"\\bigcup",tag:"mo",output:"\u22C3",ttype:UNDEROVER},{input:"\\bigwedge",tag:"mo",output:"\u22C0",ttype:UNDEROVER},{input:"\\bigvee",tag:"mo",output:"\u22C1",ttype:UNDEROVER},{input:"\\bigsqcap",tag:"mo",output:"\u2A05",ttype:UNDEROVER},{input:"\\bigsqcup",tag:"mo",output:"\u2A06",ttype:UNDEROVER},{input:"\\coprod",tag:"mo",output:"\u2210",ttype:UNDEROVER},{input:"\\bigoplus",tag:"mo",output:"\u2A01",ttype:UNDEROVER},{input:"\\bigotimes",tag:"mo",output:"\u2A02",ttype:UNDEROVER},{input:"\\bigodot",tag:"mo",output:"\u2A00",ttype:UNDEROVER},{input:"\\biguplus",tag:"mo",output:"\u2A04",ttype:UNDEROVER},{input:"\\int",tag:"mo",output:"\u222B",ttype:CONST},{input:"\\oint",tag:"mo",output:"\u222E",ttype:CONST},{input:":=",tag:"mo",output:":=",ttype:CONST},{input:"\\lt",tag:"mo",output:"<",ttype:CONST},{input:"\\gt",tag:"mo",output:">",ttype:CONST},{input:"\\ne",tag:"mo",output:"\u2260",ttype:CONST},{input:"\\neq",tag:"mo",output:"\u2260",ttype:CONST},{input:"\\le",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\leq",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\leqslant",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\ge",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\geq",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\geqslant",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\equiv",tag:"mo",output:"\u2261",ttype:CONST},{input:"\\ll",tag:"mo",output:"\u226A",ttype:CONST},{input:"\\gg",tag:"mo",output:"\u226B",ttype:CONST},{input:"\\doteq",tag:"mo",output:"\u2250",ttype:CONST},{input:"\\prec",tag:"mo",output:"\u227A",ttype:CONST},{input:"\\succ",tag:"mo",output:"\u227B",ttype:CONST},{input:"\\preceq",tag:"mo",output:"\u227C",ttype:CONST},{input:"\\succeq",tag:"mo",output:"\u227D",ttype:CONST},{input:"\\subset",tag:"mo",output:"\u2282",ttype:CONST},{input:"\\supset",tag:"mo",output:"\u2283",ttype:CONST},{input:"\\subseteq",tag:"mo",output:"\u2286",ttype:CONST},{input:"\\supseteq",tag:"mo",output:"\u2287",ttype:CONST},{input:"\\sqsubset",tag:"mo",output:"\u228F",ttype:CONST},{input:"\\sqsupset",tag:"mo",output:"\u2290",ttype:CONST},{input:"\\sqsubseteq",tag:"mo",output:"\u2291",ttype:CONST},{input:"\\sqsupseteq",tag:"mo",output:"\u2292",ttype:CONST},{input:"\\sim",tag:"mo",output:"\u223C",ttype:CONST},{input:"\\simeq",tag:"mo",output:"\u2243",ttype:CONST},{input:"\\approx",tag:"mo",output:"\u2248",ttype:CONST},{input:"\\cong",tag:"mo",output:"\u2245",ttype:CONST},{input:"\\Join",tag:"mo",output:"\u22C8",ttype:CONST},{input:"\\bowtie",tag:"mo",output:"\u22C8",ttype:CONST},{input:"\\in",tag:"mo",output:"\u2208",ttype:CONST},{input:"\\ni",tag:"mo",output:"\u220B",ttype:CONST},{input:"\\owns",tag:"mo",output:"\u220B",ttype:CONST},{input:"\\propto",tag:"mo",output:"\u221D",ttype:CONST},{input:"\\vdash",tag:"mo",output:"\u22A2",ttype:CONST},{input:"\\dashv",tag:"mo",output:"\u22A3",ttype:CONST},{input:"\\models",tag:"mo",output:"\u22A8",ttype:CONST},{input:"\\perp",tag:"mo",output:"\u22A5",ttype:CONST},{input:"\\smile",tag:"mo",output:"\u2323",ttype:CONST},{input:"\\frown",tag:"mo",output:"\u2322",ttype:CONST},{input:"\\asymp",tag:"mo",output:"\u224D",ttype:CONST},{input:"\\notin",tag:"mo",output:"\u2209",ttype:CONST},{input:"\\begin{eqnarray}",output:"X",ttype:MATRIX,invisible:true},{input:"\\begin{array}",output:"X",ttype:MATRIX,invisible:true},{input:"\\\\",output:"}&{",ttype:DEFINITION},{input:"\\end{eqnarray}",output:"}}",ttype:DEFINITION},{input:"\\end{array}",output:"}}",ttype:DEFINITION},{input:"\\big",tag:"mo",output:"X",atval:"1.2",ieval:"2.2",ttype:BIG},{input:"\\Big",tag:"mo",output:"X",atval:"1.6",ieval:"2.6",ttype:BIG},{input:"\\bigg",tag:"mo",output:"X",atval:"2.2",ieval:"3.2",ttype:BIG},{input:"\\Bigg",tag:"mo",output:"X",atval:"2.9",ieval:"3.9",ttype:BIG},{input:"\\left",tag:"mo",output:"X",ttype:LEFTBRACKET},{input:"\\right",tag:"mo",output:"X",ttype:RIGHTBRACKET},{input:"{",output:"{",ttype:LEFTBRACKET,invisible:true},{input:"}",output:"}",ttype:RIGHTBRACKET,invisible:true},{input:"(",tag:"mo",output:"(",atval:"1",ttype:STRETCHY},{input:"[",tag:"mo",output:"[",atval:"1",ttype:STRETCHY},{input:"\\lbrack",tag:"mo",output:"[",atval:"1",ttype:STRETCHY},{input:"\\{",tag:"mo",output:"{",atval:"1",ttype:STRETCHY},{input:"\\lbrace",tag:"mo",output:"{",atval:"1",ttype:STRETCHY},{input:"\\langle",tag:"mo",output:"\u2329",atval:"1",ttype:STRETCHY},{input:"\\lfloor",tag:"mo",output:"\u230A",atval:"1",ttype:STRETCHY},{input:"\\lceil",tag:"mo",output:"\u2308",atval:"1",ttype:STRETCHY},{input:")",tag:"mo",output:")",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"]",tag:"mo",output:"]",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rbrack",tag:"mo",output:"]",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\}",tag:"mo",output:"}",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rbrace",tag:"mo",output:"}",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rangle",tag:"mo",output:"\u232A",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rfloor",tag:"mo",output:"\u230B",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rceil",tag:"mo",output:"\u2309",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"|",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\|",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"\\vert",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\Vert",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"\\mid",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\parallel",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"/",tag:"mo",output:"/",atval:"1.01",ttype:STRETCHY},{input:"\\backslash",tag:"mo",output:"\u2216",atval:"1",ttype:STRETCHY},{input:"\\setminus",tag:"mo",output:"\\",ttype:CONST},{input:"\\!",tag:"mspace",atname:"width",atval:"-0.167em",ttype:SPACE},{input:"\\,",tag:"mspace",atname:"width",atval:"0.167em",ttype:SPACE},{input:"\\>",tag:"mspace",atname:"width",atval:"0.222em",ttype:SPACE},{input:"\\:",tag:"mspace",atname:"width",atval:"0.222em",ttype:SPACE},{input:"\\;",tag:"mspace",atname:"width",atval:"0.278em",ttype:SPACE},{input:"~",tag:"mspace",atname:"width",atval:"0.333em",ttype:SPACE},{input:"\\quad",tag:"mspace",atname:"width",atval:"1em",ttype:SPACE},{input:"\\qquad",tag:"mspace",atname:"width",atval:"2em",ttype:SPACE},{input:"\\prime",tag:"mo",output:"\u2032",ttype:CONST},{input:"'",tag:"mo",output:"\u02B9",ttype:CONST},{input:"''",tag:"mo",output:"\u02BA",ttype:CONST},{input:"'''",tag:"mo",output:"\u2034",ttype:CONST},{input:"''''",tag:"mo",output:"\u2057",ttype:CONST},{input:"\\ldots",tag:"mo",output:"\u2026",ttype:CONST},{input:"\\cdots",tag:"mo",output:"\u22EF",ttype:CONST},{input:"\\vdots",tag:"mo",output:"\u22EE",ttype:CONST},{input:"\\ddots",tag:"mo",output:"\u22F1",ttype:CONST},{input:"\\forall",tag:"mo",output:"\u2200",ttype:CONST},{input:"\\exists",tag:"mo",output:"\u2203",ttype:CONST},{input:"\\Re",tag:"mo",output:"\u211C",ttype:CONST},{input:"\\Im",tag:"mo",output:"\u2111",ttype:CONST},{input:"\\aleph",tag:"mo",output:"\u2135",ttype:CONST},{input:"\\hbar",tag:"mo",output:"\u210F",ttype:CONST},{input:"\\ell",tag:"mo",output:"\u2113",ttype:CONST},{input:"\\wp",tag:"mo",output:"\u2118",ttype:CONST},{input:"\\emptyset",tag:"mo",output:"\u2205",ttype:CONST},{input:"\\infty",tag:"mo",output:"\u221E",ttype:CONST},{input:"\\surd",tag:"mo",output:"\\sqrt{}",ttype:DEFINITION},{input:"\\partial",tag:"mo",output:"\u2202",ttype:CONST},{input:"\\nabla",tag:"mo",output:"\u2207",ttype:CONST},{input:"\\triangle",tag:"mo",output:"\u25B3",ttype:CONST},{input:"\\therefore",tag:"mo",output:"\u2234",ttype:CONST},{input:"\\angle",tag:"mo",output:"\u2220",ttype:CONST},{input:"\\diamond",tag:"mo",output:"\u22C4",ttype:CONST},{input:"\\Diamond",tag:"mo",output:"\u25C7",ttype:CONST},{input:"\\neg",tag:"mo",output:"\u00AC",ttype:CONST},{input:"\\lnot",tag:"mo",output:"\u00AC",ttype:CONST},{input:"\\bot",tag:"mo",output:"\u22A5",ttype:CONST},{input:"\\top",tag:"mo",output:"\u22A4",ttype:CONST},{input:"\\square",tag:"mo",output:"\u25AB",ttype:CONST},{input:"\\Box",tag:"mo",output:"\u25A1",ttype:CONST},{input:"\\wr",tag:"mo",output:"\u2240",ttype:CONST},{input:"\\arccos",tag:"mi",output:"arccos",ttype:UNARY,func:true},{input:"\\arcsin",tag:"mi",output:"arcsin",ttype:UNARY,func:true},{input:"\\arctan",tag:"mi",output:"arctan",ttype:UNARY,func:true},{input:"\\arg",tag:"mi",output:"arg",ttype:UNARY,func:true},{input:"\\cos",tag:"mi",output:"cos",ttype:UNARY,func:true},{input:"\\cosh",tag:"mi",output:"cosh",ttype:UNARY,func:true},{input:"\\cot",tag:"mi",output:"cot",ttype:UNARY,func:true},{input:"\\coth",tag:"mi",output:"coth",ttype:UNARY,func:true},{input:"\\csc",tag:"mi",output:"csc",ttype:UNARY,func:true},{input:"\\deg",tag:"mi",output:"deg",ttype:UNARY,func:true},{input:"\\det",tag:"mi",output:"det",ttype:UNARY,func:true},{input:"\\dim",tag:"mi",output:"dim",ttype:UNARY,func:true},{input:"\\exp",tag:"mi",output:"exp",ttype:UNARY,func:true},{input:"\\gcd",tag:"mi",output:"gcd",ttype:UNARY,func:true},{input:"\\hom",tag:"mi",output:"hom",ttype:UNARY,func:true},{input:"\\inf",tag:"mo",output:"inf",ttype:UNDEROVER},{input:"\\ker",tag:"mi",output:"ker",ttype:UNARY,func:true},{input:"\\lg",tag:"mi",output:"lg",ttype:UNARY,func:true},{input:"\\lim",tag:"mo",output:"lim",ttype:UNDEROVER},{input:"\\liminf",tag:"mo",output:"liminf",ttype:UNDEROVER},{input:"\\limsup",tag:"mo",output:"limsup",ttype:UNDEROVER},{input:"\\ln",tag:"mi",output:"ln",ttype:UNARY,func:true},{input:"\\log",tag:"mi",output:"log",ttype:UNARY,func:true},{input:"\\max",tag:"mo",output:"max",ttype:UNDEROVER},{input:"\\min",tag:"mo",output:"min",ttype:UNDEROVER},{input:"\\Pr",tag:"mi",output:"Pr",ttype:UNARY,func:true},{input:"\\sec",tag:"mi",output:"sec",ttype:UNARY,func:true},{input:"\\sin",tag:"mi",output:"sin",ttype:UNARY,func:true},{input:"\\sinh",tag:"mi",output:"sinh",ttype:UNARY,func:true},{input:"\\sup",tag:"mo",output:"sup",ttype:UNDEROVER},{input:"\\tan",tag:"mi",output:"tan",ttype:UNARY,func:true},{input:"\\tanh",tag:"mi",output:"tanh",ttype:UNARY,func:true},{input:"\\gets",tag:"mo",output:"\u2190",ttype:CONST},{input:"\\leftarrow",tag:"mo",output:"\u2190",ttype:CONST},{input:"\\to",tag:"mo",output:"\u2192",ttype:CONST},{input:"\\rightarrow",tag:"mo",output:"\u2192",ttype:CONST},{input:"\\leftrightarrow",tag:"mo",output:"\u2194",ttype:CONST},{input:"\\uparrow",tag:"mo",output:"\u2191",ttype:CONST},{input:"\\downarrow",tag:"mo",output:"\u2193",ttype:CONST},{input:"\\updownarrow",tag:"mo",output:"\u2195",ttype:CONST},{input:"\\Leftarrow",tag:"mo",output:"\u21D0",ttype:CONST},{input:"\\Rightarrow",tag:"mo",output:"\u21D2",ttype:CONST},{input:"\\Leftrightarrow",tag:"mo",output:"\u21D4",ttype:CONST},{input:"\\iff",tag:"mo",output:"~\\Longleftrightarrow~",ttype:DEFINITION},{input:"\\Uparrow",tag:"mo",output:"\u21D1",ttype:CONST},{input:"\\Downarrow",tag:"mo",output:"\u21D3",ttype:CONST},{input:"\\Updownarrow",tag:"mo",output:"\u21D5",ttype:CONST},{input:"\\mapsto",tag:"mo",output:"\u21A6",ttype:CONST},{input:"\\longleftarrow",tag:"mo",output:"\u2190",ttype:LONG},{input:"\\longrightarrow",tag:"mo",output:"\u2192",ttype:LONG},{input:"\\longleftrightarrow",tag:"mo",output:"\u2194",ttype:LONG},{input:"\\Longleftarrow",tag:"mo",output:"\u21D0",ttype:LONG},{input:"\\Longrightarrow",tag:"mo",output:"\u21D2",ttype:LONG},{input:"\\Longleftrightarrow",tag:"mo",output:"\u21D4",ttype:LONG},{input:"\\longmapsto",tag:"mo",output:"\u21A6",ttype:CONST},AMsqrt,AMroot,AMfrac,AMover,AMsub,AMsup,AMtext,AMmbox,AMatop,AMchoose,{input:"\\acute",tag:"mover",output:"\u00B4",ttype:UNARY,acc:true},{input:"\\grave",tag:"mover",output:"\u0060",ttype:UNARY,acc:true},{input:"\\breve",tag:"mover",output:"\u02D8",ttype:UNARY,acc:true},{input:"\\check",tag:"mover",output:"\u02C7",ttype:UNARY,acc:true},{input:"\\dot",tag:"mover",output:".",ttype:UNARY,acc:true},{input:"\\ddot",tag:"mover",output:"..",ttype:UNARY,acc:true},{input:"\\mathring",tag:"mover",output:"\u00B0",ttype:UNARY,acc:true},{input:"\\vec",tag:"mover",output:"\u20D7",ttype:UNARY,acc:true},{input:"\\overrightarrow",tag:"mover",output:"\u20D7",ttype:UNARY,acc:true},{input:"\\overleftarrow",tag:"mover",output:"\u20D6",ttype:UNARY,acc:true},{input:"\\hat",tag:"mover",output:"\u005E",ttype:UNARY,acc:true},{input:"\\widehat",tag:"mover",output:"\u0302",ttype:UNARY,acc:true},{input:"\\tilde",tag:"mover",output:"~",ttype:UNARY,acc:true},{input:"\\widetilde",tag:"mover",output:"\u02DC",ttype:UNARY,acc:true},{input:"\\bar",tag:"mover",output:"\u203E",ttype:UNARY,acc:true},{input:"\\overbrace",tag:"mover",output:"\uFE37",ttype:UNARY,acc:true},{input:"\\overbracket",tag:"mover",output:"\u23B4",ttype:UNARY,acc:true},{input:"\\overline",tag:"mover",output:"\u00AF",ttype:UNARY,acc:true},{input:"\\underbrace",tag:"munder",output:"\uFE38",ttype:UNARY,acc:true},{input:"\\underbracket",tag:"munder",output:"\u23B5",ttype:UNARY,acc:true},{input:"\\underline",tag:"munder",output:"\u00AF",ttype:UNARY,acc:true},{input:"\\displaystyle",tag:"mstyle",atname:"displaystyle",atval:"true",ttype:UNARY},{input:"\\textstyle",tag:"mstyle",atname:"displaystyle",atval:"false",ttype:UNARY},{input:"\\scriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"1",ttype:UNARY},{input:"\\scriptscriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"2",ttype:UNARY},{input:"\\textrm",tag:"mstyle",output:"\\mathrm",ttype:DEFINITION},{input:"\\mathbf",tag:"mstyle",atname:"mathvariant",atval:"bold",ttype:UNARY},{input:"\\textbf",tag:"mstyle",atname:"mathvariant",atval:"bold",ttype:UNARY},{input:"\\mathit",tag:"mstyle",atname:"mathvariant",atval:"italic",ttype:UNARY},{input:"\\textit",tag:"mstyle",atname:"mathvariant",atval:"italic",ttype:UNARY},{input:"\\mathtt",tag:"mstyle",atname:"mathvariant",atval:"monospace",ttype:UNARY},{input:"\\texttt",tag:"mstyle",atname:"mathvariant",atval:"monospace",ttype:UNARY},{input:"\\mathsf",tag:"mstyle",atname:"mathvariant",atval:"sans-serif",ttype:UNARY},{input:"\\mathbb",tag:"mstyle",atname:"mathvariant",atval:"double-struck",ttype:UNARY,codes:AMbbb},{input:"\\mathcal",tag:"mstyle",atname:"mathvariant",atval:"script",ttype:UNARY,codes:AMcal},{input:"\\mathfrak",tag:"mstyle",atname:"mathvariant",atval:"fraktur",ttype:UNARY,codes:AMfrk},{input:"\\textcolor",tag:"mstyle",atname:"mathvariant",atval:"mathcolor",ttype:BINARY},{input:"\\colorbox",tag:"mstyle",atname:"mathvariant",atval:"background",ttype:BINARY}];function compareNames(s1,s2){if(s1.input>s2.input)return 1
+else return-1;}
+var AMnames=[];function AMinitSymbols(){AMsymbols.sort(compareNames);for(i=0;i<AMsymbols.length;i++)AMnames[i]=AMsymbols[i].input;}
+var AMmathml="http://www.w3.org/1998/Math/MathML";function AMcreateElementMathML(t){if(isIE)return document.createElement("m:"+t);else return document.createElementNS(AMmathml,t);}
+function AMcreateMmlNode(t,frag){if(isIE)var node=document.createElement("m:"+t);else var node=document.createElementNS(AMmathml,t);node.appendChild(frag);return node;}
+function newcommand(oldstr,newstr){AMsymbols=AMsymbols.concat([{input:oldstr,tag:"mo",output:newstr,ttype:DEFINITION}]);}
+function AMremoveCharsAndBlanks(str,n){var st;st=str.slice(n);for(var i=0;i<st.length&&st.charCodeAt(i)<=32;i=i+1);return st.slice(i);}
+function AMposition(arr,str,n){if(n==0){var h,m;n=-1;h=arr.length;while(n+1<h){m=(n+h)>>1;if(arr[m]<str)n=m;else h=m;}
+return h;}else
+for(var i=n;i<arr.length&&arr[i]<str;i++);return i;}
+function AMgetSymbol(str){var k=0;var j=0;var mk;var st;var tagst;var match="";var more=true;for(var i=1;i<=str.length&&more;i++){st=str.slice(0,i);j=k;k=AMposition(AMnames,st,j);if(k<AMnames.length&&str.slice(0,AMnames[k].length)==AMnames[k]){match=AMnames[k];mk=k;i=match.length;}
+more=k<AMnames.length&&str.slice(0,AMnames[k].length)>=AMnames[k];}
+AMpreviousSymbol=AMcurrentSymbol;if(match!=""){AMcurrentSymbol=AMsymbols[mk].ttype;return AMsymbols[mk];}
+AMcurrentSymbol=CONST;k=1;st=str.slice(0,1);if("0"<=st&&st<="9")tagst="mn";else tagst=(("A">st||st>"Z")&&("a">st||st>"z")?"mo":"mi");return{input:st,tag:tagst,output:st,ttype:CONST};}
+var AMpreviousSymbol,AMcurrentSymbol;function AMparseSexpr(str){var symbol,node,result,result2,i,st,newFrag=document.createDocumentFragment();str=AMremoveCharsAndBlanks(str,0);symbol=AMgetSymbol(str);if(symbol==null||symbol.ttype==RIGHTBRACKET)
+return[null,str,null];if(symbol.ttype==DEFINITION){str=symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length);symbol=AMgetSymbol(str);if(symbol==null||symbol.ttype==RIGHTBRACKET)
+return[null,str,null];}
+str=AMremoveCharsAndBlanks(str,symbol.input.length);switch(symbol.ttype){case SPACE:node=AMcreateElementMathML(symbol.tag);node.setAttribute(symbol.atname,symbol.atval);return[node,str,symbol.tag];case UNDEROVER:if(isIE){if(symbol.input.substr(0,4)=="\\big"){str="\\"+symbol.input.substr(4)+str;symbol=AMgetSymbol(str);symbol.ttype=UNDEROVER;str=AMremoveCharsAndBlanks(str,symbol.input.length);}}
+return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];case CONST:var output=symbol.output;if(isIE){if(symbol.input=="'")
+output="\u2032";else if(symbol.input=="''")
+output="\u2033";else if(symbol.input=="'''")
+output="\u2033\u2032";else if(symbol.input=="''''")
+output="\u2033\u2033";else if(symbol.input=="\\square")
+output="\u25A1";else if(symbol.input.substr(0,5)=="\\frac"){var denom=symbol.input.substr(6,1);if(denom=="5"||denom=="6"){str=symbol.input.replace(/\\frac/,"\\frac ")+str;return[node,str,symbol.tag];}}}
+node=AMcreateMmlNode(symbol.tag,document.createTextNode(output));return[node,str,symbol.tag];case LONG:node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));node.setAttribute("minsize","1.5");node.setAttribute("maxsize","1.5");node=AMcreateMmlNode("mover",node);node.appendChild(AMcreateElementMathML("mspace"));return[node,str,symbol.tag];case STRETCHY:if(isIE&&symbol.input=="\\backslash")
+symbol.output="\\";node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));if(symbol.input=="|"||symbol.input=="\\vert"||symbol.input=="\\|"||symbol.input=="\\Vert"){node.setAttribute("lspace","0em");node.setAttribute("rspace","0em");}
+node.setAttribute("maxsize",symbol.atval);if(symbol.rtag!=null)
+return[node,str,symbol.rtag];else
+return[node,str,symbol.tag];case BIG:var atval=symbol.atval;if(isIE)
+atval=symbol.ieval;symbol=AMgetSymbol(str);if(symbol==null)
+return[null,str,null];str=AMremoveCharsAndBlanks(str,symbol.input.length);node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("height",atval+"ex");node=AMcreateMmlNode("mrow",node);node.appendChild(space);}else{node.setAttribute("minsize",atval);node.setAttribute("maxsize",atval);}
+return[node,str,symbol.tag];case LEFTBRACKET:if(symbol.input=="\\left"){symbol=AMgetSymbol(str);if(symbol!=null){if(symbol.input==".")
+symbol.invisible=true;str=AMremoveCharsAndBlanks(str,symbol.input.length);}}
+result=AMparseExpr(str,true,false);if(symbol==null||(typeof symbol.invisible=="boolean"&&symbol.invisible))
+node=AMcreateMmlNode("mrow",result[0]);else{node=AMcreateMmlNode("mo",document.createTextNode(symbol.output));node=AMcreateMmlNode("mrow",node);node.appendChild(result[0]);}
+return[node,result[1],result[2]];case MATRIX:if(symbol.input=="\\begin{array}"){var mask="";symbol=AMgetSymbol(str);str=AMremoveCharsAndBlanks(str,0);if(symbol==null)
+mask="l";else{str=AMremoveCharsAndBlanks(str,symbol.input.length);if(symbol.input!="{")
+mask="l";else do{symbol=AMgetSymbol(str);if(symbol!=null){str=AMremoveCharsAndBlanks(str,symbol.input.length);if(symbol.input!="}")
+mask=mask+symbol.input;}}while(symbol!=null&&symbol.input!=""&&symbol.input!="}");}
+result=AMparseExpr("{"+str,true,true);node=AMcreateMmlNode("mtable",result[0]);mask=mask.replace(/l/g,"left ");mask=mask.replace(/r/g,"right ");mask=mask.replace(/c/g,"center ");node.setAttribute("columnalign",mask);node.setAttribute("displaystyle","false");if(isIE)
+return[node,result[1],null];var lspace=AMcreateElementMathML("mspace");lspace.setAttribute("width","0.167em");var rspace=AMcreateElementMathML("mspace");rspace.setAttribute("width","0.167em");var node1=AMcreateMmlNode("mrow",lspace);node1.appendChild(node);node1.appendChild(rspace);return[node1,result[1],null];}else{result=AMparseExpr("{"+str,true,true);node=AMcreateMmlNode("mtable",result[0]);if(isIE)
+node.setAttribute("columnspacing","0.25em");else
+node.setAttribute("columnspacing","0.167em");node.setAttribute("columnalign","right center left");node.setAttribute("displaystyle","true");node=AMcreateMmlNode("mrow",node);return[node,result[1],null];}
+case TEXT:if(str.charAt(0)=="{")i=str.indexOf("}");else i=0;if(i==-1)
+i=str.length;st=str.slice(1,i);if(st.charAt(0)==" "){node=AMcreateElementMathML("mspace");node.setAttribute("width","0.33em");newFrag.appendChild(node);}
+newFrag.appendChild(AMcreateMmlNode(symbol.tag,document.createTextNode(st)));if(st.charAt(st.length-1)==" "){node=AMcreateElementMathML("mspace");node.setAttribute("width","0.33em");newFrag.appendChild(node);}
+str=AMremoveCharsAndBlanks(str,i+1);return[AMcreateMmlNode("mrow",newFrag),str,null];case UNARY:result=AMparseSexpr(str);if(result[0]==null)return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str];if(typeof symbol.func=="boolean"&&symbol.func){st=str.charAt(0);if(st=="^"||st=="_"||st==","){return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];}else{node=AMcreateMmlNode("mrow",AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("width","0.167em");node.appendChild(space);}
+node.appendChild(result[0]);return[node,result[1],symbol.tag];}}
+if(symbol.input=="\\sqrt"){if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("height","1.2ex");space.setAttribute("width","0em");node=AMcreateMmlNode(symbol.tag,result[0])
+node.appendChild(space);return[node,result[1],symbol.tag];}else
+return[AMcreateMmlNode(symbol.tag,result[0]),result[1],symbol.tag];}else if(typeof symbol.acc=="boolean"&&symbol.acc){node=AMcreateMmlNode(symbol.tag,result[0]);var output=symbol.output;if(isIE){if(symbol.input=="\\hat")
+output="\u0302";else if(symbol.input=="\\widehat")
+output="\u005E";else if(symbol.input=="\\bar")
+output="\u00AF";else if(symbol.input=="\\grave")
+output="\u0300";else if(symbol.input=="\\tilde")
+output="\u0303";}
+var node1=AMcreateMmlNode("mo",document.createTextNode(output));if(symbol.input=="\\vec"||symbol.input=="\\check")
+node1.setAttribute("maxsize","1.2");if(isIE&&symbol.input=="\\bar")
+node1.setAttribute("maxsize","0.5");if(symbol.input=="\\underbrace"||symbol.input=="\\underline")
+node1.setAttribute("accentunder","true");else
+node1.setAttribute("accent","true");node.appendChild(node1);if(symbol.input=="\\overbrace"||symbol.input=="\\underbrace")
+node.ttype=UNDEROVER;return[node,result[1],symbol.tag];}else{if(!isIE&&typeof symbol.codes!="undefined"){for(i=0;i<result[0].childNodes.length;i++)
+if(result[0].childNodes[i].nodeName=="mi"||result[0].nodeName=="mi"){st=(result[0].nodeName=="mi"?result[0].firstChild.nodeValue:result[0].childNodes[i].firstChild.nodeValue);var newst=[];for(var j=0;j<st.length;j++)
+if(st.charCodeAt(j)>64&&st.charCodeAt(j)<91)newst=newst+
+String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]);else newst=newst+st.charAt(j);if(result[0].nodeName=="mi")
+result[0]=AMcreateElementMathML("mo").appendChild(document.createTextNode(newst));else result[0].replaceChild(AMcreateElementMathML("mo").appendChild(document.createTextNode(newst)),result[0].childNodes[i]);}}
+node=AMcreateMmlNode(symbol.tag,result[0]);node.setAttribute(symbol.atname,symbol.atval);if(symbol.input=="\\scriptstyle"||symbol.input=="\\scriptscriptstyle")
+node.setAttribute("displaystyle","false");return[node,result[1],symbol.tag];}
+case BINARY:result=AMparseSexpr(str);if(result[0]==null)return[AMcreateMmlNode("mo",document.createTextNode(symbol.input)),str,null];result2=AMparseSexpr(result[1]);if(result2[0]==null)return[AMcreateMmlNode("mo",document.createTextNode(symbol.input)),str,null];if(symbol.input=="\\textcolor"||symbol.input=="\\colorbox"){var tclr=str.match(/\{\s*([#\w]+)\s*\}/);str=str.replace(/\{\s*[#\w]+\s*\}/,"");if(tclr!=null){if(IsColorName.test(tclr[1].toLowerCase())){tclr=LaTeXColor[tclr[1].toLowerCase()];}else{tclr=tclr[1];}
+node=AMcreateElementMathML("mstyle");node.setAttribute(symbol.atval,tclr);node.appendChild(result2[0]);return[node,result2[1],symbol.tag];}}
+if(symbol.input=="\\root"||symbol.input=="\\stackrel")newFrag.appendChild(result2[0]);newFrag.appendChild(result[0]);if(symbol.input=="\\frac")newFrag.appendChild(result2[0]);return[AMcreateMmlNode(symbol.tag,newFrag),result2[1],symbol.tag];case INFIX:str=AMremoveCharsAndBlanks(str,symbol.input.length);return[AMcreateMmlNode("mo",document.createTextNode(symbol.output)),str,symbol.tag];default:return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];}}
+function AMparseIexpr(str){var symbol,sym1,sym2,node,result,tag,underover;str=AMremoveCharsAndBlanks(str,0);sym1=AMgetSymbol(str);result=AMparseSexpr(str);node=result[0];str=result[1];tag=result[2];symbol=AMgetSymbol(str);if(symbol.ttype==INFIX){str=AMremoveCharsAndBlanks(str,symbol.input.length);result=AMparseSexpr(str);if(result[0]==null)
+result[0]=AMcreateMmlNode("mo",document.createTextNode("\u25A1"));str=result[1];tag=result[2];if(symbol.input=="_"||symbol.input=="^"){sym2=AMgetSymbol(str);tag=null;underover=((sym1.ttype==UNDEROVER)||(node.ttype==UNDEROVER));if(symbol.input=="_"&&sym2.input=="^"){str=AMremoveCharsAndBlanks(str,sym2.input.length);var res2=AMparseSexpr(str);str=res2[1];tag=res2[2];node=AMcreateMmlNode((underover?"munderover":"msubsup"),node);node.appendChild(result[0]);node.appendChild(res2[0]);}else if(symbol.input=="_"){node=AMcreateMmlNode((underover?"munder":"msub"),node);node.appendChild(result[0]);}else{node=AMcreateMmlNode((underover?"mover":"msup"),node);node.appendChild(result[0]);}
+node=AMcreateMmlNode("mrow",node);}else{node=AMcreateMmlNode(symbol.tag,node);if(symbol.input=="\\atop"||symbol.input=="\\choose")
+node.setAttribute("linethickness","0ex");node.appendChild(result[0]);if(symbol.input=="\\choose")
+node=AMcreateMmlNode("mfenced",node);}}
+return[node,str,tag];}
+function AMparseExpr(str,rightbracket,matrix){var symbol,node,result,i,tag,newFrag=document.createDocumentFragment();do{str=AMremoveCharsAndBlanks(str,0);result=AMparseIexpr(str);node=result[0];str=result[1];tag=result[2];symbol=AMgetSymbol(str);if(node!=undefined){if((tag=="mn"||tag=="mi")&&symbol!=null&&typeof symbol.func=="boolean"&&symbol.func){var space=AMcreateElementMathML("mspace");space.setAttribute("width","0.167em");node=AMcreateMmlNode("mrow",node);node.appendChild(space);}
+newFrag.appendChild(node);}}while((symbol.ttype!=RIGHTBRACKET)&&symbol!=null&&symbol.output!="");tag=null;if(symbol.ttype==RIGHTBRACKET){if(symbol.input=="\\right"){str=AMremoveCharsAndBlanks(str,symbol.input.length);symbol=AMgetSymbol(str);if(symbol!=null&&symbol.input==".")
+symbol.invisible=true;if(symbol!=null)
+tag=symbol.rtag;}
+if(symbol!=null)
+str=AMremoveCharsAndBlanks(str,symbol.input.length);var len=newFrag.childNodes.length;if(matrix&&len>0&&newFrag.childNodes[len-1].nodeName=="mrow"&&len>1&&newFrag.childNodes[len-2].nodeName=="mo"&&newFrag.childNodes[len-2].firstChild.nodeValue=="&"){var pos=[];var m=newFrag.childNodes.length;for(i=0;matrix&&i<m;i=i+2){pos[i]=[];node=newFrag.childNodes[i];for(var j=0;j<node.childNodes.length;j++)
+if(node.childNodes[j].firstChild.nodeValue=="&")
+pos[i][pos[i].length]=j;}
+var row,frag,n,k,table=document.createDocumentFragment();for(i=0;i<m;i=i+2){row=document.createDocumentFragment();frag=document.createDocumentFragment();node=newFrag.firstChild;n=node.childNodes.length;k=0;for(j=0;j<n;j++){if(typeof pos[i][k]!="undefined"&&j==pos[i][k]){node.removeChild(node.firstChild);row.appendChild(AMcreateMmlNode("mtd",frag));k++;}else frag.appendChild(node.firstChild);}
+row.appendChild(AMcreateMmlNode("mtd",frag));if(newFrag.childNodes.length>2){newFrag.removeChild(newFrag.firstChild);newFrag.removeChild(newFrag.firstChild);}
+table.appendChild(AMcreateMmlNode("mtr",row));}
+return[table,str];}
+if(typeof symbol.invisible!="boolean"||!symbol.invisible){node=AMcreateMmlNode("mo",document.createTextNode(symbol.output));newFrag.appendChild(node);}}
+return[newFrag,str,tag];}
+function AMparseMath(str){var result,node=AMcreateElementMathML("mstyle");var cclr=str.match(/\\color\s*\{\s*([#\w]+)\s*\}/);str=str.replace(/\\color\s*\{\s*[#\w]+\s*\}/g,"");if(cclr!=null){if(IsColorName.test(cclr[1].toLowerCase())){cclr=LaTeXColor[cclr[1].toLowerCase()];}else{cclr=cclr[1];}
+node.setAttribute("mathcolor",cclr);}else{if(mathcolor!="")node.setAttribute("mathcolor",mathcolor);};if(mathfontfamily!="")node.setAttribute("fontfamily",mathfontfamily);node.appendChild(AMparseExpr(str.replace(/^\s+/g,""),false,false)[0]);node=AMcreateMmlNode("math",node);if(showasciiformulaonhover)
+node.setAttribute("title",str.replace(/\s+/g," "));if(false){var fnode=AMcreateElementXHTML("font");fnode.setAttribute("face",mathfontfamily);fnode.appendChild(node);return fnode;}
+return node;}
+function AMstrarr2docFrag(arr,linebreaks){var newFrag=document.createDocumentFragment();var expr=false;for(var i=0;i<arr.length;i++){if(expr)newFrag.appendChild(AMparseMath(arr[i]));else{var arri=(linebreaks?arr[i].split("\n\n"):[arr[i]]);newFrag.appendChild(AMcreateElementXHTML("span").appendChild(document.createTextNode(arri[0])));for(var j=1;j<arri.length;j++){newFrag.appendChild(AMcreateElementXHTML("p"));newFrag.appendChild(AMcreateElementXHTML("span").appendChild(document.createTextNode(arri[j])));}}
+expr=!expr;}
+return newFrag;}
+function AMprocessNodeR(n,linebreaks){var mtch,str,arr,frg,i;if(n.childNodes.length==0){if((n.nodeType!=8||linebreaks)&&n.parentNode.nodeName!="form"&&n.parentNode.nodeName!="FORM"&&n.parentNode.nodeName!="textarea"&&n.parentNode.nodeName!="TEXTAREA"&&n.parentNode.nodeName!="pre"&&n.parentNode.nodeName!="PRE"){str=n.nodeValue;if(!(str==null)){str=str.replace(/\r\n\r\n/g,"\n\n");str=str.replace(/\x20+/g," ");str=str.replace(/\s*\r\n/g," ");mtch=(str.indexOf("\$")==-1?false:true);str=str.replace(/([^\\])\$/g,"$1 \$");str=str.replace(/^\$/," \$");arr=str.split(" \$");for(i=0;i<arr.length;i++)
+arr[i]=arr[i].replace(/\\\$/g,"\$");if(arr.length>1||mtch){if(checkForMathML){checkForMathML=false;var nd=AMisMathMLavailable();AMnoMathML=nd!=null;if(AMnoMathML&&notifyIfNoMathML)
+if(alertIfNoMathML)
+alert("To view the ASCIIMathML notation use Internet Explorer 6 +\nMathPlayer (free from www.dessci.com)\nor Firefox/Mozilla/Netscape");else AMbody.insertBefore(nd,AMbody.childNodes[0]);}
+if(!AMnoMathML){frg=AMstrarr2docFrag(arr,n.nodeType==8);var len=frg.childNodes.length;n.parentNode.replaceChild(frg,n);return len-1;}else return 0;}}}else return 0;}else if(n.nodeName!="math"){for(i=0;i<n.childNodes.length;i++)
+i+=AMprocessNodeR(n.childNodes[i],linebreaks);}
+return 0;}
+function AMprocessNode(n,linebreaks,spanclassAM){var frag,st;if(spanclassAM!=null){frag=document.getElementsByTagName("span")
+for(var i=0;i<frag.length;i++)
+if(frag[i].className=="AM")
+AMprocessNodeR(frag[i],linebreaks);}else{try{st=n.innerHTML;}catch(err){}
+if(st==null||st.indexOf("\$")!=-1)
+AMprocessNodeR(n,linebreaks);}
+if(isIE){frag=document.getElementsByTagName('math');for(var i=0;i<frag.length;i++)frag[i].update()}}
+var inAppendix=false;var sectionCntr=0;var IEcommentWarning=true;var biblist=[];var bibcntr=0;var LaTeXCounter=[];LaTeXCounter["definition"]=0;LaTeXCounter["proposition"]=0;LaTeXCounter["lemma"]=0;LaTeXCounter["theorem"]=0;LaTeXCounter["corollary"]=0;LaTeXCounter["example"]=0;LaTeXCounter["exercise"]=0;LaTeXCounter["subsection"]=0;LaTeXCounter["subsubsection"]=0;LaTeXCounter["figure"]=0;LaTeXCounter["equation"]=0;LaTeXCounter["table"]=0;var LaTeXColor=[];LaTeXColor["greenyellow"]="#D9FF4F";LaTeXColor["yellow"]="#FFFF00";LaTeXColor["goldenrod"]="#FFE529";LaTeXColor["dandelion"]="#FFB529";LaTeXColor["apricot"]="#FFAD7A";LaTeXColor["peach"]="#FF804D";LaTeXColor["melon"]="#FF8A80";LaTeXColor["yelloworange"]="#FF9400";LaTeXColor["orange"]="#FF6321";LaTeXColor["burntorange"]="#FF7D00";LaTeXColor["bittersweet"]="#C20300";LaTeXColor["redorange"]="#FF3B21";LaTeXColor["mahogany"]="#A60000";LaTeXColor["maroon"]="#AD0000";LaTeXColor["brickred"]="#B80000";LaTeXColor["red"]="#FF0000";LaTeXColor["orangered"]="#FF0080";LaTeXColor["rubinered"]="#FF00DE";LaTeXColor["wildstrawberry"]="#FF0A9C";LaTeXColor["salmon"]="#FF789E";LaTeXColor["carnationpink"]="#FF5EFF";LaTeXColor["magenta"]="#FF00FF";LaTeXColor["violetred"]="#FF30FF";LaTeXColor["rhodamine"]="#FF2EFF";LaTeXColor["mulberry"]="#A314FA";LaTeXColor["redviolet"]="#9600A8";LaTeXColor["fuchsia"]="#7303EB";LaTeXColor["lavender"]="#FF85FF";LaTeXColor["thistle"]="#E069FF";LaTeXColor["orchid"]="#AD5CFF";LaTeXColor["darkorchid"]="#9933CC";LaTeXColor["purple"]="#8C24FF";LaTeXColor["plum"]="#8000FF";LaTeXColor["violet"]="#361FFF";LaTeXColor["royalpurple"]="#401AFF";LaTeXColor["blueviolet"]="#1A0DF5";LaTeXColor["periwinkle"]="#6E73FF";LaTeXColor["cadetblue"]="#616EC4";LaTeXColor["cornflowerblue"]="#59DEFF";LaTeXColor["midnightblue"]="#007091";LaTeXColor["navyblue"]="#0F75FF";LaTeXColor["royalblue"]="#0080FF";LaTeXColor["blue"]="#0000FF";LaTeXColor["cerulean"]="#0FE3FF";LaTeXColor["cyan"]="#00FFFF";LaTeXColor["processblue"]="#0AFFFF";LaTeXColor["skyblue"]="#61FFE0";LaTeXColor["turquoise"]="#26FFCC";LaTeXColor["tealblue"]="#1FFAA3";LaTeXColor["aquamarine"]="#2EFFB2";LaTeXColor["bluegreen"]="#26FFAB";LaTeXColor["emerald"]="#00FF80";LaTeXColor["junglegreen"]="#03FF7A";LaTeXColor["seagreen"]="#4FFF80";LaTeXColor["green"]="#00FF00";LaTeXColor["forestgreen"]="#00E000";LaTeXColor["pinegreen"]="#00BF29";LaTeXColor["limegreen"]="#80FF00";LaTeXColor["yellowgreen"]="#8FFF42";LaTeXColor["springgreen"]="#BDFF3D";LaTeXColor["olivegreen"]="#009900";LaTeXColor["rawsienna"]="#8C0000";LaTeXColor["sepia"]="#4D0000";LaTeXColor["brown"]="#660000";LaTeXColor["tan"]="#DB9470";LaTeXColor["gray"]="#808080";LaTeXColor["grey"]="#808080";LaTeXColor["black"]="#000000";LaTeXColor["white"]="#FFFFFF";var IsColorName=/^(?:greenyellow|yellow|goldenrod|dandelion|apricot|peach|melon|yelloworange|orange|burntorange|bittersweet|redorange|mahogany|maroon|brickred|red|orangered|rubinered|wildstrawberry|salmon|carnationpink|magenta|violetred|rhodamine|mulberry|redviolet|fuchsia|lavender|thistle|orchid|darkorchid|purple|plum|violet|royalpurple|blueviolet|periwinkle|cadetblue|cornflowerblue|midnightblue|navyblue|royalblue|blue|cerulean|cyan|processblue|skyblue|turquoise|tealblue|aquamarine|bluegreen|emerald|junglegreen|seagreen|green|forestgreen|pinegreen|limegreen|yellowgreen|springgreen|olivegreen|rawsienna|sepia|brown|tan|gray|grey|black|white)$/;var IsCounter=/^(?:definition|proposition|lemma|theorem|corollary|example|exercise|subsection|subsubsection|figure|equation|table)$/;var IsLaTeXElement=/^(?:displayequation|title|author|address|date|abstract|keyword|section|subsection|subsubsection|ref|cite|thebibliography|definition|proposition|lemma|theorem|corollary|example|exercise|itemize|enumerate|enddefinition|endproposition|endlemma|endtheorem|endcorollary|endexample|endexercise|enditemize|endenumerate|LaTeXMathMLlabel|LaTeXMathML|smallskip|medskip|bigskip|quote|quotation|endquote|endquotation|center|endcenter|description|enddescription|inlinemath)$/;var IsTextOnlyArea=/^(?:form|textarea|pre)$/i;var tableid=0;function makeNumberString(cntr){if(sectionCntr>0){if(inAppendix){return"A"+sectionCntr+"."+cntr;}else{return sectionCntr+"."+cntr;}}else{return""+cntr;}};function LaTeXpreProcess(thebody){var TheBody=thebody;if(TheBody.hasChildNodes()){if(!(IsLaTeXElement.test(TheBody.className)))
+{for(var i=0;i<TheBody.childNodes.length;i++){LaTeXpreProcess(TheBody.childNodes[i])}}}
+else{if(TheBody.nodeType==3&&!(IsTextOnlyArea.test(TheBody.parentNode.nodeName)))
+{var str=TheBody.nodeValue;if(!(str==null)){str=str.replace(/\\%/g,"<per>");str=str.replace(/%[^\n]*(?=\n)/g,"");str=str.replace(/%[^\r]*(?=\r)/g,"");str=str.replace(/%[^\n]*$/,"")
+if(isIE&&str.match(/%/g)!=null&&IEcommentWarning){alert("Comments may not have parsed properly. Try putting in <pre class='LaTeX><div>..</div></pre> structure.");IEcommentWarning=false;}
+str=str.replace(/<per>/g,"%");if(str.match(/XXX[\s\S]*/)!=null){var tmp=str.match(/XXX[\s\S]*/)[0];var tmpstr=tmp.charCodeAt(7)+"::"+tmp.charCodeAt(8)+"::"+tmp.charCodeAt(9)+"::"+tmp.charCodeAt(10)+"::"+tmp.charCodeAt(11)+"::"+tmp.charCodeAt(12)+"::"+tmp.charCodeAt(13);alert(tmpstr);}
+str=str.replace(/([^\\])\\(\s)/g,"$1\u00A0$2");str=str.replace(/\\quad/g,"\u2001");str=str.replace(/\\qquad/g,"\u2001\u2001");str=str.replace(/\\enspace/g,"\u2002");str=str.replace(/\\;/g,"\u2004");str=str.replace(/\\:/g,"\u2005");str=str.replace(/\\,/g,"\u2006");str=str.replace(/\\thinspace/g,"\u200A");str=str.replace(/([^\\])~/g,"$1\u00A0");str=str.replace(/\\~/g,"~");str=str.replace(/\\\[/g," <DEQ> $\\displaystyle{");str=str.replace(/\\\]/g,"}$ <DEQ> ");str=str.replace(/\$\$/g,"${$<DEQ>$}$");str=str.replace(/\\begin\s*\{\s*array\s*\}/g,"\\begin{array}");str=str.replace(/\\end\s*\{\s*array\s*\}/g,"\\end{array}");str=str.replace(/\\begin\s*\{\s*eqnarray\s*\}/g," <DEQ>eqno$\\begin{eqnarray}");str=str.replace(/\\end\s*\{\s*eqnarray\s*\}/g,"\\end{eqnarray}$<DEQ> ");str=str.replace(/\\begin\s*\{\s*eqnarray\*\s*\}/g," <DEQ>$\\begin{eqnarray}");str=str.replace(/\\end\s*\{\s*eqnarray\*\s*\}/g,"\\end{eqnarray}$<DEQ> ");str=str.replace(/\\begin\s*\{\s*displaymath\s*\}/g," <DEQ> $\\displaystyle{");str=str.replace(/\\end\s*\{\s*displaymath\s*\}/g,"}$ <DEQ> ");str=str.replace(/\\begin\s*\{\s*equation\s*\*\s*\}/g," <DEQ> $\\displaystyle{");str=str.replace(/\\end\s*\{\s*equation\s*\*\s*\}/g,"}$ <DEQ> ");str=str.replace(/\\begin\s*\{\s*equation\s*\}/g," <DEQ>eqno$\\displaystyle{");str=str.replace(/\\end\s*\{\s*equation\s*\}/g,"}$ <DEQ> ");str=str.split("<DEQ>");var newFrag=document.createDocumentFragment();for(var i=0;i<str.length;i++){if(i%2){var DEQtable=document.createElement("table");DEQtable.className='displayequation';var DEQtbody=document.createElement("tbody");var DEQtr=document.createElement("tr");var DEQtdeq=document.createElement("td");DEQtdeq.className='eq';str[i]=str[i].replace(/\$\}\$/g,"$\\displaystyle{");str[i]=str[i].replace(/\$\{\$/g,"}");var lbl=str[i].match(/\\label\s*\{\s*(\w+)\s*\}/);var ISeqno=str[i].match(/^eqno/);str[i]=str[i].replace(/^eqno/," ");str[i]=str[i].replace(/\\label\s*\{\s*\w+\s*\}/," ");DEQtdeq.appendChild(document.createTextNode(str[i]));DEQtr.appendChild(DEQtdeq);str[i]=str[i].replace(/\\nonumber/g,"");if(ISeqno!=null||lbl!=null){var DEQtdno=document.createElement("td");DEQtdno.className='eqno';LaTeXCounter["equation"]++;var eqnoString=makeNumberString(LaTeXCounter["equation"]);var DEQanchor=document.createElement("a");if(lbl!=null){DEQanchor.id=lbl[1]};DEQanchor.className="eqno";var anchorSpan=document.createElement("span");anchorSpan.className="eqno";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(eqnoString));DEQanchor.appendChild(anchorSpan);DEQtdno.appendChild(DEQanchor);var DEQspan=document.createElement("span");DEQspan.className="eqno";DEQspan.appendChild(document.createTextNode("("+eqnoString+")"));DEQtdno.appendChild(DEQspan);DEQtr.appendChild(DEQtdno);}
+DEQtbody.appendChild(DEQtr);DEQtable.appendChild(DEQtbody);newFrag.appendChild(DEQtable);}
+else{str[i]=str[i].replace(/\$\}\$/g,"");str[i]=str[i].replace(/\$\{\$/g,"");str[i]=str[i].replace(/\\maketitle/g,"");str[i]=str[i].replace(/\\begin\s*\{\s*document\s*\}/g,"");str[i]=str[i].replace(/\\end\s*\{\s*document\s*\}/g,"");str[i]=str[i].replace(/\\documentclass[^\}]*?\}/g,"");str[i]=str[i].replace(/\\usepackage[^\}]*?\}/g,"");str[i]=str[i].replace(/\\noindent/g,"");str[i]=str[i].replace(/\\notag/g,"");str[i]=str[i].replace(/\\ref\s*\{\s*(\w+)\}/g," \\[ref\\]$1\\[ ");str[i]=str[i].replace(/\\url\s*\{\s*([^\}\n]+)\}/g," \\[url\\]$1\\[ ");str[i]=str[i].replace(/\\href\s*\{\s*([^\}]+)\}\s*\{\s*([^\}]+)\}/g," \\[href\\]$1\\]$2\\[ ");str[i]=str[i].replace(/\\cite\s*\{\s*(\w+)\}/g," \\[cite\\]$1\\[ ");str[i]=str[i].replace(/\\qed/g,"\u220E");str[i]=str[i].replace(/\\endproof/g,"\u220E");str[i]=str[i].replace(/\\proof/g,"\\textbf{Proof: }");str[i]=str[i].replace(/\\n(?=\s)/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\newline/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\linebreak/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\smallskip/g," \\[logicalbreak\\]smallskip\\[ ");str[i]=str[i].replace(/\\medskip/g," \\[logicalbreak\\]medskip\\[ ");str[i]=str[i].replace(/\\bigskip/g," \\[logicalbreak\\]bigskip\\[ ");str[i]=str[i].replace(/[\n\r]+[ \f\n\r\t\v\u2028\u2029]*[\n\r]+/g," \\[logicalbreak\\]LaTeXMathML\\[ ");if(isIE){str[i]=str[i].replace(/\r/g," ");}
+str[i]=str[i].replace(/\\bibitem\s*([^\{]*\{\s*\w*\s*\})/g," \\[bibitem\\]$1\\[ ");str[i]=str[i].replace(/\\bibitem\s*/g," \\[bibitem\\] \\[ ");str[i]=str[i].replace(/\\item\s*\[\s*(\w+)\s*\]/g," \\[alistitem\\]$1\\[ ");str[i]=str[i].replace(/\\item\s*/g," \\[alistitem\\] \\[ ");str[i]=str[i].replace(/\\appendix/g," \\[appendix\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*figure\s*\}([\s\S]+?)\\end\s*\{\s*figure\s*\}/g," \\[figure\\]$1\\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*table\s*\}([\s\S]+?)\\end\s*\{\s*table\s*\}/g," \\[table\\]$1\\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*theorem\s*\}/g," \\[theorem\\]Theorem \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*theorem\s*\}/g," \\[endtheorem\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*definition\s*\}/g," \\[definition\\]Definition \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*definition\s*\}/g," \\[enddefinition\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*lemma\s*\}/g," \\[lemma\\]Lemma \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*lemma\s*\}/g," \\[endlemma\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*corollary\s*\}/g," \\[corollary\\]Corollary \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*corollary\s*\}/g," \\[endcorollary\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*proposition\s*\}/g," \\[proposition\\]Proposition \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*proposition\s*\}/g," \\[endproposition\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*example\s*\}/g," \\[example\\]Example \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*example\s*\}/g," \\[endexample\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*exercise\s*\}/g," \\[exercise\\]Exercise \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*exercise\s*\}/g," \\[endexercise\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*thebibliography\s*\}\s*\{\s*\w+\s*\}/g," \\[thebibliography\\]References \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*thebibliography\s*\}/g," \\[thebibliography\\]References \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*thebibliography\s*\}/g," \\[endthebibliography\\]References \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*proof\s*\}/g," \\[proof\\]Proof: \\[ ");if(isIE){str[i]=str[i].replace(/\\end\s*\{\s*proof\s*\}/g,"\u220E \\[endproof\\] \\[ ");}else{str[i]=str[i].replace(/\\end\s*\{\s*proof\s*\}/g," \\[endproof\\] \\[ ");}
+str[i]=str[i].replace(/\\title\s*\{\s*([^\}]+)\}/g," \\[title\\] \\[$1 \\[endtitle\\] \\[ ");str[i]=str[i].replace(/\\author\s*\{\s*([^\}]+)\}/g," \\[author\\] \\[$1 \\[endauthor\\] \\[ ");str[i]=str[i].replace(/\\address\s*\{\s*([^\}]+)\}/g," \\[address\\] \\[$1 \\[endaddress\\] \\[ ");str[i]=str[i].replace(/\\date\s*\{\s*([^\}]+)\}/g," \\[date\\] \\[$1 \\[enddate\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*keyword\s*\}/g," \\[keyword\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*keyword\s*\}/g," \\[endkeyword\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*abstract\s*\}/g," \\[abstract\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*abstract\s*\}/g," \\[endabstract\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*(?!array|tabular)(\w+)\s*\}/g," \\[$1\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*(?!array|tabular)(\w+)\s*\}/g," \\[end$1\\] \\[ ");var sectionIndex=str[i].search(/\\section\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\section\s*\{/," \\[section\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\section\s*\{\s*[\s\S]+\}/);}
+sectionIndex=str[i].search(/\\subsection\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\subsection\s*\{/," \\[subsection\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\subsection\s*\{\s*[\s\S]+\}/);}
+sectionIndex=str[i].search(/\\subsubsection\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\subsubsection\s*\{/," \\[subsubsection\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\subsubsection\s*\{\s*[\s\S]+\}/);}
+var CatToNextEven="";var strtmp=str[i].split("\\[");for(var j=0;j<strtmp.length;j++){if(j%2){var strtmparray=strtmp[j].split("\\]");switch(strtmparray[0]){case"section":var nodeTmp=document.createElement("H2");nodeTmp.className='section';sectionCntr++;for(var div in LaTeXCounter){LaTeXCounter[div]=0};var nodeAnchor=document.createElement("a");if(inAppendix){nodeAnchor.className='appendixsection';}else{nodeAnchor.className='section';}
+var nodeNumString=makeNumberString("");var anchorSpan=document.createElement("span");anchorSpan.className="section";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='section';nodeSpan.appendChild(document.createTextNode(nodeNumString+" "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"subsection":var nodeTmp=document.createElement("H3");nodeTmp.className='subsection';LaTeXCounter["subsection"]++;LaTeXCounter["subsubsection"]=0;var nodeAnchor=document.createElement("a");nodeAnchor.className='subsection';var nodeNumString=makeNumberString(LaTeXCounter["subsection"]);var anchorSpan=document.createElement("span");anchorSpan.className="subsection";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='subsection';nodeSpan.appendChild(document.createTextNode(nodeNumString+". "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"subsubsection":var nodeTmp=document.createElement("H4");nodeTmp.className='subsubsection';LaTeXCounter["subsubsection"]++;var nodeAnchor=document.createElement("a");nodeAnchor.className='subsubsection';var nodeNumString=makeNumberString(LaTeXCounter["subsection"]+"."+LaTeXCounter["subsubsection"]);var anchorSpan=document.createElement("span");anchorSpan.className="subsubsection";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='subsubsection';nodeSpan.appendChild(document.createTextNode(nodeNumString+". "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"href":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathML';nodeTmp.href=strtmparray[1];nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"url":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathML';nodeTmp.href=strtmparray[1];nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"figure":var nodeTmp=document.createElement("table");nodeTmp.className='figure';var FIGtbody=document.createElement("tbody");var FIGlbl=strtmparray[1].match(/\\label\s*\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\\label\s*\{\w+\}/g,"");var capIndex=strtmparray[1].search(/\\caption\s*\{[\s\S]+\}/);var FIGcap="";if(capIndex>=0){var tmp=strtmparray[1];var delimcnt=0;var capstart=-1;for(var pos=capIndex;pos<tmp.length;pos++){if(tmp.charAt(pos)=="{"){delimcnt++};if(tmp.charAt(pos)=="}"){delimcnt--};if(delimcnt==1&&capstart<0){capstart=pos+1};if(delimcnt==0&&capstart>0){capend=pos-1;FIGcap=tmp.substring(capstart,pos);break}}}
+var FIGtr2=document.createElement("tr");var FIGtd2=document.createElement("td");FIGtd2.className="caption";var FIGanchor=document.createElement("a");FIGanchor.className="figure";if(FIGlbl!=null){FIGanchor.id=FIGlbl[1];}
+LaTeXCounter["figure"]++;var fignmbr=makeNumberString(LaTeXCounter["figure"]);var anchorSpan=document.createElement("span");anchorSpan.className="figure";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(fignmbr));FIGanchor.appendChild(anchorSpan);FIGtd2.appendChild(FIGanchor);var FIGspan=document.createElement("span");FIGspan.className="figure";FIGspan.appendChild(document.createTextNode("Figure "+fignmbr+". "));FIGtd2.appendChild(FIGspan);FIGtd2.appendChild(document.createTextNode(""+FIGcap));FIGtr2.appendChild(FIGtd2);FIGtbody.appendChild(FIGtr2);var IsSpecial=false;var FIGinfo=strtmparray[1].match(/\\includegraphics\s*\{([^\}]+)\}/);if(FIGinfo==null){FIGinfo=strtmparray[1].match(/\\includegraphics\s*\[[^\]]*\]\s*\{\s*([^\}]+)\s*\}/);}
+if(FIGinfo==null){FIGinfo=strtmparray[1].match(/\\special\s*\{\s*([^\}]+)\}/);IsSpecial=true};if(FIGinfo!=null){var FIGtr1=document.createElement("tr");var FIGtd1=document.createElement("td");FIGtd1.className="image";var FIGimg=document.createElement("img");var FIGsrc=FIGinfo[1];FIGimg.src=FIGsrc;FIGimg.alt="Figure "+FIGsrc+" did not load";FIGimg.title="Figure "+fignmbr+". "+FIGcap;FIGimg.id="figure"+fignmbr;FIGtd1.appendChild(FIGimg);FIGtr1.appendChild(FIGtd1);FIGtbody.appendChild(FIGtr1);}
+nodeTmp.appendChild(FIGtbody);newFrag.appendChild(nodeTmp);break;case"table":var nodeTmp=document.createElement("table");if(strtmparray[1].search(/\\centering/)>=0){nodeTmp.className='LaTeXtable centered';nodeTmp.align="center";}else{nodeTmp.className='LaTeXtable';};tableid++;nodeTmp.id="LaTeXtable"+tableid;var TABlbl=strtmparray[1].match(/\\label\s*\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\\label\s*\{\w+\}/g,"");var capIndex=strtmparray[1].search(/\\caption\s*\{[\s\S]+\}/);var TABcap="";if(capIndex>=0){var tmp=strtmparray[1];var delimcnt=0;var capstart=-1;for(var pos=capIndex;pos<tmp.length;pos++){if(tmp.charAt(pos)=="{"){delimcnt++};if(tmp.charAt(pos)=="}"){delimcnt--};if(delimcnt==1&&capstart<0){capstart=pos+1};if(delimcnt==0&&capstart>0){capend=pos-1;TABcap=tmp.substring(capstart,pos);break}}}
+if(TABcap!=""){var TABtbody=document.createElement("tbody");var TABcaption=document.createElement("caption");TABcaption.className="LaTeXtable centered";var TABanchor=document.createElement("a");TABanchor.className="LaTeXtable";if(TABlbl!=null){TABanchor.id=TABlbl[1];}
+LaTeXCounter["table"]++;var tabnmbr=makeNumberString(LaTeXCounter["table"]);var anchorSpan=document.createElement("span");anchorSpan.className="LaTeXtable";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(tabnmbr));TABanchor.appendChild(anchorSpan);TABcaption.appendChild(TABanchor);var TABspan=document.createElement("span");TABspan.className="LaTeXtable";TABspan.appendChild(document.createTextNode("Table "+tabnmbr+". "));TABcaption.appendChild(TABspan);TABcaption.appendChild(document.createTextNode(""+TABcap));nodeTmp.appendChild(TABcaption);}
+var TABinfo=strtmparray[1].match(/\\begin\s*\{\s*tabular\s*\}([\s\S]+)\\end\s*\{\s*tabular\s*\}/);if(TABinfo!=null){var TABtbody=document.createElement('tbody');var TABrow=null;var TABcell=null;var row=0;var col=0;var TABalign=TABinfo[1].match(/^\s*\{([^\}]+)\}/);TABinfo=TABinfo[1].replace(/^\s*\{[^\}]+\}/,"");TABinfo=TABinfo.replace(/\\hline/g,"");TABalign[1]=TABalign[1].replace(/\|/g,"");TABalign[1]=TABalign[1].replace(/\s/g,"");TABinfo=TABinfo.split("\\\\");for(row=0;row<TABinfo.length;row++){TABrow=document.createElement("tr");TABinfo[row]=TABinfo[row].split("&");for(col=0;col<TABinfo[row].length;col++){TABcell=document.createElement("td");switch(TABalign[1].charAt(col)){case"l":TABcell.align="left";break;case"c":TABcell.align="center";break;case"r":TABcell.align="right";break;default:TABcell.align="left";};TABcell.appendChild(document.createTextNode(TABinfo[row][col]));TABrow.appendChild(TABcell);}
+TABtbody.appendChild(TABrow);}
+nodeTmp.appendChild(TABtbody);}
+newFrag.appendChild(nodeTmp);break;case"logicalbreak":var nodeTmp=document.createElement("p");nodeTmp.className=strtmparray[1];nodeTmp.appendChild(document.createTextNode("\u00A0"));newFrag.appendChild(nodeTmp);break;case"appendix":inAppendix=true;sectionCntr=0;break;case"alistitem":var EndDiv=document.createElement("div");EndDiv.className="endlistitem";newFrag.appendChild(EndDiv);var BegDiv=document.createElement("div");BegDiv.className="listitem";if(strtmparray[1]!=" "){var BegSpan=document.createElement("span");BegSpan.className="listitemmarker";var boldBegSpan=document.createElement("b");boldBegSpan.appendChild(document.createTextNode(strtmparray[1]+" "));BegSpan.appendChild(boldBegSpan);BegDiv.appendChild(BegSpan);}
+newFrag.appendChild(BegDiv);break;case"br":newFrag.appendChild(document.createElement("br"));break;case"bibitem":newFrag.appendChild(document.createElement("br"));var nodeTmp=document.createElement("a");nodeTmp.className='bibitem';var nodeSpan=document.createElement("span");nodeSpan.className='bibitem';bibcntr++;var lbl=strtmparray[1].match(/\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\s*\{\s*\w+\s*\}/g,"");strtmparray[1]=strtmparray[1].replace(/^\s*\[/,"");strtmparray[1]=strtmparray[1].replace(/\s*\]$/,"");strtmparray[1]=strtmparray[1].replace(/^\s+|\s+$/g,"");if(lbl==null){biblist[bibcntr]="bibitem"+bibcntr}else{biblist[bibcntr]=lbl[1];};nodeTmp.name=biblist[bibcntr];nodeTmp.id=biblist[bibcntr];if(strtmparray[1]!=""){nodeSpan.appendChild(document.createTextNode(strtmparray[1]));}else{nodeSpan.appendChild(document.createTextNode("["+bibcntr+"]"));}
+nodeTmp.appendChild(nodeSpan);newFrag.appendChild(nodeTmp);break;case"cite":var nodeTmp=document.createElement("a");nodeTmp.className='cite';nodeTmp.name='cite';nodeTmp.href="#"+strtmparray[1];newFrag.appendChild(nodeTmp);break;case"ref":var nodeTmp=document.createElement("a");nodeTmp.className='ref';nodeTmp.name='ref';nodeTmp.href="#"+strtmparray[1];newFrag.appendChild(nodeTmp);break;default:var nodeTmp=document.createElement("div");nodeTmp.className=strtmparray[0];if(IsCounter.test(strtmparray[0])){LaTeXCounter[strtmparray[0]]++;var nodeAnchor=document.createElement("a");nodeAnchor.className=strtmparray[0];var divnum=makeNumberString(LaTeXCounter[strtmparray[0]]);var anchorSpan=document.createElement("span");anchorSpan.className=strtmparray[0];anchorSpan.appendChild(document.createTextNode(divnum));anchorSpan.style.display="none";nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className=strtmparray[0];nodeSpan.appendChild(document.createTextNode(strtmparray[1]+" "+divnum+". "));nodeTmp.appendChild(nodeSpan);}
+if(isIE){if(strtmparray[0]==("thebibliography"||"abstract"||"keyword"||"proof")){var nodeSpan=document.createElement("span");nodeSpan.className=strtmparray[0];nodeSpan.appendChild(document.createTextNode(strtmparray[1]));nodeTmp.appendChild(nodeSpan);}}
+if(strtmparray[0]=="endenumerate"||strtmparray[0]=="enditemize"||strtmparray[0]=="enddescription"){var endDiv=document.createElement("div");endDiv.className="endlistitem";newFrag.appendChild(endDiv);}
+newFrag.appendChild(nodeTmp);if(strtmparray[0]=="enumerate"||strtmparray[0]=="itemize"||strtmparray[0]=="description"){var endDiv=document.createElement("div");endDiv.className="listitem";newFrag.appendChild(endDiv);}}}else{strtmp[j]=strtmp[j].replace(/\\\$/g,"<per>");strtmp[j]=strtmp[j].replace(/\$([^\$]+)\$/g," \\[$1\\[ ");strtmp[j]=strtmp[j].replace(/<per>/g,"\\$");strtmp[j]=strtmp[j].replace(/\\begin\s*\{\s*math\s*\}([\s\S]+?)\\end\s*\{\s*math\s*\}/g," \\[$1\\[ ");var strtmptmp=strtmp[j].split("\\[");for(var jjj=0;jjj<strtmptmp.length;jjj++){if(jjj%2){var nodeTmp=document.createElement("span");nodeTmp.className='inlinemath';nodeTmp.appendChild(document.createTextNode("$"+strtmptmp[jjj]+"$"));newFrag.appendChild(nodeTmp);}else{var TagIndex=strtmptmp[jjj].search(/\\\w+/);var tmpIndex=TagIndex;while(tmpIndex>-1){if(/^\\textcolor/.test(strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length))){strtmptmp[jjj]=strtmptmp[jjj].replace(/\\textcolor\s*\{\s*(\w+)\s*\}\s*/," \\[textcolor\\]$1\\]|");}else{if(/^\\colorbox/.test(strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length))){strtmptmp[jjj]=strtmptmp[jjj].replace(/\\colorbox\s*\{\s*(\w+)\s*\}\s*/," \\[colorbox\\]$1\\]|");}else{strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).replace(/\\\s*(\w+)\s*/," \\[$1\\]|");}}
+TagIndex+=strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).search(/\|/);TagIndex++;strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\]\|/,"\\] ");if(strtmptmp[jjj].charAt(TagIndex)=="{"){strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+strtmptmp[jjj].substring(TagIndex+1,strtmptmp[jjj].length);var delimcnt=1;for(var kk=TagIndex;kk<strtmptmp[jjj].length;kk++){if(strtmptmp[jjj].charAt(kk)=="{"){delimcnt++};if(strtmptmp[jjj].charAt(kk)=="}"){delimcnt--};if(delimcnt==0){break;}}
+strtmptmp[jjj]=strtmptmp[jjj].substring(0,kk)+"\\[ "+strtmptmp[jjj].substring(kk+1,strtmptmp[jjj].length);TagIndex=kk+3;}else{strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+"\\[ "+strtmptmp[jjj].substring(TagIndex+1,strtmptmp[jjj].length);TagIndex=TagIndex+3;}
+if(TagIndex<strtmptmp[jjj].length){tmpIndex=strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).search(/\\\w+/);}
+else{tmpIndex=-1};TagIndex+=tmpIndex;}
+strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\\\s*\\\\/g,"\\\\");strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\\/g," \\[br\\] \\[ ");strtmptmp[jjj]=strtmptmp[jjj].replace(/\\label\s*\{\s*(\w+)\s*\}/g," \\[a\\]$1\\[ ");var strlbls=strtmptmp[jjj].split("\\[");for(var jj=0;jj<strlbls.length;jj++){if(jj%2){var strtmparray=strlbls[jj].split("\\]");switch(strtmparray[0]){case"textcolor":var nodeTmp=document.createElement("span");nodeTmp.className='LaTeXColor';if(IsColorName.test(strtmparray[1].toLowerCase())){nodeTmp.style.color=LaTeXColor[strtmparray[1].toLowerCase()];}else{nodeTmp.style.color=strtmparray[1];};nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"colorbox":var nodeTmp=document.createElement("span");nodeTmp.className='LaTeXColor';if(IsColorName.test(strtmparray[1].toLowerCase())){nodeTmp.style.background=LaTeXColor[strtmparray[1].toLowerCase()];}else{nodeTmp.style.background=strtmparray[1];};nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"br":newFrag.appendChild(document.createElement("br"));break;case"a":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathMLlabel';nodeTmp.id=strtmparray[1];nodeTmp.style.display="none";newFrag.appendChild(nodeTmp);break;default:var nodeTmp=document.createElement("span");nodeTmp.className=strtmparray[0];nodeTmp.appendChild(document.createTextNode(strtmparray[1]))
+newFrag.appendChild(nodeTmp);}}else{newFrag.appendChild(document.createTextNode(strlbls[jj]));}}}}}}}};TheBody.parentNode.replaceChild(newFrag,TheBody);}}}
+return TheBody;}
+function LaTeXDivsAndRefs(thebody){var TheBody=thebody;var EndDivClass=null;var AllDivs=TheBody.getElementsByTagName("div");var lbl2id="";var lblnode=null;for(var i=AllDivs.length-1;i>=0;i--){EndDivClass=AllDivs[i].className.match(/end\w+/);if(EndDivClass!=null){EndDivClass=EndDivClass[0];var DivClass=EndDivClass.substring(3,EndDivClass.length);var EndDivNode=AllDivs[i];break;}}
+while(EndDivClass!=null){var newFrag=document.createDocumentFragment();var RootNode=EndDivNode.parentNode;var ClassCount=1;while(EndDivNode.previousSibling!=null&&ClassCount>0){switch(EndDivNode.previousSibling.className){case EndDivClass:ClassCount++;newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);break;case DivClass:if(EndDivNode.previousSibling.nodeName=="DIV"){ClassCount--;if(lbl2id!=""){EndDivNode.previousSibling.id=lbl2id;lbl2id=""}
+if(ClassCount==0){RootNode=EndDivNode.previousSibling;}else{newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);}};break;case'LaTeXMathMLlabel':lbl2id=EndDivNode.previousSibling.id;EndDivNode.parentNode.removeChild(EndDivNode.previousSibling);break;default:newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);}}
+RootNode.appendChild(newFrag);EndDivNode.parentNode.removeChild(EndDivNode);AllDivs=TheBody.getElementsByTagName("DIV");for(i=AllDivs.length-1;i>=0;i--){EndDivClass=AllDivs[i].className.match(/end\w+/);if(EndDivClass!=null){ClassCount=0;EndDivClass=EndDivClass[0];DivClass=EndDivClass.substring(3,EndDivClass.length);EndDivNode=AllDivs[i];RootNode=EndDivNode.parentNode;break;}}}
+var AllDivs=TheBody.getElementsByTagName("div");var DIV2LI=null;for(var i=0;i<AllDivs.length;i++){if(AllDivs[i].className=="itemize"||AllDivs[i].className=="enumerate"||AllDivs[i].className=="description"){if(AllDivs[i].className=="itemize"){RootNode=document.createElement("UL");}else{RootNode=document.createElement("OL");}
+RootNode.className='LaTeXMathML';if(AllDivs[i].hasChildNodes()){AllDivs[i].removeChild(AllDivs[i].firstChild)};while(AllDivs[i].hasChildNodes()){if(AllDivs[i].firstChild.hasChildNodes()){DIV2LI=document.createElement("LI");while(AllDivs[i].firstChild.hasChildNodes()){DIV2LI.appendChild(AllDivs[i].firstChild.firstChild);}
+if(DIV2LI.firstChild.className=="listitemmarker"){DIV2LI.style.listStyleType="none";}
+RootNode.appendChild(DIV2LI)}
+AllDivs[i].removeChild(AllDivs[i].firstChild);}
+AllDivs[i].appendChild(RootNode);}}
+var AllAnchors=TheBody.getElementsByTagName("a");for(var i=0;i<AllAnchors.length;i++){if(AllAnchors[i].className=="ref"||AllAnchors[i].className=="cite"){var label=AllAnchors[i].href.match(/\#(\w+)/);if(label!=null){var labelNode=document.getElementById(label[1]);if(labelNode!=null){var TheSpans=labelNode.getElementsByTagName("SPAN");if(TheSpans!=null){var refNode=TheSpans[0].cloneNode(true);refNode.style.display="inline"
+refNode.className=AllAnchors[i].className;AllAnchors[i].appendChild(refNode);}}}}}
+return TheBody;}
+var AMbody;var AMnoMathML=false,AMtranslated=false;function translate(spanclassAM){if(!AMtranslated){AMtranslated=true;AMinitSymbols();var LaTeXContainers=[];var AllContainers=document.getElementsByTagName('*');var ExtendName="";for(var k=0,l=0;k<AllContainers.length;k++){ExtendName=" "+AllContainers[k].className+" ";if(ExtendName.match(/\sLaTeX\s/)!=null){LaTeXContainers[l]=AllContainers[k];l++;}};if(LaTeXContainers.length>0){for(var m=0;m<LaTeXContainers.length;m++){AMbody=LaTeXContainers[m];try{AMbody=LaTeXDivsAndRefs(LaTeXpreProcess(AMbody));}catch(err){alert("Unknown Error: Defaulting to Original LaTeXMathML");}
+if(AMbody.tagName=="PRE"){var PreChilds=document.createDocumentFragment();var DivChilds=document.createElement("DIV");while(AMbody.hasChildNodes()){DivChilds.appendChild(AMbody.firstChild);}
+PreChilds.appendChild(DivChilds);AMbody.parentNode.replaceChild(PreChilds,AMbody);AMbody=DivChilds;}
+AMprocessNode(AMbody,false,spanclassAM);}}else{AMbody=document.getElementsByTagName("body")[0];try{AMbody=LaTeXDivsAndRefs(LaTeXpreProcess(AMbody));}catch(err){alert("Unknown Error: Defaulting to Original LaTeXMathML");}
+AMprocessNode(AMbody,false,spanclassAM);}}}
+if(isIE){document.write("<object id=\"mathplayer\" classid=\"clsid:32F66A20-7614-11D4-BD11-00104BD3F987\"></object>");document.write("<?import namespace=\"m\" implementation=\"#mathplayer\"?>");}
+function generic()
+{translate();};if(typeof window.addEventListener!='undefined')
+{window.addEventListener('load',generic,false);}
+else if(typeof document.addEventListener!='undefined')
+{document.addEventListener('load',generic,false);}
+else if(typeof window.attachEvent!='undefined')
+{window.attachEvent('onload',generic);}
+else
+{if(typeof window.onload=='function')
+{var existing=onload;window.onload=function()
+{existing();generic();};}
+else
+{window.onload=generic;}} \ No newline at end of file
diff --git a/data/headers/ConTeXt.header b/data/headers/ConTeXt.header
new file mode 100644
index 000000000..d19b41c45
--- /dev/null
+++ b/data/headers/ConTeXt.header
@@ -0,0 +1,70 @@
+\enableregime[utf] % use UTF-8
+
+\setupcolors[state=start]
+\setupinteraction[state=start, color=middleblue] % needed for hyperlinks
+
+\setuppapersize[letter][letter] % use letter paper
+\setuplayout[width=middle, backspace=1.5in, cutspace=1.5in,
+ height=middle, header=0.75in, footer=0.75in] % page layout
+\setuppagenumbering[location={footer,center}] % number pages
+\setupbodyfont[11pt] % 11pt font
+\setupwhitespace[medium] % inter-paragraph spacing
+
+\setuphead[section][style=\tfc]
+\setuphead[subsection][style=\tfb]
+\setuphead[subsubsection][style=\bf]
+
+% define title block commands
+\unprotect
+\def\doctitle#1{\gdef\@title{#1}}
+\def\author#1{\gdef\@author{#1}}
+\def\date#1{\gdef\@date{#1}}
+\date{\currentdate} % Default to today unless specified otherwise.
+\def\maketitle{%
+ \startalignment[center]
+ \blank[2*big]
+ {\tfd \@title}
+ \blank[3*medium]
+ {\tfa \@author}
+ \blank[2*medium]
+ {\tfa \@date}
+ \blank[3*medium]
+ \stopalignment}
+\protect
+
+% define descr (for definition lists)
+\definedescription[descr][
+ headstyle=bold,style=normal,align=left,location=hanging,
+ width=broad,margin=1cm]
+
+% prevent orphaned list intros
+\setupitemize[autointro]
+
+% define defaults for bulleted lists
+\setupitemize[1][symbol=1][indentnext=no]
+\setupitemize[2][symbol=2][indentnext=no]
+\setupitemize[3][symbol=3][indentnext=no]
+\setupitemize[4][symbol=4][indentnext=no]
+
+\setupthinrules[width=15em] % width of horizontal rules
+
+% for block quotations
+\unprotect
+
+\startvariables all
+blockquote: blockquote
+\stopvariables
+
+\definedelimitedtext
+[\v!blockquote][\v!quotation]
+
+\setupdelimitedtext
+[\v!blockquote]
+[\c!left=,
+\c!right=,
+before={\blank[medium]},
+after={\blank[medium]},
+]
+
+\protect
+
diff --git a/data/headers/Docbook.header b/data/headers/Docbook.header
new file mode 100644
index 000000000..7b26b2c73
--- /dev/null
+++ b/data/headers/Docbook.header
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+ "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
diff --git a/data/headers/LaTeX.header b/data/headers/LaTeX.header
new file mode 100644
index 000000000..f6f1d4e7c
--- /dev/null
+++ b/data/headers/LaTeX.header
@@ -0,0 +1,8 @@
+\documentclass{article}
+\usepackage{amsmath}
+\usepackage[mathletters]{ucs}
+\usepackage[utf8x]{inputenc}
+\usepackage{listings}
+\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
diff --git a/data/headers/OpenDocument.header b/data/headers/OpenDocument.header
new file mode 100644
index 000000000..17ed4fd9f
--- /dev/null
+++ b/data/headers/OpenDocument.header
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="utf-8" ?>
diff --git a/data/headers/RTF.header b/data/headers/RTF.header
new file mode 100644
index 000000000..b4368694b
--- /dev/null
+++ b/data/headers/RTF.header
@@ -0,0 +1,4 @@
+{\rtf1\ansi\deff0{\fonttbl{\f0 \fswiss Helvetica;}{\f1 Courier;}}
+{\colortbl;\red255\green0\blue0;\red0\green0\blue255;}
+\widowctrl\hyphauto
+
diff --git a/data/headers/S5.header b/data/headers/S5.header
new file mode 100644
index 000000000..ebb24ebe2
--- /dev/null
+++ b/data/headers/S5.header
@@ -0,0 +1,3 @@
+<!-- configuration parameters -->
+<meta name="defaultView" content="slideshow" />
+<meta name="controlVis" content="hidden" />
diff --git a/data/odt-styles/META-INF/manifest.xml b/data/odt-styles/META-INF/manifest.xml
new file mode 100644
index 000000000..5ecd5d892
--- /dev/null
+++ b/data/odt-styles/META-INF/manifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0">
+ <manifest:file-entry manifest:media-type="application/vnd.oasis.opendocument.text" manifest:full-path="/"/>
+ <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/statusbar/"/>
+ <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/accelerator/current.xml"/>
+ <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/accelerator/"/>
+ <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/floater/"/>
+ <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/popupmenu/"/>
+ <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/progressbar/"/>
+ <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/menubar/"/>
+ <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/toolbar/"/>
+ <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/images/Bitmaps/"/>
+ <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/images/"/>
+ <manifest:file-entry manifest:media-type="application/vnd.sun.xml.ui.configuration" manifest:full-path="Configurations2/"/>
+ <manifest:file-entry manifest:media-type="application/binary" manifest:full-path="layout-cache"/>
+ <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="content.xml"/>
+ <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="styles.xml"/>
+ <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="meta.xml"/>
+ <manifest:file-entry manifest:media-type="" manifest:full-path="Thumbnails/thumbnail.png"/>
+ <manifest:file-entry manifest:media-type="" manifest:full-path="Thumbnails/"/>
+ <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="settings.xml"/>
+</manifest:manifest> \ No newline at end of file
diff --git a/data/odt-styles/Thumbnails/thumbnail.png b/data/odt-styles/Thumbnails/thumbnail.png
new file mode 100644
index 000000000..4e213b6b3
--- /dev/null
+++ b/data/odt-styles/Thumbnails/thumbnail.png
Binary files differ
diff --git a/data/odt-styles/meta.xml b/data/odt-styles/meta.xml
new file mode 100644
index 000000000..93363b77e
--- /dev/null
+++ b/data/odt-styles/meta.xml
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:ooo="http://openoffice.org/2004/office" office:version="1.1"><office:meta><meta:generator></meta:generator><dc:title></dc:title><dc:subject></dc:subject><meta:creation-date></meta:creation-date><dc:date></dc:date><meta:editing-cycles></meta:editing-cycles><meta:editing-duration></meta:editing-duration><meta:user-defined meta:name="Info 1"/><meta:user-defined meta:name="Info 2"/><meta:user-defined meta:name="Info 3"/><meta:user-defined meta:name="Info 4"/><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="0" meta:paragraph-count="0" meta:word-count="0" meta:character-count="0"/></office:meta></office:document-meta> \ No newline at end of file
diff --git a/data/odt-styles/mimetype b/data/odt-styles/mimetype
new file mode 100644
index 000000000..2e95b81c9
--- /dev/null
+++ b/data/odt-styles/mimetype
@@ -0,0 +1 @@
+application/vnd.oasis.opendocument.text \ No newline at end of file
diff --git a/data/odt-styles/settings.xml b/data/odt-styles/settings.xml
new file mode 100644
index 000000000..bb6998b79
--- /dev/null
+++ b/data/odt-styles/settings.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document-settings xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" office:version="1.1"><office:settings><config:config-item-set config:name="ooo:view-settings"><config:config-item config:name="ViewAreaTop" config:type="int">40640</config:config-item><config:config-item config:name="ViewAreaLeft" config:type="int">-1058</config:config-item><config:config-item config:name="ViewAreaWidth" config:type="int">25693</config:config-item><config:config-item config:name="ViewAreaHeight" config:type="int">15242</config:config-item><config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item><config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item><config:config-item-map-indexed config:name="Views"><config:config-item-map-entry><config:config-item config:name="ViewId" config:type="string">view2</config:config-item><config:config-item config:name="ViewLeft" config:type="int">8936</config:config-item><config:config-item config:name="ViewTop" config:type="int">54975</config:config-item><config:config-item config:name="VisibleLeft" config:type="int">-1058</config:config-item><config:config-item config:name="VisibleTop" config:type="int">40640</config:config-item><config:config-item config:name="VisibleRight" config:type="int">24633</config:config-item><config:config-item config:name="VisibleBottom" config:type="int">55880</config:config-item><config:config-item config:name="ZoomType" config:type="short">0</config:config-item><config:config-item config:name="ZoomFactor" config:type="short">100</config:config-item><config:config-item config:name="IsSelectedFrame" config:type="boolean">false</config:config-item></config:config-item-map-entry></config:config-item-map-indexed></config:config-item-set><config:config-item-set config:name="ooo:configuration-settings"><config:config-item config:name="AddParaTableSpacing" config:type="boolean">true</config:config-item><config:config-item config:name="PrintReversed" config:type="boolean">false</config:config-item><config:config-item config:name="OutlineLevelYieldsNumbering" config:type="boolean">false</config:config-item><config:config-item config:name="LinkUpdateMode" config:type="short">1</config:config-item><config:config-item config:name="PrintEmptyPages" config:type="boolean">true</config:config-item><config:config-item config:name="IgnoreFirstLineIndentInNumbering" config:type="boolean">false</config:config-item><config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item><config:config-item config:name="PrintSingleJobs" config:type="boolean">false</config:config-item><config:config-item config:name="UpdateFromTemplate" config:type="boolean">true</config:config-item><config:config-item config:name="PrintPaperFromSetup" config:type="boolean">false</config:config-item><config:config-item config:name="AddFrameOffsets" config:type="boolean">false</config:config-item><config:config-item config:name="PrintLeftPages" config:type="boolean">true</config:config-item><config:config-item config:name="RedlineProtectionKey" config:type="base64Binary"/><config:config-item config:name="PrintTables" config:type="boolean">true</config:config-item><config:config-item config:name="ChartAutoUpdate" config:type="boolean">true</config:config-item><config:config-item config:name="PrintControls" config:type="boolean">true</config:config-item><config:config-item config:name="PrinterSetup" config:type="base64Binary"/><config:config-item config:name="IgnoreTabsAndBlanksForLineCalculation" config:type="boolean">false</config:config-item><config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item><config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item><config:config-item config:name="AddParaSpacingToTableCells" config:type="boolean">true</config:config-item><config:config-item config:name="AddExternalLeading" config:type="boolean">true</config:config-item><config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item><config:config-item config:name="FieldAutoUpdate" config:type="boolean">true</config:config-item><config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item><config:config-item config:name="SaveGlobalDocumentLinks" config:type="boolean">false</config:config-item><config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item><config:config-item config:name="AlignTabStopPosition" config:type="boolean">true</config:config-item><config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item><config:config-item config:name="CurrentDatabaseDataSource" config:type="string"/><config:config-item config:name="DoNotCaptureDrawObjsOnPage" config:type="boolean">false</config:config-item><config:config-item config:name="TableRowKeep" config:type="boolean">false</config:config-item><config:config-item config:name="PrinterName" config:type="string"/><config:config-item config:name="PrintFaxName" config:type="string"/><config:config-item config:name="ConsiderTextWrapOnObjPos" config:type="boolean">false</config:config-item><config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item><config:config-item config:name="PrintRightPages" config:type="boolean">true</config:config-item><config:config-item config:name="IsLabelDocument" config:type="boolean">false</config:config-item><config:config-item config:name="UseFormerLineSpacing" config:type="boolean">false</config:config-item><config:config-item config:name="AddParaTableSpacingAtStart" config:type="boolean">true</config:config-item><config:config-item config:name="UseFormerTextWrapping" config:type="boolean">false</config:config-item><config:config-item config:name="DoNotResetParaAttrsForNumFont" config:type="boolean">false</config:config-item><config:config-item config:name="PrintProspect" config:type="boolean">false</config:config-item><config:config-item config:name="PrintGraphics" config:type="boolean">true</config:config-item><config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item><config:config-item config:name="CurrentDatabaseCommandType" config:type="int">0</config:config-item><config:config-item config:name="DoNotJustifyLinesWithManualBreak" config:type="boolean">false</config:config-item><config:config-item config:name="UseFormerObjectPositioning" config:type="boolean">false</config:config-item><config:config-item config:name="PrinterIndependentLayout" config:type="string">high-resolution</config:config-item><config:config-item config:name="UseOldNumbering" config:type="boolean">false</config:config-item><config:config-item config:name="PrintPageBackground" config:type="boolean">true</config:config-item><config:config-item config:name="CurrentDatabaseCommand" config:type="string"/><config:config-item config:name="PrintDrawings" config:type="boolean">true</config:config-item><config:config-item config:name="PrintBlackFonts" config:type="boolean">false</config:config-item><config:config-item config:name="UnxForceZeroExtLeading" config:type="boolean">false</config:config-item></config:config-item-set></office:settings></office:document-settings> \ No newline at end of file
diff --git a/data/odt-styles/styles.xml b/data/odt-styles/styles.xml
new file mode 100644
index 000000000..df9a15634
--- /dev/null
+++ b/data/odt-styles/styles.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document-styles xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" office:version="1.1"><office:font-face-decls><style:font-face style:name="StarSymbol" svg:font-family="StarSymbol"/><style:font-face style:name="Tahoma1" svg:font-family="Tahoma"/><style:font-face style:name="Courier New" svg:font-family="&apos;Courier New&apos;" style:font-family-generic="modern" style:font-pitch="fixed"/><style:font-face style:name="Times New Roman" svg:font-family="&apos;Times New Roman&apos;" style:font-family-generic="roman" style:font-pitch="variable"/><style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable"/><style:font-face style:name="Lucida Sans Unicode" svg:font-family="&apos;Lucida Sans Unicode&apos;" style:font-family-generic="system" style:font-pitch="variable"/><style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-family-generic="system" style:font-pitch="variable"/></office:font-face-decls><office:styles><style:default-style style:family="graphic"><style:graphic-properties draw:shadow-offset-x="0.1181in" draw:shadow-offset-y="0.1181in" draw:start-line-spacing-horizontal="0.1114in" draw:start-line-spacing-vertical="0.1114in" draw:end-line-spacing-horizontal="0.1114in" draw:end-line-spacing-vertical="0.1114in" style:flow-with-text="false"/><style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"><style:tab-stops/></style:paragraph-properties><style:text-properties style:use-window-font-color="true" fo:font-size="12pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-size-asian="12pt" style:language-asian="zxx" style:country-asian="none" style:font-size-complex="12pt" style:language-complex="zxx" style:country-complex="none"/></style:default-style><style:default-style style:family="paragraph"><style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="0.4925in" style:writing-mode="page"/><style:text-properties style:use-window-font-color="true" style:font-name="Times New Roman" fo:font-size="12pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="Lucida Sans Unicode" style:font-size-asian="12pt" style:language-asian="zxx" style:country-asian="none" style:font-name-complex="Tahoma" style:font-size-complex="12pt" style:language-complex="zxx" style:country-complex="none" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2"/></style:default-style><style:default-style style:family="table"><style:table-properties table:border-model="collapsing"/></style:default-style><style:default-style style:family="table-row"><style:table-row-properties fo:keep-together="auto"/></style:default-style><style:style style:name="Standard" style:family="paragraph" style:class="text"/><style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text"><style:paragraph-properties fo:margin-top="0.1665in" fo:margin-bottom="0.0835in" fo:keep-with-next="always"/><style:text-properties style:font-name="Arial" fo:font-size="14pt" style:font-name-asian="Lucida Sans Unicode" style:font-size-asian="14pt" style:font-name-complex="Tahoma" style:font-size-complex="14pt"/></style:style><style:style style:name="Text_20_body" style:display-name="Text body" style:family="paragraph" style:parent-style-name="Standard" style:class="text"><style:paragraph-properties fo:margin-top="0.0598in" fo:margin-bottom="0.0598in"/></style:style><style:style style:name="List" style:family="paragraph" style:parent-style-name="Text_20_body" style:class="list"><style:text-properties style:font-name-complex="Tahoma1"/></style:style><style:style style:name="Caption" style:family="paragraph" style:parent-style-name="Standard" style:class="extra"><style:paragraph-properties fo:margin-top="0.0835in" fo:margin-bottom="0.0835in" text:number-lines="false" text:line-number="0"/><style:text-properties fo:font-size="12pt" fo:font-style="italic" style:font-size-asian="12pt" style:font-style-asian="italic" style:font-name-complex="Tahoma1" style:font-size-complex="12pt" style:font-style-complex="italic"/></style:style><style:style style:name="Index" style:family="paragraph" style:parent-style-name="Standard" style:class="index"><style:paragraph-properties text:number-lines="false" text:line-number="0"/><style:text-properties style:font-name-complex="Tahoma1"/></style:style><style:style style:name="Heading_20_1" style:display-name="Heading 1" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:class="text" style:default-outline-level="1"><style:text-properties fo:font-size="115%" fo:font-weight="bold" style:font-size-asian="115%" style:font-weight-asian="bold" style:font-size-complex="115%" style:font-weight-complex="bold"/></style:style><style:style style:name="Heading_20_2" style:display-name="Heading 2" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:class="text" style:default-outline-level="2"><style:text-properties fo:font-size="14pt" fo:font-style="italic" fo:font-weight="bold" style:font-size-asian="14pt" style:font-style-asian="italic" style:font-weight-asian="bold" style:font-size-complex="14pt" style:font-style-complex="italic" style:font-weight-complex="bold"/></style:style><style:style style:name="Heading_20_3" style:display-name="Heading 3" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:class="text" style:default-outline-level="3"><style:text-properties fo:font-size="14pt" fo:font-weight="bold" style:font-size-asian="14pt" style:font-weight-asian="bold" style:font-size-complex="14pt" style:font-weight-complex="bold"/></style:style><style:style style:name="Heading_20_4" style:display-name="Heading 4" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:class="text" style:default-outline-level="4"><style:text-properties fo:font-size="85%" fo:font-style="italic" fo:font-weight="bold" style:font-size-asian="85%" style:font-style-asian="italic" style:font-weight-asian="bold" style:font-size-complex="85%" style:font-style-complex="italic" style:font-weight-complex="bold"/></style:style><style:style style:name="Heading_20_5" style:display-name="Heading 5" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:class="text" style:default-outline-level="5"><style:text-properties fo:font-size="85%" fo:font-weight="bold" style:font-size-asian="85%" style:font-weight-asian="bold" style:font-size-complex="85%" style:font-weight-complex="bold"/></style:style><style:style style:name="Heading_20_6" style:display-name="Heading 6" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:class="text" style:default-outline-level="6"><style:text-properties fo:font-size="75%" fo:font-weight="bold" style:font-size-asian="75%" style:font-weight-asian="bold" style:font-size-complex="75%" style:font-weight-complex="bold"/></style:style><style:style style:name="Quotations" style:family="paragraph" style:parent-style-name="Standard" style:class="html"><style:paragraph-properties fo:margin-left="0.3937in" fo:margin-right="0.3937in" fo:margin-top="0.1in" fo:margin-bottom="0.1in" fo:text-indent="0in" style:auto-text-indent="false"/></style:style><style:style style:name="Preformatted_20_Text" style:display-name="Preformatted Text" style:family="paragraph" style:parent-style-name="Standard" style:class="html"><style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in"/><style:text-properties style:font-name="Courier New" fo:font-size="10pt" style:font-name-asian="Courier New" style:font-size-asian="10pt" style:font-name-complex="Courier New" style:font-size-complex="10pt"/></style:style><style:style style:name="Definition_20_Term" style:display-name="Definition Term" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Definition_20_Definition"><style:paragraph-properties fo:margin-top="0.0598in" fo:margin-bottom="0.0598in"/></style:style><style:style style:name="Definition_20_Definition" style:display-name="Definition Definition" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body"><style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false"/></style:style><style:style style:name="Table_20_Contents" style:display-name="Table Contents" style:family="paragraph" style:parent-style-name="Standard" style:class="extra"><style:paragraph-properties fo:margin-left="0.0299in" fo:margin-right="0.0299in" fo:text-indent="0in" style:auto-text-indent="false" text:number-lines="false" text:line-number="0"/></style:style><style:style style:name="Table_20_Heading" style:display-name="Table Heading" style:family="paragraph" style:parent-style-name="Table_20_Contents" style:class="extra"><style:paragraph-properties fo:margin-left="0.0299in" fo:margin-right="0.0299in" fo:text-align="start" style:justify-single-word="false" fo:text-indent="0in" style:auto-text-indent="false" style:shadow="none" text:number-lines="false" text:line-number="0"/><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/></style:style><style:style style:name="Footnote" style:family="paragraph" style:parent-style-name="Standard" style:class="extra"><style:paragraph-properties fo:margin-left="0.1965in" fo:margin-right="0in" fo:text-indent="-0.1965in" style:auto-text-indent="false" text:number-lines="false" text:line-number="0"/><style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-size-complex="10pt"/></style:style><style:style style:name="Footer" style:family="paragraph" style:parent-style-name="Standard" style:class="extra"><style:paragraph-properties text:number-lines="false" text:line-number="0"><style:tab-stops><style:tab-stop style:position="3.25in" style:type="center"/><style:tab-stop style:position="6.5in" style:type="right"/></style:tab-stops></style:paragraph-properties></style:style><style:style style:name="Definition_20_Term_20_Tight" style:display-name="Definition Term Tight" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Definition_20_Definition_20_Tight"><style:paragraph-properties fo:margin-top="0.0799in" fo:margin-bottom="0.0799in"/></style:style><style:style style:name="Definition_20_Definition_20_Tight" style:display-name="Definition Definition Tight" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:margin-top="0in" fo:margin-bottom="0in" fo:text-indent="0in" style:auto-text-indent="false"/></style:style><style:style style:name="Date" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body"><style:text-properties fo:font-style="italic"/></style:style><style:style style:name="Author" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Date" style:master-page-name=""><style:paragraph-properties style:page-number="auto"/><style:text-properties fo:font-style="italic"/></style:style><style:style style:name="Numbering_20_Symbols" style:display-name="Numbering Symbols" style:family="text"/><style:style style:name="Bullet_20_Symbols" style:display-name="Bullet Symbols" style:family="text"><style:text-properties style:font-name="StarSymbol" fo:font-size="9pt" style:font-name-asian="StarSymbol" style:font-size-asian="9pt" style:font-name-complex="StarSymbol" style:font-size-complex="9pt"/></style:style><style:style style:name="Emphasis" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic"/></style:style><style:style style:name="Strong_20_Emphasis" style:display-name="Strong Emphasis" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/></style:style><style:style style:name="Strikeout" style:family="text"><style:text-properties style:text-line-through-style="solid"/></style:style><style:style style:name="Superscript" style:family="text"><style:text-properties style:text-position="super 58%"/></style:style><style:style style:name="Subscript" style:family="text"><style:text-properties style:text-position="sub 58%"/></style:style><style:style style:name="Citation" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic"/></style:style><style:style style:name="Teletype" style:family="text"><style:text-properties style:font-name="Courier New" style:font-name-asian="Courier New" style:font-name-complex="Courier New"/></style:style><style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text"><style:text-properties fo:color="#000080" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color"/></style:style><style:style style:name="Footnote_20_Symbol" style:display-name="Footnote Symbol" style:family="text"/><style:style style:name="Footnote_20_anchor" style:display-name="Footnote anchor" style:family="text"><style:text-properties style:text-position="super 58%"/></style:style><style:style style:name="Definition" style:family="text"/><text:outline-style><text:outline-level-style text:level="1" style:num-format=""><style:list-level-properties text:min-label-distance="0.15in"/></text:outline-level-style><text:outline-level-style text:level="2" style:num-format=""><style:list-level-properties text:min-label-distance="0.15in"/></text:outline-level-style><text:outline-level-style text:level="3" style:num-format=""><style:list-level-properties text:min-label-distance="0.15in"/></text:outline-level-style><text:outline-level-style text:level="4" style:num-format=""><style:list-level-properties text:min-label-distance="0.15in"/></text:outline-level-style><text:outline-level-style text:level="5" style:num-format=""><style:list-level-properties text:min-label-distance="0.15in"/></text:outline-level-style><text:outline-level-style text:level="6" style:num-format=""><style:list-level-properties text:min-label-distance="0.15in"/></text:outline-level-style><text:outline-level-style text:level="7" style:num-format=""><style:list-level-properties text:min-label-distance="0.15in"/></text:outline-level-style><text:outline-level-style text:level="8" style:num-format=""><style:list-level-properties text:min-label-distance="0.15in"/></text:outline-level-style><text:outline-level-style text:level="9" style:num-format=""><style:list-level-properties text:min-label-distance="0.15in"/></text:outline-level-style><text:outline-level-style text:level="10" style:num-format=""><style:list-level-properties text:min-label-distance="0.15in"/></text:outline-level-style></text:outline-style><text:list-style style:name="Numbering_20_1" style:display-name="Numbering 1"><text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="0.1972in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="0.3937in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="0.5909in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="5" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="0.7874in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="6" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="0.9846in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="7" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="1.1815in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="8" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="1.3787in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="9" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="1.5752in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="10" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="1.7724in" text:min-label-width="0.1965in"/></text:list-level-style-number></text:list-style><text:list-style style:name="Numbering_20_2" style:display-name="Numbering 2"><text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1"><style:list-level-properties text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="2"><style:list-level-properties text:space-before="0.1965in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="3"><style:list-level-properties text:space-before="0.3929in" text:min-label-width="0.3937in"/></text:list-level-style-number><text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="4"><style:list-level-properties text:space-before="0.7866in" text:min-label-width="0.4925in"/></text:list-level-style-number><text:list-level-style-number text:level="5" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="5"><style:list-level-properties text:space-before="1.2791in" text:min-label-width="0.5902in"/></text:list-level-style-number><text:list-level-style-number text:level="6" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="6"><style:list-level-properties text:space-before="1.8693in" text:min-label-width="0.7091in"/></text:list-level-style-number><text:list-level-style-number text:level="7" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="7"><style:list-level-properties text:space-before="2.5783in" text:min-label-width="0.9055in"/></text:list-level-style-number><text:list-level-style-number text:level="8" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="8"><style:list-level-properties text:space-before="3.4839in" text:min-label-width="1.0236in"/></text:list-level-style-number><text:list-level-style-number text:level="9" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="9"><style:list-level-properties text:space-before="4.5075in" text:min-label-width="1.1028in"/></text:list-level-style-number><text:list-level-style-number text:level="10" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="10"><style:list-level-properties text:space-before="5.6102in" text:min-label-width="1.2209in"/></text:list-level-style-number></text:list-style><text:list-style style:name="Numbering_20_3" style:display-name="Numbering 3"><text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1"><style:list-level-properties text:min-label-width="1.1811in"/></text:list-level-style-number><text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="2"><style:list-level-properties text:space-before="1.1815in" text:min-label-width="1.1811in"/></text:list-level-style-number><text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="3"><style:list-level-properties text:space-before="2.3626in" text:min-label-width="1.1811in"/></text:list-level-style-number><text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="4"><style:list-level-properties text:space-before="3.5441in" text:min-label-width="1.1811in"/></text:list-level-style-number><text:list-level-style-number text:level="5" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="5"><style:list-level-properties text:space-before="4.7252in" text:min-label-width="1.1811in"/></text:list-level-style-number><text:list-level-style-number text:level="6" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="6"><style:list-level-properties text:space-before="5.9063in" text:min-label-width="1.1811in"/></text:list-level-style-number><text:list-level-style-number text:level="7" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="7"><style:list-level-properties text:space-before="7.0878in" text:min-label-width="1.1811in"/></text:list-level-style-number><text:list-level-style-number text:level="8" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="8"><style:list-level-properties text:space-before="8.2689in" text:min-label-width="1.1811in"/></text:list-level-style-number><text:list-level-style-number text:level="9" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="9"><style:list-level-properties text:space-before="9.45in" text:min-label-width="1.1811in"/></text:list-level-style-number><text:list-level-style-number text:level="10" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="10"><style:list-level-properties text:space-before="10.6315in" text:min-label-width="1.1811in"/></text:list-level-style-number></text:list-style><text:list-style style:name="Numbering_20_4" style:display-name="Numbering 4"><text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="I"><style:list-level-properties text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="I" text:start-value="2"><style:list-level-properties text:space-before="0.1972in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="I" text:start-value="3"><style:list-level-properties text:space-before="0.3937in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="I" text:start-value="4"><style:list-level-properties text:space-before="0.5909in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="5" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="I" text:start-value="5"><style:list-level-properties text:space-before="0.7874in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="6" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="I" text:start-value="6"><style:list-level-properties text:space-before="0.9846in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="7" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="I" text:start-value="7"><style:list-level-properties text:space-before="1.1815in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="8" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="I" text:start-value="8"><style:list-level-properties text:space-before="1.3787in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="9" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="I" text:start-value="9"><style:list-level-properties text:space-before="1.5752in" text:min-label-width="0.1965in"/></text:list-level-style-number><text:list-level-style-number text:level="10" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="I" text:start-value="10"><style:list-level-properties text:space-before="1.7724in" text:min-label-width="0.1965in"/></text:list-level-style-number></text:list-style><text:list-style style:name="Numbering_20_5" style:display-name="Numbering 5"><text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:min-label-width="0.1575in"/></text:list-level-style-number><text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1" text:start-value="2" text:display-levels="2"><style:list-level-properties text:space-before="0.1772in" text:min-label-width="0.2563in"/></text:list-level-style-number><text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-suffix=")" style:num-format="a" text:start-value="3"><style:list-level-properties text:space-before="0.4331in" text:min-label-width="0.1772in"/></text:list-level-style-number><text:list-level-style-bullet text:level="4" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="0.6319in" text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="5" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="0.7874in" text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="6" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="0.9429in" text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="7" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="1.0988in" text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="8" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="1.2543in" text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="9" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="1.4098in" text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="10" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="1.5654in" text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet></text:list-style><text:list-style style:name="List_20_1" style:display-name="List 1"><text:list-level-style-bullet text:level="1" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="2" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="0.1579in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="3" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="0.3146in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="4" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="0.4724in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="5" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="0.6299in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="6" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="0.7878in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="7" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="0.9445in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="8" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="1.1024in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="9" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="1.2598in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="10" text:style-name="Numbering_20_Symbols" text:bullet-char="•"><style:list-level-properties text:space-before="1.4177in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet></text:list-style><text:list-style style:name="List_20_2" style:display-name="List 2"><text:list-level-style-bullet text:level="1" text:style-name="Numbering_20_Symbols" text:bullet-char="–"><style:list-level-properties text:min-label-width="0.1181in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="2" text:style-name="Numbering_20_Symbols" text:bullet-char="–"><style:list-level-properties text:space-before="0.1181in" text:min-label-width="0.1181in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="3" text:style-name="Numbering_20_Symbols" text:bullet-char="–"><style:list-level-properties text:space-before="0.2362in" text:min-label-width="0.1181in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="4" text:style-name="Numbering_20_Symbols" text:bullet-char="–"><style:list-level-properties text:space-before="0.3539in" text:min-label-width="0.1181in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="5" text:style-name="Numbering_20_Symbols" text:bullet-char="–"><style:list-level-properties text:space-before="0.472in" text:min-label-width="0.1181in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="6" text:style-name="Numbering_20_Symbols" text:bullet-char="–"><style:list-level-properties text:space-before="0.5902in" text:min-label-width="0.1181in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="7" text:style-name="Numbering_20_Symbols" text:bullet-char="–"><style:list-level-properties text:space-before="0.7091in" text:min-label-width="0.1181in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="8" text:style-name="Numbering_20_Symbols" text:bullet-char="–"><style:list-level-properties text:space-before="0.8272in" text:min-label-width="0.1181in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="9" text:style-name="Numbering_20_Symbols" text:bullet-char="–"><style:list-level-properties text:space-before="0.9453in" text:min-label-width="0.1181in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="10" text:style-name="Numbering_20_Symbols" text:bullet-char="–"><style:list-level-properties text:space-before="1.063in" text:min-label-width="0.1181in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet></text:list-style><text:list-style style:name="List_20_3" style:display-name="List 3"><text:list-level-style-bullet text:level="1" text:style-name="Numbering_20_Symbols" text:bullet-char="☑"><style:list-level-properties text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="2" text:style-name="Numbering_20_Symbols" text:bullet-char="□"><style:list-level-properties text:space-before="0.1555in" text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="3" text:style-name="Numbering_20_Symbols" text:bullet-char="☑"><style:list-level-properties text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="4" text:style-name="Numbering_20_Symbols" text:bullet-char="□"><style:list-level-properties text:space-before="0.1555in" text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="5" text:style-name="Numbering_20_Symbols" text:bullet-char="☑"><style:list-level-properties text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="6" text:style-name="Numbering_20_Symbols" text:bullet-char="□"><style:list-level-properties text:space-before="0.1555in" text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="7" text:style-name="Numbering_20_Symbols" text:bullet-char="☑"><style:list-level-properties text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="8" text:style-name="Numbering_20_Symbols" text:bullet-char="□"><style:list-level-properties text:space-before="0.1555in" text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="9" text:style-name="Numbering_20_Symbols" text:bullet-char="☑"><style:list-level-properties text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="10" text:style-name="Numbering_20_Symbols" text:bullet-char="□"><style:list-level-properties text:space-before="0.1555in" text:min-label-width="0.1555in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet></text:list-style><text:list-style style:name="List_20_4" style:display-name="List 4"><text:list-level-style-bullet text:level="1" text:style-name="Numbering_20_Symbols" text:bullet-char="➢"><style:list-level-properties text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="2" text:style-name="Numbering_20_Symbols" text:bullet-char=""><style:list-level-properties text:space-before="0.1579in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="3" text:style-name="Numbering_20_Symbols" text:bullet-char=""><style:list-level-properties text:space-before="0.3146in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="4" text:style-name="Numbering_20_Symbols" text:bullet-char=""><style:list-level-properties text:space-before="0.4724in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="5" text:style-name="Numbering_20_Symbols" text:bullet-char=""><style:list-level-properties text:space-before="0.6299in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="6" text:style-name="Numbering_20_Symbols" text:bullet-char=""><style:list-level-properties text:space-before="0.7878in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="7" text:style-name="Numbering_20_Symbols" text:bullet-char=""><style:list-level-properties text:space-before="0.9445in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="8" text:style-name="Numbering_20_Symbols" text:bullet-char=""><style:list-level-properties text:space-before="1.1024in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="9" text:style-name="Numbering_20_Symbols" text:bullet-char=""><style:list-level-properties text:space-before="1.2598in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="10" text:style-name="Numbering_20_Symbols" text:bullet-char=""><style:list-level-properties text:space-before="1.4177in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet></text:list-style><text:list-style style:name="List_20_5" style:display-name="List 5"><text:list-level-style-bullet text:level="1" text:style-name="Numbering_20_Symbols" text:bullet-char="✗"><style:list-level-properties text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="2" text:style-name="Numbering_20_Symbols" text:bullet-char="✗"><style:list-level-properties text:space-before="0.1579in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="3" text:style-name="Numbering_20_Symbols" text:bullet-char="✗"><style:list-level-properties text:space-before="0.3146in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="4" text:style-name="Numbering_20_Symbols" text:bullet-char="✗"><style:list-level-properties text:space-before="0.4724in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="5" text:style-name="Numbering_20_Symbols" text:bullet-char="✗"><style:list-level-properties text:space-before="0.6299in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="6" text:style-name="Numbering_20_Symbols" text:bullet-char="✗"><style:list-level-properties text:space-before="0.7878in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="7" text:style-name="Numbering_20_Symbols" text:bullet-char="✗"><style:list-level-properties text:space-before="0.9445in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="8" text:style-name="Numbering_20_Symbols" text:bullet-char="✗"><style:list-level-properties text:space-before="1.1024in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="9" text:style-name="Numbering_20_Symbols" text:bullet-char="✗"><style:list-level-properties text:space-before="1.2598in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="10" text:style-name="Numbering_20_Symbols" text:bullet-char="✗"><style:list-level-properties text:space-before="1.4177in" text:min-label-width="0.1575in"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet></text:list-style><text:notes-configuration text:note-class="footnote" text:citation-style-name="Footnote_20_Symbol" text:citation-body-style-name="Footnote_20_anchor" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/><text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/><text:linenumbering-configuration text:number-lines="false" text:offset="0.1965in" style:num-format="1" text:number-position="left" text:increment="5"/><style:style style:name="Horizontal_20_Line" style:display-name="Horizontal Line" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="html"><style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0.1965in" style:border-line-width-bottom="0.0008in 0.0138in 0.0008in" fo:padding="0in" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.0154in double #808080" text:number-lines="false" text:line-number="0" style:join-border="false"/><style:text-properties fo:font-size="6pt" style:font-size-asian="6pt" style:font-size-complex="6pt"/></style:style></office:styles><office:automatic-styles><style:style style:name="P1" style:family="paragraph" style:parent-style-name="Footer"><style:paragraph-properties fo:text-align="center" style:justify-single-word="false"/></style:style><style:page-layout style:name="pm1"><style:page-layout-properties fo:page-width="8.5in" fo:page-height="11in" style:num-format="1" style:print-orientation="portrait" fo:margin-top="1in" fo:margin-bottom="1in" fo:margin-left="1in" fo:margin-right="1in" style:writing-mode="lr-tb" style:footnote-max-height="0in"><style:footnote-sep style:width="0.0071in" style:distance-before-sep="0.0398in" style:distance-after-sep="0.0398in" style:adjustment="left" style:rel-width="25%" style:color="#000000"/></style:page-layout-properties><style:header-style/><style:footer-style><style:header-footer-properties fo:min-height="0.4in" fo:margin-left="0in" fo:margin-right="0in" fo:margin-top="0.2in" style:dynamic-spacing="false"/></style:footer-style></style:page-layout></office:automatic-styles><office:master-styles><style:master-page style:name="Standard" style:page-layout-name="pm1"><style:footer><text:p text:style-name="P1"><text:page-number text:select-page="current">1</text:page-number> </text:p></style:footer></style:master-page></office:master-styles></office:document-styles> \ No newline at end of file
diff --git a/data/ui/default/framing.css b/data/ui/default/framing.css
new file mode 100644
index 000000000..14d8509e9
--- /dev/null
+++ b/data/ui/default/framing.css
@@ -0,0 +1,23 @@
+/* The following styles size, place, and layer the slide components.
+ Edit these if you want to change the overall slide layout.
+ The commented lines can be uncommented (and modified, if necessary)
+ to help you with the rearrangement process. */
+
+/* target = 1024x768 */
+
+div#header, div#footer, .slide {width: 100%; top: 0; left: 0;}
+div#header {top: 0; height: 3em; z-index: 1;}
+div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;}
+.slide {top: 0; width: 92%; padding: 3.5em 4% 4%; z-index: 2; list-style: none;}
+div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0;}
+#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em; z-index: 10;}
+html>body #currentSlide {position: fixed;}
+
+/*
+div#header {background: #FCC;}
+div#footer {background: #CCF;}
+div#controls {background: #BBD;}
+div#currentSlide {background: #FFC;}
+*/
diff --git a/data/ui/default/opera.css b/data/ui/default/opera.css
new file mode 100644
index 000000000..9e9d2a3c5
--- /dev/null
+++ b/data/ui/default/opera.css
@@ -0,0 +1,7 @@
+/* DO NOT CHANGE THESE unless you really want to break Opera Show */
+.slide {
+ visibility: visible !important;
+ position: static !important;
+ page-break-before: always;
+}
+#slide0 {page-break-before: avoid;}
diff --git a/data/ui/default/outline.css b/data/ui/default/outline.css
new file mode 100644
index 000000000..62db519ed
--- /dev/null
+++ b/data/ui/default/outline.css
@@ -0,0 +1,15 @@
+/* don't change this unless you want the layout stuff to show up in the outline view! */
+
+.layout div, #footer *, #controlForm * {display: none;}
+#footer, #controls, #controlForm, #navLinks, #toggle {
+ display: block; visibility: visible; margin: 0; padding: 0;}
+#toggle {float: right; padding: 0.5em;}
+html>body #toggle {position: fixed; top: 0; right: 0;}
+
+/* making the outline look pretty-ish */
+
+#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;}
+#slide0 h1 {padding-top: 1.5em;}
+.slide h1 {margin: 1.5em 0 0; padding-top: 0.25em;
+ border-top: 1px solid #888; border-bottom: 1px solid #AAA;}
+#toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;}
diff --git a/data/ui/default/pretty.css b/data/ui/default/pretty.css
new file mode 100644
index 000000000..a87b24375
--- /dev/null
+++ b/data/ui/default/pretty.css
@@ -0,0 +1,86 @@
+/* Following are the presentation styles -- edit away! */
+
+body {background: #FFF url(bodybg.gif) -16px 0 no-repeat; color: #000; font-size: 2em;}
+:link, :visited {text-decoration: none; color: #00C;}
+#controls :active {color: #88A !important;}
+#controls :focus {outline: 1px dotted #227;}
+h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;}
+ul, pre {margin: 0; line-height: 1em;}
+html, body {margin: 0; padding: 0;}
+
+blockquote, q {font-style: italic;}
+blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em; text-align: center; font-size: 1em;}
+blockquote p {margin: 0;}
+blockquote i {font-style: normal;}
+blockquote b {display: block; margin-top: 0.5em; font-weight: normal; font-size: smaller; font-style: normal;}
+blockquote b i {font-style: italic;}
+
+kbd {font-weight: bold; font-size: 1em;}
+sup {font-size: smaller; line-height: 1px;}
+
+.slide code {padding: 2px 0.25em; font-weight: bold; color: #533;}
+.slide code.bad, code del {color: red;}
+.slide code.old {color: silver;}
+.slide pre {padding: 0; margin: 0.25em 0 0.5em 0.5em; color: #533; font-size: 90%;}
+.slide pre code {display: block;}
+.slide ul {margin-left: 5%; margin-right: 7%; list-style: disc;}
+.slide li {margin-top: 0.75em; margin-right: 0;}
+.slide ul ul {line-height: 1;}
+.slide ul ul li {margin: .2em; font-size: 85%; list-style: square;}
+.slide img.leader {display: block; margin: 0 auto;}
+
+div#header, div#footer {background: #005; color: #AAB;
+ font-family: Verdana, Helvetica, sans-serif;}
+div#header {background: #005 url(bodybg.gif) -16px 0 no-repeat;
+ line-height: 1px;}
+div#footer {font-size: 0.5em; font-weight: bold; padding: 1em 0;}
+#footer h1, #footer h2 {display: block; padding: 0 1em;}
+#footer h2 {font-style: italic;}
+
+div.long {font-size: 0.75em;}
+.slide h1 {position: absolute; top: 0.7em; left: 87px; z-index: 1;
+ margin: 0; padding: 0.3em 0 0 50px; white-space: nowrap;
+ font: bold 150%/1em Helvetica, sans-serif; text-transform: capitalize;
+ color: #DDE; background: #005;}
+.slide h3 {font-size: 130%;}
+h1 abbr {font-variant: small-caps;}
+
+div#controls {position: absolute; left: 50%; bottom: 0;
+ width: 50%;
+ text-align: right; font: bold 0.9em Verdana, Helvetica, sans-serif;}
+html>body div#controls {position: fixed; padding: 0 0 1em 0;
+ top: auto;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0; padding: 0;}
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+ background: #005; border: none; color: #779;
+ cursor: pointer;}
+#controls #navList {height: 1em;}
+#controls #navList #jumplist {position: absolute; bottom: 0; right: 0; background: #DDD; color: #227;}
+
+#currentSlide {text-align: center; font-size: 0.5em; color: #449;}
+
+#slide0 {padding-top: 3.5em; font-size: 90%;}
+#slide0 h1 {position: static; margin: 1em 0 0; padding: 0;
+ font: bold 2em Helvetica, sans-serif; white-space: normal;
+ color: #000; background: transparent;}
+#slide0 h2 {font: bold italic 1em Helvetica, sans-serif; margin: 0.25em;}
+#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;}
+#slide0 h4 {margin-top: 0; font-size: 1em;}
+
+ul.urls {list-style: none; display: inline; margin: 0;}
+.urls li {display: inline; margin: 0;}
+.note {display: none;}
+.external {border-bottom: 1px dotted gray;}
+html>body .external {border-bottom: none;}
+.external:after {content: " \274F"; font-size: smaller; color: #77B;}
+
+.incremental, .incremental *, .incremental *:after {color: #DDE; visibility: visible;}
+img.incremental {visibility: hidden;}
+.slide .current {color: #B02;}
+
+
+/* diagnostics
+
+li:after {content: " [" attr(class) "]"; color: #F88;}
+*/
diff --git a/data/ui/default/print.css b/data/ui/default/print.css
new file mode 100644
index 000000000..4a3554ddd
--- /dev/null
+++ b/data/ui/default/print.css
@@ -0,0 +1,24 @@
+/* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */
+.slide, ul {page-break-inside: avoid; visibility: visible !important;}
+h1 {page-break-after: avoid;}
+
+body {font-size: 12pt; background: white;}
+* {color: black;}
+
+#slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;}
+#slide0 h3 {margin: 0; padding: 0;}
+#slide0 h4 {margin: 0 0 0.5em; padding: 0;}
+#slide0 {margin-bottom: 3em;}
+
+h1 {border-top: 2pt solid gray; border-bottom: 1px dotted silver;}
+.extra {background: transparent !important;}
+div.extra, pre.extra, .example {font-size: 10pt; color: #333;}
+ul.extra a {font-weight: bold;}
+p.example {display: none;}
+
+#header {display: none;}
+#footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style: italic;}
+#footer h2, #controls {display: none;}
+
+/* The following rule keeps the layout stuff out of print. Remove at your own risk! */
+.layout, .layout * {display: none !important;}
diff --git a/data/ui/default/s5-core.css b/data/ui/default/s5-core.css
new file mode 100644
index 000000000..86444e041
--- /dev/null
+++ b/data/ui/default/s5-core.css
@@ -0,0 +1,9 @@
+/* Do not edit or override these styles! The system will likely break if you do. */
+
+div#header, div#footer, div#controls, .slide {position: absolute;}
+html>body div#header, html>body div#footer,
+ html>body div#controls, html>body .slide {position: fixed;}
+.handout {display: none;}
+.layout {display: block;}
+.slide, .hideme, .incremental {visibility: hidden;}
+#slide0 {visibility: visible;}
diff --git a/data/ui/default/slides.js.comment b/data/ui/default/slides.js.comment
new file mode 100644
index 000000000..489b276a2
--- /dev/null
+++ b/data/ui/default/slides.js.comment
@@ -0,0 +1,4 @@
+// S5 v1.1 slides.js -- released into the Public Domain
+//
+// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information
+// about all the wonderful and talented contributors to this code!
diff --git a/data/ui/default/slides.js.packed b/data/ui/default/slides.js.packed
new file mode 100644
index 000000000..47b95e53f
--- /dev/null
+++ b/data/ui/default/slides.js.packed
@@ -0,0 +1,74 @@
+var undef;var slideCSS='';var snum=0;var smax=1;var incpos=0;var number=undef;var s5mode=true;var defaultView='slideshow';var controlVis='visible';var isIE=navigator.appName=='Microsoft Internet Explorer'&&navigator.userAgent.indexOf('Opera')<1?1:0;var isOp=navigator.userAgent.indexOf('Opera')>-1?1:0;var isGe=navigator.userAgent.indexOf('Gecko')>-1&&navigator.userAgent.indexOf('Safari')<1?1:0;function hasClass(object,className){if(!object.className)return false;return(object.className.search('(^|\\s)'+className+'(\\s|$)')!=-1);}
+function hasValue(object,value){if(!object)return false;return(object.search('(^|\\s)'+value+'(\\s|$)')!=-1);}
+function removeClass(object,className){if(!object)return;object.className=object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'),RegExp.$1+RegExp.$2);}
+function addClass(object,className){if(!object||hasClass(object,className))return;if(object.className){object.className+=' '+className;}else{object.className=className;}}
+function GetElementsWithClassName(elementName,className){var allElements=document.getElementsByTagName(elementName);var elemColl=new Array();for(var i=0;i<allElements.length;i++){if(hasClass(allElements[i],className)){elemColl[elemColl.length]=allElements[i];}}
+return elemColl;}
+function isParentOrSelf(element,id){if(element==null||element.nodeName=='BODY')return false;else if(element.id==id)return true;else return isParentOrSelf(element.parentNode,id);}
+function nodeValue(node){var result="";if(node.nodeType==1){var children=node.childNodes;for(var i=0;i<children.length;++i){result+=nodeValue(children[i]);}}
+else if(node.nodeType==3){result=node.nodeValue;}
+return(result);}
+function slideLabel(){var slideColl=GetElementsWithClassName('*','slide');var list=document.getElementById('jumplist');smax=slideColl.length;for(var n=0;n<smax;n++){var obj=slideColl[n];var did='slide'+n.toString();obj.setAttribute('id',did);if(isOp)continue;var otext='';var menu=obj.firstChild;if(!menu)continue;while(menu&&menu.nodeType==3){menu=menu.nextSibling;}
+if(!menu)continue;var menunodes=menu.childNodes;for(var o=0;o<menunodes.length;o++){otext+=nodeValue(menunodes[o]);}
+list.options[list.length]=new Option(n+' : '+otext,n);}}
+function currentSlide(){var cs;if(document.getElementById){cs=document.getElementById('currentSlide');}else{cs=document.currentSlide;}
+cs.innerHTML='<span id="csHere">'+snum+'<\/span> '+'<span id="csSep">\/<\/span> '+'<span id="csTotal">'+(smax-1)+'<\/span>';if(snum==0){cs.style.visibility='hidden';}else{cs.style.visibility='visible';}}
+function go(step){if(document.getElementById('slideProj').disabled||step==0)return;var jl=document.getElementById('jumplist');var cid='slide'+snum;var ce=document.getElementById(cid);if(incrementals[snum].length>0){for(var i=0;i<incrementals[snum].length;i++){removeClass(incrementals[snum][i],'current');removeClass(incrementals[snum][i],'incremental');}}
+if(step!='j'){snum+=step;lmax=smax-1;if(snum>lmax)snum=lmax;if(snum<0)snum=0;}else
+snum=parseInt(jl.value);var nid='slide'+snum;var ne=document.getElementById(nid);if(!ne){ne=document.getElementById('slide0');snum=0;}
+if(step<0){incpos=incrementals[snum].length}else{incpos=0;}
+if(incrementals[snum].length>0&&incpos==0){for(var i=0;i<incrementals[snum].length;i++){if(hasClass(incrementals[snum][i],'current'))
+incpos=i+1;else
+addClass(incrementals[snum][i],'incremental');}}
+if(incrementals[snum].length>0&&incpos>0)
+addClass(incrementals[snum][incpos-1],'current');ce.style.visibility='hidden';ne.style.visibility='visible';jl.selectedIndex=snum;currentSlide();number=0;}
+function goTo(target){if(target>=smax||target==snum)return;go(target-snum);}
+function subgo(step){if(step>0){removeClass(incrementals[snum][incpos-1],'current');removeClass(incrementals[snum][incpos],'incremental');addClass(incrementals[snum][incpos],'current');incpos++;}else{incpos--;removeClass(incrementals[snum][incpos],'current');addClass(incrementals[snum][incpos],'incremental');addClass(incrementals[snum][incpos-1],'current');}}
+function toggle(){var slideColl=GetElementsWithClassName('*','slide');var slides=document.getElementById('slideProj');var outline=document.getElementById('outlineStyle');if(!slides.disabled){slides.disabled=true;outline.disabled=false;s5mode=false;fontSize('1em');for(var n=0;n<smax;n++){var slide=slideColl[n];slide.style.visibility='visible';}}else{slides.disabled=false;outline.disabled=true;s5mode=true;fontScale();for(var n=0;n<smax;n++){var slide=slideColl[n];slide.style.visibility='hidden';}
+slideColl[snum].style.visibility='visible';}}
+function showHide(action){var obj=GetElementsWithClassName('*','hideme')[0];switch(action){case's':obj.style.visibility='visible';break;case'h':obj.style.visibility='hidden';break;case'k':if(obj.style.visibility!='visible'){obj.style.visibility='visible';}else{obj.style.visibility='hidden';}
+break;}}
+function keys(key){if(!key){key=event;key.which=key.keyCode;}
+if(key.which==84){toggle();return;}
+if(s5mode){switch(key.which){case 10:case 13:if(window.event&&isParentOrSelf(window.event.srcElement,'controls'))return;if(key.target&&isParentOrSelf(key.target,'controls'))return;if(number!=undef){goTo(number);break;}
+case 32:case 34:case 39:case 40:if(number!=undef){go(number);}else if(!incrementals[snum]||incpos>=incrementals[snum].length){go(1);}else{subgo(1);}
+break;case 33:case 37:case 38:if(number!=undef){go(-1*number);}else if(!incrementals[snum]||incpos<=0){go(-1);}else{subgo(-1);}
+break;case 36:goTo(0);break;case 35:goTo(smax-1);break;case 67:showHide('k');break;}
+if(key.which<48||key.which>57){number=undef;}else{if(window.event&&isParentOrSelf(window.event.srcElement,'controls'))return;if(key.target&&isParentOrSelf(key.target,'controls'))return;number=(((number!=undef)?number:0)*10)+(key.which-48);}}
+return false;}
+function clicker(e){number=undef;var target;if(window.event){target=window.event.srcElement;e=window.event;}else target=e.target;if(target.getAttribute('href')!=null||hasValue(target.rel,'external')||isParentOrSelf(target,'controls')||isParentOrSelf(target,'embed')||isParentOrSelf(target,'object'))return true;if(!e.which||e.which==1){if(!incrementals[snum]||incpos>=incrementals[snum].length){go(1);}else{subgo(1);}}}
+function findSlide(hash){var target=null;var slides=GetElementsWithClassName('*','slide');for(var i=0;i<slides.length;i++){var targetSlide=slides[i];if((targetSlide.name&&targetSlide.name==hash)||(targetSlide.id&&targetSlide.id==hash)){target=targetSlide;break;}}
+while(target!=null&&target.nodeName!='BODY'){if(hasClass(target,'slide')){return parseInt(target.id.slice(5));}
+target=target.parentNode;}
+return null;}
+function slideJump(){if(window.location.hash==null)return;var sregex=/^#slide(\d+)$/;var matches=sregex.exec(window.location.hash);var dest=null;if(matches!=null){dest=parseInt(matches[1]);}else{dest=findSlide(window.location.hash.slice(1));}
+if(dest!=null)
+go(dest-snum);}
+function fixLinks(){var thisUri=window.location.href;thisUri=thisUri.slice(0,thisUri.length-window.location.hash.length);var aelements=document.getElementsByTagName('A');for(var i=0;i<aelements.length;i++){var a=aelements[i].href;var slideID=a.match('\#slide[0-9]{1,2}');if((slideID)&&(slideID[0].slice(0,1)=='#')){var dest=findSlide(slideID[0].slice(1));if(dest!=null){if(aelements[i].addEventListener){aelements[i].addEventListener("click",new Function("e","if (document.getElementById('slideProj').disabled) return;"+"go("+dest+" - snum); "+"if (e.preventDefault) e.preventDefault();"),true);}else if(aelements[i].attachEvent){aelements[i].attachEvent("onclick",new Function("","if (document.getElementById('slideProj').disabled) return;"+"go("+dest+" - snum); "+"event.returnValue = false;"));}}}}}
+function externalLinks(){if(!document.getElementsByTagName)return;var anchors=document.getElementsByTagName('a');for(var i=0;i<anchors.length;i++){var anchor=anchors[i];if(anchor.getAttribute('href')&&hasValue(anchor.rel,'external')){anchor.target='_blank';addClass(anchor,'external');}}}
+function createControls(){var controlsDiv=document.getElementById("controls");if(!controlsDiv)return;var hider=' onmouseover="showHide(\'s\');" onmouseout="showHide(\'h\');"';var hideDiv,hideList='';if(controlVis=='hidden'){hideDiv=hider;}else{hideList=hider;}
+controlsDiv.innerHTML='<form action="#" id="controlForm"'+hideDiv+'>'+'<div id="navLinks">'+'<a accesskey="t" id="toggle" href="javascript:toggle();">&#216;<\/a>'+'<a accesskey="z" id="prev" href="javascript:go(-1);">&laquo;<\/a>'+'<a accesskey="x" id="next" href="javascript:go(1);">&raquo;<\/a>'+'<div id="navList"'+hideList+'><select id="jumplist" onchange="go(\'j\');"><\/select><\/div>'+'<\/div><\/form>';if(controlVis=='hidden'){var hidden=document.getElementById('navLinks');}else{var hidden=document.getElementById('jumplist');}
+addClass(hidden,'hideme');}
+function fontScale(){if(!s5mode)return false;var vScale=22;var hScale=32;if(window.innerHeight){var vSize=window.innerHeight;var hSize=window.innerWidth;}else if(document.documentElement.clientHeight){var vSize=document.documentElement.clientHeight;var hSize=document.documentElement.clientWidth;}else if(document.body.clientHeight){var vSize=document.body.clientHeight;var hSize=document.body.clientWidth;}else{var vSize=700;var hSize=1024;}
+var newSize=Math.min(Math.round(vSize/vScale),Math.round(hSize/hScale));fontSize(newSize+'px');if(isGe){var obj=document.getElementsByTagName('body')[0];obj.style.display='none';obj.style.display='block';}}
+function fontSize(value){if(!(s5ss=document.getElementById('s5ss'))){if(!isIE){document.getElementsByTagName('head')[0].appendChild(s5ss=document.createElement('style'));s5ss.setAttribute('media','screen, projection');s5ss.setAttribute('id','s5ss');}else{document.createStyleSheet();document.s5ss=document.styleSheets[document.styleSheets.length-1];}}
+if(!isIE){while(s5ss.lastChild)s5ss.removeChild(s5ss.lastChild);s5ss.appendChild(document.createTextNode('body {font-size: '+value+' !important;}'));}else{document.s5ss.addRule('body','font-size: '+value+' !important;');}}
+function notOperaFix(){slideCSS=document.getElementById('slideProj').href;var slides=document.getElementById('slideProj');var outline=document.getElementById('outlineStyle');slides.setAttribute('media','screen');outline.disabled=true;if(isGe){slides.setAttribute('href','null');slides.setAttribute('href',slideCSS);}
+if(isIE&&document.styleSheets&&document.styleSheets[0]){document.styleSheets[0].addRule('img','behavior: url(ui/default/iepngfix.htc)');document.styleSheets[0].addRule('div','behavior: url(ui/default/iepngfix.htc)');document.styleSheets[0].addRule('.slide','behavior: url(ui/default/iepngfix.htc)');}}
+function getIncrementals(obj){var incrementals=new Array();if(!obj)
+return incrementals;var children=obj.childNodes;for(var i=0;i<children.length;i++){var child=children[i];if(hasClass(child,'incremental')){if(child.nodeName=='OL'||child.nodeName=='UL'){removeClass(child,'incremental');for(var j=0;j<child.childNodes.length;j++){if(child.childNodes[j].nodeType==1){addClass(child.childNodes[j],'incremental');}}}else{incrementals[incrementals.length]=child;removeClass(child,'incremental');}}
+if(hasClass(child,'show-first')){if(child.nodeName=='OL'||child.nodeName=='UL'){removeClass(child,'show-first');if(child.childNodes[isGe].nodeType==1){removeClass(child.childNodes[isGe],'incremental');}}else{incrementals[incrementals.length]=child;}}
+incrementals=incrementals.concat(getIncrementals(child));}
+return incrementals;}
+function createIncrementals(){var incrementals=new Array();for(var i=0;i<smax;i++){incrementals[i]=getIncrementals(document.getElementById('slide'+i));}
+return incrementals;}
+function defaultCheck(){var allMetas=document.getElementsByTagName('meta');for(var i=0;i<allMetas.length;i++){if(allMetas[i].name=='defaultView'){defaultView=allMetas[i].content;}
+if(allMetas[i].name=='controlVis'){controlVis=allMetas[i].content;}}}
+function trap(e){if(!e){e=event;e.which=e.keyCode;}
+try{modifierKey=e.ctrlKey||e.altKey||e.metaKey;}
+catch(e){modifierKey=false;}
+return modifierKey||e.which==0;}
+function startup(){defaultCheck();if(!isOp)
+createControls();slideLabel();fixLinks();externalLinks();fontScale();if(!isOp){notOperaFix();incrementals=createIncrementals();slideJump();if(defaultView=='outline'){toggle();}
+document.onkeyup=keys;document.onkeypress=trap;document.onclick=clicker;}}
+window.onload=startup;window.onresize=function(){setTimeout('fontScale()',50);}
diff --git a/hsmarkdown b/hsmarkdown
new file mode 100755
index 000000000..17f970234
--- /dev/null
+++ b/hsmarkdown
@@ -0,0 +1,5 @@
+#!/bin/sh
+# hsmarkdown - intended as a drop-in replacement for Markdown.pl.
+# Uses pandoc to convert from markdown to HTML, using --strict mode
+# for maximum compatibility with official markdown syntax.
+exec pandoc --from markdown --to html --strict -- "$@"
diff --git a/html2markdown b/html2markdown
new file mode 100755
index 000000000..0649e0478
--- /dev/null
+++ b/html2markdown
@@ -0,0 +1,221 @@
+#!/bin/sh -e
+# converts HTML from a URL, file, or stdin to markdown
+# uses an available program to fetch URL and tidy to normalize it first
+
+REQUIRED="tidy"
+SYNOPSIS="converts HTML from a URL, file, or STDIN to markdown-formatted text."
+
+THIS=${0##*/}
+
+NEWLINE='
+'
+
+err () { echo "$*" | fold -s -w ${COLUMNS:-110} >&2; }
+errn () { printf "$*" | fold -s -w ${COLUMNS:-110} >&2; }
+
+usage () {
+ err "$1 - $2" # short description
+ err "See the $1(1) man page for usage."
+}
+
+# Portable which(1).
+pathfind () {
+ oldifs="$IFS"; IFS=':'
+ for _p in $PATH; do
+ if [ -x "$_p/$*" ] && [ -f "$_p/$*" ]; then
+ IFS="$oldifs"
+ return 0
+ fi
+ done
+ IFS="$oldifs"
+ return 1
+}
+
+for p in pandoc $REQUIRED; do
+ pathfind $p || {
+ err "You need '$p' to use this program!"
+ exit 1
+ }
+done
+
+CONF=$(pandoc --dump-args "$@" 2>&1) || {
+ errcode=$?
+ echo "$CONF" | sed -e '/^pandoc \[OPTIONS\] \[FILES\]/,$d' >&2
+ [ $errcode -eq 2 ] && usage "$THIS" "$SYNOPSIS"
+ exit $errcode
+}
+
+OUTPUT=$(echo "$CONF" | sed -ne '1p')
+ARGS=$(echo "$CONF" | sed -e '1d')
+
+
+grab_url_with () {
+ url="${1:?internal error: grab_url_with: url required}"
+
+ shift
+ cmdline="$@"
+
+ prog=
+ prog_opts=
+ if [ -n "$cmdline" ]; then
+ eval "set -- $cmdline"
+ prog=$1
+ shift
+ prog_opts="$@"
+ fi
+
+ if [ -z "$prog" ]; then
+ # Locate a sensible web grabber (note the order).
+ for p in wget lynx w3m curl links w3c; do
+ if pathfind $p; then
+ prog=$p
+ break
+ fi
+ done
+
+ [ -n "$prog" ] || {
+ errn "$THIS: Couldn't find a program to fetch the file from URL "
+ err "(e.g. wget, w3m, lynx, w3c, or curl)."
+ return 1
+ }
+ else
+ pathfind "$prog" || {
+ err "$THIS: No such web grabber '$prog' found; aborting."
+ return 1
+ }
+ fi
+
+ # Setup proper base options for known grabbers.
+ base_opts=
+ case "$prog" in
+ wget) base_opts="-O-" ;;
+ lynx) base_opts="-source" ;;
+ w3m) base_opts="-dump_source" ;;
+ curl) base_opts="" ;;
+ links) base_opts="-source" ;;
+ w3c) base_opts="-n -get" ;;
+ *) err "$THIS: unhandled web grabber '$prog'; hope it succeeds."
+ esac
+
+ err "$THIS: invoking '$prog $base_opts $prog_opts $url'..."
+ eval "set -- $base_opts $prog_opts"
+ $prog "$@" "$url"
+}
+
+# Parse command-line arguments
+parse_arguments () {
+ while [ $# -gt 0 ]; do
+ case "$1" in
+ --encoding=*)
+ wholeopt="$1"
+ # extract encoding from after =
+ encoding="${wholeopt#*=}" ;;
+ -e|--encoding|-encoding)
+ shift
+ encoding="$1" ;;
+ --grabber=*)
+ wholeopt="$1"
+ # extract encoding from after =
+ grabber="\"${wholeopt#*=}\"" ;;
+ -g|--grabber|-grabber)
+ shift
+ grabber="$1" ;;
+ *)
+ if [ -z "$argument" ]; then
+ argument="$1"
+ else
+ err "Warning: extra argument '$1' will be ignored."
+ fi ;;
+ esac
+ shift
+ done
+}
+
+argument=
+encoding=
+grabber=
+
+oldifs="$IFS"
+IFS=$NEWLINE
+parse_arguments $ARGS
+IFS="$oldifs"
+
+inurl=
+if [ -n "$argument" ] && ! [ -f "$argument" ]; then
+ # Treat given argument as an URL.
+ inurl="$argument"
+fi
+
+# As a security measure refuse to proceed if mktemp is not available.
+pathfind mktemp || { err "Couldn't find 'mktemp'; aborting."; exit 1; }
+
+# Avoid issues with /tmp directory on Windows/Cygwin
+cygwin=
+cygwin=$(uname | sed -ne '/^CYGWIN/p')
+if [ -n "$cygwin" ]; then
+ TMPDIR=.
+ export TMPDIR
+fi
+
+THIS_TEMPDIR=
+THIS_TEMPDIR="$(mktemp -d -t $THIS.XXXXXXXX)" || exit 1
+readonly THIS_TEMPDIR
+
+trap 'exitcode=$?
+ [ -z "$THIS_TEMPDIR" ] || rm -rf "$THIS_TEMPDIR"
+ exit $exitcode' 0 1 2 3 13 15
+
+if [ -n "$inurl" ]; then
+ err "Attempting to fetch file from '$inurl'..."
+
+ grabber_out=$THIS_TEMPDIR/grabber.out
+ grabber_log=$THIS_TEMPDIR/grabber.log
+ if ! grab_url_with "$inurl" "$grabber" 1>$grabber_out 2>$grabber_log; then
+ errn "grab_url_with failed"
+ if [ -f $grabber_log ]; then
+ err " with the following error log."
+ err
+ cat >&2 $grabber_log
+ else
+ err .
+ fi
+ exit 1
+ fi
+
+ argument="$grabber_out"
+fi
+
+if [ -z "$encoding" ] && [ "x$argument" != "x" ]; then
+ # Try to determine character encoding if not specified
+ # and input is not STDIN.
+ encoding=$(
+ head "$argument" |
+ LC_ALL=C tr 'A-Z' 'a-z' |
+ sed -ne '/<meta .*content-type.*charset=/ {
+ s/.*charset=["'\'']*\([-a-zA-Z0-9]*\).*["'\'']*/\1/p
+ }'
+ )
+fi
+
+if [ -n "$encoding" ] && pathfind iconv; then
+ alias to_utf8='iconv -f "$encoding" -t utf-8'
+else # assume UTF-8
+ alias to_utf8='cat'
+fi
+
+htmlinput=$THIS_TEMPDIR/htmlinput
+
+if [ -z "$argument" ]; then
+ to_utf8 > $htmlinput # read from STDIN
+elif [ -f "$argument" ]; then
+ to_utf8 "$argument" > $htmlinput # read from file
+else
+ err "File '$argument' not found."
+ exit 1
+fi
+
+if ! cat $htmlinput | pandoc --ignore-args -r html -w markdown "$@" ; then
+ err "Failed to parse HTML. Trying again with tidy..."
+ tidy -q -asxhtml -utf8 $htmlinput | \
+ pandoc --ignore-args -r html -w markdown "$@"
+fi
diff --git a/man/man1/hsmarkdown.1.md b/man/man1/hsmarkdown.1.md
new file mode 100644
index 000000000..a197ef2ca
--- /dev/null
+++ b/man/man1/hsmarkdown.1.md
@@ -0,0 +1,42 @@
+% HSMARKDOWN(1) Pandoc User Manuals
+% John MacFarlane
+% January 8, 2008
+
+# NAME
+
+hsmarkdown - convert markdown-formatted text to HTML
+
+# SYNOPSIS
+
+hsmarkdown [*input-file*]...
+
+# DESCRIPTION
+
+`hsmarkdown` converts markdown-formatted text to HTML. It is designed
+to be usable as a drop-in replacement for John Gruber's `Markdown.pl`.
+
+If no *input-file* is specified, input is read from *stdin*.
+Otherwise, the *input-files* are concatenated (with a blank
+line between each) and used as input. Output goes to *stdout* by
+default. For output to a file, use shell redirection:
+
+ hsmarkdown input.txt > output.html
+
+`hsmarkdown` uses the UTF-8 character encoding for both input and output.
+If your local character encoding is not UTF-8, you should pipe input
+and output through `iconv`:
+
+ iconv -t utf-8 input.txt | hsmarkdown | iconv -f utf-8
+
+`hsmarkdown` is implemented as a wrapper around `pandoc`(1). It
+calls `pandoc` with the options `--from markdown --to html
+--strict` and disables all other options. (Command-line options
+will be interpreted as filenames, as they are by `Markdown.pl`.)
+
+# SEE ALSO
+
+`pandoc`(1). The *README*
+file distributed with Pandoc contains full documentation.
+
+The Pandoc source code and all documentation may be downloaded from
+<http://johnmacfarlane.net/pandoc/>.
diff --git a/man/man1/html2markdown.1.md b/man/man1/html2markdown.1.md
new file mode 100644
index 000000000..73e3420dd
--- /dev/null
+++ b/man/man1/html2markdown.1.md
@@ -0,0 +1,95 @@
+% HTML2MARKDOWN(1) Pandoc User Manuals
+% John MacFarlane and Recai Oktas
+% January 8, 2008
+
+# NAME
+
+html2markdown - converts HTML to markdown-formatted text
+
+# SYNOPSIS
+
+html2markdown [*pandoc-options*] [\-- *special-options*] [*input-file* or
+*URL*]
+
+# DESCRIPTION
+
+`html2markdown` converts *input-file* or *URL* (or text
+from *stdin*) from HTML to markdown-formatted plain text.
+If a URL is specified, `html2markdown` uses an available program
+(e.g. wget, w3m, lynx or curl) to fetch its contents. Output is sent
+to *stdout* unless an output file is specified using the `-o`
+option.
+
+`html2markdown` uses the character encoding specified in the
+"Content-type" meta tag. If this is not present, or if input comes
+from *stdin*, UTF-8 is assumed. A character encoding may be specified
+explicitly using the `-e` special option.
+
+# OPTIONS
+
+`html2markdown` is a wrapper for `pandoc`, so all of
+`pandoc`'s options may be used. See `pandoc`(1) for
+a complete list. The following options are most relevant:
+
+-s, \--standalone
+: Include title, author, and date information (if present) at the
+ top of markdown output.
+
+-o *FILE*, \--output=*FILE*
+: Write output to *FILE* instead of *stdout*.
+
+\--strict
+: Use strict markdown syntax, with no extensions or variants.
+
+\--reference-links
+: Use reference-style links, rather than inline links, in writing markdown
+ or reStructuredText.
+
+-R, \--parse-raw
+: Parse untranslatable HTML codes as raw HTML.
+
+\--no-wrap
+: Disable text wrapping in output. (Default is to wrap text.)
+
+-H *FILE*, \--include-in-header=*FILE*
+: Include contents of *FILE* at the end of the header. Implies
+ `-s`.
+
+-B *FILE*, \--include-before-body=*FILE*
+: Include contents of *FILE* at the beginning of the document body.
+
+-A *FILE*, \--include-after-body=*FILE*
+: Include contents of *FILE* at the end of the document body.
+
+-C *FILE*, \--custom-header=*FILE*
+: Use contents of *FILE*
+ as the document header (overriding the default header, which can be
+ printed using `pandoc -D markdown`). Implies `-s`.
+
+# SPECIAL OPTIONS
+
+In addition, the following special options may be used. The special
+options must be separated from the `html2markdown` command and any
+regular `pandoc` options by the delimiter \``--`', as in
+
+ html2markdown -o foo.txt -- -g 'curl -u bar:baz' -e latin1 \
+ www.foo.com
+
+-e *encoding*, \--encoding=*encoding*
+: Assume the character encoding *encoding* in reading HTML.
+ (Note: *encoding* will be passed to `iconv`; a list of
+ available encodings may be obtained using `iconv -l`.)
+ If this option is not specified and input is not from
+ *stdin*, `html2markdown` will try to extract the character encoding
+ from the "Content-type" meta tag. If no character encoding is
+ specified in this way, or if input is from *stdin*, UTF-8 will be
+ assumed.
+
+-g *command*, \--grabber=*command*
+: Use *command* to fetch the contents of a URL. (By default,
+ `html2markdown` searches for an available program or text-based
+ browser to fetch the contents of a URL.)
+
+# SEE ALSO
+
+`pandoc`(1), `iconv`(1)
diff --git a/man/man1/markdown2pdf.1.md b/man/man1/markdown2pdf.1.md
new file mode 100644
index 000000000..0bc8329d7
--- /dev/null
+++ b/man/man1/markdown2pdf.1.md
@@ -0,0 +1,69 @@
+% MARKDOWN2PDF(1) Pandoc User Manuals
+% John MacFarlane and Recai Oktas
+% January 8, 2008
+
+# NAME
+
+markdown2pdf - converts markdown-formatted text to PDF, using pdflatex
+
+# SYNOPSIS
+
+markdown2pdf [*options*] [*input-file*]...
+
+# DESCRIPTION
+
+`markdown2pdf` converts *input-file* (or text from standard
+input) from markdown-formatted plain text to PDF, using `pdflatex`.
+If no output filename is specified (using the `-o` option),
+the name of the output file is derived from the input file; thus, for
+example, if the input file is *hello.txt*, the output file will be
+*hello.pdf*. If the input is read from STDIN and no output filename
+is specified, the output file will be named *stdin.pdf*. If multiple
+input files are specified, they will be concatenated before conversion,
+and the name of the output file will be derived from the first input file.
+
+Input is assumed to be in the UTF-8 character encoding. If your
+local character encoding is not UTF-8, you should pipe input
+through `iconv`:
+
+ iconv -t utf-8 input.txt | markdown2pdf
+
+`markdown2pdf` assumes that the `unicode`, `array`, `fancyvrb`,
+`graphicx`, and `ulem` packages are in latex's search path. If these
+packages are not included in your latex setup, they can be obtained from
+<http://ctan.org>.
+
+# OPTIONS
+
+`markdown2pdf` is a wrapper around `pandoc`, so all of
+`pandoc`'s options can be used with `markdown2pdf` as well.
+See `pandoc`(1) for a complete list.
+The following options are most relevant:
+
+-o *FILE*, \--output=*FILE*
+: Write output to *FILE*.
+
+\--strict
+: Use strict markdown syntax, with no extensions or variants.
+
+-N, \--number-sections
+: Number section headings in LaTeX output. (Default is not to number them.)
+
+-H *FILE*, \--include-in-header=*FILE*
+: Include (LaTeX) contents of *FILE* at the end of the header. Implies
+ `-s`.
+
+-B *FILE*, \--include-before-body=*FILE*
+: Include (LaTeX) contents of *FILE* at the beginning of the document body.
+
+-A *FILE*, \--include-after-body=*FILE*
+: Include (LaTeX) contents of *FILE* at the end of the document body.
+
+-C *FILE*, \--custom-header=*FILE*
+: Use contents of *FILE*
+ as the LaTeX document header (overriding the default header, which can be
+ printed using `pandoc -D latex`). Implies `-s`.
+
+# SEE ALSO
+
+`pandoc`(1), `pdflatex`(1)
diff --git a/man/man1/pandoc.1.md b/man/man1/pandoc.1.md
new file mode 100644
index 000000000..9a0907321
--- /dev/null
+++ b/man/man1/pandoc.1.md
@@ -0,0 +1,222 @@
+% PANDOC(1) Pandoc User Manuals
+% John MacFarlane
+% January 8, 2008
+
+# NAME
+
+pandoc - general markup converter
+
+# SYNOPSIS
+
+pandoc [*options*] [*input-file*]...
+
+# DESCRIPTION
+
+Pandoc converts files from one markup format to another. It can
+read markdown and (subsets of) reStructuredText, HTML, and LaTeX, and
+it can write markdown, reStructuredText, HTML, LaTeX, ConTeXt, Texinfo,
+groff man, MediaWiki markup, RTF, OpenDocument XML, ODT, DocBook XML,
+and S5 HTML slide shows.
+
+If no *input-file* is specified, input is read from *stdin*.
+Otherwise, the *input-files* are concatenated (with a blank
+line between each) and used as input. Output goes to *stdout* by
+default (though output to *stdout* is disabled for the `odt` output
+format). For output to a file, use the `-o` option:
+
+ pandoc -o output.html input.txt
+
+The input and output formats may be specified using command-line options
+(see **OPTIONS**, below, for details). If these formats are not
+specified explicitly, Pandoc will attempt to determine them
+from the extensions of the input and output filenames. If input comes
+from *stdin* or from a file with an unknown extension, the input is assumed
+to be markdown. If no output filename is specified using the `-o`
+option, or if a filename is specified but its extension is unknown,
+the output will default to HTML. Thus, for example,
+
+ pandoc -o chap1.tex chap1.txt
+
+converts *chap1.txt* from markdown to LaTeX. And
+
+ pandoc README
+
+converts *README* from markdown to HTML.
+
+Pandoc's version of markdown is an extended variant of standard
+markdown: the differences are described in the *README* file in
+the user documentation. If standard markdown syntax is desired, the
+`--strict` option may be used.
+
+Pandoc uses the UTF-8 character encoding for both input and output.
+If your local character encoding is not UTF-8, you should pipe input
+and output through `iconv`:
+
+ iconv -t utf-8 input.txt | pandoc | iconv -f utf-8
+
+Pandoc's HTML parser is not very forgiving. If your input is
+HTML, consider running it through `tidy`(1) before passing it
+to Pandoc. Or use `html2markdown`(1), a wrapper around `pandoc`.
+
+# OPTIONS
+
+-f *FORMAT*, -r *FORMAT*, \--from=*FORMAT*, \--read=*FORMAT*
+: Specify input format. *FORMAT* can be
+ `native` (native Haskell), `markdown` (markdown or plain text),
+ `rst` (reStructuredText), `html` (HTML), or `latex` (LaTeX).
+ If `+lhs` is appended to `markdown`, `rst`, or `latex`, the input
+ will be treated as literate Haskell source.
+
+-t *FORMAT*, -w *FORMAT*, \--to=*FORMAT*, \--write=*FORMAT*
+: Specify output format. *FORMAT* can be `native` (native Haskell),
+ `markdown` (markdown or plain text), `rst` (reStructuredText),
+ `html` (HTML), `latex` (LaTeX), `context` (ConTeXt), `man` (groff man),
+ `mediawiki` (MediaWiki markup), `texinfo` (GNU Texinfo),
+ `docbook` (DocBook XML), `opendocument` (OpenDocument XML),
+ `odt` (OpenOffice text document), `s5` (S5 HTML and javascript slide
+ show), or `rtf` (rich text format). Note that `odt` output will not
+ be directed to *stdout*; an output filename must be specified using
+ the `-o/--output` option. If `+lhs` is appended to `markdown`,
+ `rst`, `latex`, or `html`, the output will be rendered as literate
+ Haskell source.
+
+-s, \--standalone
+: Produce output with an appropriate header and footer (e.g. a
+ standalone HTML, LaTeX, or RTF file, not a fragment).
+
+-o *FILE*, \--output=*FILE*
+: Write output to *FILE* instead of *stdout*. If *FILE* is
+ \``-`', output will go to *stdout*.
+
+-p, \--preserve-tabs
+: Preserve tabs instead of converting them to spaces.
+
+\--tab-stop=*TABSTOP*
+: Specify tab stop (default is 4).
+
+\--strict
+: Use strict markdown syntax, with no extensions or variants.
+
+\--reference-links
+: Use reference-style links, rather than inline links, in writing markdown
+ or reStructuredText.
+
+-R, \--parse-raw
+: Parse untranslatable HTML codes and LaTeX environments as raw HTML
+ or LaTeX, instead of ignoring them.
+
+-S, \--smart
+: Use smart quotes, dashes, and ellipses. (This option is significant
+ only when the input format is `markdown`. It is selected automatically
+ when the output format is `latex` or `context`.)
+
+-m*URL*, \--latexmathml=*URL*
+: Use LaTeXMathML to display embedded TeX math in HTML output.
+ To insert a link to a local copy of the `LaTeXMathML.js` script,
+ provide a *URL*. If no *URL* is provided, the contents of the
+ script will be inserted directly into the HTML header.
+
+\--jsmath=*URL*
+: Use jsMath to display embedded TeX math in HTML output.
+ The *URL* should point to the jsMath load script; if provided,
+ it will be linked to in the header of standalone HTML documents.
+
+\--gladtex
+: Enclose TeX math in `<eq>` tags in HTML output. These can then
+ be processed by gladTeX to produce links to images of the typeset
+ formulas.
+
+\--mimetex=*URL*
+: Render TeX math using the mimeTeX CGI script. If *URL* is not specified,
+ it is assumed that the script is at `/cgi-bin/mimetex.cgi`.
+
+-i, \--incremental
+: Make list items in S5 display incrementally (one by one).
+
+-N, \--number-sections
+: Number section headings in LaTeX output. (Default is not to number
+ them.)
+
+\--no-wrap
+: Disable text wrapping in output. (Default is to wrap text.)
+
+\--sanitize-html
+: Sanitizes HTML (in markdown or HTML input) using a whitelist.
+ Unsafe tags are replaced by HTML comments; unsafe attributes
+ are omitted. URIs in links and images are also checked against a
+ whitelist of URI schemes.
+
+\--email-obfuscation=*none|javascript|references*
+: Specify a method for obfuscating `mailto:` links in HTML documents.
+ *none* leaves `mailto:` links as they are. *javascript* obfuscates
+ them using javascript. *references* obfuscates them by printing their
+ letters as decimal or hexadecimal character references.
+ If `--strict` is specified, *references* is used regardless of the
+ presence of this option.
+
+\--toc, \--table-of-contents
+: Include an automatically generated table of contents (HTML, markdown,
+ RTF) or an instruction to create one (LaTeX, reStructuredText).
+ This option has no effect on man, DocBook, or S5 output.
+
+-c *CSS*, \--css=*CSS*
+: Link to a CSS style sheet. *CSS* is the pathname of the style sheet.
+
+-H *FILE*, \--include-in-header=*FILE*
+: Include contents of *FILE* at the end of the header. Implies `-s`.
+
+-B *FILE*, \--include-before-body=*FILE*
+: Include contents of *FILE* at the beginning of the document body.
+
+-A *FILE*, \--include-after-body=*FILE*
+: Include contents of *FILE* at the end of the document body.
+
+-C *FILE*, \--custom-header=*FILE*
+: Use contents of *FILE* as the document header (overriding the
+ default header, which can be printed by using the `-D` option).
+ Implies `-s`.
+
+-D *FORMAT*, \--print-default-header=*FORMAT*
+: Print the default header for *FORMAT* (`html`, `s5`, `latex`,
+ `context`, `docbook`, `man`, `markdown`, `opendocument`,
+ `rst`, `rtf`).
+
+-T *STRING*, \--title-prefix=*STRING*
+: Specify *STRING* as a prefix to the HTML window title.
+
+\--dump-args
+: Print information about command-line arguments to *stdout*, then exit.
+ The first line of output contains the name of the output file specified
+ with the `-o` option, or \``-`' (for *stdout*) if no output file was
+ specified. The remaining lines contain the command-line arguments,
+ one per line, in the order they appear. These do not include regular
+ Pandoc options and their arguments, but do include any options appearing
+ after a \``--`' separator at the end of the line.
+ This option is intended primarily for use in wrapper scripts.
+
+\--ignore-args
+: Ignore command-line arguments (for use in wrapper scripts).
+ Regular Pandoc options are not ignored. Thus, for example,
+
+: pandoc --ignore-args -o foo.html -s foo.txt -- -e latin1
+
+: is equivalent to
+
+: pandoc -o foo.html -s
+
+-v, \--version
+: Print version.
+
+-h, \--help
+: Show usage message.
+
+# SEE ALSO
+
+`hsmarkdown`(1),
+`html2markdown`(1),
+`markdown2pdf` (1).
+The *README* file distributed with Pandoc contains full documentation.
+
+The Pandoc source code and all documentation may be downloaded from
+<http://johnmacfarlane.net/pandoc/>.
+
diff --git a/markdown2pdf b/markdown2pdf
new file mode 100755
index 000000000..ab0f3ae78
--- /dev/null
+++ b/markdown2pdf
@@ -0,0 +1,140 @@
+#!/bin/sh -e
+
+REQUIRED="pdflatex"
+SYNOPSIS="converts markdown-formatted text to PDF, using pdflatex."
+
+THIS=${0##*/}
+
+NEWLINE='
+'
+
+err () { echo "$*" | fold -s -w ${COLUMNS:-110} >&2; }
+errn () { printf "$*" | fold -s -w ${COLUMNS:-110} >&2; }
+
+usage () {
+ err "$1 - $2" # short description
+ err "See the $1(1) man page for usage."
+}
+
+# Portable which(1).
+pathfind () {
+ oldifs="$IFS"; IFS=':'
+ for _p in $PATH; do
+ if [ -x "$_p/$*" ] && [ -f "$_p/$*" ]; then
+ IFS="$oldifs"
+ return 0
+ fi
+ done
+ IFS="$oldifs"
+ return 1
+}
+
+for p in pandoc $REQUIRED; do
+ pathfind $p || {
+ err "You need '$p' to use this program!"
+ exit 1
+ }
+done
+
+CONF=$(pandoc --dump-args "$@" 2>&1) || {
+ errcode=$?
+ echo "$CONF" | sed -e '/^pandoc \[OPTIONS\] \[FILES\]/,$d' >&2
+ [ $errcode -eq 2 ] && usage "$THIS" "$SYNOPSIS"
+ exit $errcode
+}
+
+OUTPUT=$(echo "$CONF" | sed -ne '1p')
+ARGS=$(echo "$CONF" | sed -e '1d')
+
+
+# As a security measure refuse to proceed if mktemp is not available.
+pathfind mktemp || { err "Couldn't find 'mktemp'; aborting."; exit 1; }
+
+# Avoid issues with /tmp directory on Windows/Cygwin
+cygwin=
+cygwin=$(uname | sed -ne '/^CYGWIN/p')
+if [ -n "$cygwin" ]; then
+ TMPDIR=.
+ export TMPDIR
+fi
+
+THIS_TEMPDIR=
+THIS_TEMPDIR="$(mktemp -d -t $THIS.XXXXXXXX)" || exit 1
+readonly THIS_TEMPDIR
+
+trap 'exitcode=$?
+ [ -z "$THIS_TEMPDIR" ] || rm -rf "$THIS_TEMPDIR"
+ exit $exitcode' 0 1 2 3 13 15
+
+texname=output
+logfile=$THIS_TEMPDIR/log
+
+pandoc -s -r markdown -w latex "$@" -o $THIS_TEMPDIR/$texname.tex
+
+if [ "$OUTPUT" = "-" ]; then
+ firstinfile="$(echo $ARGS | sed -ne '1p')"
+ firstinfilebase="${firstinfile%.*}"
+ destname="${firstinfilebase:-stdin}.pdf"
+else
+ destname="$OUTPUT"
+fi
+
+(
+ origdir=$(pwd)
+ cd $THIS_TEMPDIR
+ TEXINPUTS=$origdir:$TEXINPUTS:
+ export TEXINPUTS
+ finished=no
+ runs=0
+ while [ $finished = "no" ]; do
+ pdflatex -interaction=batchmode $texname.tex >/dev/null || {
+ errcode=$?
+ err "${THIS}: pdfLaTeX failed with error code $errcode"
+ [ -f $texname.log ] && {
+ err "${THIS}: error context:"
+ sed -ne '/^!/,/^[[:space:]]*$/p' \
+ -ne '/^[Ll]a[Tt]e[Xx] [Ww]arning/,/^[[:space:]]*$/p' \
+ -ne '/^[Ee]rror/,/^[[:space:]]*$/p' $texname.log >&2
+ if grep -q "File \`ucs.sty' not found" $texname.log; then
+ err "${THIS}: Please install the 'unicode' package from CTAN:"
+ err " http://www.ctan.org/tex-archive/macros/latex/contrib/unicode/"
+ fi
+ if grep -q "File \`ulem.sty' not found" $texname.log; then
+ err "${THIS}: Please install the 'ulem' package from CTAN:"
+ err " http://www.ctan.org/tex-archive/macros/latex/contrib/misc/ulem.sty"
+ fi
+ }
+ exit $errcode
+ }
+ if [ $runs -lt 3 ] &&
+ ((grep -q "LaTeX Warning: There were undefined references." $texname.log) ||
+ (echo "$@" | grep -q -- "--toc\|--table-of-contents")); then
+ runs=$(($runs + 1))
+ if grep -q "LaTeX Warning:.*[Cc]itation" $texname.log; then
+ bibtex $texname 2>&1 >bibtex.err
+ if [ $runs -gt 2 ]; then
+ if grep -q "error message" bibtex.err ||
+ grep -q "Warning" bibtex.err; then
+ cat bibtex.err >&2
+ fi
+ fi
+ fi
+ else
+ finished=yes
+ fi
+ done
+) || exit $?
+
+is_target_exists=
+if [ -f "$destname" ]; then
+ is_target_exists=1
+ mv "$destname" "$destname~"
+fi
+
+mv -f $THIS_TEMPDIR/$texname.pdf "$destname"
+
+errn "Created $destname"
+[ -z "$is_target_exists" ] || {
+ errn " (previous file has been backed up as $destname~)"
+}
+err .
diff --git a/pandoc.cabal b/pandoc.cabal
new file mode 100644
index 000000000..0339a97fe
--- /dev/null
+++ b/pandoc.cabal
@@ -0,0 +1,245 @@
+Name: pandoc
+Version: 1.2.1
+Cabal-Version: >= 1.2
+Build-Type: Custom
+License: GPL
+License-File: COPYING
+Copyright: (c) 2006-2008 John MacFarlane
+Author: John MacFarlane <jgm@berkeley.edu>
+Maintainer: John MacFarlane <jgm@berkeley.edu>
+Bug-Reports: http://code.google.com/p/pandoc/issues/list
+Stability: alpha
+Homepage: http://johnmacfarlane.net/pandoc
+Category: Text
+Tested-With: GHC
+Synopsis: Conversion between markup formats
+Description: Pandoc is a Haskell library for converting from one markup
+ format to another, and a command-line tool that uses
+ this library. It can read markdown and (subsets of)
+ reStructuredText, HTML, and LaTeX, and it can write
+ markdown, reStructuredText, HTML, LaTeX, ConTeXt, Docbook,
+ OpenDocument, ODT, RTF, MediaWiki, groff man pages, and
+ S5 HTML slide shows.
+ .
+ Pandoc extends standard markdown syntax with footnotes,
+ embedded LaTeX, definition lists, tables, and other
+ features. A compatibility mode is provided for those
+ who need a drop-in replacement for Markdown.pl.
+ .
+ In contrast to existing tools for converting markdown
+ to HTML, which use regex substitutions, pandoc has
+ a modular design: it consists of a set of readers,
+ which parse text in a given format and produce a native
+ representation of the document, and a set of writers,
+ which convert this native representation into a target
+ format. Thus, adding an input or output format requires
+ only adding a reader or writer.
+Data-Files:
+ -- documentation
+ README, INSTALL, COPYRIGHT, BUGS, changelog,
+ -- wrappers
+ markdown2pdf, html2markdown, hsmarkdown
+Extra-Source-Files:
+ -- sources for man pages
+ man/man1/pandoc.1.md, man/man1/markdown2pdf.1.md,
+ man/man1/html2markdown.1.md, man/man1/hsmarkdown.1.md,
+ -- Makefile
+ Makefile,
+ -- data for DefaultHeaders.hs
+ data/headers/ConTeXt.header,
+ data/headers/Docbook.header,
+ data/headers/LaTeX.header,
+ data/headers/OpenDocument.header,
+ data/headers/RTF.header,
+ data/headers/S5.header,
+ -- data for LaTeXMathML writer
+ data/LaTeXMathML.js.comment,
+ data/LaTeXMathML.js.packed,
+ -- data for S5 writer
+ data/ui/default/slides.js.comment,
+ data/ui/default/slides.js.packed,
+ data/ui/default/s5-core.css,
+ data/ui/default/framing.css,
+ data/ui/default/pretty.css,
+ data/ui/default/opera.css,
+ data/ui/default/outline.css,
+ data/ui/default/print.css,
+ -- data for ODT writer
+ data/odt-styles/meta.xml,
+ data/odt-styles/settings.xml,
+ data/odt-styles/META-INF/manifest.xml,
+ data/odt-styles/Thumbnails/thumbnail.png,
+ data/odt-styles/styles.xml,
+ data/odt-styles/mimetype,
+ -- tests
+ tests/bodybg.gif,
+ tests/writer.latex,
+ tests/html-reader.html,
+ tests/html-reader.native,
+ tests/insert,
+ tests/lalune.jpg,
+ tests/movie.jpg,
+ tests/latex-reader.latex,
+ tests/latex-reader.native,
+ tests/markdown-reader-more.txt,
+ tests/markdown-reader-more.native,
+ tests/rst-reader.native,
+ tests/rst-reader.rst,
+ tests/s5.basic.html,
+ tests/s5.fancy.html,
+ tests/s5.fragment.html,
+ tests/s5.inserts.html,
+ tests/s5.native,
+ tests/tables.context,
+ tests/tables.docbook,
+ tests/tables.html,
+ tests/tables.latex,
+ tests/tables.man,
+ tests/tables.markdown,
+ tests/tables.mediawiki,
+ tests/tables.native,
+ tests/tables.opendocument,
+ tests/tables.texinfo,
+ tests/tables.rst,
+ tests/tables.rtf,
+ tests/tables.txt,
+ tests/testsuite.native,
+ tests/testsuite.txt,
+ tests/writer.context,
+ tests/writer.docbook,
+ tests/writer.html,
+ tests/writer.man,
+ tests/writer.markdown,
+ tests/writer.mediawiki,
+ tests/writer.native,
+ tests/writer.opendocument,
+ tests/writer.rst,
+ tests/writer.rtf,
+ tests/writer.texinfo,
+ tests/lhs-test.native,
+ tests/lhs-test.markdown,
+ tests/lhs-test.markdown+lhs,
+ tests/lhs-test.rst,
+ tests/lhs-test.rst+lhs,
+ tests/lhs-test.latex,
+ tests/lhs-test.latex+lhs,
+ tests/lhs-test.html,
+ tests/lhs-test.html+lhs,
+ tests/lhs-test.fragment.html+lhs,
+ tests/Diff.hs,
+ tests/RunTests.hs
+Extra-Tmp-Files: man/man1/pandoc.1, man/man1/hsmarkdown.1,
+ man/man1/html2markdown.1
+
+Flag highlighting
+ Description: Compile in support for syntax highlighting of code blocks.
+ Default: False
+Flag executable
+ Description: Build the pandoc executable.
+ Default: True
+Flag wrappers
+ Description: Build the wrappers (hsmarkdown, html2markdown, markdown2pdf).
+ Default: False
+Flag library
+ Description: Build the pandoc library.
+ Default: True
+Flag citeproc
+ Description: Compile in support for citeproc-hs bibliographic formatting.
+ Default: False
+
+Library
+ Build-Depends: pretty >= 1, containers >= 0.1,
+ parsec >= 2.1 && < 3, xhtml >= 3000.0,
+ mtl >= 1.1, network >= 2, filepath >= 1.1,
+ process >= 1, directory >= 1, template-haskell >= 2.2,
+ bytestring >= 0.9, zip-archive >= 0.1.1,
+ utf8-string >= 0.3, old-time >= 1
+ if impl(ghc >= 6.10)
+ Build-depends: base >= 4 && < 5, syb
+ else
+ Build-depends: base >= 3 && < 4
+ if flag(highlighting)
+ Build-depends: highlighting-kate >= 0.2.3
+ cpp-options: -D_HIGHLIGHTING
+ if flag(citeproc)
+ Build-depends: citeproc-hs
+ Exposed-Modules: Text.Pandoc.Biblio
+ cpp-options: -D_CITEPROC
+ Hs-Source-Dirs: src
+ Exposed-Modules: Text.Pandoc,
+ Text.Pandoc.Blocks,
+ Text.Pandoc.Definition,
+ Text.Pandoc.CharacterReferences,
+ Text.Pandoc.Shared,
+ Text.Pandoc.ODT,
+ Text.Pandoc.LaTeXMathML,
+ Text.Pandoc.DefaultHeaders,
+ Text.Pandoc.Highlighting,
+ Text.Pandoc.Readers.HTML,
+ Text.Pandoc.Readers.LaTeX,
+ Text.Pandoc.Readers.Markdown,
+ Text.Pandoc.Readers.RST,
+ Text.Pandoc.Readers.TeXMath,
+ Text.Pandoc.Writers.Docbook,
+ Text.Pandoc.Writers.HTML,
+ Text.Pandoc.Writers.LaTeX,
+ Text.Pandoc.Writers.ConTeXt,
+ Text.Pandoc.Writers.OpenDocument,
+ Text.Pandoc.Writers.Texinfo,
+ Text.Pandoc.Writers.Man,
+ Text.Pandoc.Writers.Markdown,
+ Text.Pandoc.Writers.RST,
+ Text.Pandoc.Writers.MediaWiki,
+ Text.Pandoc.Writers.RTF,
+ Text.Pandoc.Writers.S5
+ Other-Modules: Text.Pandoc.XML,
+ Text.Pandoc.TH,
+ Paths_pandoc
+ Extensions: CPP, TemplateHaskell, FlexibleInstances
+ Ghc-Options: -O2 -Wall
+ Ghc-Prof-Options: -auto-all -caf-all
+
+ if flag(library)
+ Buildable: True
+ else
+ Buildable: False
+
+Executable pandoc
+ Hs-Source-Dirs: src
+ Main-Is: pandoc.hs
+ Ghc-Options: -O2 -Wall -threaded
+ Ghc-Prof-Options: -auto-all -caf-all
+ Extensions: CPP, TemplateHaskell
+
+ if flag(highlighting)
+ cpp-options: -D_HIGHLIGHTING
+ if flag(citeproc)
+ Build-depends: citeproc-hs >= 0.2
+ cpp-options: -D_CITEPROC
+ if flag(executable)
+ Buildable: True
+ else
+ Buildable: False
+
+Executable hsmarkdown
+ Hs-Source-Dirs: src
+ Main-Is: hsmarkdown.hs
+ Ghc-Options: -Wall -threaded
+ Ghc-Prof-Options: -auto-all
+ Extensions: CPP, TemplateHaskell
+ if flag(wrappers)
+ Buildable: True
+ else
+ Buildable: False
+
+Executable markdown2pdf
+ Hs-Source-Dirs: src
+ Main-Is: markdown2pdf.hs
+ Ghc-Options: -Wall -threaded
+ Ghc-Prof-Options: -auto-all
+ Extensions: CPP, TemplateHaskell
+ if flag(wrappers)
+ Buildable: True
+ else
+ Buildable: False
+
diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs
new file mode 100644
index 000000000..6cca14afe
--- /dev/null
+++ b/src/Text/Pandoc.hs
@@ -0,0 +1,117 @@
+{-
+Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc
+ Copyright : Copyright (C) 2006-7 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+This helper module exports the main writers, readers, and data
+structure definitions from the Pandoc libraries.
+
+A typical application will chain together a reader and a writer
+to convert strings from one format to another. For example, the
+following simple program will act as a filter converting markdown
+fragments to reStructuredText, using reference-style links instead of
+inline links:
+
+> module Main where
+> import Text.Pandoc
+> import qualified System.IO.UTF8 as U
+>
+> markdownToRST :: String -> String
+> markdownToRST =
+> (writeRST defaultWriterOptions {writerReferenceLinks = True}) .
+> readMarkdown defaultParserState
+>
+> main = U.getContents >>= U.putStrLn . markdownToRST
+
+-}
+
+module Text.Pandoc
+ (
+ -- * Definitions
+ module Text.Pandoc.Definition
+ -- * Readers: converting /to/ Pandoc format
+ , readMarkdown
+ , readRST
+ , readLaTeX
+ , readHtml
+ -- * Parser state used in readers
+ , ParserState (..)
+ , defaultParserState
+ , ParserContext (..)
+ , QuoteContext (..)
+ , KeyTable
+ , NoteTable
+ , HeaderType (..)
+ -- * Writers: converting /from/ Pandoc format
+ , writeMarkdown
+ , writeRST
+ , writeLaTeX
+ , writeConTeXt
+ , writeTexinfo
+ , writeHtml
+ , writeHtmlString
+ , writeS5
+ , writeS5String
+ , writeDocbook
+ , writeOpenDocument
+ , writeMan
+ , writeMediaWiki
+ , writeRTF
+ , prettyPandoc
+ -- * Writer options used in writers
+ , WriterOptions (..)
+ , HTMLMathMethod (..)
+ , defaultWriterOptions
+ -- * Default headers for various output formats
+ , module Text.Pandoc.DefaultHeaders
+ -- * Version
+ , pandocVersion
+ ) where
+
+import Text.Pandoc.Definition
+import Text.Pandoc.Readers.Markdown
+import Text.Pandoc.Readers.RST
+import Text.Pandoc.Readers.LaTeX
+import Text.Pandoc.Readers.HTML
+import Text.Pandoc.Writers.Markdown
+import Text.Pandoc.Writers.RST
+import Text.Pandoc.Writers.LaTeX
+import Text.Pandoc.Writers.ConTeXt
+import Text.Pandoc.Writers.Texinfo
+import Text.Pandoc.Writers.HTML
+import Text.Pandoc.Writers.S5
+import Text.Pandoc.Writers.Docbook
+import Text.Pandoc.Writers.OpenDocument
+import Text.Pandoc.Writers.Man
+import Text.Pandoc.Writers.RTF
+import Text.Pandoc.Writers.MediaWiki
+import Text.Pandoc.DefaultHeaders
+import Text.Pandoc.Shared
+import Data.Version (showVersion)
+import Paths_pandoc (version)
+
+-- | Version number of pandoc library.
+pandocVersion :: String
+pandocVersion = showVersion version
diff --git a/src/Text/Pandoc/Biblio.hs b/src/Text/Pandoc/Biblio.hs
new file mode 100644
index 000000000..436eadd68
--- /dev/null
+++ b/src/Text/Pandoc/Biblio.hs
@@ -0,0 +1,66 @@
+{-# LANGUAGE PatternGuards #-}
+{-
+Copyright (C) 2008 Andrea Rossato <andrea.rossato@ing.unitn.it>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Biblio
+ Copyright : Copyright (C) 2008 Andrea Rossato
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Andrea Rossato <andrea.rossato@ing.unitn.it>
+ Stability : alpha
+ Portability : portable
+-}
+
+module Text.Pandoc.Biblio ( processBiblio ) where
+
+import Control.Monad ( when )
+import Data.List
+import Text.CSL
+import Text.Pandoc.Definition
+
+-- | Process a 'Pandoc' document by adding citations formatted
+-- according to a CSL style, using 'citeproc' from citeproc-hs.
+processBiblio :: String -> [Reference] -> Pandoc -> IO Pandoc
+processBiblio cf r p
+ = if null r then return p
+ else do
+ when (null cf) $ error "Missing the needed citation style file"
+ csl <- readCSLFile cf
+ let groups = queryWith getCite p
+ result = citeproc csl r groups
+ cits_map = zip groups (citations result)
+ biblioList = map (read . renderPandoc' csl) (bibliography result)
+ Pandoc m b = processWith (processCite csl cits_map) p
+ return $ Pandoc m $ b ++ biblioList
+
+-- | Substitute 'Cite' elements with formatted citations.
+processCite :: Style -> [([Target],[FormattedOutput])] -> Inline -> Inline
+processCite s cs il
+ | Cite t _ <- il = Cite t (process t)
+ | otherwise = il
+ where
+ process t = case elemIndex t (map fst cs) of
+ Just i -> read . renderPandoc s $ snd (cs !! i)
+ Nothing -> [Str ("Error processing " ++ show t)]
+
+-- | Retrieve all citations from a 'Pandoc' docuument. To be used with
+-- 'queryWith'.
+getCite :: Inline -> [[(String,String)]]
+getCite i | Cite t _ <- i = [t]
+ | otherwise = []
diff --git a/src/Text/Pandoc/Blocks.hs b/src/Text/Pandoc/Blocks.hs
new file mode 100644
index 000000000..122931773
--- /dev/null
+++ b/src/Text/Pandoc/Blocks.hs
@@ -0,0 +1,146 @@
+{-
+Copyright (C) 2007 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Blocks
+ Copyright : Copyright (C) 2007 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Functions for the manipulation of fixed-width blocks of text.
+These are used in the construction of plain-text tables.
+-}
+
+module Text.Pandoc.Blocks
+ (
+ TextBlock (..),
+ docToBlock,
+ blockToDoc,
+ widthOfBlock,
+ heightOfBlock,
+ hcatBlocks,
+ hsepBlocks,
+ centerAlignBlock,
+ leftAlignBlock,
+ rightAlignBlock
+ )
+where
+import Text.PrettyPrint
+import Data.List ( intersperse )
+
+-- | A fixed-width block of text. Parameters are width of block,
+-- height of block, and list of lines.
+data TextBlock = TextBlock Int Int [String]
+instance Show TextBlock where
+ show x = show $ blockToDoc x
+
+-- | Break lines in a list of lines so that none are greater than
+-- a given width.
+breakLines :: Int -- ^ Maximum length of lines.
+ -> [String] -- ^ List of lines.
+ -> [String]
+breakLines _ [] = []
+breakLines width (l:ls) =
+ if length l > width
+ then (take width l):(breakLines width ((drop width l):ls))
+ else l:(breakLines width ls)
+
+-- | Convert a @Doc@ element into a @TextBlock@ with a specified width.
+docToBlock :: Int -- ^ Width of text block.
+ -> Doc -- ^ @Doc@ to convert.
+ -> TextBlock
+docToBlock width doc =
+ let rendered = renderStyle (style {lineLength = width,
+ ribbonsPerLine = 1}) doc
+ lns = breakLines width $ lines rendered
+ in TextBlock width (length lns) lns
+
+-- | Convert a @TextBlock@ to a @Doc@ element.
+blockToDoc :: TextBlock -> Doc
+blockToDoc (TextBlock _ _ lns) =
+ if null lns
+ then empty
+ else vcat $ map text lns
+
+-- | Returns width of a @TextBlock@ (number of columns).
+widthOfBlock :: TextBlock -> Int
+widthOfBlock (TextBlock width _ _) = width
+
+-- | Returns height of a @TextBlock@ (number of rows).
+heightOfBlock :: TextBlock -> Int
+heightOfBlock (TextBlock _ height _) = height
+
+-- | Pads a string out to a given width using spaces.
+hPad :: Int -- ^ Desired width.
+ -> String -- ^ String to pad.
+ -> String
+hPad width line =
+ let linelen = length line
+ in if linelen <= width
+ then line ++ replicate (width - linelen) ' '
+ else take width line
+
+-- | Concatenates a list of @TextBlock@s into a new @TextBlock@ in
+-- which they appear side by side.
+hcatBlocks :: [TextBlock] -> TextBlock
+hcatBlocks [] = TextBlock 0 0 []
+hcatBlocks [x] = x -- This is not redundant! We don't want last item hPad'd.
+hcatBlocks ((TextBlock width1 height1 lns1):xs) =
+ let (TextBlock width2 height2 lns2) = hcatBlocks xs
+ height = max height1 height2
+ width = width1 + width2
+ lns1' = map (hPad width1) $ lns1 ++ replicate (height - height1) ""
+ lns2' = lns2 ++ replicate (height - height2) ""
+ lns = zipWith (++) lns1' lns2'
+ in TextBlock width height lns
+
+-- | Like @hcatBlocks@, but inserts space between the @TextBlock@s.
+hsepBlocks :: [TextBlock] -> TextBlock
+hsepBlocks = hcatBlocks . (intersperse (TextBlock 1 1 [" "]))
+
+isWhitespace :: Char -> Bool
+isWhitespace x = x `elem` " \t"
+
+-- | Left-aligns the contents of a @TextBlock@ within the block.
+leftAlignBlock :: TextBlock -> TextBlock
+leftAlignBlock (TextBlock width height lns) =
+ TextBlock width height $ map (dropWhile isWhitespace) lns
+
+-- | Right-aligns the contents of a @TextBlock@ within the block.
+rightAlignBlock :: TextBlock -> TextBlock
+rightAlignBlock (TextBlock width height lns) =
+ let rightAlignLine ln =
+ let (spaces, rest) = span isWhitespace $ reverse $ hPad width ln
+ in reverse (rest ++ spaces)
+ in TextBlock width height $ map rightAlignLine lns
+
+-- | Centers the contents of a @TextBlock@ within the block.
+centerAlignBlock :: TextBlock -> TextBlock
+centerAlignBlock (TextBlock width height lns) =
+ let centerAlignLine ln =
+ let ln' = hPad width ln
+ (startSpaces, rest) = span isWhitespace ln'
+ endSpaces = takeWhile isWhitespace (reverse ln')
+ numSpaces = length (startSpaces ++ endSpaces)
+ startSpaces' = replicate (quot numSpaces 2) ' '
+ in startSpaces' ++ rest
+ in TextBlock width height $ map centerAlignLine lns
+
diff --git a/src/Text/Pandoc/CharacterReferences.hs b/src/Text/Pandoc/CharacterReferences.hs
new file mode 100644
index 000000000..ac517ddf0
--- /dev/null
+++ b/src/Text/Pandoc/CharacterReferences.hs
@@ -0,0 +1,327 @@
+{-
+Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.CharacterReferences
+ Copyright : Copyright (C) 2006-7 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Functions for parsing character references.
+-}
+module Text.Pandoc.CharacterReferences (
+ characterReference,
+ decodeCharacterReferences,
+ ) where
+import Data.Char ( chr )
+import Text.ParserCombinators.Parsec
+import qualified Data.Map as Map
+
+-- | Parse character entity.
+characterReference :: GenParser Char st Char
+characterReference = try $ do
+ char '&'
+ character <- numRef <|> entity
+ char ';'
+ return character
+
+numRef :: GenParser Char st Char
+numRef = do
+ char '#'
+ num <- hexNum <|> decNum
+ return $ chr $ num
+
+hexNum :: GenParser Char st Int
+hexNum = oneOf "Xx" >> many1 hexDigit >>= return . read . (\xs -> '0':'x':xs)
+
+decNum :: GenParser Char st Int
+decNum = many1 digit >>= return . read
+
+entity :: GenParser Char st Char
+entity = do
+ body <- many1 alphaNum
+ return $ Map.findWithDefault '?' body entityTable
+
+-- | Convert entities in a string to characters.
+decodeCharacterReferences :: String -> String
+decodeCharacterReferences str =
+ case parse (many (characterReference <|> anyChar)) str str of
+ Left err -> error $ "\nError: " ++ show err
+ Right result -> result
+
+entityTable :: Map.Map String Char
+entityTable = Map.fromList entityTableList
+
+entityTableList :: [(String, Char)]
+entityTableList = [
+ ("quot", chr 34),
+ ("amp", chr 38),
+ ("lt", chr 60),
+ ("gt", chr 62),
+ ("nbsp", chr 160),
+ ("iexcl", chr 161),
+ ("cent", chr 162),
+ ("pound", chr 163),
+ ("curren", chr 164),
+ ("yen", chr 165),
+ ("brvbar", chr 166),
+ ("sect", chr 167),
+ ("uml", chr 168),
+ ("copy", chr 169),
+ ("ordf", chr 170),
+ ("laquo", chr 171),
+ ("not", chr 172),
+ ("shy", chr 173),
+ ("reg", chr 174),
+ ("macr", chr 175),
+ ("deg", chr 176),
+ ("plusmn", chr 177),
+ ("sup2", chr 178),
+ ("sup3", chr 179),
+ ("acute", chr 180),
+ ("micro", chr 181),
+ ("para", chr 182),
+ ("middot", chr 183),
+ ("cedil", chr 184),
+ ("sup1", chr 185),
+ ("ordm", chr 186),
+ ("raquo", chr 187),
+ ("frac14", chr 188),
+ ("frac12", chr 189),
+ ("frac34", chr 190),
+ ("iquest", chr 191),
+ ("Agrave", chr 192),
+ ("Aacute", chr 193),
+ ("Acirc", chr 194),
+ ("Atilde", chr 195),
+ ("Auml", chr 196),
+ ("Aring", chr 197),
+ ("AElig", chr 198),
+ ("Ccedil", chr 199),
+ ("Egrave", chr 200),
+ ("Eacute", chr 201),
+ ("Ecirc", chr 202),
+ ("Euml", chr 203),
+ ("Igrave", chr 204),
+ ("Iacute", chr 205),
+ ("Icirc", chr 206),
+ ("Iuml", chr 207),
+ ("ETH", chr 208),
+ ("Ntilde", chr 209),
+ ("Ograve", chr 210),
+ ("Oacute", chr 211),
+ ("Ocirc", chr 212),
+ ("Otilde", chr 213),
+ ("Ouml", chr 214),
+ ("times", chr 215),
+ ("Oslash", chr 216),
+ ("Ugrave", chr 217),
+ ("Uacute", chr 218),
+ ("Ucirc", chr 219),
+ ("Uuml", chr 220),
+ ("Yacute", chr 221),
+ ("THORN", chr 222),
+ ("szlig", chr 223),
+ ("agrave", chr 224),
+ ("aacute", chr 225),
+ ("acirc", chr 226),
+ ("atilde", chr 227),
+ ("auml", chr 228),
+ ("aring", chr 229),
+ ("aelig", chr 230),
+ ("ccedil", chr 231),
+ ("egrave", chr 232),
+ ("eacute", chr 233),
+ ("ecirc", chr 234),
+ ("euml", chr 235),
+ ("igrave", chr 236),
+ ("iacute", chr 237),
+ ("icirc", chr 238),
+ ("iuml", chr 239),
+ ("eth", chr 240),
+ ("ntilde", chr 241),
+ ("ograve", chr 242),
+ ("oacute", chr 243),
+ ("ocirc", chr 244),
+ ("otilde", chr 245),
+ ("ouml", chr 246),
+ ("divide", chr 247),
+ ("oslash", chr 248),
+ ("ugrave", chr 249),
+ ("uacute", chr 250),
+ ("ucirc", chr 251),
+ ("uuml", chr 252),
+ ("yacute", chr 253),
+ ("thorn", chr 254),
+ ("yuml", chr 255),
+ ("OElig", chr 338),
+ ("oelig", chr 339),
+ ("Scaron", chr 352),
+ ("scaron", chr 353),
+ ("Yuml", chr 376),
+ ("fnof", chr 402),
+ ("circ", chr 710),
+ ("tilde", chr 732),
+ ("Alpha", chr 913),
+ ("Beta", chr 914),
+ ("Gamma", chr 915),
+ ("Delta", chr 916),
+ ("Epsilon", chr 917),
+ ("Zeta", chr 918),
+ ("Eta", chr 919),
+ ("Theta", chr 920),
+ ("Iota", chr 921),
+ ("Kappa", chr 922),
+ ("Lambda", chr 923),
+ ("Mu", chr 924),
+ ("Nu", chr 925),
+ ("Xi", chr 926),
+ ("Omicron", chr 927),
+ ("Pi", chr 928),
+ ("Rho", chr 929),
+ ("Sigma", chr 931),
+ ("Tau", chr 932),
+ ("Upsilon", chr 933),
+ ("Phi", chr 934),
+ ("Chi", chr 935),
+ ("Psi", chr 936),
+ ("Omega", chr 937),
+ ("alpha", chr 945),
+ ("beta", chr 946),
+ ("gamma", chr 947),
+ ("delta", chr 948),
+ ("epsilon", chr 949),
+ ("zeta", chr 950),
+ ("eta", chr 951),
+ ("theta", chr 952),
+ ("iota", chr 953),
+ ("kappa", chr 954),
+ ("lambda", chr 955),
+ ("mu", chr 956),
+ ("nu", chr 957),
+ ("xi", chr 958),
+ ("omicron", chr 959),
+ ("pi", chr 960),
+ ("rho", chr 961),
+ ("sigmaf", chr 962),
+ ("sigma", chr 963),
+ ("tau", chr 964),
+ ("upsilon", chr 965),
+ ("phi", chr 966),
+ ("chi", chr 967),
+ ("psi", chr 968),
+ ("omega", chr 969),
+ ("thetasym", chr 977),
+ ("upsih", chr 978),
+ ("piv", chr 982),
+ ("ensp", chr 8194),
+ ("emsp", chr 8195),
+ ("thinsp", chr 8201),
+ ("zwnj", chr 8204),
+ ("zwj", chr 8205),
+ ("lrm", chr 8206),
+ ("rlm", chr 8207),
+ ("ndash", chr 8211),
+ ("mdash", chr 8212),
+ ("lsquo", chr 8216),
+ ("rsquo", chr 8217),
+ ("sbquo", chr 8218),
+ ("ldquo", chr 8220),
+ ("rdquo", chr 8221),
+ ("bdquo", chr 8222),
+ ("dagger", chr 8224),
+ ("Dagger", chr 8225),
+ ("bull", chr 8226),
+ ("hellip", chr 8230),
+ ("permil", chr 8240),
+ ("prime", chr 8242),
+ ("Prime", chr 8243),
+ ("lsaquo", chr 8249),
+ ("rsaquo", chr 8250),
+ ("oline", chr 8254),
+ ("frasl", chr 8260),
+ ("euro", chr 8364),
+ ("image", chr 8465),
+ ("weierp", chr 8472),
+ ("real", chr 8476),
+ ("trade", chr 8482),
+ ("alefsym", chr 8501),
+ ("larr", chr 8592),
+ ("uarr", chr 8593),
+ ("rarr", chr 8594),
+ ("darr", chr 8595),
+ ("harr", chr 8596),
+ ("crarr", chr 8629),
+ ("lArr", chr 8656),
+ ("uArr", chr 8657),
+ ("rArr", chr 8658),
+ ("dArr", chr 8659),
+ ("hArr", chr 8660),
+ ("forall", chr 8704),
+ ("part", chr 8706),
+ ("exist", chr 8707),
+ ("empty", chr 8709),
+ ("nabla", chr 8711),
+ ("isin", chr 8712),
+ ("notin", chr 8713),
+ ("ni", chr 8715),
+ ("prod", chr 8719),
+ ("sum", chr 8721),
+ ("minus", chr 8722),
+ ("lowast", chr 8727),
+ ("radic", chr 8730),
+ ("prop", chr 8733),
+ ("infin", chr 8734),
+ ("ang", chr 8736),
+ ("and", chr 8743),
+ ("or", chr 8744),
+ ("cap", chr 8745),
+ ("cup", chr 8746),
+ ("int", chr 8747),
+ ("there4", chr 8756),
+ ("sim", chr 8764),
+ ("cong", chr 8773),
+ ("asymp", chr 8776),
+ ("ne", chr 8800),
+ ("equiv", chr 8801),
+ ("le", chr 8804),
+ ("ge", chr 8805),
+ ("sub", chr 8834),
+ ("sup", chr 8835),
+ ("nsub", chr 8836),
+ ("sube", chr 8838),
+ ("supe", chr 8839),
+ ("oplus", chr 8853),
+ ("otimes", chr 8855),
+ ("perp", chr 8869),
+ ("sdot", chr 8901),
+ ("lceil", chr 8968),
+ ("rceil", chr 8969),
+ ("lfloor", chr 8970),
+ ("rfloor", chr 8971),
+ ("lang", chr 9001),
+ ("rang", chr 9002),
+ ("loz", chr 9674),
+ ("spades", chr 9824),
+ ("clubs", chr 9827),
+ ("hearts", chr 9829),
+ ("diams", chr 9830)
+ ]
diff --git a/src/Text/Pandoc/DefaultHeaders.hs b/src/Text/Pandoc/DefaultHeaders.hs
new file mode 100644
index 000000000..e9c1f17e5
--- /dev/null
+++ b/src/Text/Pandoc/DefaultHeaders.hs
@@ -0,0 +1,69 @@
+{-# LANGUAGE CPP, TemplateHaskell #-}
+{-
+Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.DefaultHeaders
+ Copyright : Copyright (C) 2006-7 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Default headers for Pandoc writers.
+-}
+module Text.Pandoc.DefaultHeaders (
+ defaultLaTeXHeader,
+ defaultConTeXtHeader,
+ defaultDocbookHeader,
+ defaultOpenDocumentHeader,
+ defaultS5Header,
+ defaultRTFHeader
+ ) where
+import Text.Pandoc.Writers.S5
+import System.FilePath ( (</>) )
+import Text.Pandoc.TH ( contentsOf )
+
+defaultLaTeXHeader :: String
+#ifndef __HADDOCK__
+defaultLaTeXHeader = $(contentsOf $ "data" </> "headers" </> "LaTeX.header")
+#endif
+
+defaultConTeXtHeader :: String
+#ifndef __HADDOCK__
+defaultConTeXtHeader = $(contentsOf $ "data" </> "headers" </> "ConTeXt.header")
+#endif
+
+defaultDocbookHeader :: String
+#ifndef __HADDOCK__
+defaultDocbookHeader = $(contentsOf $ "data" </> "headers" </> "Docbook.header")
+#endif
+
+defaultOpenDocumentHeader :: String
+#ifndef __HADDOCK__
+defaultOpenDocumentHeader = $(contentsOf $ "data" </> "headers" </> "OpenDocument.header")
+#endif
+
+defaultS5Header :: String
+defaultS5Header = s5Meta ++ s5CSS ++ s5Javascript
+
+defaultRTFHeader :: String
+#ifndef __HADDOCK__
+defaultRTFHeader = $(contentsOf $ "data" </> "headers" </> "RTF.header")
+#endif
diff --git a/src/Text/Pandoc/Definition.hs b/src/Text/Pandoc/Definition.hs
new file mode 100644
index 000000000..92ce094d4
--- /dev/null
+++ b/src/Text/Pandoc/Definition.hs
@@ -0,0 +1,150 @@
+{-# OPTIONS_GHC -fglasgow-exts #-} -- for deriving Typeable
+{-
+Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Definition
+ Copyright : Copyright (C) 2006-7 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Definition of 'Pandoc' data structure for format-neutral representation
+of documents.
+-}
+module Text.Pandoc.Definition where
+
+import Data.Generics
+
+data Pandoc = Pandoc Meta [Block] deriving (Eq, Read, Show, Typeable, Data)
+
+-- | Bibliographic information for the document: title (list of 'Inline'),
+-- authors (list of strings), date (string).
+data Meta = Meta [Inline] -- title
+ [String] -- authors
+ String -- date
+ deriving (Eq, Show, Read, Typeable, Data)
+
+-- | Alignment of a table column.
+data Alignment = AlignLeft
+ | AlignRight
+ | AlignCenter
+ | AlignDefault deriving (Eq, Show, Read, Typeable, Data)
+
+-- | List attributes.
+type ListAttributes = (Int, ListNumberStyle, ListNumberDelim)
+
+-- | Style of list numbers.
+data ListNumberStyle = DefaultStyle
+ | Decimal
+ | LowerRoman
+ | UpperRoman
+ | LowerAlpha
+ | UpperAlpha deriving (Eq, Show, Read, Typeable, Data)
+
+-- | Delimiter of list numbers.
+data ListNumberDelim = DefaultDelim
+ | Period
+ | OneParen
+ | TwoParens deriving (Eq, Show, Read, Typeable, Data)
+
+-- | Attributes: identifier, classes, key-value pairs
+type Attr = (String, [String], [(String, String)])
+
+-- | Block element.
+data Block
+ = Plain [Inline] -- ^ Plain text, not a paragraph
+ | Para [Inline] -- ^ Paragraph
+ | CodeBlock Attr String -- ^ Code block (literal) with attributes
+ | RawHtml String -- ^ Raw HTML block (literal)
+ | BlockQuote [Block] -- ^ Block quote (list of blocks)
+ | OrderedList ListAttributes [[Block]] -- ^ Ordered list (attributes
+ -- and a list of items, each a list of blocks)
+ | BulletList [[Block]] -- ^ Bullet list (list of items, each
+ -- a list of blocks)
+ | DefinitionList [([Inline],[Block])] -- ^ Definition list
+ -- (list of items, each a pair of an inline list,
+ -- the term, and a block list)
+ | Header Int [Inline] -- ^ Header - level (integer) and text (inlines)
+ | HorizontalRule -- ^ Horizontal rule
+ | Table [Inline] [Alignment] [Double] [[Block]] [[[Block]]] -- ^ Table,
+ -- with caption, column alignments,
+ -- relative column widths, column headers
+ -- (each a list of blocks), and rows
+ -- (each a list of lists of blocks)
+ | Null -- ^ Nothing
+ deriving (Eq, Read, Show, Typeable, Data)
+
+-- | Type of quotation marks to use in Quoted inline.
+data QuoteType = SingleQuote | DoubleQuote deriving (Show, Eq, Read, Typeable, Data)
+
+-- | Link target (URL, title).
+type Target = (String, String)
+
+-- | Type of math element (display or inline).
+data MathType = DisplayMath | InlineMath deriving (Show, Eq, Read, Typeable, Data)
+
+-- | Inline elements.
+data Inline
+ = Str String -- ^ Text (string)
+ | Emph [Inline] -- ^ Emphasized text (list of inlines)
+ | Strong [Inline] -- ^ Strongly emphasized text (list of inlines)
+ | Strikeout [Inline] -- ^ Strikeout text (list of inlines)
+ | Superscript [Inline] -- ^ Superscripted text (list of inlines)
+ | Subscript [Inline] -- ^ Subscripted text (list of inlines)
+ | SmallCaps [Inline] -- ^ Small caps text (list of inlines)
+ | Quoted QuoteType [Inline] -- ^ Quoted text (list of inlines)
+ | Cite [Target] [Inline] -- ^ Citation (list of inlines)
+ | Code String -- ^ Inline code (literal)
+ | Space -- ^ Inter-word space
+ | EmDash -- ^ Em dash
+ | EnDash -- ^ En dash
+ | Apostrophe -- ^ Apostrophe
+ | Ellipses -- ^ Ellipses
+ | LineBreak -- ^ Hard line break
+ | Math MathType String -- ^ TeX math (literal)
+ | TeX String -- ^ LaTeX code (literal)
+ | HtmlInline String -- ^ HTML code (literal)
+ | Link [Inline] Target -- ^ Hyperlink: text (list of inlines), target
+ | Image [Inline] Target -- ^ Image: alt text (list of inlines), target
+ -- and target
+ | Note [Block] -- ^ Footnote or endnote
+ deriving (Show, Eq, Read, Typeable, Data)
+
+-- | Applies a transformation on @a@s to matching elements in a @b@.
+processWith :: (Data a, Data b) => (a -> a) -> b -> b
+processWith f = everywhere (mkT f)
+
+-- | Like 'processWith', but with monadic transformations.
+processWithM :: (Monad m, Data a, Data b) => (a -> m a) -> b -> m b
+processWithM f = everywhereM (mkM f)
+
+-- | Runs a query on matching @a@ elements in a @c@.
+queryWith :: (Data a, Data c) => (a -> [b]) -> c -> [b]
+queryWith f = everything (++) ([] `mkQ` f)
+
+{-# DEPRECATED processPandoc "Use processWith instead" #-}
+processPandoc :: Data a => (a -> a) -> Pandoc -> Pandoc
+processPandoc = processWith
+
+{-# DEPRECATED queryPandoc "Use queryWith instead" #-}
+queryPandoc :: Data a => (a -> [b]) -> Pandoc -> [b]
+queryPandoc = queryWith
+
diff --git a/src/Text/Pandoc/Highlighting.hs b/src/Text/Pandoc/Highlighting.hs
new file mode 100644
index 000000000..6a88e5d70
--- /dev/null
+++ b/src/Text/Pandoc/Highlighting.hs
@@ -0,0 +1,67 @@
+{-# LANGUAGE CPP #-}
+{-
+Copyright (C) 2008 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Highlighting
+ Copyright : Copyright (C) 2008 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Exports functions for syntax highlighting.
+-}
+
+module Text.Pandoc.Highlighting ( languages, highlightHtml, defaultHighlightingCss, languagesByExtension ) where
+import Text.XHtml
+import Text.Pandoc.Definition
+#ifdef _HIGHLIGHTING
+import Text.Highlighting.Kate ( languages, highlightAs, formatAsXHtml, FormatOption (..), defaultHighlightingCss, languagesByExtension )
+import Data.List (find, lookup)
+import Data.Maybe (fromMaybe)
+import Data.Char (toLower)
+
+highlightHtml :: Attr -> String -> Either String Html
+highlightHtml (_, classes, keyvals) rawCode =
+ let firstNum = read $ fromMaybe "1" $ lookup "startFrom" keyvals
+ fmtOpts = [OptNumberFrom firstNum] ++
+ case find (`elem` ["number","numberLines","number-lines"]) classes of
+ Nothing -> []
+ Just _ -> [OptNumberLines]
+ lcLanguages = map (map toLower) languages
+ in case find (\c -> (map toLower c) `elem` lcLanguages) classes of
+ Nothing -> Left "Unknown or unsupported language"
+ Just language -> case highlightAs language rawCode of
+ Left err -> Left err
+ Right hl -> Right $ formatAsXHtml fmtOpts language hl
+
+#else
+defaultHighlightingCss :: String
+defaultHighlightingCss = ""
+
+languages :: [String]
+languages = []
+
+languagesByExtension :: String -> [String]
+languagesByExtension _ = []
+
+highlightHtml :: Attr -> String -> Either String Html
+highlightHtml _ _ = Left "Pandoc was not compiled with support for highlighting"
+#endif
diff --git a/src/Text/Pandoc/LaTeXMathML.hs b/src/Text/Pandoc/LaTeXMathML.hs
new file mode 100644
index 000000000..1eb3c23cc
--- /dev/null
+++ b/src/Text/Pandoc/LaTeXMathML.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE CPP, TemplateHaskell #-}
+-- | Definitions for use of LaTeXMathML in HTML.
+-- (See <http://math.etsu.edu/LaTeXMathML/>)
+module Text.Pandoc.LaTeXMathML ( latexMathMLScript ) where
+import Text.Pandoc.TH ( contentsOf )
+import System.FilePath ( (</>) )
+
+-- | String containing LaTeXMathML javascript.
+latexMathMLScript :: String
+#ifndef __HADDOCK__
+latexMathMLScript = "<script type=\"text/javascript\">\n" ++
+ $(contentsOf $ "data" </> "LaTeXMathML.js.comment") ++
+ $(contentsOf $ "data" </> "LaTeXMathML.js.packed") ++ "</script>\n"
+#endif
diff --git a/src/Text/Pandoc/ODT.hs b/src/Text/Pandoc/ODT.hs
new file mode 100644
index 000000000..f9e4dd8f1
--- /dev/null
+++ b/src/Text/Pandoc/ODT.hs
@@ -0,0 +1,88 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-
+Copyright (C) 2008 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.ODT
+ Copyright : Copyright (C) 2006-7 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Functions for producing an ODT file from OpenDocument XML.
+-}
+module Text.Pandoc.ODT ( saveOpenDocumentAsODT ) where
+import Text.Pandoc.TH ( makeZip )
+import Data.List ( find )
+import System.FilePath ( (</>), takeFileName )
+import qualified Data.ByteString.Lazy as B
+import Data.ByteString.Lazy.UTF8 ( fromString )
+import Prelude hiding ( writeFile, readFile )
+import Codec.Archive.Zip
+import Control.Applicative ( (<$>) )
+import Text.ParserCombinators.Parsec
+import System.Time
+
+-- | Produce an ODT file from OpenDocument XML.
+saveOpenDocumentAsODT :: FilePath -- ^ Pathname of ODT file to be produced.
+ -> FilePath -- ^ Relative directory of source file.
+ -> String -- ^ OpenDocument XML contents.
+ -> IO ()
+saveOpenDocumentAsODT destinationODTPath sourceDirRelative xml = do
+ let refArchive = read $(makeZip $ "data" </> "odt-styles")
+ -- handle pictures
+ let (newContents, pics) =
+ case runParser pPictures [] "OpenDocument XML contents" xml of
+ Left err -> error $ show err
+ Right x -> x
+ picEntries <- mapM (makePictureEntry sourceDirRelative) pics
+ (TOD epochTime _) <- getClockTime
+ let contentEntry = toEntry "content.xml" epochTime $ fromString newContents
+ let archive = foldr addEntryToArchive refArchive (contentEntry : picEntries)
+ B.writeFile destinationODTPath $ fromArchive archive
+
+makePictureEntry :: FilePath -- ^ Relative directory of source file
+ -> (FilePath, String) -- ^ Path and new path of picture
+ -> IO Entry
+makePictureEntry sourceDirRelative (path, newPath) = do
+ entry <- readEntry [] $ sourceDirRelative </> path
+ return (entry { eRelativePath = newPath })
+
+pPictures :: GenParser Char [(FilePath, String)] ([Char], [(FilePath, String)])
+pPictures = do
+ contents <- concat <$> many (pPicture <|> many1 (noneOf "<") <|> string "<")
+ pics <- getState
+ return (contents, pics)
+
+pPicture :: GenParser Char [(FilePath, String)] [Char]
+pPicture = try $ do
+ string "<draw:image xlink:href=\""
+ path <- manyTill anyChar (char '"')
+ let filename = takeFileName path
+ pics <- getState
+ newPath <- case find (\(o, _) -> o == path) pics of
+ Just (_, new) -> return new
+ Nothing -> do
+ -- get a unique name
+ let dups = length $ (filter (\(o, _) -> takeFileName o == filename)) pics
+ let new = "Pictures/" ++ replicate dups '0' ++ filename
+ updateState ((path, new) :)
+ return new
+ return $ "<draw:image xlink:href=\"" ++ newPath ++ "\""
diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs
new file mode 100644
index 000000000..c988c68d2
--- /dev/null
+++ b/src/Text/Pandoc/Readers/HTML.hs
@@ -0,0 +1,677 @@
+{-
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.HTML
+ Copyright : Copyright (C) 2006-8 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of HTML to 'Pandoc' document.
+-}
+module Text.Pandoc.Readers.HTML (
+ readHtml,
+ rawHtmlInline,
+ rawHtmlBlock,
+ anyHtmlBlockTag,
+ anyHtmlInlineTag,
+ anyHtmlTag,
+ anyHtmlEndTag,
+ htmlEndTag,
+ extractTagType,
+ htmlBlockElement,
+ unsanitaryURI
+ ) where
+
+import Text.ParserCombinators.Parsec
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Text.Pandoc.CharacterReferences ( decodeCharacterReferences )
+import Data.Maybe ( fromMaybe )
+import Data.List ( takeWhile, dropWhile, isPrefixOf, isSuffixOf, intercalate )
+import Data.Char ( toLower, isAlphaNum )
+import Network.URI ( parseURIReference, URI (..) )
+
+-- | Convert HTML-formatted string to 'Pandoc' document.
+readHtml :: ParserState -- ^ Parser state
+ -> String -- ^ String to parse
+ -> Pandoc
+readHtml = readWith parseHtml
+
+--
+-- Constants
+--
+
+eitherBlockOrInline :: [[Char]]
+eitherBlockOrInline = ["applet", "button", "del", "iframe", "ins",
+ "map", "area", "object"]
+
+{-
+inlineHtmlTags :: [[Char]]
+inlineHtmlTags = ["a", "abbr", "acronym", "b", "basefont", "bdo", "big",
+ "br", "cite", "code", "dfn", "em", "font", "i", "img",
+ "input", "kbd", "label", "q", "s", "samp", "select",
+ "small", "span", "strike", "strong", "sub", "sup",
+ "textarea", "tt", "u", "var"] ++ eitherBlockOrInline
+-}
+
+blockHtmlTags :: [[Char]]
+blockHtmlTags = ["address", "blockquote", "body", "center", "dir", "div",
+ "dl", "fieldset", "form", "h1", "h2", "h3", "h4",
+ "h5", "h6", "hr", "html", "isindex", "menu", "noframes",
+ "noscript", "ol", "p", "pre", "table", "ul", "dd",
+ "dt", "frameset", "li", "tbody", "td", "tfoot",
+ "th", "thead", "tr", "script"] ++ eitherBlockOrInline
+
+sanitaryTags :: [[Char]]
+sanitaryTags = ["a", "abbr", "acronym", "address", "area", "b", "big",
+ "blockquote", "br", "button", "caption", "center",
+ "cite", "code", "col", "colgroup", "dd", "del", "dfn",
+ "dir", "div", "dl", "dt", "em", "fieldset", "font",
+ "form", "h1", "h2", "h3", "h4", "h5", "h6", "hr",
+ "i", "img", "input", "ins", "kbd", "label", "legend",
+ "li", "map", "menu", "ol", "optgroup", "option", "p",
+ "pre", "q", "s", "samp", "select", "small", "span",
+ "strike", "strong", "sub", "sup", "table", "tbody",
+ "td", "textarea", "tfoot", "th", "thead", "tr", "tt",
+ "u", "ul", "var"]
+
+sanitaryAttributes :: [[Char]]
+sanitaryAttributes = ["abbr", "accept", "accept-charset",
+ "accesskey", "action", "align", "alt", "axis",
+ "border", "cellpadding", "cellspacing", "char",
+ "charoff", "charset", "checked", "cite", "class",
+ "clear", "cols", "colspan", "color", "compact",
+ "coords", "datetime", "dir", "disabled",
+ "enctype", "for", "frame", "headers", "height",
+ "href", "hreflang", "hspace", "id", "ismap",
+ "label", "lang", "longdesc", "maxlength", "media",
+ "method", "multiple", "name", "nohref", "noshade",
+ "nowrap", "prompt", "readonly", "rel", "rev",
+ "rows", "rowspan", "rules", "scope", "selected",
+ "shape", "size", "span", "src", "start",
+ "summary", "tabindex", "target", "title", "type",
+ "usemap", "valign", "value", "vspace", "width"]
+
+--
+-- HTML utility functions
+--
+
+-- | Returns @True@ if sanitization is specified and the specified tag is
+-- not on the sanitized tag list.
+unsanitaryTag :: [Char]
+ -> GenParser tok ParserState Bool
+unsanitaryTag tag = do
+ st <- getState
+ return $ stateSanitizeHTML st && tag `notElem` sanitaryTags
+
+-- | returns @True@ if sanitization is specified and the specified attribute
+-- is not on the sanitized attribute list.
+unsanitaryAttribute :: ([Char], String, t)
+ -> GenParser tok ParserState Bool
+unsanitaryAttribute (attr, val, _) = do
+ st <- getState
+ return $ stateSanitizeHTML st &&
+ (attr `notElem` sanitaryAttributes ||
+ (attr `elem` ["href","src"] && unsanitaryURI val))
+
+-- | Returns @True@ if the specified URI is potentially a security risk.
+unsanitaryURI :: String -> Bool
+unsanitaryURI u =
+ let safeURISchemes = [ "", "http:", "https:", "ftp:", "mailto:", "file:",
+ "telnet:", "gopher:", "aaa:", "aaas:", "acap:", "cap:", "cid:",
+ "crid:", "dav:", "dict:", "dns:", "fax:", "go:", "h323:", "im:",
+ "imap:", "ldap:", "mid:", "news:", "nfs:", "nntp:", "pop:",
+ "pres:", "sip:", "sips:", "snmp:", "tel:", "urn:", "wais:",
+ "xmpp:", "z39.50r:", "z39.50s:", "aim:", "callto:", "cvs:",
+ "ed2k:", "feed:", "fish:", "gg:", "irc:", "ircs:", "lastfm:",
+ "ldaps:", "magnet:", "mms:", "msnim:", "notes:", "rsync:",
+ "secondlife:", "skype:", "ssh:", "sftp:", "smb:", "sms:",
+ "snews:", "webcal:", "ymsgr:"]
+ in case parseURIReference u of
+ Just p -> (map toLower $ uriScheme p) `notElem` safeURISchemes
+ Nothing -> True
+
+-- | Read blocks until end tag.
+blocksTilEnd :: String -> GenParser Char ParserState [Block]
+blocksTilEnd tag = do
+ blocks <- manyTill (block >>~ spaces) (htmlEndTag tag)
+ return $ filter (/= Null) blocks
+
+-- | Read inlines until end tag.
+inlinesTilEnd :: String -> GenParser Char ParserState [Inline]
+inlinesTilEnd tag = manyTill inline (htmlEndTag tag)
+
+-- | Parse blocks between open and close tag.
+blocksIn :: String -> GenParser Char ParserState [Block]
+blocksIn tag = try $ htmlTag tag >> spaces >> blocksTilEnd tag
+
+-- | Parse inlines between open and close tag.
+inlinesIn :: String -> GenParser Char ParserState [Inline]
+inlinesIn tag = try $ htmlTag tag >> spaces >> inlinesTilEnd tag
+
+-- | Extract type from a tag: e.g. @br@ from @\<br\>@
+extractTagType :: String -> String
+extractTagType ('<':rest) =
+ let isSpaceOrSlash c = c `elem` "/ \n\t" in
+ map toLower $ takeWhile isAlphaNum $ dropWhile isSpaceOrSlash rest
+extractTagType _ = ""
+
+-- | Parse any HTML tag (opening or self-closing) and return text of tag
+anyHtmlTag :: GenParser Char ParserState [Char]
+anyHtmlTag = try $ do
+ char '<'
+ spaces
+ tag <- many1 alphaNum
+ attribs <- many htmlAttribute
+ spaces
+ ender <- option "" (string "/")
+ let ender' = if null ender then "" else " /"
+ spaces
+ char '>'
+ let result = "<" ++ tag ++
+ concatMap (\(_, _, raw) -> (' ':raw)) attribs ++ ender' ++ ">"
+ unsanitary <- unsanitaryTag tag
+ if unsanitary
+ then return $ "<!-- unsafe HTML removed -->"
+ else return result
+
+anyHtmlEndTag :: GenParser Char ParserState [Char]
+anyHtmlEndTag = try $ do
+ char '<'
+ spaces
+ char '/'
+ spaces
+ tag <- many1 alphaNum
+ spaces
+ char '>'
+ let result = "</" ++ tag ++ ">"
+ unsanitary <- unsanitaryTag tag
+ if unsanitary
+ then return $ "<!-- unsafe HTML removed -->"
+ else return result
+
+htmlTag :: String -> GenParser Char ParserState (String, [(String, String)])
+htmlTag tag = try $ do
+ char '<'
+ spaces
+ stringAnyCase tag
+ attribs <- many htmlAttribute
+ spaces
+ optional (string "/")
+ spaces
+ char '>'
+ return (tag, (map (\(name, content, _) -> (name, content)) attribs))
+
+-- parses a quoted html attribute value
+quoted :: Char -> GenParser Char st (String, String)
+quoted quoteChar = do
+ result <- between (char quoteChar) (char quoteChar)
+ (many (noneOf [quoteChar]))
+ return (result, [quoteChar])
+
+nullAttribute :: ([Char], [Char], [Char])
+nullAttribute = ("", "", "")
+
+htmlAttribute :: GenParser Char ParserState ([Char], [Char], [Char])
+htmlAttribute = do
+ attr <- htmlRegularAttribute <|> htmlMinimizedAttribute
+ unsanitary <- unsanitaryAttribute attr
+ if unsanitary
+ then return nullAttribute
+ else return attr
+
+-- minimized boolean attribute
+htmlMinimizedAttribute :: GenParser Char st ([Char], [Char], [Char])
+htmlMinimizedAttribute = try $ do
+ many1 space
+ name <- many1 (choice [letter, oneOf ".-_:"])
+ return (name, name, name)
+
+htmlRegularAttribute :: GenParser Char st ([Char], [Char], [Char])
+htmlRegularAttribute = try $ do
+ many1 space
+ name <- many1 (choice [letter, oneOf ".-_:"])
+ spaces
+ char '='
+ spaces
+ (content, quoteStr) <- choice [ (quoted '\''),
+ (quoted '"'),
+ (do
+ a <- many (alphaNum <|> (oneOf "-._:"))
+ return (a,"")) ]
+ return (name, content,
+ (name ++ "=" ++ quoteStr ++ content ++ quoteStr))
+
+-- | Parse an end tag of type 'tag'
+htmlEndTag :: [Char] -> GenParser Char st [Char]
+htmlEndTag tag = try $ do
+ char '<'
+ spaces
+ char '/'
+ spaces
+ stringAnyCase tag
+ spaces
+ char '>'
+ return $ "</" ++ tag ++ ">"
+
+{-
+-- | Returns @True@ if the tag is (or can be) an inline tag.
+isInline :: String -> Bool
+isInline tag = (extractTagType tag) `elem` inlineHtmlTags
+-}
+
+-- | Returns @True@ if the tag is (or can be) a block tag.
+isBlock :: String -> Bool
+isBlock tag = (extractTagType tag) `elem` blockHtmlTags
+
+anyHtmlBlockTag :: GenParser Char ParserState [Char]
+anyHtmlBlockTag = try $ do
+ tag <- anyHtmlTag <|> anyHtmlEndTag
+ if isBlock tag then return tag else fail "not a block tag"
+
+anyHtmlInlineTag :: GenParser Char ParserState [Char]
+anyHtmlInlineTag = try $ do
+ tag <- anyHtmlTag <|> anyHtmlEndTag
+ if not (isBlock tag) then return tag else fail "not an inline tag"
+
+-- | Parses material between script tags.
+-- Scripts must be treated differently, because they can contain '<>' etc.
+htmlScript :: GenParser Char ParserState [Char]
+htmlScript = try $ do
+ open <- string "<script"
+ rest <- manyTill anyChar (htmlEndTag "script")
+ st <- getState
+ if stateSanitizeHTML st && not ("script" `elem` sanitaryTags)
+ then return "<!-- unsafe HTML removed -->"
+ else return $ open ++ rest ++ "</script>"
+
+-- | Parses material between style tags.
+-- Style tags must be treated differently, because they can contain CSS
+htmlStyle :: GenParser Char ParserState [Char]
+htmlStyle = try $ do
+ open <- string "<style"
+ rest <- manyTill anyChar (htmlEndTag "style")
+ st <- getState
+ if stateSanitizeHTML st && not ("style" `elem` sanitaryTags)
+ then return "<!-- unsafe HTML removed -->"
+ else return $ open ++ rest ++ "</style>"
+
+htmlBlockElement :: GenParser Char ParserState [Char]
+htmlBlockElement = choice [ htmlScript, htmlStyle, htmlComment, xmlDec, definition ]
+
+rawHtmlBlock :: GenParser Char ParserState Block
+rawHtmlBlock = try $ do
+ body <- htmlBlockElement <|> rawVerbatimBlock <|> anyHtmlBlockTag
+ state <- getState
+ if stateParseRaw state then return (RawHtml body) else return Null
+
+-- This is a block whose contents should be passed through verbatim, not interpreted.
+rawVerbatimBlock :: GenParser Char ParserState [Char]
+rawVerbatimBlock = try $ do
+ start <- anyHtmlBlockTag
+ let tagtype = extractTagType start
+ if tagtype `elem` ["pre"]
+ then do
+ contents <- many (notFollowedBy' (htmlEndTag tagtype) >> anyChar)
+ end <- htmlEndTag tagtype
+ return $ start ++ contents ++ end
+ else fail "Not a verbatim block"
+
+-- We don't want to parse </body> or </html> as raw HTML, since these
+-- are handled in parseHtml.
+rawHtmlBlock' :: GenParser Char ParserState Block
+rawHtmlBlock' = do notFollowedBy' (htmlTag "/body" <|> htmlTag "/html")
+ rawHtmlBlock
+
+-- | Parses an HTML comment.
+htmlComment :: GenParser Char st [Char]
+htmlComment = try $ do
+ string "<!--"
+ comment <- many ( (satisfy (/='-'))
+ <|> (char '-' >>~ notFollowedBy (try $ char '-' >> char '>')))
+ string "-->"
+ return $ "<!--" ++ comment ++ "-->"
+
+--
+-- parsing documents
+--
+
+xmlDec :: GenParser Char st [Char]
+xmlDec = try $ do
+ string "<?"
+ rest <- manyTill anyChar (char '>')
+ return $ "<?" ++ rest ++ ">"
+
+definition :: GenParser Char st [Char]
+definition = try $ do
+ string "<!"
+ rest <- manyTill anyChar (char '>')
+ return $ "<!" ++ rest ++ ">"
+
+nonTitleNonHead :: GenParser Char ParserState Char
+nonTitleNonHead = try $ do
+ notFollowedBy $ (htmlTag "title" >> return ' ') <|>
+ (htmlEndTag "head" >> return ' ')
+ (rawHtmlBlock >> return ' ') <|> anyChar
+
+parseTitle :: GenParser Char ParserState [Inline]
+parseTitle = try $ do
+ (tag, _) <- htmlTag "title"
+ contents <- inlinesTilEnd tag
+ spaces
+ return contents
+
+-- parse header and return meta-information (for now, just title)
+parseHead :: GenParser Char ParserState ([Inline], [a], [Char])
+parseHead = try $ do
+ htmlTag "head"
+ spaces
+ skipMany nonTitleNonHead
+ contents <- option [] parseTitle
+ skipMany nonTitleNonHead
+ htmlEndTag "head"
+ return (contents, [], "")
+
+skipHtmlTag :: String -> GenParser Char ParserState ()
+skipHtmlTag tag = optional (htmlTag tag)
+
+-- h1 class="title" representation of title in body
+bodyTitle :: GenParser Char ParserState [Inline]
+bodyTitle = try $ do
+ (_, attribs) <- htmlTag "h1"
+ case (extractAttribute "class" attribs) of
+ Just "title" -> return ""
+ _ -> fail "not title"
+ inlinesTilEnd "h1"
+
+parseHtml :: GenParser Char ParserState Pandoc
+parseHtml = do
+ sepEndBy (choice [xmlDec, definition, htmlComment]) spaces
+ skipHtmlTag "html"
+ spaces
+ (title, authors, date) <- option ([], [], "") parseHead
+ spaces
+ skipHtmlTag "body"
+ spaces
+ optional bodyTitle -- skip title in body, because it's represented in meta
+ blocks <- parseBlocks
+ spaces
+ optional (htmlEndTag "body")
+ spaces
+ optional (htmlEndTag "html" >> many anyChar) -- ignore anything after </html>
+ eof
+ return $ Pandoc (Meta title authors date) blocks
+
+--
+-- parsing blocks
+--
+
+parseBlocks :: GenParser Char ParserState [Block]
+parseBlocks = spaces >> sepEndBy block spaces >>= (return . filter (/= Null))
+
+block :: GenParser Char ParserState Block
+block = choice [ codeBlock
+ , header
+ , hrule
+ , list
+ , blockQuote
+ , para
+ , plain
+ , rawHtmlBlock'
+ ] <?> "block"
+
+--
+-- header blocks
+--
+
+header :: GenParser Char ParserState Block
+header = choice (map headerLevel (enumFromTo 1 5)) <?> "header"
+
+headerLevel :: Int -> GenParser Char ParserState Block
+headerLevel n = try $ do
+ let level = "h" ++ show n
+ htmlTag level
+ contents <- inlinesTilEnd level
+ return $ Header n (normalizeSpaces contents)
+
+--
+-- hrule block
+--
+
+hrule :: GenParser Char ParserState Block
+hrule = try $ do
+ (_, attribs) <- htmlTag "hr"
+ state <- getState
+ if not (null attribs) && stateParseRaw state
+ then unexpected "attributes in hr" -- parse as raw in this case
+ else return HorizontalRule
+
+--
+-- code blocks
+--
+
+-- Note: HTML tags in code blocks (e.g. for syntax highlighting) are
+-- skipped, because they are not portable to output formats other than HTML.
+codeBlock :: GenParser Char ParserState Block
+codeBlock = try $ do
+ htmlTag "pre"
+ result <- manyTill
+ (many1 (satisfy (/= '<')) <|>
+ ((anyHtmlTag <|> anyHtmlEndTag) >> return ""))
+ (htmlEndTag "pre")
+ let result' = concat result
+ -- drop leading newline if any
+ let result'' = if "\n" `isPrefixOf` result'
+ then drop 1 result'
+ else result'
+ -- drop trailing newline if any
+ let result''' = if "\n" `isSuffixOf` result''
+ then init result''
+ else result''
+ return $ CodeBlock ("",[],[]) $ decodeCharacterReferences result'''
+
+--
+-- block quotes
+--
+
+blockQuote :: GenParser Char ParserState Block
+blockQuote = try $ htmlTag "blockquote" >> spaces >>
+ blocksTilEnd "blockquote" >>= (return . BlockQuote)
+
+--
+-- list blocks
+--
+
+list :: GenParser Char ParserState Block
+list = choice [ bulletList, orderedList, definitionList ] <?> "list"
+
+orderedList :: GenParser Char ParserState Block
+orderedList = try $ do
+ (_, attribs) <- htmlTag "ol"
+ (start, style) <- option (1, DefaultStyle) $
+ do failIfStrict
+ let sta = fromMaybe "1" $
+ lookup "start" attribs
+ let sty = fromMaybe (fromMaybe "" $
+ lookup "style" attribs) $
+ lookup "class" attribs
+ let sty' = case sty of
+ "lower-roman" -> LowerRoman
+ "upper-roman" -> UpperRoman
+ "lower-alpha" -> LowerAlpha
+ "upper-alpha" -> UpperAlpha
+ "decimal" -> Decimal
+ _ -> DefaultStyle
+ return (read sta, sty')
+ spaces
+ items <- sepEndBy1 (blocksIn "li") spaces
+ htmlEndTag "ol"
+ return $ OrderedList (start, style, DefaultDelim) items
+
+bulletList :: GenParser Char ParserState Block
+bulletList = try $ do
+ htmlTag "ul"
+ spaces
+ items <- sepEndBy1 (blocksIn "li") spaces
+ htmlEndTag "ul"
+ return $ BulletList items
+
+definitionList :: GenParser Char ParserState Block
+definitionList = try $ do
+ failIfStrict -- def lists not part of standard markdown
+ htmlTag "dl"
+ spaces
+ items <- sepEndBy1 definitionListItem spaces
+ htmlEndTag "dl"
+ return $ DefinitionList items
+
+definitionListItem :: GenParser Char ParserState ([Inline], [Block])
+definitionListItem = try $ do
+ terms <- sepEndBy1 (inlinesIn "dt") spaces
+ defs <- sepEndBy1 (blocksIn "dd") spaces
+ let term = intercalate [LineBreak] terms
+ return (term, concat defs)
+
+--
+-- paragraph block
+--
+
+para :: GenParser Char ParserState Block
+para = try $ htmlTag "p" >> inlinesTilEnd "p" >>=
+ return . Para . normalizeSpaces
+
+--
+-- plain block
+--
+
+plain :: GenParser Char ParserState Block
+plain = many1 inline >>= return . Plain . normalizeSpaces
+
+--
+-- inline
+--
+
+inline :: GenParser Char ParserState Inline
+inline = choice [ charRef
+ , strong
+ , emph
+ , superscript
+ , subscript
+ , strikeout
+ , spanStrikeout
+ , code
+ , str
+ , linebreak
+ , whitespace
+ , link
+ , image
+ , rawHtmlInline
+ ] <?> "inline"
+
+code :: GenParser Char ParserState Inline
+code = try $ do
+ htmlTag "code"
+ result <- manyTill anyChar (htmlEndTag "code")
+ -- remove internal line breaks, leading and trailing space,
+ -- and decode character references
+ return $ Code $ decodeCharacterReferences $ removeLeadingTrailingSpace $
+ intercalate " " $ lines result
+
+rawHtmlInline :: GenParser Char ParserState Inline
+rawHtmlInline = do
+ result <- htmlScript <|> htmlStyle <|> htmlComment <|> anyHtmlInlineTag
+ state <- getState
+ if stateParseRaw state then return (HtmlInline result) else return (Str "")
+
+betweenTags :: [Char] -> GenParser Char ParserState [Inline]
+betweenTags tag = try $ htmlTag tag >> inlinesTilEnd tag >>=
+ return . normalizeSpaces
+
+emph :: GenParser Char ParserState Inline
+emph = (betweenTags "em" <|> betweenTags "i") >>= return . Emph
+
+strong :: GenParser Char ParserState Inline
+strong = (betweenTags "b" <|> betweenTags "strong") >>= return . Strong
+
+superscript :: GenParser Char ParserState Inline
+superscript = failIfStrict >> betweenTags "sup" >>= return . Superscript
+
+subscript :: GenParser Char ParserState Inline
+subscript = failIfStrict >> betweenTags "sub" >>= return . Subscript
+
+strikeout :: GenParser Char ParserState Inline
+strikeout = failIfStrict >> (betweenTags "s" <|> betweenTags "strike") >>=
+ return . Strikeout
+
+spanStrikeout :: GenParser Char ParserState Inline
+spanStrikeout = try $ do
+ failIfStrict -- strict markdown has no strikeout, so treat as raw HTML
+ (_, attributes) <- htmlTag "span"
+ result <- case (extractAttribute "class" attributes) of
+ Just "strikeout" -> inlinesTilEnd "span"
+ _ -> fail "not a strikeout"
+ return $ Strikeout result
+
+whitespace :: GenParser Char st Inline
+whitespace = many1 space >> return Space
+
+-- hard line break
+linebreak :: GenParser Char ParserState Inline
+linebreak = htmlTag "br" >> optional newline >> return LineBreak
+
+str :: GenParser Char st Inline
+str = many1 (noneOf "<& \t\n") >>= return . Str
+
+--
+-- links and images
+--
+
+-- extract contents of attribute (attribute names are case-insensitive)
+extractAttribute :: [Char] -> [([Char], String)] -> Maybe String
+extractAttribute _ [] = Nothing
+extractAttribute name ((attrName, contents):rest) =
+ let name' = map toLower name
+ attrName' = map toLower attrName
+ in if attrName' == name'
+ then Just (decodeCharacterReferences contents)
+ else extractAttribute name rest
+
+link :: GenParser Char ParserState Inline
+link = try $ do
+ (_, attributes) <- htmlTag "a"
+ url <- case (extractAttribute "href" attributes) of
+ Just url -> return url
+ Nothing -> fail "no href"
+ let title = fromMaybe "" $ extractAttribute "title" attributes
+ lab <- inlinesTilEnd "a"
+ return $ Link (normalizeSpaces lab) (url, title)
+
+image :: GenParser Char ParserState Inline
+image = try $ do
+ (_, attributes) <- htmlTag "img"
+ url <- case (extractAttribute "src" attributes) of
+ Just url -> return url
+ Nothing -> fail "no src"
+ let title = fromMaybe "" $ extractAttribute "title" attributes
+ let alt = fromMaybe "" (extractAttribute "alt" attributes)
+ return $ Image [Str alt] (url, title)
+
diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs
new file mode 100644
index 000000000..5d02a2be5
--- /dev/null
+++ b/src/Text/Pandoc/Readers/LaTeX.hs
@@ -0,0 +1,778 @@
+{-
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.LaTeX
+ Copyright : Copyright (C) 2006-8 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of LaTeX to 'Pandoc' document.
+-}
+module Text.Pandoc.Readers.LaTeX (
+ readLaTeX,
+ rawLaTeXInline,
+ rawLaTeXEnvironment'
+ ) where
+
+import Text.ParserCombinators.Parsec
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Data.Maybe ( fromMaybe )
+import Data.Char ( chr )
+import Data.List ( isPrefixOf, isSuffixOf )
+
+-- | Parse LaTeX from string and return 'Pandoc' document.
+readLaTeX :: ParserState -- ^ Parser state, including options for parser
+ -> String -- ^ String to parse
+ -> Pandoc
+readLaTeX = readWith parseLaTeX
+
+-- characters with special meaning
+specialChars :: [Char]
+specialChars = "\\`$%^&_~#{}\n \t|<>'\"-"
+
+--
+-- utility functions
+--
+
+-- | Returns text between brackets and its matching pair.
+bracketedText :: Char -> Char -> GenParser Char st [Char]
+bracketedText openB closeB = do
+ result <- charsInBalanced' openB closeB
+ return $ [openB] ++ result ++ [closeB]
+
+-- | Returns an option or argument of a LaTeX command.
+optOrArg :: GenParser Char st [Char]
+optOrArg = bracketedText '{' '}' <|> bracketedText '[' ']'
+
+-- | True if the string begins with '{'.
+isArg :: [Char] -> Bool
+isArg ('{':_) = True
+isArg _ = False
+
+-- | Returns list of options and arguments of a LaTeX command.
+commandArgs :: GenParser Char st [[Char]]
+commandArgs = many optOrArg
+
+-- | Parses LaTeX command, returns (name, star, list of options or arguments).
+command :: GenParser Char st ([Char], [Char], [[Char]])
+command = do
+ char '\\'
+ name <- many1 letter
+ star <- option "" (string "*") -- some commands have starred versions
+ args <- commandArgs
+ return (name, star, args)
+
+begin :: [Char] -> GenParser Char st [Char]
+begin name = try $ do
+ string $ "\\begin{" ++ name ++ "}"
+ optional commandArgs
+ spaces
+ return name
+
+end :: [Char] -> GenParser Char st [Char]
+end name = try $ do
+ string $ "\\end{" ++ name ++ "}"
+ return name
+
+-- | Returns a list of block elements containing the contents of an
+-- environment.
+environment :: [Char] -> GenParser Char ParserState [Block]
+environment name = try $ begin name >> spaces >> manyTill block (end name) >>~ spaces
+
+anyEnvironment :: GenParser Char ParserState Block
+anyEnvironment = try $ do
+ string "\\begin{"
+ name <- many letter
+ star <- option "" (string "*") -- some environments have starred variants
+ char '}'
+ optional commandArgs
+ spaces
+ contents <- manyTill block (end (name ++ star))
+ spaces
+ return $ BlockQuote contents
+
+--
+-- parsing documents
+--
+
+-- | Process LaTeX preamble, extracting metadata.
+processLaTeXPreamble :: GenParser Char ParserState ()
+processLaTeXPreamble = try $ manyTill
+ (choice [bibliographic, comment, unknownCommand, nullBlock])
+ (try (string "\\begin{document}")) >>
+ spaces
+
+-- | Parse LaTeX and return 'Pandoc'.
+parseLaTeX :: GenParser Char ParserState Pandoc
+parseLaTeX = do
+ optional processLaTeXPreamble -- preamble might not be present (fragment)
+ spaces
+ blocks <- parseBlocks
+ spaces
+ optional $ try (string "\\end{document}" >> many anyChar)
+ -- might not be present (fragment)
+ spaces
+ eof
+ state <- getState
+ let blocks' = filter (/= Null) blocks
+ let title' = stateTitle state
+ let authors' = stateAuthors state
+ let date' = stateDate state
+ return $ Pandoc (Meta title' authors' date') blocks'
+
+--
+-- parsing blocks
+--
+
+parseBlocks :: GenParser Char ParserState [Block]
+parseBlocks = spaces >> many block
+
+block :: GenParser Char ParserState Block
+block = choice [ hrule
+ , codeBlock
+ , header
+ , list
+ , blockQuote
+ , comment
+ , bibliographic
+ , para
+ , itemBlock
+ , unknownEnvironment
+ , ignore
+ , unknownCommand ] <?> "block"
+
+--
+-- header blocks
+--
+
+header :: GenParser Char ParserState Block
+header = try $ do
+ char '\\'
+ subs <- many (try (string "sub"))
+ string "section"
+ optional (char '*')
+ char '{'
+ title' <- manyTill inline (char '}')
+ spaces
+ return $ Header (length subs + 1) (normalizeSpaces title')
+
+--
+-- hrule block
+--
+
+hrule :: GenParser Char st Block
+hrule = oneOfStrings [ "\\begin{center}\\rule{3in}{0.4pt}\\end{center}\n\n",
+ "\\newpage" ] >> spaces >> return HorizontalRule
+
+--
+-- code blocks
+--
+
+codeBlock :: GenParser Char ParserState Block
+codeBlock = codeBlockWith "verbatim" <|> codeBlockWith "Verbatim" <|> lhsCodeBlock
+-- Note: Verbatim is from fancyvrb.
+
+codeBlockWith :: String -> GenParser Char st Block
+codeBlockWith env = try $ do
+ string ("\\begin{" ++ env ++ "}") -- don't use begin function because it
+ -- gobbles whitespace
+ optional blanklines -- we want to gobble blank lines, but not
+ -- leading space
+ contents <- manyTill anyChar (try (string $ "\\end{" ++ env ++ "}"))
+ spaces
+ let classes = if env == "code" then ["haskell"] else []
+ return $ CodeBlock ("",classes,[]) (stripTrailingNewlines contents)
+
+lhsCodeBlock :: GenParser Char ParserState Block
+lhsCodeBlock = do
+ failUnlessLHS
+ (CodeBlock (_,_,_) cont) <- codeBlockWith "code"
+ return $ CodeBlock ("", ["sourceCode","haskell"], []) cont
+
+--
+-- block quotes
+--
+
+blockQuote :: GenParser Char ParserState Block
+blockQuote = (environment "quote" <|> environment "quotation") >>~ spaces >>=
+ return . BlockQuote
+
+--
+-- list blocks
+--
+
+list :: GenParser Char ParserState Block
+list = bulletList <|> orderedList <|> definitionList <?> "list"
+
+listItem :: GenParser Char ParserState ([Inline], [Block])
+listItem = try $ do
+ ("item", _, args) <- command
+ spaces
+ state <- getState
+ let oldParserContext = stateParserContext state
+ updateState (\s -> s {stateParserContext = ListItemState})
+ blocks <- many block
+ updateState (\s -> s {stateParserContext = oldParserContext})
+ opt <- case args of
+ ([x]) | "[" `isPrefixOf` x && "]" `isSuffixOf` x ->
+ parseFromString (many inline) $ tail $ init x
+ _ -> return []
+ return (opt, blocks)
+
+orderedList :: GenParser Char ParserState Block
+orderedList = try $ do
+ string "\\begin{enumerate}"
+ (_, style, delim) <- option (1, DefaultStyle, DefaultDelim) $
+ try $ do failIfStrict
+ char '['
+ res <- anyOrderedListMarker
+ char ']'
+ return res
+ spaces
+ option "" $ try $ do string "\\setlength{\\itemindent}"
+ char '{'
+ manyTill anyChar (char '}')
+ spaces
+ start <- option 1 $ try $ do failIfStrict
+ string "\\setcounter{enum"
+ many1 (oneOf "iv")
+ string "}{"
+ num <- many1 digit
+ char '}'
+ spaces
+ return $ (read num) + 1
+ items <- many listItem
+ end "enumerate"
+ spaces
+ return $ OrderedList (start, style, delim) $ map snd items
+
+bulletList :: GenParser Char ParserState Block
+bulletList = try $ do
+ begin "itemize"
+ spaces
+ items <- many listItem
+ end "itemize"
+ spaces
+ return (BulletList $ map snd items)
+
+definitionList :: GenParser Char ParserState Block
+definitionList = try $ do
+ begin "description"
+ spaces
+ items <- many listItem
+ end "description"
+ spaces
+ return (DefinitionList items)
+
+--
+-- paragraph block
+--
+
+para :: GenParser Char ParserState Block
+para = do
+ res <- many1 inline
+ spaces
+ return $ if null (filter (`notElem` [Str "", Space]) res)
+ then Null
+ else Para $ normalizeSpaces res
+
+--
+-- title authors date
+--
+
+bibliographic :: GenParser Char ParserState Block
+bibliographic = choice [ maketitle, title, authors, date ]
+
+maketitle :: GenParser Char st Block
+maketitle = try (string "\\maketitle") >> spaces >> return Null
+
+title :: GenParser Char ParserState Block
+title = try $ do
+ string "\\title{"
+ tit <- manyTill inline (char '}')
+ spaces
+ updateState (\state -> state { stateTitle = tit })
+ return Null
+
+authors :: GenParser Char ParserState Block
+authors = try $ do
+ string "\\author{"
+ authors' <- manyTill anyChar (char '}')
+ spaces
+ let authors'' = map removeLeadingTrailingSpace $ lines $
+ substitute "\\\\" "\n" authors'
+ updateState (\s -> s { stateAuthors = authors'' })
+ return Null
+
+date :: GenParser Char ParserState Block
+date = try $ do
+ string "\\date{"
+ date' <- manyTill anyChar (char '}')
+ spaces
+ updateState (\state -> state { stateDate = date' })
+ return Null
+
+--
+-- item block
+-- for use in unknown environments that aren't being parsed as raw latex
+--
+
+-- this forces items to be parsed in different blocks
+itemBlock :: GenParser Char ParserState Block
+itemBlock = try $ do
+ ("item", _, args) <- command
+ state <- getState
+ if stateParserContext state == ListItemState
+ then fail "item should be handled by list block"
+ else if null args
+ then return Null
+ else return $ Plain [Str (stripFirstAndLast (head args))]
+
+--
+-- raw LaTeX
+--
+
+-- | Parse any LaTeX environment and return a Para block containing
+-- the whole literal environment as raw TeX.
+rawLaTeXEnvironment :: GenParser Char st Block
+rawLaTeXEnvironment = do
+ contents <- rawLaTeXEnvironment'
+ spaces
+ return $ Para [TeX contents]
+
+-- | Parse any LaTeX environment and return a string containing
+-- the whole literal environment as raw TeX.
+rawLaTeXEnvironment' :: GenParser Char st String
+rawLaTeXEnvironment' = try $ do
+ string "\\begin{"
+ name <- many1 letter
+ star <- option "" (string "*") -- for starred variants
+ let name' = name ++ star
+ char '}'
+ args <- option [] commandArgs
+ let argStr = concat args
+ contents <- manyTill (choice [ (many1 (noneOf "\\")),
+ rawLaTeXEnvironment',
+ string "\\" ])
+ (end name')
+ return $ "\\begin{" ++ name' ++ "}" ++ argStr ++
+ concat contents ++ "\\end{" ++ name' ++ "}"
+
+unknownEnvironment :: GenParser Char ParserState Block
+unknownEnvironment = try $ do
+ state <- getState
+ result <- if stateParseRaw state -- check whether we should include raw TeX
+ then rawLaTeXEnvironment -- if so, get whole raw environment
+ else anyEnvironment -- otherwise just the contents
+ return result
+
+-- \ignore{} is used conventionally in literate haskell for definitions
+-- that are to be processed by the compiler but not printed.
+ignore :: GenParser Char ParserState Block
+ignore = try $ do
+ ("ignore", _, _) <- command
+ spaces
+ return Null
+
+unknownCommand :: GenParser Char ParserState Block
+unknownCommand = try $ do
+ notFollowedBy' $ choice $ map end ["itemize", "enumerate", "description",
+ "document"]
+ state <- getState
+ if stateParserContext state == ListItemState
+ then notFollowedBy' $ string "\\item"
+ else return ()
+ if stateParseRaw state
+ then do
+ (name, star, args) <- command
+ spaces
+ return $ Plain [TeX ("\\" ++ name ++ star ++ concat args)]
+ else do -- skip unknown command, leaving arguments to be parsed
+ char '\\'
+ letter
+ many (letter <|> digit)
+ optional (try $ string "{}")
+ spaces
+ return Null
+
+-- latex comment
+comment :: GenParser Char st Block
+comment = try $ char '%' >> manyTill anyChar newline >> spaces >> return Null
+
+--
+-- inline
+--
+
+inline :: GenParser Char ParserState Inline
+inline = choice [ str
+ , endline
+ , whitespace
+ , quoted
+ , apostrophe
+ , spacer
+ , strong
+ , math
+ , ellipses
+ , emDash
+ , enDash
+ , hyphen
+ , emph
+ , strikeout
+ , superscript
+ , subscript
+ , ref
+ , lab
+ , code
+ , url
+ , link
+ , image
+ , footnote
+ , linebreak
+ , accentedChar
+ , specialChar
+ , rawLaTeXInline
+ , escapedChar
+ , unescapedChar
+ ] <?> "inline"
+
+accentedChar :: GenParser Char st Inline
+accentedChar = normalAccentedChar <|> specialAccentedChar
+
+normalAccentedChar :: GenParser Char st Inline
+normalAccentedChar = try $ do
+ char '\\'
+ accent <- oneOf "'`^\"~"
+ character <- (try $ char '{' >> letter >>~ char '}') <|> letter
+ let table = fromMaybe [] $ lookup character accentTable
+ let result = case lookup accent table of
+ Just num -> chr num
+ Nothing -> '?'
+ return $ Str [result]
+
+-- an association list of letters and association list of accents
+-- and decimal character numbers.
+accentTable :: [(Char, [(Char, Int)])]
+accentTable =
+ [ ('A', [('`', 192), ('\'', 193), ('^', 194), ('~', 195), ('"', 196)]),
+ ('E', [('`', 200), ('\'', 201), ('^', 202), ('"', 203)]),
+ ('I', [('`', 204), ('\'', 205), ('^', 206), ('"', 207)]),
+ ('N', [('~', 209)]),
+ ('O', [('`', 210), ('\'', 211), ('^', 212), ('~', 213), ('"', 214)]),
+ ('U', [('`', 217), ('\'', 218), ('^', 219), ('"', 220)]),
+ ('a', [('`', 224), ('\'', 225), ('^', 227), ('"', 228)]),
+ ('e', [('`', 232), ('\'', 233), ('^', 234), ('"', 235)]),
+ ('i', [('`', 236), ('\'', 237), ('^', 238), ('"', 239)]),
+ ('n', [('~', 241)]),
+ ('o', [('`', 242), ('\'', 243), ('^', 244), ('~', 245), ('"', 246)]),
+ ('u', [('`', 249), ('\'', 250), ('^', 251), ('"', 252)]) ]
+
+specialAccentedChar :: GenParser Char st Inline
+specialAccentedChar = choice [ ccedil, aring, iuml, szlig, aelig,
+ oslash, pound, euro, copyright, sect ]
+
+ccedil :: GenParser Char st Inline
+ccedil = try $ do
+ char '\\'
+ letter' <- oneOfStrings ["cc", "cC"]
+ let num = if letter' == "cc" then 231 else 199
+ return $ Str [chr num]
+
+aring :: GenParser Char st Inline
+aring = try $ do
+ char '\\'
+ letter' <- oneOfStrings ["aa", "AA"]
+ let num = if letter' == "aa" then 229 else 197
+ return $ Str [chr num]
+
+iuml :: GenParser Char st Inline
+iuml = try (string "\\\"") >> oneOfStrings ["\\i", "{\\i}"] >>
+ return (Str [chr 239])
+
+szlig :: GenParser Char st Inline
+szlig = try (string "\\ss") >> return (Str [chr 223])
+
+oslash :: GenParser Char st Inline
+oslash = try $ do
+ char '\\'
+ letter' <- choice [char 'o', char 'O']
+ let num = if letter' == 'o' then 248 else 216
+ return $ Str [chr num]
+
+aelig :: GenParser Char st Inline
+aelig = try $ do
+ char '\\'
+ letter' <- oneOfStrings ["ae", "AE"]
+ let num = if letter' == "ae" then 230 else 198
+ return $ Str [chr num]
+
+pound :: GenParser Char st Inline
+pound = try (string "\\pounds") >> return (Str [chr 163])
+
+euro :: GenParser Char st Inline
+euro = try (string "\\euro") >> return (Str [chr 8364])
+
+copyright :: GenParser Char st Inline
+copyright = try (string "\\copyright") >> return (Str [chr 169])
+
+sect :: GenParser Char st Inline
+sect = try (string "\\S") >> return (Str [chr 167])
+
+escapedChar :: GenParser Char st Inline
+escapedChar = do
+ result <- escaped (oneOf " $%&_#{}\n")
+ return $ if result == Str "\n" then Str " " else result
+
+-- nonescaped special characters
+unescapedChar :: GenParser Char st Inline
+unescapedChar = oneOf "`$^&_#{}|<>" >>= return . (\c -> Str [c])
+
+specialChar :: GenParser Char st Inline
+specialChar = choice [ backslash, tilde, caret, bar, lt, gt, doubleQuote ]
+
+backslash :: GenParser Char st Inline
+backslash = try (string "\\textbackslash") >> optional (try $ string "{}") >> return (Str "\\")
+
+tilde :: GenParser Char st Inline
+tilde = try (string "\\ensuremath{\\sim}") >> return (Str "~")
+
+caret :: GenParser Char st Inline
+caret = try (string "\\^{}") >> return (Str "^")
+
+bar :: GenParser Char st Inline
+bar = try (string "\\textbar") >> optional (try $ string "{}") >> return (Str "\\")
+
+lt :: GenParser Char st Inline
+lt = try (string "\\textless") >> optional (try $ string "{}") >> return (Str "<")
+
+gt :: GenParser Char st Inline
+gt = try (string "\\textgreater") >> optional (try $ string "{}") >> return (Str ">")
+
+doubleQuote :: GenParser Char st Inline
+doubleQuote = char '"' >> return (Str "\"")
+
+code :: GenParser Char ParserState Inline
+code = code1 <|> code2 <|> lhsInlineCode
+
+code1 :: GenParser Char st Inline
+code1 = try $ do
+ string "\\verb"
+ marker <- anyChar
+ result <- manyTill anyChar (char marker)
+ return $ Code $ removeLeadingTrailingSpace result
+
+code2 :: GenParser Char st Inline
+code2 = try $ do
+ string "\\texttt{"
+ result <- manyTill (noneOf "\\\n~$%^&{}") (char '}')
+ return $ Code result
+
+lhsInlineCode :: GenParser Char ParserState Inline
+lhsInlineCode = try $ do
+ failUnlessLHS
+ char '|'
+ result <- manyTill (noneOf "|\n") (char '|')
+ return $ Code result
+
+emph :: GenParser Char ParserState Inline
+emph = try $ oneOfStrings [ "\\emph{", "\\textit{" ] >>
+ manyTill inline (char '}') >>= return . Emph
+
+strikeout :: GenParser Char ParserState Inline
+strikeout = try $ string "\\sout{" >> manyTill inline (char '}') >>=
+ return . Strikeout
+
+superscript :: GenParser Char ParserState Inline
+superscript = try $ string "\\textsuperscript{" >>
+ manyTill inline (char '}') >>= return . Superscript
+
+-- note: \textsubscript isn't a standard latex command, but we use
+-- a defined version in pandoc.
+subscript :: GenParser Char ParserState Inline
+subscript = try $ string "\\textsubscript{" >> manyTill inline (char '}') >>=
+ return . Subscript
+
+apostrophe :: GenParser Char ParserState Inline
+apostrophe = char '\'' >> return Apostrophe
+
+quoted :: GenParser Char ParserState Inline
+quoted = doubleQuoted <|> singleQuoted
+
+singleQuoted :: GenParser Char ParserState Inline
+singleQuoted = enclosed singleQuoteStart singleQuoteEnd inline >>=
+ return . Quoted SingleQuote . normalizeSpaces
+
+doubleQuoted :: GenParser Char ParserState Inline
+doubleQuoted = enclosed doubleQuoteStart doubleQuoteEnd inline >>=
+ return . Quoted DoubleQuote . normalizeSpaces
+
+singleQuoteStart :: GenParser Char st Char
+singleQuoteStart = char '`'
+
+singleQuoteEnd :: GenParser Char st ()
+singleQuoteEnd = try $ char '\'' >> notFollowedBy alphaNum
+
+doubleQuoteStart :: CharParser st String
+doubleQuoteStart = string "``"
+
+doubleQuoteEnd :: CharParser st String
+doubleQuoteEnd = try $ string "''"
+
+ellipses :: GenParser Char st Inline
+ellipses = try $ string "\\ldots" >> optional (try $ string "{}") >>
+ return Ellipses
+
+enDash :: GenParser Char st Inline
+enDash = try (string "--") >> return EnDash
+
+emDash :: GenParser Char st Inline
+emDash = try (string "---") >> return EmDash
+
+hyphen :: GenParser Char st Inline
+hyphen = char '-' >> return (Str "-")
+
+lab :: GenParser Char st Inline
+lab = try $ do
+ string "\\label{"
+ result <- manyTill anyChar (char '}')
+ return $ Str $ "(" ++ result ++ ")"
+
+ref :: GenParser Char st Inline
+ref = try (string "\\ref{") >> manyTill anyChar (char '}') >>= return . Str
+
+strong :: GenParser Char ParserState Inline
+strong = try (string "\\textbf{") >> manyTill inline (char '}') >>=
+ return . Strong
+
+whitespace :: GenParser Char st Inline
+whitespace = many1 (oneOf "~ \t") >> return Space
+
+-- hard line break
+linebreak :: GenParser Char st Inline
+linebreak = try (string "\\\\") >> return LineBreak
+
+spacer :: GenParser Char st Inline
+spacer = try (string "\\,") >> return (Str "")
+
+str :: GenParser Char st Inline
+str = many1 (noneOf specialChars) >>= return . Str
+
+-- endline internal to paragraph
+endline :: GenParser Char st Inline
+endline = try $ newline >> notFollowedBy blankline >> return Space
+
+-- math
+math :: GenParser Char st Inline
+math = (math3 >>= return . Math DisplayMath)
+ <|> (math1 >>= return . Math InlineMath)
+ <|> (math2 >>= return . Math InlineMath)
+ <|> (math4 >>= return . Math DisplayMath)
+ <|> (math5 >>= return . Math DisplayMath)
+ <|> (math6 >>= return . Math DisplayMath)
+ <?> "math"
+
+math1 :: GenParser Char st String
+math1 = try $ char '$' >> manyTill anyChar (char '$')
+
+math2 :: GenParser Char st String
+math2 = try $ string "\\(" >> manyTill anyChar (try $ string "\\)")
+
+math3 :: GenParser Char st String
+math3 = try $ char '$' >> math1 >>~ char '$'
+
+math4 :: GenParser Char st String
+math4 = try $ do
+ name <- begin "displaymath" <|> begin "equation" <|> begin "equation*" <|>
+ begin "gather" <|> begin "gather*" <|> begin "gathered" <|>
+ begin "multline" <|> begin "multline*"
+ spaces
+ manyTill anyChar (end name)
+
+math5 :: GenParser Char st String
+math5 = try $ (string "\\[") >> spaces >> manyTill anyChar (try $ string "\\]")
+
+math6 :: GenParser Char st String
+math6 = try $ do
+ name <- begin "eqnarray" <|> begin "eqnarray*" <|> begin "align" <|>
+ begin "align*" <|> begin "alignat" <|> begin "alignat*" <|>
+ begin "split" <|> begin "aligned" <|> begin "alignedat"
+ spaces
+ res <- manyTill anyChar (end name)
+ return $ filter (/= '&') res -- remove alignment codes
+
+--
+-- links and images
+--
+
+url :: GenParser Char ParserState Inline
+url = try $ do
+ string "\\url"
+ url' <- charsInBalanced '{' '}'
+ return $ Link [Code url'] (url', "")
+
+link :: GenParser Char ParserState Inline
+link = try $ do
+ string "\\href{"
+ url' <- manyTill anyChar (char '}')
+ char '{'
+ label' <- manyTill inline (char '}')
+ return $ Link (normalizeSpaces label') (url', "")
+
+image :: GenParser Char ParserState Inline
+image = try $ do
+ ("includegraphics", _, args) <- command
+ let args' = filter isArg args -- filter out options
+ let src = if null args' then
+ ("", "")
+ else
+ (stripFirstAndLast (head args'), "")
+ return $ Image [Str "image"] src
+
+footnote :: GenParser Char ParserState Inline
+footnote = try $ do
+ (name, _, (contents:[])) <- command
+ if ((name == "footnote") || (name == "thanks"))
+ then string ""
+ else fail "not a footnote or thanks command"
+ let contents' = stripFirstAndLast contents
+ -- parse the extracted block, which may contain various block elements:
+ rest <- getInput
+ setInput $ contents'
+ blocks <- parseBlocks
+ setInput rest
+ return $ Note blocks
+
+-- | Parse any LaTeX command and return it in a raw TeX inline element.
+rawLaTeXInline :: GenParser Char ParserState Inline
+rawLaTeXInline = try $ do
+ notFollowedBy' $ oneOfStrings ["\\begin", "\\end", "\\item", "\\ignore"]
+ state <- getState
+ if stateParseRaw state
+ then do
+ (name, star, args) <- command
+ return $ TeX ("\\" ++ name ++ star ++ concat args)
+ else do -- skip unknown command, leaving arguments to be parsed
+ char '\\'
+ letter
+ many (letter <|> digit)
+ optional (try $ string "{}")
+ return $ Str ""
diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs
new file mode 100644
index 000000000..ae682e72e
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Markdown.hs
@@ -0,0 +1,1245 @@
+{-# LANGUAGE CPP #-}
+{-
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Markdown
+ Copyright : Copyright (C) 2006-8 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of markdown-formatted plain text to 'Pandoc' document.
+-}
+module Text.Pandoc.Readers.Markdown (
+ readMarkdown
+ ) where
+
+import Data.List ( transpose, isPrefixOf, isSuffixOf, lookup, sortBy, findIndex, intercalate )
+import Data.Ord ( comparing )
+import Data.Char ( isAlphaNum, isUpper )
+import Data.Maybe
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Text.Pandoc.Readers.LaTeX ( rawLaTeXInline, rawLaTeXEnvironment' )
+import Text.Pandoc.Readers.HTML ( rawHtmlBlock, anyHtmlBlockTag,
+ anyHtmlInlineTag, anyHtmlTag,
+ anyHtmlEndTag, htmlEndTag, extractTagType,
+ htmlBlockElement, unsanitaryURI )
+import Text.Pandoc.CharacterReferences ( decodeCharacterReferences )
+import Text.ParserCombinators.Parsec
+import Control.Monad (when)
+
+-- | Read markdown from an input string and return a Pandoc document.
+readMarkdown :: ParserState -> String -> Pandoc
+readMarkdown state s = (readWith parseMarkdown) state (s ++ "\n\n")
+
+--
+-- Constants and data structure definitions
+--
+
+bulletListMarkers :: [Char]
+bulletListMarkers = "*+-"
+
+hruleChars :: [Char]
+hruleChars = "*-_"
+
+setextHChars :: [Char]
+setextHChars = "=-"
+
+-- treat these as potentially non-text when parsing inline:
+specialChars :: [Char]
+specialChars = "\\[]*_~`<>$!^-.&'\"\8216\8217\8220\8221"
+
+--
+-- auxiliary functions
+--
+
+indentSpaces :: GenParser Char ParserState [Char]
+indentSpaces = try $ do
+ state <- getState
+ let tabStop = stateTabStop state
+ count tabStop (char ' ') <|>
+ string "\t" <?> "indentation"
+
+nonindentSpaces :: GenParser Char ParserState [Char]
+nonindentSpaces = do
+ state <- getState
+ let tabStop = stateTabStop state
+ sps <- many (char ' ')
+ if length sps < tabStop
+ then return sps
+ else unexpected "indented line"
+
+skipNonindentSpaces :: GenParser Char ParserState ()
+skipNonindentSpaces = do
+ state <- getState
+ atMostSpaces (stateTabStop state - 1)
+
+atMostSpaces :: Int -> GenParser Char ParserState ()
+atMostSpaces 0 = notFollowedBy (char ' ')
+atMostSpaces n = (char ' ' >> atMostSpaces (n-1)) <|> return ()
+
+-- | Fail unless we're at beginning of a line.
+failUnlessBeginningOfLine :: GenParser tok st ()
+failUnlessBeginningOfLine = do
+ pos <- getPosition
+ if sourceColumn pos == 1 then return () else fail "not beginning of line"
+
+-- | Fail unless we're in "smart typography" mode.
+failUnlessSmart :: GenParser tok ParserState ()
+failUnlessSmart = do
+ state <- getState
+ if stateSmart state then return () else fail "Smart typography feature"
+
+-- | Parse a sequence of inline elements between square brackets,
+-- including inlines between balanced pairs of square brackets.
+inlinesInBalancedBrackets :: GenParser Char ParserState Inline
+ -> GenParser Char ParserState [Inline]
+inlinesInBalancedBrackets parser = try $ do
+ char '['
+ result <- manyTill ( (do lookAhead $ try $ do (Str res) <- parser
+ if res == "["
+ then return ()
+ else pzero
+ bal <- inlinesInBalancedBrackets parser
+ return $ [Str "["] ++ bal ++ [Str "]"])
+ <|> (count 1 parser))
+ (char ']')
+ return $ concat result
+
+--
+-- document structure
+--
+
+titleLine :: GenParser Char ParserState [Inline]
+titleLine = try $ char '%' >> skipSpaces >> manyTill inline newline
+
+authorsLine :: GenParser Char st [String]
+authorsLine = try $ do
+ char '%'
+ skipSpaces
+ authors <- sepEndBy (many1 (noneOf ",;\n")) (oneOf ",;")
+ newline
+ return $ map (decodeCharacterReferences . removeLeadingTrailingSpace) authors
+
+dateLine :: GenParser Char st String
+dateLine = try $ do
+ char '%'
+ skipSpaces
+ date <- many (noneOf "\n")
+ newline
+ return $ decodeCharacterReferences $ removeTrailingSpace date
+
+titleBlock :: GenParser Char ParserState ([Inline], [String], [Char])
+titleBlock = try $ do
+ failIfStrict
+ title <- option [] titleLine
+ author <- option [] authorsLine
+ date <- option "" dateLine
+ optional blanklines
+ return (title, author, date)
+
+parseMarkdown :: GenParser Char ParserState Pandoc
+parseMarkdown = do
+ -- markdown allows raw HTML
+ updateState (\state -> state { stateParseRaw = True })
+ startPos <- getPosition
+ -- go through once just to get list of reference keys
+ -- docMinusKeys is the raw document with blanks where the keys were...
+ docMinusKeys <- manyTill (referenceKey <|> lineClump) eof >>=
+ return . concat
+ setInput docMinusKeys
+ setPosition startPos
+ st <- getState
+ -- go through again for notes unless strict...
+ if stateStrict st
+ then return ()
+ else do docMinusNotes <- manyTill (noteBlock <|> lineClump) eof >>=
+ return . concat
+ st' <- getState
+ let reversedNotes = stateNotes st'
+ updateState $ \s -> s { stateNotes = reverse reversedNotes }
+ setInput docMinusNotes
+ setPosition startPos
+ -- now parse it for real...
+ (title, author, date) <- option ([],[],"") titleBlock
+ blocks <- parseBlocks
+ return $ Pandoc (Meta title author date) $ filter (/= Null) blocks
+
+--
+-- initial pass for references and notes
+--
+
+referenceKey :: GenParser Char ParserState [Char]
+referenceKey = try $ do
+ startPos <- getPosition
+ skipNonindentSpaces
+ lab <- reference
+ char ':'
+ skipSpaces >> optional newline >> skipSpaces >> notFollowedBy (char '[')
+ let sourceURL excludes = many $
+ optional (char '\\') >> (noneOf (' ':excludes) <|> (notFollowedBy' referenceTitle >> char ' '))
+ src <- try (char '<' >> sourceURL ">\t\n" >>~ char '>') <|> sourceURL "\t\n"
+ tit <- option "" referenceTitle
+ blanklines
+ endPos <- getPosition
+ let newkey = (lab, (intercalate "%20" $ words $ removeTrailingSpace src, tit))
+ st <- getState
+ let oldkeys = stateKeys st
+ updateState $ \s -> s { stateKeys = newkey : oldkeys }
+ -- return blanks so line count isn't affected
+ return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
+
+referenceTitle :: GenParser Char st String
+referenceTitle = try $ do
+ skipSpaces >> optional newline >> skipSpaces
+ tit <- (charsInBalanced '(' ')' >>= return . unwords . words)
+ <|> do delim <- char '\'' <|> char '"'
+ manyTill anyChar (try (char delim >> skipSpaces >>
+ notFollowedBy (noneOf ")\n")))
+ return $ decodeCharacterReferences tit
+
+noteMarker :: GenParser Char st [Char]
+noteMarker = string "[^" >> manyTill (noneOf " \t\n") (char ']')
+
+rawLine :: GenParser Char ParserState [Char]
+rawLine = do
+ notFollowedBy blankline
+ notFollowedBy' noteMarker
+ contents <- many1 nonEndline
+ end <- option "" (newline >> optional indentSpaces >> return "\n")
+ return $ contents ++ end
+
+rawLines :: GenParser Char ParserState [Char]
+rawLines = many1 rawLine >>= return . concat
+
+noteBlock :: GenParser Char ParserState [Char]
+noteBlock = try $ do
+ startPos <- getPosition
+ ref <- noteMarker
+ char ':'
+ optional blankline
+ optional indentSpaces
+ raw <- sepBy rawLines (try (blankline >> indentSpaces))
+ optional blanklines
+ endPos <- getPosition
+ -- parse the extracted text, which may contain various block elements:
+ contents <- parseFromString parseBlocks $ (intercalate "\n" raw) ++ "\n\n"
+ let newnote = (ref, contents)
+ st <- getState
+ let oldnotes = stateNotes st
+ updateState $ \s -> s { stateNotes = newnote : oldnotes }
+ -- return blanks so line count isn't affected
+ return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
+
+--
+-- parsing blocks
+--
+
+parseBlocks :: GenParser Char ParserState [Block]
+parseBlocks = manyTill block eof
+
+block :: GenParser Char ParserState Block
+block = do
+ st <- getState
+ choice (if stateStrict st
+ then [ header
+ , codeBlockIndented
+ , blockQuote
+ , hrule
+ , bulletList
+ , orderedList
+ , htmlBlock
+ , para
+ , plain
+ , nullBlock ]
+ else [ codeBlockDelimited
+ , header
+ , table
+ , codeBlockIndented
+ , lhsCodeBlock
+ , blockQuote
+ , hrule
+ , bulletList
+ , orderedList
+ , definitionList
+ , para
+ , rawHtmlBlocks
+ , plain
+ , nullBlock ]) <?> "block"
+
+--
+-- header blocks
+--
+
+header :: GenParser Char ParserState Block
+header = setextHeader <|> atxHeader <?> "header"
+
+atxHeader :: GenParser Char ParserState Block
+atxHeader = try $ do
+ level <- many1 (char '#') >>= return . length
+ notFollowedBy (char '.' <|> char ')') -- this would be a list
+ skipSpaces
+ text <- manyTill inline atxClosing >>= return . normalizeSpaces
+ return $ Header level text
+
+atxClosing :: GenParser Char st [Char]
+atxClosing = try $ skipMany (char '#') >> blanklines
+
+setextHeader :: GenParser Char ParserState Block
+setextHeader = try $ do
+ text <- many1Till inline newline
+ underlineChar <- oneOf setextHChars
+ many (char underlineChar)
+ blanklines
+ let level = (fromMaybe 0 $ findIndex (== underlineChar) setextHChars) + 1
+ return $ Header level (normalizeSpaces text)
+
+--
+-- hrule block
+--
+
+hrule :: GenParser Char st Block
+hrule = try $ do
+ skipSpaces
+ start <- oneOf hruleChars
+ count 2 (skipSpaces >> char start)
+ skipMany (spaceChar <|> char start)
+ newline
+ optional blanklines
+ return HorizontalRule
+
+--
+-- code blocks
+--
+
+indentedLine :: GenParser Char ParserState [Char]
+indentedLine = indentSpaces >> manyTill anyChar newline >>= return . (++ "\n")
+
+codeBlockDelimiter :: Maybe Int
+ -> GenParser Char st (Int, ([Char], [[Char]], [([Char], [Char])]))
+codeBlockDelimiter len = try $ do
+ size <- case len of
+ Just l -> count l (char '~') >> many (char '~') >> return l
+ Nothing -> count 3 (char '~') >> many (char '~') >>=
+ return . (+ 3) . length
+ many spaceChar
+ attr <- option ([],[],[]) attributes
+ blankline
+ return (size, attr)
+
+attributes :: GenParser Char st ([Char], [[Char]], [([Char], [Char])])
+attributes = try $ do
+ char '{'
+ many spaceChar
+ attrs <- many (attribute >>~ many spaceChar)
+ char '}'
+ let (ids, classes, keyvals) = unzip3 attrs
+ let id' = if null ids then "" else head ids
+ return (id', concat classes, concat keyvals)
+
+attribute :: GenParser Char st ([Char], [[Char]], [([Char], [Char])])
+attribute = identifierAttr <|> classAttr <|> keyValAttr
+
+identifier :: GenParser Char st [Char]
+identifier = do
+ first <- letter
+ rest <- many $ alphaNum <|> oneOf "-_:."
+ return (first:rest)
+
+identifierAttr :: GenParser Char st ([Char], [a], [a1])
+identifierAttr = try $ do
+ char '#'
+ result <- identifier
+ return (result,[],[])
+
+classAttr :: GenParser Char st ([Char], [[Char]], [a])
+classAttr = try $ do
+ char '.'
+ result <- identifier
+ return ("",[result],[])
+
+keyValAttr :: GenParser Char st ([Char], [a], [([Char], [Char])])
+keyValAttr = try $ do
+ key <- identifier
+ char '='
+ char '"'
+ val <- manyTill (noneOf "\n") (char '"')
+ return ("",[],[(key,val)])
+
+codeBlockDelimited :: GenParser Char st Block
+codeBlockDelimited = try $ do
+ (size, attr) <- codeBlockDelimiter Nothing
+ contents <- manyTill anyLine (codeBlockDelimiter (Just size))
+ blanklines
+ return $ CodeBlock attr $ intercalate "\n" contents
+
+codeBlockIndented :: GenParser Char ParserState Block
+codeBlockIndented = do
+ contents <- many1 (indentedLine <|>
+ try (do b <- blanklines
+ l <- indentedLine
+ return $ b ++ l))
+ optional blanklines
+ return $ CodeBlock ("",[],[]) $ stripTrailingNewlines $ concat contents
+
+lhsCodeBlock :: GenParser Char ParserState Block
+lhsCodeBlock = do
+ failUnlessLHS
+ contents <- lhsCodeBlockBird <|> lhsCodeBlockLaTeX
+ return $ CodeBlock ("",["sourceCode","haskell"],[]) contents
+
+lhsCodeBlockLaTeX :: GenParser Char ParserState String
+lhsCodeBlockLaTeX = try $ do
+ string "\\begin{code}"
+ manyTill spaceChar newline
+ contents <- many1Till anyChar (try $ string "\\end{code}")
+ blanklines
+ return $ stripTrailingNewlines contents
+
+lhsCodeBlockBird :: GenParser Char ParserState String
+lhsCodeBlockBird = try $ do
+ pos <- getPosition
+ when (sourceColumn pos /= 1) $ fail "Not in first column"
+ lns <- many1 birdTrackLine
+ -- if (as is normal) there is always a space after >, drop it
+ let lns' = if all (\ln -> null ln || take 1 ln == " ") lns
+ then map (drop 1) lns
+ else lns
+ blanklines
+ return $ intercalate "\n" lns'
+
+birdTrackLine :: GenParser Char st [Char]
+birdTrackLine = do
+ char '>'
+ manyTill anyChar newline
+
+
+--
+-- block quotes
+--
+
+emailBlockQuoteStart :: GenParser Char ParserState Char
+emailBlockQuoteStart = try $ skipNonindentSpaces >> char '>' >>~ optional (char ' ')
+
+emailBlockQuote :: GenParser Char ParserState [[Char]]
+emailBlockQuote = try $ do
+ emailBlockQuoteStart
+ raw <- sepBy (many (nonEndline <|>
+ (try (endline >> notFollowedBy emailBlockQuoteStart >>
+ return '\n'))))
+ (try (newline >> emailBlockQuoteStart))
+ newline <|> (eof >> return '\n')
+ optional blanklines
+ return raw
+
+blockQuote :: GenParser Char ParserState Block
+blockQuote = do
+ raw <- emailBlockQuote
+ -- parse the extracted block, which may contain various block elements:
+ contents <- parseFromString parseBlocks $ (intercalate "\n" raw) ++ "\n\n"
+ return $ BlockQuote contents
+
+--
+-- list blocks
+--
+
+bulletListStart :: GenParser Char ParserState ()
+bulletListStart = try $ do
+ optional newline -- if preceded by a Plain block in a list context
+ skipNonindentSpaces
+ notFollowedBy' hrule -- because hrules start out just like lists
+ oneOf bulletListMarkers
+ spaceChar
+ skipSpaces
+
+anyOrderedListStart :: GenParser Char ParserState (Int, ListNumberStyle, ListNumberDelim)
+anyOrderedListStart = try $ do
+ optional newline -- if preceded by a Plain block in a list context
+ skipNonindentSpaces
+ notFollowedBy $ string "p." >> spaceChar >> digit -- page number
+ state <- getState
+ if stateStrict state
+ then do many1 digit
+ char '.'
+ spaceChar
+ return (1, DefaultStyle, DefaultDelim)
+ else do (num, style, delim) <- anyOrderedListMarker
+ -- if it could be an abbreviated first name, insist on more than one space
+ if delim == Period && (style == UpperAlpha || (style == UpperRoman &&
+ num `elem` [1, 5, 10, 50, 100, 500, 1000]))
+ then char '\t' <|> (char ' ' >>~ notFollowedBy (satisfy isUpper))
+ else spaceChar
+ skipSpaces
+ return (num, style, delim)
+
+listStart :: GenParser Char ParserState ()
+listStart = bulletListStart <|> (anyOrderedListStart >> return ())
+
+-- parse a line of a list item (start = parser for beginning of list item)
+listLine :: GenParser Char ParserState [Char]
+listLine = try $ do
+ notFollowedBy' listStart
+ notFollowedBy blankline
+ notFollowedBy' (do indentSpaces
+ many (spaceChar)
+ listStart)
+ line <- manyTill anyChar newline
+ return $ line ++ "\n"
+
+-- parse raw text for one list item, excluding start marker and continuations
+rawListItem :: GenParser Char ParserState [Char]
+rawListItem = try $ do
+ listStart
+ result <- many1 listLine
+ blanks <- many blankline
+ return $ concat result ++ blanks
+
+-- continuation of a list item - indented and separated by blankline
+-- or (in compact lists) endline.
+-- note: nested lists are parsed as continuations
+listContinuation :: GenParser Char ParserState [Char]
+listContinuation = try $ do
+ lookAhead indentSpaces
+ result <- many1 listContinuationLine
+ blanks <- many blankline
+ return $ concat result ++ blanks
+
+listContinuationLine :: GenParser Char ParserState [Char]
+listContinuationLine = try $ do
+ notFollowedBy blankline
+ notFollowedBy' listStart
+ optional indentSpaces
+ result <- manyTill anyChar newline
+ return $ result ++ "\n"
+
+listItem :: GenParser Char ParserState [Block]
+listItem = try $ do
+ first <- rawListItem
+ continuations <- many listContinuation
+ -- parsing with ListItemState forces markers at beginning of lines to
+ -- count as list item markers, even if not separated by blank space.
+ -- see definition of "endline"
+ state <- getState
+ let oldContext = stateParserContext state
+ setState $ state {stateParserContext = ListItemState}
+ -- parse the extracted block, which may contain various block elements:
+ let raw = concat (first:continuations)
+ contents <- parseFromString parseBlocks raw
+ updateState (\st -> st {stateParserContext = oldContext})
+ return contents
+
+orderedList :: GenParser Char ParserState Block
+orderedList = try $ do
+ (start, style, delim) <- lookAhead anyOrderedListStart
+ items <- many1 listItem
+ return $ OrderedList (start, style, delim) $ compactify items
+
+bulletList :: GenParser Char ParserState Block
+bulletList = try $ do
+ lookAhead bulletListStart
+ many1 listItem >>= return . BulletList . compactify
+
+-- definition lists
+
+definitionListItem :: GenParser Char ParserState ([Inline], [Block])
+definitionListItem = try $ do
+ notFollowedBy blankline
+ notFollowedBy' indentSpaces
+ -- first, see if this has any chance of being a definition list:
+ lookAhead (anyLine >> char ':')
+ term <- manyTill inline newline
+ raw <- many1 defRawBlock
+ state <- getState
+ let oldContext = stateParserContext state
+ -- parse the extracted block, which may contain various block elements:
+ contents <- parseFromString parseBlocks $ concat raw
+ updateState (\st -> st {stateParserContext = oldContext})
+ return ((normalizeSpaces term), contents)
+
+defRawBlock :: GenParser Char ParserState [Char]
+defRawBlock = try $ do
+ char ':'
+ state <- getState
+ let tabStop = stateTabStop state
+ try (count (tabStop - 1) (char ' ')) <|> (many (char ' ') >> string "\t")
+ firstline <- anyLine
+ rawlines <- many (notFollowedBy blankline >> indentSpaces >> anyLine)
+ trailing <- option "" blanklines
+ return $ firstline ++ "\n" ++ unlines rawlines ++ trailing
+
+definitionList :: GenParser Char ParserState Block
+definitionList = do
+ items <- many1 definitionListItem
+ let (terms, defs) = unzip items
+ let defs' = compactify defs
+ let items' = zip terms defs'
+ return $ DefinitionList items'
+
+--
+-- paragraph block
+--
+
+isHtmlOrBlank :: Inline -> Bool
+isHtmlOrBlank (HtmlInline _) = True
+isHtmlOrBlank (Space) = True
+isHtmlOrBlank (LineBreak) = True
+isHtmlOrBlank _ = False
+
+para :: GenParser Char ParserState Block
+para = try $ do
+ result <- many1 inline
+ if all isHtmlOrBlank result
+ then fail "treat as raw HTML"
+ else return ()
+ newline
+ blanklines <|> do st <- getState
+ if stateStrict st
+ then lookAhead (blockQuote <|> header) >> return ""
+ else pzero
+ return $ Para $ normalizeSpaces result
+
+plain :: GenParser Char ParserState Block
+plain = many1 inline >>~ spaces >>= return . Plain . normalizeSpaces
+
+--
+-- raw html
+--
+
+htmlElement :: GenParser Char ParserState [Char]
+htmlElement = strictHtmlBlock <|> htmlBlockElement <?> "html element"
+
+htmlBlock :: GenParser Char ParserState Block
+htmlBlock = try $ do
+ failUnlessBeginningOfLine
+ first <- htmlElement
+ finalSpace <- many spaceChar
+ finalNewlines <- many newline
+ return $ RawHtml $ first ++ finalSpace ++ finalNewlines
+
+-- True if tag is self-closing
+isSelfClosing :: [Char] -> Bool
+isSelfClosing tag =
+ isSuffixOf "/>" $ filter (not . (`elem` " \n\t")) tag
+
+strictHtmlBlock :: GenParser Char ParserState [Char]
+strictHtmlBlock = try $ do
+ tag <- anyHtmlBlockTag
+ let tag' = extractTagType tag
+ if isSelfClosing tag || tag' == "hr"
+ then return tag
+ else do contents <- many (notFollowedBy' (htmlEndTag tag') >>
+ (htmlElement <|> (count 1 anyChar)))
+ end <- htmlEndTag tag'
+ return $ tag ++ concat contents ++ end
+
+rawHtmlBlocks :: GenParser Char ParserState Block
+rawHtmlBlocks = do
+ htmlBlocks <- many1 $ do (RawHtml blk) <- rawHtmlBlock
+ sps <- do sp1 <- many spaceChar
+ sp2 <- option "" (blankline >> return "\n")
+ sp3 <- many spaceChar
+ sp4 <- option "" blanklines
+ return $ sp1 ++ sp2 ++ sp3 ++ sp4
+ -- note: we want raw html to be able to
+ -- precede a code block, when separated
+ -- by a blank line
+ return $ blk ++ sps
+ let combined = concat htmlBlocks
+ let combined' = if last combined == '\n' then init combined else combined
+ return $ RawHtml combined'
+
+--
+-- Tables
+--
+
+-- Parse a dashed line with optional trailing spaces; return its length
+-- and the length including trailing space.
+dashedLine :: Char
+ -> GenParser Char st (Int, Int)
+dashedLine ch = do
+ dashes <- many1 (char ch)
+ sp <- many spaceChar
+ return $ (length dashes, length $ dashes ++ sp)
+
+-- Parse a table header with dashed lines of '-' preceded by
+-- one line of text.
+simpleTableHeader :: GenParser Char ParserState ([[Char]], [Alignment], [Int])
+simpleTableHeader = try $ do
+ rawContent <- anyLine
+ initSp <- nonindentSpaces
+ dashes <- many1 (dashedLine '-')
+ newline
+ let (lengths, lines') = unzip dashes
+ let indices = scanl (+) (length initSp) lines'
+ let rawHeads = tail $ splitByIndices (init indices) rawContent
+ let aligns = zipWith alignType (map (\a -> [a]) rawHeads) lengths
+ return (rawHeads, aligns, indices)
+
+-- Parse a table footer - dashed lines followed by blank line.
+tableFooter :: GenParser Char ParserState [Char]
+tableFooter = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> blanklines
+
+-- Parse a table separator - dashed line.
+tableSep :: GenParser Char ParserState String
+tableSep = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> string "\n"
+
+-- Parse a raw line and split it into chunks by indices.
+rawTableLine :: [Int]
+ -> GenParser Char ParserState [String]
+rawTableLine indices = do
+ notFollowedBy' (blanklines <|> tableFooter)
+ line <- many1Till anyChar newline
+ return $ map removeLeadingTrailingSpace $ tail $
+ splitByIndices (init indices) line
+
+-- Parse a table line and return a list of lists of blocks (columns).
+tableLine :: [Int]
+ -> GenParser Char ParserState [[Block]]
+tableLine indices = rawTableLine indices >>= mapM (parseFromString (many plain))
+
+-- Parse a multiline table row and return a list of blocks (columns).
+multilineRow :: [Int]
+ -> GenParser Char ParserState [[Block]]
+multilineRow indices = do
+ colLines <- many1 (rawTableLine indices)
+ optional blanklines
+ let cols = map unlines $ transpose colLines
+ mapM (parseFromString (many plain)) cols
+
+-- Calculate relative widths of table columns, based on indices
+widthsFromIndices :: Int -- Number of columns on terminal
+ -> [Int] -- Indices
+ -> [Double] -- Fractional relative sizes of columns
+widthsFromIndices _ [] = []
+widthsFromIndices numColumns indices =
+ let lengths = zipWith (-) indices (0:indices)
+ totLength = sum lengths
+ quotient = if totLength > numColumns
+ then fromIntegral totLength
+ else fromIntegral numColumns
+ fracs = map (\l -> (fromIntegral l) / quotient) lengths in
+ tail fracs
+
+-- Parses a table caption: inlines beginning with 'Table:'
+-- and followed by blank lines.
+tableCaption :: GenParser Char ParserState [Inline]
+tableCaption = try $ do
+ skipNonindentSpaces
+ string "Table:"
+ result <- many1 inline
+ blanklines
+ return $ normalizeSpaces result
+
+-- Parse a table using 'headerParser', 'lineParser', and 'footerParser'.
+tableWith :: GenParser Char ParserState ([[Char]], [Alignment], [Int])
+ -> ([Int] -> GenParser Char ParserState [[Block]])
+ -> GenParser Char ParserState end
+ -> GenParser Char ParserState Block
+tableWith headerParser lineParser footerParser = try $ do
+ (rawHeads, aligns, indices) <- headerParser
+ lines' <- many1Till (lineParser indices) footerParser
+ caption <- option [] tableCaption
+ heads <- mapM (parseFromString (many plain)) rawHeads
+ state <- getState
+ let numColumns = stateColumns state
+ let widths = widthsFromIndices numColumns indices
+ return $ Table caption aligns widths heads lines'
+
+-- Parse a simple table with '---' header and one line per row.
+simpleTable :: GenParser Char ParserState Block
+simpleTable = tableWith simpleTableHeader tableLine blanklines
+
+-- Parse a multiline table: starts with row of '-' on top, then header
+-- (which may be multiline), then the rows,
+-- which may be multiline, separated by blank lines, and
+-- ending with a footer (dashed line followed by blank line).
+multilineTable :: GenParser Char ParserState Block
+multilineTable = tableWith multilineTableHeader multilineRow tableFooter
+
+multilineTableHeader :: GenParser Char ParserState ([String], [Alignment], [Int])
+multilineTableHeader = try $ do
+ tableSep
+ rawContent <- many1 (notFollowedBy' tableSep >> many1Till anyChar newline)
+ initSp <- nonindentSpaces
+ dashes <- many1 (dashedLine '-')
+ newline
+ let (lengths, lines') = unzip dashes
+ let indices = scanl (+) (length initSp) lines'
+ let rawHeadsList = transpose $ map
+ (\ln -> tail $ splitByIndices (init indices) ln)
+ rawContent
+ let rawHeads = map (intercalate " ") rawHeadsList
+ let aligns = zipWith alignType rawHeadsList lengths
+ return ((map removeLeadingTrailingSpace rawHeads), aligns, indices)
+
+-- Returns an alignment type for a table, based on a list of strings
+-- (the rows of the column header) and a number (the length of the
+-- dashed line under the rows.
+alignType :: [String]
+ -> Int
+ -> Alignment
+alignType [] _ = AlignDefault
+alignType strLst len =
+ let s = head $ sortBy (comparing length) $
+ map removeTrailingSpace strLst
+ leftSpace = if null s then False else (s !! 0) `elem` " \t"
+ rightSpace = length s < len || (s !! (len - 1)) `elem` " \t"
+ in case (leftSpace, rightSpace) of
+ (True, False) -> AlignRight
+ (False, True) -> AlignLeft
+ (True, True) -> AlignCenter
+ (False, False) -> AlignDefault
+
+table :: GenParser Char ParserState Block
+table = simpleTable <|> multilineTable <?> "table"
+
+--
+-- inline
+--
+
+inline :: GenParser Char ParserState Inline
+inline = choice inlineParsers <?> "inline"
+
+inlineParsers :: [GenParser Char ParserState Inline]
+inlineParsers = [ str
+ , smartPunctuation
+ , whitespace
+ , endline
+ , code
+ , charRef
+ , strong
+ , emph
+ , note
+ , inlineNote
+ , link
+#ifdef _CITEPROC
+ , inlineCitation
+#endif
+ , image
+ , math
+ , strikeout
+ , superscript
+ , subscript
+ , autoLink
+ , rawHtmlInline'
+ , rawLaTeXInline'
+ , escapedChar
+ , symbol
+ , ltSign ]
+
+inlineNonLink :: GenParser Char ParserState Inline
+inlineNonLink = (choice $
+ map (\parser -> try (parser >>= failIfLink)) inlineParsers)
+ <?> "inline (non-link)"
+
+failIfLink :: Inline -> GenParser tok st Inline
+failIfLink (Link _ _) = pzero
+failIfLink elt = return elt
+
+escapedChar :: GenParser Char ParserState Inline
+escapedChar = do
+ char '\\'
+ state <- getState
+ result <- option '\\' $ if stateStrict state
+ then oneOf "\\`*_{}[]()>#+-.!~"
+ else satisfy (not . isAlphaNum)
+ let result' = if result == ' '
+ then '\160' -- '\ ' is a nonbreaking space
+ else result
+ return $ Str [result']
+
+ltSign :: GenParser Char ParserState Inline
+ltSign = do
+ st <- getState
+ if stateStrict st
+ then char '<'
+ else notFollowedBy' rawHtmlBlocks >> char '<' -- unless it starts html
+ return $ Str ['<']
+
+specialCharsMinusLt :: [Char]
+specialCharsMinusLt = filter (/= '<') specialChars
+
+symbol :: GenParser Char ParserState Inline
+symbol = do
+ result <- oneOf specialCharsMinusLt
+ return $ Str [result]
+
+-- parses inline code, between n `s and n `s
+code :: GenParser Char ParserState Inline
+code = try $ do
+ starts <- many1 (char '`')
+ skipSpaces
+ result <- many1Till (many1 (noneOf "`\n") <|> many1 (char '`') <|>
+ (char '\n' >> return " "))
+ (try (skipSpaces >> count (length starts) (char '`') >>
+ notFollowedBy (char '`')))
+ return $ Code $ removeLeadingTrailingSpace $ concat result
+
+mathWord :: GenParser Char st [Char]
+mathWord = many1 ((noneOf " \t\n\\$") <|>
+ (try (char '\\') >>~ notFollowedBy (char '$')))
+
+math :: GenParser Char ParserState Inline
+math = (mathDisplay >>= return . Math DisplayMath)
+ <|> (mathInline >>= return . Math InlineMath)
+
+mathDisplay :: GenParser Char ParserState String
+mathDisplay = try $ do
+ failIfStrict
+ string "$$"
+ many1Till (noneOf "\n" <|> (newline >>~ notFollowedBy' blankline)) (try $ string "$$")
+
+mathInline :: GenParser Char ParserState String
+mathInline = try $ do
+ failIfStrict
+ char '$'
+ notFollowedBy space
+ words' <- sepBy1 mathWord (many1 (spaceChar <|> (newline >>~ notFollowedBy' blankline)))
+ char '$'
+ notFollowedBy digit
+ return $ intercalate " " words'
+
+emph :: GenParser Char ParserState Inline
+emph = ((enclosed (char '*') (notFollowedBy' strong >> char '*') inline) <|>
+ (enclosed (char '_') (notFollowedBy' strong >> char '_' >>
+ notFollowedBy alphaNum) inline)) >>=
+ return . Emph . normalizeSpaces
+
+strong :: GenParser Char ParserState Inline
+strong = ((enclosed (string "**") (try $ string "**") inline) <|>
+ (enclosed (string "__") (try $ string "__") inline)) >>=
+ return . Strong . normalizeSpaces
+
+strikeout :: GenParser Char ParserState Inline
+strikeout = failIfStrict >> enclosed (string "~~") (try $ string "~~") inline >>=
+ return . Strikeout . normalizeSpaces
+
+superscript :: GenParser Char ParserState Inline
+superscript = failIfStrict >> enclosed (char '^') (char '^')
+ (notFollowedBy spaceChar >> inline) >>= -- may not contain Space
+ return . Superscript
+
+subscript :: GenParser Char ParserState Inline
+subscript = failIfStrict >> enclosed (char '~') (char '~')
+ (notFollowedBy spaceChar >> inline) >>= -- may not contain Space
+ return . Subscript
+
+smartPunctuation :: GenParser Char ParserState Inline
+smartPunctuation = failUnlessSmart >>
+ choice [ quoted, apostrophe, dash, ellipses ]
+
+apostrophe :: GenParser Char ParserState Inline
+apostrophe = (char '\'' <|> char '\8217') >> return Apostrophe
+
+quoted :: GenParser Char ParserState Inline
+quoted = doubleQuoted <|> singleQuoted
+
+withQuoteContext :: QuoteContext
+ -> (GenParser Char ParserState Inline)
+ -> GenParser Char ParserState Inline
+withQuoteContext context parser = do
+ oldState <- getState
+ let oldQuoteContext = stateQuoteContext oldState
+ setState oldState { stateQuoteContext = context }
+ result <- parser
+ newState <- getState
+ setState newState { stateQuoteContext = oldQuoteContext }
+ return result
+
+singleQuoted :: GenParser Char ParserState Inline
+singleQuoted = try $ do
+ singleQuoteStart
+ withQuoteContext InSingleQuote $ many1Till inline singleQuoteEnd >>=
+ return . Quoted SingleQuote . normalizeSpaces
+
+doubleQuoted :: GenParser Char ParserState Inline
+doubleQuoted = try $ do
+ doubleQuoteStart
+ withQuoteContext InDoubleQuote $ many1Till inline doubleQuoteEnd >>=
+ return . Quoted DoubleQuote . normalizeSpaces
+
+failIfInQuoteContext :: QuoteContext -> GenParser tok ParserState ()
+failIfInQuoteContext context = do
+ st <- getState
+ if stateQuoteContext st == context
+ then fail "already inside quotes"
+ else return ()
+
+singleQuoteStart :: GenParser Char ParserState Char
+singleQuoteStart = do
+ failIfInQuoteContext InSingleQuote
+ char '\8216' <|>
+ (try $ do char '\''
+ notFollowedBy (oneOf ")!],.;:-? \t\n")
+ notFollowedBy (try (oneOfStrings ["s","t","m","ve","ll","re"] >>
+ satisfy (not . isAlphaNum)))
+ -- possess/contraction
+ return '\'')
+
+singleQuoteEnd :: GenParser Char st Char
+singleQuoteEnd = try $ do
+ char '\8217' <|> char '\''
+ notFollowedBy alphaNum
+ return '\''
+
+doubleQuoteStart :: GenParser Char ParserState Char
+doubleQuoteStart = do
+ failIfInQuoteContext InDoubleQuote
+ char '\8220' <|>
+ (try $ do char '"'
+ notFollowedBy (oneOf " \t\n")
+ return '"')
+
+doubleQuoteEnd :: GenParser Char st Char
+doubleQuoteEnd = char '\8221' <|> char '"'
+
+ellipses :: GenParser Char st Inline
+ellipses = oneOfStrings ["...", " . . . ", ". . .", " . . ."] >> return Ellipses
+
+dash :: GenParser Char st Inline
+dash = enDash <|> emDash
+
+enDash :: GenParser Char st Inline
+enDash = try $ char '-' >> notFollowedBy (noneOf "0123456789") >> return EnDash
+
+emDash :: GenParser Char st Inline
+emDash = oneOfStrings ["---", "--"] >> return EmDash
+
+whitespace :: GenParser Char ParserState Inline
+whitespace = spaceChar >>
+ ( (spaceChar >> skipMany spaceChar >> option Space (endline >> return LineBreak))
+ <|> (skipMany spaceChar >> return Space) ) <?> "whitespace"
+
+nonEndline :: GenParser Char st Char
+nonEndline = satisfy (/='\n')
+
+strChar :: GenParser Char st Char
+strChar = noneOf (specialChars ++ " \t\n")
+
+str :: GenParser Char ParserState Inline
+str = do
+ result <- many1 strChar
+ state <- getState
+ let spacesToNbr = map (\c -> if c == ' ' then '\160' else c)
+ if stateSmart state
+ then case likelyAbbrev result of
+ [] -> return $ Str result
+ xs -> choice (map (\x ->
+ try (string x >> char ' ' >>
+ notFollowedBy spaceChar >>
+ return (Str $ result ++ spacesToNbr x ++ "\160"))) xs)
+ <|> (return $ Str result)
+ else return $ Str result
+
+-- | if the string matches the beginning of an abbreviation (before
+-- the first period, return strings that would finish the abbreviation.
+likelyAbbrev :: String -> [String]
+likelyAbbrev x =
+ let abbrevs = [ "Mr.", "Mrs.", "Ms.", "Capt.", "Dr.", "Prof.",
+ "Gen.", "Gov.", "e.g.", "i.e.", "Sgt.", "St.",
+ "vol.", "vs.", "Sen.", "Rep.", "Pres.", "Hon.",
+ "Rev.", "Ph.D.", "M.D.", "M.A." ]
+ abbrPairs = map (break (=='.')) abbrevs
+ in map snd $ filter (\(y,_) -> y == x) abbrPairs
+
+-- an endline character that can be treated as a space, not a structural break
+endline :: GenParser Char ParserState Inline
+endline = try $ do
+ newline
+ notFollowedBy blankline
+ st <- getState
+ if stateStrict st
+ then do notFollowedBy emailBlockQuoteStart
+ notFollowedBy (char '#') -- atx header
+ else return ()
+ -- parse potential list-starts differently if in a list:
+ if stateParserContext st == ListItemState
+ then notFollowedBy' (bulletListStart <|>
+ (anyOrderedListStart >> return ()))
+ else return ()
+ return Space
+
+--
+-- links
+--
+
+-- a reference label for a link
+reference :: GenParser Char ParserState [Inline]
+reference = do notFollowedBy' (string "[^") -- footnote reference
+ result <- inlinesInBalancedBrackets inlineNonLink
+ return $ normalizeSpaces result
+
+-- source for a link, with optional title
+source :: GenParser Char st (String, [Char])
+source =
+ (try $ charsInBalanced '(' ')' >>= parseFromString source') <|>
+ -- the following is needed for cases like: [ref](/url(a).
+ (enclosed (char '(') (char ')') anyChar >>=
+ parseFromString source')
+
+-- auxiliary function for source
+source' :: GenParser Char st (String, [Char])
+source' = do
+ skipSpaces
+ let sourceURL excludes = many $
+ optional (char '\\') >> (noneOf (' ':excludes) <|> (notFollowedBy' linkTitle >> char ' '))
+ src <- try (char '<' >> sourceURL ">\t\n" >>~ char '>') <|> sourceURL "\t\n"
+ tit <- option "" linkTitle
+ skipSpaces
+ eof
+ return (intercalate "%20" $ words $ removeTrailingSpace src, tit)
+
+linkTitle :: GenParser Char st String
+linkTitle = try $ do
+ (many1 spaceChar >> option '\n' newline) <|> newline
+ skipSpaces
+ delim <- oneOf "'\""
+ tit <- manyTill (optional (char '\\') >> anyChar)
+ (try (char delim >> skipSpaces >> eof))
+ return $ decodeCharacterReferences tit
+
+link :: GenParser Char ParserState Inline
+link = try $ do
+ lab <- reference
+ src <- source <|> referenceLink lab
+ sanitize <- getState >>= return . stateSanitizeHTML
+ if sanitize && unsanitaryURI (fst src)
+ then fail "Unsanitary URI"
+ else return $ Link lab src
+
+-- a link like [this][ref] or [this][] or [this]
+referenceLink :: [Inline]
+ -> GenParser Char ParserState (String, [Char])
+referenceLink lab = do
+ ref <- option [] (try (optional (char ' ') >>
+ optional (newline >> skipSpaces) >> reference))
+ let ref' = if null ref then lab else ref
+ state <- getState
+ case lookupKeySrc (stateKeys state) ref' of
+ Nothing -> fail "no corresponding key"
+ Just target -> return target
+
+autoLink :: GenParser Char ParserState Inline
+autoLink = try $ do
+ char '<'
+ src <- uri <|> (emailAddress >>= (return . ("mailto:" ++)))
+ char '>'
+ let src' = if "mailto:" `isPrefixOf` src
+ then drop 7 src
+ else src
+ st <- getState
+ let sanitize = stateSanitizeHTML st
+ if sanitize && unsanitaryURI src
+ then fail "Unsanitary URI"
+ else return $ if stateStrict st
+ then Link [Str src'] (src, "")
+ else Link [Code src'] (src, "")
+
+image :: GenParser Char ParserState Inline
+image = try $ do
+ char '!'
+ (Link lab src) <- link
+ return $ Image lab src
+
+note :: GenParser Char ParserState Inline
+note = try $ do
+ failIfStrict
+ ref <- noteMarker
+ state <- getState
+ let notes = stateNotes state
+ case lookup ref notes of
+ Nothing -> fail "note not found"
+ Just contents -> return $ Note contents
+
+inlineNote :: GenParser Char ParserState Inline
+inlineNote = try $ do
+ failIfStrict
+ char '^'
+ contents <- inlinesInBalancedBrackets inline
+ return $ Note [Para contents]
+
+rawLaTeXInline' :: GenParser Char ParserState Inline
+rawLaTeXInline' = do
+ failIfStrict
+ (rawConTeXtEnvironment' >>= return . TeX)
+ <|> (rawLaTeXEnvironment' >>= return . TeX)
+ <|> rawLaTeXInline
+
+rawConTeXtEnvironment' :: GenParser Char st String
+rawConTeXtEnvironment' = try $ do
+ string "\\start"
+ completion <- inBrackets (letter <|> digit <|> spaceChar)
+ <|> (many1 letter)
+ contents <- manyTill (rawConTeXtEnvironment' <|> (count 1 anyChar))
+ (try $ string "\\stop" >> string completion)
+ return $ "\\start" ++ completion ++ concat contents ++ "\\stop" ++ completion
+
+inBrackets :: (GenParser Char st Char) -> GenParser Char st String
+inBrackets parser = do
+ char '['
+ contents <- many parser
+ char ']'
+ return $ "[" ++ contents ++ "]"
+
+rawHtmlInline' :: GenParser Char ParserState Inline
+rawHtmlInline' = do
+ st <- getState
+ result <- if stateStrict st
+ then choice [htmlBlockElement, anyHtmlTag, anyHtmlEndTag]
+ else anyHtmlInlineTag
+ return $ HtmlInline result
+
+#ifdef _CITEPROC
+inlineCitation :: GenParser Char ParserState Inline
+inlineCitation = try $ do
+ failIfStrict
+ cit <- citeMarker
+ let citations = readWith parseCitation defaultParserState cit
+ mr <- mapM chkCit citations
+ if catMaybes mr /= []
+ then return $ Cite citations []
+ else fail "no citation found"
+
+chkCit :: Target -> GenParser Char ParserState (Maybe Target)
+chkCit t = do
+ st <- getState
+ case lookupKeySrc (stateKeys st) [Str $ fst t] of
+ Just _ -> fail "This is a link"
+ Nothing -> if elem (fst t) $ stateCitations st
+ then return $ Just t
+ else return $ Nothing
+
+citeMarker :: GenParser Char ParserState String
+citeMarker = char '[' >> manyTill ( noneOf "\n" <|> (newline >>~ notFollowedBy blankline) ) (char ']')
+
+parseCitation :: GenParser Char ParserState [(String,String)]
+parseCitation = try $ sepBy (parseLabel) (oneOf ";")
+
+parseLabel :: GenParser Char ParserState (String,String)
+parseLabel = try $ do
+ res <- sepBy (skipSpaces >> optional newline >> skipSpaces >> many1 (noneOf "@;")) (oneOf "@")
+ case res of
+ [lab,loc] -> return (lab, loc)
+ [lab] -> return (lab, "" )
+ _ -> return ("" , "" )
+
+#endif
diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs
new file mode 100644
index 000000000..884d6f0e6
--- /dev/null
+++ b/src/Text/Pandoc/Readers/RST.hs
@@ -0,0 +1,706 @@
+{-
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.RST
+ Copyright : Copyright (C) 2006-8 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion from reStructuredText to 'Pandoc' document.
+-}
+module Text.Pandoc.Readers.RST (
+ readRST
+ ) where
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Text.ParserCombinators.Parsec
+import Control.Monad ( when )
+import Data.List ( findIndex, delete, intercalate )
+
+-- | Parse reStructuredText string and return Pandoc document.
+readRST :: ParserState -> String -> Pandoc
+readRST state s = (readWith parseRST) state (s ++ "\n\n")
+
+--
+-- Constants and data structure definitions
+---
+
+bulletListMarkers :: [Char]
+bulletListMarkers = "*+-"
+
+underlineChars :: [Char]
+underlineChars = "!\"#$&'()*+,-./:;<=>?@[\\]^_`{|}~"
+
+-- treat these as potentially non-text when parsing inline:
+specialChars :: [Char]
+specialChars = "\\`|*_<>$:[-"
+
+--
+-- parsing documents
+--
+
+isHeader :: Int -> Block -> Bool
+isHeader n (Header x _) = x == n
+isHeader _ _ = False
+
+-- | Promote all headers in a list of blocks. (Part of
+-- title transformation for RST.)
+promoteHeaders :: Int -> [Block] -> [Block]
+promoteHeaders num ((Header level text):rest) =
+ (Header (level - num) text):(promoteHeaders num rest)
+promoteHeaders num (other:rest) = other:(promoteHeaders num rest)
+promoteHeaders _ [] = []
+
+-- | If list of blocks starts with a header (or a header and subheader)
+-- of level that are not found elsewhere, return it as a title and
+-- promote all the other headers.
+titleTransform :: [Block] -- ^ list of blocks
+ -> ([Block], [Inline]) -- ^ modified list of blocks, title
+titleTransform ((Header 1 head1):(Header 2 head2):rest) |
+ not (any (isHeader 1) rest || any (isHeader 2) rest) = -- both title & subtitle
+ (promoteHeaders 2 rest, head1 ++ [Str ":", Space] ++ head2)
+titleTransform ((Header 1 head1):rest) |
+ not (any (isHeader 1) rest) = -- title, no subtitle
+ (promoteHeaders 1 rest, head1)
+titleTransform blocks = (blocks, [])
+
+parseRST :: GenParser Char ParserState Pandoc
+parseRST = do
+ startPos <- getPosition
+ -- go through once just to get list of reference keys
+ -- docMinusKeys is the raw document with blanks where the keys were...
+ docMinusKeys <- manyTill (referenceKey <|> lineClump) eof >>= return . concat
+ setInput docMinusKeys
+ setPosition startPos
+ st <- getState
+ let reversedKeys = stateKeys st
+ updateState $ \s -> s { stateKeys = reverse reversedKeys }
+ -- now parse it for real...
+ blocks <- parseBlocks
+ let blocks' = filter (/= Null) blocks
+ state <- getState
+ let (blocks'', title) = if stateStandalone state
+ then titleTransform blocks'
+ else (blocks', [])
+ let authors = stateAuthors state
+ let date = stateDate state
+ let title' = if (null title) then (stateTitle state) else title
+ return $ Pandoc (Meta title' authors date) blocks''
+
+--
+-- parsing blocks
+--
+
+parseBlocks :: GenParser Char ParserState [Block]
+parseBlocks = manyTill block eof
+
+block :: GenParser Char ParserState Block
+block = choice [ codeBlock
+ , rawHtmlBlock
+ , rawLaTeXBlock
+ , fieldList
+ , blockQuote
+ , imageBlock
+ , unknownDirective
+ , header
+ , hrule
+ , lineBlock -- must go before definitionList
+ , list
+ , lhsCodeBlock
+ , para
+ , plain
+ , nullBlock ] <?> "block"
+
+--
+-- field list
+--
+
+fieldListItem :: String -> GenParser Char st ([Char], [Char])
+fieldListItem indent = try $ do
+ string indent
+ char ':'
+ name <- many1 alphaNum
+ string ": "
+ skipSpaces
+ first <- manyTill anyChar newline
+ rest <- option "" $ try $ lookAhead (string indent >> oneOf " \t") >>
+ indentedBlock
+ return (name, intercalate " " (first:(lines rest)))
+
+fieldList :: GenParser Char ParserState Block
+fieldList = try $ do
+ indent <- lookAhead $ many (oneOf " \t")
+ items <- many1 $ fieldListItem indent
+ blanklines
+ let authors = case lookup "Authors" items of
+ Just auth -> [auth]
+ Nothing -> map snd (filter (\(x,_) -> x == "Author") items)
+ if null authors
+ then return ()
+ else updateState $ \st -> st {stateAuthors = authors}
+ case (lookup "Date" items) of
+ Just dat -> updateState $ \st -> st {stateDate = dat}
+ Nothing -> return ()
+ case (lookup "Title" items) of
+ Just tit -> parseFromString (many inline) tit >>=
+ \t -> updateState $ \st -> st {stateTitle = t}
+ Nothing -> return ()
+ let remaining = filter (\(x,_) -> (x /= "Authors") && (x /= "Author") &&
+ (x /= "Date") && (x /= "Title")) items
+ if null remaining
+ then return Null
+ else do terms <- mapM (return . (:[]) . Str . fst) remaining
+ defs <- mapM (parseFromString (many block) . snd)
+ remaining
+ return $ DefinitionList $ zip terms defs
+
+--
+-- line block
+--
+
+lineBlockLine :: GenParser Char ParserState [Inline]
+lineBlockLine = try $ do
+ string "| "
+ white <- many (oneOf " \t")
+ line <- many $ (notFollowedBy newline >> inline) <|> (try $ endline >>~ char ' ')
+ optional endline
+ return $ normalizeSpaces $ (if null white then [] else [Str white]) ++ line
+
+lineBlock :: GenParser Char ParserState Block
+lineBlock = try $ do
+ lines' <- many1 lineBlockLine
+ blanklines
+ return $ Para (intercalate [LineBreak] lines')
+
+--
+-- paragraph block
+--
+
+para :: GenParser Char ParserState Block
+para = paraBeforeCodeBlock <|> paraNormal <?> "paragraph"
+
+codeBlockStart :: GenParser Char st Char
+codeBlockStart = string "::" >> blankline >> blankline
+
+-- paragraph that ends in a :: starting a code block
+paraBeforeCodeBlock :: GenParser Char ParserState Block
+paraBeforeCodeBlock = try $ do
+ result <- many1 (notFollowedBy' codeBlockStart >> inline)
+ lookAhead (string "::")
+ return $ Para $ if last result == Space
+ then normalizeSpaces result
+ else (normalizeSpaces result) ++ [Str ":"]
+
+-- regular paragraph
+paraNormal :: GenParser Char ParserState Block
+paraNormal = try $ do
+ result <- many1 inline
+ newline
+ blanklines
+ return $ Para $ normalizeSpaces result
+
+plain :: GenParser Char ParserState Block
+plain = many1 inline >>= return . Plain . normalizeSpaces
+
+--
+-- image block
+--
+
+imageBlock :: GenParser Char st Block
+imageBlock = try $ do
+ string ".. image:: "
+ src <- manyTill anyChar newline
+ fields <- option [] $ do indent <- lookAhead $ many (oneOf " /t")
+ many1 $ fieldListItem indent
+ optional blanklines
+ case lookup "alt" fields of
+ Just alt -> return $ Plain [Image [Str alt] (src, alt)]
+ Nothing -> return $ Plain [Image [Str "image"] (src, "")]
+--
+-- header blocks
+--
+
+header :: GenParser Char ParserState Block
+header = doubleHeader <|> singleHeader <?> "header"
+
+-- a header with lines on top and bottom
+doubleHeader :: GenParser Char ParserState Block
+doubleHeader = try $ do
+ c <- oneOf underlineChars
+ rest <- many (char c) -- the top line
+ let lenTop = length (c:rest)
+ skipSpaces
+ newline
+ txt <- many1 (notFollowedBy blankline >> inline)
+ pos <- getPosition
+ let len = (sourceColumn pos) - 1
+ if (len > lenTop) then fail "title longer than border" else return ()
+ blankline -- spaces and newline
+ count lenTop (char c) -- the bottom line
+ blanklines
+ -- check to see if we've had this kind of header before.
+ -- if so, get appropriate level. if not, add to list.
+ state <- getState
+ let headerTable = stateHeaderTable state
+ let (headerTable',level) = case findIndex (== DoubleHeader c) headerTable of
+ Just ind -> (headerTable, ind + 1)
+ Nothing -> (headerTable ++ [DoubleHeader c], (length headerTable) + 1)
+ setState (state { stateHeaderTable = headerTable' })
+ return $ Header level (normalizeSpaces txt)
+
+-- a header with line on the bottom only
+singleHeader :: GenParser Char ParserState Block
+singleHeader = try $ do
+ notFollowedBy' whitespace
+ txt <- many1 (do {notFollowedBy blankline; inline})
+ pos <- getPosition
+ let len = (sourceColumn pos) - 1
+ blankline
+ c <- oneOf underlineChars
+ count (len - 1) (char c)
+ many (char c)
+ blanklines
+ state <- getState
+ let headerTable = stateHeaderTable state
+ let (headerTable',level) = case findIndex (== SingleHeader c) headerTable of
+ Just ind -> (headerTable, ind + 1)
+ Nothing -> (headerTable ++ [SingleHeader c], (length headerTable) + 1)
+ setState (state { stateHeaderTable = headerTable' })
+ return $ Header level (normalizeSpaces txt)
+
+--
+-- hrule block
+--
+
+hrule :: GenParser Char st Block
+hrule = try $ do
+ chr <- oneOf underlineChars
+ count 3 (char chr)
+ skipMany (char chr)
+ blankline
+ blanklines
+ return HorizontalRule
+
+--
+-- code blocks
+--
+
+-- read a line indented by a given string
+indentedLine :: String -> GenParser Char st [Char]
+indentedLine indents = try $ do
+ string indents
+ result <- manyTill anyChar newline
+ return $ result ++ "\n"
+
+-- two or more indented lines, possibly separated by blank lines.
+-- any amount of indentation will work.
+indentedBlock :: GenParser Char st [Char]
+indentedBlock = do
+ indents <- lookAhead $ many1 (oneOf " \t")
+ lns <- many $ choice $ [ indentedLine indents,
+ try $ do b <- blanklines
+ l <- indentedLine indents
+ return (b ++ l) ]
+ optional blanklines
+ return $ concat lns
+
+codeBlock :: GenParser Char st Block
+codeBlock = try $ do
+ codeBlockStart
+ result <- indentedBlock
+ return $ CodeBlock ("",[],[]) $ stripTrailingNewlines result
+
+lhsCodeBlock :: GenParser Char ParserState Block
+lhsCodeBlock = try $ do
+ failUnlessLHS
+ pos <- getPosition
+ when (sourceColumn pos /= 1) $ fail "Not in first column"
+ lns <- many1 birdTrackLine
+ -- if (as is normal) there is always a space after >, drop it
+ let lns' = if all (\ln -> null ln || take 1 ln == " ") lns
+ then map (drop 1) lns
+ else lns
+ blanklines
+ return $ CodeBlock ("", ["sourceCode", "haskell"], []) $ intercalate "\n" lns'
+
+birdTrackLine :: GenParser Char st [Char]
+birdTrackLine = do
+ char '>'
+ manyTill anyChar newline
+
+--
+-- raw html
+--
+
+rawHtmlBlock :: GenParser Char st Block
+rawHtmlBlock = try $ string ".. raw:: html" >> blanklines >>
+ indentedBlock >>= return . RawHtml
+
+--
+-- raw latex
+--
+
+rawLaTeXBlock :: GenParser Char st Block
+rawLaTeXBlock = try $ do
+ string ".. raw:: latex"
+ blanklines
+ result <- indentedBlock
+ return $ Para [(TeX result)]
+
+--
+-- block quotes
+--
+
+blockQuote :: GenParser Char ParserState Block
+blockQuote = do
+ raw <- indentedBlock
+ -- parse the extracted block, which may contain various block elements:
+ contents <- parseFromString parseBlocks $ raw ++ "\n\n"
+ return $ BlockQuote contents
+
+--
+-- list blocks
+--
+
+list :: GenParser Char ParserState Block
+list = choice [ bulletList, orderedList, definitionList ] <?> "list"
+
+definitionListItem :: GenParser Char ParserState ([Inline], [Block])
+definitionListItem = try $ do
+ -- avoid capturing a directive or comment
+ notFollowedBy (try $ char '.' >> char '.')
+ term <- many1Till inline endline
+ raw <- indentedBlock
+ -- parse the extracted block, which may contain various block elements:
+ contents <- parseFromString parseBlocks $ raw ++ "\n\n"
+ return (normalizeSpaces term, contents)
+
+definitionList :: GenParser Char ParserState Block
+definitionList = many1 definitionListItem >>= return . DefinitionList
+
+-- parses bullet list start and returns its length (inc. following whitespace)
+bulletListStart :: GenParser Char st Int
+bulletListStart = try $ do
+ notFollowedBy' hrule -- because hrules start out just like lists
+ marker <- oneOf bulletListMarkers
+ white <- many1 spaceChar
+ return $ length (marker:white)
+
+-- parses ordered list start and returns its length (inc following whitespace)
+orderedListStart :: ListNumberStyle
+ -> ListNumberDelim
+ -> GenParser Char st Int
+orderedListStart style delim = try $ do
+ (_, markerLen) <- withHorizDisplacement (orderedListMarker style delim)
+ white <- many1 spaceChar
+ return $ markerLen + length white
+
+-- parse a line of a list item
+listLine :: Int -> GenParser Char ParserState [Char]
+listLine markerLength = try $ do
+ notFollowedBy blankline
+ indentWith markerLength
+ line <- manyTill anyChar newline
+ return $ line ++ "\n"
+
+-- indent by specified number of spaces (or equiv. tabs)
+indentWith :: Int -> GenParser Char ParserState [Char]
+indentWith num = do
+ state <- getState
+ let tabStop = stateTabStop state
+ if (num < tabStop)
+ then count num (char ' ')
+ else choice [ try (count num (char ' ')),
+ (try (char '\t' >> count (num - tabStop) (char ' '))) ]
+
+-- parse raw text for one list item, excluding start marker and continuations
+rawListItem :: GenParser Char ParserState Int
+ -> GenParser Char ParserState (Int, [Char])
+rawListItem start = try $ do
+ markerLength <- start
+ firstLine <- manyTill anyChar newline
+ restLines <- many (listLine markerLength)
+ return (markerLength, (firstLine ++ "\n" ++ (concat restLines)))
+
+-- continuation of a list item - indented and separated by blankline or
+-- (in compact lists) endline.
+-- Note: nested lists are parsed as continuations.
+listContinuation :: Int -> GenParser Char ParserState [Char]
+listContinuation markerLength = try $ do
+ blanks <- many1 blankline
+ result <- many1 (listLine markerLength)
+ return $ blanks ++ concat result
+
+listItem :: GenParser Char ParserState Int
+ -> GenParser Char ParserState [Block]
+listItem start = try $ do
+ (markerLength, first) <- rawListItem start
+ rest <- many (listContinuation markerLength)
+ blanks <- choice [ try (many blankline >>~ lookAhead start),
+ many1 blankline ] -- whole list must end with blank.
+ -- parsing with ListItemState forces markers at beginning of lines to
+ -- count as list item markers, even if not separated by blank space.
+ -- see definition of "endline"
+ state <- getState
+ let oldContext = stateParserContext state
+ setState $ state {stateParserContext = ListItemState}
+ -- parse the extracted block, which may itself contain block elements
+ parsed <- parseFromString parseBlocks $ concat (first:rest) ++ blanks
+ updateState (\st -> st {stateParserContext = oldContext})
+ return parsed
+
+orderedList :: GenParser Char ParserState Block
+orderedList = try $ do
+ (start, style, delim) <- lookAhead (anyOrderedListMarker >>~ spaceChar)
+ items <- many1 (listItem (orderedListStart style delim))
+ let items' = compactify items
+ return $ OrderedList (start, style, delim) items'
+
+bulletList :: GenParser Char ParserState Block
+bulletList = many1 (listItem bulletListStart) >>=
+ return . BulletList . compactify
+
+--
+-- unknown directive (e.g. comment)
+--
+
+unknownDirective :: GenParser Char st Block
+unknownDirective = try $ do
+ string ".."
+ notFollowedBy (noneOf " \t\n")
+ manyTill anyChar newline
+ many $ blanklines <|> (oneOf " \t" >> manyTill anyChar newline)
+ return Null
+
+--
+-- reference key
+--
+
+quotedReferenceName :: GenParser Char ParserState [Inline]
+quotedReferenceName = try $ do
+ char '`' >> notFollowedBy (char '`') -- `` means inline code!
+ label' <- many1Till inline (char '`')
+ return label'
+
+unquotedReferenceName :: GenParser Char ParserState [Inline]
+unquotedReferenceName = try $ do
+ label' <- many1Till inline (lookAhead $ char ':')
+ return label'
+
+isolated :: Char -> GenParser Char st Char
+isolated ch = try $ char ch >>~ notFollowedBy (char ch)
+
+simpleReferenceName :: GenParser Char st [Inline]
+simpleReferenceName = do
+ raw <- many1 (alphaNum <|> isolated '-' <|> isolated '.' <|>
+ (try $ char '_' >>~ lookAhead alphaNum))
+ return [Str raw]
+
+referenceName :: GenParser Char ParserState [Inline]
+referenceName = quotedReferenceName <|>
+ (try $ simpleReferenceName >>~ lookAhead (char ':')) <|>
+ unquotedReferenceName
+
+referenceKey :: GenParser Char ParserState [Char]
+referenceKey = do
+ startPos <- getPosition
+ key <- choice [imageKey, anonymousKey, regularKey]
+ st <- getState
+ let oldkeys = stateKeys st
+ updateState $ \s -> s { stateKeys = key : oldkeys }
+ optional blanklines
+ endPos <- getPosition
+ -- return enough blanks to replace key
+ return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
+
+targetURI :: GenParser Char st [Char]
+targetURI = do
+ skipSpaces
+ optional newline
+ contents <- many1 (try (many spaceChar >> newline >>
+ many1 spaceChar >> noneOf " \t\n") <|> noneOf "\n")
+ blanklines
+ return contents
+
+imageKey :: GenParser Char ParserState ([Inline], (String, [Char]))
+imageKey = try $ do
+ string ".. |"
+ ref <- manyTill inline (char '|')
+ skipSpaces
+ string "image::"
+ src <- targetURI
+ return (normalizeSpaces ref, (removeLeadingTrailingSpace src, ""))
+
+anonymousKey :: GenParser Char st ([Inline], (String, [Char]))
+anonymousKey = try $ do
+ oneOfStrings [".. __:", "__"]
+ src <- targetURI
+ return ([Str "_"], (removeLeadingTrailingSpace src, ""))
+
+regularKey :: GenParser Char ParserState ([Inline], (String, [Char]))
+regularKey = try $ do
+ string ".. _"
+ ref <- referenceName
+ char ':'
+ src <- targetURI
+ return (normalizeSpaces ref, (removeLeadingTrailingSpace src, ""))
+
+ --
+ -- inline
+ --
+
+inline :: GenParser Char ParserState Inline
+inline = choice [ link
+ , str
+ , whitespace
+ , endline
+ , strong
+ , emph
+ , code
+ , image
+ , hyphens
+ , superscript
+ , subscript
+ , escapedChar
+ , symbol ] <?> "inline"
+
+hyphens :: GenParser Char ParserState Inline
+hyphens = do
+ result <- many1 (char '-')
+ option Space endline
+ -- don't want to treat endline after hyphen or dash as a space
+ return $ Str result
+
+escapedChar :: GenParser Char st Inline
+escapedChar = escaped anyChar
+
+symbol :: GenParser Char ParserState Inline
+symbol = do
+ result <- oneOf specialChars
+ return $ Str [result]
+
+-- parses inline code, between codeStart and codeEnd
+code :: GenParser Char ParserState Inline
+code = try $ do
+ string "``"
+ result <- manyTill anyChar (try (string "``"))
+ return $ Code $ removeLeadingTrailingSpace $ intercalate " " $ lines result
+
+emph :: GenParser Char ParserState Inline
+emph = enclosed (char '*') (char '*') inline >>=
+ return . Emph . normalizeSpaces
+
+strong :: GenParser Char ParserState Inline
+strong = enclosed (string "**") (try $ string "**") inline >>=
+ return . Strong . normalizeSpaces
+
+interpreted :: [Char] -> GenParser Char st [Inline]
+interpreted role = try $ do
+ optional $ try $ string "\\ "
+ result <- enclosed (string $ ":" ++ role ++ ":`") (char '`') anyChar
+ try (string "\\ ") <|> lookAhead (count 1 $ oneOf " \t\n") <|> (eof >> return "")
+ return [Str result]
+
+superscript :: GenParser Char ParserState Inline
+superscript = interpreted "sup" >>= (return . Superscript)
+
+subscript :: GenParser Char ParserState Inline
+subscript = interpreted "sub" >>= (return . Subscript)
+
+whitespace :: GenParser Char ParserState Inline
+whitespace = many1 spaceChar >> return Space <?> "whitespace"
+
+str :: GenParser Char ParserState Inline
+str = many1 (noneOf (specialChars ++ "\t\n ")) >>= return . Str
+
+-- an endline character that can be treated as a space, not a structural break
+endline :: GenParser Char ParserState Inline
+endline = try $ do
+ newline
+ notFollowedBy blankline
+ -- parse potential list-starts at beginning of line differently in a list:
+ st <- getState
+ if (stateParserContext st) == ListItemState
+ then notFollowedBy (anyOrderedListMarker >> spaceChar) >>
+ notFollowedBy' bulletListStart
+ else return ()
+ return Space
+
+--
+-- links
+--
+
+link :: GenParser Char ParserState Inline
+link = choice [explicitLink, referenceLink, autoLink] <?> "link"
+
+explicitLink :: GenParser Char ParserState Inline
+explicitLink = try $ do
+ char '`'
+ notFollowedBy (char '`') -- `` marks start of inline code
+ label' <- manyTill (notFollowedBy (char '`') >> inline)
+ (try (spaces >> char '<'))
+ src <- manyTill (noneOf ">\n") (char '>')
+ skipSpaces
+ string "`_"
+ return $ Link (normalizeSpaces label') (removeLeadingTrailingSpace src, "")
+
+referenceLink :: GenParser Char ParserState Inline
+referenceLink = try $ do
+ label' <- (quotedReferenceName <|> simpleReferenceName) >>~ char '_'
+ key <- option label' (do{char '_'; return [Str "_"]}) -- anonymous link
+ state <- getState
+ let keyTable = stateKeys state
+ src <- case lookupKeySrc keyTable key of
+ Nothing -> fail "no corresponding key"
+ Just target -> return target
+ -- if anonymous link, remove first anon key so it won't be used again
+ let keyTable' = if (key == [Str "_"]) -- anonymous link?
+ then delete ([Str "_"], src) keyTable -- remove first anon key
+ else keyTable
+ setState $ state { stateKeys = keyTable' }
+ return $ Link (normalizeSpaces label') src
+
+autoURI :: GenParser Char ParserState Inline
+autoURI = do
+ src <- uri
+ return $ Link [Str src] (src, "")
+
+autoEmail :: GenParser Char ParserState Inline
+autoEmail = do
+ src <- emailAddress
+ return $ Link [Str src] ("mailto:" ++ src, "")
+
+autoLink :: GenParser Char ParserState Inline
+autoLink = autoURI <|> autoEmail
+
+-- For now, we assume that all substitution references are for images.
+image :: GenParser Char ParserState Inline
+image = try $ do
+ char '|'
+ ref <- manyTill inline (char '|')
+ state <- getState
+ let keyTable = stateKeys state
+ src <- case lookupKeySrc keyTable ref of
+ Nothing -> fail "no corresponding key"
+ Just target -> return target
+ return $ Image (normalizeSpaces ref) src
+
diff --git a/src/Text/Pandoc/Readers/TeXMath.hs b/src/Text/Pandoc/Readers/TeXMath.hs
new file mode 100644
index 000000000..04b0f3b8f
--- /dev/null
+++ b/src/Text/Pandoc/Readers/TeXMath.hs
@@ -0,0 +1,233 @@
+{-
+Copyright (C) 2007 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.TeXMath
+ Copyright : Copyright (C) 2007 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of TeX math to a list of 'Pandoc' inline elements.
+-}
+module Text.Pandoc.Readers.TeXMath (
+ readTeXMath
+ ) where
+
+import Text.ParserCombinators.Parsec
+import Text.Pandoc.Definition
+
+-- | Converts a string of raw TeX math to a list of 'Pandoc' inlines.
+readTeXMath :: String -> [Inline]
+readTeXMath inp = case parse teXMath ("formula: " ++ inp) inp of
+ Left _ -> [Str inp] -- if unparseable, just include original
+ Right res -> res
+
+teXMath :: GenParser Char st [Inline]
+teXMath = manyTill mathPart eof >>= return . concat
+
+mathPart :: GenParser Char st [Inline]
+mathPart = whitespace <|> superscript <|> subscript <|> symbol <|>
+ argument <|> digits <|> letters <|> misc
+
+whitespace :: GenParser Char st [Inline]
+whitespace = many1 space >> return []
+
+symbol :: GenParser Char st [Inline]
+symbol = try $ do
+ char '\\'
+ res <- many1 letter
+ case lookup res teXsymbols of
+ Just m -> return [Str m]
+ Nothing -> return [Str $ "\\" ++ res]
+
+argument :: GenParser Char st [Inline]
+argument = try $ do
+ char '{'
+ res <- many mathPart
+ char '}'
+ return $ if null res
+ then [Str " "]
+ else [Str "{"] ++ concat res ++ [Str "}"]
+
+digits :: GenParser Char st [Inline]
+digits = do
+ res <- many1 digit
+ return [Str res]
+
+letters :: GenParser Char st [Inline]
+letters = do
+ res <- many1 letter
+ return [Emph [Str res]]
+
+misc :: GenParser Char st [Inline]
+misc = do
+ res <- noneOf "}"
+ return [Str [res]]
+
+scriptArg :: GenParser Char st [Inline]
+scriptArg = try $ do
+ (try (do{char '{'; r <- many mathPart; char '}'; return $ concat r}))
+ <|> symbol
+ <|> (do{c <- (letter <|> digit); return [Str [c]]})
+
+superscript :: GenParser Char st [Inline]
+superscript = try $ do
+ char '^'
+ arg <- scriptArg
+ return [Superscript arg]
+
+subscript :: GenParser Char st [Inline]
+subscript = try $ do
+ char '_'
+ arg <- scriptArg
+ return [Subscript arg]
+
+withThinSpace :: String -> String
+withThinSpace str = "\x2009" ++ str ++ "\x2009"
+
+teXsymbols :: [(String, String)]
+teXsymbols =
+ [("alpha","\x3B1")
+ ,("beta", "\x3B2")
+ ,("chi", "\x3C7")
+ ,("delta", "\x3B4")
+ ,("Delta", "\x394")
+ ,("epsilon", "\x3B5")
+ ,("varepsilon", "\x25B")
+ ,("eta", "\x3B7")
+ ,("gamma", "\x3B3")
+ ,("Gamma", "\x393")
+ ,("iota", "\x3B9")
+ ,("kappa", "\x3BA")
+ ,("lambda", "\x3BB")
+ ,("Lambda", "\x39B")
+ ,("mu", "\x3BC")
+ ,("nu", "\x3BD")
+ ,("omega", "\x3C9")
+ ,("Omega", "\x3A9")
+ ,("phi", "\x3C6")
+ ,("varphi", "\x3D5")
+ ,("Phi", "\x3A6")
+ ,("pi", "\x3C0")
+ ,("Pi", "\x3A0")
+ ,("psi", "\x3C8")
+ ,("Psi", "\x3A8")
+ ,("rho", "\x3C1")
+ ,("sigma", "\x3C3")
+ ,("Sigma", "\x3A3")
+ ,("tau", "\x3C4")
+ ,("theta", "\x3B8")
+ ,("vartheta", "\x3D1")
+ ,("Theta", "\x398")
+ ,("upsilon", "\x3C5")
+ ,("xi", "\x3BE")
+ ,("Xi", "\x39E")
+ ,("zeta", "\x3B6")
+ ,("ne", "\x2260")
+ ,("lt", withThinSpace "<")
+ ,("le", withThinSpace "\x2264")
+ ,("leq", withThinSpace "\x2264")
+ ,("ge", withThinSpace "\x2265")
+ ,("geq", withThinSpace "\x2265")
+ ,("prec", withThinSpace "\x227A")
+ ,("succ", withThinSpace "\x227B")
+ ,("preceq", withThinSpace "\x2AAF")
+ ,("succeq", withThinSpace "\x2AB0")
+ ,("in", withThinSpace "\x2208")
+ ,("notin", withThinSpace "\x2209")
+ ,("subset", withThinSpace "\x2282")
+ ,("supset", withThinSpace "\x2283")
+ ,("subseteq", withThinSpace "\x2286")
+ ,("supseteq", withThinSpace "\x2287")
+ ,("equiv", withThinSpace "\x2261")
+ ,("cong", withThinSpace "\x2245")
+ ,("approx", withThinSpace "\x2248")
+ ,("propto", withThinSpace "\x221D")
+ ,("cdot", withThinSpace "\x22C5")
+ ,("star", withThinSpace "\x22C6")
+ ,("backslash", "\\")
+ ,("times", withThinSpace "\x00D7")
+ ,("divide", withThinSpace "\x00F7")
+ ,("circ", withThinSpace "\x2218")
+ ,("oplus", withThinSpace "\x2295")
+ ,("otimes", withThinSpace "\x2297")
+ ,("odot", withThinSpace "\x2299")
+ ,("sum", "\x2211")
+ ,("prod", "\x220F")
+ ,("wedge", withThinSpace "\x2227")
+ ,("bigwedge", withThinSpace "\x22C0")
+ ,("vee", withThinSpace "\x2228")
+ ,("bigvee", withThinSpace "\x22C1")
+ ,("cap", withThinSpace "\x2229")
+ ,("bigcap", withThinSpace "\x22C2")
+ ,("cup", withThinSpace "\x222A")
+ ,("bigcup", withThinSpace "\x22C3")
+ ,("neg", "\x00AC")
+ ,("implies", withThinSpace "\x21D2")
+ ,("iff", withThinSpace "\x21D4")
+ ,("forall", "\x2200")
+ ,("exists", "\x2203")
+ ,("bot", "\x22A5")
+ ,("top", "\x22A4")
+ ,("vdash", "\x22A2")
+ ,("models", withThinSpace "\x22A8")
+ ,("uparrow", "\x2191")
+ ,("downarrow", "\x2193")
+ ,("rightarrow", withThinSpace "\x2192")
+ ,("to", withThinSpace "\x2192")
+ ,("rightarrowtail", "\x21A3")
+ ,("twoheadrightarrow", withThinSpace "\x21A0")
+ ,("twoheadrightarrowtail", withThinSpace "\x2916")
+ ,("mapsto", withThinSpace "\x21A6")
+ ,("leftarrow", withThinSpace "\x2190")
+ ,("leftrightarrow", withThinSpace "\x2194")
+ ,("Rightarrow", withThinSpace "\x21D2")
+ ,("Leftarrow", withThinSpace "\x21D0")
+ ,("Leftrightarrow", withThinSpace "\x21D4")
+ ,("partial", "\x2202")
+ ,("nabla", "\x2207")
+ ,("pm", "\x00B1")
+ ,("emptyset", "\x2205")
+ ,("infty", "\x221E")
+ ,("aleph", "\x2135")
+ ,("ldots", "...")
+ ,("therefore", "\x2234")
+ ,("angle", "\x2220")
+ ,("quad", "\x00A0\x00A0")
+ ,("cdots", "\x22EF")
+ ,("vdots", "\x22EE")
+ ,("ddots", "\x22F1")
+ ,("diamond", "\x22C4")
+ ,("Box", "\x25A1")
+ ,("lfloor", "\x230A")
+ ,("rfloor", "\x230B")
+ ,("lceiling", "\x2308")
+ ,("rceiling", "\x2309")
+ ,("langle", "\x2329")
+ ,("rangle", "\x232A")
+ ,("{", "{")
+ ,("}", "}")
+ ,("[", "[")
+ ,("]", "]")
+ ,("|", "|")
+ ,("||", "||")
+ ]
+
diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs
new file mode 100644
index 000000000..b67e169c8
--- /dev/null
+++ b/src/Text/Pandoc/Shared.hs
@@ -0,0 +1,1030 @@
+{-# LANGUAGE CPP, DeriveDataTypeable #-}
+{-
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Shared
+ Copyright : Copyright (C) 2006-8 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Utility functions and definitions used by the various Pandoc modules.
+-}
+module Text.Pandoc.Shared (
+ -- * List processing
+ splitBy,
+ splitByIndices,
+ substitute,
+ -- * Text processing
+ backslashEscapes,
+ escapeStringUsing,
+ stripTrailingNewlines,
+ removeLeadingTrailingSpace,
+ removeLeadingSpace,
+ removeTrailingSpace,
+ stripFirstAndLast,
+ camelCaseToHyphenated,
+ toRomanNumeral,
+ wrapped,
+ wrapIfNeeded,
+ wrappedTeX,
+ wrapTeXIfNeeded,
+ BlockWrapper (..),
+ wrappedBlocksToDoc,
+ tabFilter,
+ -- * Parsing
+ (>>~),
+ anyLine,
+ many1Till,
+ notFollowedBy',
+ oneOfStrings,
+ spaceChar,
+ skipSpaces,
+ blankline,
+ blanklines,
+ enclosed,
+ stringAnyCase,
+ parseFromString,
+ lineClump,
+ charsInBalanced,
+ charsInBalanced',
+ romanNumeral,
+ emailAddress,
+ uri,
+ withHorizDisplacement,
+ nullBlock,
+ failIfStrict,
+ failUnlessLHS,
+ escaped,
+ anyOrderedListMarker,
+ orderedListMarker,
+ charRef,
+ readWith,
+ testStringWith,
+ ParserState (..),
+ defaultParserState,
+ HeaderType (..),
+ ParserContext (..),
+ QuoteContext (..),
+ NoteTable,
+ KeyTable,
+ lookupKeySrc,
+ refsMatch,
+ -- * Prettyprinting
+ hang',
+ prettyPandoc,
+ -- * Pandoc block and inline list processing
+ orderedListMarkers,
+ normalizeSpaces,
+ compactify,
+ Element (..),
+ hierarchicalize,
+ isHeaderBlock,
+ -- * Writer options
+ HTMLMathMethod (..),
+ ObfuscationMethod (..),
+ WriterOptions (..),
+ defaultWriterOptions,
+ -- * File handling
+ inDirectory
+ ) where
+
+import Text.Pandoc.Definition
+import Text.ParserCombinators.Parsec
+import Text.PrettyPrint.HughesPJ ( Doc, fsep, ($$), (<>), empty, isEmpty, text, nest )
+import qualified Text.PrettyPrint.HughesPJ as PP
+import Text.Pandoc.CharacterReferences ( characterReference )
+import Data.Char ( toLower, toUpper, ord, isLower, isUpper, isAlpha,
+ isPunctuation )
+import Data.List ( find, isPrefixOf, intercalate )
+import Network.URI ( parseURI, URI (..), isAllowedInURI )
+import System.Directory
+import Prelude hiding ( putStrLn, writeFile, readFile, getContents )
+import System.IO.UTF8
+import Data.Generics
+import qualified Control.Monad.State as S
+import Control.Monad (join)
+
+--
+-- List processing
+--
+
+-- | Split list by groups of one or more sep.
+splitBy :: (Eq a) => a -> [a] -> [[a]]
+splitBy _ [] = []
+splitBy sep lst =
+ let (first, rest) = break (== sep) lst
+ rest' = dropWhile (== sep) rest
+ in first:(splitBy sep rest')
+
+-- | Split list into chunks divided at specified indices.
+splitByIndices :: [Int] -> [a] -> [[a]]
+splitByIndices [] lst = [lst]
+splitByIndices (x:xs) lst =
+ let (first, rest) = splitAt x lst in
+ first:(splitByIndices (map (\y -> y - x) xs) rest)
+
+-- | Replace each occurrence of one sublist in a list with another.
+substitute :: (Eq a) => [a] -> [a] -> [a] -> [a]
+substitute _ _ [] = []
+substitute [] _ lst = lst
+substitute target replacement lst =
+ if target `isPrefixOf` lst
+ then replacement ++ (substitute target replacement $ drop (length target) lst)
+ else (head lst):(substitute target replacement $ tail lst)
+
+--
+-- Text processing
+--
+
+-- | Returns an association list of backslash escapes for the
+-- designated characters.
+backslashEscapes :: [Char] -- ^ list of special characters to escape
+ -> [(Char, String)]
+backslashEscapes = map (\ch -> (ch, ['\\',ch]))
+
+-- | Escape a string of characters, using an association list of
+-- characters and strings.
+escapeStringUsing :: [(Char, String)] -> String -> String
+escapeStringUsing _ [] = ""
+escapeStringUsing escapeTable (x:xs) =
+ case (lookup x escapeTable) of
+ Just str -> str ++ rest
+ Nothing -> x:rest
+ where rest = escapeStringUsing escapeTable xs
+
+-- | Strip trailing newlines from string.
+stripTrailingNewlines :: String -> String
+stripTrailingNewlines = reverse . dropWhile (== '\n') . reverse
+
+-- | Remove leading and trailing space (including newlines) from string.
+removeLeadingTrailingSpace :: String -> String
+removeLeadingTrailingSpace = removeLeadingSpace . removeTrailingSpace
+
+-- | Remove leading space (including newlines) from string.
+removeLeadingSpace :: String -> String
+removeLeadingSpace = dropWhile (`elem` " \n\t")
+
+-- | Remove trailing space (including newlines) from string.
+removeTrailingSpace :: String -> String
+removeTrailingSpace = reverse . removeLeadingSpace . reverse
+
+-- | Strip leading and trailing characters from string
+stripFirstAndLast :: String -> String
+stripFirstAndLast str =
+ drop 1 $ take ((length str) - 1) str
+
+-- | Change CamelCase word to hyphenated lowercase (e.g., camel-case).
+camelCaseToHyphenated :: String -> String
+camelCaseToHyphenated [] = ""
+camelCaseToHyphenated (a:b:rest) | isLower a && isUpper b =
+ a:'-':(toLower b):(camelCaseToHyphenated rest)
+camelCaseToHyphenated (a:rest) = (toLower a):(camelCaseToHyphenated rest)
+
+-- | Convert number < 4000 to uppercase roman numeral.
+toRomanNumeral :: Int -> String
+toRomanNumeral x =
+ if x >= 4000 || x < 0
+ then "?"
+ else case x of
+ _ | x >= 1000 -> "M" ++ toRomanNumeral (x - 1000)
+ _ | x >= 900 -> "CM" ++ toRomanNumeral (x - 900)
+ _ | x >= 500 -> "D" ++ toRomanNumeral (x - 500)
+ _ | x >= 400 -> "CD" ++ toRomanNumeral (x - 400)
+ _ | x >= 100 -> "C" ++ toRomanNumeral (x - 100)
+ _ | x >= 90 -> "XC" ++ toRomanNumeral (x - 90)
+ _ | x >= 50 -> "L" ++ toRomanNumeral (x - 50)
+ _ | x >= 40 -> "XL" ++ toRomanNumeral (x - 40)
+ _ | x >= 10 -> "X" ++ toRomanNumeral (x - 10)
+ _ | x >= 9 -> "IX" ++ toRomanNumeral (x - 5)
+ _ | x >= 5 -> "V" ++ toRomanNumeral (x - 5)
+ _ | x >= 4 -> "IV" ++ toRomanNumeral (x - 4)
+ _ | x >= 1 -> "I" ++ toRomanNumeral (x - 1)
+ _ -> ""
+
+-- | Wrap inlines to line length.
+wrapped :: Monad m => ([Inline] -> m Doc) -> [Inline] -> m Doc
+wrapped listWriter sect = (mapM listWriter $ splitBy Space sect) >>=
+ return . fsep
+
+-- | Wrap inlines if the text wrap option is selected.
+wrapIfNeeded :: Monad m => WriterOptions -> ([Inline] -> m Doc) ->
+ [Inline] -> m Doc
+wrapIfNeeded opts = if writerWrapText opts
+ then wrapped
+ else ($)
+
+-- auxiliary function for wrappedTeX
+isNote :: Inline -> Bool
+isNote (Note _) = True
+isNote _ = False
+
+-- | Wrap inlines to line length, treating footnotes in a way that
+-- makes sense in LaTeX and ConTeXt.
+wrappedTeX :: Monad m
+ => Bool
+ -> ([Inline] -> m Doc)
+ -> [Inline]
+ -> m Doc
+wrappedTeX includePercent listWriter sect = do
+ let (firstpart, rest) = break isNote sect
+ firstpartWrapped <- wrapped listWriter firstpart
+ if null rest
+ then return firstpartWrapped
+ else do let (note:rest') = rest
+ let (rest1, rest2) = break (== Space) rest'
+ -- rest1 is whatever comes between the note and a Space.
+ -- if the note is followed directly by a Space, rest1 is null.
+ -- rest1 is printed after the note but before the line break,
+ -- to avoid spurious blank space the note and immediately
+ -- following punctuation.
+ rest1Out <- if null rest1
+ then return empty
+ else listWriter rest1
+ rest2Wrapped <- if null rest2
+ then return empty
+ else wrappedTeX includePercent listWriter (tail rest2)
+ noteText <- listWriter [note]
+ return $ (firstpartWrapped <> if includePercent then PP.char '%' else empty) $$
+ (noteText <> rest1Out) $$
+ rest2Wrapped
+
+-- | Wrap inlines if the text wrap option is selected, specialized
+-- for LaTeX and ConTeXt.
+wrapTeXIfNeeded :: Monad m
+ => WriterOptions
+ -> Bool
+ -> ([Inline] -> m Doc)
+ -> [Inline]
+ -> m Doc
+wrapTeXIfNeeded opts includePercent = if writerWrapText opts
+ then wrappedTeX includePercent
+ else ($)
+
+-- | Indicates whether block should be surrounded by blank lines (@Pad@) or not (@Reg@).
+data BlockWrapper = Pad Doc | Reg Doc
+
+-- | Converts a list of wrapped blocks to a Doc, with appropriate spaces around blocks.
+wrappedBlocksToDoc :: [BlockWrapper] -> Doc
+wrappedBlocksToDoc = foldr addBlock empty
+ where addBlock (Pad d) accum | isEmpty accum = d
+ addBlock (Pad d) accum = d $$ text "" $$ accum
+ addBlock (Reg d) accum = d $$ accum
+
+-- | Convert tabs to spaces and filter out DOS line endings.
+-- Tabs will be preserved if tab stop is set to 0.
+tabFilter :: Int -- ^ Tab stop
+ -> String -- ^ Input
+ -> String
+tabFilter tabStop =
+ let go _ [] = ""
+ go _ ('\n':xs) = '\n' : go tabStop xs
+ go _ ('\r':'\n':xs) = '\n' : go tabStop xs
+ go _ ('\r':xs) = '\n' : go tabStop xs
+ go spsToNextStop ('\t':xs) =
+ if tabStop == 0
+ then '\t' : go tabStop xs
+ else replicate spsToNextStop ' ' ++ go tabStop xs
+ go 1 (x:xs) =
+ x : go tabStop xs
+ go spsToNextStop (x:xs) =
+ x : go (spsToNextStop - 1) xs
+ in go tabStop
+
+--
+-- Parsing
+--
+
+-- | Like >>, but returns the operation on the left.
+-- (Suggested by Tillmann Rendel on Haskell-cafe list.)
+(>>~) :: (Monad m) => m a -> m b -> m a
+a >>~ b = a >>= \x -> b >> return x
+
+-- | Parse any line of text
+anyLine :: GenParser Char st [Char]
+anyLine = manyTill anyChar newline
+
+-- | Like @manyTill@, but reads at least one item.
+many1Till :: GenParser tok st a
+ -> GenParser tok st end
+ -> GenParser tok st [a]
+many1Till p end = do
+ first <- p
+ rest <- manyTill p end
+ return (first:rest)
+
+-- | A more general form of @notFollowedBy@. This one allows any
+-- type of parser to be specified, and succeeds only if that parser fails.
+-- It does not consume any input.
+notFollowedBy' :: Show b => GenParser a st b -> GenParser a st ()
+notFollowedBy' p = try $ join $ do a <- try p
+ return (unexpected (show a))
+ <|>
+ return (return ())
+-- (This version due to Andrew Pimlott on the Haskell mailing list.)
+
+-- | Parses one of a list of strings (tried in order).
+oneOfStrings :: [String] -> GenParser Char st String
+oneOfStrings listOfStrings = choice $ map (try . string) listOfStrings
+
+-- | Parses a space or tab.
+spaceChar :: CharParser st Char
+spaceChar = char ' ' <|> char '\t'
+
+-- | Skips zero or more spaces or tabs.
+skipSpaces :: GenParser Char st ()
+skipSpaces = skipMany spaceChar
+
+-- | Skips zero or more spaces or tabs, then reads a newline.
+blankline :: GenParser Char st Char
+blankline = try $ skipSpaces >> newline
+
+-- | Parses one or more blank lines and returns a string of newlines.
+blanklines :: GenParser Char st [Char]
+blanklines = many1 blankline
+
+-- | Parses material enclosed between start and end parsers.
+enclosed :: GenParser Char st t -- ^ start parser
+ -> GenParser Char st end -- ^ end parser
+ -> GenParser Char st a -- ^ content parser (to be used repeatedly)
+ -> GenParser Char st [a]
+enclosed start end parser = try $
+ start >> notFollowedBy space >> many1Till parser end
+
+-- | Parse string, case insensitive.
+stringAnyCase :: [Char] -> CharParser st String
+stringAnyCase [] = string ""
+stringAnyCase (x:xs) = do
+ firstChar <- char (toUpper x) <|> char (toLower x)
+ rest <- stringAnyCase xs
+ return (firstChar:rest)
+
+-- | Parse contents of 'str' using 'parser' and return result.
+parseFromString :: GenParser tok st a -> [tok] -> GenParser tok st a
+parseFromString parser str = do
+ oldPos <- getPosition
+ oldInput <- getInput
+ setInput str
+ result <- parser
+ setInput oldInput
+ setPosition oldPos
+ return result
+
+-- | Parse raw line block up to and including blank lines.
+lineClump :: GenParser Char st String
+lineClump = blanklines
+ <|> (many1 (notFollowedBy blankline >> anyLine) >>= return . unlines)
+
+-- | Parse a string of characters between an open character
+-- and a close character, including text between balanced
+-- pairs of open and close, which must be different. For example,
+-- @charsInBalanced '(' ')'@ will parse "(hello (there))"
+-- and return "hello (there)". Stop if a blank line is
+-- encountered.
+charsInBalanced :: Char -> Char -> GenParser Char st String
+charsInBalanced open close = try $ do
+ char open
+ raw <- many $ (many1 (noneOf [open, close, '\n']))
+ <|> (do res <- charsInBalanced open close
+ return $ [open] ++ res ++ [close])
+ <|> try (string "\n" >>~ notFollowedBy' blanklines)
+ char close
+ return $ concat raw
+
+-- | Like @charsInBalanced@, but allow blank lines in the content.
+charsInBalanced' :: Char -> Char -> GenParser Char st String
+charsInBalanced' open close = try $ do
+ char open
+ raw <- many $ (many1 (noneOf [open, close]))
+ <|> (do res <- charsInBalanced' open close
+ return $ [open] ++ res ++ [close])
+ char close
+ return $ concat raw
+
+-- Auxiliary functions for romanNumeral:
+
+lowercaseRomanDigits :: [Char]
+lowercaseRomanDigits = ['i','v','x','l','c','d','m']
+
+uppercaseRomanDigits :: [Char]
+uppercaseRomanDigits = map toUpper lowercaseRomanDigits
+
+-- | Parses a roman numeral (uppercase or lowercase), returns number.
+romanNumeral :: Bool -- ^ Uppercase if true
+ -> GenParser Char st Int
+romanNumeral upperCase = do
+ let romanDigits = if upperCase
+ then uppercaseRomanDigits
+ else lowercaseRomanDigits
+ lookAhead $ oneOf romanDigits
+ let [one, five, ten, fifty, hundred, fivehundred, thousand] =
+ map char romanDigits
+ thousands <- many thousand >>= (return . (1000 *) . length)
+ ninehundreds <- option 0 $ try $ hundred >> thousand >> return 900
+ fivehundreds <- many fivehundred >>= (return . (500 *) . length)
+ fourhundreds <- option 0 $ try $ hundred >> fivehundred >> return 400
+ hundreds <- many hundred >>= (return . (100 *) . length)
+ nineties <- option 0 $ try $ ten >> hundred >> return 90
+ fifties <- many fifty >>= (return . (50 *) . length)
+ forties <- option 0 $ try $ ten >> fifty >> return 40
+ tens <- many ten >>= (return . (10 *) . length)
+ nines <- option 0 $ try $ one >> ten >> return 9
+ fives <- many five >>= (return . (5 *) . length)
+ fours <- option 0 $ try $ one >> five >> return 4
+ ones <- many one >>= (return . length)
+ let total = thousands + ninehundreds + fivehundreds + fourhundreds +
+ hundreds + nineties + fifties + forties + tens + nines +
+ fives + fours + ones
+ if total == 0
+ then fail "not a roman numeral"
+ else return total
+
+-- Parsers for email addresses and URIs
+
+emailChar :: GenParser Char st Char
+emailChar = alphaNum <|> oneOf "-+_."
+
+domainChar :: GenParser Char st Char
+domainChar = alphaNum <|> char '-'
+
+domain :: GenParser Char st [Char]
+domain = do
+ first <- many1 domainChar
+ dom <- many1 $ try (char '.' >> many1 domainChar )
+ return $ intercalate "." (first:dom)
+
+-- | Parses an email address; returns string.
+emailAddress :: GenParser Char st [Char]
+emailAddress = try $ do
+ firstLetter <- alphaNum
+ restAddr <- many emailChar
+ let addr = firstLetter:restAddr
+ char '@'
+ dom <- domain
+ return $ addr ++ '@':dom
+
+-- | Parses a URI.
+uri :: GenParser Char st String
+uri = try $ do
+ str <- many1 $ satisfy isAllowedInURI
+ case parseURI str of
+ Just uri' -> if uriScheme uri' `elem` [ "http:", "https:", "ftp:",
+ "file:", "mailto:",
+ "news:", "telnet:" ]
+ then return $ show uri'
+ else fail "not a URI"
+ Nothing -> fail "not a URI"
+
+-- | Applies a parser, returns tuple of its results and its horizontal
+-- displacement (the difference between the source column at the end
+-- and the source column at the beginning). Vertical displacement
+-- (source row) is ignored.
+withHorizDisplacement :: GenParser Char st a -- ^ Parser to apply
+ -> GenParser Char st (a, Int) -- ^ (result, displacement)
+withHorizDisplacement parser = do
+ pos1 <- getPosition
+ result <- parser
+ pos2 <- getPosition
+ return (result, sourceColumn pos2 - sourceColumn pos1)
+
+-- | Parses a character and returns 'Null' (so that the parser can move on
+-- if it gets stuck).
+nullBlock :: GenParser Char st Block
+nullBlock = anyChar >> return Null
+
+-- | Fail if reader is in strict markdown syntax mode.
+failIfStrict :: GenParser Char ParserState ()
+failIfStrict = do
+ state <- getState
+ if stateStrict state then fail "strict mode" else return ()
+
+-- | Fail unless we're in literate haskell mode.
+failUnlessLHS :: GenParser tok ParserState ()
+failUnlessLHS = do
+ state <- getState
+ if stateLiterateHaskell state then return () else fail "Literate haskell feature"
+
+-- | Parses backslash, then applies character parser.
+escaped :: GenParser Char st Char -- ^ Parser for character to escape
+ -> GenParser Char st Inline
+escaped parser = try $ do
+ char '\\'
+ result <- parser
+ return (Str [result])
+
+-- | Parses an uppercase roman numeral and returns (UpperRoman, number).
+upperRoman :: GenParser Char st (ListNumberStyle, Int)
+upperRoman = do
+ num <- romanNumeral True
+ return (UpperRoman, num)
+
+-- | Parses a lowercase roman numeral and returns (LowerRoman, number).
+lowerRoman :: GenParser Char st (ListNumberStyle, Int)
+lowerRoman = do
+ num <- romanNumeral False
+ return (LowerRoman, num)
+
+-- | Parses a decimal numeral and returns (Decimal, number).
+decimal :: GenParser Char st (ListNumberStyle, Int)
+decimal = do
+ num <- many1 digit
+ return (Decimal, read num)
+
+-- | Parses a '#' returns (DefaultStyle, 1).
+defaultNum :: GenParser Char st (ListNumberStyle, Int)
+defaultNum = do
+ char '#'
+ return (DefaultStyle, 1)
+
+-- | Parses a lowercase letter and returns (LowerAlpha, number).
+lowerAlpha :: GenParser Char st (ListNumberStyle, Int)
+lowerAlpha = do
+ ch <- oneOf ['a'..'z']
+ return (LowerAlpha, ord ch - ord 'a' + 1)
+
+-- | Parses an uppercase letter and returns (UpperAlpha, number).
+upperAlpha :: GenParser Char st (ListNumberStyle, Int)
+upperAlpha = do
+ ch <- oneOf ['A'..'Z']
+ return (UpperAlpha, ord ch - ord 'A' + 1)
+
+-- | Parses a roman numeral i or I
+romanOne :: GenParser Char st (ListNumberStyle, Int)
+romanOne = (char 'i' >> return (LowerRoman, 1)) <|>
+ (char 'I' >> return (UpperRoman, 1))
+
+-- | Parses an ordered list marker and returns list attributes.
+anyOrderedListMarker :: GenParser Char st ListAttributes
+anyOrderedListMarker = choice $
+ [delimParser numParser | delimParser <- [inPeriod, inOneParen, inTwoParens],
+ numParser <- [decimal, defaultNum, romanOne,
+ lowerAlpha, lowerRoman, upperAlpha, upperRoman]]
+
+-- | Parses a list number (num) followed by a period, returns list attributes.
+inPeriod :: GenParser Char st (ListNumberStyle, Int)
+ -> GenParser Char st ListAttributes
+inPeriod num = try $ do
+ (style, start) <- num
+ char '.'
+ let delim = if style == DefaultStyle
+ then DefaultDelim
+ else Period
+ return (start, style, delim)
+
+-- | Parses a list number (num) followed by a paren, returns list attributes.
+inOneParen :: GenParser Char st (ListNumberStyle, Int)
+ -> GenParser Char st ListAttributes
+inOneParen num = try $ do
+ (style, start) <- num
+ char ')'
+ return (start, style, OneParen)
+
+-- | Parses a list number (num) enclosed in parens, returns list attributes.
+inTwoParens :: GenParser Char st (ListNumberStyle, Int)
+ -> GenParser Char st ListAttributes
+inTwoParens num = try $ do
+ char '('
+ (style, start) <- num
+ char ')'
+ return (start, style, TwoParens)
+
+-- | Parses an ordered list marker with a given style and delimiter,
+-- returns number.
+orderedListMarker :: ListNumberStyle
+ -> ListNumberDelim
+ -> GenParser Char st Int
+orderedListMarker style delim = do
+ let num = defaultNum <|> -- # can continue any kind of list
+ case style of
+ DefaultStyle -> decimal
+ Decimal -> decimal
+ UpperRoman -> upperRoman
+ LowerRoman -> lowerRoman
+ UpperAlpha -> upperAlpha
+ LowerAlpha -> lowerAlpha
+ let context = case delim of
+ DefaultDelim -> inPeriod
+ Period -> inPeriod
+ OneParen -> inOneParen
+ TwoParens -> inTwoParens
+ (start, _, _) <- context num
+ return start
+
+-- | Parses a character reference and returns a Str element.
+charRef :: GenParser Char st Inline
+charRef = do
+ c <- characterReference
+ return $ Str [c]
+
+-- | Parse a string with a given parser and state.
+readWith :: GenParser Char ParserState a -- ^ parser
+ -> ParserState -- ^ initial state
+ -> String -- ^ input string
+ -> a
+readWith parser state input =
+ case runParser parser state "source" input of
+ Left err -> error $ "\nError:\n" ++ show err
+ Right result -> result
+
+-- | Parse a string with @parser@ (for testing).
+testStringWith :: (Show a) => GenParser Char ParserState a
+ -> String
+ -> IO ()
+testStringWith parser str = putStrLn $ show $
+ readWith parser defaultParserState str
+
+-- | Parsing options.
+data ParserState = ParserState
+ { stateParseRaw :: Bool, -- ^ Parse raw HTML and LaTeX?
+ stateParserContext :: ParserContext, -- ^ Inside list?
+ stateQuoteContext :: QuoteContext, -- ^ Inside quoted environment?
+ stateSanitizeHTML :: Bool, -- ^ Sanitize HTML?
+ stateKeys :: KeyTable, -- ^ List of reference keys
+#ifdef _CITEPROC
+ stateCitations :: [String], -- ^ List of available citations
+#endif
+ stateNotes :: NoteTable, -- ^ List of notes
+ stateTabStop :: Int, -- ^ Tab stop
+ stateStandalone :: Bool, -- ^ Parse bibliographic info?
+ stateTitle :: [Inline], -- ^ Title of document
+ stateAuthors :: [String], -- ^ Authors of document
+ stateDate :: String, -- ^ Date of document
+ stateStrict :: Bool, -- ^ Use strict markdown syntax?
+ stateSmart :: Bool, -- ^ Use smart typography?
+ stateLiterateHaskell :: Bool, -- ^ Treat input as literate haskell
+ stateColumns :: Int, -- ^ Number of columns in terminal
+ stateHeaderTable :: [HeaderType] -- ^ Ordered list of header types used
+ }
+ deriving Show
+
+defaultParserState :: ParserState
+defaultParserState =
+ ParserState { stateParseRaw = False,
+ stateParserContext = NullState,
+ stateQuoteContext = NoQuote,
+ stateSanitizeHTML = False,
+ stateKeys = [],
+#ifdef _CITEPROC
+ stateCitations = [],
+#endif
+ stateNotes = [],
+ stateTabStop = 4,
+ stateStandalone = False,
+ stateTitle = [],
+ stateAuthors = [],
+ stateDate = [],
+ stateStrict = False,
+ stateSmart = False,
+ stateLiterateHaskell = False,
+ stateColumns = 80,
+ stateHeaderTable = [] }
+
+data HeaderType
+ = SingleHeader Char -- ^ Single line of characters underneath
+ | DoubleHeader Char -- ^ Lines of characters above and below
+ deriving (Eq, Show)
+
+data ParserContext
+ = ListItemState -- ^ Used when running parser on list item contents
+ | NullState -- ^ Default state
+ deriving (Eq, Show)
+
+data QuoteContext
+ = InSingleQuote -- ^ Used when parsing inside single quotes
+ | InDoubleQuote -- ^ Used when parsing inside double quotes
+ | NoQuote -- ^ Used when not parsing inside quotes
+ deriving (Eq, Show)
+
+type NoteTable = [(String, [Block])]
+
+type KeyTable = [([Inline], Target)]
+
+-- | Look up key in key table and return target object.
+lookupKeySrc :: KeyTable -- ^ Key table
+ -> [Inline] -- ^ Key
+ -> Maybe Target
+lookupKeySrc table key = case find (refsMatch key . fst) table of
+ Nothing -> Nothing
+ Just (_, src) -> Just src
+
+-- | Returns @True@ if keys match (case insensitive).
+refsMatch :: [Inline] -> [Inline] -> Bool
+refsMatch ((Str x):restx) ((Str y):resty) =
+ ((map toLower x) == (map toLower y)) && refsMatch restx resty
+refsMatch ((Emph x):restx) ((Emph y):resty) =
+ refsMatch x y && refsMatch restx resty
+refsMatch ((Strong x):restx) ((Strong y):resty) =
+ refsMatch x y && refsMatch restx resty
+refsMatch ((Strikeout x):restx) ((Strikeout y):resty) =
+ refsMatch x y && refsMatch restx resty
+refsMatch ((Superscript x):restx) ((Superscript y):resty) =
+ refsMatch x y && refsMatch restx resty
+refsMatch ((Subscript x):restx) ((Subscript y):resty) =
+ refsMatch x y && refsMatch restx resty
+refsMatch ((SmallCaps x):restx) ((SmallCaps y):resty) =
+ refsMatch x y && refsMatch restx resty
+refsMatch ((Quoted t x):restx) ((Quoted u y):resty) =
+ t == u && refsMatch x y && refsMatch restx resty
+refsMatch ((Code x):restx) ((Code y):resty) =
+ ((map toLower x) == (map toLower y)) && refsMatch restx resty
+refsMatch ((Math t x):restx) ((Math u y):resty) =
+ ((map toLower x) == (map toLower y)) && t == u && refsMatch restx resty
+refsMatch ((TeX x):restx) ((TeX y):resty) =
+ ((map toLower x) == (map toLower y)) && refsMatch restx resty
+refsMatch ((HtmlInline x):restx) ((HtmlInline y):resty) =
+ ((map toLower x) == (map toLower y)) && refsMatch restx resty
+refsMatch (x:restx) (y:resty) = (x == y) && refsMatch restx resty
+refsMatch [] x = null x
+refsMatch x [] = null x
+
+--
+-- Prettyprinting
+--
+
+-- | A version of hang that works like the version in pretty-1.0.0.0
+hang' :: Doc -> Int -> Doc -> Doc
+hang' d1 n d2 = d1 $$ (nest n d2)
+
+-- | Indent string as a block.
+indentBy :: Int -- ^ Number of spaces to indent the block
+ -> Int -- ^ Number of spaces (rel to block) to indent first line
+ -> String -- ^ Contents of block to indent
+ -> String
+indentBy _ _ [] = ""
+indentBy num first str =
+ let (firstLine:restLines) = lines str
+ firstLineIndent = num + first
+ in (replicate firstLineIndent ' ') ++ firstLine ++ "\n" ++
+ (intercalate "\n" $ map ((replicate num ' ') ++ ) restLines)
+
+-- | Prettyprint list of Pandoc blocks elements.
+prettyBlockList :: Int -- ^ Number of spaces to indent list of blocks
+ -> [Block] -- ^ List of blocks
+ -> String
+prettyBlockList indent [] = indentBy indent 0 "[]"
+prettyBlockList indent blocks = indentBy indent (-2) $ "[ " ++
+ (intercalate "\n, " (map prettyBlock blocks)) ++ " ]"
+
+-- | Prettyprint Pandoc block element.
+prettyBlock :: Block -> String
+prettyBlock (BlockQuote blocks) = "BlockQuote\n " ++
+ (prettyBlockList 2 blocks)
+prettyBlock (OrderedList attribs blockLists) =
+ "OrderedList " ++ show attribs ++ "\n" ++ indentBy 2 0 ("[ " ++
+ (intercalate ", " $ map (\blocks -> prettyBlockList 2 blocks)
+ blockLists)) ++ " ]"
+prettyBlock (BulletList blockLists) = "BulletList\n" ++
+ indentBy 2 0 ("[ " ++ (intercalate ", "
+ (map (\blocks -> prettyBlockList 2 blocks) blockLists))) ++ " ]"
+prettyBlock (DefinitionList blockLists) = "DefinitionList\n" ++
+ indentBy 2 0 ("[" ++ (intercalate ",\n"
+ (map (\(term, blocks) -> " (" ++ show term ++ ",\n" ++
+ indentBy 1 2 (prettyBlockList 2 blocks) ++ " )") blockLists))) ++ " ]"
+prettyBlock (Table caption aligns widths header rows) =
+ "Table " ++ show caption ++ " " ++ show aligns ++ " " ++
+ show widths ++ "\n" ++ prettyRow header ++ " [\n" ++
+ (intercalate ",\n" (map prettyRow rows)) ++ " ]"
+ where prettyRow cols = indentBy 2 0 ("[ " ++ (intercalate ", "
+ (map (\blocks -> prettyBlockList 2 blocks)
+ cols))) ++ " ]"
+prettyBlock block = show block
+
+-- | Prettyprint Pandoc document.
+prettyPandoc :: Pandoc -> String
+prettyPandoc (Pandoc meta blocks) = "Pandoc " ++ "(" ++ show meta ++
+ ")\n" ++ (prettyBlockList 0 blocks) ++ "\n"
+
+--
+-- Pandoc block and inline list processing
+--
+
+-- | Generate infinite lazy list of markers for an ordered list,
+-- depending on list attributes.
+orderedListMarkers :: (Int, ListNumberStyle, ListNumberDelim) -> [String]
+orderedListMarkers (start, numstyle, numdelim) =
+ let singleton c = [c]
+ nums = case numstyle of
+ DefaultStyle -> map show [start..]
+ Decimal -> map show [start..]
+ UpperAlpha -> drop (start - 1) $ cycle $
+ map singleton ['A'..'Z']
+ LowerAlpha -> drop (start - 1) $ cycle $
+ map singleton ['a'..'z']
+ UpperRoman -> map toRomanNumeral [start..]
+ LowerRoman -> map (map toLower . toRomanNumeral) [start..]
+ inDelim str = case numdelim of
+ DefaultDelim -> str ++ "."
+ Period -> str ++ "."
+ OneParen -> str ++ ")"
+ TwoParens -> "(" ++ str ++ ")"
+ in map inDelim nums
+
+-- | Normalize a list of inline elements: remove leading and trailing
+-- @Space@ elements, collapse double @Space@s into singles, and
+-- remove empty Str elements.
+normalizeSpaces :: [Inline] -> [Inline]
+normalizeSpaces [] = []
+normalizeSpaces list =
+ let removeDoubles [] = []
+ removeDoubles (Space:Space:rest) = removeDoubles (Space:rest)
+ removeDoubles (Space:(Str ""):Space:rest) = removeDoubles (Space:rest)
+ removeDoubles ((Str ""):rest) = removeDoubles rest
+ removeDoubles (x:rest) = x:(removeDoubles rest)
+ removeLeading (Space:xs) = removeLeading xs
+ removeLeading x = x
+ removeTrailing [] = []
+ removeTrailing lst = if (last lst == Space)
+ then init lst
+ else lst
+ in removeLeading $ removeTrailing $ removeDoubles list
+
+-- | Change final list item from @Para@ to @Plain@ if the list should
+-- be compact.
+compactify :: [[Block]] -- ^ List of list items (each a list of blocks)
+ -> [[Block]]
+compactify [] = []
+compactify items =
+ let final = last items
+ others = init items
+ in case last final of
+ Para a -> if all endsWithPlain others && not (null final)
+ then others ++ [init final ++ [Plain a]]
+ else items
+ _ -> items
+
+endsWithPlain :: [Block] -> Bool
+endsWithPlain [] = False
+endsWithPlain blocks =
+ case last blocks of
+ Plain _ -> True
+ (BulletList (x:xs)) -> endsWithPlain $ last (x:xs)
+ (OrderedList _ (x:xs)) -> endsWithPlain $ last (x:xs)
+ (DefinitionList (x:xs)) -> endsWithPlain $ last $ map snd (x:xs)
+ _ -> False
+
+-- | Data structure for defining hierarchical Pandoc documents
+data Element = Blk Block
+ | Sec Int String [Inline] [Element]
+ -- lvl ident label contents
+ deriving (Eq, Read, Show, Typeable, Data)
+
+-- | Convert Pandoc inline list to plain text identifier.
+inlineListToIdentifier :: [Inline] -> String
+inlineListToIdentifier = dropWhile (not . isAlpha) . inlineListToIdentifier'
+
+inlineListToIdentifier' :: [Inline] -> [Char]
+inlineListToIdentifier' [] = ""
+inlineListToIdentifier' (x:xs) =
+ xAsText ++ inlineListToIdentifier' xs
+ where xAsText = case x of
+ Str s -> filter (\c -> c == '-' || not (isPunctuation c)) $
+ intercalate "-" $ words $ map toLower s
+ Emph lst -> inlineListToIdentifier' lst
+ Strikeout lst -> inlineListToIdentifier' lst
+ Superscript lst -> inlineListToIdentifier' lst
+ SmallCaps lst -> inlineListToIdentifier' lst
+ Subscript lst -> inlineListToIdentifier' lst
+ Strong lst -> inlineListToIdentifier' lst
+ Quoted _ lst -> inlineListToIdentifier' lst
+ Cite _ lst -> inlineListToIdentifier' lst
+ Code s -> s
+ Space -> "-"
+ EmDash -> "-"
+ EnDash -> "-"
+ Apostrophe -> ""
+ Ellipses -> ""
+ LineBreak -> "-"
+ Math _ _ -> ""
+ TeX _ -> ""
+ HtmlInline _ -> ""
+ Link lst _ -> inlineListToIdentifier' lst
+ Image lst _ -> inlineListToIdentifier' lst
+ Note _ -> ""
+
+-- | Convert list of Pandoc blocks into (hierarchical) list of Elements
+hierarchicalize :: [Block] -> [Element]
+hierarchicalize blocks = S.evalState (hierarchicalizeWithIds blocks) []
+
+hierarchicalizeWithIds :: [Block] -> S.State [String] [Element]
+hierarchicalizeWithIds [] = return []
+hierarchicalizeWithIds ((Header level title'):xs) = do
+ usedIdents <- S.get
+ let ident = uniqueIdent title' usedIdents
+ S.modify (ident :)
+ let (sectionContents, rest) = break (headerLtEq level) xs
+ sectionContents' <- hierarchicalizeWithIds sectionContents
+ rest' <- hierarchicalizeWithIds rest
+ return $ Sec level ident title' sectionContents' : rest'
+hierarchicalizeWithIds (x:rest) = do
+ rest' <- hierarchicalizeWithIds rest
+ return $ (Blk x) : rest'
+
+headerLtEq :: Int -> Block -> Bool
+headerLtEq level (Header l _) = l <= level
+headerLtEq _ _ = False
+
+uniqueIdent :: [Inline] -> [String] -> String
+uniqueIdent title' usedIdents =
+ let baseIdent = inlineListToIdentifier title'
+ numIdent n = baseIdent ++ "-" ++ show n
+ in if baseIdent `elem` usedIdents
+ then case find (\x -> numIdent x `notElem` usedIdents) ([1..60000] :: [Int]) of
+ Just x -> numIdent x
+ Nothing -> baseIdent -- if we have more than 60,000, allow repeats
+ else baseIdent
+
+-- | True if block is a Header block.
+isHeaderBlock :: Block -> Bool
+isHeaderBlock (Header _ _) = True
+isHeaderBlock _ = False
+
+--
+-- Writer options
+--
+
+data HTMLMathMethod = PlainMath
+ | LaTeXMathML (Maybe String) -- url of LaTeXMathML.js
+ | JsMath (Maybe String) -- url of jsMath load script
+ | GladTeX
+ | MimeTeX String -- url of mimetex.cgi
+ deriving (Show, Read, Eq)
+
+-- | Methods for obfuscating email addresses in HTML.
+data ObfuscationMethod = NoObfuscation
+ | ReferenceObfuscation
+ | JavascriptObfuscation
+ deriving (Show, Read, Eq)
+
+-- | Options for writers
+data WriterOptions = WriterOptions
+ { writerStandalone :: Bool -- ^ Include header and footer
+ , writerHeader :: String -- ^ Header for the document
+ , writerTitlePrefix :: String -- ^ Prefix for HTML titles
+ , writerTabStop :: Int -- ^ Tabstop for conversion btw spaces and tabs
+ , writerTableOfContents :: Bool -- ^ Include table of contents
+ , writerS5 :: Bool -- ^ We're writing S5
+ , writerHTMLMathMethod :: HTMLMathMethod -- ^ How to print math in HTML
+ , writerIgnoreNotes :: Bool -- ^ Ignore footnotes (used in making toc)
+ , writerIncremental :: Bool -- ^ Incremental S5 lists
+ , writerNumberSections :: Bool -- ^ Number sections in LaTeX
+ , writerIncludeBefore :: String -- ^ String to include before the body
+ , writerIncludeAfter :: String -- ^ String to include after the body
+ , writerStrictMarkdown :: Bool -- ^ Use strict markdown syntax
+ , writerReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
+ , writerWrapText :: Bool -- ^ Wrap text to line length
+ , writerLiterateHaskell :: Bool -- ^ Write as literate haskell
+ , writerEmailObfuscation :: ObfuscationMethod -- ^ How to obfuscate emails
+ } deriving Show
+
+-- | Default writer options.
+defaultWriterOptions :: WriterOptions
+defaultWriterOptions =
+ WriterOptions { writerStandalone = False
+ , writerHeader = ""
+ , writerTitlePrefix = ""
+ , writerTabStop = 4
+ , writerTableOfContents = False
+ , writerS5 = False
+ , writerHTMLMathMethod = PlainMath
+ , writerIgnoreNotes = False
+ , writerIncremental = False
+ , writerNumberSections = False
+ , writerIncludeBefore = ""
+ , writerIncludeAfter = ""
+ , writerStrictMarkdown = False
+ , writerReferenceLinks = False
+ , writerWrapText = True
+ , writerLiterateHaskell = False
+ , writerEmailObfuscation = JavascriptObfuscation
+ }
+
+--
+-- File handling
+--
+
+-- | Perform an IO action in a directory, returning to starting directory.
+inDirectory :: FilePath -> IO a -> IO a
+inDirectory path action = do
+ oldDir <- getCurrentDirectory
+ setCurrentDirectory path
+ result <- action
+ setCurrentDirectory oldDir
+ return result
diff --git a/src/Text/Pandoc/TH.hs b/src/Text/Pandoc/TH.hs
new file mode 100644
index 000000000..0dc5a6719
--- /dev/null
+++ b/src/Text/Pandoc/TH.hs
@@ -0,0 +1,65 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-
+Copyright (C) 2008 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.TH
+ Copyright : Copyright (C) 2006-8 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Template haskell functions used by Pandoc modules.
+-}
+module Text.Pandoc.TH (
+ contentsOf,
+ binaryContentsOf,
+ makeZip
+ ) where
+
+import Language.Haskell.TH
+import Language.Haskell.TH.Syntax (Lift (..))
+import qualified Data.ByteString as B
+import Data.ByteString.Internal ( w2c )
+import Prelude hiding ( readFile )
+import System.IO.UTF8
+import Codec.Archive.Zip
+import Text.Pandoc.Shared ( inDirectory )
+
+-- | Insert contents of text file into a template.
+contentsOf :: FilePath -> ExpQ
+contentsOf p = lift =<< (runIO $ readFile p)
+
+-- | Insert contents of binary file into a template.
+-- Note that @Data.ByteString.readFile@ uses binary mode on windows.
+binaryContentsOf :: FilePath -> ExpQ
+binaryContentsOf p = lift =<< (runIO $ B.readFile p)
+
+instance Lift B.ByteString where
+ lift x = return (LitE (StringL $ map w2c $ B.unpack x))
+
+instance Lift Archive where
+ lift x = return (LitE (StringL $ show x ))
+
+-- | Construct zip file from files in a directory, and
+-- insert into a template.
+makeZip :: FilePath -> ExpQ
+makeZip path = lift =<< (runIO $ inDirectory path $ addFilesToArchive [OptRecursive] emptyArchive ["."])
+
diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs
new file mode 100644
index 000000000..014751968
--- /dev/null
+++ b/src/Text/Pandoc/Writers/ConTeXt.hs
@@ -0,0 +1,302 @@
+{-
+Copyright (C) 2007-8 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.ConTeXt
+ Copyright : Copyright (C) 2007-8 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' format into ConTeXt.
+-}
+module Text.Pandoc.Writers.ConTeXt ( writeConTeXt ) where
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Text.Printf ( printf )
+import Data.List ( isSuffixOf, intercalate )
+import Control.Monad.State
+import Text.PrettyPrint.HughesPJ hiding ( Str )
+
+data WriterState =
+ WriterState { stNextRef :: Int -- number of next URL reference
+ , stOrderedListLevel :: Int -- level of ordered list
+ , stOptions :: WriterOptions -- writer options
+ }
+
+orderedListStyles :: [[Char]]
+orderedListStyles = cycle ["[n]","[a]", "[r]", "[g]"]
+
+-- | Convert Pandoc to ConTeXt.
+writeConTeXt :: WriterOptions -> Pandoc -> String
+writeConTeXt options document =
+ let defaultWriterState = WriterState { stNextRef = 1
+ , stOrderedListLevel = 0
+ , stOptions = options
+ }
+ in render $
+ evalState (pandocToConTeXt options document) defaultWriterState
+
+pandocToConTeXt :: WriterOptions -> Pandoc -> State WriterState Doc
+pandocToConTeXt options (Pandoc meta blocks) = do
+ main <- blockListToConTeXt blocks
+ let before = if null (writerIncludeBefore options)
+ then empty
+ else text $ writerIncludeBefore options
+ let after = if null (writerIncludeAfter options)
+ then empty
+ else text $ writerIncludeAfter options
+ let body = before $$ main $$ after
+ head' <- if writerStandalone options
+ then contextHeader options meta
+ else return empty
+ let toc = if writerTableOfContents options
+ then text "\\placecontent\n"
+ else empty
+ let foot = if writerStandalone options
+ then text "\\stoptext\n"
+ else empty
+ return $ head' $$ toc $$ body $$ foot
+
+-- | Insert bibliographic information into ConTeXt header.
+contextHeader :: WriterOptions -- ^ Options, including ConTeXt header
+ -> Meta -- ^ Meta with bibliographic information
+ -> State WriterState Doc
+contextHeader options (Meta title authors date) = do
+ titletext <- if null title
+ then return empty
+ else inlineListToConTeXt title
+ let authorstext = if null authors
+ then ""
+ else if length authors == 1
+ then stringToConTeXt $ head authors
+ else stringToConTeXt $ (intercalate ", " $
+ init authors) ++ " & " ++ last authors
+ let datetext = if date == ""
+ then ""
+ else stringToConTeXt date
+ let titleblock = text "\\doctitle{" <> titletext <> char '}' $$
+ text ("\\author{" ++ authorstext ++ "}") $$
+ text ("\\date{" ++ datetext ++ "}")
+ let header = text $ writerHeader options
+ return $ header $$ titleblock $$ text "\\starttext\n\\maketitle\n"
+
+-- escape things as needed for ConTeXt
+
+escapeCharForConTeXt :: Char -> String
+escapeCharForConTeXt ch =
+ case ch of
+ '{' -> "\\letteropenbrace{}"
+ '}' -> "\\letterclosebrace{}"
+ '\\' -> "\\letterbackslash{}"
+ '$' -> "\\$"
+ '|' -> "\\letterbar{}"
+ '^' -> "\\letterhat{}"
+ '%' -> "\\%"
+ '~' -> "\\lettertilde{}"
+ '&' -> "\\&"
+ '#' -> "\\#"
+ '<' -> "\\letterless{}"
+ '>' -> "\\lettermore{}"
+ '_' -> "\\letterunderscore{}"
+ '\160' -> "~"
+ x -> [x]
+
+-- | Escape string for ConTeXt
+stringToConTeXt :: String -> String
+stringToConTeXt = concatMap escapeCharForConTeXt
+
+-- | Convert Pandoc block element to ConTeXt.
+blockToConTeXt :: Block
+ -> State WriterState BlockWrapper
+blockToConTeXt Null = return $ Reg empty
+blockToConTeXt (Plain lst) = do
+ st <- get
+ let options = stOptions st
+ contents <- wrapTeXIfNeeded options False inlineListToConTeXt lst
+ return $ Reg contents
+blockToConTeXt (Para lst) = do
+ st <- get
+ let options = stOptions st
+ contents <- wrapTeXIfNeeded options False inlineListToConTeXt lst
+ return $ Pad contents
+blockToConTeXt (BlockQuote lst) = do
+ contents <- blockListToConTeXt lst
+ return $ Pad $ text "\\startblockquote" $$ contents $$ text "\\stopblockquote"
+blockToConTeXt (CodeBlock _ str) =
+ return $ Reg $ text $ "\\starttyping\n" ++ str ++ "\n\\stoptyping\n"
+ -- \n because \stoptyping can't have anything after it, inc. }
+blockToConTeXt (RawHtml _) = return $ Reg empty
+blockToConTeXt (BulletList lst) = do
+ contents <- mapM listItemToConTeXt lst
+ return $ Pad $ text "\\startitemize" $$ vcat contents $$ text "\\stopitemize"
+blockToConTeXt (OrderedList (start, style', delim) lst) = do
+ st <- get
+ let level = stOrderedListLevel st
+ put $ st {stOrderedListLevel = level + 1}
+ contents <- mapM listItemToConTeXt lst
+ put $ st {stOrderedListLevel = level}
+ let start' = if start == 1 then "" else "start=" ++ show start
+ let delim' = case delim of
+ DefaultDelim -> ""
+ Period -> "stopper=."
+ OneParen -> "stopper=)"
+ TwoParens -> "left=(,stopper=)"
+ let width = maximum $ map length $ take (length contents)
+ (orderedListMarkers (start, style', delim))
+ let width' = (toEnum width + 1) / 2
+ let width'' = if width' > (1.5 :: Double)
+ then "width=" ++ show width' ++ "em"
+ else ""
+ let specs2Items = filter (not . null) [start', delim', width'']
+ let specs2 = if null specs2Items
+ then ""
+ else "[" ++ intercalate "," specs2Items ++ "]"
+ let style'' = case style' of
+ DefaultStyle -> orderedListStyles !! level
+ Decimal -> "[n]"
+ LowerRoman -> "[r]"
+ UpperRoman -> "[R]"
+ LowerAlpha -> "[a]"
+ UpperAlpha -> "[A]"
+ let specs = style'' ++ specs2
+ return $ Pad $ text ("\\startitemize" ++ specs) $$ vcat contents $$
+ text "\\stopitemize"
+blockToConTeXt (DefinitionList lst) =
+ mapM defListItemToConTeXt lst >>= return . Pad . wrappedBlocksToDoc
+blockToConTeXt HorizontalRule = return $ Pad $ text "\\thinrule"
+blockToConTeXt (Header level lst) = do
+ contents <- inlineListToConTeXt lst
+ st <- get
+ let opts = stOptions st
+ let base = if writerNumberSections opts then "section" else "subject"
+ return $ Pad $ if level >= 1 && level <= 5
+ then char '\\' <> text (concat (replicate (level - 1) "sub")) <>
+ text base <> char '{' <> contents <> char '}'
+ else contents
+blockToConTeXt (Table caption aligns widths heads rows) = do
+ let colWidths = map printDecimal widths
+ let colDescriptor colWidth alignment = (case alignment of
+ AlignLeft -> 'l'
+ AlignRight -> 'r'
+ AlignCenter -> 'c'
+ AlignDefault -> 'l'):
+ "p(" ++ colWidth ++ "\\textwidth)|"
+ let colDescriptors = "|" ++ (concat $
+ zipWith colDescriptor colWidths aligns)
+ headers <- tableRowToConTeXt heads
+ captionText <- inlineListToConTeXt caption
+ let captionText' = if null caption then text "none" else captionText
+ rows' <- mapM tableRowToConTeXt rows
+ return $ Pad $ text "\\placetable[here]{" <> captionText' <> char '}' $$
+ text "\\starttable[" <> text colDescriptors <> char ']' $$
+ text "\\HL" $$ headers $$ text "\\HL" $$
+ vcat rows' $$ text "\\HL\n\\stoptable"
+
+printDecimal :: Double -> String
+printDecimal = printf "%.2f"
+
+tableRowToConTeXt :: [[Block]] -> State WriterState Doc
+tableRowToConTeXt cols = do
+ cols' <- mapM blockListToConTeXt cols
+ return $ (vcat (map (text "\\NC " <>) cols')) $$
+ text "\\NC\\AR"
+
+listItemToConTeXt :: [Block] -> State WriterState Doc
+listItemToConTeXt list = blockListToConTeXt list >>=
+ return . (text "\\item" $$) . (nest 2)
+
+defListItemToConTeXt :: ([Inline], [Block]) -> State WriterState BlockWrapper
+defListItemToConTeXt (term, def) = do
+ term' <- inlineListToConTeXt term
+ def' <- blockListToConTeXt def
+ return $ Pad $ text "\\startdescr{" <> term' <> char '}' $$ def' $$ text "\\stopdescr"
+
+-- | Convert list of block elements to ConTeXt.
+blockListToConTeXt :: [Block] -> State WriterState Doc
+blockListToConTeXt lst = mapM blockToConTeXt lst >>= return . wrappedBlocksToDoc
+
+-- | Convert list of inline elements to ConTeXt.
+inlineListToConTeXt :: [Inline] -- ^ Inlines to convert
+ -> State WriterState Doc
+inlineListToConTeXt lst = mapM inlineToConTeXt lst >>= return . hcat
+
+-- | Convert inline element to ConTeXt
+inlineToConTeXt :: Inline -- ^ Inline to convert
+ -> State WriterState Doc
+inlineToConTeXt (Emph lst) = do
+ contents <- inlineListToConTeXt lst
+ return $ text "{\\em " <> contents <> char '}'
+inlineToConTeXt (Strong lst) = do
+ contents <- inlineListToConTeXt lst
+ return $ text "{\\bf " <> contents <> char '}'
+inlineToConTeXt (Strikeout lst) = do
+ contents <- inlineListToConTeXt lst
+ return $ text "\\overstrikes{" <> contents <> char '}'
+inlineToConTeXt (Superscript lst) = do
+ contents <- inlineListToConTeXt lst
+ return $ text "\\high{" <> contents <> char '}'
+inlineToConTeXt (Subscript lst) = do
+ contents <- inlineListToConTeXt lst
+ return $ text "\\low{" <> contents <> char '}'
+inlineToConTeXt (SmallCaps lst) = do
+ contents <- inlineListToConTeXt lst
+ return $ text "{\\sc " <> contents <> char '}'
+inlineToConTeXt (Code str) = return $ text $ "\\type{" ++ str ++ "}"
+inlineToConTeXt (Quoted SingleQuote lst) = do
+ contents <- inlineListToConTeXt lst
+ return $ text "\\quote{" <> contents <> char '}'
+inlineToConTeXt (Quoted DoubleQuote lst) = do
+ contents <- inlineListToConTeXt lst
+ return $ text "\\quotation{" <> contents <> char '}'
+inlineToConTeXt (Cite _ lst) = inlineListToConTeXt lst
+inlineToConTeXt Apostrophe = return $ char '\''
+inlineToConTeXt EmDash = return $ text "---"
+inlineToConTeXt EnDash = return $ text "--"
+inlineToConTeXt Ellipses = return $ text "\\ldots{}"
+inlineToConTeXt (Str str) = return $ text $ stringToConTeXt str
+inlineToConTeXt (Math InlineMath str) = return $ char '$' <> text str <> char '$'
+inlineToConTeXt (Math DisplayMath str) = return $ text "\\startformula " <> text str <> text " \\stopformula"
+inlineToConTeXt (TeX str) = return $ text str
+inlineToConTeXt (HtmlInline _) = return empty
+inlineToConTeXt (LineBreak) = return $ text "\\crlf\n"
+inlineToConTeXt Space = return $ char ' '
+inlineToConTeXt (Link [Code str] (src, tit)) = -- since ConTeXt has its own
+ inlineToConTeXt (Link [Str str] (src, tit)) -- way of printing links...
+inlineToConTeXt (Link txt (src, _)) = do
+ st <- get
+ let next = stNextRef st
+ put $ st {stNextRef = next + 1}
+ let ref = show next
+ label <- inlineListToConTeXt txt
+ return $ text "\\useURL[" <> text ref <> text "][" <> text src <>
+ text "][][" <> label <> text "]\\from[" <> text ref <> char ']'
+inlineToConTeXt (Image alternate (src, tit)) = do
+ alt <- inlineListToConTeXt alternate
+ return $ text "\\placefigure\n[]\n[fig:" <> alt <> text "]\n{" <>
+ text tit <> text "}\n{\\externalfigure[" <> text src <> text "]}"
+inlineToConTeXt (Note contents) = do
+ contents' <- blockListToConTeXt contents
+ let rawnote = stripTrailingNewlines $ render contents'
+ -- note: a \n before } is needed when note ends with a \stoptyping
+ let optNewline = "\\stoptyping" `isSuffixOf` rawnote
+ return $ text "\\footnote{" <>
+ text rawnote <> (if optNewline then char '\n' else empty) <> char '}'
+
diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs
new file mode 100644
index 000000000..cd426e7c8
--- /dev/null
+++ b/src/Text/Pandoc/Writers/Docbook.hs
@@ -0,0 +1,274 @@
+{-
+Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.Docbook
+ Copyright : Copyright (C) 2006-7 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' documents to Docbook XML.
+-}
+module Text.Pandoc.Writers.Docbook ( writeDocbook) where
+import Text.Pandoc.Definition
+import Text.Pandoc.XML
+import Text.Pandoc.Shared
+import Text.Pandoc.Readers.TeXMath
+import Data.List ( isPrefixOf, drop, intercalate )
+import Data.Char ( toLower )
+import Text.PrettyPrint.HughesPJ hiding ( Str )
+import Text.Pandoc.Highlighting (languages, languagesByExtension)
+
+-- | Convert list of authors to a docbook <author> section
+authorToDocbook :: [Char] -> Doc
+authorToDocbook name = inTagsIndented "author" $
+ if ',' `elem` name
+ then -- last name first
+ let (lastname, rest) = break (==',') name
+ firstname = removeLeadingSpace rest in
+ inTagsSimple "firstname" (text $ escapeStringForXML firstname) <>
+ inTagsSimple "surname" (text $ escapeStringForXML lastname)
+ else -- last name last
+ let namewords = words name
+ lengthname = length namewords
+ (firstname, lastname) = case lengthname of
+ 0 -> ("","")
+ 1 -> ("", name)
+ n -> (intercalate " " (take (n-1) namewords), last namewords)
+ in inTagsSimple "firstname" (text $ escapeStringForXML firstname) $$
+ inTagsSimple "surname" (text $ escapeStringForXML lastname)
+
+-- | Convert Pandoc document to string in Docbook format.
+writeDocbook :: WriterOptions -> Pandoc -> String
+writeDocbook opts (Pandoc (Meta title authors date) blocks) =
+ let head' = if writerStandalone opts
+ then text (writerHeader opts)
+ else empty
+ meta = if writerStandalone opts
+ then inTagsIndented "articleinfo" $
+ (inTagsSimple "title" (wrap opts title)) $$
+ (vcat (map authorToDocbook authors)) $$
+ (inTagsSimple "date" (text $ escapeStringForXML date))
+ else empty
+ elements = hierarchicalize blocks
+ before = writerIncludeBefore opts
+ after = writerIncludeAfter opts
+ body = (if null before then empty else text before) $$
+ vcat (map (elementToDocbook opts) elements) $$
+ (if null after then empty else text after)
+ body' = if writerStandalone opts
+ then inTagsIndented "article" (meta $$ body)
+ else body
+ in render $ head' $$ body' $$ text ""
+
+-- | Convert an Element to Docbook.
+elementToDocbook :: WriterOptions -> Element -> Doc
+elementToDocbook opts (Blk block) = blockToDocbook opts block
+elementToDocbook opts (Sec _ _ title elements) =
+ -- Docbook doesn't allow sections with no content, so insert some if needed
+ let elements' = if null elements
+ then [Blk (Para [])]
+ else elements
+ in inTagsIndented "section" $
+ inTagsSimple "title" (wrap opts title) $$
+ vcat (map (elementToDocbook opts) elements')
+
+-- | Convert a list of Pandoc blocks to Docbook.
+blocksToDocbook :: WriterOptions -> [Block] -> Doc
+blocksToDocbook opts = vcat . map (blockToDocbook opts)
+
+-- | Auxiliary function to convert Plain block to Para.
+plainToPara :: Block -> Block
+plainToPara (Plain x) = Para x
+plainToPara x = x
+
+-- | Convert a list of pairs of terms and definitions into a list of
+-- Docbook varlistentrys.
+deflistItemsToDocbook :: WriterOptions -> [([Inline],[Block])] -> Doc
+deflistItemsToDocbook opts items =
+ vcat $ map (\(term, def) -> deflistItemToDocbook opts term def) items
+
+-- | Convert a term and a list of blocks into a Docbook varlistentry.
+deflistItemToDocbook :: WriterOptions -> [Inline] -> [Block] -> Doc
+deflistItemToDocbook opts term def =
+ let def' = map plainToPara def
+ in inTagsIndented "varlistentry" $
+ inTagsIndented "term" (inlinesToDocbook opts term) $$
+ inTagsIndented "listitem" (blocksToDocbook opts def')
+
+-- | Convert a list of lists of blocks to a list of Docbook list items.
+listItemsToDocbook :: WriterOptions -> [[Block]] -> Doc
+listItemsToDocbook opts items = vcat $ map (listItemToDocbook opts) items
+
+-- | Convert a list of blocks into a Docbook list item.
+listItemToDocbook :: WriterOptions -> [Block] -> Doc
+listItemToDocbook opts item =
+ inTagsIndented "listitem" $ blocksToDocbook opts $ map plainToPara item
+
+-- | Convert a Pandoc block element to Docbook.
+blockToDocbook :: WriterOptions -> Block -> Doc
+blockToDocbook _ Null = empty
+blockToDocbook _ (Header _ _) = empty -- should not occur after hierarchicalize
+blockToDocbook opts (Plain lst) = wrap opts lst
+blockToDocbook opts (Para lst) = inTagsIndented "para" $ wrap opts lst
+blockToDocbook opts (BlockQuote blocks) =
+ inTagsIndented "blockquote" $ blocksToDocbook opts blocks
+blockToDocbook _ (CodeBlock (_,classes,_) str) =
+ text ("<screen" ++ lang ++ ">\n") <>
+ text (escapeStringForXML str) <> text "\n</screen>"
+ where lang = if null langs
+ then ""
+ else " language=\"" ++ escapeStringForXML (head langs) ++
+ "\""
+ isLang l = map toLower l `elem` map (map toLower) languages
+ langsFrom s = if isLang s
+ then [s]
+ else languagesByExtension . map toLower $ s
+ langs = concatMap langsFrom classes
+blockToDocbook opts (BulletList lst) =
+ inTagsIndented "itemizedlist" $ listItemsToDocbook opts lst
+blockToDocbook _ (OrderedList _ []) = empty
+blockToDocbook opts (OrderedList (start, numstyle, _) (first:rest)) =
+ let attribs = case numstyle of
+ DefaultStyle -> []
+ Decimal -> [("numeration", "arabic")]
+ UpperAlpha -> [("numeration", "upperalpha")]
+ LowerAlpha -> [("numeration", "loweralpha")]
+ UpperRoman -> [("numeration", "upperroman")]
+ LowerRoman -> [("numeration", "lowerroman")]
+ items = if start == 1
+ then listItemsToDocbook opts (first:rest)
+ else (inTags True "listitem" [("override",show start)]
+ (blocksToDocbook opts $ map plainToPara first)) $$
+ listItemsToDocbook opts rest
+ in inTags True "orderedlist" attribs items
+blockToDocbook opts (DefinitionList lst) =
+ inTagsIndented "variablelist" $ deflistItemsToDocbook opts lst
+blockToDocbook _ (RawHtml str) = text str -- raw XML block
+blockToDocbook _ HorizontalRule = empty -- not semantic
+blockToDocbook opts (Table caption aligns widths headers rows) =
+ let alignStrings = map alignmentToString aligns
+ captionDoc = if null caption
+ then empty
+ else inTagsIndented "caption"
+ (inlinesToDocbook opts caption)
+ tableType = if isEmpty captionDoc then "informaltable" else "table"
+ in inTagsIndented tableType $ captionDoc $$
+ (colHeadsToDocbook opts alignStrings widths headers) $$
+ (vcat $ map (tableRowToDocbook opts alignStrings) rows)
+
+colHeadsToDocbook :: WriterOptions
+ -> [[Char]]
+ -> [Double]
+ -> [[Block]]
+ -> Doc
+colHeadsToDocbook opts alignStrings widths headers =
+ let heads = zipWith3 (\align width item ->
+ tableItemToDocbook opts "th" align width item)
+ alignStrings widths headers
+ in inTagsIndented "tr" $ vcat heads
+
+alignmentToString :: Alignment -> [Char]
+alignmentToString alignment = case alignment of
+ AlignLeft -> "left"
+ AlignRight -> "right"
+ AlignCenter -> "center"
+ AlignDefault -> "left"
+
+tableRowToDocbook :: WriterOptions -> [[Char]] -> [[Block]] -> Doc
+tableRowToDocbook opts aligns cols = inTagsIndented "tr" $
+ vcat $ zipWith3 (tableItemToDocbook opts "td") aligns (repeat 0) cols
+
+tableItemToDocbook :: WriterOptions
+ -> [Char]
+ -> [Char]
+ -> Double
+ -> [Block]
+ -> Doc
+tableItemToDocbook opts tag align width item =
+ let attrib = [("align", align)] ++
+ if width /= 0
+ then [("style", "{width: " ++
+ show (truncate (100*width) :: Integer) ++ "%;}")]
+ else []
+ in inTags True tag attrib $ vcat $ map (blockToDocbook opts) item
+
+-- | Take list of inline elements and return wrapped doc.
+wrap :: WriterOptions -> [Inline] -> Doc
+wrap opts lst = if writerWrapText opts
+ then fsep $ map (inlinesToDocbook opts) (splitBy Space lst)
+ else inlinesToDocbook opts lst
+
+-- | Convert a list of inline elements to Docbook.
+inlinesToDocbook :: WriterOptions -> [Inline] -> Doc
+inlinesToDocbook opts lst = hcat $ map (inlineToDocbook opts) lst
+
+-- | Convert an inline element to Docbook.
+inlineToDocbook :: WriterOptions -> Inline -> Doc
+inlineToDocbook _ (Str str) = text $ escapeStringForXML str
+inlineToDocbook opts (Emph lst) =
+ inTagsSimple "emphasis" $ inlinesToDocbook opts lst
+inlineToDocbook opts (Strong lst) =
+ inTags False "emphasis" [("role", "strong")] $ inlinesToDocbook opts lst
+inlineToDocbook opts (Strikeout lst) =
+ inTags False "emphasis" [("role", "strikethrough")] $
+ inlinesToDocbook opts lst
+inlineToDocbook opts (Superscript lst) =
+ inTagsSimple "superscript" $ inlinesToDocbook opts lst
+inlineToDocbook opts (Subscript lst) =
+ inTagsSimple "subscript" $ inlinesToDocbook opts lst
+inlineToDocbook opts (SmallCaps lst) =
+ inTags False "emphasis" [("role", "smallcaps")] $
+ inlinesToDocbook opts lst
+inlineToDocbook opts (Quoted _ lst) =
+ inTagsSimple "quote" $ inlinesToDocbook opts lst
+inlineToDocbook opts (Cite _ lst) =
+ inlinesToDocbook opts lst
+inlineToDocbook _ Apostrophe = char '\''
+inlineToDocbook _ Ellipses = text "&#8230;"
+inlineToDocbook _ EmDash = text "&#8212;"
+inlineToDocbook _ EnDash = text "&#8211;"
+inlineToDocbook _ (Code str) =
+ inTagsSimple "literal" $ text (escapeStringForXML str)
+inlineToDocbook opts (Math _ str) = inlinesToDocbook opts $ readTeXMath str
+inlineToDocbook _ (TeX _) = empty
+inlineToDocbook _ (HtmlInline _) = empty
+inlineToDocbook _ LineBreak = text $ "<literallayout></literallayout>"
+inlineToDocbook _ Space = char ' '
+inlineToDocbook opts (Link txt (src, _)) =
+ if isPrefixOf "mailto:" src
+ then let src' = drop 7 src
+ emailLink = inTagsSimple "email" $ text $
+ escapeStringForXML $ src'
+ in if txt == [Code src']
+ then emailLink
+ else inlinesToDocbook opts txt <+> char '(' <> emailLink <>
+ char ')'
+ else inTags False "ulink" [("url", src)] $ inlinesToDocbook opts txt
+inlineToDocbook _ (Image _ (src, tit)) =
+ let titleDoc = if null tit
+ then empty
+ else inTagsIndented "objectinfo" $
+ inTagsIndented "title" (text $ escapeStringForXML tit)
+ in inTagsIndented "inlinemediaobject" $ inTagsIndented "imageobject" $
+ titleDoc $$ selfClosingTag "imagedata" [("fileref", src)]
+inlineToDocbook opts (Note contents) =
+ inTagsIndented "footnote" $ blocksToDocbook opts contents
diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs
new file mode 100644
index 000000000..4b6ea5982
--- /dev/null
+++ b/src/Text/Pandoc/Writers/HTML.hs
@@ -0,0 +1,493 @@
+{-# OPTIONS_GHC -fno-warn-deprecations #-}
+{-
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.HTML
+ Copyright : Copyright (C) 2006-8 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' documents to HTML.
+-}
+module Text.Pandoc.Writers.HTML ( writeHtml , writeHtmlString ) where
+import Text.Pandoc.Definition
+import Text.Pandoc.LaTeXMathML
+import Text.Pandoc.CharacterReferences ( decodeCharacterReferences )
+import Text.Pandoc.Shared
+import Text.Pandoc.Readers.TeXMath
+import Text.Pandoc.Highlighting ( highlightHtml, defaultHighlightingCss )
+import Numeric ( showHex )
+import Data.Char ( ord, toLower )
+import Data.List ( isPrefixOf, intercalate )
+import Data.Maybe ( catMaybes )
+import qualified Data.Set as S
+import Control.Monad.State
+import Text.XHtml.Transitional hiding ( stringToHtml )
+
+data WriterState = WriterState
+ { stNotes :: [Html] -- ^ List of notes
+ , stMath :: Bool -- ^ Math is used in document
+ , stCSS :: S.Set String -- ^ CSS to include in header
+ } deriving Show
+
+defaultWriterState :: WriterState
+defaultWriterState = WriterState {stNotes= [], stMath = False, stCSS = S.empty}
+
+-- Helpers to render HTML with the appropriate function.
+
+render :: (HTML html) => WriterOptions -> html -> String
+render opts = if writerWrapText opts then renderHtml else showHtml
+
+renderFragment :: (HTML html) => WriterOptions -> html -> String
+renderFragment opts = if writerWrapText opts
+ then renderHtmlFragment
+ else showHtmlFragment
+
+-- | Slightly modified version of Text.XHtml's stringToHtml.
+-- Only uses numerical entities for 0xff and greater.
+-- Adds &nbsp;.
+stringToHtml :: String -> Html
+stringToHtml = primHtml . concatMap fixChar
+ where
+ fixChar '<' = "&lt;"
+ fixChar '>' = "&gt;"
+ fixChar '&' = "&amp;"
+ fixChar '"' = "&quot;"
+ fixChar '\160' = "&nbsp;"
+ fixChar c | ord c < 0xff = [c]
+ fixChar c = "&#" ++ show (ord c) ++ ";"
+
+-- | Convert Pandoc document to Html string.
+writeHtmlString :: WriterOptions -> Pandoc -> String
+writeHtmlString opts =
+ if writerStandalone opts
+ then render opts . writeHtml opts
+ else renderFragment opts . writeHtml opts
+
+-- | Convert Pandoc document to Html structure.
+writeHtml :: WriterOptions -> Pandoc -> Html
+writeHtml opts (Pandoc (Meta tit authors date) blocks) =
+ let titlePrefix = writerTitlePrefix opts
+ topTitle = evalState (inlineListToHtml opts tit) defaultWriterState
+ topTitle' = if null titlePrefix
+ then topTitle
+ else if null tit
+ then stringToHtml titlePrefix
+ else titlePrefix +++ " - " +++ topTitle
+ metadata = thetitle topTitle' +++
+ meta ! [httpequiv "Content-Type",
+ content "text/html; charset=UTF-8"] +++
+ meta ! [name "generator", content "pandoc"] +++
+ (toHtmlFromList $
+ map (\a -> meta ! [name "author", content a]) authors) +++
+ (if null date
+ then noHtml
+ else meta ! [name "date", content date])
+ titleHeader = if writerStandalone opts && not (null tit) &&
+ not (writerS5 opts)
+ then h1 ! [theclass "title"] $ topTitle
+ else noHtml
+ sects = hierarchicalize blocks
+ toc = if writerTableOfContents opts
+ then evalState (tableOfContents opts sects) defaultWriterState
+ else noHtml
+ (blocks', newstate) = runState
+ (mapM (elementToHtml opts) sects >>= return . toHtmlFromList)
+ defaultWriterState
+ cssLines = stCSS newstate
+ css = if S.null cssLines
+ then noHtml
+ else style ! [thetype "text/css"] $ primHtml $
+ '\n':(unlines $ S.toList cssLines)
+ math = if stMath newstate
+ then case writerHTMLMathMethod opts of
+ LaTeXMathML Nothing ->
+ primHtml latexMathMLScript
+ LaTeXMathML (Just url) ->
+ script !
+ [src url, thetype "text/javascript"] $
+ noHtml
+ JsMath (Just url) ->
+ script !
+ [src url, thetype "text/javascript"] $
+ noHtml
+ _ -> noHtml
+ else noHtml
+ head' = header $ metadata +++ math +++ css +++
+ primHtml (writerHeader opts)
+ notes = reverse (stNotes newstate)
+ before = primHtml $ writerIncludeBefore opts
+ after = primHtml $ writerIncludeAfter opts
+ thebody = before +++ titleHeader +++ toc +++ blocks' +++
+ footnoteSection notes +++ after
+ in if writerStandalone opts
+ then head' +++ body thebody
+ else thebody
+
+-- | Construct table of contents from list of elements.
+tableOfContents :: WriterOptions -> [Element] -> State WriterState Html
+tableOfContents _ [] = return noHtml
+tableOfContents opts sects = do
+ let opts' = opts { writerIgnoreNotes = True }
+ contents <- mapM (elementToListItem opts') sects
+ return $ thediv ! [identifier "TOC"] $ unordList $ catMaybes contents
+
+-- | Converts an Element to a list item for a table of contents,
+-- retrieving the appropriate identifier from state.
+elementToListItem :: WriterOptions -> Element -> State WriterState (Maybe Html)
+elementToListItem _ (Blk _) = return Nothing
+elementToListItem opts (Sec _ id' headerText subsecs) = do
+ txt <- inlineListToHtml opts headerText
+ subHeads <- mapM (elementToListItem opts) subsecs >>= return . catMaybes
+ let subList = if null subHeads
+ then noHtml
+ else unordList subHeads
+ return $ Just $ (anchor ! [href ("#" ++ id')] $ txt) +++ subList
+
+-- | Convert an Element to Html.
+elementToHtml :: WriterOptions -> Element -> State WriterState Html
+elementToHtml opts (Blk block) = blockToHtml opts block
+elementToHtml opts (Sec level id' title' elements) = do
+ innerContents <- mapM (elementToHtml opts) elements
+ header' <- blockToHtml opts (Header level title')
+ return $ if writerS5 opts || (writerStrictMarkdown opts && not (writerTableOfContents opts))
+ -- S5 gets confused by the extra divs around sections
+ then toHtmlFromList (header' : innerContents)
+ else thediv ! [identifier id'] << (header' : innerContents)
+
+-- | Convert list of Note blocks to a footnote <div>.
+-- Assumes notes are sorted.
+footnoteSection :: [Html] -> Html
+footnoteSection notes =
+ if null notes
+ then noHtml
+ else thediv ! [theclass "footnotes"] $ hr +++ (olist << notes)
+
+
+-- | Parse a mailto link; return Just (name, domain) or Nothing.
+parseMailto :: String -> Maybe (String, String)
+parseMailto ('m':'a':'i':'l':'t':'o':':':addr) =
+ let (name', rest) = span (/='@') addr
+ domain = drop 1 rest
+ in Just (name', domain)
+parseMailto _ = Nothing
+
+-- | Obfuscate a "mailto:" link.
+obfuscateLink :: WriterOptions -> String -> String -> Html
+obfuscateLink opts txt s | writerEmailObfuscation opts == NoObfuscation =
+ anchor ! [href s] << txt
+obfuscateLink opts txt s =
+ let meth = writerEmailObfuscation opts
+ s' = map toLower s
+ in case parseMailto s' of
+ (Just (name', domain)) ->
+ let domain' = substitute "." " dot " domain
+ at' = obfuscateChar '@'
+ (linkText, altText) =
+ if txt == drop 7 s' -- autolink
+ then ("'<code>'+e+'</code>'", name' ++ " at " ++ domain')
+ else ("'" ++ txt ++ "'", txt ++ " (" ++ name' ++ " at " ++
+ domain' ++ ")")
+ in case meth of
+ ReferenceObfuscation ->
+ -- need to use primHtml or &'s are escaped to &amp; in URL
+ primHtml $ "<a href=\"" ++ (obfuscateString s')
+ ++ "\">" ++ (obfuscateString txt) ++ "</a>"
+ JavascriptObfuscation ->
+ (script ! [thetype "text/javascript"] $
+ primHtml ("\n<!--\nh='" ++
+ obfuscateString domain ++ "';a='" ++ at' ++ "';n='" ++
+ obfuscateString name' ++ "';e=n+a+h;\n" ++
+ "document.write('<a h'+'ref'+'=\"ma'+'ilto'+':'+e+'\">'+" ++
+ linkText ++ "+'<\\/'+'a'+'>');\n// -->\n")) +++
+ noscript (primHtml $ obfuscateString altText)
+ _ -> error $ "Unknown obfuscation method: " ++ show meth
+ _ -> anchor ! [href s] $ primHtml txt -- malformed email
+
+-- | Obfuscate character as entity.
+obfuscateChar :: Char -> String
+obfuscateChar char =
+ let num = ord char
+ numstr = if even num then show num else "x" ++ showHex num ""
+ in "&#" ++ numstr ++ ";"
+
+-- | Obfuscate string using entities.
+obfuscateString :: String -> String
+obfuscateString = concatMap obfuscateChar . decodeCharacterReferences
+
+-- | Add CSS for document header.
+addToCSS :: String -> State WriterState ()
+addToCSS item = do
+ st <- get
+ let current = stCSS st
+ put $ st {stCSS = S.insert item current}
+
+-- | Convert Pandoc block element to HTML.
+blockToHtml :: WriterOptions -> Block -> State WriterState Html
+blockToHtml _ Null = return $ noHtml
+blockToHtml opts (Plain lst) = inlineListToHtml opts lst
+blockToHtml opts (Para lst) = inlineListToHtml opts lst >>= (return . paragraph)
+blockToHtml _ (RawHtml str) = return $ primHtml str
+blockToHtml _ (HorizontalRule) = return $ hr
+blockToHtml opts (CodeBlock (_,classes,_) rawCode) | "haskell" `elem` classes &&
+ writerLiterateHaskell opts =
+ let classes' = map (\c -> if c == "haskell" then "literatehaskell" else c) classes
+ in blockToHtml opts $ CodeBlock ("",classes',[]) $ intercalate "\n" $ map ("> " ++) $ lines rawCode
+blockToHtml _ (CodeBlock attr@(_,classes,_) rawCode) = do
+ case highlightHtml attr rawCode of
+ Left _ -> -- change leading newlines into <br /> tags, because some
+ -- browsers ignore leading newlines in pre blocks
+ let (leadingBreaks, rawCode') = span (=='\n') rawCode
+ in return $ pre ! (if null classes
+ then []
+ else [theclass $ unwords classes]) $ thecode <<
+ (replicate (length leadingBreaks) br +++
+ [stringToHtml $ rawCode' ++ "\n"])
+ Right h -> addToCSS defaultHighlightingCss >> return h
+blockToHtml opts (BlockQuote blocks) =
+ -- in S5, treat list in blockquote specially
+ -- if default is incremental, make it nonincremental;
+ -- otherwise incremental
+ if writerS5 opts
+ then let inc = not (writerIncremental opts) in
+ case blocks of
+ [BulletList lst] -> blockToHtml (opts {writerIncremental = inc})
+ (BulletList lst)
+ [OrderedList attribs lst] ->
+ blockToHtml (opts {writerIncremental = inc})
+ (OrderedList attribs lst)
+ _ -> blockListToHtml opts blocks >>=
+ (return . blockquote)
+ else blockListToHtml opts blocks >>= (return . blockquote)
+blockToHtml opts (Header level lst) = do
+ contents <- inlineListToHtml opts lst
+ let contents' = if writerTableOfContents opts
+ then anchor ! [href "#TOC"] $ contents
+ else contents
+ return $ case level of
+ 1 -> h1 contents'
+ 2 -> h2 contents'
+ 3 -> h3 contents'
+ 4 -> h4 contents'
+ 5 -> h5 contents'
+ 6 -> h6 contents'
+ _ -> paragraph contents'
+blockToHtml opts (BulletList lst) = do
+ contents <- mapM (blockListToHtml opts) lst
+ let attribs = if writerIncremental opts
+ then [theclass "incremental"]
+ else []
+ return $ unordList ! attribs $ contents
+blockToHtml opts (OrderedList (startnum, numstyle, _) lst) = do
+ contents <- mapM (blockListToHtml opts) lst
+ let numstyle' = camelCaseToHyphenated $ show numstyle
+ let attribs = (if writerIncremental opts
+ then [theclass "incremental"]
+ else []) ++
+ (if startnum /= 1
+ then [start startnum]
+ else []) ++
+ (if numstyle /= DefaultStyle
+ then [thestyle $ "list-style-type: " ++ numstyle' ++ ";"]
+ else [])
+ return $ ordList ! attribs $ contents
+blockToHtml opts (DefinitionList lst) = do
+ contents <- mapM (\(term, def) -> do term' <- inlineListToHtml opts term
+ def' <- blockListToHtml opts def
+ return $ (term', def')) lst
+ let attribs = if writerIncremental opts
+ then [theclass "incremental"]
+ else []
+ return $ defList ! attribs $ contents
+blockToHtml opts (Table capt aligns widths headers rows') = do
+ let alignStrings = map alignmentToString aligns
+ captionDoc <- if null capt
+ then return noHtml
+ else inlineListToHtml opts capt >>= return . caption
+ colHeads <- colHeadsToHtml opts alignStrings
+ widths headers
+ rows'' <- zipWithM (tableRowToHtml opts alignStrings) (cycle ["odd", "even"]) rows'
+ return $ table $ captionDoc +++ colHeads +++ rows''
+
+colHeadsToHtml :: WriterOptions
+ -> [[Char]]
+ -> [Double]
+ -> [[Block]]
+ -> State WriterState Html
+colHeadsToHtml opts alignStrings widths headers = do
+ heads <- sequence $ zipWith3
+ (\alignment columnwidth item -> tableItemToHtml opts th alignment columnwidth item)
+ alignStrings widths headers
+ return $ tr ! [theclass "header"] $ toHtmlFromList heads
+
+alignmentToString :: Alignment -> [Char]
+alignmentToString alignment = case alignment of
+ AlignLeft -> "left"
+ AlignRight -> "right"
+ AlignCenter -> "center"
+ AlignDefault -> "left"
+
+tableRowToHtml :: WriterOptions
+ -> [[Char]]
+ -> String
+ -> [[Block]]
+ -> State WriterState Html
+tableRowToHtml opts aligns rowclass columns =
+ (sequence $ zipWith3 (tableItemToHtml opts td) aligns (repeat 0) columns) >>=
+ return . (tr ! [theclass rowclass]) . toHtmlFromList
+
+tableItemToHtml :: WriterOptions
+ -> (Html -> Html)
+ -> [Char]
+ -> Double
+ -> [Block]
+ -> State WriterState Html
+tableItemToHtml opts tag' align' width' item = do
+ contents <- blockListToHtml opts item
+ let attrib = [align align'] ++
+ if width' /= 0
+ then [thestyle ("width: " ++ (show (truncate (100 * width') :: Integer)) ++ "%;")]
+ else []
+ return $ tag' ! attrib $ contents
+
+blockListToHtml :: WriterOptions -> [Block] -> State WriterState Html
+blockListToHtml opts lst =
+ mapM (blockToHtml opts) lst >>= return . toHtmlFromList
+
+-- | Convert list of Pandoc inline elements to HTML.
+inlineListToHtml :: WriterOptions -> [Inline] -> State WriterState Html
+inlineListToHtml opts lst =
+ mapM (inlineToHtml opts) lst >>= return . toHtmlFromList
+
+-- | Convert Pandoc inline element to HTML.
+inlineToHtml :: WriterOptions -> Inline -> State WriterState Html
+inlineToHtml opts inline =
+ case inline of
+ (Str str) -> return $ stringToHtml str
+ (Space) -> return $ stringToHtml " "
+ (LineBreak) -> return $ br
+ (EmDash) -> return $ primHtmlChar "mdash"
+ (EnDash) -> return $ primHtmlChar "ndash"
+ (Ellipses) -> return $ primHtmlChar "hellip"
+ (Apostrophe) -> return $ primHtmlChar "rsquo"
+ (Emph lst) -> inlineListToHtml opts lst >>= return . emphasize
+ (Strong lst) -> inlineListToHtml opts lst >>= return . strong
+ (Code str) -> return $ thecode << str
+ (Strikeout lst) -> inlineListToHtml opts lst >>=
+ return . (thespan ! [thestyle "text-decoration: line-through;"])
+ (SmallCaps lst) -> inlineListToHtml opts lst >>=
+ return . (thespan ! [thestyle "font-variant: small-caps;"])
+ (Superscript lst) -> inlineListToHtml opts lst >>= return . sup
+ (Subscript lst) -> inlineListToHtml opts lst >>= return . sub
+ (Quoted quoteType lst) ->
+ let (leftQuote, rightQuote) = case quoteType of
+ SingleQuote -> (primHtmlChar "lsquo",
+ primHtmlChar "rsquo")
+ DoubleQuote -> (primHtmlChar "ldquo",
+ primHtmlChar "rdquo")
+ in do contents <- inlineListToHtml opts lst
+ return $ leftQuote +++ contents +++ rightQuote
+ (Math t str) ->
+ modify (\st -> st {stMath = True}) >>
+ (case writerHTMLMathMethod opts of
+ LaTeXMathML _ ->
+ -- putting LaTeXMathML in container with class "LaTeX" prevents
+ -- non-math elements on the page from being treated as math by
+ -- the javascript
+ return $ thespan ! [theclass "LaTeX"] $
+ if t == InlineMath
+ then primHtml ("$" ++ str ++ "$")
+ else primHtml ("$$" ++ str ++ "$$")
+ JsMath _ ->
+ return $ if t == InlineMath
+ then thespan ! [theclass "math"] $ primHtml str
+ else thediv ! [theclass "math"] $ primHtml str
+ MimeTeX url ->
+ return $ image ! [src (url ++ "?" ++ str),
+ alt str, title str]
+ GladTeX ->
+ return $ primHtml $ "<EQ>" ++ str ++ "</EQ>"
+ PlainMath ->
+ inlineListToHtml opts (readTeXMath str) >>=
+ return . (thespan ! [theclass "math"]) )
+ (TeX str) -> case writerHTMLMathMethod opts of
+ LaTeXMathML _ -> do modify (\st -> st {stMath = True})
+ return $ primHtml str
+ _ -> return noHtml
+ (HtmlInline str) -> return $ primHtml str
+ (Link [Code str] (s,_)) | "mailto:" `isPrefixOf` s ->
+ return $ obfuscateLink opts str s
+ (Link txt (s,_)) | "mailto:" `isPrefixOf` s -> do
+ linkText <- inlineListToHtml opts txt
+ return $ obfuscateLink opts (show linkText) s
+ (Link txt (s,tit)) -> do
+ linkText <- inlineListToHtml opts txt
+ return $ anchor ! ([href s] ++
+ if null tit then [] else [title tit]) $
+ linkText
+ (Image txt (s,tit)) -> do
+ alternate <- inlineListToHtml opts txt
+ let alternate' = renderFragment opts alternate
+ let attributes = [src s] ++
+ (if null tit
+ then []
+ else [title tit]) ++
+ if null txt
+ then []
+ else [alt alternate']
+ return $ image ! attributes
+ -- note: null title included, as in Markdown.pl
+ (Note contents) -> do
+ st <- get
+ let notes = stNotes st
+ let number = (length notes) + 1
+ let ref = show number
+ htmlContents <- blockListToNote opts ref contents
+ -- push contents onto front of notes
+ put $ st {stNotes = (htmlContents:notes)}
+ return $ anchor ! [href ("#fn" ++ ref),
+ theclass "footnoteRef",
+ identifier ("fnref" ++ ref)] <<
+ sup << ref
+ (Cite _ il) -> inlineListToHtml opts il
+
+blockListToNote :: WriterOptions -> String -> [Block] -> State WriterState Html
+blockListToNote opts ref blocks =
+ -- If last block is Para or Plain, include the backlink at the end of
+ -- that block. Otherwise, insert a new Plain block with the backlink.
+ let backlink = [HtmlInline $ " <a href=\"#fnref" ++ ref ++
+ "\" class=\"footnoteBackLink\"" ++
+ " title=\"Jump back to footnote " ++ ref ++ "\">&#8617;</a>"]
+ blocks' = if null blocks
+ then []
+ else let lastBlock = last blocks
+ otherBlocks = init blocks
+ in case lastBlock of
+ (Para lst) -> otherBlocks ++
+ [Para (lst ++ backlink)]
+ (Plain lst) -> otherBlocks ++
+ [Plain (lst ++ backlink)]
+ _ -> otherBlocks ++ [lastBlock,
+ Plain backlink]
+ in do contents <- blockListToHtml opts blocks'
+ return $ li ! [identifier ("fn" ++ ref)] $ contents
+
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
new file mode 100644
index 000000000..f3cbf1acb
--- /dev/null
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -0,0 +1,331 @@
+{-
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.LaTeX
+ Copyright : Copyright (C) 2006-8 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' format into LaTeX.
+-}
+module Text.Pandoc.Writers.LaTeX ( writeLaTeX ) where
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Text.Printf ( printf )
+import Data.List ( (\\), isSuffixOf, intercalate )
+import Data.Char ( toLower )
+import qualified Data.Set as S
+import Control.Monad.State
+import Text.PrettyPrint.HughesPJ hiding ( Str )
+
+data WriterState =
+ WriterState { stIncludes :: S.Set String -- strings to include in header
+ , stInNote :: Bool -- @True@ if we're in a note
+ , stOLLevel :: Int -- level of ordered list nesting
+ , stOptions :: WriterOptions -- writer options, so they don't have to be parameter
+ }
+
+-- | Add line to header.
+addToHeader :: String -> State WriterState ()
+addToHeader str = do
+ st <- get
+ let includes = stIncludes st
+ put st {stIncludes = S.insert str includes}
+
+-- | Convert Pandoc to LaTeX.
+writeLaTeX :: WriterOptions -> Pandoc -> String
+writeLaTeX options document =
+ render $ evalState (pandocToLaTeX options document) $
+ WriterState { stIncludes = S.empty, stInNote = False, stOLLevel = 1, stOptions = options }
+
+pandocToLaTeX :: WriterOptions -> Pandoc -> State WriterState Doc
+pandocToLaTeX options (Pandoc meta blocks) = do
+ main <- blockListToLaTeX blocks
+ head' <- if writerStandalone options
+ then latexHeader options meta
+ else return empty
+ let before = if null (writerIncludeBefore options)
+ then empty
+ else text (writerIncludeBefore options)
+ let after = if null (writerIncludeAfter options)
+ then empty
+ else text (writerIncludeAfter options)
+ let body = before $$ main $$ after
+ let toc = if writerTableOfContents options
+ then text "\\tableofcontents\n"
+ else empty
+ let foot = if writerStandalone options
+ then text "\\end{document}"
+ else empty
+ return $ head' $$ toc $$ body $$ foot
+
+-- | Insert bibliographic information into LaTeX header.
+latexHeader :: WriterOptions -- ^ Options, including LaTeX header
+ -> Meta -- ^ Meta with bibliographic information
+ -> State WriterState Doc
+latexHeader options (Meta title authors date) = do
+ titletext <- if null title
+ then return empty
+ else inlineListToLaTeX title >>= return . inCmd "title"
+ headerIncludes <- get >>= return . S.toList . stIncludes
+ let extras = text $ unlines headerIncludes
+ let verbatim = if "\\usepackage{fancyvrb}" `elem` headerIncludes
+ then text "\\VerbatimFootnotes % allows verbatim text in footnotes"
+ else empty
+ let authorstext = text $ "\\author{" ++
+ intercalate "\\\\" (map stringToLaTeX authors) ++ "}"
+ let datetext = if date == ""
+ then empty
+ else text $ "\\date{" ++ stringToLaTeX date ++ "}"
+ let maketitle = if null title then empty else text "\\maketitle"
+ let secnumline = if (writerNumberSections options)
+ then empty
+ else text "\\setcounter{secnumdepth}{0}"
+ let baseHeader = text $ writerHeader options
+ let header = baseHeader $$ extras
+ return $ header $$ secnumline $$ verbatim $$ titletext $$ authorstext $$
+ datetext $$ text "\\begin{document}" $$ maketitle $$ text ""
+
+-- escape things as needed for LaTeX
+
+stringToLaTeX :: String -> String
+stringToLaTeX = escapeStringUsing latexEscapes
+ where latexEscapes = backslashEscapes "{}$%&_#" ++
+ [ ('^', "\\^{}")
+ , ('\\', "\\textbackslash{}")
+ , ('~', "\\ensuremath{\\sim}")
+ , ('|', "\\textbar{}")
+ , ('<', "\\textless{}")
+ , ('>', "\\textgreater{}")
+ , ('\160', "~")
+ ]
+
+-- | Puts contents into LaTeX command.
+inCmd :: String -> Doc -> Doc
+inCmd cmd contents = char '\\' <> text cmd <> braces contents
+
+-- | Remove all code elements from list of inline elements
+-- (because it's illegal to have verbatim inside some command arguments)
+deVerb :: [Inline] -> [Inline]
+deVerb [] = []
+deVerb ((Code str):rest) =
+ (TeX $ "\\texttt{" ++ stringToLaTeX str ++ "}"):(deVerb rest)
+deVerb (other:rest) = other:(deVerb rest)
+
+-- | Convert Pandoc block element to LaTeX.
+blockToLaTeX :: Block -- ^ Block to convert
+ -> State WriterState Doc
+blockToLaTeX Null = return empty
+blockToLaTeX (Plain lst) = do
+ st <- get
+ let opts = stOptions st
+ wrapTeXIfNeeded opts True inlineListToLaTeX lst
+blockToLaTeX (Para lst) = do
+ st <- get
+ let opts = stOptions st
+ result <- wrapTeXIfNeeded opts True inlineListToLaTeX lst
+ return $ result <> char '\n'
+blockToLaTeX (BlockQuote lst) = do
+ contents <- blockListToLaTeX lst
+ return $ text "\\begin{quote}" $$ contents $$ text "\\end{quote}"
+blockToLaTeX (CodeBlock (_,classes,_) str) = do
+ st <- get
+ env <- if writerLiterateHaskell (stOptions st) && "haskell" `elem` classes
+ then return "code"
+ else if stInNote st
+ then do addToHeader "\\usepackage{fancyvrb}"
+ return "Verbatim"
+ else return "verbatim"
+ return $ text ("\\begin{" ++ env ++ "}\n") <> text str <>
+ text ("\n\\end{" ++ env ++ "}")
+blockToLaTeX (RawHtml _) = return empty
+blockToLaTeX (BulletList lst) = do
+ items <- mapM listItemToLaTeX lst
+ return $ text "\\begin{itemize}" $$ vcat items $$ text "\\end{itemize}"
+blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do
+ st <- get
+ let oldlevel = stOLLevel st
+ put $ st {stOLLevel = oldlevel + 1}
+ items <- mapM listItemToLaTeX lst
+ modify (\s -> s {stOLLevel = oldlevel})
+ exemplar <- if numstyle /= DefaultStyle || numdelim /= DefaultDelim
+ then do addToHeader "\\usepackage{enumerate}"
+ return $ char '[' <>
+ text (head (orderedListMarkers (1, numstyle,
+ numdelim))) <> char ']'
+ else return empty
+ let resetcounter = if start /= 1 && oldlevel <= 4
+ then text $ "\\setcounter{enum" ++
+ map toLower (toRomanNumeral oldlevel) ++
+ "}{" ++ show (start - 1) ++ "}"
+ else empty
+ return $ text "\\begin{enumerate}" <> exemplar $$ resetcounter $$
+ vcat items $$ text "\\end{enumerate}"
+blockToLaTeX (DefinitionList lst) = do
+ items <- mapM defListItemToLaTeX lst
+ return $ text "\\begin{description}" $$ vcat items $$
+ text "\\end{description}"
+blockToLaTeX HorizontalRule = return $ text $
+ "\\begin{center}\\rule{3in}{0.4pt}\\end{center}\n"
+blockToLaTeX (Header level lst) = do
+ txt <- inlineListToLaTeX (deVerb lst)
+ return $ if (level > 0) && (level <= 3)
+ then text ("\\" ++ (concat (replicate (level - 1) "sub")) ++
+ "section{") <> txt <> text "}\n"
+ else txt <> char '\n'
+blockToLaTeX (Table caption aligns widths heads rows) = do
+ headers <- tableRowToLaTeX heads
+ captionText <- inlineListToLaTeX caption
+ rows' <- mapM tableRowToLaTeX rows
+ let colWidths = map (printf "%.2f") widths
+ let colDescriptors = concat $ zipWith
+ (\width align -> ">{\\PBS" ++
+ (case align of
+ AlignLeft -> "\\raggedright"
+ AlignRight -> "\\raggedleft"
+ AlignCenter -> "\\centering"
+ AlignDefault -> "\\raggedright") ++
+ "\\hspace{0pt}}p{" ++ width ++
+ "\\columnwidth}")
+ colWidths aligns
+ let tableBody = text ("\\begin{tabular}{" ++ colDescriptors ++ "}") $$
+ headers $$ text "\\hline" $$ vcat rows' $$
+ text "\\end{tabular}"
+ let centered txt = text "\\begin{center}" $$ txt $$ text "\\end{center}"
+ addToHeader $ "\\usepackage{array}\n" ++
+ "% This is needed because raggedright in table elements redefines \\\\:\n" ++
+ "\\newcommand{\\PreserveBackslash}[1]{\\let\\temp=\\\\#1\\let\\\\=\\temp}\n" ++
+ "\\let\\PBS=\\PreserveBackslash"
+ return $ if isEmpty captionText
+ then centered tableBody <> char '\n'
+ else text "\\begin{table}[h]" $$ centered tableBody $$
+ inCmd "caption" captionText $$ text "\\end{table}\n"
+
+blockListToLaTeX :: [Block] -> State WriterState Doc
+blockListToLaTeX lst = mapM blockToLaTeX lst >>= return . vcat
+
+tableRowToLaTeX :: [[Block]] -> State WriterState Doc
+tableRowToLaTeX cols = mapM blockListToLaTeX cols >>=
+ return . ($$ text "\\\\") . foldl (\row item -> row $$
+ (if isEmpty row then text "" else text " & ") <> item) empty
+
+listItemToLaTeX :: [Block] -> State WriterState Doc
+listItemToLaTeX lst = blockListToLaTeX lst >>= return . (text "\\item" $$) .
+ (nest 2)
+
+defListItemToLaTeX :: ([Inline], [Block]) -> State WriterState Doc
+defListItemToLaTeX (term, def) = do
+ term' <- inlineListToLaTeX $ deVerb term
+ def' <- blockListToLaTeX def
+ return $ text "\\item[" <> term' <> text "]" $$ def'
+
+-- | Convert list of inline elements to LaTeX.
+inlineListToLaTeX :: [Inline] -- ^ Inlines to convert
+ -> State WriterState Doc
+inlineListToLaTeX lst = mapM inlineToLaTeX lst >>= return . hcat
+
+isQuoted :: Inline -> Bool
+isQuoted (Quoted _ _) = True
+isQuoted Apostrophe = True
+isQuoted _ = False
+
+-- | Convert inline element to LaTeX
+inlineToLaTeX :: Inline -- ^ Inline to convert
+ -> State WriterState Doc
+inlineToLaTeX (Emph lst) =
+ inlineListToLaTeX (deVerb lst) >>= return . inCmd "emph"
+inlineToLaTeX (Strong lst) =
+ inlineListToLaTeX (deVerb lst) >>= return . inCmd "textbf"
+inlineToLaTeX (Strikeout lst) = do
+ contents <- inlineListToLaTeX $ deVerb lst
+ addToHeader "\\usepackage[normalem]{ulem}"
+ return $ inCmd "sout" contents
+inlineToLaTeX (Superscript lst) =
+ inlineListToLaTeX (deVerb lst) >>= return . inCmd "textsuperscript"
+inlineToLaTeX (Subscript lst) = do
+ contents <- inlineListToLaTeX $ deVerb lst
+ -- oddly, latex includes \textsuperscript but not \textsubscript
+ -- so we have to define it (using a different name so as not to conflict with memoir class):
+ addToHeader "\\newcommand{\\textsubscr}[1]{\\ensuremath{_{\\scriptsize\\textrm{#1}}}}"
+ return $ inCmd "textsubscr" contents
+inlineToLaTeX (SmallCaps lst) =
+ inlineListToLaTeX (deVerb lst) >>= return . inCmd "textsc"
+inlineToLaTeX (Cite _ lst) =
+ inlineListToLaTeX lst
+inlineToLaTeX (Code str) = do
+ st <- get
+ if stInNote st
+ then do addToHeader "\\usepackage{fancyvrb}"
+ else return ()
+ let chr = ((enumFromTo '!' '~') \\ str) !! 0
+ return $ text $ "\\verb" ++ [chr] ++ str ++ [chr]
+inlineToLaTeX (Quoted SingleQuote lst) = do
+ contents <- inlineListToLaTeX lst
+ let s1 = if (not (null lst)) && (isQuoted (head lst))
+ then text "\\,"
+ else empty
+ let s2 = if (not (null lst)) && (isQuoted (last lst))
+ then text "\\,"
+ else empty
+ return $ char '`' <> s1 <> contents <> s2 <> char '\''
+inlineToLaTeX (Quoted DoubleQuote lst) = do
+ contents <- inlineListToLaTeX lst
+ let s1 = if (not (null lst)) && (isQuoted (head lst))
+ then text "\\,"
+ else empty
+ let s2 = if (not (null lst)) && (isQuoted (last lst))
+ then text "\\,"
+ else empty
+ return $ text "``" <> s1 <> contents <> s2 <> text "''"
+inlineToLaTeX Apostrophe = return $ char '\''
+inlineToLaTeX EmDash = return $ text "---"
+inlineToLaTeX EnDash = return $ text "--"
+inlineToLaTeX Ellipses = return $ text "\\ldots{}"
+inlineToLaTeX (Str str) = return $ text $ stringToLaTeX str
+inlineToLaTeX (Math InlineMath str) = return $ char '$' <> text str <> char '$'
+inlineToLaTeX (Math DisplayMath str) = return $ text "\\[" <> text str <> text "\\]"
+inlineToLaTeX (TeX str) = return $ text str
+inlineToLaTeX (HtmlInline _) = return empty
+inlineToLaTeX (LineBreak) = return $ text "\\\\"
+inlineToLaTeX Space = return $ char ' '
+inlineToLaTeX (Link txt (src, _)) = do
+ addToHeader "\\usepackage[breaklinks=true]{hyperref}"
+ case txt of
+ [Code x] | x == src -> -- autolink
+ do addToHeader "\\usepackage{url}"
+ return $ text $ "\\url{" ++ x ++ "}"
+ _ -> do contents <- inlineListToLaTeX $ deVerb txt
+ return $ text ("\\href{" ++ src ++ "}{") <> contents <>
+ char '}'
+inlineToLaTeX (Image _ (source, _)) = do
+ addToHeader "\\usepackage{graphicx}"
+ return $ text $ "\\includegraphics{" ++ source ++ "}"
+inlineToLaTeX (Note contents) = do
+ st <- get
+ put (st {stInNote = True})
+ contents' <- blockListToLaTeX contents
+ modify (\s -> s {stInNote = False})
+ let rawnote = stripTrailingNewlines $ render contents'
+ -- note: a \n before } is needed when note ends with a Verbatim environment
+ let optNewline = "\\end{Verbatim}" `isSuffixOf` rawnote
+ return $ text "\\footnote{" <>
+ text rawnote <> (if optNewline then char '\n' else empty) <> char '}'
diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs
new file mode 100644
index 000000000..89c865754
--- /dev/null
+++ b/src/Text/Pandoc/Writers/Man.hs
@@ -0,0 +1,334 @@
+{-
+Copyright (C) 2007 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.Man
+ Copyright : Copyright (C) 2007 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' documents to groff man page format.
+
+-}
+module Text.Pandoc.Writers.Man ( writeMan) where
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Text.Printf ( printf )
+import Data.List ( isPrefixOf, drop, nub, intersperse, intercalate )
+import Text.PrettyPrint.HughesPJ hiding ( Str )
+import Control.Monad.State
+import Control.Monad ( liftM )
+
+type Notes = [[Block]]
+type Preprocessors = [String] -- e.g. "t" for tbl
+type WriterState = (Notes, Preprocessors)
+
+-- | Convert Pandoc to Man.
+writeMan :: WriterOptions -> Pandoc -> String
+writeMan opts document = render $ evalState (pandocToMan opts document) ([],[])
+
+-- | Return groff man representation of document.
+pandocToMan :: WriterOptions -> Pandoc -> State WriterState Doc
+pandocToMan opts (Pandoc meta blocks) = do
+ let before = writerIncludeBefore opts
+ let after = writerIncludeAfter opts
+ let before' = if null before then empty else text before
+ let after' = if null after then empty else text after
+ (head', foot) <- metaToMan opts meta
+ body <- blockListToMan opts blocks
+ (notes, preprocessors) <- get
+ let preamble = if null preprocessors || not (writerStandalone opts)
+ then empty
+ else text $ ".\\\" " ++ concat (nub preprocessors)
+ notes' <- notesToMan opts (reverse notes)
+ return $ preamble $$ head' $$ before' $$ body $$ notes' $$ foot $$ after'
+
+-- | Insert bibliographic information into Man header and footer.
+metaToMan :: WriterOptions -- ^ Options, including Man header
+ -> Meta -- ^ Meta with bibliographic information
+ -> State WriterState (Doc, Doc)
+metaToMan options (Meta title authors date) = do
+ titleText <- inlineListToMan options title
+ let (cmdName, rest) = break (== ' ') $ render titleText
+ let (title', section) = case reverse cmdName of
+ (')':d:'(':xs) | d `elem` ['0'..'9'] ->
+ (text (reverse xs), char d)
+ xs -> (text (reverse xs), doubleQuotes empty)
+ let extras = map (doubleQuotes . text . removeLeadingTrailingSpace) $
+ splitBy '|' rest
+ let head' = (text ".TH") <+> title' <+> section <+>
+ doubleQuotes (text date) <+> hsep extras
+ let foot = case length authors of
+ 0 -> empty
+ 1 -> text ".SH AUTHOR" $$ (text $ intercalate ", " authors)
+ _ -> text ".SH AUTHORS" $$ (text $ intercalate ", " authors)
+ return $ if writerStandalone options
+ then (head', foot)
+ else (empty, empty)
+
+-- | Return man representation of notes.
+notesToMan :: WriterOptions -> [[Block]] -> State WriterState Doc
+notesToMan opts notes =
+ if null notes
+ then return empty
+ else mapM (\(num, note) -> noteToMan opts num note) (zip [1..] notes) >>=
+ return . (text ".SH NOTES" $$) . vcat
+
+-- | Return man representation of a note.
+noteToMan :: WriterOptions -> Int -> [Block] -> State WriterState Doc
+noteToMan opts num note = do
+ contents <- blockListToMan opts note
+ let marker = text "\n.SS [" <> text (show num) <> char ']'
+ return $ marker $$ contents
+
+-- | Association list of characters to escape.
+manEscapes :: [(Char, String)]
+manEscapes = [('\160', "\\ "), ('\'', "\\[aq]")] ++ backslashEscapes "@\\"
+
+-- | Escape special characters for Man.
+escapeString :: String -> String
+escapeString = escapeStringUsing manEscapes
+
+-- | Escape a literal (code) section for Man.
+escapeCode :: String -> String
+escapeCode = escapeStringUsing (manEscapes ++ backslashEscapes "\t ")
+
+-- We split inline lists into sentences, and print one sentence per
+-- line. groff/troff treats the line-ending period differently.
+-- See http://code.google.com/p/pandoc/issues/detail?id=148.
+
+-- | Returns the first sentence in a list of inlines, and the rest.
+breakSentence :: [Inline] -> ([Inline], [Inline])
+breakSentence [] = ([],[])
+breakSentence xs =
+ let isSentenceEndInline (Str ".") = True
+ isSentenceEndInline (Str "?") = True
+ isSentenceEndInline _ = False
+ (as, bs) = break isSentenceEndInline xs
+ in case bs of
+ [] -> (as, [])
+ [c] -> (as ++ [c], [])
+ (c:Space:cs) -> (as ++ [c], cs)
+ (Str ".":Str ")":cs) -> (as ++ [Str ".", Str ")"], cs)
+ (c:cs) -> (as ++ [c] ++ ds, es)
+ where (ds, es) = breakSentence cs
+
+-- | Split a list of inlines into sentences.
+splitSentences :: [Inline] -> [[Inline]]
+splitSentences xs =
+ let (sent, rest) = breakSentence xs
+ in if null rest then [sent] else sent : splitSentences rest
+
+-- | Convert Pandoc block element to man.
+blockToMan :: WriterOptions -- ^ Options
+ -> Block -- ^ Block element
+ -> State WriterState Doc
+blockToMan _ Null = return empty
+blockToMan opts (Plain inlines) =
+ liftM vcat $ mapM (wrapIfNeeded opts (inlineListToMan opts)) $
+ splitSentences inlines
+blockToMan opts (Para inlines) = do
+ contents <- liftM vcat $ mapM (wrapIfNeeded opts (inlineListToMan opts)) $
+ splitSentences inlines
+ return $ text ".PP" $$ contents
+blockToMan _ (RawHtml str) = return $ text str
+blockToMan _ HorizontalRule = return $ text $ ".PP\n * * * * *"
+blockToMan opts (Header level inlines) = do
+ contents <- inlineListToMan opts inlines
+ let heading = case level of
+ 1 -> ".SH "
+ _ -> ".SS "
+ return $ text heading <> contents
+blockToMan _ (CodeBlock _ str) = return $
+ text ".PP" $$ text "\\f[CR]" $$
+ text ((unlines . map (" " ++) . lines) (escapeCode str)) <> text "\\f[]"
+blockToMan opts (BlockQuote blocks) = do
+ contents <- blockListToMan opts blocks
+ return $ text ".RS" $$ contents $$ text ".RE"
+blockToMan opts (Table caption alignments widths headers rows) =
+ let aligncode AlignLeft = "l"
+ aligncode AlignRight = "r"
+ aligncode AlignCenter = "c"
+ aligncode AlignDefault = "l"
+ in do
+ caption' <- inlineListToMan opts caption
+ modify (\(notes, preprocessors) -> (notes, "t":preprocessors))
+ let iwidths = map (printf "w(%0.2fn)" . (70 *)) widths
+ -- 78n default width - 8n indent = 70n
+ let coldescriptions = text $ intercalate " "
+ (zipWith (\align width -> aligncode align ++ width)
+ alignments iwidths) ++ "."
+ colheadings <- mapM (blockListToMan opts) headers
+ let makeRow cols = text "T{" $$
+ (vcat $ intersperse (text "T}@T{") cols) $$
+ text "T}"
+ let colheadings' = makeRow colheadings
+ body <- mapM (\row -> do
+ cols <- mapM (blockListToMan opts) row
+ return $ makeRow cols) rows
+ return $ text ".PP" $$ caption' $$
+ text ".TS" $$ text "tab(@);" $$ coldescriptions $$
+ colheadings' $$ char '_' $$ vcat body $$ text ".TE"
+
+blockToMan opts (BulletList items) = do
+ contents <- mapM (bulletListItemToMan opts) items
+ return (vcat contents)
+blockToMan opts (OrderedList attribs items) = do
+ let markers = take (length items) $ orderedListMarkers attribs
+ let indent = 1 + (maximum $ map length markers)
+ contents <- mapM (\(num, item) -> orderedListItemToMan opts num indent item) $
+ zip markers items
+ return (vcat contents)
+blockToMan opts (DefinitionList items) = do
+ contents <- mapM (definitionListItemToMan opts) items
+ return (vcat contents)
+
+-- | Convert bullet list item (list of blocks) to man.
+bulletListItemToMan :: WriterOptions -> [Block] -> State WriterState Doc
+bulletListItemToMan _ [] = return empty
+bulletListItemToMan opts ((Para first):rest) =
+ bulletListItemToMan opts ((Plain first):rest)
+bulletListItemToMan opts ((Plain first):rest) = do
+ first' <- blockToMan opts (Plain first)
+ rest' <- blockListToMan opts rest
+ let first'' = text ".IP \\[bu] 2" $$ first'
+ let rest'' = if null rest
+ then empty
+ else text ".RS 2" $$ rest' $$ text ".RE"
+ return (first'' $$ rest'')
+bulletListItemToMan opts (first:rest) = do
+ first' <- blockToMan opts first
+ rest' <- blockListToMan opts rest
+ return $ text "\\[bu] .RS 2" $$ first' $$ rest' $$ text ".RE"
+
+-- | Convert ordered list item (a list of blocks) to man.
+orderedListItemToMan :: WriterOptions -- ^ options
+ -> String -- ^ order marker for list item
+ -> Int -- ^ number of spaces to indent
+ -> [Block] -- ^ list item (list of blocks)
+ -> State WriterState Doc
+orderedListItemToMan _ _ _ [] = return empty
+orderedListItemToMan opts num indent ((Para first):rest) =
+ orderedListItemToMan opts num indent ((Plain first):rest)
+orderedListItemToMan opts num indent (first:rest) = do
+ first' <- blockToMan opts first
+ rest' <- blockListToMan opts rest
+ let num' = printf ("%" ++ show (indent - 1) ++ "s") num
+ let first'' = text (".IP \"" ++ num' ++ "\" " ++ show indent) $$ first'
+ let rest'' = if null rest
+ then empty
+ else text ".RS 4" $$ rest' $$ text ".RE"
+ return $ first'' $$ rest''
+
+-- | Convert definition list item (label, list of blocks) to man.
+definitionListItemToMan :: WriterOptions
+ -> ([Inline],[Block])
+ -> State WriterState Doc
+definitionListItemToMan opts (label, items) = do
+ labelText <- inlineListToMan opts label
+ contents <- if null items
+ then return empty
+ else do
+ let (first, rest) = case items of
+ ((Para x):y) -> (Plain x,y)
+ (x:y) -> (x,y)
+ [] -> error "items is null"
+ rest' <- mapM (\item -> blockToMan opts item)
+ rest >>= (return . vcat)
+ first' <- blockToMan opts first
+ return $ first' $$ text ".RS" $$ rest' $$ text ".RE"
+ return $ text ".TP\n.B " <> labelText $+$ contents
+
+-- | Convert list of Pandoc block elements to man.
+blockListToMan :: WriterOptions -- ^ Options
+ -> [Block] -- ^ List of block elements
+ -> State WriterState Doc
+blockListToMan opts blocks =
+ mapM (blockToMan opts) blocks >>= (return . vcat)
+
+-- | Convert list of Pandoc inline elements to man.
+inlineListToMan :: WriterOptions -> [Inline] -> State WriterState Doc
+-- if list starts with ., insert a zero-width character \& so it
+-- won't be interpreted as markup if it falls at the beginning of a line.
+inlineListToMan opts lst@(Str "." : _) = mapM (inlineToMan opts) lst >>=
+ (return . (text "\\&" <>) . hcat)
+inlineListToMan opts lst = mapM (inlineToMan opts) lst >>= (return . hcat)
+
+-- | Convert Pandoc inline element to man.
+inlineToMan :: WriterOptions -> Inline -> State WriterState Doc
+inlineToMan opts (Emph lst) = do
+ contents <- inlineListToMan opts lst
+ return $ text "\\f[I]" <> contents <> text "\\f[]"
+inlineToMan opts (Strong lst) = do
+ contents <- inlineListToMan opts lst
+ return $ text "\\f[B]" <> contents <> text "\\f[]"
+inlineToMan opts (Strikeout lst) = do
+ contents <- inlineListToMan opts lst
+ return $ text "[STRIKEOUT:" <> contents <> char ']'
+inlineToMan opts (Superscript lst) = do
+ contents <- inlineListToMan opts lst
+ return $ char '^' <> contents <> char '^'
+inlineToMan opts (Subscript lst) = do
+ contents <- inlineListToMan opts lst
+ return $ char '~' <> contents <> char '~'
+inlineToMan opts (SmallCaps lst) = inlineListToMan opts lst -- not supported
+inlineToMan opts (Quoted SingleQuote lst) = do
+ contents <- inlineListToMan opts lst
+ return $ char '`' <> contents <> char '\''
+inlineToMan opts (Quoted DoubleQuote lst) = do
+ contents <- inlineListToMan opts lst
+ return $ text "\\[lq]" <> contents <> text "\\[rq]"
+inlineToMan opts (Cite _ lst) =
+ inlineListToMan opts lst
+inlineToMan _ EmDash = return $ text "\\[em]"
+inlineToMan _ EnDash = return $ text "\\[en]"
+inlineToMan _ Apostrophe = return $ char '\''
+inlineToMan _ Ellipses = return $ text "\\&..."
+inlineToMan _ (Code str) =
+ return $ text $ "\\f[B]" ++ escapeCode str ++ "\\f[]"
+inlineToMan _ (Str str) = return $ text $ escapeString str
+inlineToMan opts (Math InlineMath str) = inlineToMan opts (Code str)
+inlineToMan opts (Math DisplayMath str) = do
+ contents <- inlineToMan opts (Code str)
+ return $ text ".RS" $$ contents $$ text ".RE"
+inlineToMan _ (TeX _) = return empty
+inlineToMan _ (HtmlInline str) = return $ text $ escapeCode str
+inlineToMan _ (LineBreak) = return $ text "\n.PD 0\n.P\n.PD\n"
+inlineToMan _ Space = return $ char ' '
+inlineToMan opts (Link txt (src, _)) = do
+ linktext <- inlineListToMan opts txt
+ let srcSuffix = if isPrefixOf "mailto:" src then drop 7 src else src
+ return $ if txt == [Code srcSuffix]
+ then char '<' <> text srcSuffix <> char '>'
+ else linktext <> text " (" <> text src <> char ')'
+inlineToMan opts (Image alternate (source, tit)) = do
+ let txt = if (null alternate) || (alternate == [Str ""]) ||
+ (alternate == [Str source]) -- to prevent autolinks
+ then [Str "image"]
+ else alternate
+ linkPart <- inlineToMan opts (Link txt (source, tit))
+ return $ char '[' <> text "IMAGE: " <> linkPart <> char ']'
+inlineToMan _ (Note contents) = do
+ modify (\(notes, prep) -> (contents:notes, prep)) -- add to notes in state
+ (notes, _) <- get
+ let ref = show $ (length notes)
+ return $ char '[' <> text ref <> char ']'
+
diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs
new file mode 100644
index 000000000..b2c1dc175
--- /dev/null
+++ b/src/Text/Pandoc/Writers/Markdown.hs
@@ -0,0 +1,399 @@
+{-
+Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.Markdown
+ Copyright : Copyright (C) 2006-7 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' documents to markdown-formatted plain text.
+
+Markdown: <http://daringfireball.net/projects/markdown/>
+-}
+module Text.Pandoc.Writers.Markdown ( writeMarkdown) where
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Text.Pandoc.Blocks
+import Text.ParserCombinators.Parsec ( parse, GenParser )
+import Data.List ( group, isPrefixOf, drop, find, intersperse, intercalate )
+import Text.PrettyPrint.HughesPJ hiding ( Str )
+import Control.Monad.State
+
+type Notes = [[Block]]
+type Refs = KeyTable
+type WriterState = (Notes, Refs)
+
+-- | Convert Pandoc to Markdown.
+writeMarkdown :: WriterOptions -> Pandoc -> String
+writeMarkdown opts document =
+ render $ evalState (pandocToMarkdown opts document) ([],[])
+
+-- | Return markdown representation of document.
+pandocToMarkdown :: WriterOptions -> Pandoc -> State WriterState Doc
+pandocToMarkdown opts (Pandoc meta blocks) = do
+ let before = writerIncludeBefore opts
+ let after = writerIncludeAfter opts
+ let header = writerHeader opts
+ let before' = if null before then empty else text before
+ let after' = if null after then empty else text after
+ let header' = if null header then empty else text header
+ metaBlock <- metaToMarkdown opts meta
+ let head' = if writerStandalone opts
+ then metaBlock $+$ header'
+ else empty
+ let headerBlocks = filter isHeaderBlock blocks
+ let toc = if writerTableOfContents opts
+ then tableOfContents opts headerBlocks
+ else empty
+ body <- blockListToMarkdown opts blocks
+ (notes, _) <- get
+ notes' <- notesToMarkdown opts (reverse notes)
+ (_, refs) <- get -- note that the notes may contain refs
+ refs' <- keyTableToMarkdown opts (reverse refs)
+ return $ head' $+$ before' $+$ toc $+$ body $+$ text "" $+$
+ notes' $+$ text "" $+$ refs' $+$ after'
+
+-- | Return markdown representation of reference key table.
+keyTableToMarkdown :: WriterOptions -> KeyTable -> State WriterState Doc
+keyTableToMarkdown opts refs = mapM (keyToMarkdown opts) refs >>= return . vcat
+
+-- | Return markdown representation of a reference key.
+keyToMarkdown :: WriterOptions
+ -> ([Inline], (String, String))
+ -> State WriterState Doc
+keyToMarkdown opts (label, (src, tit)) = do
+ label' <- inlineListToMarkdown opts label
+ let tit' = if null tit then empty else text $ " \"" ++ tit ++ "\""
+ return $ text " " <> char '[' <> label' <> char ']' <> text ": " <>
+ text src <> tit'
+
+-- | Return markdown representation of notes.
+notesToMarkdown :: WriterOptions -> [[Block]] -> State WriterState Doc
+notesToMarkdown opts notes =
+ mapM (\(num, note) -> noteToMarkdown opts num note) (zip [1..] notes) >>=
+ return . vcat
+
+-- | Return markdown representation of a note.
+noteToMarkdown :: WriterOptions -> Int -> [Block] -> State WriterState Doc
+noteToMarkdown opts num blocks = do
+ contents <- blockListToMarkdown opts blocks
+ let marker = text "[^" <> text (show num) <> text "]:"
+ return $ hang' marker (writerTabStop opts) contents
+
+-- | Escape special characters for Markdown.
+escapeString :: String -> String
+escapeString = escapeStringUsing markdownEscapes
+ where markdownEscapes = backslashEscapes "\\`*_>#~^"
+
+-- | Convert bibliographic information into Markdown header.
+metaToMarkdown :: WriterOptions -> Meta -> State WriterState Doc
+metaToMarkdown _ (Meta [] [] []) = return empty
+metaToMarkdown opts (Meta title authors date) = do
+ title' <- titleToMarkdown opts title
+ authors' <- authorsToMarkdown authors
+ date' <- dateToMarkdown date
+ return $ title' $+$ authors' $+$ date' $+$ text ""
+
+titleToMarkdown :: WriterOptions -> [Inline] -> State WriterState Doc
+titleToMarkdown _ [] = return empty
+titleToMarkdown opts lst = do
+ contents <- inlineListToMarkdown opts lst
+ return $ text "% " <> contents
+
+authorsToMarkdown :: [String] -> State WriterState Doc
+authorsToMarkdown [] = return empty
+authorsToMarkdown lst = return $
+ text "% " <> text (intercalate ", " (map escapeString lst))
+
+dateToMarkdown :: String -> State WriterState Doc
+dateToMarkdown [] = return empty
+dateToMarkdown str = return $ text "% " <> text (escapeString str)
+
+-- | Construct table of contents from list of header blocks.
+tableOfContents :: WriterOptions -> [Block] -> Doc
+tableOfContents opts headers =
+ let opts' = opts { writerIgnoreNotes = True }
+ contents = BulletList $ map elementToListItem $ hierarchicalize headers
+ in evalState (blockToMarkdown opts' contents) ([],[])
+
+-- | Converts an Element to a list item for a table of contents,
+elementToListItem :: Element -> [Block]
+elementToListItem (Blk _) = []
+elementToListItem (Sec _ _ headerText subsecs) = [Plain headerText] ++
+ if null subsecs
+ then []
+ else [BulletList $ map elementToListItem subsecs]
+
+-- | Ordered list start parser for use in Para below.
+olMarker :: GenParser Char st Char
+olMarker = do (start, style', delim) <- anyOrderedListMarker
+ if delim == Period &&
+ (style' == UpperAlpha || (style' == UpperRoman &&
+ start `elem` [1, 5, 10, 50, 100, 500, 1000]))
+ then spaceChar >> spaceChar
+ else spaceChar
+
+-- | True if string begins with an ordered list marker
+beginsWithOrderedListMarker :: String -> Bool
+beginsWithOrderedListMarker str =
+ case parse olMarker "para start" str of
+ Left _ -> False
+ Right _ -> True
+
+wrappedMarkdown :: WriterOptions -> [Inline] -> State WriterState Doc
+wrappedMarkdown opts inlines = do
+ let chunks = splitBy LineBreak inlines
+ let chunks' = if null chunks
+ then []
+ else (map (++ [Str " "]) $ init chunks) ++ [last chunks]
+ lns <- mapM (wrapIfNeeded opts (inlineListToMarkdown opts)) chunks'
+ return $ vcat lns
+
+-- | Convert Pandoc block element to markdown.
+blockToMarkdown :: WriterOptions -- ^ Options
+ -> Block -- ^ Block element
+ -> State WriterState Doc
+blockToMarkdown _ Null = return empty
+blockToMarkdown opts (Plain inlines) =
+ wrappedMarkdown opts inlines
+blockToMarkdown opts (Para inlines) = do
+ contents <- wrappedMarkdown opts inlines
+ -- escape if para starts with ordered list marker
+ let esc = if (not (writerStrictMarkdown opts)) &&
+ beginsWithOrderedListMarker (render contents)
+ then char '\\'
+ else empty
+ return $ esc <> contents <> text "\n"
+blockToMarkdown _ (RawHtml str) = return $ text str
+blockToMarkdown _ HorizontalRule = return $ text "\n* * * * *\n"
+blockToMarkdown opts (Header level inlines) = do
+ contents <- inlineListToMarkdown opts inlines
+ -- use setext style headers if in literate haskell mode.
+ -- ghc interprets '#' characters in column 1 as line number specifiers.
+ if writerLiterateHaskell opts
+ then let len = length $ render contents
+ in return $ contents <> text "\n" <>
+ case level of
+ 1 -> text $ replicate len '=' ++ "\n"
+ 2 -> text $ replicate len '-' ++ "\n"
+ _ -> empty
+ else return $ text ((replicate level '#') ++ " ") <> contents <> text "\n"
+blockToMarkdown opts (CodeBlock (_,classes,_) str) | "haskell" `elem` classes &&
+ writerLiterateHaskell opts =
+ return $ (vcat $ map (text "> " <>) $ map text (lines str)) <> text "\n"
+blockToMarkdown opts (CodeBlock _ str) = return $
+ (nest (writerTabStop opts) $ vcat $ map text (lines str)) <> text "\n"
+blockToMarkdown opts (BlockQuote blocks) = do
+ -- if we're writing literate haskell, put a space before the bird tracks
+ -- so they won't be interpreted as lhs...
+ let leader = if writerLiterateHaskell opts
+ then text . (" > " ++)
+ else text . ("> " ++)
+ contents <- blockListToMarkdown opts blocks
+ return $ (vcat $ map leader $ lines $ render contents) <>
+ text "\n"
+blockToMarkdown opts (Table caption aligns widths headers rows) = do
+ caption' <- inlineListToMarkdown opts caption
+ let caption'' = if null caption
+ then empty
+ else text "" $+$ (text "Table: " <> caption')
+ headers' <- mapM (blockListToMarkdown opts) headers
+ let widthsInChars = map (floor . (78 *)) widths
+ let alignHeader alignment = case alignment of
+ AlignLeft -> leftAlignBlock
+ AlignCenter -> centerAlignBlock
+ AlignRight -> rightAlignBlock
+ AlignDefault -> leftAlignBlock
+ let makeRow = hsepBlocks . (zipWith alignHeader aligns) .
+ (zipWith docToBlock widthsInChars)
+ let head' = makeRow headers'
+ rows' <- mapM (\row -> do cols <- mapM (blockListToMarkdown opts) row
+ return $ makeRow cols) rows
+ let maxRowHeight = maximum $ map heightOfBlock (head':rows')
+ let isMultilineTable = maxRowHeight > 1
+ let underline = hsep $
+ map (\width -> text $ replicate width '-') widthsInChars
+ let border = if isMultilineTable
+ then text $ replicate (sum widthsInChars + (length widthsInChars - 1)) '-'
+ else empty
+ let spacer = if isMultilineTable
+ then text ""
+ else empty
+ let body = vcat $ intersperse spacer $ map blockToDoc rows'
+ return $ (nest 2 $ border $+$ (blockToDoc head') $+$ underline $+$ body $+$
+ border $+$ caption'') <> text "\n"
+blockToMarkdown opts (BulletList items) = do
+ contents <- mapM (bulletListItemToMarkdown opts) items
+ return $ (vcat contents) <> text "\n"
+blockToMarkdown opts (OrderedList attribs items) = do
+ let markers = orderedListMarkers attribs
+ let markers' = map (\m -> if length m < 3
+ then m ++ replicate (3 - length m) ' '
+ else m) markers
+ contents <- mapM (\(item, num) -> orderedListItemToMarkdown opts item num) $
+ zip markers' items
+ return $ (vcat contents) <> text "\n"
+blockToMarkdown opts (DefinitionList items) = do
+ contents <- mapM (definitionListItemToMarkdown opts) items
+ return $ (vcat contents) <> text "\n"
+
+-- | Convert bullet list item (list of blocks) to markdown.
+bulletListItemToMarkdown :: WriterOptions -> [Block] -> State WriterState Doc
+bulletListItemToMarkdown opts items = do
+ contents <- blockListToMarkdown opts items
+ return $ hang' (text "- ") (writerTabStop opts) contents
+
+-- | Convert ordered list item (a list of blocks) to markdown.
+orderedListItemToMarkdown :: WriterOptions -- ^ options
+ -> String -- ^ list item marker
+ -> [Block] -- ^ list item (list of blocks)
+ -> State WriterState Doc
+orderedListItemToMarkdown opts marker items = do
+ contents <- blockListToMarkdown opts items
+ return $ hsep [nest (min (3 - length marker) 0) (text marker),
+ nest (writerTabStop opts) contents]
+
+-- | Convert definition list item (label, list of blocks) to markdown.
+definitionListItemToMarkdown :: WriterOptions
+ -> ([Inline],[Block])
+ -> State WriterState Doc
+definitionListItemToMarkdown opts (label, items) = do
+ labelText <- inlineListToMarkdown opts label
+ let tabStop = writerTabStop opts
+ let leader = char ':'
+ contents <- mapM (\item -> blockToMarkdown opts item >>=
+ (\txt -> return (leader $$ nest tabStop txt)))
+ items >>= return . vcat
+ return $ labelText $+$ contents
+
+-- | Convert list of Pandoc block elements to markdown.
+blockListToMarkdown :: WriterOptions -- ^ Options
+ -> [Block] -- ^ List of block elements
+ -> State WriterState Doc
+blockListToMarkdown opts blocks =
+ mapM (blockToMarkdown opts) blocks >>= return . vcat
+
+-- | Get reference for target; if none exists, create unique one and return.
+-- Prefer label if possible; otherwise, generate a unique key.
+getReference :: [Inline] -> Target -> State WriterState [Inline]
+getReference label (src, tit) = do
+ (_,refs) <- get
+ case find ((== (src, tit)) . snd) refs of
+ Just (ref, _) -> return ref
+ Nothing -> do
+ let label' = case find ((== label) . fst) refs of
+ Just _ -> -- label is used; generate numerical label
+ case find (\n -> not (any (== [Str (show n)])
+ (map fst refs))) [1..(10000 :: Integer)] of
+ Just x -> [Str (show x)]
+ Nothing -> error "no unique label"
+ Nothing -> label
+ modify (\(notes, refs') -> (notes, (label', (src,tit)):refs'))
+ return label'
+
+-- | Convert list of Pandoc inline elements to markdown.
+inlineListToMarkdown :: WriterOptions -> [Inline] -> State WriterState Doc
+inlineListToMarkdown opts lst =
+ mapM (inlineToMarkdown opts) lst >>= return . hcat
+
+-- | Convert Pandoc inline element to markdown.
+inlineToMarkdown :: WriterOptions -> Inline -> State WriterState Doc
+inlineToMarkdown opts (Emph lst) = do
+ contents <- inlineListToMarkdown opts lst
+ return $ char '*' <> contents <> char '*'
+inlineToMarkdown opts (Strong lst) = do
+ contents <- inlineListToMarkdown opts lst
+ return $ text "**" <> contents <> text "**"
+inlineToMarkdown opts (Strikeout lst) = do
+ contents <- inlineListToMarkdown opts lst
+ return $ text "~~" <> contents <> text "~~"
+inlineToMarkdown opts (Superscript lst) = do
+ contents <- inlineListToMarkdown opts lst
+ let contents' = text $ substitute " " "\\ " $ render contents
+ return $ char '^' <> contents' <> char '^'
+inlineToMarkdown opts (Subscript lst) = do
+ contents <- inlineListToMarkdown opts lst
+ let contents' = text $ substitute " " "\\ " $ render contents
+ return $ char '~' <> contents' <> char '~'
+inlineToMarkdown opts (SmallCaps lst) = inlineListToMarkdown opts lst
+inlineToMarkdown opts (Quoted SingleQuote lst) = do
+ contents <- inlineListToMarkdown opts lst
+ return $ char '\'' <> contents <> char '\''
+inlineToMarkdown opts (Quoted DoubleQuote lst) = do
+ contents <- inlineListToMarkdown opts lst
+ return $ char '"' <> contents <> char '"'
+inlineToMarkdown _ EmDash = return $ text "--"
+inlineToMarkdown _ EnDash = return $ char '-'
+inlineToMarkdown _ Apostrophe = return $ char '\''
+inlineToMarkdown _ Ellipses = return $ text "..."
+inlineToMarkdown _ (Code str) =
+ let tickGroups = filter (\s -> '`' `elem` s) $ group str
+ longest = if null tickGroups
+ then 0
+ else maximum $ map length tickGroups
+ marker = replicate (longest + 1) '`'
+ spacer = if (longest == 0) then "" else " " in
+ return $ text (marker ++ spacer ++ str ++ spacer ++ marker)
+inlineToMarkdown _ (Str str) = return $ text $ escapeString str
+inlineToMarkdown _ (Math InlineMath str) = return $ char '$' <> text str <> char '$'
+inlineToMarkdown _ (Math DisplayMath str) = return $ text "$$" <> text str <> text "$$"
+inlineToMarkdown _ (TeX str) = return $ text str
+inlineToMarkdown _ (HtmlInline str) = return $ text str
+inlineToMarkdown _ (LineBreak) = return $ text " \n"
+inlineToMarkdown _ Space = return $ char ' '
+inlineToMarkdown _ (Cite cits _ ) = do
+ let format (a,b) xs = text a <>
+ (if b /= [] then char '@' else empty) <>
+ text b <>
+ (if isEmpty xs then empty else text "; ") <>
+ xs
+ return $ char '[' <> foldr format empty cits <> char ']'
+inlineToMarkdown opts (Link txt (src, tit)) = do
+ linktext <- inlineListToMarkdown opts txt
+ let linktitle = if null tit then empty else text $ " \"" ++ tit ++ "\""
+ let srcSuffix = if isPrefixOf "mailto:" src then drop 7 src else src
+ let useRefLinks = writerReferenceLinks opts
+ let useAuto = null tit && txt == [Code srcSuffix]
+ ref <- if useRefLinks then getReference txt (src, tit) else return []
+ reftext <- inlineListToMarkdown opts ref
+ return $ if useAuto
+ then char '<' <> text srcSuffix <> char '>'
+ else if useRefLinks
+ then let first = char '[' <> linktext <> char ']'
+ second = if txt == ref
+ then text "[]"
+ else char '[' <> reftext <> char ']'
+ in first <> second
+ else char '[' <> linktext <> char ']' <>
+ char '(' <> text src <> linktitle <> char ')'
+inlineToMarkdown opts (Image alternate (source, tit)) = do
+ let txt = if (null alternate) || (alternate == [Str ""]) ||
+ (alternate == [Str source]) -- to prevent autolinks
+ then [Str "image"]
+ else alternate
+ linkPart <- inlineToMarkdown opts (Link txt (source, tit))
+ return $ char '!' <> linkPart
+inlineToMarkdown _ (Note contents) = do
+ modify (\(notes, refs) -> (contents:notes, refs)) -- add to notes in state
+ (notes, _) <- get
+ let ref = show $ (length notes)
+ return $ text "[^" <> text ref <> char ']'
diff --git a/src/Text/Pandoc/Writers/MediaWiki.hs b/src/Text/Pandoc/Writers/MediaWiki.hs
new file mode 100644
index 000000000..c5f6b3bf1
--- /dev/null
+++ b/src/Text/Pandoc/Writers/MediaWiki.hs
@@ -0,0 +1,396 @@
+{-
+Copyright (C) 2008 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.MediaWiki
+ Copyright : Copyright (C) 2006-7 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' documents to MediaWiki markup.
+
+MediaWiki: <http://www.mediawiki.org/wiki/MediaWiki>
+-}
+module Text.Pandoc.Writers.MediaWiki ( writeMediaWiki ) where
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Text.Pandoc.XML ( escapeStringForXML )
+import Data.List ( intersect )
+import Network.URI ( isURI )
+import Control.Monad.State
+
+data WriterState = WriterState {
+ stNotes :: Bool -- True if there are notes
+ , stListLevel :: [Char] -- String at beginning of list items, e.g. "**"
+ , stUseTags :: Bool -- True if we should use HTML tags because we're in a complex list
+ }
+
+-- | Convert Pandoc to MediaWiki.
+writeMediaWiki :: WriterOptions -> Pandoc -> String
+writeMediaWiki opts document =
+ evalState (pandocToMediaWiki opts document)
+ (WriterState { stNotes = False, stListLevel = [], stUseTags = False })
+
+-- | Return MediaWiki representation of document.
+pandocToMediaWiki :: WriterOptions -> Pandoc -> State WriterState String
+pandocToMediaWiki opts (Pandoc _ blocks) = do
+ let before = writerIncludeBefore opts
+ let after = writerIncludeAfter opts
+ let head' = if writerStandalone opts
+ then writerHeader opts
+ else ""
+ let toc = if writerTableOfContents opts
+ then "__TOC__\n"
+ else ""
+ body <- blockListToMediaWiki opts blocks
+ notesExist <- get >>= return . stNotes
+ let notes = if notesExist
+ then "\n== Notes ==\n<references />"
+ else ""
+ return $ head' ++ before ++ toc ++ body ++ after ++ notes
+
+-- | Escape special characters for MediaWiki.
+escapeString :: String -> String
+escapeString = escapeStringForXML
+
+-- | Convert Pandoc block element to MediaWiki.
+blockToMediaWiki :: WriterOptions -- ^ Options
+ -> Block -- ^ Block element
+ -> State WriterState String
+
+blockToMediaWiki _ Null = return ""
+
+blockToMediaWiki opts (Plain inlines) =
+ inlineListToMediaWiki opts inlines
+
+blockToMediaWiki opts (Para inlines) = do
+ useTags <- get >>= return . stUseTags
+ listLevel <- get >>= return . stListLevel
+ contents <- inlineListToMediaWiki opts inlines
+ return $ if useTags
+ then "<p>" ++ contents ++ "</p>"
+ else contents ++ if null listLevel then "\n" else ""
+
+blockToMediaWiki _ (RawHtml str) = return str
+
+blockToMediaWiki _ HorizontalRule = return "\n-----\n"
+
+blockToMediaWiki opts (Header level inlines) = do
+ contents <- inlineListToMediaWiki opts inlines
+ let eqs = replicate (level + 1) '='
+ return $ eqs ++ " " ++ contents ++ " " ++ eqs ++ "\n"
+
+blockToMediaWiki _ (CodeBlock (_,classes,_) str) = do
+ let at = classes `intersect` ["actionscript", "ada", "apache", "applescript", "asm", "asp",
+ "autoit", "bash", "blitzbasic", "bnf", "c", "c_mac", "caddcl", "cadlisp", "cfdg", "cfm",
+ "cpp", "cpp-qt", "csharp", "css", "d", "delphi", "diff", "div", "dos", "eiffel", "fortran",
+ "freebasic", "gml", "groovy", "html4strict", "idl", "ini", "inno", "io", "java", "java5",
+ "javascript", "latex", "lisp", "lua", "matlab", "mirc", "mpasm", "mysql", "nsis", "objc",
+ "ocaml", "ocaml-brief", "oobas", "oracle8", "pascal", "perl", "php", "php-brief", "plsql",
+ "python", "qbasic", "rails", "reg", "robots", "ruby", "sas", "scheme", "sdlbasic",
+ "smalltalk", "smarty", "sql", "tcl", "", "thinbasic", "tsql", "vb", "vbnet", "vhdl",
+ "visualfoxpro", "winbatch", "xml", "xpp", "z80"]
+ let (beg, end) = if null at
+ then ("<pre" ++ if null classes then ">" else " class=\"" ++ unwords classes ++ "\">", "</pre>")
+ else ("<source lang=\"" ++ head at ++ "\">", "</source>")
+ return $ beg ++ escapeString str ++ end
+
+blockToMediaWiki opts (BlockQuote blocks) = do
+ contents <- blockListToMediaWiki opts blocks
+ return $ "<blockquote>" ++ contents ++ "</blockquote>"
+
+blockToMediaWiki opts (Table caption aligns widths headers rows) = do
+ let alignStrings = map alignmentToString aligns
+ captionDoc <- if null caption
+ then return ""
+ else do
+ c <- inlineListToMediaWiki opts caption
+ return $ "<caption>" ++ c ++ "</caption>"
+ colHeads <- colHeadsToMediaWiki opts alignStrings widths headers
+ rows' <- mapM (tableRowToMediaWiki opts alignStrings) rows
+ return $ "<table>\n" ++ captionDoc ++ colHeads ++ vcat rows' ++ "\n</table>"
+
+blockToMediaWiki opts x@(BulletList items) = do
+ oldUseTags <- get >>= return . stUseTags
+ let useTags = oldUseTags || not (isSimpleList x)
+ if useTags
+ then do
+ modify $ \s -> s { stUseTags = True }
+ contents <- mapM (listItemToMediaWiki opts) items
+ modify $ \s -> s { stUseTags = oldUseTags }
+ return $ "<ul>\n" ++ vcat contents ++ "</ul>\n"
+ else do
+ modify $ \s -> s { stListLevel = stListLevel s ++ "*" }
+ contents <- mapM (listItemToMediaWiki opts) items
+ modify $ \s -> s { stListLevel = init (stListLevel s) }
+ return $ vcat contents
+
+blockToMediaWiki opts x@(OrderedList attribs items) = do
+ oldUseTags <- get >>= return . stUseTags
+ let useTags = oldUseTags || not (isSimpleList x)
+ if useTags
+ then do
+ modify $ \s -> s { stUseTags = True }
+ contents <- mapM (listItemToMediaWiki opts) items
+ modify $ \s -> s { stUseTags = oldUseTags }
+ return $ "<ol" ++ listAttribsToString attribs ++ ">\n" ++ vcat contents ++ "</ol>\n"
+ else do
+ modify $ \s -> s { stListLevel = stListLevel s ++ "#" }
+ contents <- mapM (listItemToMediaWiki opts) items
+ modify $ \s -> s { stListLevel = init (stListLevel s) }
+ return $ vcat contents
+
+blockToMediaWiki opts x@(DefinitionList items) = do
+ oldUseTags <- get >>= return . stUseTags
+ let useTags = oldUseTags || not (isSimpleList x)
+ if useTags
+ then do
+ modify $ \s -> s { stUseTags = True }
+ contents <- mapM (definitionListItemToMediaWiki opts) items
+ modify $ \s -> s { stUseTags = oldUseTags }
+ return $ "<dl>\n" ++ vcat contents ++ "</dl>\n"
+ else do
+ modify $ \s -> s { stListLevel = stListLevel s ++ ";" }
+ contents <- mapM (definitionListItemToMediaWiki opts) items
+ modify $ \s -> s { stListLevel = init (stListLevel s) }
+ return $ vcat contents
+
+-- Auxiliary functions for lists:
+
+-- | Convert ordered list attributes to HTML attribute string
+listAttribsToString :: ListAttributes -> String
+listAttribsToString (startnum, numstyle, _) =
+ let numstyle' = camelCaseToHyphenated $ show numstyle
+ in (if startnum /= 1
+ then " start=\"" ++ show startnum ++ "\""
+ else "") ++
+ (if numstyle /= DefaultStyle
+ then " style=\"list-style-type: " ++ numstyle' ++ ";\""
+ else "")
+
+-- | Convert bullet or ordered list item (list of blocks) to MediaWiki.
+listItemToMediaWiki :: WriterOptions -> [Block] -> State WriterState String
+listItemToMediaWiki opts items = do
+ contents <- blockListToMediaWiki opts items
+ useTags <- get >>= return . stUseTags
+ if useTags
+ then return $ "<li>" ++ contents ++ "</li>"
+ else do
+ marker <- get >>= return . stListLevel
+ return $ marker ++ " " ++ contents
+
+-- | Convert definition list item (label, list of blocks) to MediaWiki.
+definitionListItemToMediaWiki :: WriterOptions
+ -> ([Inline],[Block])
+ -> State WriterState String
+definitionListItemToMediaWiki opts (label, items) = do
+ labelText <- inlineListToMediaWiki opts label
+ contents <- blockListToMediaWiki opts items
+ useTags <- get >>= return . stUseTags
+ if useTags
+ then return $ "<dt>" ++ labelText ++ "</dt>\n<dd>" ++ contents ++ "</dd>"
+ else do
+ marker <- get >>= return . stListLevel
+ return $ marker ++ " " ++ labelText ++ "\n" ++ (init marker ++ ": ") ++ contents
+
+-- | True if the list can be handled by simple wiki markup, False if HTML tags will be needed.
+isSimpleList :: Block -> Bool
+isSimpleList x =
+ case x of
+ BulletList items -> all isSimpleListItem items
+ OrderedList (num, sty, _) items -> all isSimpleListItem items &&
+ num == 1 && sty `elem` [DefaultStyle, Decimal]
+ DefinitionList items -> all isSimpleListItem $ map snd items
+ _ -> False
+
+-- | True if list item can be handled with the simple wiki syntax. False if
+-- HTML tags will be needed.
+isSimpleListItem :: [Block] -> Bool
+isSimpleListItem [] = True
+isSimpleListItem [x] =
+ case x of
+ Plain _ -> True
+ Para _ -> True
+ BulletList _ -> isSimpleList x
+ OrderedList _ _ -> isSimpleList x
+ DefinitionList _ -> isSimpleList x
+ _ -> False
+isSimpleListItem [x, y] | isPlainOrPara x =
+ case y of
+ BulletList _ -> isSimpleList y
+ OrderedList _ _ -> isSimpleList y
+ DefinitionList _ -> isSimpleList y
+ _ -> False
+isSimpleListItem _ = False
+
+isPlainOrPara :: Block -> Bool
+isPlainOrPara (Plain _) = True
+isPlainOrPara (Para _) = True
+isPlainOrPara _ = False
+
+tr :: String -> String
+tr x = "<tr>\n" ++ x ++ "\n</tr>"
+
+-- | Concatenates strings with line breaks between them.
+vcat :: [String] -> String
+vcat [] = ""
+vcat [x] = x
+vcat (x:xs) = x ++ "\n" ++ vcat xs
+
+-- Auxiliary functions for tables:
+
+colHeadsToMediaWiki :: WriterOptions
+ -> [[Char]]
+ -> [Double]
+ -> [[Block]]
+ -> State WriterState String
+colHeadsToMediaWiki opts alignStrings widths headers = do
+ heads <- sequence $ zipWith3
+ (\alignment columnwidth item -> tableItemToMediaWiki opts "th" alignment columnwidth item)
+ alignStrings widths headers
+ return $ tr $ vcat heads
+
+alignmentToString :: Alignment -> [Char]
+alignmentToString alignment = case alignment of
+ AlignLeft -> "left"
+ AlignRight -> "right"
+ AlignCenter -> "center"
+ AlignDefault -> "left"
+
+tableRowToMediaWiki :: WriterOptions
+ -> [[Char]]
+ -> [[Block]]
+ -> State WriterState String
+tableRowToMediaWiki opts aligns columns =
+ (sequence $ zipWith3 (tableItemToMediaWiki opts "td") aligns (repeat 0) columns) >>=
+ return . tr . vcat
+
+tableItemToMediaWiki :: WriterOptions
+ -> [Char]
+ -> [Char]
+ -> Double
+ -> [Block]
+ -> State WriterState String
+tableItemToMediaWiki opts tag' align' width' item = do
+ contents <- blockListToMediaWiki opts item
+ let attrib = " align=\"" ++ align' ++ "\"" ++
+ if width' /= 0
+ then " style=\"width: " ++ (show (truncate (100 * width') :: Integer)) ++ "%;\""
+ else ""
+ return $ "<" ++ tag' ++ attrib ++ ">" ++ contents ++ "</" ++ tag' ++ ">"
+
+-- | Convert list of Pandoc block elements to MediaWiki.
+blockListToMediaWiki :: WriterOptions -- ^ Options
+ -> [Block] -- ^ List of block elements
+ -> State WriterState String
+blockListToMediaWiki opts blocks =
+ mapM (blockToMediaWiki opts) blocks >>= return . vcat
+
+-- | Convert list of Pandoc inline elements to MediaWiki.
+inlineListToMediaWiki :: WriterOptions -> [Inline] -> State WriterState String
+inlineListToMediaWiki opts lst =
+ mapM (inlineToMediaWiki opts) lst >>= return . concat
+
+-- | Convert Pandoc inline element to MediaWiki.
+inlineToMediaWiki :: WriterOptions -> Inline -> State WriterState String
+
+inlineToMediaWiki opts (Emph lst) = do
+ contents <- inlineListToMediaWiki opts lst
+ return $ "''" ++ contents ++ "''"
+
+inlineToMediaWiki opts (Strong lst) = do
+ contents <- inlineListToMediaWiki opts lst
+ return $ "'''" ++ contents ++ "'''"
+
+inlineToMediaWiki opts (Strikeout lst) = do
+ contents <- inlineListToMediaWiki opts lst
+ return $ "<s>" ++ contents ++ "</s>"
+
+inlineToMediaWiki opts (Superscript lst) = do
+ contents <- inlineListToMediaWiki opts lst
+ return $ "<sup>" ++ contents ++ "</sup>"
+
+inlineToMediaWiki opts (Subscript lst) = do
+ contents <- inlineListToMediaWiki opts lst
+ return $ "<sub>" ++ contents ++ "</sub>"
+
+inlineToMediaWiki opts (SmallCaps lst) = inlineListToMediaWiki opts lst
+
+inlineToMediaWiki opts (Quoted SingleQuote lst) = do
+ contents <- inlineListToMediaWiki opts lst
+ return $ "&lsquo;" ++ contents ++ "&rsquo;"
+
+inlineToMediaWiki opts (Quoted DoubleQuote lst) = do
+ contents <- inlineListToMediaWiki opts lst
+ return $ "&ldquo;" ++ contents ++ "&rdquo;"
+
+inlineToMediaWiki opts (Cite _ lst) = inlineListToMediaWiki opts lst
+
+inlineToMediaWiki _ EmDash = return "&mdash;"
+
+inlineToMediaWiki _ EnDash = return "&ndash;"
+
+inlineToMediaWiki _ Apostrophe = return "&rsquo;"
+
+inlineToMediaWiki _ Ellipses = return "&hellip;"
+
+inlineToMediaWiki _ (Code str) =
+ return $ "<tt>" ++ (escapeString str) ++ "</tt>"
+
+inlineToMediaWiki _ (Str str) = return $ escapeString str
+
+inlineToMediaWiki _ (Math _ str) = return $ "<math>" ++ str ++ "</math>"
+ -- note: str should NOT be escaped
+
+inlineToMediaWiki _ (TeX _) = return ""
+
+inlineToMediaWiki _ (HtmlInline str) = return str
+
+inlineToMediaWiki _ (LineBreak) = return "<br />\n"
+
+inlineToMediaWiki _ Space = return " "
+
+inlineToMediaWiki opts (Link txt (src, _)) = do
+ link <- inlineListToMediaWiki opts txt
+ let useAuto = txt == [Code src]
+ let src' = if isURI src
+ then src
+ else if take 1 src == "/"
+ then "http://{{SERVERNAME}}" ++ src
+ else "http://{{SERVERNAME}}/" ++ src
+ return $ if useAuto
+ then src'
+ else "[" ++ src' ++ " " ++ link ++ "]"
+
+inlineToMediaWiki opts (Image alt (source, tit)) = do
+ alt' <- inlineListToMediaWiki opts alt
+ let txt = if (null tit)
+ then if null alt
+ then ""
+ else "|" ++ alt'
+ else "|" ++ tit
+ return $ "[[Image:" ++ source ++ txt ++ "]]"
+
+inlineToMediaWiki opts (Note contents) = do
+ contents' <- blockListToMediaWiki opts contents
+ modify (\s -> s { stNotes = True })
+ return $ "<ref>" ++ contents' ++ "</ref>"
+ -- note - may not work for notes with multiple blocks
diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs
new file mode 100644
index 000000000..52438f81e
--- /dev/null
+++ b/src/Text/Pandoc/Writers/OpenDocument.hs
@@ -0,0 +1,568 @@
+{-# LANGUAGE PatternGuards #-}
+{-
+Copyright (C) 2008 Andrea Rossato <andrea.rossato@ing.unitn.it>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.OpenDocument
+ Copyright : Copyright (C) 2008 Andrea Rossato
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Andrea Rossato <andrea.rossato@ing.unitn.it>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' documents to OpenDocument XML.
+-}
+module Text.Pandoc.Writers.OpenDocument ( writeOpenDocument ) where
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Text.Pandoc.XML
+import Text.Pandoc.Readers.TeXMath
+import Text.PrettyPrint.HughesPJ hiding ( Str )
+import Text.Printf ( printf )
+import Control.Applicative ( (<$>) )
+import Control.Arrow ( (***), (>>>) )
+import Control.Monad.State hiding ( when )
+import Data.Char (chr)
+import Data.List (intercalate)
+
+-- | Auxiliary function to convert Plain block to Para.
+plainToPara :: Block -> Block
+plainToPara (Plain x) = Para x
+plainToPara x = x
+
+--
+-- OpenDocument writer
+--
+
+data WriterState =
+ WriterState { stNotes :: [Doc]
+ , stTableStyles :: [Doc]
+ , stParaStyles :: [Doc]
+ , stListStyles :: [(Int, [Doc])]
+ , stTextStyles :: [Doc]
+ , stTextStyleAttr :: [(TextStyle,[(String,String)])]
+ , stIndentPara :: Int
+ , stInDefinition :: Bool
+ , stTight :: Bool
+ }
+
+defaultWriterState :: WriterState
+defaultWriterState =
+ WriterState { stNotes = []
+ , stTableStyles = []
+ , stParaStyles = []
+ , stListStyles = []
+ , stTextStyles = []
+ , stTextStyleAttr = []
+ , stIndentPara = 0
+ , stInDefinition = False
+ , stTight = False
+ }
+
+when :: Bool -> Doc -> Doc
+when p a = if p then a else empty
+
+addTableStyle :: Doc -> State WriterState ()
+addTableStyle i = modify $ \s -> s { stTableStyles = i : stTableStyles s }
+
+addNote :: Doc -> State WriterState ()
+addNote i = modify $ \s -> s { stNotes = i : stNotes s }
+
+addParaStyle :: Doc -> State WriterState ()
+addParaStyle i = modify $ \s -> s { stParaStyles = i : stParaStyles s }
+
+addTextStyle :: Doc -> State WriterState ()
+addTextStyle i = modify $ \s -> s { stTextStyles = i : stTextStyles s }
+
+addTextStyleAttr :: (TextStyle, [(String,String)]) -> State WriterState ()
+addTextStyleAttr i = modify $ \s -> s { stTextStyleAttr = i : stTextStyleAttr s }
+
+rmTextStyleAttr :: State WriterState ()
+rmTextStyleAttr = modify $ \s -> s { stTextStyleAttr = rmHead (stTextStyleAttr s) }
+ where rmHead l = if l /= [] then tail l else []
+
+increaseIndent :: State WriterState ()
+increaseIndent = modify $ \s -> s { stIndentPara = 1 + stIndentPara s }
+
+resetIndent :: State WriterState ()
+resetIndent = modify $ \s -> s { stIndentPara = (stIndentPara s) - 1 }
+
+inTightList :: State WriterState a -> State WriterState a
+inTightList f = modify (\s -> s { stTight = True }) >> f >>= \r ->
+ modify (\s -> s { stTight = False }) >> return r
+
+setInDefinitionList :: Bool -> State WriterState ()
+setInDefinitionList b = modify $ \s -> s { stInDefinition = b }
+
+inParagraphTags :: Doc -> Doc
+inParagraphTags = inTags False "text:p" [("text:style-name", "Text_20_body")]
+
+inParagraphTagsWithStyle :: String -> Doc -> Doc
+inParagraphTagsWithStyle sty = inTags False "text:p" [("text:style-name", sty)]
+
+inSpanTags :: String -> Doc -> Doc
+inSpanTags s = inTags False "text:span" [("text:style-name",s)]
+
+withTextStyle :: TextStyle -> State WriterState a -> State WriterState a
+withTextStyle s f = addTextStyleAttr (s,textStyleAttr s) >>
+ f >>= \r -> rmTextStyleAttr >> return r
+
+inTextStyle :: Doc -> State WriterState Doc
+inTextStyle d = do
+ at <- gets stTextStyleAttr
+ if at == []
+ then return d
+ else do
+ tn <- (+) 1 . length <$> gets stTextStyles
+ addTextStyle $ inTags False "style:style" [("style:name" , "T" ++ show tn)
+ ,("style:family", "text" )]
+ $ selfClosingTag "style:text-properties" (concatMap snd at)
+ return $ inTags False "text:span" [("text:style-name","T" ++ show tn)] d
+
+inHeaderTags :: Int -> Doc -> Doc
+inHeaderTags i = inTags False "text:h" [ ("text:style-name", "Heading_20_" ++ show i)
+ , ("text:outline-level", show i)]
+
+inQuotes :: QuoteType -> Doc -> Doc
+inQuotes SingleQuote s = text "&#8216;" <> s <> text "&#8217;"
+inQuotes DoubleQuote s = text "&#8220;" <> s <> text "&#8221;"
+
+handleSpaces :: String -> Doc
+handleSpaces s
+ | ( ' ':_) <- s = genTag s
+ | ('\t':x) <- s = selfClosingTag "text:tab" [] <> rm x
+ | otherwise = rm s
+ where
+ genTag = span (==' ') >>> tag . length *** rm >>> uncurry (<>)
+ tag n = when (n /= 0) $ selfClosingTag "text:s" [("text:c", show n)]
+ rm ( ' ':xs) = char ' ' <> genTag xs
+ rm ('\t':xs) = selfClosingTag "text:tab" [] <> genTag xs
+ rm ( x:xs) = char x <> rm xs
+ rm [] = empty
+
+-- | Convert list of authors to a docbook <author> section
+authorToOpenDocument :: [Char] -> Doc
+authorToOpenDocument name =
+ if ',' `elem` name
+ then -- last name first
+ let (lastname, rest) = break (==',') name
+ firstname = removeLeadingSpace rest
+ in inParagraphTagsWithStyle "Author" $
+ (text $ escapeStringForXML firstname) <+>
+ (text $ escapeStringForXML lastname)
+ else -- last name last
+ let namewords = words name
+ lengthname = length namewords
+ (firstname, lastname) = case lengthname of
+ 0 -> ("","")
+ 1 -> ("", name)
+ n -> (intercalate " " (take (n-1) namewords), last namewords)
+ in inParagraphTagsWithStyle "Author" $
+ (text $ escapeStringForXML firstname) <+>
+ (text $ escapeStringForXML lastname)
+
+-- | Convert Pandoc document to string in OpenDocument format.
+writeOpenDocument :: WriterOptions -> Pandoc -> String
+writeOpenDocument opts (Pandoc (Meta title authors date) blocks) =
+ let root = inTags True "office:document-content" openDocumentNameSpaces
+ header = when (writerStandalone opts) $ text (writerHeader opts)
+ title' = case runState (wrap opts title) defaultWriterState of
+ (t,_) -> if isEmpty t then empty else inHeaderTags 1 t
+ authors' = when (authors /= []) $ vcat (map authorToOpenDocument authors)
+ date' = when (date /= []) $
+ inParagraphTagsWithStyle "Date" (text $ escapeStringForXML date)
+ meta = when (writerStandalone opts) $ title' $$ authors' $$ date'
+ before = writerIncludeBefore opts
+ after = writerIncludeAfter opts
+ (doc, s) = runState (blocksToOpenDocument opts blocks) defaultWriterState
+ body = (if null before then empty else text before) $$
+ doc $$
+ (if null after then empty else text after)
+ body' = if writerStandalone opts
+ then inTagsIndented "office:body" $
+ inTagsIndented "office:text" (meta $$ body)
+ else body
+ styles = stTableStyles s ++ stParaStyles s ++ stTextStyles s
+ listStyle (n,l) = inTags True "text:list-style" [("style:name", "L" ++ show n)] (vcat l)
+ listStyles = map listStyle (stListStyles s)
+ in render $ header $$ root (generateStyles (styles ++ listStyles) $$ body' $$ text "")
+
+withParagraphStyle :: WriterOptions -> String -> [Block] -> State WriterState Doc
+withParagraphStyle o s (b:bs)
+ | Para l <- b = go =<< inParagraphTagsWithStyle s <$> inlinesToOpenDocument o l
+ | otherwise = go =<< blockToOpenDocument o b
+ where go i = ($$) i <$> withParagraphStyle o s bs
+withParagraphStyle _ _ [] = return empty
+
+inPreformattedTags :: String -> State WriterState Doc
+inPreformattedTags s = do
+ n <- paraStyle "Preformatted_20_Text" []
+ return . inParagraphTagsWithStyle ("P" ++ show n) . handleSpaces $ s
+
+orderedListToOpenDocument :: WriterOptions -> Int -> [[Block]] -> State WriterState Doc
+orderedListToOpenDocument o pn bs =
+ vcat . map (inTagsIndented "text:list-item") <$>
+ mapM (orderedItemToOpenDocument o pn . map plainToPara) bs
+
+orderedItemToOpenDocument :: WriterOptions -> Int -> [Block] -> State WriterState Doc
+orderedItemToOpenDocument o n (b:bs)
+ | OrderedList a l <- b = newLevel a l
+ | Para l <- b = go =<< inParagraphTagsWithStyle ("P" ++ show n) <$> inlinesToOpenDocument o l
+ | otherwise = go =<< blockToOpenDocument o b
+ where
+ go i = ($$) i <$> orderedItemToOpenDocument o n bs
+ newLevel a l = do
+ nn <- length <$> gets stParaStyles
+ ls <- head <$> gets stListStyles
+ modify $ \s -> s { stListStyles = orderedListLevelStyle a ls : tail (stListStyles s) }
+ inTagsIndented "text:list" <$> orderedListToOpenDocument o nn l
+orderedItemToOpenDocument _ _ [] = return empty
+
+isTightList :: [[Block]] -> Bool
+isTightList [] = False
+isTightList (b:_)
+ | Plain {} : _ <- b = True
+ | otherwise = False
+
+newOrderedListStyle :: Bool -> ListAttributes -> State WriterState (Int,Int)
+newOrderedListStyle b a = do
+ ln <- (+) 1 . length <$> gets stListStyles
+ let nbs = orderedListLevelStyle a (ln, [])
+ pn <- if b then inTightList (paraListStyle ln) else paraListStyle ln
+ modify $ \s -> s { stListStyles = nbs : stListStyles s }
+ return (ln,pn)
+
+bulletListToOpenDocument :: WriterOptions -> [[Block]] -> State WriterState Doc
+bulletListToOpenDocument o b = do
+ ln <- (+) 1 . length <$> gets stListStyles
+ (pn,ns) <- if isTightList b then inTightList (bulletListStyle ln) else bulletListStyle ln
+ modify $ \s -> s { stListStyles = ns : stListStyles s }
+ is <- listItemsToOpenDocument ("P" ++ show pn) o b
+ return $ inTags True "text:list" [("text:style-name", "L" ++ show ln)] is
+
+listItemsToOpenDocument :: String -> WriterOptions -> [[Block]] -> State WriterState Doc
+listItemsToOpenDocument s o is =
+ vcat . map (inTagsIndented "text:list-item") <$> mapM (withParagraphStyle o s . map plainToPara) is
+
+deflistItemToOpenDocument :: WriterOptions -> ([Inline],[Block]) -> State WriterState Doc
+deflistItemToOpenDocument o (t,d) = do
+ let ts = if isTightList [d]
+ then "Definition_20_Term_20_Tight" else "Definition_20_Term"
+ ds = if isTightList [d]
+ then "Definition_20_Definition_20_Tight" else "Definition_20_Definition"
+ t' <- withParagraphStyle o ts [Para t]
+ d' <- withParagraphStyle o ds (map plainToPara d)
+ return $ t' $$ d'
+
+inBlockQuote :: WriterOptions -> Int -> [Block] -> State WriterState Doc
+inBlockQuote o i (b:bs)
+ | BlockQuote l <- b = do increaseIndent
+ ni <- paraStyle "Quotations" []
+ go =<< inBlockQuote o ni (map plainToPara l)
+ | Para l <- b = do go =<< inParagraphTagsWithStyle ("P" ++ show i) <$> inlinesToOpenDocument o l
+ | otherwise = do go =<< blockToOpenDocument o b
+ where go block = ($$) block <$> inBlockQuote o i bs
+inBlockQuote _ _ [] = resetIndent >> return empty
+
+-- | Convert a list of Pandoc blocks to OpenDocument.
+blocksToOpenDocument :: WriterOptions -> [Block] -> State WriterState Doc
+blocksToOpenDocument o b = vcat <$> mapM (blockToOpenDocument o) b
+
+-- | Convert a Pandoc block element to OpenDocument.
+blockToOpenDocument :: WriterOptions -> Block -> State WriterState Doc
+blockToOpenDocument o bs
+ | Plain b <- bs = inParagraphTags <$> wrap o b
+ | Para b <- bs = inParagraphTags <$> wrap o b
+ | Header i b <- bs = inHeaderTags i <$> wrap o b
+ | BlockQuote b <- bs = mkBlockQuote b
+ | CodeBlock _ s <- bs = preformatted s
+ | RawHtml _ <- bs = return empty
+ | DefinitionList b <- bs = defList b
+ | BulletList b <- bs = bulletListToOpenDocument o b
+ | OrderedList a b <- bs = orderedList a b
+ | Table c a w h r <- bs = table c a w h r
+ | Null <- bs = return empty
+ | HorizontalRule <- bs = return $ selfClosingTag "text:p" [ ("text:style-name", "Horizontal_20_Line") ]
+ | otherwise = return empty
+ where
+ defList b = do setInDefinitionList True
+ r <- vcat <$> mapM (deflistItemToOpenDocument o) b
+ setInDefinitionList False
+ return r
+ preformatted s = vcat <$> mapM (inPreformattedTags . escapeStringForXML) (lines s)
+ mkBlockQuote b = do increaseIndent
+ i <- paraStyle "Quotations" []
+ inBlockQuote o i (map plainToPara b)
+ orderedList a b = do (ln,pn) <- newOrderedListStyle (isTightList b) a
+ inTags True "text:list" [ ("text:style-name", "L" ++ show ln)]
+ <$> orderedListToOpenDocument o pn b
+ table c a w h r = do
+ tn <- length <$> gets stTableStyles
+ pn <- length <$> gets stParaStyles
+ let genIds = map chr [65..]
+ name = "Table" ++ show (tn + 1)
+ columnIds = zip genIds w
+ mkColumn n = selfClosingTag "table:table-column" [("table:style-name", name ++ "." ++ [fst n])]
+ columns = map mkColumn columnIds
+ paraHStyles = paraTableStyles "Heading" pn a
+ paraStyles = paraTableStyles "Contents" (pn + length (newPara paraHStyles)) a
+ newPara = map snd . filter (not . isEmpty . snd)
+ addTableStyle $ tableStyle tn columnIds
+ mapM_ addParaStyle . newPara $ paraHStyles ++ paraStyles
+ captionDoc <- if null c
+ then return empty
+ else withParagraphStyle o "Caption" [Para c]
+ th <- colHeadsToOpenDocument o name (map fst paraHStyles) h
+ tr <- mapM (tableRowToOpenDocument o name (map fst paraStyles)) r
+ return $ inTags True "table:table" [ ("table:name" , name)
+ , ("table:style-name", name)
+ ] (vcat columns $$ th $$ vcat tr) $$ captionDoc
+
+colHeadsToOpenDocument :: WriterOptions -> String -> [String] -> [[Block]] -> State WriterState Doc
+colHeadsToOpenDocument o tn ns hs =
+ inTagsIndented "table:table-header-rows" . inTagsIndented "table:table-row" . vcat <$>
+ mapM (tableItemToOpenDocument o tn) (zip ns hs)
+
+tableRowToOpenDocument :: WriterOptions -> String -> [String] -> [[Block]] -> State WriterState Doc
+tableRowToOpenDocument o tn ns cs =
+ inTagsIndented "table:table-row" . vcat <$>
+ mapM (tableItemToOpenDocument o tn) (zip ns cs)
+
+tableItemToOpenDocument :: WriterOptions -> String -> (String,[Block])-> State WriterState Doc
+tableItemToOpenDocument o tn (n,i) =
+ let a = [ ("table:style-name" , tn ++ ".A1" )
+ , ("office:value-type", "string" )
+ ]
+ in inTags True "table:table-cell" a <$>
+ withParagraphStyle o n (map plainToPara i)
+
+-- | Take list of inline elements and return wrapped doc.
+wrap :: WriterOptions -> [Inline] -> State WriterState Doc
+wrap o l = if writerWrapText o
+ then fsep <$> mapM (inlinesToOpenDocument o) (splitBy Space l)
+ else inlinesToOpenDocument o l
+
+-- | Convert a list of inline elements to OpenDocument.
+inlinesToOpenDocument :: WriterOptions -> [Inline] -> State WriterState Doc
+inlinesToOpenDocument o l = hcat <$> mapM (inlineToOpenDocument o) l
+
+-- | Convert an inline element to OpenDocument.
+inlineToOpenDocument :: WriterOptions -> Inline -> State WriterState Doc
+inlineToOpenDocument o ils
+ | Ellipses <- ils = inTextStyle $ text "&#8230;"
+ | EmDash <- ils = inTextStyle $ text "&#8212;"
+ | EnDash <- ils = inTextStyle $ text "&#8211;"
+ | Apostrophe <- ils = inTextStyle $ text "&#8217;"
+ | Space <- ils = inTextStyle $ char ' '
+ | LineBreak <- ils = return $ selfClosingTag "text:line-break" []
+ | Str s <- ils = inTextStyle $ handleSpaces $ escapeStringForXML s
+ | Emph l <- ils = withTextStyle Italic $ inlinesToOpenDocument o l
+ | Strong l <- ils = withTextStyle Bold $ inlinesToOpenDocument o l
+ | Strikeout l <- ils = withTextStyle Strike $ inlinesToOpenDocument o l
+ | Superscript l <- ils = withTextStyle Sup $ inlinesToOpenDocument o l
+ | Subscript l <- ils = withTextStyle Sub $ inlinesToOpenDocument o l
+ | SmallCaps l <- ils = withTextStyle SmallC $ inlinesToOpenDocument o l
+ | Quoted t l <- ils = inQuotes t <$> inlinesToOpenDocument o l
+ | Code s <- ils = preformatted s
+ | Math _ s <- ils = inlinesToOpenDocument o (readTeXMath s)
+ | Cite _ l <- ils = inlinesToOpenDocument o l
+ | TeX s <- ils = preformatted s
+ | HtmlInline s <- ils = preformatted s
+ | Link l (s,t) <- ils = mkLink s t <$> inlinesToOpenDocument o l
+ | Image _ (s,_) <- ils = return $ mkImg s
+ | Note l <- ils = mkNote l
+ | otherwise = return empty
+ where
+ preformatted = return . inSpanTags "Teletype" . handleSpaces . escapeStringForXML
+ mkLink s t = inTags False "text:a" [ ("xlink:type" , "simple")
+ , ("xlink:href" , s )
+ , ("office:name", t )
+ ] . inSpanTags "Definition"
+ mkImg s = inTags False "draw:frame" [] $
+ selfClosingTag "draw:image" [ ("xlink:href" , s )
+ , ("xlink:type" , "simple")
+ , (" xlink:show" , "embed" )
+ , ("xlink:actuate", "onLoad")]
+ mkNote l = do
+ n <- length <$> gets stNotes
+ let footNote t = inTags False "text:note"
+ [ ("text:id" , "ftn" ++ show n)
+ , ("text:note-class", "footnote" )] $
+ inTagsSimple "text:note-citation" (text . show $ n + 1) $$
+ inTagsSimple "text:note-body" t
+ nn <- footNote <$> withParagraphStyle o "Footnote" l
+ addNote nn
+ return nn
+
+generateStyles :: [Doc] -> Doc
+generateStyles acc =
+ let scripts = selfClosingTag "office:scripts" []
+ fonts = inTagsIndented "office:font-face-decls"
+ (vcat $ map font ["Lucida Sans Unicode", "Tahoma", "Times New Roman"])
+ font fn = selfClosingTag "style:font-face"
+ [ ("style:name" , "&apos;" ++ fn ++ "&apos;")
+ , ("svg:font-family", fn )]
+ in scripts $$ fonts $$ inTagsIndented "office:automatic-styles" (vcat $ reverse acc)
+
+bulletListStyle :: Int -> State WriterState (Int,(Int,[Doc]))
+bulletListStyle l =
+ let doStyles i = inTags True "text:list-level-style-bullet"
+ [ ("text:level" , show (i + 1) )
+ , ("text:style-name" , "Bullet_20_Symbols")
+ , ("style:num-suffix", "." )
+ , ("text:bullet-char", [bulletList !! i] )
+ ] (listLevelStyle (1 + i))
+ bulletList = map chr $ cycle [8226,8227,8259]
+ listElStyle = map doStyles [0..9]
+ in do pn <- paraListStyle l
+ return (pn, (l, listElStyle))
+
+orderedListLevelStyle :: ListAttributes -> (Int, [Doc]) -> (Int,[Doc])
+orderedListLevelStyle (s,n, d) (l,ls) =
+ let suffix = case d of
+ OneParen -> [("style:num-suffix", ")")]
+ TwoParens -> [("style:num-prefix", "(")
+ ,("style:num-suffix", ")")]
+ _ -> [("style:num-suffix", ".")]
+ format = case n of
+ UpperAlpha -> "A"
+ LowerAlpha -> "a"
+ UpperRoman -> "I"
+ LowerRoman -> "i"
+ _ -> "1"
+ listStyle = inTags True "text:list-level-style-number"
+ ([ ("text:level" , show $ 1 + length ls )
+ , ("text:style-name" , "Numbering_20_Symbols")
+ , ("style:num-format", format )
+ , ("text:start-value", show s )
+ ] ++ suffix) (listLevelStyle (1 + length ls))
+ in (l, ls ++ [listStyle])
+
+listLevelStyle :: Int -> Doc
+listLevelStyle i =
+ let indent = show (0.25 * fromIntegral i :: Double) in
+ selfClosingTag "style:list-level-properties"
+ [ ("text:space-before" , indent ++ "in")
+ , ("text:min-label-width", "0.25in")]
+
+tableStyle :: Int -> [(Char,Double)] -> Doc
+tableStyle num wcs =
+ let tableId = "Table" ++ show (num + 1)
+ table = inTags True "style:style"
+ [("style:name", tableId)] $
+ selfClosingTag "style:table-properties"
+ [ ("style:rel-width", "100%" )
+ , ("table:align" , "center")]
+ colStyle (c,w) = inTags True "style:style"
+ [ ("style:name" , tableId ++ "." ++ [c])
+ , ("style:family", "table-column" )] $
+ selfClosingTag "style:table-column-properties"
+ [("style:column-width", printf "%.2f" (7 * w) ++ "in")]
+ cellStyle = inTags True "style:style"
+ [ ("style:name" , tableId ++ ".A1")
+ , ("style:family", "table-cell" )] $
+ selfClosingTag "style:table-cell-properties"
+ [ ("fo:border", "none")]
+ columnStyles = map colStyle wcs
+ in table $$ vcat columnStyles $$ cellStyle
+
+paraStyle :: String -> [(String,String)] -> State WriterState Int
+paraStyle parent attrs = do
+ pn <- (+) 1 . length <$> gets stParaStyles
+ i <- (*) 0.5 . fromIntegral <$> gets stIndentPara :: State WriterState Double
+ b <- gets stInDefinition
+ t <- gets stTight
+ let styleAttr = [ ("style:name" , "P" ++ show pn)
+ , ("style:family" , "paragraph" )
+ , ("style:parent-style-name", parent )]
+ indentVal = flip (++) "in" . show $ if b then (max 0.5 i) else i
+ tight = if t then [ ("fo:margin-top" , "0in" )
+ , ("fo:margin-bottom" , "0in" )]
+ else []
+ indent = when (i /= 0 || b || t) $
+ selfClosingTag "style:paragraph-properties" $
+ [ ("fo:margin-left" , indentVal)
+ , ("fo:margin-right" , "0in" )
+ , ("fo:text-indent" , "0in" )
+ , ("style:auto-text-indent" , "false" )]
+ ++ tight
+ addParaStyle $ inTags True "style:style" (styleAttr ++ attrs) indent
+ return pn
+
+paraListStyle :: Int -> State WriterState Int
+paraListStyle l = paraStyle "Text_20_body" [("style:list-style-name", "L" ++ show l )]
+
+paraTableStyles :: String -> Int -> [Alignment] -> [(String, Doc)]
+paraTableStyles _ _ [] = []
+paraTableStyles t s (a:xs)
+ | AlignRight <- a = ( pName s, res s "end" ) : paraTableStyles t (s + 1) xs
+ | AlignCenter <- a = ( pName s, res s "center") : paraTableStyles t (s + 1) xs
+ | otherwise = ("Table_20_" ++ t, empty ) : paraTableStyles t s xs
+ where pName sn = "P" ++ show (sn + 1)
+ res sn x = inTags True "style:style"
+ [ ("style:name" , pName sn )
+ , ("style:family" , "paragraph" )
+ , ("style:parent-style-name", "Table_20_" ++ t)] $
+ selfClosingTag "style:paragraph-properties"
+ [ ("fo:text-align", x)
+ , ("style:justify-single-word", "false")]
+
+data TextStyle = Italic | Bold | Strike | Sub | Sup | SmallC deriving ( Eq )
+
+textStyleAttr :: TextStyle -> [(String,String)]
+textStyleAttr s
+ | Italic <- s = [("fo:font-style" ,"italic" )
+ ,("style:font-style-asian" ,"italic" )
+ ,("style:font-style-complex" ,"italic" )]
+ | Bold <- s = [("fo:font-weight" ,"bold" )
+ ,("style:font-weight-asian" ,"bold" )
+ ,("style:font-weight-complex" ,"bold" )]
+ | Strike <- s = [("style:text-line-through-style", "solid" )]
+ | Sub <- s = [("style:text-position" ,"sub 58%" )]
+ | Sup <- s = [("style:text-position" ,"super 58%" )]
+ | SmallC <- s = [("fo:font-variant" ,"small-caps")]
+ | otherwise = []
+
+openDocumentNameSpaces :: [(String, String)]
+openDocumentNameSpaces =
+ [ ("xmlns:office" , "urn:oasis:names:tc:opendocument:xmlns:office:1.0" )
+ , ("xmlns:style" , "urn:oasis:names:tc:opendocument:xmlns:style:1.0" )
+ , ("xmlns:text" , "urn:oasis:names:tc:opendocument:xmlns:text:1.0" )
+ , ("xmlns:table" , "urn:oasis:names:tc:opendocument:xmlns:table:1.0" )
+ , ("xmlns:draw" , "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" )
+ , ("xmlns:fo" , "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0")
+ , ("xmlns:xlink" , "http://www.w3.org/1999/xlink" )
+ , ("xmlns:dc" , "http://purl.org/dc/elements/1.1/" )
+ , ("xmlns:meta" , "urn:oasis:names:tc:opendocument:xmlns:meta:1.0" )
+ , ("xmlns:number" , "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" )
+ , ("xmlns:svg" , "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" )
+ , ("xmlns:chart" , "urn:oasis:names:tc:opendocument:xmlns:chart:1.0" )
+ , ("xmlns:dr3d" , "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" )
+ , ("xmlns:math" , "http://www.w3.org/1998/Math/MathML" )
+ , ("xmlns:form" , "urn:oasis:names:tc:opendocument:xmlns:form:1.0" )
+ , ("xmlns:script" , "urn:oasis:names:tc:opendocument:xmlns:script:1.0" )
+ , ("xmlns:ooo" , "http://openoffice.org/2004/office" )
+ , ("xmlns:ooow" , "http://openoffice.org/2004/writer" )
+ , ("xmlns:oooc" , "http://openoffice.org/2004/calc" )
+ , ("xmlns:dom" , "http://www.w3.org/2001/xml-events" )
+ , ("xmlns:xforms" , "http://www.w3.org/2002/xforms" )
+ , ("xmlns:xsd" , "http://www.w3.org/2001/XMLSchema" )
+ , ("xmlns:xsi" , "http://www.w3.org/2001/XMLSchema-instance" )
+ , ("office:version", "1.0" )
+ ]
diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs
new file mode 100644
index 000000000..728c78712
--- /dev/null
+++ b/src/Text/Pandoc/Writers/RST.hs
@@ -0,0 +1,349 @@
+{-
+Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.RST
+ Copyright : Copyright (C) 2006-7 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' documents to reStructuredText.
+
+reStructuredText: <http://docutils.sourceforge.net/rst.html>
+-}
+module Text.Pandoc.Writers.RST ( writeRST) where
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Text.Pandoc.Blocks
+import Data.List ( isPrefixOf, isSuffixOf, drop, intersperse )
+import Text.PrettyPrint.HughesPJ hiding ( Str )
+import Control.Monad.State
+import Control.Applicative ( (<$>) )
+
+data WriterState =
+ WriterState { stNotes :: [[Block]]
+ , stLinks :: KeyTable
+ , stImages :: KeyTable
+ , stIncludes :: [String]
+ , stOptions :: WriterOptions
+ }
+
+-- | Convert Pandoc to RST.
+writeRST :: WriterOptions -> Pandoc -> String
+writeRST opts document =
+ let st = WriterState { stNotes = [], stLinks = [],
+ stImages = [], stIncludes = [],
+ stOptions = opts }
+ in render $ evalState (pandocToRST document) st
+
+-- | Return RST representation of document.
+pandocToRST :: Pandoc -> State WriterState Doc
+pandocToRST (Pandoc meta blocks) = do
+ opts <- get >>= (return . stOptions)
+ let before = writerIncludeBefore opts
+ after = writerIncludeAfter opts
+ header = writerHeader opts
+ before' = if null before then empty else text before
+ after' = if null after then empty else text after
+ header' = if null header then empty else text header
+ metaBlock <- metaToRST opts meta
+ let head' = if (writerStandalone opts)
+ then metaBlock $+$ header'
+ else empty
+ body <- blockListToRST blocks
+ includes <- get >>= (return . concat . stIncludes)
+ let includes' = if null includes then empty else text includes
+ notes <- get >>= (notesToRST . reverse . stNotes)
+ -- note that the notes may contain refs, so we do them first
+ refs <- get >>= (keyTableToRST . reverse . stLinks)
+ pics <- get >>= (pictTableToRST . reverse . stImages)
+ return $ head' $+$ before' $+$ includes' $+$ body $+$ notes $+$ text "" $+$
+ refs $+$ pics $+$ after'
+
+-- | Return RST representation of reference key table.
+keyTableToRST :: KeyTable -> State WriterState Doc
+keyTableToRST refs = mapM keyToRST refs >>= return . vcat
+
+-- | Return RST representation of a reference key.
+keyToRST :: ([Inline], (String, String))
+ -> State WriterState Doc
+keyToRST (label, (src, _)) = do
+ label' <- inlineListToRST label
+ let label'' = if ':' `elem` (render label')
+ then char '`' <> label' <> char '`'
+ else label'
+ return $ text ".. _" <> label'' <> text ": " <> text src
+
+-- | Return RST representation of notes.
+notesToRST :: [[Block]] -> State WriterState Doc
+notesToRST notes =
+ mapM (\(num, note) -> noteToRST num note) (zip [1..] notes) >>=
+ return . vcat
+
+-- | Return RST representation of a note.
+noteToRST :: Int -> [Block] -> State WriterState Doc
+noteToRST num note = do
+ contents <- blockListToRST note
+ let marker = text ".. [" <> text (show num) <> text "]"
+ return $ marker $$ nest 3 contents
+
+-- | Return RST representation of picture reference table.
+pictTableToRST :: KeyTable -> State WriterState Doc
+pictTableToRST refs = mapM pictToRST refs >>= return . vcat
+
+-- | Return RST representation of a picture substitution reference.
+pictToRST :: ([Inline], (String, String))
+ -> State WriterState Doc
+pictToRST (label, (src, _)) = do
+ label' <- inlineListToRST label
+ return $ text ".. " <> char '|' <> label' <> char '|' <> text " image:: " <>
+ text src
+
+-- | Take list of inline elements and return wrapped doc.
+wrappedRST :: WriterOptions -> [Inline] -> State WriterState Doc
+wrappedRST opts inlines = do
+ lineBreakDoc <- inlineToRST LineBreak
+ chunks <- mapM (wrapIfNeeded opts inlineListToRST)
+ (splitBy LineBreak inlines)
+ return $ vcat $ intersperse lineBreakDoc chunks
+
+-- | Escape special characters for RST.
+escapeString :: String -> String
+escapeString = escapeStringUsing (backslashEscapes "`\\|*_")
+
+-- | Convert bibliographic information into RST header.
+metaToRST :: WriterOptions -> Meta -> State WriterState Doc
+metaToRST _ (Meta [] [] []) = return empty
+metaToRST opts (Meta title authors date) = do
+ title' <- titleToRST title
+ authors' <- authorsToRST authors
+ date' <- dateToRST date
+ let toc = if writerTableOfContents opts
+ then text "" $+$ text ".. contents::"
+ else empty
+ return $ title' $+$ authors' $+$ date' $+$ toc $+$ text ""
+
+titleToRST :: [Inline] -> State WriterState Doc
+titleToRST [] = return empty
+titleToRST lst = do
+ contents <- inlineListToRST lst
+ let titleLength = length $ render contents
+ let border = text (replicate titleLength '=')
+ return $ border $+$ contents $+$ border <> text "\n"
+
+authorsToRST :: [String] -> State WriterState Doc
+authorsToRST [] = return empty
+authorsToRST (first:rest) = do
+ rest' <- authorsToRST rest
+ return $ (text ":Author: " <> text first) $+$ rest'
+
+dateToRST :: String -> State WriterState Doc
+dateToRST [] = return empty
+dateToRST str = return $ text ":Date: " <> text (escapeString str)
+
+-- | Convert Pandoc block element to RST.
+blockToRST :: Block -- ^ Block element
+ -> State WriterState Doc
+blockToRST Null = return empty
+blockToRST (Plain inlines) = do
+ opts <- get >>= (return . stOptions)
+ wrappedRST opts inlines
+blockToRST (Para inlines) = do
+ opts <- get >>= (return . stOptions)
+ contents <- wrappedRST opts inlines
+ return $ contents <> text "\n"
+blockToRST (RawHtml str) =
+ let str' = if "\n" `isSuffixOf` str then str ++ "\n" else str ++ "\n\n" in
+ return $ (text "\n.. raw:: html\n") $$ (nest 3 $ vcat $ map text (lines str'))
+blockToRST HorizontalRule = return $ text "--------------\n"
+blockToRST (Header level inlines) = do
+ contents <- inlineListToRST inlines
+ let headerLength = length $ render contents
+ let headerChar = if level > 5 then ' ' else "=-~^'" !! (level - 1)
+ let border = text $ replicate headerLength headerChar
+ return $ contents $+$ border <> text "\n"
+blockToRST (CodeBlock (_,classes,_) str) = do
+ opts <- stOptions <$> get
+ let tabstop = writerTabStop opts
+ if "haskell" `elem` classes && writerLiterateHaskell opts
+ then return $ (vcat $ map (text "> " <>) $ map text (lines str)) <> text "\n"
+ else return $ (text "::\n") $+$
+ (nest tabstop $ vcat $ map text (lines str)) <> text "\n"
+blockToRST (BlockQuote blocks) = do
+ tabstop <- get >>= (return . writerTabStop . stOptions)
+ contents <- blockListToRST blocks
+ return $ (nest tabstop contents) <> text "\n"
+blockToRST (Table caption _ widths headers rows) = do
+ caption' <- inlineListToRST caption
+ let caption'' = if null caption
+ then empty
+ else text "" $+$ (text "Table: " <> caption')
+ headers' <- mapM blockListToRST headers
+ let widthsInChars = map (floor . (78 *)) widths
+ let hpipeBlocks blocks = hcatBlocks [beg, middle, end]
+ where height = maximum (map heightOfBlock blocks)
+ sep' = TextBlock 3 height (replicate height " | ")
+ beg = TextBlock 2 height (replicate height "| ")
+ end = TextBlock 2 height (replicate height " |")
+ middle = hcatBlocks $ intersperse sep' blocks
+ let makeRow = hpipeBlocks . zipWith docToBlock widthsInChars
+ let head' = makeRow headers'
+ rows' <- mapM (\row -> do cols <- mapM blockListToRST row
+ return $ makeRow cols) rows
+ let border ch = char '+' <> char ch <>
+ (hcat $ intersperse (char ch <> char '+' <> char ch) $
+ map (\l -> text $ replicate l ch) widthsInChars) <>
+ char ch <> char '+'
+ let body = vcat $ intersperse (border '-') $ map blockToDoc rows'
+ return $ border '-' $+$ blockToDoc head' $+$ border '=' $+$ body $+$
+ border '-' $$ caption'' $$ text ""
+blockToRST (BulletList items) = do
+ contents <- mapM bulletListItemToRST items
+ -- ensure that sublists have preceding blank line
+ return $ text "" $+$ vcat contents <> text "\n"
+blockToRST (OrderedList (start, style', delim) items) = do
+ let markers = if start == 1 && style' == DefaultStyle && delim == DefaultDelim
+ then take (length items) $ repeat "#."
+ else take (length items) $ orderedListMarkers
+ (start, style', delim)
+ let maxMarkerLength = maximum $ map length markers
+ let markers' = map (\m -> let s = maxMarkerLength - length m
+ in m ++ replicate s ' ') markers
+ contents <- mapM (\(item, num) -> orderedListItemToRST item num) $
+ zip markers' items
+ -- ensure that sublists have preceding blank line
+ return $ text "" $+$ vcat contents <> text "\n"
+blockToRST (DefinitionList items) = do
+ contents <- mapM definitionListItemToRST items
+ return $ (vcat contents) <> text "\n"
+
+-- | Convert bullet list item (list of blocks) to RST.
+bulletListItemToRST :: [Block] -> State WriterState Doc
+bulletListItemToRST items = do
+ contents <- blockListToRST items
+ return $ (text "- ") <> contents
+
+-- | Convert ordered list item (a list of blocks) to RST.
+orderedListItemToRST :: String -- ^ marker for list item
+ -> [Block] -- ^ list item (list of blocks)
+ -> State WriterState Doc
+orderedListItemToRST marker items = do
+ contents <- blockListToRST items
+ return $ (text marker <> char ' ') <> contents
+
+-- | Convert defintion list item (label, list of blocks) to RST.
+definitionListItemToRST :: ([Inline], [Block]) -> State WriterState Doc
+definitionListItemToRST (label, items) = do
+ label' <- inlineListToRST label
+ contents <- blockListToRST items
+ tabstop <- get >>= (return . writerTabStop . stOptions)
+ return $ label' $+$ nest tabstop contents
+
+-- | Convert list of Pandoc block elements to RST.
+blockListToRST :: [Block] -- ^ List of block elements
+ -> State WriterState Doc
+blockListToRST blocks = mapM blockToRST blocks >>= return . vcat
+
+-- | Convert list of Pandoc inline elements to RST.
+inlineListToRST :: [Inline] -> State WriterState Doc
+inlineListToRST lst = mapM inlineToRST lst >>= return . hcat
+
+-- | Convert Pandoc inline element to RST.
+inlineToRST :: Inline -> State WriterState Doc
+inlineToRST (Emph lst) = do
+ contents <- inlineListToRST lst
+ return $ char '*' <> contents <> char '*'
+inlineToRST (Strong lst) = do
+ contents <- inlineListToRST lst
+ return $ text "**" <> contents <> text "**"
+inlineToRST (Strikeout lst) = do
+ contents <- inlineListToRST lst
+ return $ text "[STRIKEOUT:" <> contents <> char ']'
+inlineToRST (Superscript lst) = do
+ contents <- inlineListToRST lst
+ return $ text "\\ :sup:`" <> contents <> text "`\\ "
+inlineToRST (Subscript lst) = do
+ contents <- inlineListToRST lst
+ return $ text "\\ :sub:`" <> contents <> text "`\\ "
+inlineToRST (SmallCaps lst) = inlineListToRST lst
+inlineToRST (Quoted SingleQuote lst) = do
+ contents <- inlineListToRST lst
+ return $ char '\'' <> contents <> char '\''
+inlineToRST (Quoted DoubleQuote lst) = do
+ contents <- inlineListToRST lst
+ return $ char '"' <> contents <> char '"'
+inlineToRST (Cite _ lst) =
+ inlineListToRST lst
+inlineToRST EmDash = return $ text "--"
+inlineToRST EnDash = return $ char '-'
+inlineToRST Apostrophe = return $ char '\''
+inlineToRST Ellipses = return $ text "..."
+inlineToRST (Code str) = return $ text $ "``" ++ str ++ "``"
+inlineToRST (Str str) = return $ text $ escapeString str
+inlineToRST (Math t str) = do
+ includes <- get >>= (return . stIncludes)
+ let rawMathRole = ".. role:: math(raw)\n" ++
+ " :format: html latex\n"
+ if not (rawMathRole `elem` includes)
+ then modify $ \st -> st { stIncludes = rawMathRole : includes }
+ else return ()
+ return $ if t == InlineMath
+ then text $ ":math:`$" ++ str ++ "$`"
+ else text $ ":math:`$$" ++ str ++ "$$`"
+inlineToRST (TeX _) = return empty
+inlineToRST (HtmlInline _) = return empty
+inlineToRST (LineBreak) = do
+ return $ empty -- there's no line break in RST
+inlineToRST Space = return $ char ' '
+inlineToRST (Link [Code str] (src, _)) | src == str ||
+ src == "mailto:" ++ str = do
+ let srcSuffix = if isPrefixOf "mailto:" src then drop 7 src else src
+ return $ text srcSuffix
+inlineToRST (Link txt (src, tit)) = do
+ useReferenceLinks <- get >>= (return . writerReferenceLinks . stOptions)
+ linktext <- inlineListToRST $ normalizeSpaces txt
+ if useReferenceLinks
+ then do refs <- get >>= (return . stLinks)
+ let refs' = if (txt, (src, tit)) `elem` refs
+ then refs
+ else (txt, (src, tit)):refs
+ modify $ \st -> st { stLinks = refs' }
+ return $ char '`' <> linktext <> text "`_"
+ else return $ char '`' <> linktext <> text " <" <> text src <> text ">`_"
+inlineToRST (Image alternate (source, tit)) = do
+ pics <- get >>= (return . stImages)
+ let labelsUsed = map fst pics
+ let txt = if null alternate || alternate == [Str ""] ||
+ alternate `elem` labelsUsed
+ then [Str $ "image" ++ show (length pics)]
+ else alternate
+ let pics' = if (txt, (source, tit)) `elem` pics
+ then pics
+ else (txt, (source, tit)):pics
+ modify $ \st -> st { stImages = pics' }
+ label <- inlineListToRST txt
+ return $ char '|' <> label <> char '|'
+inlineToRST (Note contents) = do
+ -- add to notes in state
+ notes <- get >>= (return . stNotes)
+ modify $ \st -> st { stNotes = contents:notes }
+ let ref = show $ (length notes) + 1
+ return $ text " [" <> text ref <> text "]_"
diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs
new file mode 100644
index 000000000..62d8c4a0c
--- /dev/null
+++ b/src/Text/Pandoc/Writers/RTF.hs
@@ -0,0 +1,291 @@
+{-
+Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.RTF
+ Copyright : Copyright (C) 2006-7 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' documents to RTF (rich text format).
+-}
+module Text.Pandoc.Writers.RTF ( writeRTF ) where
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Text.Pandoc.Readers.TeXMath
+import Data.List ( isSuffixOf, intercalate )
+import Data.Char ( ord, isDigit )
+
+-- | Convert Pandoc to a string in rich text format.
+writeRTF :: WriterOptions -> Pandoc -> String
+writeRTF options (Pandoc meta blocks) =
+ let head' = if writerStandalone options
+ then rtfHeader (writerHeader options) meta
+ else ""
+ toc = if writerTableOfContents options
+ then tableOfContents $ filter isHeaderBlock blocks
+ else ""
+ foot = if writerStandalone options then "\n}\n" else ""
+ body = writerIncludeBefore options ++
+ concatMap (blockToRTF 0 AlignDefault) blocks ++
+ writerIncludeAfter options
+ in head' ++ toc ++ body ++ foot
+
+-- | Construct table of contents from list of header blocks.
+tableOfContents :: [Block] -> String
+tableOfContents headers =
+ let contentsTree = hierarchicalize headers
+ in concatMap (blockToRTF 0 AlignDefault) $
+ [Header 1 [Str "Contents"],
+ BulletList (map elementToListItem contentsTree)]
+
+elementToListItem :: Element -> [Block]
+elementToListItem (Blk _) = []
+elementToListItem (Sec _ _ sectext subsecs) = [Plain sectext] ++
+ if null subsecs
+ then []
+ else [BulletList (map elementToListItem subsecs)]
+
+-- | Convert unicode characters (> 127) into rich text format representation.
+handleUnicode :: String -> String
+handleUnicode [] = []
+handleUnicode (c:cs) =
+ if ord c > 127
+ then '\\':'u':(show (ord c)) ++ "?" ++ handleUnicode cs
+ else c:(handleUnicode cs)
+
+-- | Escape special characters.
+escapeSpecial :: String -> String
+escapeSpecial = escapeStringUsing (('\t',"\\tab "):(backslashEscapes "{\\}"))
+
+-- | Escape strings as needed for rich text format.
+stringToRTF :: String -> String
+stringToRTF = handleUnicode . escapeSpecial
+
+-- | Escape things as needed for code block in RTF.
+codeStringToRTF :: String -> String
+codeStringToRTF str = intercalate "\\line\n" $ lines (stringToRTF str)
+
+-- | Make a paragraph with first-line indent, block indent, and space after.
+rtfParSpaced :: Int -- ^ space after (in twips)
+ -> Int -- ^ block indent (in twips)
+ -> Int -- ^ first line indent (relative to block) (in twips)
+ -> Alignment -- ^ alignment
+ -> String -- ^ string with content
+ -> String
+rtfParSpaced spaceAfter indent firstLineIndent alignment content =
+ let alignString = case alignment of
+ AlignLeft -> "\\ql "
+ AlignRight -> "\\qr "
+ AlignCenter -> "\\qc "
+ AlignDefault -> "\\ql "
+ in "{\\pard " ++ alignString ++
+ "\\f0 \\sa" ++ (show spaceAfter) ++ " \\li" ++ (show indent) ++
+ " \\fi" ++ (show firstLineIndent) ++ " " ++ content ++ "\\par}\n"
+
+-- | Default paragraph.
+rtfPar :: Int -- ^ block indent (in twips)
+ -> Int -- ^ first line indent (relative to block) (in twips)
+ -> Alignment -- ^ alignment
+ -> String -- ^ string with content
+ -> String
+rtfPar = rtfParSpaced 180
+
+-- | Compact paragraph (e.g. for compact list items).
+rtfCompact :: Int -- ^ block indent (in twips)
+ -> Int -- ^ first line indent (relative to block) (in twips)
+ -> Alignment -- ^ alignment
+ -> String -- ^ string with content
+ -> String
+rtfCompact = rtfParSpaced 0
+
+-- number of twips to indent
+indentIncrement :: Int
+indentIncrement = 720
+
+listIncrement :: Int
+listIncrement = 360
+
+-- | Returns appropriate bullet list marker for indent level.
+bulletMarker :: Int -> String
+bulletMarker indent = case indent `mod` 720 of
+ 0 -> "\\bullet "
+ _ -> "\\endash "
+
+-- | Returns appropriate (list of) ordered list markers for indent level.
+orderedMarkers :: Int -> ListAttributes -> [String]
+orderedMarkers indent (start, style, delim) =
+ if style == DefaultStyle && delim == DefaultDelim
+ then case indent `mod` 720 of
+ 0 -> orderedListMarkers (start, Decimal, Period)
+ _ -> orderedListMarkers (start, LowerAlpha, Period)
+ else orderedListMarkers (start, style, delim)
+
+-- | Returns RTF header.
+rtfHeader :: String -- ^ header text
+ -> Meta -- ^ bibliographic information
+ -> String
+rtfHeader headerText (Meta title authors date) =
+ let titletext = if null title
+ then ""
+ else rtfPar 0 0 AlignCenter $
+ "\\b \\fs36 " ++ inlineListToRTF title
+ authorstext = if null authors
+ then ""
+ else rtfPar 0 0 AlignCenter (" " ++ (intercalate "\\" $
+ map stringToRTF authors))
+ datetext = if date == ""
+ then ""
+ else rtfPar 0 0 AlignCenter (" " ++ stringToRTF date) in
+ let spacer = if null (titletext ++ authorstext ++ datetext)
+ then ""
+ else rtfPar 0 0 AlignDefault "" in
+ headerText ++ titletext ++ authorstext ++ datetext ++ spacer
+
+-- | Convert Pandoc block element to RTF.
+blockToRTF :: Int -- ^ indent level
+ -> Alignment -- ^ alignment
+ -> Block -- ^ block to convert
+ -> String
+blockToRTF _ _ Null = ""
+blockToRTF indent alignment (Plain lst) =
+ rtfCompact indent 0 alignment $ inlineListToRTF lst
+blockToRTF indent alignment (Para lst) =
+ rtfPar indent 0 alignment $ inlineListToRTF lst
+blockToRTF indent alignment (BlockQuote lst) =
+ concatMap (blockToRTF (indent + indentIncrement) alignment) lst
+blockToRTF indent _ (CodeBlock _ str) =
+ rtfPar indent 0 AlignLeft ("\\f1 " ++ (codeStringToRTF str))
+blockToRTF _ _ (RawHtml _) = ""
+blockToRTF indent alignment (BulletList lst) = spaceAtEnd $
+ concatMap (listItemToRTF alignment indent (bulletMarker indent)) lst
+blockToRTF indent alignment (OrderedList attribs lst) = spaceAtEnd $ concat $
+ zipWith (listItemToRTF alignment indent) (orderedMarkers indent attribs) lst
+blockToRTF indent alignment (DefinitionList lst) = spaceAtEnd $
+ concatMap (definitionListItemToRTF alignment indent) lst
+blockToRTF indent _ HorizontalRule =
+ rtfPar indent 0 AlignCenter "\\emdash\\emdash\\emdash\\emdash\\emdash"
+blockToRTF indent alignment (Header level lst) = rtfPar indent 0 alignment $
+ "\\b \\fs" ++ (show (40 - (level * 4))) ++ " " ++ inlineListToRTF lst
+blockToRTF indent alignment (Table caption aligns sizes headers rows) =
+ tableRowToRTF True indent aligns sizes headers ++
+ concatMap (tableRowToRTF False indent aligns sizes) rows ++
+ rtfPar indent 0 alignment (inlineListToRTF caption)
+
+tableRowToRTF :: Bool -> Int -> [Alignment] -> [Double] -> [[Block]] -> String
+tableRowToRTF header indent aligns sizes cols =
+ let columns = concat $ zipWith (tableItemToRTF indent) aligns cols
+ totalTwips = 6 * 1440 -- 6 inches
+ rightEdges = tail $ scanl (\sofar new -> sofar + floor (new * totalTwips))
+ (0 :: Integer) sizes
+ cellDefs = map (\edge -> (if header
+ then "\\clbrdrb\\brdrs"
+ else "") ++ "\\cellx" ++ show edge)
+ rightEdges
+ start = "{\n\\trowd \\trgaph120\n" ++ concat cellDefs ++ "\n" ++
+ "\\trkeep\\intbl\n{\n"
+ end = "}\n\\intbl\\row}\n"
+ in start ++ columns ++ end
+
+tableItemToRTF :: Int -> Alignment -> [Block] -> String
+tableItemToRTF indent alignment item =
+ let contents = concatMap (blockToRTF indent alignment) item
+ in "{\\intbl " ++ contents ++ "\\cell}\n"
+
+-- | Ensure that there's the same amount of space after compact
+-- lists as after regular lists.
+spaceAtEnd :: String -> String
+spaceAtEnd str =
+ if isSuffixOf "\\par}\n" str
+ then (take ((length str) - 6) str) ++ "\\sa180\\par}\n"
+ else str
+
+-- | Convert list item (list of blocks) to RTF.
+listItemToRTF :: Alignment -- ^ alignment
+ -> Int -- ^ indent level
+ -> String -- ^ list start marker
+ -> [Block] -- ^ list item (list of blocks)
+ -> [Char]
+listItemToRTF alignment indent marker [] =
+ rtfCompact (indent + listIncrement) (0 - listIncrement) alignment
+ (marker ++ "\\tx" ++ (show listIncrement) ++ "\\tab ")
+listItemToRTF alignment indent marker list =
+ let (first:rest) = map (blockToRTF (indent + listIncrement) alignment) list
+ listMarker = "\\fi" ++ show (0 - listIncrement) ++ " " ++ marker ++ "\\tx" ++
+ show listIncrement ++ "\\tab"
+ insertListMarker ('\\':'f':'i':'-':d:xs) | isDigit d =
+ listMarker ++ dropWhile isDigit xs
+ insertListMarker ('\\':'f':'i':d:xs) | isDigit d =
+ listMarker ++ dropWhile isDigit xs
+ insertListMarker (x:xs) =
+ x : insertListMarker xs
+ insertListMarker [] = []
+ -- insert the list marker into the (processed) first block
+ in insertListMarker first ++ concat rest
+
+-- | Convert definition list item (label, list of blocks) to RTF.
+definitionListItemToRTF :: Alignment -- ^ alignment
+ -> Int -- ^ indent level
+ -> ([Inline],[Block]) -- ^ list item (list of blocks)
+ -> [Char]
+definitionListItemToRTF alignment indent (label, items) =
+ let labelText = blockToRTF indent alignment (Plain label)
+ itemsText = concatMap (blockToRTF (indent + listIncrement) alignment) items
+ in labelText ++ itemsText
+
+-- | Convert list of inline items to RTF.
+inlineListToRTF :: [Inline] -- ^ list of inlines to convert
+ -> String
+inlineListToRTF lst = concatMap inlineToRTF lst
+
+-- | Convert inline item to RTF.
+inlineToRTF :: Inline -- ^ inline to convert
+ -> String
+inlineToRTF (Emph lst) = "{\\i " ++ (inlineListToRTF lst) ++ "}"
+inlineToRTF (Strong lst) = "{\\b " ++ (inlineListToRTF lst) ++ "}"
+inlineToRTF (Strikeout lst) = "{\\strike " ++ (inlineListToRTF lst) ++ "}"
+inlineToRTF (Superscript lst) = "{\\super " ++ (inlineListToRTF lst) ++ "}"
+inlineToRTF (Subscript lst) = "{\\sub " ++ (inlineListToRTF lst) ++ "}"
+inlineToRTF (SmallCaps lst) = "{\\scaps " ++ (inlineListToRTF lst) ++ "}"
+inlineToRTF (Quoted SingleQuote lst) =
+ "\\u8216'" ++ (inlineListToRTF lst) ++ "\\u8217'"
+inlineToRTF (Quoted DoubleQuote lst) =
+ "\\u8220\"" ++ (inlineListToRTF lst) ++ "\\u8221\""
+inlineToRTF Apostrophe = "\\u8217'"
+inlineToRTF Ellipses = "\\u8230?"
+inlineToRTF EmDash = "\\u8212-"
+inlineToRTF EnDash = "\\u8211-"
+inlineToRTF (Code str) = "{\\f1 " ++ (codeStringToRTF str) ++ "}"
+inlineToRTF (Str str) = stringToRTF str
+inlineToRTF (Math _ str) = inlineListToRTF $ readTeXMath str
+inlineToRTF (Cite _ lst) = inlineListToRTF lst
+inlineToRTF (TeX _) = ""
+inlineToRTF (HtmlInline _) = ""
+inlineToRTF (LineBreak) = "\\line "
+inlineToRTF Space = " "
+inlineToRTF (Link text (src, _)) =
+ "{\\field{\\*\\fldinst{HYPERLINK \"" ++ (codeStringToRTF src) ++
+ "\"}}{\\fldrslt{\\ul\n" ++ (inlineListToRTF text) ++ "\n}}}\n"
+inlineToRTF (Image _ (source, _)) =
+ "{\\cf1 [image: " ++ source ++ "]\\cf0}"
+inlineToRTF (Note contents) =
+ "{\\super\\chftn}{\\*\\footnote\\chftn\\~\\plain\\pard " ++
+ (concatMap (blockToRTF 0 AlignDefault) contents) ++ "}"
diff --git a/src/Text/Pandoc/Writers/S5.hs b/src/Text/Pandoc/Writers/S5.hs
new file mode 100644
index 000000000..6f528503a
--- /dev/null
+++ b/src/Text/Pandoc/Writers/S5.hs
@@ -0,0 +1,157 @@
+{-# LANGUAGE CPP, TemplateHaskell #-}
+{-
+Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.S5
+ Copyright : Copyright (C) 2006-7 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Definitions for creation of S5 powerpoint-like HTML.
+(See <http://meyerweb.com/eric/tools/s5/>.)
+-}
+module Text.Pandoc.Writers.S5 (
+ -- * Strings
+ s5Meta,
+ s5Javascript,
+ s5CSS,
+ s5Links,
+ -- * Functions
+ writeS5,
+ writeS5String,
+ insertS5Structure
+ ) where
+import Text.Pandoc.Shared ( WriterOptions )
+import Text.Pandoc.TH ( contentsOf )
+import Text.Pandoc.Writers.HTML ( writeHtml, writeHtmlString )
+import Text.Pandoc.Definition
+import Text.XHtml.Strict
+import System.FilePath ( (</>) )
+import Data.List ( intercalate )
+
+s5Meta :: String
+s5Meta = "<!-- configuration parameters -->\n<meta name=\"defaultView\" content=\"slideshow\" />\n<meta name=\"controlVis\" content=\"hidden\" />\n"
+
+s5Javascript :: String
+#ifndef __HADDOCK__
+s5Javascript = "<script type=\"text/javascript\">\n" ++
+ $(contentsOf $ "data" </> "ui" </> "default" </> "slides.js.comment") ++
+ $(contentsOf $ "data" </> "ui" </> "default" </> "slides.js.packed") ++ "</script>\n"
+#endif
+
+s5CoreCSS :: String
+#ifndef __HADDOCK__
+s5CoreCSS = $(contentsOf $ "data" </> "ui" </> "default" </> "s5-core.css")
+#endif
+
+s5FramingCSS :: String
+#ifndef __HADDOCK__
+s5FramingCSS = $(contentsOf $ "data" </> "ui" </> "default" </> "framing.css")
+#endif
+
+s5PrettyCSS :: String
+#ifndef __HADDOCK__
+s5PrettyCSS = $(contentsOf $ "data" </> "ui" </> "default" </> "pretty.css")
+#endif
+
+s5OperaCSS :: String
+#ifndef __HADDOCK__
+s5OperaCSS = $(contentsOf $ "data" </> "ui" </> "default" </> "opera.css")
+#endif
+
+s5OutlineCSS :: String
+#ifndef __HADDOCK__
+s5OutlineCSS = $(contentsOf $ "data" </> "ui" </> "default" </> "outline.css")
+#endif
+
+s5PrintCSS :: String
+#ifndef __HADDOCK__
+s5PrintCSS = $(contentsOf $ "data" </> "ui" </> "default" </> "print.css")
+#endif
+
+s5CSS :: String
+s5CSS = "<style type=\"text/css\" media=\"projection\" id=\"slideProj\">\n" ++ s5CoreCSS ++ "\n" ++ s5FramingCSS ++ "\n" ++ s5PrettyCSS ++ "\n</style>\n<style type=\"text/css\" media=\"projection\" id=\"operaFix\">\n" ++ s5OperaCSS ++ "\n</style>\n<style type=\"text/css\" media=\"screen\" id=\"outlineStyle\">\n" ++ s5OutlineCSS ++ "\n</style>\n<style type=\"text/css\" media=\"print\" id=\"slidePrint\">\n" ++ s5PrintCSS ++ "\n</style>\n"
+
+s5Links :: String
+s5Links = "<!-- style sheet links -->\n<link rel=\"stylesheet\" href=\"ui/default/slides.css\" type=\"text/css\" media=\"projection\" id=\"slideProj\" />\n<link rel=\"stylesheet\" href=\"ui/default/outline.css\" type=\"text/css\" media=\"screen\" id=\"outlineStyle\" />\n<link rel=\"stylesheet\" href=\"ui/default/print.css\" type=\"text/css\" media=\"print\" id=\"slidePrint\" />\n<link rel=\"stylesheet\" href=\"ui/default/opera.css\" type=\"text/css\" media=\"projection\" id=\"operaFix\" />\n<!-- S5 JS -->\n<script src=\"ui/default/slides.js\" type=\"text/javascript\"></script>\n"
+
+-- | Converts Pandoc document to an S5 HTML presentation (Html structure).
+writeS5 :: WriterOptions -> Pandoc -> Html
+writeS5 options = (writeHtml options) . insertS5Structure
+
+-- | Converts Pandoc document to an S5 HTML presentation (string).
+writeS5String :: WriterOptions -> Pandoc -> String
+writeS5String options = (writeHtmlString options) . insertS5Structure
+
+-- | Inserts HTML needed for an S5 presentation (e.g. around slides).
+layoutDiv :: [Inline] -- ^ Title of document (for header or footer)
+ -> String -- ^ Date of document (for header or footer)
+ -> [Block] -- ^ List of block elements returned
+layoutDiv title' date = [(RawHtml "<div class=\"layout\">\n<div id=\"controls\"></div>\n<div id=\"currentSlide\"></div>\n<div id=\"header\"></div>\n<div id=\"footer\">\n"), (Header 1 [Str date]), (Header 2 title'), (RawHtml "</div>\n</div>\n")]
+
+presentationStart :: Block
+presentationStart = RawHtml "<div class=\"presentation\">\n\n"
+
+presentationEnd :: Block
+presentationEnd = RawHtml "</div>\n"
+
+slideStart :: Block
+slideStart = RawHtml "<div class=\"slide\">\n"
+
+slideEnd :: Block
+slideEnd = RawHtml "</div>\n"
+
+-- | Returns 'True' if block is a Header 1.
+isH1 :: Block -> Bool
+isH1 (Header 1 _) = True
+isH1 _ = False
+
+-- | Insert HTML around sections to make individual slides.
+insertSlides :: Bool -> [Block] -> [Block]
+insertSlides beginning blocks =
+ let (beforeHead, rest) = break isH1 blocks in
+ if (null rest) then
+ if beginning then
+ beforeHead
+ else
+ beforeHead ++ [slideEnd]
+ else
+ if beginning then
+ beforeHead ++
+ slideStart:(head rest):(insertSlides False (tail rest))
+ else
+ beforeHead ++
+ slideEnd:slideStart:(head rest):(insertSlides False (tail rest))
+
+-- | Insert blocks into 'Pandoc' for slide structure.
+insertS5Structure :: Pandoc -> Pandoc
+insertS5Structure (Pandoc meta' []) = Pandoc meta' []
+insertS5Structure (Pandoc (Meta title' authors date) blocks) =
+ let slides = insertSlides True blocks
+ firstSlide = if not (null title')
+ then [slideStart, (Header 1 title'),
+ (Header 3 [Str (intercalate ", " authors)]),
+ (Header 4 [Str date]), slideEnd]
+ else []
+ newBlocks = (layoutDiv title' date) ++ presentationStart:firstSlide ++
+ slides ++ [presentationEnd]
+ in Pandoc (Meta title' authors date) newBlocks
diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs
new file mode 100644
index 000000000..305a1a8d0
--- /dev/null
+++ b/src/Text/Pandoc/Writers/Texinfo.hs
@@ -0,0 +1,474 @@
+{-
+Copyright (C) 2008 John MacFarlane and Peter Wang
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.Texinfo
+ Copyright : Copyright (C) 2008 John MacFarlane and Peter Wang
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' format into Texinfo.
+-}
+module Text.Pandoc.Writers.Texinfo ( writeTexinfo ) where
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared
+import Text.Pandoc.Readers.TeXMath
+import Text.Printf ( printf )
+import Data.List ( isSuffixOf )
+import Data.Char ( chr, ord )
+import qualified Data.Set as S
+import Control.Monad.State
+import Text.PrettyPrint.HughesPJ hiding ( Str )
+
+data WriterState =
+ WriterState { stIncludes :: S.Set String -- strings to include in header
+ }
+
+{- TODO:
+ - internal cross references a la HTML
+ - generated .texi files don't work when run through texi2dvi
+ -}
+
+-- | Add line to header.
+addToHeader :: String -> State WriterState ()
+addToHeader str = do
+ st <- get
+ let includes = stIncludes st
+ put st {stIncludes = S.insert str includes}
+
+-- | Convert Pandoc to Texinfo.
+writeTexinfo :: WriterOptions -> Pandoc -> String
+writeTexinfo options document =
+ render $ evalState (pandocToTexinfo options $ wrapTop document) $
+ WriterState { stIncludes = S.empty }
+
+-- | Add a "Top" node around the document, needed by Texinfo.
+wrapTop :: Pandoc -> Pandoc
+wrapTop (Pandoc (Meta title authors date) blocks) =
+ Pandoc (Meta title authors date) (Header 0 title : blocks)
+
+pandocToTexinfo :: WriterOptions -> Pandoc -> State WriterState Doc
+pandocToTexinfo options (Pandoc meta blocks) = do
+ main <- blockListToTexinfo blocks
+ head' <- if writerStandalone options
+ then texinfoHeader options meta
+ else return empty
+ let before = if null (writerIncludeBefore options)
+ then empty
+ else text (writerIncludeBefore options)
+ let after = if null (writerIncludeAfter options)
+ then empty
+ else text (writerIncludeAfter options)
+ let body = before $$ main $$ after
+ -- XXX toc untested
+ let toc = if writerTableOfContents options
+ then text "@contents"
+ else empty
+ let foot = if writerStandalone options
+ then text "@bye"
+ else empty
+ return $ head' $$ toc $$ body $$ foot
+
+-- | Insert bibliographic information into Texinfo header.
+texinfoHeader :: WriterOptions -- ^ Options, including Texinfo header
+ -> Meta -- ^ Meta with bibliographic information
+ -> State WriterState Doc
+texinfoHeader options (Meta title authors date) = do
+ titletext <- if null title
+ then return empty
+ else do
+ t <- inlineListToTexinfo title
+ return $ text "@title " <> t
+ headerIncludes <- get >>= return . S.toList . stIncludes
+ let extras = text $ unlines headerIncludes
+ let authorstext = map makeAuthor authors
+ let datetext = if date == ""
+ then empty
+ else text $ stringToTexinfo date
+
+ let baseHeader = text $ writerHeader options
+ let header = baseHeader $$ extras
+ return $ text "\\input texinfo" $$
+ header $$
+ text "@ifnottex" $$
+ text "@paragraphindent 0" $$
+ text "@end ifnottex" $$
+ text "@titlepage" $$
+ titletext $$ vcat authorstext $$
+ datetext $$
+ text "@end titlepage"
+
+makeAuthor :: String -> Doc
+makeAuthor author = text $ "@author " ++ (stringToTexinfo author)
+
+-- | Escape things as needed for Texinfo.
+stringToTexinfo :: String -> String
+stringToTexinfo = escapeStringUsing texinfoEscapes
+ where texinfoEscapes = [ ('{', "@{")
+ , ('}', "@}")
+ , ('@', "@@")
+ , (',', "@comma{}") -- only needed in argument lists
+ , ('\160', "@ ")
+ ]
+
+-- | Puts contents into Texinfo command.
+inCmd :: String -> Doc -> Doc
+inCmd cmd contents = char '@' <> text cmd <> braces contents
+
+-- | Convert Pandoc block element to Texinfo.
+blockToTexinfo :: Block -- ^ Block to convert
+ -> State WriterState Doc
+
+blockToTexinfo Null = return empty
+
+blockToTexinfo (Plain lst) =
+ inlineListToTexinfo lst
+
+blockToTexinfo (Para lst) =
+ inlineListToTexinfo lst -- this is handled differently from Plain in blockListToTexinfo
+
+blockToTexinfo (BlockQuote lst) = do
+ contents <- blockListToTexinfo lst
+ return $ text "@quotation" $$
+ contents $$
+ text "@end quotation"
+
+blockToTexinfo (CodeBlock _ str) = do
+ return $ text "@verbatim" $$
+ vcat (map text (lines str)) $$
+ text "@end verbatim\n"
+
+blockToTexinfo (RawHtml _) = return empty
+
+blockToTexinfo (BulletList lst) = do
+ items <- mapM listItemToTexinfo lst
+ return $ text "@itemize" $$
+ vcat items $$
+ text "@end itemize\n"
+
+blockToTexinfo (OrderedList (start, numstyle, _) lst) = do
+ items <- mapM listItemToTexinfo lst
+ return $ text "@enumerate " <> exemplar $$
+ vcat items $$
+ text "@end enumerate\n"
+ where
+ exemplar = case numstyle of
+ DefaultStyle -> decimal
+ Decimal -> decimal
+ UpperRoman -> decimal -- Roman numerals not supported
+ LowerRoman -> decimal
+ UpperAlpha -> upperAlpha
+ LowerAlpha -> lowerAlpha
+ decimal = if start == 1
+ then empty
+ else text (show start)
+ upperAlpha = text [chr $ ord 'A' + start - 1]
+ lowerAlpha = text [chr $ ord 'a' + start - 1]
+
+blockToTexinfo (DefinitionList lst) = do
+ items <- mapM defListItemToTexinfo lst
+ return $ text "@table @asis" $$
+ vcat items $$
+ text "@end table\n"
+
+blockToTexinfo HorizontalRule =
+ -- XXX can't get the equivalent from LaTeX.hs to work
+ return $ text "@iftex" $$
+ text "@bigskip@hrule@bigskip" $$
+ text "@end iftex" $$
+ text "@ifnottex" $$
+ text (take 72 $ repeat '-') $$
+ text "@end ifnottex"
+
+blockToTexinfo (Header 0 lst) = do
+ txt <- if null lst
+ then return $ text "Top"
+ else inlineListToTexinfo lst
+ return $ text "@node Top" $$
+ text "@top " <> txt <> char '\n'
+
+blockToTexinfo (Header level lst) = do
+ node <- inlineListForNode lst
+ txt <- inlineListToTexinfo lst
+ return $ if (level > 0) && (level <= 4)
+ then text "\n@node " <> node <> char '\n' <>
+ text (seccmd level) <> txt
+ else txt
+ where
+ seccmd 1 = "@chapter "
+ seccmd 2 = "@section "
+ seccmd 3 = "@subsection "
+ seccmd 4 = "@subsubsection "
+ seccmd _ = error "illegal seccmd level"
+
+blockToTexinfo (Table caption aligns widths heads rows) = do
+ headers <- tableHeadToTexinfo aligns heads
+ captionText <- inlineListToTexinfo caption
+ rowsText <- mapM (tableRowToTexinfo aligns) rows
+ let colWidths = map (printf "%.2f ") widths
+ let colDescriptors = concat colWidths
+ let tableBody = text ("@multitable @columnfractions " ++ colDescriptors) $$
+ headers $$
+ vcat rowsText $$
+ text "@end multitable"
+ return $ if isEmpty captionText
+ then tableBody <> char '\n'
+ else text "@float" $$
+ tableBody $$
+ inCmd "caption" captionText $$
+ text "@end float"
+
+tableHeadToTexinfo :: [Alignment]
+ -> [[Block]]
+ -> State WriterState Doc
+tableHeadToTexinfo = tableAnyRowToTexinfo "@headitem "
+
+tableRowToTexinfo :: [Alignment]
+ -> [[Block]]
+ -> State WriterState Doc
+tableRowToTexinfo = tableAnyRowToTexinfo "@item "
+
+tableAnyRowToTexinfo :: String
+ -> [Alignment]
+ -> [[Block]]
+ -> State WriterState Doc
+tableAnyRowToTexinfo itemtype aligns cols =
+ zipWithM alignedBlock aligns cols >>=
+ return . (text itemtype $$) . foldl (\row item -> row $$
+ (if isEmpty row then empty else text " @tab ") <> item) empty
+
+alignedBlock :: Alignment
+ -> [Block]
+ -> State WriterState Doc
+-- XXX @flushleft and @flushright text won't get word wrapped. Since word
+-- wrapping is more important than alignment, we ignore the alignment.
+alignedBlock _ = blockListToTexinfo
+{-
+alignedBlock AlignLeft col = do
+ b <- blockListToTexinfo col
+ return $ text "@flushleft" $$ b $$ text "@end flushleft"
+alignedBlock AlignRight col = do
+ b <- blockListToTexinfo col
+ return $ text "@flushright" $$ b $$ text "@end flushright"
+alignedBlock _ col = blockListToTexinfo col
+-}
+
+-- | Convert Pandoc block elements to Texinfo.
+blockListToTexinfo :: [Block]
+ -> State WriterState Doc
+blockListToTexinfo [] = return $ empty
+blockListToTexinfo (x:xs) = do
+ x' <- blockToTexinfo x
+ case x of
+ Header level _ -> do
+ -- We need need to insert a menu for this node.
+ let (before, after) = break isHeader xs
+ before' <- blockListToTexinfo before
+ let menu = if level < 4
+ then collectNodes (level + 1) after
+ else []
+ lines' <- mapM makeMenuLine menu
+ let menu' = if null lines'
+ then empty
+ else text "@menu" $$
+ vcat lines' $$
+ text "@end menu"
+ after' <- blockListToTexinfo after
+ return $ x' $$ before' $$ menu' $$ after'
+ Para _ -> do
+ xs' <- blockListToTexinfo xs
+ case xs of
+ ((CodeBlock _ _):_) -> return $ x' $$ xs'
+ _ -> return $ x' $$ text "" $$ xs'
+ _ -> do
+ xs' <- blockListToTexinfo xs
+ return $ x' $$ xs'
+
+isHeader :: Block -> Bool
+isHeader (Header _ _) = True
+isHeader _ = False
+
+collectNodes :: Int -> [Block] -> [Block]
+collectNodes _ [] = []
+collectNodes level (x:xs) =
+ case x of
+ (Header hl _) ->
+ if hl < level
+ then []
+ else if hl == level
+ then x : collectNodes level xs
+ else collectNodes level xs
+ _ ->
+ collectNodes level xs
+
+makeMenuLine :: Block
+ -> State WriterState Doc
+makeMenuLine (Header _ lst) = do
+ txt <- inlineListForNode lst
+ return $ text "* " <> txt <> text "::"
+makeMenuLine _ = error "makeMenuLine called with non-Header block"
+
+listItemToTexinfo :: [Block]
+ -> State WriterState Doc
+listItemToTexinfo lst = blockListToTexinfo lst >>=
+ return . (text "@item" $$)
+
+defListItemToTexinfo :: ([Inline], [Block])
+ -> State WriterState Doc
+defListItemToTexinfo (term, def) = do
+ term' <- inlineListToTexinfo term
+ def' <- blockListToTexinfo def
+ return $ text "@item " <> term' <> text "\n" $$ def'
+
+-- | Convert list of inline elements to Texinfo.
+inlineListToTexinfo :: [Inline] -- ^ Inlines to convert
+ -> State WriterState Doc
+inlineListToTexinfo lst = mapM inlineToTexinfo lst >>= return . hcat
+
+-- | Convert list of inline elements to Texinfo acceptable for a node name.
+inlineListForNode :: [Inline] -- ^ Inlines to convert
+ -> State WriterState Doc
+inlineListForNode lst = mapM inlineForNode lst >>= return . hcat
+
+inlineForNode :: Inline -> State WriterState Doc
+inlineForNode (Str str) = return $ text $ filter (not.disallowedInNode) str
+inlineForNode (Emph lst) = inlineListForNode lst
+inlineForNode (Strong lst) = inlineListForNode lst
+inlineForNode (Strikeout lst) = inlineListForNode lst
+inlineForNode (Superscript lst) = inlineListForNode lst
+inlineForNode (Subscript lst) = inlineListForNode lst
+inlineForNode (SmallCaps lst) = inlineListForNode lst
+inlineForNode (Quoted _ lst) = inlineListForNode lst
+inlineForNode (Cite _ lst) = inlineListForNode lst
+inlineForNode (Code str) = inlineForNode (Str str)
+inlineForNode Space = return $ char ' '
+inlineForNode EmDash = return $ text "---"
+inlineForNode EnDash = return $ text "--"
+inlineForNode Apostrophe = return $ char '\''
+inlineForNode Ellipses = return $ text "..."
+inlineForNode LineBreak = return empty
+inlineForNode (Math _ str) = inlineListForNode $ readTeXMath str
+inlineForNode (TeX _) = return empty
+inlineForNode (HtmlInline _) = return empty
+inlineForNode (Link lst _) = inlineListForNode lst
+inlineForNode (Image lst _) = inlineListForNode lst
+inlineForNode (Note _) = return empty
+
+-- periods, commas, colons, and parentheses are disallowed in node names
+disallowedInNode :: Char -> Bool
+disallowedInNode c = c `elem` ".,:()"
+
+-- | Convert inline element to Texinfo
+inlineToTexinfo :: Inline -- ^ Inline to convert
+ -> State WriterState Doc
+
+inlineToTexinfo (Emph lst) =
+ inlineListToTexinfo lst >>= return . inCmd "emph"
+
+inlineToTexinfo (Strong lst) =
+ inlineListToTexinfo lst >>= return . inCmd "strong"
+
+inlineToTexinfo (Strikeout lst) = do
+ addToHeader $ "@macro textstrikeout{text}\n" ++
+ "~~\\text\\~~\n" ++
+ "@end macro\n"
+ contents <- inlineListToTexinfo lst
+ return $ text "@textstrikeout{" <> contents <> text "}"
+
+inlineToTexinfo (Superscript lst) = do
+ addToHeader $ "@macro textsuperscript{text}\n" ++
+ "@iftex\n" ++
+ "@textsuperscript{\\text\\}\n" ++
+ "@end iftex\n" ++
+ "@ifnottex\n" ++
+ "^@{\\text\\@}\n" ++
+ "@end ifnottex\n" ++
+ "@end macro\n"
+ contents <- inlineListToTexinfo lst
+ return $ text "@textsuperscript{" <> contents <> char '}'
+
+inlineToTexinfo (Subscript lst) = do
+ addToHeader $ "@macro textsubscript{text}\n" ++
+ "@iftex\n" ++
+ "@textsubscript{\\text\\}\n" ++
+ "@end iftex\n" ++
+ "@ifnottex\n" ++
+ "_@{\\text\\@}\n" ++
+ "@end ifnottex\n" ++
+ "@end macro\n"
+ contents <- inlineListToTexinfo lst
+ return $ text "@textsubscript{" <> contents <> char '}'
+
+inlineToTexinfo (SmallCaps lst) =
+ inlineListToTexinfo lst >>= return . inCmd "sc"
+
+inlineToTexinfo (Code str) = do
+ return $ text $ "@code{" ++ stringToTexinfo str ++ "}"
+
+inlineToTexinfo (Quoted SingleQuote lst) = do
+ contents <- inlineListToTexinfo lst
+ return $ char '`' <> contents <> char '\''
+
+inlineToTexinfo (Quoted DoubleQuote lst) = do
+ contents <- inlineListToTexinfo lst
+ return $ text "``" <> contents <> text "''"
+
+inlineToTexinfo (Cite _ lst) =
+ inlineListToTexinfo lst
+inlineToTexinfo Apostrophe = return $ char '\''
+inlineToTexinfo EmDash = return $ text "---"
+inlineToTexinfo EnDash = return $ text "--"
+inlineToTexinfo Ellipses = return $ text "@dots{}"
+inlineToTexinfo (Str str) = return $ text (stringToTexinfo str)
+inlineToTexinfo (Math _ str) = return $ inCmd "math" $ text str
+inlineToTexinfo (TeX str) = return $ text "@tex" $$ text str $$ text "@end tex"
+inlineToTexinfo (HtmlInline _) = return empty
+inlineToTexinfo (LineBreak) = return $ text "@*"
+inlineToTexinfo Space = return $ char ' '
+
+inlineToTexinfo (Link txt (src, _)) = do
+ case txt of
+ [Code x] | x == src -> -- autolink
+ do return $ text $ "@url{" ++ x ++ "}"
+ _ -> do contents <- inlineListToTexinfo txt
+ let src1 = stringToTexinfo src
+ return $ text ("@uref{" ++ src1 ++ ",") <> contents <>
+ char '}'
+
+inlineToTexinfo (Image alternate (source, _)) = do
+ content <- inlineListToTexinfo alternate
+ return $ text ("@image{" ++ base ++ ",,,") <> content <> text "," <>
+ text (ext ++ "}")
+ where
+ (revext, revbase) = break (=='.') (reverse source)
+ ext = reverse revext
+ base = case revbase of
+ ('.' : rest) -> reverse rest
+ _ -> reverse revbase
+
+inlineToTexinfo (Note contents) = do
+ contents' <- blockListToTexinfo contents
+ let rawnote = stripTrailingNewlines $ render contents'
+ let optNewline = "@end verbatim" `isSuffixOf` rawnote
+ return $ text "@footnote{" <>
+ text rawnote <>
+ (if optNewline then char '\n' else empty) <>
+ char '}'
diff --git a/src/Text/Pandoc/XML.hs b/src/Text/Pandoc/XML.hs
new file mode 100644
index 000000000..14e2eebbb
--- /dev/null
+++ b/src/Text/Pandoc/XML.hs
@@ -0,0 +1,88 @@
+{-
+Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.XML
+ Copyright : Copyright (C) 2006-7 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Functions for escaping and formatting XML.
+-}
+module Text.Pandoc.XML ( escapeCharForXML,
+ escapeStringForXML,
+ inTags,
+ selfClosingTag,
+ inTagsSimple,
+ inTagsIndented ) where
+import Text.PrettyPrint.HughesPJ
+
+-- | Escape one character as needed for XML.
+escapeCharForXML :: Char -> String
+escapeCharForXML x = case x of
+ '&' -> "&amp;"
+ '<' -> "&lt;"
+ '>' -> "&gt;"
+ '"' -> "&quot;"
+ '\160' -> "&#160;"
+ c -> [c]
+
+-- | True if the character needs to be escaped.
+needsEscaping :: Char -> Bool
+needsEscaping c = c `elem` "&<>\"\160"
+
+-- | Escape string as needed for XML. Entity references are not preserved.
+escapeStringForXML :: String -> String
+escapeStringForXML "" = ""
+escapeStringForXML str =
+ case break needsEscaping str of
+ (okay, "") -> okay
+ (okay, (c:cs)) -> okay ++ escapeCharForXML c ++ escapeStringForXML cs
+
+-- | Return a text object with a string of formatted XML attributes.
+attributeList :: [(String, String)] -> Doc
+attributeList = text . concatMap
+ (\(a, b) -> " " ++ escapeStringForXML a ++ "=\"" ++
+ escapeStringForXML b ++ "\"")
+
+-- | Put the supplied contents between start and end tags of tagType,
+-- with specified attributes and (if specified) indentation.
+inTags:: Bool -> String -> [(String, String)] -> Doc -> Doc
+inTags isIndented tagType attribs contents =
+ let openTag = char '<' <> text tagType <> attributeList attribs <>
+ char '>'
+ closeTag = text "</" <> text tagType <> char '>'
+ in if isIndented
+ then openTag $$ nest 2 contents $$ closeTag
+ else openTag <> contents <> closeTag
+
+-- | Return a self-closing tag of tagType with specified attributes
+selfClosingTag :: String -> [(String, String)] -> Doc
+selfClosingTag tagType attribs =
+ char '<' <> text tagType <> attributeList attribs <> text " />"
+
+-- | Put the supplied contents between start and end tags of tagType.
+inTagsSimple :: String -> Doc -> Doc
+inTagsSimple tagType = inTags False tagType []
+
+-- | Put the supplied contents in indented block btw start and end tags.
+inTagsIndented :: String -> Doc -> Doc
+inTagsIndented tagType = inTags True tagType []
diff --git a/src/hsmarkdown.hs b/src/hsmarkdown.hs
new file mode 100644
index 000000000..453c34468
--- /dev/null
+++ b/src/hsmarkdown.hs
@@ -0,0 +1,43 @@
+{-# LANGUAGE CPP #-}
+{-
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Copyright : Copyright (C) 2009 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley@edu>
+ Stability : alpha
+ Portability : portable
+
+Wrapper around pandoc that emulates Markdown.pl as closely as possible.
+-}
+module Main where
+import System.Process
+import System.Environment ( getArgs )
+import Prelude hiding ( putStr, putStrLn, writeFile, readFile, getContents )
+import System.IO.UTF8
+import Control.Monad (forM_)
+
+main :: IO ()
+main = do
+ files <- getArgs
+ let runPandoc inp = readProcess "pandoc" ["--from", "markdown", "--to", "html", "--strict"] inp >>= putStrLn
+ if null files
+ then getContents >>= runPandoc
+ else forM_ files $ \f -> readFile f >>= runPandoc
diff --git a/src/markdown2pdf.hs b/src/markdown2pdf.hs
new file mode 100644
index 000000000..6a04999fa
--- /dev/null
+++ b/src/markdown2pdf.hs
@@ -0,0 +1,198 @@
+module Main where
+
+import Data.List (isInfixOf, intercalate, (\\))
+import Data.Maybe (isNothing)
+
+import Control.Monad (when, unless, guard)
+import Control.Exception (tryJust, bracket)
+
+import System.IO (stderr, hPutStrLn)
+import System.IO.Error (isDoesNotExistError)
+import System.Exit (ExitCode (..), exitWith)
+import System.FilePath
+import System.Directory
+import System.Process (readProcessWithExitCode)
+import System.Environment (getArgs, getProgName)
+
+
+run :: FilePath -> [String] -> IO (Either String String)
+run file opts = do
+ (code, out, err) <- readProcessWithExitCode file opts ""
+ let msg = out ++ err
+ case code of
+ ExitFailure _ -> return $ Left $! msg
+ ExitSuccess -> return $ Right $! msg
+
+parsePandocArgs :: [String] -> IO (Maybe ([String], String))
+parsePandocArgs args = do
+ result <- run "pandoc" $ ["--dump-args"] ++ args
+ return $ either (const Nothing) (parse . map trim . lines) result
+ where parse [] = Nothing
+ parse ("-":[]) = Just ([], "stdin") -- no output or input
+ parse ("-":x:xs) = Just (x:xs, dropExtension x) -- no output
+ parse ( x :xs) = Just (xs, dropExtension x) -- at least output
+ --trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace
+ trim = takeWhile (/='\r') . dropWhile (=='\r')
+
+runPandoc :: [String] -> FilePath -> IO (Either String FilePath)
+runPandoc inputs output = do
+ let texFile = replaceExtension output "tex"
+ result <- run "pandoc" $
+ ["-s", "--no-wrap", "-r", "markdown", "-w", "latex"]
+ ++ inputs ++ ["-o", texFile]
+ return $ either Left (const $ Right texFile) result
+
+runLatexRaw :: FilePath -> IO (Either (Either String String) FilePath)
+runLatexRaw file = do
+ -- we ignore the ExitCode because pdflatex always fails the first time
+ run "pdflatex" ["-interaction=batchmode", "-output-directory",
+ takeDirectory file, dropExtension file] >> return ()
+ let pdfFile = replaceExtension file "pdf"
+ let logFile = replaceExtension file "log"
+ txt <- tryJust (guard . isDoesNotExistError) (readFile logFile)
+ let checks = checkLatex $ either (const "") id txt
+ case checks of
+ -- err , bib , ref , msg
+ (True , _ , _ , msg) -> return $ Left $ Left msg -- failure
+ (False, True , _ , msg) -> runBibtex file >>
+ (return $ Left $ Right msg) -- citations
+ (False, _ , True, msg) -> return $ Left $ Right msg -- references
+ (False, False, False, _ ) -> return $ Right pdfFile -- success
+
+runLatex :: FilePath -> IO (Either String FilePath)
+runLatex file = step 3
+ where
+ step 0 = return $ Left "Limit of attempts reached"
+ step n = do
+ result <- runLatexRaw file
+ case result of
+ Left (Left err) -> return $ Left err
+ Left (Right _ ) -> step (n-1 :: Int)
+ Right pdfFile -> return $ Right pdfFile
+
+checkLatex :: String -> (Bool, Bool, Bool, String)
+checkLatex "" = (True, False, False, "Could not read log file")
+checkLatex txt = (err , bib, ref, unlines $! msgs ++ tips)
+ where
+ xs `oneOf` x = any (flip isInfixOf x) xs
+ msgs = filter (oneOf ["Error:", "Warning:"]) (lines txt)
+ tips = checkPackages msgs
+ err = any (oneOf ["LaTeX Error:", "Latex Error:"]) msgs
+ bib = any (oneOf ["Warning: Citation"
+ ,"Warning: There were undefined citations"]) msgs
+ ref = any (oneOf ["Warning: Reference"
+ ,"Warning: Label"
+ ,"Warning: There were undefined references"
+ ,"--toc", "--table-of-contents"]) msgs
+
+checkPackages :: [String] -> [String]
+checkPackages = concatMap chks
+ where -- for each message, search 'pks' for matches and give a hint
+ chks x = concatMap (chk x) pks
+ chk x (k,v) = if sub k `isInfixOf` x then tip k v else []
+ sub k = "`" ++ k ++ ".sty' not found"
+ tip k v = ["Please install the '" ++ k ++
+ "' package from CTAN:", " " ++ v]
+ pks = [("ucs"
+ ,"http://www.ctan.org/tex-archive/macros/latex/contrib/unicode/")
+ ,("ulem"
+ ,"http://www.ctan.org/tex-archive/macros/latex/contrib/misc/")
+ ,("graphicx"
+ ,"http://www.ctan.org/tex-archive/macros/latex/required/graphics/")
+ ,("fancyhdr"
+ ,"http://www.ctan.org/tex-archive/macros/latex/contrib/fancyhdr/")
+ ,("array"
+ ,"http://www.ctan.org/tex-archive/macros/latex/required/tools/")]
+
+runBibtex :: FilePath -> IO (Either String FilePath)
+runBibtex file = do
+ let auxFile = replaceExtension file "aux"
+ result <- run "bibtex" [auxFile]
+ return $ either Left (const $ Right auxFile) result
+
+exit :: String -> IO a
+exit x = do
+ progName <- getProgName
+ hPutStrLn stderr $ progName ++ ": " ++ x
+ exitWith $ ExitFailure 1
+
+saveStdin :: FilePath -> IO (Either String FilePath)
+saveStdin file = do
+ text <- getContents
+ writeFile file text
+ fileExist <- doesFileExist file
+ case fileExist of
+ False -> return $ Left $! "Could not create " ++ file
+ True -> return $ Right file
+
+saveOutput :: FilePath -> FilePath -> IO ()
+saveOutput input output = do
+ outputExist <- doesFileExist output
+ when outputExist $ do
+ let output' = output ++ "~"
+ renameFile output output'
+ putStrLn $! "Created backup file " ++ output'
+ copyFile input output
+ putStrLn $! "Created " ++ output
+
+main :: IO ()
+main = bracket
+ -- acquire resource
+ (do dir <- getTemporaryDirectory
+ let tmp = dir </> "pandoc"
+ createDirectoryIfMissing True tmp
+ return tmp)
+
+ -- release resource
+ ( \tmp -> removeDirectoryRecursive tmp)
+
+ -- run computation
+ $ \tmp -> do
+ -- check for executable files
+ let execs = ["pandoc", "pdflatex", "bibtex"]
+ paths <- mapM findExecutable execs
+ let miss = map snd $ filter (isNothing . fst) $ zip paths execs
+ unless (null miss) $ exit $! "Could not find " ++ intercalate ", " miss
+ args <- getArgs
+ -- check for invalid arguments and print help message if needed
+ let goodopts = ["-f","-r","--from","--read","--strict","-N",
+ "-p","--preserve-tabs","--tab-stop","-R","--parse-raw",
+ "--toc","--table-of-contents",
+ "--number-sections","-H","--include-in-header",
+ "-B","--include-before-body","-A","--include-after-body",
+ "-C","--custom-header","-o","--output"]
+ let goodoptsLong = filter (\op -> length op > 2) goodopts
+ let isOpt ('-':_) = True
+ isOpt _ = False
+ unless (null (filter isOpt args \\ goodopts)) $ do
+ (code, out, _err) <- readProcessWithExitCode "pandoc" ["--help"] ""
+ putStrLn "markdown2pdf [OPTIONS] [FILES]\nOptions:"
+ putStr $ unlines $
+ filter (\l -> any (`isInfixOf` l) goodoptsLong) $ lines out
+ exitWith code
+ -- parse arguments
+ -- if no input given, use 'stdin'
+ pandocArgs <- parsePandocArgs args
+ (input, output) <- case pandocArgs of
+ Nothing -> exit "Could not parse arguments"
+ Just ([],out) -> do
+ stdinFile <- saveStdin (replaceDirectory (takeBaseName out) tmp)
+ case stdinFile of
+ Left err -> exit err
+ Right f -> return ([f], out)
+ -- no need because we'll pass all arguments to pandoc
+ Just (_ ,out) -> return ([], out)
+ -- run pandoc
+ pandocRes <- runPandoc (input ++ args) $ replaceDirectory output tmp
+ case pandocRes of
+ Left err -> exit err
+ Right texFile -> do
+ -- run pdflatex
+ latexRes <- runLatex texFile
+ case latexRes of
+ Left err -> exit err
+ Right pdfFile -> do
+ -- save the output creating a backup if necessary
+ saveOutput pdfFile $
+ replaceDirectory pdfFile (takeDirectory output)
+
diff --git a/src/pandoc.hs b/src/pandoc.hs
new file mode 100644
index 000000000..d6c45501e
--- /dev/null
+++ b/src/pandoc.hs
@@ -0,0 +1,652 @@
+{-# LANGUAGE CPP #-}
+{-
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Main
+ Copyright : Copyright (C) 2006-8 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley@edu>
+ Stability : alpha
+ Portability : portable
+
+Parses command-line options and calls the appropriate readers and
+writers.
+-}
+module Main where
+import Text.Pandoc
+import Text.Pandoc.ODT
+import Text.Pandoc.Shared ( HTMLMathMethod (..), tabFilter, ObfuscationMethod (..) )
+#ifdef _HIGHLIGHTING
+import Text.Pandoc.Highlighting ( languages )
+#endif
+import System.Environment ( getArgs, getProgName, getEnvironment )
+import System.Exit ( exitWith, ExitCode (..) )
+import System.FilePath
+import System.Console.GetOpt
+import Data.Maybe ( fromMaybe )
+import Data.Char ( toLower )
+import Data.List ( intercalate, isSuffixOf )
+import Prelude hiding ( putStr, putStrLn, writeFile, readFile, getContents )
+import System.IO ( stdout, stderr )
+import System.IO.UTF8
+#ifdef _CITEPROC
+import Text.CSL
+import Text.Pandoc.Biblio
+#endif
+import Control.Monad (when, unless)
+
+copyrightMessage :: String
+copyrightMessage = "\nCopyright (C) 2006-8 John MacFarlane\n" ++
+ "Web: http://johnmacfarlane.net/pandoc\n" ++
+ "This is free software; see the source for copying conditions. There is no\n" ++
+ "warranty, not even for merchantability or fitness for a particular purpose."
+
+compileInfo :: String
+compileInfo =
+#ifdef _CITEPROC
+ "\nCompiled with citeproc support." ++
+#endif
+#ifdef _HIGHLIGHTING
+ "\nCompiled with syntax highlighting support for:\n" ++
+ wrapWords 78 languages ++
+#endif
+ ""
+
+-- | Converts a list of strings into a single string with the items printed as
+-- comma separated words in lines with a maximum line length.
+wrapWords :: Int -> [String] -> String
+wrapWords c = wrap' c c where
+ wrap' _ _ [] = ""
+ wrap' cols remaining (x:xs) = if remaining == cols
+ then x ++ wrap' cols (remaining - length x) xs
+ else if (length x + 1) > remaining
+ then ",\n" ++ x ++ wrap' cols (cols - length x) xs
+ else ", " ++ x ++ wrap' cols (remaining - (length x + 2)) xs
+
+-- | Association list of formats and readers.
+readers :: [(String, ParserState -> String -> Pandoc)]
+readers = [("native" , readPandoc)
+ ,("markdown" , readMarkdown)
+ ,("markdown+lhs" , readMarkdown)
+ ,("rst" , readRST)
+ ,("rst+lhs" , readRST)
+ ,("html" , readHtml)
+ ,("latex" , readLaTeX)
+ ,("latex+lhs" , readLaTeX)
+ ]
+
+-- | Reader for native Pandoc format.
+readPandoc :: ParserState -> String -> Pandoc
+readPandoc _ = read
+
+-- | Association list of formats and pairs of writers and default headers.
+writers :: [ ( String, ( WriterOptions -> Pandoc -> String, String ) ) ]
+writers = [("native" , (writeDoc, ""))
+ ,("html" , (writeHtmlString, ""))
+ ,("html+lhs" , (writeHtmlString, ""))
+ ,("s5" , (writeS5String, defaultS5Header))
+ ,("docbook" , (writeDocbook, defaultDocbookHeader))
+ ,("opendocument" , (writeOpenDocument, defaultOpenDocumentHeader))
+ ,("odt" , (writeOpenDocument, defaultOpenDocumentHeader))
+ ,("latex" , (writeLaTeX, defaultLaTeXHeader))
+ ,("latex+lhs" , (writeLaTeX, defaultLaTeXHeader))
+ ,("context" , (writeConTeXt, defaultConTeXtHeader))
+ ,("texinfo" , (writeTexinfo, ""))
+ ,("man" , (writeMan, ""))
+ ,("markdown" , (writeMarkdown, ""))
+ ,("markdown+lhs" , (writeMarkdown, ""))
+ ,("rst" , (writeRST, ""))
+ ,("rst+lhs" , (writeRST, ""))
+ ,("mediawiki" , (writeMediaWiki, ""))
+ ,("rtf" , (writeRTF, defaultRTFHeader))
+ ]
+
+isNonTextOutput :: String -> Bool
+isNonTextOutput = (`elem` ["odt"])
+
+-- | Writer for Pandoc native format.
+writeDoc :: WriterOptions -> Pandoc -> String
+writeDoc _ = prettyPandoc
+
+-- | Data structure for command line options.
+data Opt = Opt
+ { optTabStop :: Int -- ^ Number of spaces per tab
+ , optPreserveTabs :: Bool -- ^ Preserve tabs instead of converting to spaces
+ , optStandalone :: Bool -- ^ Include header, footer
+ , optReader :: String -- ^ Reader format
+ , optWriter :: String -- ^ Writer format
+ , optParseRaw :: Bool -- ^ Parse unconvertable HTML and TeX
+ , optCSS :: [String] -- ^ CSS file to link to
+ , optTableOfContents :: Bool -- ^ Include table of contents
+ , optIncludeInHeader :: String -- ^ File to include in header
+ , optIncludeBeforeBody :: String -- ^ File to include at top of body
+ , optIncludeAfterBody :: String -- ^ File to include at end of body
+ , optCustomHeader :: String -- ^ Custom header to use, or "DEFAULT"
+ , optTitlePrefix :: String -- ^ Optional prefix for HTML title
+ , optOutputFile :: String -- ^ Name of output file
+ , optNumberSections :: Bool -- ^ Number sections in LaTeX
+ , optIncremental :: Bool -- ^ Use incremental lists in S5
+ , optSmart :: Bool -- ^ Use smart typography
+ , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
+ , optDumpArgs :: Bool -- ^ Output command-line arguments
+ , optIgnoreArgs :: Bool -- ^ Ignore command-line arguments
+ , optStrict :: Bool -- ^ Use strict markdown syntax
+ , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
+ , optWrapText :: Bool -- ^ Wrap text
+ , optSanitizeHTML :: Bool -- ^ Sanitize HTML
+ , optPlugins :: [Pandoc -> IO Pandoc] -- ^ Plugins to apply
+ , optEmailObfuscation :: ObfuscationMethod
+#ifdef _CITEPROC
+ , optBiblioFile :: String
+ , optBiblioFormat :: String
+ , optCslFile :: String
+#endif
+ }
+
+-- | Defaults for command-line options.
+defaultOpts :: Opt
+defaultOpts = Opt
+ { optTabStop = 4
+ , optPreserveTabs = False
+ , optStandalone = False
+ , optReader = "" -- null for default reader
+ , optWriter = "" -- null for default writer
+ , optParseRaw = False
+ , optCSS = []
+ , optTableOfContents = False
+ , optIncludeInHeader = ""
+ , optIncludeBeforeBody = ""
+ , optIncludeAfterBody = ""
+ , optCustomHeader = "DEFAULT"
+ , optTitlePrefix = ""
+ , optOutputFile = "-" -- "-" means stdout
+ , optNumberSections = False
+ , optIncremental = False
+ , optSmart = False
+ , optHTMLMathMethod = PlainMath
+ , optDumpArgs = False
+ , optIgnoreArgs = False
+ , optStrict = False
+ , optReferenceLinks = False
+ , optWrapText = True
+ , optSanitizeHTML = False
+ , optPlugins = []
+ , optEmailObfuscation = JavascriptObfuscation
+#ifdef _CITEPROC
+ , optBiblioFile = []
+ , optBiblioFormat = []
+ , optCslFile = []
+#endif
+ }
+
+-- | A list of functions, each transforming the options data structure
+-- in response to a command-line option.
+options :: [OptDescr (Opt -> IO Opt)]
+options =
+ [ Option "fr" ["from","read"]
+ (ReqArg
+ (\arg opt -> return opt { optReader = map toLower arg })
+ "FORMAT")
+ "" -- ("(" ++ (intercalate ", " $ map fst readers) ++ ")")
+
+ , Option "tw" ["to","write"]
+ (ReqArg
+ (\arg opt -> return opt { optWriter = map toLower arg })
+ "FORMAT")
+ "" -- ("(" ++ (intercalate ", " $ map fst writers) ++ ")")
+
+ , Option "s" ["standalone"]
+ (NoArg
+ (\opt -> return opt { optStandalone = True }))
+ "" -- "Include needed header and footer on output"
+
+ , Option "o" ["output"]
+ (ReqArg
+ (\arg opt -> return opt { optOutputFile = arg })
+ "FILENAME")
+ "" -- "Name of output file"
+
+ , Option "p" ["preserve-tabs"]
+ (NoArg
+ (\opt -> return opt { optPreserveTabs = True }))
+ "" -- "Preserve tabs instead of converting to spaces"
+
+ , Option "" ["tab-stop"]
+ (ReqArg
+ (\arg opt -> return opt { optTabStop = (read arg) } )
+ "TABSTOP")
+ "" -- "Tab stop (default 4)"
+
+ , Option "" ["strict"]
+ (NoArg
+ (\opt -> return opt { optStrict = True } ))
+ "" -- "Disable markdown syntax extensions"
+
+ , Option "" ["reference-links"]
+ (NoArg
+ (\opt -> return opt { optReferenceLinks = True } ))
+ "" -- "Use reference links in parsing HTML"
+
+ , Option "R" ["parse-raw"]
+ (NoArg
+ (\opt -> return opt { optParseRaw = True }))
+ "" -- "Parse untranslatable HTML codes and LaTeX environments as raw"
+
+ , Option "S" ["smart"]
+ (NoArg
+ (\opt -> return opt { optSmart = True }))
+ "" -- "Use smart quotes, dashes, and ellipses"
+
+ , Option "m" ["latexmathml", "asciimathml"]
+ (OptArg
+ (\arg opt -> return opt { optHTMLMathMethod =
+ LaTeXMathML arg })
+ "URL")
+ "" -- "Use LaTeXMathML script in html output"
+
+ , Option "" ["mimetex"]
+ (OptArg
+ (\arg opt -> return opt { optHTMLMathMethod = MimeTeX
+ (fromMaybe "/cgi-bin/mimetex.cgi" arg)})
+ "URL")
+ "" -- "Use mimetex for HTML math"
+
+ , Option "" ["jsmath"]
+ (OptArg
+ (\arg opt -> return opt { optHTMLMathMethod = JsMath arg})
+ "URL")
+ "" -- "Use jsMath for HTML math"
+
+ , Option "" ["gladtex"]
+ (NoArg
+ (\opt -> return opt { optHTMLMathMethod = GladTeX }))
+ "" -- "Use gladtex for HTML math"
+
+ , Option "i" ["incremental"]
+ (NoArg
+ (\opt -> return opt { optIncremental = True }))
+ "" -- "Make list items display incrementally in S5"
+
+ , Option "N" ["number-sections"]
+ (NoArg
+ (\opt -> return opt { optNumberSections = True }))
+ "" -- "Number sections in LaTeX"
+
+ , Option "" ["no-wrap"]
+ (NoArg
+ (\opt -> return opt { optWrapText = False }))
+ "" -- "Do not wrap text in output"
+
+ , Option "" ["sanitize-html"]
+ (NoArg
+ (\opt -> return opt { optSanitizeHTML = True }))
+ "" -- "Sanitize HTML"
+
+ , Option "" ["email-obfuscation"]
+ (ReqArg
+ (\arg opt -> do
+ method <- case arg of
+ "references" -> return ReferenceObfuscation
+ "javascript" -> return JavascriptObfuscation
+ "none" -> return NoObfuscation
+ _ -> hPutStrLn stderr ("Error: Unknown obfuscation method: " ++ arg) >>
+ exitWith (ExitFailure 6)
+ return opt { optEmailObfuscation = method })
+ "none|javascript|references")
+ "" -- "Method for obfuscating email in HTML"
+
+ , Option "" ["toc", "table-of-contents"]
+ (NoArg
+ (\opt -> return opt { optTableOfContents = True }))
+ "" -- "Include table of contents"
+
+ , Option "c" ["css"]
+ (ReqArg
+ (\arg opt -> do
+ let old = optCSS opt
+ return opt { optCSS = old ++ [arg],
+ optStandalone = True })
+ "CSS")
+ "" -- "Link to CSS style sheet"
+
+ , Option "H" ["include-in-header"]
+ (ReqArg
+ (\arg opt -> do
+ let old = optIncludeInHeader opt
+ text <- readFile arg
+ return opt { optIncludeInHeader = old ++ text,
+ optStandalone = True })
+ "FILENAME")
+ "" -- "File to include at end of header (implies -s)"
+
+ , Option "B" ["include-before-body"]
+ (ReqArg
+ (\arg opt -> do
+ let old = optIncludeBeforeBody opt
+ text <- readFile arg
+ return opt { optIncludeBeforeBody = old ++ text })
+ "FILENAME")
+ "" -- "File to include before document body"
+
+ , Option "A" ["include-after-body"]
+ (ReqArg
+ (\arg opt -> do
+ let old = optIncludeAfterBody opt
+ text <- readFile arg
+ return opt { optIncludeAfterBody = old ++ text })
+ "FILENAME")
+ "" -- "File to include after document body"
+
+ , Option "C" ["custom-header"]
+ (ReqArg
+ (\arg opt -> do
+ text <- readFile arg
+ return opt { optCustomHeader = text,
+ optStandalone = True })
+ "FILENAME")
+ "" -- "File to use for custom header (implies -s)"
+
+ , Option "T" ["title-prefix"]
+ (ReqArg
+ (\arg opt -> return opt { optTitlePrefix = arg,
+ optStandalone = True })
+ "STRING")
+ "" -- "String to prefix to HTML window title"
+
+ , Option "D" ["print-default-header"]
+ (ReqArg
+ (\arg _ -> do
+ let header = case (lookup arg writers) of
+ Just (_, h) -> h
+ Nothing -> error ("Unknown reader: " ++ arg)
+ hPutStr stdout header
+ exitWith ExitSuccess)
+ "FORMAT")
+ "" -- "Print default header for FORMAT"
+#ifdef _CITEPROC
+ , Option "" ["biblio"]
+ (ReqArg
+ (\arg opt -> return opt { optBiblioFile = arg} )
+ "FILENAME")
+ ""
+ , Option "" ["biblio-format"]
+ (ReqArg
+ (\arg opt -> return opt { optBiblioFormat = arg} )
+ "STRING")
+ ""
+ , Option "" ["csl"]
+ (ReqArg
+ (\arg opt -> return opt { optCslFile = arg} )
+ "FILENAME")
+ ""
+#endif
+ , Option "" ["dump-args"]
+ (NoArg
+ (\opt -> return opt { optDumpArgs = True }))
+ "" -- "Print output filename and arguments to stdout."
+
+ , Option "" ["ignore-args"]
+ (NoArg
+ (\opt -> return opt { optIgnoreArgs = True }))
+ "" -- "Ignore command-line arguments."
+
+ , Option "v" ["version"]
+ (NoArg
+ (\_ -> do
+ prg <- getProgName
+ hPutStrLn stdout (prg ++ " " ++ pandocVersion ++ compileInfo ++
+ copyrightMessage)
+ exitWith ExitSuccess ))
+ "" -- "Print version"
+
+ , Option "h" ["help"]
+ (NoArg
+ (\_ -> do
+ prg <- getProgName
+ hPutStr stdout (usageMessage prg options)
+ exitWith ExitSuccess ))
+ "" -- "Show help"
+ ]
+
+-- Returns usage message
+usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
+usageMessage programName = usageInfo
+ (programName ++ " [OPTIONS] [FILES]" ++ "\nInput formats: " ++
+ (intercalate ", " $ map fst readers) ++ "\nOutput formats: " ++
+ (intercalate ", " $ map fst writers) ++ "\nOptions:")
+
+-- Determine default reader based on source file extensions
+defaultReaderName :: [FilePath] -> String
+defaultReaderName [] = "markdown"
+defaultReaderName (x:xs) =
+ case takeExtension (map toLower x) of
+ ".xhtml" -> "html"
+ ".html" -> "html"
+ ".htm" -> "html"
+ ".tex" -> "latex"
+ ".latex" -> "latex"
+ ".ltx" -> "latex"
+ ".rst" -> "rst"
+ ".lhs" -> "markdown+lhs"
+ ".native" -> "native"
+ _ -> defaultReaderName xs
+
+-- Returns True if extension of first source is .lhs
+lhsExtension :: [FilePath] -> Bool
+lhsExtension (x:_) = takeExtension x == ".lhs"
+lhsExtension _ = False
+
+-- Determine default writer based on output file extension
+defaultWriterName :: FilePath -> String
+defaultWriterName "-" = "html" -- no output file
+defaultWriterName x =
+ case takeExtension (map toLower x) of
+ "" -> "markdown" -- empty extension
+ ".tex" -> "latex"
+ ".latex" -> "latex"
+ ".ltx" -> "latex"
+ ".context" -> "context"
+ ".ctx" -> "context"
+ ".rtf" -> "rtf"
+ ".rst" -> "rst"
+ ".s5" -> "s5"
+ ".native" -> "native"
+ ".txt" -> "markdown"
+ ".text" -> "markdown"
+ ".md" -> "markdown"
+ ".markdown" -> "markdown"
+ ".lhs" -> "markdown+lhs"
+ ".texi" -> "texinfo"
+ ".texinfo" -> "texinfo"
+ ".db" -> "docbook"
+ ".odt" -> "odt"
+ ['.',y] | y `elem` ['1'..'9'] -> "man"
+ _ -> "html"
+
+main :: IO ()
+main = do
+
+ rawArgs <- getArgs
+ prg <- getProgName
+ let compatMode = (prg == "hsmarkdown")
+
+ let (actions, args, errors) = if compatMode
+ then ([], rawArgs, [])
+ else getOpt Permute options rawArgs
+
+ unless (null errors) $
+ do name <- getProgName
+ mapM_ (\e -> hPutStrLn stderr e) errors
+ hPutStr stderr (usageMessage name options)
+ exitWith $ ExitFailure 2
+
+ let defaultOpts' = if compatMode
+ then defaultOpts { optReader = "markdown"
+ , optWriter = "html"
+ , optStrict = True }
+ else defaultOpts
+
+ -- thread option data structure through all supplied option actions
+ opts <- foldl (>>=) (return defaultOpts') actions
+
+ let Opt { optTabStop = tabStop
+ , optPreserveTabs = preserveTabs
+ , optStandalone = standalone
+ , optReader = readerName
+ , optWriter = writerName
+ , optParseRaw = parseRaw
+ , optCSS = css
+ , optTableOfContents = toc
+ , optIncludeInHeader = includeHeader
+ , optIncludeBeforeBody = includeBefore
+ , optIncludeAfterBody = includeAfter
+ , optCustomHeader = customHeader
+ , optTitlePrefix = titlePrefix
+ , optOutputFile = outputFile
+ , optNumberSections = numberSections
+ , optIncremental = incremental
+ , optSmart = smart
+ , optHTMLMathMethod = mathMethod
+ , optDumpArgs = dumpArgs
+ , optIgnoreArgs = ignoreArgs
+ , optStrict = strict
+ , optReferenceLinks = referenceLinks
+ , optWrapText = wrap
+ , optSanitizeHTML = sanitize
+ , optEmailObfuscation = obfuscationMethod
+#ifdef _CITEPROC
+ , optBiblioFile = biblioFile
+ , optBiblioFormat = biblioFormat
+ , optCslFile = cslFile
+#endif
+ } = opts
+
+ when dumpArgs $
+ do hPutStrLn stdout outputFile
+ mapM_ (\arg -> hPutStrLn stdout arg) args
+ exitWith ExitSuccess
+
+ let sources = if ignoreArgs then [] else args
+
+ -- assign reader and writer based on options and filenames
+ let readerName' = if null readerName
+ then defaultReaderName sources
+ else readerName
+
+ let writerName' = if null writerName
+ then defaultWriterName outputFile
+ else writerName
+
+ reader <- case (lookup readerName' readers) of
+ Just r -> return r
+ Nothing -> error ("Unknown reader: " ++ readerName')
+
+ (writer, defaultHeader) <- case (lookup writerName' writers) of
+ Just (w,h) -> return (w, h)
+ Nothing -> error ("Unknown writer: " ++ writerName')
+
+ environment <- getEnvironment
+ let columns = case lookup "COLUMNS" environment of
+ Just cols -> read cols
+ Nothing -> stateColumns defaultParserState
+
+ let standalone' = standalone || isNonTextOutput writerName'
+
+#ifdef _CITEPROC
+ refs <- if null biblioFile then return [] else readBiblioFile biblioFile biblioFormat
+#endif
+
+ let startParserState =
+ defaultParserState { stateParseRaw = parseRaw,
+ stateTabStop = tabStop,
+ stateSanitizeHTML = sanitize,
+ stateLiterateHaskell = "+lhs" `isSuffixOf` readerName' ||
+ lhsExtension sources,
+ stateStandalone = standalone',
+#ifdef _CITEPROC
+ stateCitations = map citeKey refs,
+#endif
+ stateSmart = smart || writerName' `elem`
+ ["latex", "context", "man"],
+ stateColumns = columns,
+ stateStrict = strict }
+ let csslink = if null css
+ then ""
+ else concatMap
+ (\f -> "<link rel=\"stylesheet\" href=\"" ++
+ f ++ "\" type=\"text/css\" media=\"all\" />\n")
+ css
+ let header = (if customHeader == "DEFAULT"
+ then defaultHeader
+ else customHeader) ++ csslink ++ includeHeader
+ let writerOptions = WriterOptions { writerStandalone = standalone',
+ writerHeader = header,
+ writerTitlePrefix = titlePrefix,
+ writerTabStop = tabStop,
+ writerTableOfContents = toc &&
+ writerName' /= "s5",
+ writerHTMLMathMethod = mathMethod,
+ writerS5 = (writerName' == "s5"),
+ writerIgnoreNotes = False,
+ writerIncremental = incremental,
+ writerNumberSections = numberSections,
+ writerIncludeBefore = includeBefore,
+ writerIncludeAfter = includeAfter,
+ writerStrictMarkdown = strict,
+ writerReferenceLinks = referenceLinks,
+ writerWrapText = wrap,
+ writerLiterateHaskell = "+lhs" `isSuffixOf` writerName' ||
+ lhsExtension [outputFile],
+ writerEmailObfuscation = if strict
+ then ReferenceObfuscation
+ else obfuscationMethod }
+
+ when (isNonTextOutput writerName' && outputFile == "-") $
+ do hPutStrLn stderr ("Error: Cannot write " ++ writerName ++ " output to stdout.\n" ++
+ "Specify an output file using the -o option.")
+ exitWith $ ExitFailure 5
+
+ let sourceDirRelative = if null sources
+ then ""
+ else takeDirectory (head sources)
+
+ let readSources [] = mapM readSource ["-"]
+ readSources srcs = mapM readSource srcs
+ readSource "-" = getContents
+ readSource src = readFile src
+
+ let convertTabs = tabFilter (if preserveTabs then 0 else tabStop)
+
+ doc <- fmap (reader startParserState . convertTabs . intercalate "\n") (readSources sources)
+
+ doc' <- do
+#ifdef _CITEPROC
+ processBiblio cslFile refs doc
+#else
+ return doc
+#endif
+
+ let writerOutput = writer writerOptions doc' ++ "\n"
+
+ case writerName' of
+ "odt" -> saveOpenDocumentAsODT outputFile sourceDirRelative writerOutput
+ _ -> if outputFile == "-"
+ then putStr writerOutput
+ else writeFile outputFile writerOutput
diff --git a/tests/Diff.hs b/tests/Diff.hs
new file mode 100644
index 000000000..f7e562ee2
--- /dev/null
+++ b/tests/Diff.hs
@@ -0,0 +1,76 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module : Data.Algorithm.Diff
+-- Copyright : (c) Sterling Clover 2008
+-- License : BSD 3 Clause
+-- Maintainer : s.clover@gmail.com
+-- Stability : experimental
+-- Portability : portable
+--
+-- This is an implementation of the O(ND) diff algorithm as described in
+-- \"An O(ND) Difference Algorithm and Its Variations (1986)\"
+-- <http://citeseer.ist.psu.edu/myers86ond.html>. It is O(mn) in space.
+-- The algorithm is the same one used by standared Unix diff.
+-- The assumption is that users of this library will want to diff over
+-- interesting things or peform interesting tasks with the results
+-- (given that, otherwise, they would simply use the standard Unix diff
+-- utility). Thus no attempt is made to present a fancier API to aid
+-- in doing standard and uninteresting things with the results.
+-----------------------------------------------------------------------------
+
+module Diff (DI(..), getDiff, getGroupedDiff) where
+import Data.Array
+import Data.List
+
+-- | Difference Indicator. A value is either from the First list, the Second
+-- or from Both.
+data DI = F | S | B deriving (Show, Eq)
+
+data DL = DL {poi::Int, poj::Int, path::[DI]} deriving (Show, Eq)
+
+instance Ord DL where x <= y = poi x <= poi y
+
+canDiag :: (Eq a) => [a] -> [a] -> Int -> Int -> (Int, Int) -> Bool
+canDiag as bs lena lenb = \(i,j) ->
+ if i < lena && j < lenb then arAs ! i == arBs ! j else False
+ where arAs = listArray (0,lena - 1) as
+ arBs = listArray (0,lenb - 1) bs
+
+chunk :: Int -> [a] -> [[a]]
+chunk x = unfoldr (\a -> case splitAt x a of ([],[]) -> Nothing; a' -> Just a')
+
+dstep :: ((Int,Int)->Bool) -> [DL] -> [DL]
+dstep cd dls = map maximum $ [hd]:(chunk 2 rst)
+ where (hd:rst) = concatMap extend dls
+ extend dl = let pdl = path dl
+ in [addsnake cd $ dl {poi=poi dl + 1, path=(F : pdl)},
+ addsnake cd $ dl {poj=poj dl + 1, path=(S : pdl)}]
+
+addsnake :: ((Int,Int)->Bool) -> DL -> DL
+addsnake cd dl
+ | cd (pi, pj) = addsnake cd $
+ dl {poi = pi + 1, poj = pj + 1, path=(B : path dl)}
+ | otherwise = dl
+ where pi = poi dl; pj = poj dl
+
+lcs :: (Eq a) => [a] -> [a] -> [DI]
+lcs as bs = path . head . dropWhile (\dl -> poi dl /= lena || poj dl /= lenb) .
+ concat . iterate (dstep cd) . (:[]) . addsnake cd $
+ DL {poi=0,poj=0,path=[]}
+ where cd = canDiag as bs lena lenb
+ lena = length as; lenb = length bs
+
+-- | Takes two lists and returns a list indicating the differences
+-- between them.
+getDiff :: (Eq t) => [t] -> [t] -> [(DI, t)]
+getDiff a b = markup a b . reverse $ lcs a b
+ where markup (x:xs) ys (F:ds) = (F, x) : markup xs ys ds
+ markup xs (y:ys) (S:ds) = (S, y) : markup xs ys ds
+ markup (x:xs) (_:ys) (B:ds) = (B, x) : markup xs ys ds
+ markup _ _ _ = []
+
+-- | Takes two lists and returns a list indicating the differences
+-- between them, grouped into chunks.
+getGroupedDiff :: (Eq t) => [t] -> [t] -> [(DI, [t])]
+getGroupedDiff a b = map go . groupBy (\x y -> fst x == fst y) $ getDiff a b
+ where go ((d,x) : xs) = (d, x : map snd xs)
diff --git a/tests/RunTests.hs b/tests/RunTests.hs
new file mode 100644
index 000000000..90e2276b2
--- /dev/null
+++ b/tests/RunTests.hs
@@ -0,0 +1,163 @@
+{-# OPTIONS_GHC -Wall #-}
+-- RunTests.hs - run test suite for pandoc
+-- This script is designed to be run from the tests directory.
+-- It assumes the pandoc executable is in dist/build/pandoc.
+--
+-- runhaskell -i.. RunTests.hs [lhs]
+--
+-- If the lhs argument is provided, tests for lhs support will be
+-- run. These presuppose that pandoc has been compiled with the
+-- -fhighlighting flag, so these tests are not run by default.
+
+module Main where
+import System.Exit
+import System.IO.UTF8
+import System.IO ( openTempFile, stderr )
+import Prelude hiding ( putStrLn, putStr, readFile )
+import System.Process ( runProcess, waitForProcess )
+import System.FilePath ( (</>), (<.>) )
+import System.Directory
+import System.Environment
+import System.Exit
+import Text.Printf
+import Diff
+
+pandocPath :: FilePath
+pandocPath = ".." </> "dist" </> "build" </> "pandoc" </> "pandoc"
+
+data TestResult = TestPassed
+ | TestError ExitCode
+ | TestFailed [(DI, String)]
+ deriving (Eq)
+
+instance Show TestResult where
+ show TestPassed = "PASSED"
+ show (TestError ec) = "ERROR " ++ show ec
+ show (TestFailed d) = "FAILED\n" ++ showDiff d
+
+showDiff :: [(DI, String)] -> String
+showDiff [] = ""
+showDiff ((F, ln) : ds) = "|TEST| " ++ ln ++ "\n" ++ showDiff ds
+showDiff ((S, ln) : ds) = "|NORM| " ++ ln ++ "\n" ++ showDiff ds
+showDiff ((B, _ ) : ds) = showDiff ds
+
+writerFormats :: [String]
+writerFormats = [ "native"
+ , "html"
+ , "docbook"
+ , "opendocument"
+ , "latex"
+ , "context"
+ , "texinfo"
+ , "man"
+ , "markdown"
+ , "rst"
+ , "mediawiki"
+ , "rtf"
+ ]
+
+lhsWriterFormats :: [String]
+lhsWriterFormats = [ "markdown"
+ , "markdown+lhs"
+ , "rst"
+ , "rst+lhs"
+ , "latex"
+ , "latex+lhs"
+ , "html"
+ , "html+lhs"
+ ]
+
+lhsReaderFormats :: [String]
+lhsReaderFormats = [ "markdown+lhs"
+ , "rst+lhs"
+ , "latex+lhs"
+ ]
+
+main :: IO ()
+main = do
+ args <- getArgs
+ let runLhsTests = "lhs" `elem` args
+ r1s <- mapM runWriterTest writerFormats
+ r2 <- runS5WriterTest "basic" ["-s"] "s5"
+ r3 <- runS5WriterTest "fancy" ["-s","-m","-i"] "s5"
+ r4 <- runS5WriterTest "fragment" [] "html"
+ r5 <- runS5WriterTest "inserts" ["-s", "-H", "insert",
+ "-B", "insert", "-A", "insert", "-c", "main.css"] "html"
+ r6 <- runTest "markdown reader" ["-r", "markdown", "-w", "native", "-s", "-S"]
+ "testsuite.txt" "testsuite.native"
+ r7 <- runTest "markdown reader (tables)" ["-r", "markdown", "-w", "native"]
+ "tables.txt" "tables.native"
+ r7a <- runTest "markdown reader (more)" ["-r", "markdown", "-w", "native"]
+ "markdown-reader-more.txt" "markdown-reader-more.native"
+ r8 <- runTest "rst reader" ["-r", "rst", "-w", "native", "-s", "-S"]
+ "rst-reader.rst" "rst-reader.native"
+ r9 <- runTest "html reader" ["-r", "html", "-w", "native", "-s"]
+ "html-reader.html" "html-reader.native"
+ r10 <- runTest "latex reader" ["-r", "latex", "-w", "native", "-s", "-R"]
+ "latex-reader.latex" "latex-reader.native"
+ r11 <- runTest "native reader" ["-r", "native", "-w", "native", "-s"]
+ "testsuite.native" "testsuite.native"
+ r12s <- if runLhsTests
+ then mapM runLhsWriterTest lhsWriterFormats
+ else putStrLn "Skipping lhs writer tests because they presuppose highlighting support" >> return []
+ r13s <- if runLhsTests
+ then mapM runLhsReaderTest lhsReaderFormats
+ else putStrLn "Skipping lhs reader tests because they presuppose highlighting support" >> return []
+ let results = r1s ++ [r2, r3, r4, r5, r6, r7, r7a, r8, r9, r10, r11] ++ r12s ++ r13s
+ if all id results
+ then do
+ putStrLn "\nAll tests passed."
+ exitWith ExitSuccess
+ else do
+ let failures = length $ filter not results
+ putStrLn $ "\n" ++ show failures ++ " tests failed."
+ exitWith (ExitFailure failures)
+
+-- makes sure file is fully closed after reading
+readFile' :: FilePath -> IO String
+readFile' f = do s <- readFile f
+ return $! (length s `seq` s)
+
+runLhsWriterTest :: String -> IO Bool
+runLhsWriterTest format =
+ runTest ("(lhs) " ++ format ++ " writer") ["-r", "native", "-s", "-w", format] "lhs-test.native" ("lhs-test" <.> format)
+
+runLhsReaderTest :: String -> IO Bool
+runLhsReaderTest format =
+ runTest ("(lhs) " ++ format ++ " reader") ["-r", format, "-w", "html+lhs"] ("lhs-test" <.> format) "lhs-test.fragment.html+lhs"
+
+runWriterTest :: String -> IO Bool
+runWriterTest format = do
+ r1 <- runTest (format ++ " writer") ["-r", "native", "-s", "-w", format] "testsuite.native" ("writer" <.> format)
+ r2 <- runTest (format ++ " writer (tables)") ["-r", "native", "-w", format] "tables.native" ("tables" <.> format)
+ return (r1 && r2)
+
+runS5WriterTest :: String -> [String] -> String -> IO Bool
+runS5WriterTest modifier opts format = runTest (format ++ " writer (" ++ modifier ++ ")")
+ (["-r", "native", "-w", format] ++ opts) "s5.native" ("s5." ++ modifier <.> "html")
+
+-- | Run a test, return True if test passed.
+runTest :: String -- ^ Title of test
+ -> [String] -- ^ Options to pass to pandoc
+ -> String -- ^ Input filepath
+ -> FilePath -- ^ Norm (for test results) filepath
+ -> IO Bool
+runTest testname opts inp norm = do
+ (outputPath, hOut) <- openTempFile "" "pandoc-test"
+ let inpPath = inp
+ let normPath = norm
+ -- Note: COLUMNS must be set for markdown table reader
+ ph <- runProcess pandocPath (opts ++ [inpPath]) Nothing (Just [("COLUMNS", "80")]) Nothing (Just hOut) (Just stderr)
+ ec <- waitForProcess ph
+ result <- if ec == ExitSuccess
+ then do
+ -- filter \r so the tests will work on Windows machines
+ outputContents <- readFile' outputPath >>= return . filter (/='\r')
+ normContents <- readFile' normPath >>= return . filter (/='\r')
+ if outputContents == normContents
+ then return TestPassed
+ else return $ TestFailed $ getDiff (lines outputContents) (lines normContents)
+ else return $ TestError ec
+ removeFile outputPath
+ putStrLn $ printf "%-28s ---> %s" testname (show result)
+ return (result == TestPassed)
diff --git a/tests/bodybg.gif b/tests/bodybg.gif
new file mode 100644
index 000000000..5f448a16f
--- /dev/null
+++ b/tests/bodybg.gif
Binary files differ
diff --git a/tests/html-reader.html b/tests/html-reader.html
new file mode 100644
index 000000000..da6c075b3
--- /dev/null
+++ b/tests/html-reader.html
@@ -0,0 +1,463 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="generator" content="pandoc" />
+<style type="text/css">
+div.pandocNote { border-left: 1px solid grey; padding-left: 1em; }
+span.pandocNoteRef { vertical-align: super; font-size: 80%; }
+span.pandocNoteMarker { }
+</style>
+<title>Pandoc Test Suite</title>
+</head>
+<body>
+<h1 class="title">Pandoc Test Suite</h1>
+<p>This is a set of tests for pandoc. Most of them are adapted from John Gruber's markdown test suite.</p>
+<hr />
+<h1>Headers</h1>
+<h2>Level 2 with an <a href="/url">embedded link</a></h2>
+<h3>Level 3 with <em>emphasis</em></h3>
+<h4>Level 4</h4>
+<h5>Level 5</h5>
+<h1>Level 1</h1>
+<h2>Level 2 with <em>emphasis</em></h2>
+<h3>Level 3</h3>
+<p>with no blank line</p>
+<h2>Level 2</h2>
+<p>with no blank line</p>
+<hr />
+<h1>Paragraphs</h1>
+<p>Here's a regular paragraph.</p>
+<p>In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.</p>
+<p>Here's one with a bullet. * criminey.</p>
+<p>There should be a hard line break<br />
+ here.</p>
+<hr />
+<h1>Block Quotes</h1>
+<p>E-mail style:</p>
+<blockquote>
+<p>This is a block quote. It is pretty short.</p>
+</blockquote>
+<blockquote>
+<p>Code in a block quote:</p>
+<pre><code>sub status {
+ print "working";
+}
+</code></pre>
+<p>A list:</p>
+<ol>
+<li>item one</li>
+<li>item two</li>
+</ol>
+<p>Nested block quotes:</p>
+<blockquote>
+<p>nested</p>
+</blockquote>
+<blockquote>
+<p>nested</p>
+</blockquote>
+</blockquote>
+<p>This should not be a block quote: 2 &gt; 1.</p>
+<p>Box-style:</p>
+<blockquote>
+<p>Example:</p>
+<pre><code>sub status {
+ print "working";
+}
+</code></pre>
+</blockquote>
+<blockquote>
+<ol>
+<li>do laundry</li>
+<li>take out the trash</li>
+</ol>
+</blockquote>
+<p>Here's a nested one:</p>
+<blockquote>
+<p>Joe said:</p>
+<blockquote>
+<p>Don't quote me.</p>
+</blockquote>
+</blockquote>
+<p>And a following paragraph.</p>
+<hr />
+<h1>Code Blocks</h1>
+<p>Code:</p>
+<pre><code>---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+</code></pre>
+<p>And:</p>
+<pre><code> this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+</code></pre>
+<hr />
+<h1>Lists</h1>
+<h2>Unordered</h2>
+<p>Asterisks tight:</p>
+<ul>
+<li>asterisk 1</li>
+<li>asterisk 2</li>
+<li>asterisk 3</li>
+</ul>
+<p>Asterisks loose:</p>
+<ul>
+<li><p>asterisk 1</p>
+</li>
+<li><p>asterisk 2</p>
+</li>
+<li><p>asterisk 3</p>
+</li>
+</ul>
+<p>Pluses tight:</p>
+<ul>
+<li>Plus 1</li>
+<li>Plus 2</li>
+<li>Plus 3</li>
+</ul>
+<p>Pluses loose:</p>
+<ul>
+<li><p>Plus 1</p>
+</li>
+<li><p>Plus 2</p>
+</li>
+<li><p>Plus 3</p>
+</li>
+</ul>
+<p>Minuses tight:</p>
+<ul>
+<li>Minus 1</li>
+<li>Minus 2</li>
+<li>Minus 3</li>
+</ul>
+<p>Minuses loose:</p>
+<ul>
+<li><p>Minus 1</p>
+</li>
+<li><p>Minus 2</p>
+</li>
+<li><p>Minus 3</p>
+</li>
+</ul>
+<h2>Ordered</h2>
+<p>Tight:</p>
+<ol>
+<li>First</li>
+<li>Second</li>
+<li>Third</li>
+</ol>
+<p>and:</p>
+<ol>
+<li>One</li>
+<li>Two</li>
+<li>Three</li>
+</ol>
+<p>Loose using tabs:</p>
+<ol>
+<li><p>First</p>
+</li>
+<li><p>Second</p>
+</li>
+<li><p>Third</p>
+</li>
+</ol>
+<p>and using spaces:</p>
+<ol>
+<li><p>One</p>
+</li>
+<li><p>Two</p>
+</li>
+<li><p>Three</p>
+</li>
+</ol>
+<p>Multiple paragraphs:</p>
+<ol>
+<li><p>Item 1, graf one.</p>
+<p>Item 1. graf two. The quick brown fox jumped over the lazy dog's back.</p>
+</li>
+<li><p>Item 2.</p>
+</li>
+<li><p>Item 3.</p>
+</li>
+</ol>
+<h2>Nested</h2>
+<ul>
+<li>Tab<ul>
+<li>Tab<ul>
+<li>Tab</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+<p>Here's another:</p>
+<ol>
+<li>First</li>
+<li>Second:<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul>
+</li>
+<li>Third</li>
+</ol>
+<p>Same thing but with paragraphs:</p>
+<ol>
+<li><p>First</p>
+</li>
+<li><p>Second:</p>
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul>
+</li>
+<li><p>Third</p>
+</li>
+</ol>
+<h2>Tabs and spaces</h2>
+<ul>
+<li><p>this is a list item indented with tabs</p>
+</li>
+<li><p>this is a list item indented with spaces</p>
+<ul>
+<li><p>this is an example list item indented with tabs</p>
+</li>
+<li><p>this is an example list item indented with spaces</p>
+</li>
+</ul>
+</li>
+</ul>
+<h2 id="fancy-list-markers"
+ >Fancy list markers</h2
+ ><ol start="2" class="decimal"
+ ><li
+ >begins with 2</li
+ ><li
+ ><p
+ >and now 3</p
+ ><p
+ >with a continuation</p
+ ><ol start="4" class="lower-roman"
+ ><li
+ >sublist with roman numerals, starting with 4</li
+ ><li
+ >more items<ol class="upper-alpha"
+ ><li
+ >a subsublist</li
+ ><li
+ >a subsublist</li
+ ></ol
+ ></li
+ ></ol
+ ></li
+ ></ol
+ ><p
+ >Nesting:</p
+ ><ol class="upper-alpha"
+ ><li
+ >Upper Alpha<ol class="upper-roman"
+ ><li
+ >Upper Roman.<ol start="6" class="decimal"
+ ><li
+ >Decimal start with 6<ol start="3" class="lower-alpha"
+ ><li
+ >Lower alpha with paren</li
+ ></ol
+ ></li
+ ></ol
+ ></li
+ ></ol
+ ></li
+ ></ol
+ ><p
+ >Autonumbering:</p
+ ><ol
+ ><li
+ >Autonumber.</li
+ ><li
+ >More.<ol
+ ><li
+ >Nested.</li
+ ></ol
+ ></li
+ ></ol
+ ><hr
+ />
+<h2>Definition</h2>
+<dl>
+ <dt>Violin</dt>
+ <dd>Stringed musical instrument.</dd>
+ <dd>Torture device.</dd>
+ <dt>Cello</dt>
+ <dt>Violoncello</dt>
+ <dd>Low-voiced stringed instrument.</dd>
+</dl>
+<hr />
+<h1>HTML Blocks</h1>
+<p>Simple block on one line:</p>
+foo<p>And nested without indentation:</p>
+foobar<p>Interpreted markdown in a table:</p>
+This is <em>emphasized</em>. And this is <strong>strong</strong><p>Here's a simple block:</p>
+foo<p>This should be a code block, though:</p>
+<pre><code>&lt;div>
+ foo
+&lt;/div>
+</code></pre>
+<p>As should this:</p>
+<pre><code>&lt;div>foo&lt;/div>
+</code></pre>
+<p>Now, nested:</p>
+foo<p>This should just be an HTML comment:</p>
+<p>Multiline:</p>
+<p>Code block:</p>
+<pre><code>&lt;!-- Comment -->
+</code></pre>
+<p>Just plain comment, with trailing spaces on the line:</p>
+<p>Code:</p>
+<pre><code>&lt;hr />
+</code></pre>
+<p>Hr's:</p>
+<hr />
+<hr />
+<hr />
+<hr />
+<hr />
+<hr />
+<hr />
+<hr />
+<hr />
+<hr />
+<h1>Inline Markup</h1>
+<p>This is <em>emphasized</em>, and so <em>is this</em>.</p>
+<p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p>
+<p>An <em><a href="/url">emphasized link</a></em>.</p>
+<p><strong><em>This is strong and em.</em></strong></p>
+<p>So is <strong><em>this</em></strong> word.</p>
+<p><strong><em>This is strong and em.</em></strong></p>
+<p>So is <strong><em>this</em></strong> word.</p>
+<p>This is code: <code>></code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html></code>.</p>
+<hr />
+<h1>Smart quotes, ellipses, dashes</h1>
+<p>"Hello," said the spider. "'Shelob' is my name."</p>
+<p>'A', 'B', and 'C' are letters.</p>
+<p>'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'</p>
+<p>'He said, "I want to go."' Were you alive in the 70's?</p>
+<p>Here is some quoted '<code>code</code>' and a "<a href="http://example.com/?foo=1&amp;bar=2">quoted link</a>".</p>
+<p>Some dashes: one---two --- three--four -- five.</p>
+<p>Dashes between numbers: 5-7, 255-66, 1987-1999.</p>
+<p>Ellipses...and. . .and . . . .</p>
+<hr />
+<h1>LaTeX</h1>
+<ul>
+<li>\cite[22-23]{smith.1899}</li>
+<li>\doublespacing</li>
+<li>$2+2=4$</li>
+<li>$x \in y$</li>
+<li>$\alpha \wedge \omega$</li>
+<li>$223$</li>
+<li>$p$-Tree</li>
+<li>$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</li>
+<li>Here's one that has a line break in it: $\alpha + \omega \times x^2$.</li>
+</ul>
+<p>These shouldn't be math:</p>
+<ul>
+<li>To get the famous equation, write <code>$e = mc^2$</code>.</li>
+<li>$22,000 is a <em>lot</em> of money. So is $34,000. (It worked if "lot" is emphasized.)</li>
+<li>Escaped <code>$</code>: $73 <em>this should be emphasized</em> 23$.</li>
+</ul>
+<p>Here's a LaTeX table:</p>
+<p>\begin{tabular}{|l|l|}\hline Animal &amp; Number \\ \hline Dog &amp; 2 \\ Cat &amp; 1 \\ \hline \end{tabular}</p>
+<hr />
+<h1>Special Characters</h1>
+<p>Here is some unicode:</p>
+<ul>
+<li>I hat: Î</li>
+<li>o umlaut: ö</li>
+<li>section: §</li>
+<li>set membership: ∈</li>
+<li>copyright: ©</li>
+</ul>
+<p>AT&amp;T has an ampersand in their name.</p>
+<p>AT&amp;T is another way to write it.</p>
+<p>This &amp; that.</p>
+<p>4 &lt; 5.</p>
+<p>6 &gt; 5.</p>
+<p>Backslash: \</p>
+<p>Backtick: `</p>
+<p>Asterisk: *</p>
+<p>Underscore: _</p>
+<p>Left brace: {</p>
+<p>Right brace: }</p>
+<p>Left bracket: [</p>
+<p>Right bracket: ]</p>
+<p>Left paren: (</p>
+<p>Right paren: )</p>
+<p>Greater-than: &gt;</p>
+<p>Hash: #</p>
+<p>Period: .</p>
+<p>Bang: !</p>
+<p>Plus: +</p>
+<p>Minus: -</p>
+<hr />
+<h1>Links</h1>
+<h2>Explicit</h2>
+<p>Just a <a href="/url/">URL</a>.</p>
+<p><a href="/url/" title="title">URL and title</a>.</p>
+<p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p>
+<p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p>
+<p><a href="/url/" title="title with &quot;quotes&quot; in it">URL and title</a></p>
+<p><a href="/url/" title="title with single quotes">URL and title</a></p>
+Email link (nobody [at] nowhere.net)<p><a href="">Empty</a>.</p>
+<h2>Reference</h2>
+<p>Foo <a href="/url/">bar</a>.</p>
+<p>Foo <a href="/url/">bar</a>.</p>
+<p>Foo <a href="/url/">bar</a>.</p>
+<p>With <a href="/url/">embedded [brackets]</a>.</p>
+<p><a href="/url/">b</a> by itself should be a link.</p>
+<p>Indented <a href="/url">once</a>.</p>
+<p>Indented <a href="/url">twice</a>.</p>
+<p>Indented <a href="/url">thrice</a>.</p>
+<p>This should [not] be a link.</p>
+<pre><code>[not]: /url
+</code></pre>
+<p>Foo <a href="/url/" title="Title with &quot;quotes&quot; inside">bar</a>.</p>
+<p>Foo <a href="/url/" title="Title with &quot;quote&quot; inside">biz</a>.</p>
+<h2>With ampersands</h2>
+<p>Here's a <a href="http://example.com/?foo=1&amp;bar=2">link with an ampersand in the URL</a>.</p>
+<p>Here's a link with an amersand in the link text: <a href="http://att.com/" title="AT&T">AT&amp;T</a>.</p>
+<p>Here's an <a href="/script?foo=1&amp;bar=2">inline link</a>.</p>
+<p>Here's an <a href="/script?foo=1&amp;bar=2">inline link in pointy braces</a>.</p>
+<h2>Autolinks</h2>
+<p>With an ampersand: <a href="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</a></p>
+<ul>
+<li>In a list?</li>
+<li><a href="http://example.com/">http://example.com/</a></li>
+<li>It should.</li>
+</ul>
+An e-mail address: nobody [at] nowhere.net<blockquote>
+<p>Blockquoted: <a href="http://example.com/">http://example.com/</a></p>
+</blockquote>
+<p>Auto-links should not occur here: <code>&lt;http://example.com/></code></p>
+<pre><code>or here: &lt;http://example.com/>
+</code></pre>
+<hr />
+<h1>Images</h1>
+<p>From "Voyage dans la Lune" by Georges Melies (1902):</p>
+<p><img src="lalune.jpg" title="Voyage dans la Lune" alt="lalune"></p>
+<p>Here is a movie <img src="movie.jpg" alt="movie"> icon.</p>
+<hr />
+<h1>Footnotes</h1>
+<p>Here is a footnote reference<a href="#note_1">(1)</a>, and another<a href="#note_longnote">(longnote)</a>. This should <em>not</em> be a footnote reference, because it contains a space^(my note).</p>
+<p><a href="#ref_1">(1)</a> Here is the footnote. It can go anywhere in the document, not just at the end.</p>
+<p><a href="#ref_longnote">(longnote)</a> Here's the other note. This one contains multiple blocks.</p>
+<p>Caret characters are used to indicate that the blocks all belong to a single footnote (as with block quotes).</p>
+<pre><code> { &lt;code> }
+</code></pre>
+<p>If you want, you can use a caret at the beginning of every line, as with blockquotes, but all that you need is a caret at the beginning of the first line of the block and any preceding blank lines.</p>
+</body>
+</html>
diff --git a/tests/html-reader.native b/tests/html-reader.native
new file mode 100644
index 000000000..ae371f1c0
--- /dev/null
+++ b/tests/html-reader.native
@@ -0,0 +1,346 @@
+Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] [] "")
+[ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber's",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
+, HorizontalRule
+, Header 1 [Str "Headers"]
+, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] ("/url","")]
+, Header 3 [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
+, Header 4 [Str "Level",Space,Str "4"]
+, Header 5 [Str "Level",Space,Str "5"]
+, Header 1 [Str "Level",Space,Str "1"]
+, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
+, Header 3 [Str "Level",Space,Str "3"]
+, Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+, Header 2 [Str "Level",Space,Str "2"]
+, Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+, HorizontalRule
+, Header 1 [Str "Paragraphs"]
+, Para [Str "Here's",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
+, Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",Space,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item.",Space,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",Space,Str "list",Space,Str "item."]
+, Para [Str "Here's",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",Space,Str "*",Space,Str "criminey."]
+, Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Space,Str "here."]
+, HorizontalRule
+, Header 1 [Str "Block",Space,Str "Quotes"]
+, Para [Str "E-mail",Space,Str "style:"]
+, BlockQuote
+ [ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",Space,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."] ]
+
+, BlockQuote
+ [ Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
+ , CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
+ , Para [Str "A",Space,Str "list:"]
+ , OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "item",Space,Str "one"] ]
+ , [ Plain [Str "item",Space,Str "two"] ] ]
+ , Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
+ , BlockQuote
+ [ Para [Str "nested"] ]
+
+ , BlockQuote
+ [ Para [Str "nested"] ]
+ ]
+, Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",Space,Str ">",Space,Str "1."]
+, Para [Str "Box-style:"]
+, BlockQuote
+ [ Para [Str "Example:"]
+ , CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}" ]
+, BlockQuote
+ [ OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "do",Space,Str "laundry"] ]
+ , [ Plain [Str "take",Space,Str "out",Space,Str "the",Space,Str "trash"] ] ] ]
+, Para [Str "Here's",Space,Str "a",Space,Str "nested",Space,Str "one:"]
+, BlockQuote
+ [ Para [Str "Joe",Space,Str "said:"]
+ , BlockQuote
+ [ Para [Str "Don't",Space,Str "quote",Space,Str "me."] ]
+ ]
+, Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
+, HorizontalRule
+, Header 1 [Str "Code",Space,Str "Blocks"]
+, Para [Str "Code:"]
+, CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
+, Para [Str "And:"]
+, CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
+, HorizontalRule
+, Header 1 [Str "Lists"]
+, Header 2 [Str "Unordered"]
+, Para [Str "Asterisks",Space,Str "tight:"]
+, BulletList
+ [ [ Plain [Str "asterisk",Space,Str "1"] ]
+ , [ Plain [Str "asterisk",Space,Str "2"] ]
+ , [ Plain [Str "asterisk",Space,Str "3"] ] ]
+, Para [Str "Asterisks",Space,Str "loose:"]
+, BulletList
+ [ [ Para [Str "asterisk",Space,Str "1"] ]
+ , [ Para [Str "asterisk",Space,Str "2"] ]
+ , [ Para [Str "asterisk",Space,Str "3"] ] ]
+, Para [Str "Pluses",Space,Str "tight:"]
+, BulletList
+ [ [ Plain [Str "Plus",Space,Str "1"] ]
+ , [ Plain [Str "Plus",Space,Str "2"] ]
+ , [ Plain [Str "Plus",Space,Str "3"] ] ]
+, Para [Str "Pluses",Space,Str "loose:"]
+, BulletList
+ [ [ Para [Str "Plus",Space,Str "1"] ]
+ , [ Para [Str "Plus",Space,Str "2"] ]
+ , [ Para [Str "Plus",Space,Str "3"] ] ]
+, Para [Str "Minuses",Space,Str "tight:"]
+, BulletList
+ [ [ Plain [Str "Minus",Space,Str "1"] ]
+ , [ Plain [Str "Minus",Space,Str "2"] ]
+ , [ Plain [Str "Minus",Space,Str "3"] ] ]
+, Para [Str "Minuses",Space,Str "loose:"]
+, BulletList
+ [ [ Para [Str "Minus",Space,Str "1"] ]
+ , [ Para [Str "Minus",Space,Str "2"] ]
+ , [ Para [Str "Minus",Space,Str "3"] ] ]
+, Header 2 [Str "Ordered"]
+, Para [Str "Tight:"]
+, OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "First"] ]
+ , [ Plain [Str "Second"] ]
+ , [ Plain [Str "Third"] ] ]
+, Para [Str "and:"]
+, OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "One"] ]
+ , [ Plain [Str "Two"] ]
+ , [ Plain [Str "Three"] ] ]
+, Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
+, OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Para [Str "First"] ]
+ , [ Para [Str "Second"] ]
+ , [ Para [Str "Third"] ] ]
+, Para [Str "and",Space,Str "using",Space,Str "spaces:"]
+, OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Para [Str "One"] ]
+ , [ Para [Str "Two"] ]
+ , [ Para [Str "Three"] ] ]
+, Para [Str "Multiple",Space,Str "paragraphs:"]
+, OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
+ , Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog's",Space,Str "back."] ], [ Para [Str "Item",Space,Str "2."] ]
+ , [ Para [Str "Item",Space,Str "3."] ] ]
+, Header 2 [Str "Nested"]
+, BulletList
+ [ [ Plain [Str "Tab"]
+ , BulletList
+ [ [ Plain [Str "Tab"]
+ , BulletList
+ [ [ Plain [Str "Tab"] ]
+ ] ] ] ] ]
+, Para [Str "Here's",Space,Str "another:"]
+, OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "First"] ]
+ , [ Plain [Str "Second:"]
+ , BulletList
+ [ [ Plain [Str "Fee"] ]
+ , [ Plain [Str "Fie"] ]
+ , [ Plain [Str "Foe"] ] ] ], [ Plain [Str "Third"] ] ]
+, Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
+, OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Para [Str "First"] ]
+ , [ Para [Str "Second:"]
+ , BulletList
+ [ [ Plain [Str "Fee"] ]
+ , [ Plain [Str "Fie"] ]
+ , [ Plain [Str "Foe"] ] ] ], [ Para [Str "Third"] ] ]
+, Header 2 [Str "Tabs",Space,Str "and",Space,Str "spaces"]
+, BulletList
+ [ [ Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"] ]
+ , [ Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]
+ , BulletList
+ [ [ Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"] ]
+ , [ Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"] ] ] ] ]
+, Header 2 [Str "Fancy",Space,Str "list",Space,Str "markers"]
+, OrderedList (2,Decimal,DefaultDelim)
+ [ [ Plain [Str "begins",Space,Str "with",Space,Str "2"] ]
+ , [ Para [Str "and",Space,Str "now",Space,Str "3"]
+ , Para [Str "with",Space,Str "a",Space,Str "continuation"]
+ , OrderedList (4,LowerRoman,DefaultDelim)
+ [ [ Plain [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",Space,Str "starting",Space,Str "with",Space,Str "4"] ]
+ , [ Plain [Str "more",Space,Str "items"]
+ , OrderedList (1,UpperAlpha,DefaultDelim)
+ [ [ Plain [Str "a",Space,Str "subsublist"] ]
+ , [ Plain [Str "a",Space,Str "subsublist"] ] ] ] ] ] ]
+, Para [Str "Nesting:"]
+, OrderedList (1,UpperAlpha,DefaultDelim)
+ [ [ Plain [Str "Upper",Space,Str "Alpha"]
+ , OrderedList (1,UpperRoman,DefaultDelim)
+ [ [ Plain [Str "Upper",Space,Str "Roman."]
+ , OrderedList (6,Decimal,DefaultDelim)
+ [ [ Plain [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
+ , OrderedList (3,LowerAlpha,DefaultDelim)
+ [ [ Plain [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"] ]
+ ] ] ] ] ] ] ]
+, Para [Str "Autonumbering:"]
+, OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "Autonumber."] ]
+ , [ Plain [Str "More."]
+ , OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "Nested."] ]
+ ] ] ]
+, HorizontalRule
+, Header 2 [Str "Definition"]
+, DefinitionList
+ [ ([Str "Violin"],
+ [ Plain [Str "Stringed",Space,Str "musical",Space,Str "instrument."]
+ , Plain [Str "Torture",Space,Str "device."] ] ),
+ ([Str "Cello",LineBreak,Str "Violoncello"],
+ [ Plain [Str "Low-voiced",Space,Str "stringed",Space,Str "instrument."] ]
+ ) ]
+, HorizontalRule
+, Header 1 [Str "HTML",Space,Str "Blocks"]
+, Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line:"]
+, Plain [Str "foo"]
+, Para [Str "And",Space,Str "nested",Space,Str "without",Space,Str "indentation:"]
+, Plain [Str "foobar"]
+, Para [Str "Interpreted",Space,Str "markdown",Space,Str "in",Space,Str "a",Space,Str "table:"]
+, Plain [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ".",Space,Str "And",Space,Str "this",Space,Str "is",Space,Strong [Str "strong"]]
+, Para [Str "Here's",Space,Str "a",Space,Str "simple",Space,Str "block:"]
+, Plain [Str "foo"]
+, Para [Str "This",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "code",Space,Str "block,",Space,Str "though:"]
+, CodeBlock ("",[],[]) "<div>\n foo\n</div>"
+, Para [Str "As",Space,Str "should",Space,Str "this:"]
+, CodeBlock ("",[],[]) "<div>foo</div>"
+, Para [Str "Now,",Space,Str "nested:"]
+, Plain [Str "foo"]
+, Para [Str "This",Space,Str "should",Space,Str "just",Space,Str "be",Space,Str "an",Space,Str "HTML",Space,Str "comment:"]
+, Para [Str "Multiline:"]
+, Para [Str "Code",Space,Str "block:"]
+, CodeBlock ("",[],[]) "<!-- Comment -->"
+, Para [Str "Just",Space,Str "plain",Space,Str "comment,",Space,Str "with",Space,Str "trailing",Space,Str "spaces",Space,Str "on",Space,Str "the",Space,Str "line:"]
+, Para [Str "Code:"]
+, CodeBlock ("",[],[]) "<hr />"
+, Para [Str "Hr's:"]
+, HorizontalRule
+, HorizontalRule
+, HorizontalRule
+, HorizontalRule
+, HorizontalRule
+, HorizontalRule
+, HorizontalRule
+, HorizontalRule
+, HorizontalRule
+, HorizontalRule
+, Header 1 [Str "Inline",Space,Str "Markup"]
+, Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
+, Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
+, Para [Str "An",Space,Emph [Link [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
+, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+, Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+, Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+, Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ">",Str ",",Space,Code "$",Str ",",Space,Code "\\",Str ",",Space,Code "\\$",Str ",",Space,Code "<html>",Str "."]
+, HorizontalRule
+, Header 1 [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
+, Para [Str "\"Hello,\"",Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Str "\"'Shelob'",Space,Str "is",Space,Str "my",Space,Str "name.\""]
+, Para [Str "'A',",Space,Str "'B',",Space,Str "and",Space,Str "'C'",Space,Str "are",Space,Str "letters."]
+, Para [Str "'Oak,'",Space,Str "'elm,'",Space,Str "and",Space,Str "'beech'",Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",Space,Str "So",Space,Str "is",Space,Str "'pine.'"]
+, Para [Str "'He",Space,Str "said,",Space,Str "\"I",Space,Str "want",Space,Str "to",Space,Str "go.\"'",Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70's?"]
+, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Str "'",Code "code",Str "'",Space,Str "and",Space,Str "a",Space,Str "\"",Link [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2",""),Str "\"."]
+, Para [Str "Some",Space,Str "dashes:",Space,Str "one---two",Space,Str "---",Space,Str "three--four",Space,Str "--",Space,Str "five."]
+, Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5-7,",Space,Str "255-66,",Space,Str "1987-1999."]
+, Para [Str "Ellipses...and.",Space,Str ".",Space,Str ".and",Space,Str ".",Space,Str ".",Space,Str ".",Space,Str "."]
+, HorizontalRule
+, Header 1 [Str "LaTeX"]
+, BulletList
+ [ [ Plain [Str "\\cite[22-23]{smith.1899}"] ]
+ , [ Plain [Str "\\doublespacing"] ]
+ , [ Plain [Str "$2+2=4$"] ]
+ , [ Plain [Str "$x",Space,Str "\\in",Space,Str "y$"] ]
+ , [ Plain [Str "$\\alpha",Space,Str "\\wedge",Space,Str "\\omega$"] ]
+ , [ Plain [Str "$223$"] ]
+ , [ Plain [Str "$p$-Tree"] ]
+ , [ Plain [Str "$\\frac{d}{dx}f(x)=\\lim_{h\\to",Space,Str "0}\\frac{f(x+h)-f(x)}{h}$"] ]
+ , [ Plain [Str "Here's",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",Space,Str "$\\alpha",Space,Str "+",Space,Str "\\omega",Space,Str "\\times",Space,Str "x^2$."] ] ]
+, Para [Str "These",Space,Str "shouldn't",Space,Str "be",Space,Str "math:"]
+, BulletList
+ [ [ Plain [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",Space,Code "$e = mc^2$",Str "."] ]
+ , [ Plain [Str "$22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money.",Space,Str "So",Space,Str "is",Space,Str "$34,000.",Space,Str "(It",Space,Str "worked",Space,Str "if",Space,Str "\"lot\"",Space,Str "is",Space,Str "emphasized.)"] ]
+ , [ Plain [Str "Escaped",Space,Code "$",Str ":",Space,Str "$73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23$."] ] ]
+, Para [Str "Here's",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
+, Para [Str "\\begin{tabular}{|l|l|}\\hline",Space,Str "Animal",Space,Str "&",Space,Str "Number",Space,Str "\\\\",Space,Str "\\hline",Space,Str "Dog",Space,Str "&",Space,Str "2",Space,Str "\\\\",Space,Str "Cat",Space,Str "&",Space,Str "1",Space,Str "\\\\",Space,Str "\\hline",Space,Str "\\end{tabular}"]
+, HorizontalRule
+, Header 1 [Str "Special",Space,Str "Characters"]
+, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
+, BulletList
+ [ [ Plain [Str "I",Space,Str "hat:",Space,Str "\206"] ]
+ , [ Plain [Str "o",Space,Str "umlaut:",Space,Str "\246"] ]
+ , [ Plain [Str "section:",Space,Str "\167"] ]
+ , [ Plain [Str "set",Space,Str "membership:",Space,Str "\8712"] ]
+ , [ Plain [Str "copyright:",Space,Str "\169"] ] ]
+, Para [Str "AT",Str "&",Str "T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
+, Para [Str "AT",Str "&",Str "T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it."]
+, Para [Str "This",Space,Str "&",Space,Str "that."]
+, Para [Str "4",Space,Str "<",Space,Str "5."]
+, Para [Str "6",Space,Str ">",Space,Str "5."]
+, Para [Str "Backslash:",Space,Str "\\"]
+, Para [Str "Backtick:",Space,Str "`"]
+, Para [Str "Asterisk:",Space,Str "*"]
+, Para [Str "Underscore:",Space,Str "_"]
+, Para [Str "Left",Space,Str "brace:",Space,Str "{"]
+, Para [Str "Right",Space,Str "brace:",Space,Str "}"]
+, Para [Str "Left",Space,Str "bracket:",Space,Str "["]
+, Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
+, Para [Str "Left",Space,Str "paren:",Space,Str "("]
+, Para [Str "Right",Space,Str "paren:",Space,Str ")"]
+, Para [Str "Greater-than:",Space,Str ">"]
+, Para [Str "Hash:",Space,Str "#"]
+, Para [Str "Period:",Space,Str "."]
+, Para [Str "Bang:",Space,Str "!"]
+, Para [Str "Plus:",Space,Str "+"]
+, Para [Str "Minus:",Space,Str "-"]
+, HorizontalRule
+, Header 1 [Str "Links"]
+, Header 2 [Str "Explicit"]
+, Para [Str "Just",Space,Str "a",Space,Link [Str "URL"] ("/url/",""),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
+, Plain [Str "Email",Space,Str "link",Space,Str "(nobody",Space,Str "[at]",Space,Str "nowhere.net)"]
+, Para [Link [Str "Empty"] ("",""),Str "."]
+, Header 2 [Str "Reference"]
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "With",Space,Link [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
+, Para [Link [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
+, Para [Str "Indented",Space,Link [Str "once"] ("/url",""),Str "."]
+, Para [Str "Indented",Space,Link [Str "twice"] ("/url",""),Str "."]
+, Para [Str "Indented",Space,Link [Str "thrice"] ("/url",""),Str "."]
+, Para [Str "This",Space,Str "should",Space,Str "[not]",Space,Str "be",Space,Str "a",Space,Str "link."]
+, CodeBlock ("",[],[]) "[not]: /url"
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
+, Para [Str "Foo",Space,Link [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
+, Header 2 [Str "With",Space,Str "ampersands"]
+, Para [Str "Here's",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
+, Para [Str "Here's",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link [Str "AT",Str "&",Str "T"] ("http://att.com/","AT&T"),Str "."]
+, Para [Str "Here's",Space,Str "an",Space,Link [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
+, Para [Str "Here's",Space,Str "an",Space,Link [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
+, Header 2 [Str "Autolinks"]
+, Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link [Str "http://example.com/?foo=1",Str "&",Str "bar=2"] ("http://example.com/?foo=1&bar=2","")]
+, BulletList
+ [ [ Plain [Str "In",Space,Str "a",Space,Str "list?"] ]
+ , [ Plain [Link [Str "http://example.com/"] ("http://example.com/","")] ]
+ , [ Plain [Str "It",Space,Str "should."] ] ]
+, Plain [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Str "nobody",Space,Str "[at]",Space,Str "nowhere.net"]
+, BlockQuote
+ [ Para [Str "Blockquoted:",Space,Link [Str "http://example.com/"] ("http://example.com/","")] ]
+
+, Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code "<http://example.com/>"]
+, CodeBlock ("",[],[]) "or here: <http://example.com/>"
+, HorizontalRule
+, Header 1 [Str "Images"]
+, Para [Str "From",Space,Str "\"Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune\"",Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
+, Para [Image [Str "lalune"] ("lalune.jpg","Voyage dans la Lune")]
+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] ("movie.jpg",""),Space,Str "icon."]
+, HorizontalRule
+, Header 1 [Str "Footnotes"]
+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference",Link [Str "(1)"] ("#note_1",""),Str ",",Space,Str "and",Space,Str "another",Link [Str "(longnote)"] ("#note_longnote",""),Str ".",Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space^(my",Space,Str "note)."]
+, Para [Link [Str "(1)"] ("#ref_1",""),Space,Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "in",Space,Str "the",Space,Str "document,",Space,Str "not",Space,Str "just",Space,Str "at",Space,Str "the",Space,Str "end."]
+, Para [Link [Str "(longnote)"] ("#ref_longnote",""),Space,Str "Here's",Space,Str "the",Space,Str "other",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks."]
+, Para [Str "Caret",Space,Str "characters",Space,Str "are",Space,Str "used",Space,Str "to",Space,Str "indicate",Space,Str "that",Space,Str "the",Space,Str "blocks",Space,Str "all",Space,Str "belong",Space,Str "to",Space,Str "a",Space,Str "single",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "block",Space,Str "quotes)."]
+, CodeBlock ("",[],[]) " { <code> }"
+, Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "use",Space,Str "a",Space,Str "caret",Space,Str "at",Space,Str "the",Space,Str "beginning",Space,Str "of",Space,Str "every",Space,Str "line,",Space,Str "as",Space,Str "with",Space,Str "blockquotes,",Space,Str "but",Space,Str "all",Space,Str "that",Space,Str "you",Space,Str "need",Space,Str "is",Space,Str "a",Space,Str "caret",Space,Str "at",Space,Str "the",Space,Str "beginning",Space,Str "of",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "the",Space,Str "block",Space,Str "and",Space,Str "any",Space,Str "preceding",Space,Str "blank",Space,Str "lines."] ]
+
diff --git a/tests/insert b/tests/insert
new file mode 100644
index 000000000..f06069ede
--- /dev/null
+++ b/tests/insert
@@ -0,0 +1 @@
+STUFF INSERTED
diff --git a/tests/lalune.jpg b/tests/lalune.jpg
new file mode 100644
index 000000000..5a50fc088
--- /dev/null
+++ b/tests/lalune.jpg
Binary files differ
diff --git a/tests/latex-reader.latex b/tests/latex-reader.latex
new file mode 100644
index 000000000..883217c86
--- /dev/null
+++ b/tests/latex-reader.latex
@@ -0,0 +1,830 @@
+\documentclass{article}
+\usepackage[mathletters]{ucs}
+\usepackage[utf8x]{inputenc}
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+
+\newcommand{\textsubscript}[1]{\ensuremath{_{\scriptsize\textrm{#1}}}}
+\usepackage[breaklinks=true]{hyperref}
+\usepackage[normalem]{ulem}
+\usepackage{enumerate}
+\usepackage{fancyvrb}
+\usepackage{graphicx}
+\usepackage{url}
+
+\setcounter{secnumdepth}{0}
+\VerbatimFootnotes % allows verbatim text in footnotes
+\title{Pandoc Test Suite}
+\author{John MacFarlane\\Anonymous}
+\date{July 17, 2006}
+\begin{document}
+\maketitle
+
+This is a set of tests for pandoc. Most of them are adapted from
+John Gruber's markdown test suite.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Headers}
+
+\subsection{Level 2 with an \href{/url}{embedded link}}
+
+\subsubsection{Level 3 with \emph{emphasis}}
+
+Level 4
+
+Level 5
+
+\section{Level 1}
+
+\subsection{Level 2 with \emph{emphasis}}
+
+\subsubsection{Level 3}
+
+with no blank line
+
+\subsection{Level 2}
+
+with no blank line
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Paragraphs}
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a
+list item. Because a hard-wrapped line in the middle of a paragraph
+looked like a list item.
+
+Here's one with a bullet. * criminey.
+
+There should be a hard line break\\here.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Block Quotes}
+
+E-mail style:
+
+\begin{quote}
+This is a block quote. It is pretty short.
+
+\end{quote}
+\begin{quote}
+Code in a block quote:
+
+\begin{verbatim}
+sub status {
+ print "working";
+}
+\end{verbatim}
+A list:
+
+\begin{enumerate}[1.]
+\item
+ item one
+\item
+ item two
+\end{enumerate}
+Nested block quotes:
+
+\begin{quote}
+nested
+
+\end{quote}
+\begin{quote}
+nested
+
+\end{quote}
+\end{quote}
+This should not be a block quote: 2 \textgreater{} 1.
+
+Box-style:
+
+\begin{quote}
+Example:
+
+\begin{verbatim}
+sub status {
+ print "working";
+}
+\end{verbatim}
+\end{quote}
+\begin{quote}
+\begin{enumerate}[1.]
+\item
+ do laundry
+\item
+ take out the trash
+\end{enumerate}
+\end{quote}
+Here's a nested one:
+
+\begin{quote}
+Joe said:
+
+\begin{quote}
+Don't quote me.
+
+\end{quote}
+\end{quote}
+And a following paragraph.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Code Blocks}
+
+Code:
+
+\begin{verbatim}
+---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+\end{verbatim}
+And:
+
+\begin{verbatim}
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+\end{verbatim}
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Lists}
+
+\subsection{Unordered}
+
+Asterisks tight:
+
+\begin{itemize}
+\item
+ asterisk 1
+\item
+ asterisk 2
+\item
+ asterisk 3
+\end{itemize}
+Asterisks loose:
+
+\begin{itemize}
+\item
+ asterisk 1
+
+\item
+ asterisk 2
+
+\item
+ asterisk 3
+
+\end{itemize}
+Pluses tight:
+
+\begin{itemize}
+\item
+ Plus 1
+\item
+ Plus 2
+\item
+ Plus 3
+\end{itemize}
+Pluses loose:
+
+\begin{itemize}
+\item
+ Plus 1
+
+\item
+ Plus 2
+
+\item
+ Plus 3
+
+\end{itemize}
+Minuses tight:
+
+\begin{itemize}
+\item
+ Minus 1
+\item
+ Minus 2
+\item
+ Minus 3
+\end{itemize}
+Minuses loose:
+
+\begin{itemize}
+\item
+ Minus 1
+
+\item
+ Minus 2
+
+\item
+ Minus 3
+
+\end{itemize}
+\subsection{Ordered}
+
+Tight:
+
+\begin{enumerate}[1.]
+\item
+ First
+\item
+ Second
+\item
+ Third
+\end{enumerate}
+and:
+
+\begin{enumerate}[1.]
+\item
+ One
+\item
+ Two
+\item
+ Three
+\end{enumerate}
+Loose using tabs:
+
+\begin{enumerate}[1.]
+\item
+ First
+
+\item
+ Second
+
+\item
+ Third
+
+\end{enumerate}
+and using spaces:
+
+\begin{enumerate}[1.]
+\item
+ One
+
+\item
+ Two
+
+\item
+ Three
+
+\end{enumerate}
+Multiple paragraphs:
+
+\begin{enumerate}[1.]
+\item
+ Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's
+ back.
+
+\item
+ Item 2.
+
+\item
+ Item 3.
+
+\end{enumerate}
+\subsection{Nested}
+
+\begin{itemize}
+\item
+ Tab
+ \begin{itemize}
+ \item
+ Tab
+ \begin{itemize}
+ \item
+ Tab
+ \end{itemize}
+ \end{itemize}
+\end{itemize}
+Here's another:
+
+\begin{enumerate}[1.]
+\item
+ First
+\item
+ Second:
+ \begin{itemize}
+ \item
+ Fee
+ \item
+ Fie
+ \item
+ Foe
+ \end{itemize}
+\item
+ Third
+\end{enumerate}
+Same thing but with paragraphs:
+
+\begin{enumerate}[1.]
+\item
+ First
+
+\item
+ Second:
+
+ \begin{itemize}
+ \item
+ Fee
+ \item
+ Fie
+ \item
+ Foe
+ \end{itemize}
+\item
+ Third
+
+\end{enumerate}
+\subsection{Tabs and spaces}
+
+\begin{itemize}
+\item
+ this is a list item indented with tabs
+
+\item
+ this is a list item indented with spaces
+
+ \begin{itemize}
+ \item
+ this is an example list item indented with tabs
+
+ \item
+ this is an example list item indented with spaces
+
+ \end{itemize}
+\end{itemize}
+\subsection{Fancy list markers}
+
+\begin{enumerate}[(1)]
+\setcounter{enumi}{1}
+\item
+ begins with 2
+\item
+ and now 3
+
+ with a continuation
+
+ \begin{enumerate}[i.]
+ \setcounter{enumii}{3}
+ \item
+ sublist with roman numerals, starting with 4
+ \item
+ more items
+ \begin{enumerate}[(A)]
+ \item
+ a subsublist
+ \item
+ a subsublist
+ \end{enumerate}
+ \end{enumerate}
+\end{enumerate}
+Nesting:
+
+\begin{enumerate}[A.]
+\item
+ Upper Alpha
+ \begin{enumerate}[I.]
+ \item
+ Upper Roman.
+ \begin{enumerate}[(1)]
+ \setcounter{enumiii}{5}
+ \item
+ Decimal start with 6
+ \begin{enumerate}[a)]
+ \setcounter{enumiv}{2}
+ \item
+ Lower alpha with paren
+ \end{enumerate}
+ \end{enumerate}
+ \end{enumerate}
+\end{enumerate}
+Autonumbering:
+
+\begin{enumerate}
+\item
+ Autonumber.
+\item
+ More.
+ \begin{enumerate}
+ \item
+ Nested.
+ \end{enumerate}
+\end{enumerate}
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Definition Lists}
+
+Tight using spaces:
+
+\begin{description}
+\item[apple]
+red fruit
+\item[orange]
+orange fruit
+\item[banana]
+yellow fruit
+\end{description}
+Tight using tabs:
+
+\begin{description}
+\item[apple]
+red fruit
+\item[orange]
+orange fruit
+\item[banana]
+yellow fruit
+\end{description}
+Loose:
+
+\begin{description}
+\item[apple]
+red fruit
+
+\item[orange]
+orange fruit
+
+\item[banana]
+yellow fruit
+
+\end{description}
+Multiple blocks with italics:
+
+\begin{description}
+\item[\emph{apple}]
+red fruit
+
+contains seeds, crisp, pleasant to taste
+
+\item[\emph{orange}]
+orange fruit
+
+\begin{verbatim}
+{ orange code block }
+\end{verbatim}
+\begin{quote}
+orange block quote
+
+\end{quote}
+\end{description}
+\section{HTML Blocks}
+
+Simple block on one line:
+
+foo
+And nested without indentation:
+
+foo
+bar
+Interpreted markdown in a table:
+
+This is \emph{emphasized}
+And this is \textbf{strong}
+Here's a simple block:
+
+foo
+This should be a code block, though:
+
+\begin{verbatim}
+<div>
+ foo
+</div>
+\end{verbatim}
+As should this:
+
+\begin{verbatim}
+<div>foo</div>
+\end{verbatim}
+Now, nested:
+
+foo
+This should just be an HTML comment:
+
+Multiline:
+
+Code block:
+
+\begin{verbatim}
+<!-- Comment -->
+\end{verbatim}
+Just plain comment, with trailing spaces on the line:
+
+Code:
+
+\begin{verbatim}
+<hr />
+\end{verbatim}
+Hr's:
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Inline Markup}
+
+This is \emph{emphasized}, and so \emph{is this}.
+
+This is \textbf{strong}, and so \textbf{is this}.
+
+An \emph{\href{/url}{emphasized link}}.
+
+\textbf{\emph{This is strong and em.}}
+
+So is \textbf{\emph{this}} word.
+
+\textbf{\emph{This is strong and em.}}
+
+So is \textbf{\emph{this}} word.
+
+This is code: \verb!>!, \verb!$!, \verb!\!, \verb!\$!,
+\verb!<html>!.
+
+\sout{This is \emph{strikeout}.}
+
+Superscripts: a\textsuperscript{bc}d
+a\textsuperscript{\emph{hello}} a\textsuperscript{hello there}.
+
+Subscripts: H\textsubscript{2}O, H\textsubscript{23}O,
+H\textsubscript{many of them}O.
+
+These should not be superscripts or subscripts, because of the
+unescaped spaces: a\^{}b c\^{}d, a\ensuremath{\sim}b
+c\ensuremath{\sim}d.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Smart quotes, ellipses, dashes}
+
+``Hello,'' said the spider. ``\,`Shelob' is my name.''
+
+`A', `B', and `C' are letters.
+
+`Oak,' `elm,' and `beech' are names of trees. So is `pine.'
+
+`He said, ``I want to go.''\,' Were you alive in the 70's?
+
+Here is some quoted `\verb!code!' and a
+``\href{http://example.com/?foo=1&bar=2}{quoted link}''.
+
+Some dashes: one---two---three---four---five.
+
+Dashes between numbers: 5--7, 255--66, 1987--1999.
+
+Ellipses\ldots{}and\ldots{}and\ldots{}.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{LaTeX}
+
+\begin{itemize}
+\item
+ \cite[22-23]{smith.1899}
+\item
+ \doublespacing
+\item
+ $2+2=4$
+\item
+ $x \in y$
+\item
+ $\alpha \wedge \omega$
+\item
+ $223$
+\item
+ $p$-Tree
+\item
+ $\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$
+\item
+ Here's one that has a line break in it:
+ $\alpha + \omega \times x^2$.
+\end{itemize}
+These shouldn't be math:
+
+\begin{itemize}
+\item
+ To get the famous equation, write \verb!$e = mc^2$!.
+\item
+ \$22,000 is a \emph{lot} of money. So is \$34,000. (It worked if
+ ``lot'' is emphasized.)
+\item
+ Escaped \verb!$!: \$73 \emph{this should be emphasized} 23\$.
+\end{itemize}
+Here's a LaTeX table:
+
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Special Characters}
+
+Here is some unicode:
+
+\begin{itemize}
+\item
+ I hat: Î
+\item
+ o umlaut: ö
+\item
+ section: §
+\item
+ set membership: ∈
+\item
+ copyright: ©
+\end{itemize}
+AT\&T has an ampersand in their name.
+
+AT\&T is another way to write it.
+
+This \& that.
+
+4 \textless{} 5.
+
+6 \textgreater{} 5.
+
+Backslash: \textbackslash{}
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: \_
+
+Left brace: \{
+
+Right brace: \}
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: \textgreater{}
+
+Hash: \#
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Links}
+
+\subsection{Explicit}
+
+Just a \href{/url/}{URL}.
+
+\href{/url/}{URL and title}.
+
+\href{/url/}{URL and title}.
+
+\href{/url/}{URL and title}.
+
+\href{/url/}{URL and title}
+
+\href{/url/}{URL and title}
+
+\href{/url/with_underscore}{with\_underscore}
+
+\href{mailto:nobody@nowhere.net}{Email link}
+
+\href{}{Empty}.
+
+\subsection{Reference}
+
+Foo \href{/url/}{bar}.
+
+Foo \href{/url/}{bar}.
+
+Foo \href{/url/}{bar}.
+
+With \href{/url/}{embedded [brackets]}.
+
+\href{/url/}{b} by itself should be a link.
+
+Indented \href{/url}{once}.
+
+Indented \href{/url}{twice}.
+
+Indented \href{/url}{thrice}.
+
+This should [not][] be a link.
+
+\begin{verbatim}
+[not]: /url
+\end{verbatim}
+Foo \href{/url/}{bar}.
+
+Foo \href{/url/}{biz}.
+
+\subsection{With ampersands}
+
+Here's a
+\href{http://example.com/?foo=1&bar=2}{link with an ampersand in the URL}.
+
+Here's a link with an amersand in the link text:
+\href{http://att.com/}{AT\&T}.
+
+Here's an \href{/script?foo=1&bar=2}{inline link}.
+
+Here's an
+\href{/script?foo=1&bar=2}{inline link in pointy braces}.
+
+\subsection{Autolinks}
+
+With an ampersand: \url{http://example.com/?foo=1&bar=2}
+
+\begin{itemize}
+\item
+ In a list?
+\item
+ \url{http://example.com/}
+\item
+ It should.
+\end{itemize}
+An e-mail address:
+\href{mailto:nobody@nowhere.net}{\texttt{nobody@nowhere.net}}
+
+\begin{quote}
+Blockquoted: \url{http://example.com/}
+
+\end{quote}
+Auto-links should not occur here: \verb!<http://example.com/>!
+
+\begin{verbatim}
+or here: <http://example.com/>
+\end{verbatim}
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Images}
+
+From ``Voyage dans la Lune'' by Georges Melies (1902):
+
+\includegraphics{lalune.jpg}
+
+Here is a movie \includegraphics{movie.jpg} icon.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Footnotes}
+
+Here is a footnote
+reference,\footnote{ Here is the footnote. It can go anywhere after the footnote
+reference. It need not be placed at the end of the document.
+}
+and
+another.\footnote{ Here's the long note. This one contains multiple blocks.
+
+Subsequent blocks are indented to show that they belong to the
+footnote (as with list items).
+
+\begin{Verbatim}
+ { <code> }
+\end{Verbatim}
+If you want, you can indent every line, but you can also be lazy
+and just indent the first line of each block.
+}
+This should \emph{not} be a footnote reference, because it contains
+a space.[\^{}my note] Here is an inline
+note.\footnote{ This is \emph{easier} to type. Inline notes may contain
+\href{http://google.com}{links} and \verb!]! verbatim characters,
+as well as [bracketed text].
+}
+
+\begin{quote}
+Notes can go in quotes.\footnote{ In quote.
+}
+
+\end{quote}
+\begin{enumerate}[1.]
+\item
+ And in list items.\footnote{ In list.
+}
+\end{enumerate}
+This paragraph should not be part of the note, as it is not
+indented.
+
+\end{document}
diff --git a/tests/latex-reader.native b/tests/latex-reader.native
new file mode 100644
index 000000000..4a239bc07
--- /dev/null
+++ b/tests/latex-reader.native
@@ -0,0 +1,378 @@
+Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] ["John MacFarlane","Anonymous"] "July 17, 2006")
+[ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber",Apostrophe,Str "s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
+, HorizontalRule
+, Header 1 [Str "Headers"]
+, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] ("/url","")]
+, Header 3 [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
+, Para [Str "Level",Space,Str "4"]
+, Para [Str "Level",Space,Str "5"]
+, Header 1 [Str "Level",Space,Str "1"]
+, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
+, Header 3 [Str "Level",Space,Str "3"]
+, Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+, Header 2 [Str "Level",Space,Str "2"]
+, Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+, HorizontalRule
+, Header 1 [Str "Paragraphs"]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
+, Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",Space,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item.",Space,Str "Because",Space,Str "a",Space,Str "hard",Str "-",Str "wrapped",Space,Str "line",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",Space,Str "list",Space,Str "item."]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",Space,Str "*",Space,Str "criminey."]
+, Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Str "here."]
+, HorizontalRule
+, Header 1 [Str "Block",Space,Str "Quotes"]
+, Para [Str "E",Str "-",Str "mail",Space,Str "style:"]
+, BlockQuote
+ [ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",Space,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."] ]
+
+, BlockQuote
+ [ Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
+ , CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
+ , Para [Str "A",Space,Str "list:"]
+ , OrderedList (1,Decimal,Period)
+ [ [ Para [Str "item",Space,Str "one"] ]
+ , [ Para [Str "item",Space,Str "two"] ] ]
+ , Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
+ , BlockQuote
+ [ Para [Str "nested"] ]
+
+ , BlockQuote
+ [ Para [Str "nested"] ]
+ ]
+, Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",Space,Str ">",Space,Str "1."]
+, Para [Str "Box",Str "-",Str "style:"]
+, BlockQuote
+ [ Para [Str "Example:"]
+ , CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}" ]
+, BlockQuote
+ [ OrderedList (1,Decimal,Period)
+ [ [ Para [Str "do",Space,Str "laundry"] ]
+ , [ Para [Str "take",Space,Str "out",Space,Str "the",Space,Str "trash"] ] ] ]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "nested",Space,Str "one:"]
+, BlockQuote
+ [ Para [Str "Joe",Space,Str "said:"]
+ , BlockQuote
+ [ Para [Str "Don",Apostrophe,Str "t",Space,Str "quote",Space,Str "me."] ]
+ ]
+, Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
+, HorizontalRule
+, Header 1 [Str "Code",Space,Str "Blocks"]
+, Para [Str "Code:"]
+, CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
+, Para [Str "And:"]
+, CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
+, HorizontalRule
+, Header 1 [Str "Lists"]
+, Header 2 [Str "Unordered"]
+, Para [Str "Asterisks",Space,Str "tight:"]
+, BulletList
+ [ [ Para [Str "asterisk",Space,Str "1"] ]
+ , [ Para [Str "asterisk",Space,Str "2"] ]
+ , [ Para [Str "asterisk",Space,Str "3"] ] ]
+, Para [Str "Asterisks",Space,Str "loose:"]
+, BulletList
+ [ [ Para [Str "asterisk",Space,Str "1"] ]
+ , [ Para [Str "asterisk",Space,Str "2"] ]
+ , [ Para [Str "asterisk",Space,Str "3"] ] ]
+, Para [Str "Pluses",Space,Str "tight:"]
+, BulletList
+ [ [ Para [Str "Plus",Space,Str "1"] ]
+ , [ Para [Str "Plus",Space,Str "2"] ]
+ , [ Para [Str "Plus",Space,Str "3"] ] ]
+, Para [Str "Pluses",Space,Str "loose:"]
+, BulletList
+ [ [ Para [Str "Plus",Space,Str "1"] ]
+ , [ Para [Str "Plus",Space,Str "2"] ]
+ , [ Para [Str "Plus",Space,Str "3"] ] ]
+, Para [Str "Minuses",Space,Str "tight:"]
+, BulletList
+ [ [ Para [Str "Minus",Space,Str "1"] ]
+ , [ Para [Str "Minus",Space,Str "2"] ]
+ , [ Para [Str "Minus",Space,Str "3"] ] ]
+, Para [Str "Minuses",Space,Str "loose:"]
+, BulletList
+ [ [ Para [Str "Minus",Space,Str "1"] ]
+ , [ Para [Str "Minus",Space,Str "2"] ]
+ , [ Para [Str "Minus",Space,Str "3"] ] ]
+, Header 2 [Str "Ordered"]
+, Para [Str "Tight:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "First"] ]
+ , [ Para [Str "Second"] ]
+ , [ Para [Str "Third"] ] ]
+, Para [Str "and:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "One"] ]
+ , [ Para [Str "Two"] ]
+ , [ Para [Str "Three"] ] ]
+, Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "First"] ]
+ , [ Para [Str "Second"] ]
+ , [ Para [Str "Third"] ] ]
+, Para [Str "and",Space,Str "using",Space,Str "spaces:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "One"] ]
+ , [ Para [Str "Two"] ]
+ , [ Para [Str "Three"] ] ]
+, Para [Str "Multiple",Space,Str "paragraphs:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
+ , Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog",Apostrophe,Str "s",Space,Str "back."] ], [ Para [Str "Item",Space,Str "2."] ]
+ , [ Para [Str "Item",Space,Str "3."] ] ]
+, Header 2 [Str "Nested"]
+, BulletList
+ [ [ Para [Str "Tab"]
+ , BulletList
+ [ [ Para [Str "Tab"]
+ , BulletList
+ [ [ Para [Str "Tab"] ]
+ ] ] ] ] ]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "another:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "First"] ]
+ , [ Para [Str "Second:"]
+ , BulletList
+ [ [ Para [Str "Fee"] ]
+ , [ Para [Str "Fie"] ]
+ , [ Para [Str "Foe"] ] ] ], [ Para [Str "Third"] ] ]
+, Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "First"] ]
+ , [ Para [Str "Second:"]
+ , BulletList
+ [ [ Para [Str "Fee"] ]
+ , [ Para [Str "Fie"] ]
+ , [ Para [Str "Foe"] ] ] ], [ Para [Str "Third"] ] ]
+, Header 2 [Str "Tabs",Space,Str "and",Space,Str "spaces"]
+, BulletList
+ [ [ Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"] ]
+ , [ Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]
+ , BulletList
+ [ [ Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"] ]
+ , [ Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"] ] ] ] ]
+, Header 2 [Str "Fancy",Space,Str "list",Space,Str "markers"]
+, OrderedList (2,Decimal,TwoParens)
+ [ [ Para [Str "begins",Space,Str "with",Space,Str "2"] ]
+ , [ Para [Str "and",Space,Str "now",Space,Str "3"]
+ , Para [Str "with",Space,Str "a",Space,Str "continuation"]
+ , OrderedList (4,LowerRoman,Period)
+ [ [ Para [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",Space,Str "starting",Space,Str "with",Space,Str "4"] ]
+ , [ Para [Str "more",Space,Str "items"]
+ , OrderedList (1,UpperAlpha,TwoParens)
+ [ [ Para [Str "a",Space,Str "subsublist"] ]
+ , [ Para [Str "a",Space,Str "subsublist"] ] ] ] ] ] ]
+, Para [Str "Nesting:"]
+, OrderedList (1,UpperAlpha,Period)
+ [ [ Para [Str "Upper",Space,Str "Alpha"]
+ , OrderedList (1,UpperRoman,Period)
+ [ [ Para [Str "Upper",Space,Str "Roman."]
+ , OrderedList (6,Decimal,TwoParens)
+ [ [ Para [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
+ , OrderedList (3,LowerAlpha,OneParen)
+ [ [ Para [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"] ]
+ ] ] ] ] ] ] ]
+, Para [Str "Autonumbering:"]
+, OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Para [Str "Autonumber."] ]
+ , [ Para [Str "More."]
+ , OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Para [Str "Nested."] ]
+ ] ] ]
+, Para [Str "Should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "list",Space,Str "item:"]
+, Para [Str "M.A.",Space,Str "2007"]
+, Para [Str "B.",Space,Str "Williams"]
+, HorizontalRule
+, Header 1 [Str "Definition",Space,Str "Lists"]
+, Para [Str "Tight",Space,Str "using",Space,Str "spaces:"]
+, DefinitionList
+ [ ([Str "apple"],
+ [ Para [Str "red",Space,Str "fruit"] ]
+ ),
+ ([Str "orange"],
+ [ Para [Str "orange",Space,Str "fruit"] ]
+ ),
+ ([Str "banana"],
+ [ Para [Str "yellow",Space,Str "fruit"] ]
+ ) ]
+, Para [Str "Tight",Space,Str "using",Space,Str "tabs:"]
+, DefinitionList
+ [ ([Str "apple"],
+ [ Para [Str "red",Space,Str "fruit"] ]
+ ),
+ ([Str "orange"],
+ [ Para [Str "orange",Space,Str "fruit"] ]
+ ),
+ ([Str "banana"],
+ [ Para [Str "yellow",Space,Str "fruit"] ]
+ ) ]
+, Para [Str "Loose:"]
+, DefinitionList
+ [ ([Str "apple"],
+ [ Para [Str "red",Space,Str "fruit"] ]
+ ),
+ ([Str "orange"],
+ [ Para [Str "orange",Space,Str "fruit"] ]
+ ),
+ ([Str "banana"],
+ [ Para [Str "yellow",Space,Str "fruit"] ]
+ ) ]
+, Para [Str "Multiple",Space,Str "blocks",Space,Str "with",Space,Str "italics:"]
+, DefinitionList
+ [ ([Emph [Str "apple"]],
+ [ Para [Str "red",Space,Str "fruit"]
+ , Para [Str "contains",Space,Str "seeds,",Space,Str "crisp,",Space,Str "pleasant",Space,Str "to",Space,Str "taste"] ] ),
+ ([Emph [Str "orange"]],
+ [ Para [Str "orange",Space,Str "fruit"]
+ , CodeBlock ("",[],[]) "{ orange code block }"
+ , BlockQuote
+ [ Para [Str "orange",Space,Str "block",Space,Str "quote"] ]
+ ] ) ]
+, Header 1 [Str "HTML",Space,Str "Blocks"]
+, Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line:"]
+, Para [Str "foo",Space,Str "And",Space,Str "nested",Space,Str "without",Space,Str "indentation:"]
+, Para [Str "foo",Space,Str "bar",Space,Str "Interpreted",Space,Str "markdown",Space,Str "in",Space,Str "a",Space,Str "table:"]
+, Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Space,Str "And",Space,Str "this",Space,Str "is",Space,Strong [Str "strong"],Space,Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "simple",Space,Str "block:"]
+, Para [Str "foo",Space,Str "This",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "code",Space,Str "block,",Space,Str "though:"]
+, CodeBlock ("",[],[]) "<div>\n foo\n</div>"
+, Para [Str "As",Space,Str "should",Space,Str "this:"]
+, CodeBlock ("",[],[]) "<div>foo</div>"
+, Para [Str "Now,",Space,Str "nested:"]
+, Para [Str "foo",Space,Str "This",Space,Str "should",Space,Str "just",Space,Str "be",Space,Str "an",Space,Str "HTML",Space,Str "comment:"]
+, Para [Str "Multiline:"]
+, Para [Str "Code",Space,Str "block:"]
+, CodeBlock ("",[],[]) "<!-- Comment -->"
+, Para [Str "Just",Space,Str "plain",Space,Str "comment,",Space,Str "with",Space,Str "trailing",Space,Str "spaces",Space,Str "on",Space,Str "the",Space,Str "line:"]
+, Para [Str "Code:"]
+, CodeBlock ("",[],[]) "<hr />"
+, Para [Str "Hr",Apostrophe,Str "s:"]
+, HorizontalRule
+, Header 1 [Str "Inline",Space,Str "Markup"]
+, Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
+, Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
+, Para [Str "An",Space,Emph [Link [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
+, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+, Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+, Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+, Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ">",Str ",",Space,Code "$",Str ",",Space,Code "\\",Str ",",Space,Code "\\$",Str ",",Space,Code "<html>",Str "."]
+, Para [Strikeout [Str "This",Space,Str "is",Space,Emph [Str "strikeout"],Str "."]]
+, Para [Str "Superscripts:",Space,Str "a",Superscript [Str "bc"],Str "d",Space,Str "a",Superscript [Emph [Str "hello"]],Space,Str "a",Superscript [Str "hello",Space,Str "there"],Str "."]
+, Para [Str "Subscripts:",Space,Str "H",Subscript [Str "2"],Str "O,",Space,Str "H",Subscript [Str "23"],Str "O,",Space,Str "H",Subscript [Str "many",Space,Str "of",Space,Str "them"],Str "O."]
+, Para [Str "These",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "superscripts",Space,Str "or",Space,Str "subscripts,",Space,Str "because",Space,Str "of",Space,Str "the",Space,Str "unescaped",Space,Str "spaces:",Space,Str "a",Str "^",Str "b",Space,Str "c",Str "^",Str "d,",Space,Str "a",Str "~",Str "b",Space,Str "c",Str "~",Str "d."]
+, HorizontalRule
+, Header 1 [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
+, Para [Quoted DoubleQuote [Str "Hello,"],Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Quoted DoubleQuote [Quoted SingleQuote [Str "Shelob"],Space,Str "is",Space,Str "my",Space,Str "name."]]
+, Para [Quoted SingleQuote [Str "A"],Str ",",Space,Quoted SingleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted SingleQuote [Str "C"],Space,Str "are",Space,Str "letters."]
+, Para [Quoted SingleQuote [Str "Oak,"],Space,Quoted SingleQuote [Str "elm,"],Space,Str "and",Space,Quoted SingleQuote [Str "beech"],Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",Space,Str "So",Space,Str "is",Space,Quoted SingleQuote [Str "pine."]]
+, Para [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go."]],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70",Apostrophe,Str "s?"]
+, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code "code"],Space,Str "and",Space,Str "a",Space,Quoted DoubleQuote [Link [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2","")],Str "."]
+, Para [Str "Some",Space,Str "dashes:",Space,Str "one",EmDash,Str "two",EmDash,Str "three",EmDash,Str "four",EmDash,Str "five."]
+, Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5",EnDash,Str "7,",Space,Str "255",EnDash,Str "66,",Space,Str "1987",EnDash,Str "1999."]
+, Para [Str "Ellipses",Ellipses,Str "and",Ellipses,Str "and",Ellipses,Str "."]
+, HorizontalRule
+, Header 1 [Str "LaTeX"]
+, BulletList
+ [ [ Para [TeX "\\cite[22-23]{smith.1899}"] ]
+ , [ Para [TeX "\\doublespacing"] ]
+ , [ Para [Math InlineMath "2+2=4"] ]
+ , [ Para [Math InlineMath "x \\in y"] ]
+ , [ Para [Math InlineMath "\\alpha \\wedge \\omega"] ]
+ , [ Para [Math InlineMath "223"] ]
+ , [ Para [Math InlineMath "p",Str "-",Str "Tree"] ]
+ , [ Para [Math InlineMath "\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}"] ]
+ , [ Para [Str "Here",Apostrophe,Str "s",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",Space,Math InlineMath "\\alpha + \\omega \\times x^2",Str "."] ] ]
+, Para [Str "These",Space,Str "shouldn",Apostrophe,Str "t",Space,Str "be",Space,Str "math:"]
+, BulletList
+ [ [ Para [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",Space,Code "$e = mc^2$",Str "."] ]
+ , [ Para [Str "$",Str "22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money.",Space,Str "So",Space,Str "is",Space,Str "$",Str "34,000.",Space,Str "(It",Space,Str "worked",Space,Str "if",Space,Quoted DoubleQuote [Str "lot"],Space,Str "is",Space,Str "emphasized.)"] ]
+ , [ Para [Str "Escaped",Space,Code "$",Str ":",Space,Str "$",Str "73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23",Str "$",Str "."] ] ]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
+, Para [TeX "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}"]
+, HorizontalRule
+, Header 1 [Str "Special",Space,Str "Characters"]
+, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
+, BulletList
+ [ [ Para [Str "I",Space,Str "hat:",Space,Str "\206"] ]
+ , [ Para [Str "o",Space,Str "umlaut:",Space,Str "\246"] ]
+ , [ Para [Str "section:",Space,Str "\167"] ]
+ , [ Para [Str "set",Space,Str "membership:",Space,Str "\8712"] ]
+ , [ Para [Str "copyright:",Space,Str "\169"] ] ]
+, Para [Str "AT",Str "&",Str "T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
+, Para [Str "AT",Str "&",Str "T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it."]
+, Para [Str "This",Space,Str "&",Space,Str "that."]
+, Para [Str "4",Space,Str "<",Space,Str "5."]
+, Para [Str "6",Space,Str ">",Space,Str "5."]
+, Para [Str "Backslash:",Space,Str "\\"]
+, Para [Str "Backtick:",Space,Str "`"]
+, Para [Str "Asterisk:",Space,Str "*"]
+, Para [Str "Underscore:",Space,Str "_"]
+, Para [Str "Left",Space,Str "brace:",Space,Str "{"]
+, Para [Str "Right",Space,Str "brace:",Space,Str "}"]
+, Para [Str "Left",Space,Str "bracket:",Space,Str "["]
+, Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
+, Para [Str "Left",Space,Str "paren:",Space,Str "("]
+, Para [Str "Right",Space,Str "paren:",Space,Str ")"]
+, Para [Str "Greater",Str "-",Str "than:",Space,Str ">"]
+, Para [Str "Hash:",Space,Str "#"]
+, Para [Str "Period:",Space,Str "."]
+, Para [Str "Bang:",Space,Str "!"]
+, Para [Str "Plus:",Space,Str "+"]
+, Para [Str "Minus:",Space,Str "-"]
+, HorizontalRule
+, Header 1 [Str "Links"]
+, Header 2 [Str "Explicit"]
+, Para [Str "Just",Space,Str "a",Space,Link [Str "URL"] ("/url/",""),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/",""),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/",""),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/",""),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","")]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","")]
+, Para [Link [Str "with",Str "_",Str "underscore"] ("/url/with_underscore","")]
+, Para [Link [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
+, Para [Link [Str "Empty"] ("",""),Str "."]
+, Header 2 [Str "Reference"]
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "With",Space,Link [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
+, Para [Link [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
+, Para [Str "Indented",Space,Link [Str "once"] ("/url",""),Str "."]
+, Para [Str "Indented",Space,Link [Str "twice"] ("/url",""),Str "."]
+, Para [Str "Indented",Space,Link [Str "thrice"] ("/url",""),Str "."]
+, Para [Str "This",Space,Str "should",Space,Str "[not][]",Space,Str "be",Space,Str "a",Space,Str "link."]
+, CodeBlock ("",[],[]) "[not]: /url"
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "Foo",Space,Link [Str "biz"] ("/url/",""),Str "."]
+, Header 2 [Str "With",Space,Str "ampersands"]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link [Str "AT",Str "&",Str "T"] ("http://att.com/",""),Str "."]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
+, Header 2 [Str "Autolinks"]
+, Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link [Code "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
+, BulletList
+ [ [ Para [Str "In",Space,Str "a",Space,Str "list?"] ]
+ , [ Para [Link [Code "http://example.com/"] ("http://example.com/","")] ]
+ , [ Para [Str "It",Space,Str "should."] ] ]
+, Para [Str "An",Space,Str "e",Str "-",Str "mail",Space,Str "address:",Space,Link [Code "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")]
+, BlockQuote
+ [ Para [Str "Blockquoted:",Space,Link [Code "http://example.com/"] ("http://example.com/","")] ]
+
+, Para [Str "Auto",Str "-",Str "links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code "<http://example.com/>"]
+, CodeBlock ("",[],[]) "or here: <http://example.com/>"
+, HorizontalRule
+, Header 1 [Str "Images"]
+, Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
+, Para [Image [Str "image"] ("lalune.jpg","")]
+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "image"] ("movie.jpg",""),Space,Str "icon."]
+, HorizontalRule
+, Header 1 [Str "Footnotes"]
+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",Space,Str "reference.",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document."]],Space,Str "and",Space,Str "another.",Note [Para [Str "Here",Apostrophe,Str "s",Space,Str "the",Space,Str "long",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks."],Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)."],CodeBlock ("",[],[]) " { <code> }",Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",Space,Str "lazy",Space,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block."]],Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space.[",Str "^",Str "my",Space,Str "note]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",Space,Str "note.",Note [Para [Str "This",Space,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type.",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",Space,Link [Str "links"] ("http://google.com",""),Space,Str "and",Space,Code "]",Space,Str "verbatim",Space,Str "characters,",Space,Str "as",Space,Str "well",Space,Str "as",Space,Str "[bracketed",Space,Str "text]."]]]
+, BlockQuote
+ [ Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes.",Note [Para [Str "In",Space,Str "quote."]]] ]
+
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "And",Space,Str "in",Space,Str "list",Space,Str "items.",Note [Para [Str "In",Space,Str "list."]]] ]
+ ]
+, Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented."] ]
+
diff --git a/tests/lhs-test.fragment.html+lhs b/tests/lhs-test.fragment.html+lhs
new file mode 100644
index 000000000..2100db251
--- /dev/null
+++ b/tests/lhs-test.fragment.html+lhs
@@ -0,0 +1,51 @@
+<div id="lhs-test"
+><h1
+ >lhs test</h1
+ ><p
+ ><code
+ >unsplit</code
+ > is an arrow that takes a pair of values and combines them to return a single value:</p
+ ><pre class="sourceCode literatehaskell"
+ ><code
+ ><span class="Char Special"
+ >&gt;</span
+ ><span class="Function FunctionDefinition"
+ > unsplit ::</span
+ ><span class="Normal NormalText"
+ > (Arrow a) =&gt; (b -&gt; c -&gt; d) -&gt; a (b, c) d</span
+ ><br
+ /><span class="Char Special"
+ >&gt;</span
+ ><span class="Normal NormalText"
+ > unsplit = arr . </span
+ ><span class="Function"
+ >uncurry</span
+ ><span class="Normal NormalText"
+ > </span
+ ><br
+ /><span class="Char Special"
+ >&gt;</span
+ ><span class="Normal NormalText"
+ > </span
+ ><span class="Comment"
+ >-- arr (\op (x,y) -&gt; x `op` y) </span
+ ><br
+ /></code
+ ></pre
+ ><p
+ ><code
+ >(***)</code
+ > combines two arrows into a new arrow by running the two arrows on a pair of values (one arrow on the first item of the pair and one arrow on the second item of the pair).</p
+ ><pre
+ ><code
+ >f *** g = first f &gt;&gt;&gt; second g
+</code
+ ></pre
+ ><p
+ >Block quote:</p
+ ><blockquote
+ ><p
+ >foo bar</p
+ ></blockquote
+ ></div
+>
diff --git a/tests/lhs-test.html b/tests/lhs-test.html
new file mode 100644
index 000000000..5ab1ee102
--- /dev/null
+++ b/tests/lhs-test.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+><head
+ ><title
+ ></title
+ ><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
+ /><meta name="generator" content="pandoc"
+ /><style type="text/css"
+ >
+table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode, table.sourceCode pre
+ { margin: 0; padding: 0; border: 0; vertical-align: baseline; border: none; }
+td.lineNumbers { border-right: 1px solid #AAAAAA; text-align: right; color: #AAAAAA; padding-right: 5px; padding-left: 5px; }
+td.sourceCode { padding-left: 5px; }
+pre.sourceCode { }
+pre.sourceCode span.Normal { }
+pre.sourceCode span.Keyword { color: #007020; font-weight: bold; }
+pre.sourceCode span.DataType { color: #902000; }
+pre.sourceCode span.DecVal { color: #40a070; }
+pre.sourceCode span.BaseN { color: #40a070; }
+pre.sourceCode span.Float { color: #40a070; }
+pre.sourceCode span.Char { color: #4070a0; }
+pre.sourceCode span.String { color: #4070a0; }
+pre.sourceCode span.Comment { color: #60a0b0; font-style: italic; }
+pre.sourceCode span.Others { color: #007020; }
+pre.sourceCode span.Alert { color: red; font-weight: bold; }
+pre.sourceCode span.Function { color: #06287e; }
+pre.sourceCode span.RegionMarker { }
+pre.sourceCode span.Error { color: red; font-weight: bold; }
+</style
+ ></head
+ ><body
+ ><div id="lhs-test"
+ ><h1
+ >lhs test</h1
+ ><p
+ ><code
+ >unsplit</code
+ > is an arrow that takes a pair of values and combines them to return a single value:</p
+ ><pre class="sourceCode haskell"
+ ><code
+ ><span class="Function FunctionDefinition"
+ >unsplit ::</span
+ ><span class="Normal NormalText"
+ > (Arrow a) =&gt; (b -&gt; c -&gt; d) -&gt; a (b, c) d</span
+ ><br
+ /><span class="Normal NormalText"
+ >unsplit = arr . </span
+ ><span class="Function"
+ >uncurry</span
+ ><span class="Normal NormalText"
+ > </span
+ ><br
+ /><span class="Normal NormalText"
+ > </span
+ ><span class="Comment"
+ >-- arr (\op (x,y) -&gt; x `op` y) </span
+ ><br
+ /></code
+ ></pre
+ ><p
+ ><code
+ >(***)</code
+ > combines two arrows into a new arrow by running the two arrows on a pair of values (one arrow on the first item of the pair and one arrow on the second item of the pair).</p
+ ><pre
+ ><code
+ >f *** g = first f &gt;&gt;&gt; second g
+</code
+ ></pre
+ ><p
+ >Block quote:</p
+ ><blockquote
+ ><p
+ >foo bar</p
+ ></blockquote
+ ></div
+ ></body
+ ></html
+>
+
diff --git a/tests/lhs-test.html+lhs b/tests/lhs-test.html+lhs
new file mode 100644
index 000000000..d57ffc652
--- /dev/null
+++ b/tests/lhs-test.html+lhs
@@ -0,0 +1,85 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+><head
+ ><title
+ ></title
+ ><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
+ /><meta name="generator" content="pandoc"
+ /><style type="text/css"
+ >
+table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode, table.sourceCode pre
+ { margin: 0; padding: 0; border: 0; vertical-align: baseline; border: none; }
+td.lineNumbers { border-right: 1px solid #AAAAAA; text-align: right; color: #AAAAAA; padding-right: 5px; padding-left: 5px; }
+td.sourceCode { padding-left: 5px; }
+pre.sourceCode { }
+pre.sourceCode span.Normal { }
+pre.sourceCode span.Keyword { color: #007020; font-weight: bold; }
+pre.sourceCode span.DataType { color: #902000; }
+pre.sourceCode span.DecVal { color: #40a070; }
+pre.sourceCode span.BaseN { color: #40a070; }
+pre.sourceCode span.Float { color: #40a070; }
+pre.sourceCode span.Char { color: #4070a0; }
+pre.sourceCode span.String { color: #4070a0; }
+pre.sourceCode span.Comment { color: #60a0b0; font-style: italic; }
+pre.sourceCode span.Others { color: #007020; }
+pre.sourceCode span.Alert { color: red; font-weight: bold; }
+pre.sourceCode span.Function { color: #06287e; }
+pre.sourceCode span.RegionMarker { }
+pre.sourceCode span.Error { color: red; font-weight: bold; }
+</style
+ ></head
+ ><body
+ ><div id="lhs-test"
+ ><h1
+ >lhs test</h1
+ ><p
+ ><code
+ >unsplit</code
+ > is an arrow that takes a pair of values and combines them to return a single value:</p
+ ><pre class="sourceCode literatehaskell"
+ ><code
+ ><span class="Char Special"
+ >&gt;</span
+ ><span class="Function FunctionDefinition"
+ > unsplit ::</span
+ ><span class="Normal NormalText"
+ > (Arrow a) =&gt; (b -&gt; c -&gt; d) -&gt; a (b, c) d</span
+ ><br
+ /><span class="Char Special"
+ >&gt;</span
+ ><span class="Normal NormalText"
+ > unsplit = arr . </span
+ ><span class="Function"
+ >uncurry</span
+ ><span class="Normal NormalText"
+ > </span
+ ><br
+ /><span class="Char Special"
+ >&gt;</span
+ ><span class="Normal NormalText"
+ > </span
+ ><span class="Comment"
+ >-- arr (\op (x,y) -&gt; x `op` y) </span
+ ><br
+ /></code
+ ></pre
+ ><p
+ ><code
+ >(***)</code
+ > combines two arrows into a new arrow by running the two arrows on a pair of values (one arrow on the first item of the pair and one arrow on the second item of the pair).</p
+ ><pre
+ ><code
+ >f *** g = first f &gt;&gt;&gt; second g
+</code
+ ></pre
+ ><p
+ >Block quote:</p
+ ><blockquote
+ ><p
+ >foo bar</p
+ ></blockquote
+ ></div
+ ></body
+ ></html
+>
+
diff --git a/tests/lhs-test.latex b/tests/lhs-test.latex
new file mode 100644
index 000000000..cd086e033
--- /dev/null
+++ b/tests/lhs-test.latex
@@ -0,0 +1,38 @@
+\documentclass{article}
+\usepackage{amsmath}
+\usepackage[mathletters]{ucs}
+\usepackage[utf8x]{inputenc}
+\usepackage{listings}
+\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+
+
+\setcounter{secnumdepth}{0}
+\author{}
+\begin{document}
+
+\section{lhs test}
+
+\verb!unsplit! is an arrow that takes a pair of values and combines
+them to return a single value:
+
+\begin{verbatim}
+unsplit :: (Arrow a) => (b -> c -> d) -> a (b, c) d
+unsplit = arr . uncurry
+ -- arr (\op (x,y) -> x `op` y)
+\end{verbatim}
+\verb!(***)! combines two arrows into a new arrow by running the
+two arrows on a pair of values (one arrow on the first item of the
+pair and one arrow on the second item of the pair).
+
+\begin{verbatim}
+f *** g = first f >>> second g
+\end{verbatim}
+Block quote:
+
+\begin{quote}
+foo bar
+
+\end{quote}
+\end{document}
diff --git a/tests/lhs-test.latex+lhs b/tests/lhs-test.latex+lhs
new file mode 100644
index 000000000..951cbb81f
--- /dev/null
+++ b/tests/lhs-test.latex+lhs
@@ -0,0 +1,38 @@
+\documentclass{article}
+\usepackage{amsmath}
+\usepackage[mathletters]{ucs}
+\usepackage[utf8x]{inputenc}
+\usepackage{listings}
+\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+
+
+\setcounter{secnumdepth}{0}
+\author{}
+\begin{document}
+
+\section{lhs test}
+
+\verb!unsplit! is an arrow that takes a pair of values and combines
+them to return a single value:
+
+\begin{code}
+unsplit :: (Arrow a) => (b -> c -> d) -> a (b, c) d
+unsplit = arr . uncurry
+ -- arr (\op (x,y) -> x `op` y)
+\end{code}
+\verb!(***)! combines two arrows into a new arrow by running the
+two arrows on a pair of values (one arrow on the first item of the
+pair and one arrow on the second item of the pair).
+
+\begin{verbatim}
+f *** g = first f >>> second g
+\end{verbatim}
+Block quote:
+
+\begin{quote}
+foo bar
+
+\end{quote}
+\end{document}
diff --git a/tests/lhs-test.markdown b/tests/lhs-test.markdown
new file mode 100644
index 000000000..5b7c6465a
--- /dev/null
+++ b/tests/lhs-test.markdown
@@ -0,0 +1,21 @@
+# lhs test
+
+`unsplit` is an arrow that takes a pair of values and combines them
+to return a single value:
+
+ unsplit :: (Arrow a) => (b -> c -> d) -> a (b, c) d
+ unsplit = arr . uncurry
+ -- arr (\op (x,y) -> x `op` y)
+
+`(***)` combines two arrows into a new arrow by running the two
+arrows on a pair of values (one arrow on the first item of the pair
+and one arrow on the second item of the pair).
+
+ f *** g = first f >>> second g
+
+Block quote:
+
+> foo bar
+
+
+
diff --git a/tests/lhs-test.markdown+lhs b/tests/lhs-test.markdown+lhs
new file mode 100644
index 000000000..fa8564a98
--- /dev/null
+++ b/tests/lhs-test.markdown+lhs
@@ -0,0 +1,22 @@
+lhs test
+========
+
+`unsplit` is an arrow that takes a pair of values and combines them
+to return a single value:
+
+> unsplit :: (Arrow a) => (b -> c -> d) -> a (b, c) d
+> unsplit = arr . uncurry
+> -- arr (\op (x,y) -> x `op` y)
+
+`(***)` combines two arrows into a new arrow by running the two
+arrows on a pair of values (one arrow on the first item of the pair
+and one arrow on the second item of the pair).
+
+ f *** g = first f >>> second g
+
+Block quote:
+
+ > foo bar
+
+
+
diff --git a/tests/lhs-test.native b/tests/lhs-test.native
new file mode 100644
index 000000000..cd4f45bfa
--- /dev/null
+++ b/tests/lhs-test.native
@@ -0,0 +1,11 @@
+Pandoc (Meta [] [] "")
+[ Header 1 [Str "lhs",Space,Str "test"]
+, Para [Code "unsplit",Space,Str "is",Space,Str "an",Space,Str "arrow",Space,Str "that",Space,Str "takes",Space,Str "a",Space,Str "pair",Space,Str "of",Space,Str "values",Space,Str "and",Space,Str "combines",Space,Str "them",Space,Str "to",Space,Str "return",Space,Str "a",Space,Str "single",Space,Str "value:"]
+, CodeBlock ("",["sourceCode","haskell"],[]) "unsplit :: (Arrow a) => (b -> c -> d) -> a (b, c) d\nunsplit = arr . uncurry \n -- arr (\\op (x,y) -> x `op` y) "
+, Para [Code "(***)",Space,Str "combines",Space,Str "two",Space,Str "arrows",Space,Str "into",Space,Str "a",Space,Str "new",Space,Str "arrow",Space,Str "by",Space,Str "running",Space,Str "the",Space,Str "two",Space,Str "arrows",Space,Str "on",Space,Str "a",Space,Str "pair",Space,Str "of",Space,Str "values",Space,Str "(one",Space,Str "arrow",Space,Str "on",Space,Str "the",Space,Str "first",Space,Str "item",Space,Str "of",Space,Str "the",Space,Str "pair",Space,Str "and",Space,Str "one",Space,Str "arrow",Space,Str "on",Space,Str "the",Space,Str "second",Space,Str "item",Space,Str "of",Space,Str "the",Space,Str "pair)",Str "."]
+, CodeBlock ("",[],[]) "f *** g = first f >>> second g"
+, Para [Str "Block",Space,Str "quote:"]
+, BlockQuote
+ [ Para [Str "foo",Space,Str "bar"] ]
+ ]
+
diff --git a/tests/lhs-test.rst b/tests/lhs-test.rst
new file mode 100644
index 000000000..c567fb4ed
--- /dev/null
+++ b/tests/lhs-test.rst
@@ -0,0 +1,26 @@
+lhs test
+========
+
+``unsplit`` is an arrow that takes a pair of values and combines
+them to return a single value:
+
+::
+
+ unsplit :: (Arrow a) => (b -> c -> d) -> a (b, c) d
+ unsplit = arr . uncurry
+ -- arr (\op (x,y) -> x `op` y)
+
+``(***)`` combines two arrows into a new arrow by running the two
+arrows on a pair of values (one arrow on the first item of the pair
+and one arrow on the second item of the pair).
+
+::
+
+ f *** g = first f >>> second g
+
+Block quote:
+
+ foo bar
+
+
+
diff --git a/tests/lhs-test.rst+lhs b/tests/lhs-test.rst+lhs
new file mode 100644
index 000000000..7feeea2dc
--- /dev/null
+++ b/tests/lhs-test.rst+lhs
@@ -0,0 +1,24 @@
+lhs test
+========
+
+``unsplit`` is an arrow that takes a pair of values and combines
+them to return a single value:
+
+> unsplit :: (Arrow a) => (b -> c -> d) -> a (b, c) d
+> unsplit = arr . uncurry
+> -- arr (\op (x,y) -> x `op` y)
+
+``(***)`` combines two arrows into a new arrow by running the two
+arrows on a pair of values (one arrow on the first item of the pair
+and one arrow on the second item of the pair).
+
+::
+
+ f *** g = first f >>> second g
+
+Block quote:
+
+ foo bar
+
+
+
diff --git a/tests/markdown-reader-more.native b/tests/markdown-reader-more.native
new file mode 100644
index 000000000..3160f0cd3
--- /dev/null
+++ b/tests/markdown-reader-more.native
@@ -0,0 +1,17 @@
+Pandoc (Meta [] [] "")
+[ Header 1 [Str "Additional",Space,Str "markdown",Space,Str "reader",Space,Str "tests"]
+, Header 2 [Str "Blank",Space,Str "line",Space,Str "before",Space,Str "URL",Space,Str "in",Space,Str "link",Space,Str "reference"]
+, Para [Link [Str "foo"] ("/url",""),Space,Str "and",Space,Link [Str "bar"] ("/url","title")]
+, Header 2 [Str "Raw",Space,Str "ConTeXt",Space,Str "environments"]
+, Para [TeX "\\placeformula",Space,TeX "\\startformula\n L_{1} = L_{2}\n \\stopformula"]
+, Para [TeX "\\start[a2]\n\\start[a2]\n\\stop[a2]\n\\stop[a2]"]
+, Header 2 [Str "URLs",Space,Str "with",Space,Str "spaces"]
+, Para [Link [Str "foo"] ("/bar%20and%20baz",""),Space,Link [Str "foo"] ("/bar%20and%20baz",""),Space,Link [Str "foo"] ("/bar%20and%20baz",""),Space,Link [Str "foo"] ("bar%20baz","title")]
+, Para [Link [Str "baz"] ("/foo%20foo",""),Space,Link [Str "bam"] ("/foo%20fee",""),Space,Link [Str "bork"] ("/foo/zee%20zob","title")]
+, Header 2 [Str "Horizontal",Space,Str "rules",Space,Str "with",Space,Str "spaces",Space,Str "at",Space,Str "end"]
+, HorizontalRule
+, HorizontalRule
+, Header 2 [Str "Raw",Space,Str "HTML",Space,Str "before",Space,Str "header"]
+, Plain [HtmlInline "<a>",HtmlInline "</a>"]
+, Header 3 [Str "my",Space,Str "header"] ]
+
diff --git a/tests/markdown-reader-more.txt b/tests/markdown-reader-more.txt
new file mode 100644
index 000000000..d2315046f
--- /dev/null
+++ b/tests/markdown-reader-more.txt
@@ -0,0 +1,49 @@
+# Additional markdown reader tests
+
+## Blank line before URL in link reference
+
+[foo] and [bar]
+
+[foo]:
+ /url
+
+[bar]:
+/url
+"title"
+
+## Raw ConTeXt environments
+
+\placeformula \startformula
+ L_{1} = L_{2}
+ \stopformula
+
+\start[a2]
+\start[a2]
+\stop[a2]
+\stop[a2]
+
+## URLs with spaces
+
+[foo](/bar and baz)
+[foo](/bar and baz )
+[foo]( /bar and baz )
+[foo](bar baz "title" )
+
+[baz][] [bam][] [bork][]
+
+[baz]: /foo foo
+[bam]: /foo fee
+[bork]: /foo/zee zob (title)
+
+## Horizontal rules with spaces at end
+
+* * * * *
+
+-- - -- -- -
+
+## Raw HTML before header
+
+<a></a>
+
+### my header
+
diff --git a/tests/movie.jpg b/tests/movie.jpg
new file mode 100644
index 000000000..7240efa3b
--- /dev/null
+++ b/tests/movie.jpg
Binary files differ
diff --git a/tests/rst-reader.native b/tests/rst-reader.native
new file mode 100644
index 000000000..8848fa111
--- /dev/null
+++ b/tests/rst-reader.native
@@ -0,0 +1,245 @@
+Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite",Str ":",Space,Str "Subtitle"] ["John MacFarlane","Anonymous"] "July 17, 2006")
+[ DefinitionList
+ [ ([Str "Revision"],
+ [ Plain [Str "3"] ]
+ ) ]
+, Header 1 [Str "Level",Space,Str "one",Space,Str "header"]
+, Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber's",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
+, Header 2 [Str "Level",Space,Str "two",Space,Str "header"]
+, Header 3 [Str "Level",Space,Str "three"]
+, Header 4 [Str "Level",Space,Str "four",Space,Str "with",Space,Emph [Str "emphasis"]]
+, Header 5 [Str "Level",Space,Str "five"]
+, Header 1 [Str "Paragraphs"]
+, Para [Str "Here's",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
+, Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",Space,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item.",Space,Str "Because",Space,Str "a",Space,Str "hard",Str "-",Str "wrapped",Space,Str "line",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",Space,Str "list",Space,Str "item."]
+, Para [Str "Here's",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",Space,Str "*",Space,Str "criminey."]
+, Para [Str "Horizontal",Space,Str "rule",Str ":"]
+, HorizontalRule
+, Para [Str "Another",Str ":"]
+, HorizontalRule
+, Header 1 [Str "Block",Space,Str "Quotes"]
+, Para [Str "Here's",Space,Str "a",Space,Str "block",Space,Str "quote",Str ":"]
+, BlockQuote
+ [ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",Space,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."] ]
+
+, Para [Str "Here's",Space,Str "another,",Space,Str "differently",Space,Str "indented",Str ":"]
+, BlockQuote
+ [ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",Space,Str "It's",Space,Str "indented",Space,Str "with",Space,Str "a",Space,Str "tab."]
+ , Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote",Str ":"]
+ , CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
+ , Para [Str "List",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote",Str ":"]
+ , OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "item",Space,Str "one"] ]
+ , [ Plain [Str "item",Space,Str "two"] ] ]
+ , Para [Str "Nested",Space,Str "block",Space,Str "quotes",Str ":"]
+ , BlockQuote
+ [ Para [Str "nested"]
+ , BlockQuote
+ [ Para [Str "nested"] ]
+ ] ]
+, Header 1 [Str "Code",Space,Str "Blocks"]
+, Para [Str "Code",Str ":"]
+, CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}"
+, CodeBlock ("",[],[]) "this code block is indented by one tab"
+, Para [Str "And",Str ":"]
+, CodeBlock ("",[],[]) "this block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
+, Header 1 [Str "Lists"]
+, Header 2 [Str "Unordered"]
+, Para [Str "Asterisks",Space,Str "tight",Str ":"]
+, BulletList
+ [ [ Plain [Str "asterisk",Space,Str "1"] ]
+ , [ Plain [Str "asterisk",Space,Str "2"] ]
+ , [ Plain [Str "asterisk",Space,Str "3"] ] ]
+, Para [Str "Asterisks",Space,Str "loose",Str ":"]
+, BulletList
+ [ [ Para [Str "asterisk",Space,Str "1"] ]
+ , [ Para [Str "asterisk",Space,Str "2"] ]
+ , [ Para [Str "asterisk",Space,Str "3"] ] ]
+, Para [Str "Pluses",Space,Str "tight",Str ":"]
+, BulletList
+ [ [ Plain [Str "Plus",Space,Str "1"] ]
+ , [ Plain [Str "Plus",Space,Str "2"] ]
+ , [ Plain [Str "Plus",Space,Str "3"] ] ]
+, Para [Str "Pluses",Space,Str "loose",Str ":"]
+, BulletList
+ [ [ Para [Str "Plus",Space,Str "1"] ]
+ , [ Para [Str "Plus",Space,Str "2"] ]
+ , [ Para [Str "Plus",Space,Str "3"] ] ]
+, Para [Str "Minuses",Space,Str "tight",Str ":"]
+, BulletList
+ [ [ Plain [Str "Minus",Space,Str "1"] ]
+ , [ Plain [Str "Minus",Space,Str "2"] ]
+ , [ Plain [Str "Minus",Space,Str "3"] ] ]
+, Para [Str "Minuses",Space,Str "loose",Str ":"]
+, BulletList
+ [ [ Para [Str "Minus",Space,Str "1"] ]
+ , [ Para [Str "Minus",Space,Str "2"] ]
+ , [ Para [Str "Minus",Space,Str "3"] ] ]
+, Header 2 [Str "Ordered"]
+, Para [Str "Tight",Str ":"]
+, OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "First"] ]
+ , [ Plain [Str "Second"] ]
+ , [ Plain [Str "Third"] ] ]
+, Para [Str "and",Str ":"]
+, OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "One"] ]
+ , [ Plain [Str "Two"] ]
+ , [ Plain [Str "Three"] ] ]
+, Para [Str "Loose",Space,Str "using",Space,Str "tabs",Str ":"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "First"] ]
+ , [ Para [Str "Second"] ]
+ , [ Para [Str "Third"] ] ]
+, Para [Str "and",Space,Str "using",Space,Str "spaces",Str ":"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "One"] ]
+ , [ Para [Str "Two"] ]
+ , [ Para [Str "Three"] ] ]
+, Para [Str "Multiple",Space,Str "paragraphs",Str ":"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
+ , Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog's",Space,Str "back."] ], [ Para [Str "Item",Space,Str "2."] ]
+ , [ Para [Str "Item",Space,Str "3."] ] ]
+, Para [Str "Nested",Str ":"]
+, BulletList
+ [ [ Para [Str "Tab"]
+ , BulletList
+ [ [ Para [Str "Tab"]
+ , BulletList
+ [ [ Plain [Str "Tab"] ]
+ ] ] ] ] ]
+, Para [Str "Here's",Space,Str "another",Str ":"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "First"] ]
+ , [ Para [Str "Second",Str ":"]
+ , BlockQuote
+ [ BulletList
+ [ [ Plain [Str "Fee"] ]
+ , [ Plain [Str "Fie"] ]
+ , [ Plain [Str "Foe"] ] ] ] ], [ Para [Str "Third"] ] ]
+, Header 2 [Str "Fancy",Space,Str "list",Space,Str "markers"]
+, OrderedList (2,Decimal,TwoParens)
+ [ [ Plain [Str "begins",Space,Str "with",Space,Str "2"] ]
+ , [ Para [Str "and",Space,Str "now",Space,Str "3"]
+ , Para [Str "with",Space,Str "a",Space,Str "continuation"]
+ , OrderedList (4,LowerRoman,Period)
+ [ [ Plain [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",Space,Str "starting",Space,Str "with",Space,Str "4"] ]
+ , [ Para [Str "more",Space,Str "items"]
+ , OrderedList (1,UpperAlpha,TwoParens)
+ [ [ Plain [Str "a",Space,Str "subsublist"] ]
+ , [ Plain [Str "a",Space,Str "subsublist"] ] ] ] ] ] ]
+, Para [Str "Nesting",Str ":"]
+, OrderedList (1,UpperAlpha,Period)
+ [ [ Para [Str "Upper",Space,Str "Alpha"]
+ , OrderedList (1,UpperRoman,Period)
+ [ [ Para [Str "Upper",Space,Str "Roman."]
+ , OrderedList (6,Decimal,TwoParens)
+ [ [ Para [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
+ , OrderedList (3,LowerAlpha,OneParen)
+ [ [ Plain [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"] ]
+ ] ] ] ] ] ] ]
+, Para [Str "Autonumbering",Str ":"]
+, OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "Autonumber."] ]
+ , [ Para [Str "More."]
+ , OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "Nested."] ]
+ ] ] ]
+, Para [Str "Autonumbering",Space,Str "with",Space,Str "explicit",Space,Str "start",Str ":"]
+, OrderedList (4,LowerAlpha,TwoParens)
+ [ [ Plain [Str "item",Space,Str "1"] ]
+ , [ Plain [Str "item",Space,Str "2"] ] ]
+, Header 2 [Str "Definition"]
+, DefinitionList
+ [ ([Str "term",Space,Str "1"],
+ [ Para [Str "Definition",Space,Str "1."] ]
+ ),
+ ([Str "term",Space,Str "2"],
+ [ Para [Str "Definition",Space,Str "2,",Space,Str "paragraph",Space,Str "1."]
+ , Para [Str "Definition",Space,Str "2,",Space,Str "paragraph",Space,Str "2."] ] ),
+ ([Str "term",Space,Str "with",Space,Emph [Str "emphasis"]],
+ [ Para [Str "Definition",Space,Str "3."] ]
+ ) ]
+, Header 1 [Str "Field",Space,Str "Lists"]
+, DefinitionList
+ [ ([Str "address"],
+ [ Plain [Str "61",Space,Str "Main",Space,Str "St."] ]
+ ),
+ ([Str "city"],
+ [ Plain [Emph [Str "Nowhere"],Str ",",Space,Str "MA,",Space,Str "USA"] ]
+ ),
+ ([Str "phone"],
+ [ Plain [Str "123",Str "-",Str "4567"] ]
+ ) ]
+, DefinitionList
+ [ ([Str "address"],
+ [ Plain [Str "61",Space,Str "Main",Space,Str "St."] ]
+ ),
+ ([Str "city"],
+ [ Plain [Emph [Str "Nowhere"],Str ",",Space,Str "MA,",Space,Str "USA"] ]
+ ),
+ ([Str "phone"],
+ [ Plain [Str "123",Str "-",Str "4567"] ]
+ ) ]
+, Header 1 [Str "HTML",Space,Str "Blocks"]
+, Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line",Str ":"]
+, RawHtml "<div>foo</div>\n"
+, Para [Str "Now,",Space,Str "nested",Str ":"]
+, RawHtml "<div>\n <div>\n <div>\n foo\n </div>\n </div>\n</div>\n"
+, Header 1 [Str "LaTeX",Space,Str "Block"]
+, Para [TeX "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}\n"]
+, Header 1 [Str "Inline",Space,Str "Markup"]
+, Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ".",Space,Str "This",Space,Str "is",Space,Strong [Str "strong"],Str "."]
+, Para [Str "This",Space,Str "is",Space,Str "code",Str ":",Space,Code ">",Str ",",Space,Code "$",Str ",",Space,Code "\\",Str ",",Space,Code "\\$",Str ",",Space,Code "<html>",Str "."]
+, Para [Str "This",Space,Str "is",Subscript [Str "subscripted"],Space,Str "and",Space,Str "this",Space,Str "is",Space,Superscript [Str "superscripted"],Str "."]
+, Header 1 [Str "Special",Space,Str "Characters"]
+, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode",Str ":"]
+, BulletList
+ [ [ Plain [Str "I",Space,Str "hat",Str ":",Space,Str "\206"] ]
+ , [ Plain [Str "o",Space,Str "umlaut",Str ":",Space,Str "\246"] ]
+ , [ Plain [Str "section",Str ":",Space,Str "\167"] ]
+ , [ Plain [Str "set",Space,Str "membership",Str ":",Space,Str "\8712"] ]
+ , [ Plain [Str "copyright",Str ":",Space,Str "\169"] ] ]
+, Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
+, Para [Str "This",Space,Str "&",Space,Str "that."]
+, Para [Str "4",Space,Str "<",Space,Str "5."]
+, Para [Str "6",Space,Str ">",Space,Str "5."]
+, Para [Str "Backslash",Str ":",Space,Str "\\"]
+, Para [Str "Backtick",Str ":",Space,Str "`"]
+, Para [Str "Asterisk",Str ":",Space,Str "*"]
+, Para [Str "Underscore",Str ":",Space,Str "_"]
+, Para [Str "Left",Space,Str "brace",Str ":",Space,Str "{"]
+, Para [Str "Right",Space,Str "brace",Str ":",Space,Str "}"]
+, Para [Str "Left",Space,Str "bracket",Str ":",Space,Str "["]
+, Para [Str "Right",Space,Str "bracket",Str ":",Space,Str "]"]
+, Para [Str "Left",Space,Str "paren",Str ":",Space,Str "("]
+, Para [Str "Right",Space,Str "paren",Str ":",Space,Str ")"]
+, Para [Str "Greater",Str "-",Str "than",Str ":",Space,Str ">"]
+, Para [Str "Hash",Str ":",Space,Str "#"]
+, Para [Str "Period",Str ":",Space,Str "."]
+, Para [Str "Bang",Str ":",Space,Str "!"]
+, Para [Str "Plus",Str ":",Space,Str "+"]
+, Para [Str "Minus",Str ":",Space,Str "-"]
+, Header 1 [Str "Links"]
+, Para [Str "Explicit",Str ":",Space,Str "a",Space,Link [Str "URL"] ("/url/",""),Str "."]
+, Para [Str "Two",Space,Str "anonymous",Space,Str "links",Str ":",Space,Link [Str "the",Space,Str "first"] ("/url1/",""),Space,Str "and",Space,Link [Str "the",Space,Str "second"] ("/url2/","")]
+, Para [Str "Reference",Space,Str "links",Str ":",Space,Link [Str "link1"] ("/url1/",""),Space,Str "and",Space,Link [Str "link2"] ("/url2/",""),Space,Str "and",Space,Link [Str "link1"] ("/url1/",""),Space,Str "again."]
+, Para [Str "Here's",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
+, Para [Str "Here's",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text",Str ":",Space,Link [Str "AT&T"] ("/url/",""),Str "."]
+, Para [Str "Autolinks",Str ":",Space,Link [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2",""),Space,Str "and",Space,Link [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net",""),Str "."]
+, Para [Str "But",Space,Str "not",Space,Str "here",Str ":"]
+, CodeBlock ("",[],[]) "http://example.com/"
+, Header 1 [Str "Images"]
+, Para [Str "From",Space,Str "\"Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune\"",Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902)",Str ":"]
+, Plain [Image [Str "image"] ("lalune.jpg","")]
+, Plain [Image [Str "Voyage dans la Lune"] ("lalune.jpg","Voyage dans la Lune")]
+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] ("movie.jpg",""),Space,Str "icon."]
+, Header 1 [Str "Comments"]
+, Para [Str "First",Space,Str "paragraph"]
+, Para [Str "Another",Space,Str "paragraph"]
+, Para [Str "A",Space,Str "third",Space,Str "paragraph"]
+, Header 1 [Str "Line",Space,Str "blocks"]
+, Para [Str "But",Space,Str "can",Space,Str "a",Space,Str "bee",Space,Str "be",Space,Str "said",Space,Str "to",Space,Str "be",LineBreak,Str " ",Str "or",Space,Str "not",Space,Str "to",Space,Str "be",Space,Str "an",Space,Str "entire",Space,Str "bee,",LineBreak,Str " ",Str "when",Space,Str "half",Space,Str "the",Space,Str "bee",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "bee,",LineBreak,Str " ",Str "due",Space,Str "to",Space,Str "some",Space,Str "ancient",Space,Str "injury?"]
+, Para [Str "Continuation",Space,Str "line",LineBreak,Str " ",Str "and",Space,Str "another"] ]
+
diff --git a/tests/rst-reader.rst b/tests/rst-reader.rst
new file mode 100644
index 000000000..2cc99d294
--- /dev/null
+++ b/tests/rst-reader.rst
@@ -0,0 +1,448 @@
+Pandoc Test Suite
+#################
+Subtitle
+^^^^^^^^
+
+:Author: John MacFarlane
+:Author: Anonymous
+:Date: July 17, 2006
+:Revision: 3
+
+Level one header
+================
+
+This is a set of tests for pandoc. Most of them are adapted from
+John Gruber's markdown test suite.
+
+Level two header
+----------------
+
+Level three
++++++++++++
+
+Level four with *emphasis*
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Level five
+''''''''''
+
+Paragraphs
+==========
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version
+8. This line turns into a list item.
+Because a hard-wrapped line in the
+middle of a paragraph looked like a
+list item.
+
+Here's one with a bullet.
+* criminey.
+
+Horizontal rule:
+
+-----
+
+Another:
+
+****
+
+Block Quotes
+============
+
+Here's a block quote:
+
+ This is a block quote.
+ It is pretty short.
+
+Here's another, differently indented:
+
+ This is a block quote.
+ It's indented with a tab.
+
+ Code in a block quote::
+
+ sub status {
+ print "working";
+ }
+
+ List in a block quote:
+
+ 1. item one
+ 2. item two
+
+ Nested block quotes:
+
+ nested
+
+ nested
+
+Code Blocks
+===========
+
+Code:
+
+::
+
+ ---- (should be four hyphens)
+
+ sub status {
+ print "working";
+ }
+
+::
+
+ this code block is indented by one tab
+
+And::
+
+ this block is indented by two tabs
+
+ These should not be escaped: \$ \\ \> \[ \{
+
+Lists
+=====
+
+Unordered
+---------
+
+Asterisks tight:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+
+Asterisks loose:
+
+* asterisk 1
+
+* asterisk 2
+
+* asterisk 3
+
+Pluses tight:
+
++ Plus 1
++ Plus 2
++ Plus 3
+
+Pluses loose:
+
++ Plus 1
+
++ Plus 2
+
++ Plus 3
+
+Minuses tight:
+
+- Minus 1
+- Minus 2
+- Minus 3
+
+Minuses loose:
+
+- Minus 1
+
+- Minus 2
+
+- Minus 3
+
+Ordered
+-------
+
+Tight:
+
+1. First
+2. Second
+3. Third
+
+and:
+
+1. One
+2. Two
+3. Three
+
+Loose using tabs:
+
+1. First
+
+2. Second
+
+3. Third
+
+and using spaces:
+
+1. One
+
+2. Two
+
+3. Three
+
+Multiple paragraphs:
+
+1. Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's
+ back.
+
+2. Item 2.
+
+3. Item 3.
+
+Nested:
+
+* Tab
+
+ * Tab
+
+ * Tab
+
+Here's another:
+
+1. First
+
+2. Second:
+
+ * Fee
+ * Fie
+ * Foe
+
+3. Third
+
+Fancy list markers
+------------------
+
+(2) begins with 2
+(3) and now 3
+
+ with a continuation
+
+ iv. sublist with roman numerals, starting with 4
+ v. more items
+
+ (A) a subsublist
+ (B) a subsublist
+
+Nesting:
+
+A. Upper Alpha
+
+ I. Upper Roman.
+
+ (6) Decimal start with 6
+
+ c) Lower alpha with paren
+
+Autonumbering:
+
+#. Autonumber.
+#. More.
+
+ #. Nested.
+
+Autonumbering with explicit start:
+
+(d) item 1
+(#) item 2
+
+Definition
+----------
+
+term 1
+ Definition 1.
+
+term 2
+ Definition 2, paragraph 1.
+
+ Definition 2, paragraph 2.
+
+term with *emphasis*
+ Definition 3.
+
+Field Lists
+===========
+
+ :address: 61 Main St.
+ :city: *Nowhere*, MA,
+ USA
+ :phone: 123-4567
+
+:address: 61 Main St.
+:city: *Nowhere*, MA,
+ USA
+:phone: 123-4567
+
+HTML Blocks
+===========
+
+Simple block on one line:
+
+.. raw:: html
+
+ <div>foo</div>
+
+Now, nested:
+
+.. raw:: html
+
+ <div>
+ <div>
+ <div>
+ foo
+ </div>
+ </div>
+ </div>
+
+LaTeX Block
+===========
+
+.. raw:: latex
+
+ \begin{tabular}{|l|l|}\hline
+ Animal & Number \\ \hline
+ Dog & 2 \\
+ Cat & 1 \\ \hline
+ \end{tabular}
+
+Inline Markup
+=============
+
+This is *emphasized*. This is **strong**.
+
+This is code: ``>``, ``$``, ``\``, ``\$``, ``<html>``.
+
+This is\ :sub:`subscripted` and this is :sup:`superscripted`\ .
+
+Special Characters
+==================
+
+Here is some unicode:
+
+- I hat: Î
+- o umlaut: ö
+- section: §
+- set membership: ∈
+- copyright: ©
+
+AT&T has an ampersand in their name.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \\
+
+Backtick: \`
+
+Asterisk: \*
+
+Underscore: \_
+
+Left brace: \{
+
+Right brace: \}
+
+Left bracket: \[
+
+Right bracket: \]
+
+Left paren: \(
+
+Right paren: \)
+
+Greater-than: \>
+
+Hash: \#
+
+Period: \.
+
+Bang: \!
+
+Plus: \+
+
+Minus: \-
+
+Links
+=====
+
+Explicit: a `URL </url/>`_.
+
+Two anonymous links: `the first`__ and `the second`__
+
+__ /url1/
+__ /url2/
+
+Reference links: `link1`_ and `link2`_ and link1_ again.
+
+.. _link1: /url1/
+.. _`link2`: /url2/
+
+Here's a `link with an ampersand in the URL`_.
+
+Here's a link with an amersand in the link text: `AT&T </url/>`_.
+
+.. _link with an ampersand in the URL: http://example.com/?foo=1&bar=2
+
+Autolinks: http://example.com/?foo=1&bar=2 and nobody@nowhere.net.
+
+But not here::
+
+ http://example.com/
+
+Images
+======
+
+From "Voyage dans la Lune" by Georges Melies (1902):
+
+.. image:: lalune.jpg
+
+.. image:: lalune.jpg
+ :height: 2343
+ :alt: Voyage dans la Lune
+
+Here is a movie |movie| icon.
+
+.. |movie| image:: movie.jpg
+
+Comments
+========
+
+First paragraph
+
+.. comment
+
+..
+ Comment block, should not appear in output
+ as defined by reStructuredText
+
+Another paragraph
+
+..
+ Another comment block.
+
+ This one spans several
+ text elements.
+
+ It doesn't end until
+ indentation is restored to the
+ preceding level.
+
+A third paragraph
+
+Line blocks
+===========
+
+| But can a bee be said to be
+| or not to be an entire bee,
+| when half the bee is not a bee,
+| due to some ancient injury?
+
+| Continuation
+ line
+| and
+ another
+
diff --git a/tests/s5.basic.html b/tests/s5.basic.html
new file mode 100644
index 000000000..bb2b25ae3
--- /dev/null
+++ b/tests/s5.basic.html
@@ -0,0 +1,343 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+><head
+ ><title
+ >My S5 Document</title
+ ><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
+ /><meta name="generator" content="pandoc"
+ /><meta name="author" content="Sam Smith"
+ /><meta name="author" content="Jen Jones"
+ /><meta name="date" content="July 15, 2006"
+ /><!-- configuration parameters -->
+<meta name="defaultView" content="slideshow" />
+<meta name="controlVis" content="hidden" />
+<style type="text/css" media="projection" id="slideProj">
+/* Do not edit or override these styles! The system will likely break if you do. */
+
+div#header, div#footer, div#controls, .slide {position: absolute;}
+html>body div#header, html>body div#footer,
+ html>body div#controls, html>body .slide {position: fixed;}
+.handout {display: none;}
+.layout {display: block;}
+.slide, .hideme, .incremental {visibility: hidden;}
+#slide0 {visibility: visible;}
+
+/* The following styles size, place, and layer the slide components.
+ Edit these if you want to change the overall slide layout.
+ The commented lines can be uncommented (and modified, if necessary)
+ to help you with the rearrangement process. */
+
+/* target = 1024x768 */
+
+div#header, div#footer, .slide {width: 100%; top: 0; left: 0;}
+div#header {top: 0; height: 3em; z-index: 1;}
+div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;}
+.slide {top: 0; width: 92%; padding: 3.5em 4% 4%; z-index: 2; list-style: none;}
+div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0;}
+#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em; z-index: 10;}
+html>body #currentSlide {position: fixed;}
+
+/*
+div#header {background: #FCC;}
+div#footer {background: #CCF;}
+div#controls {background: #BBD;}
+div#currentSlide {background: #FFC;}
+*/
+
+/* Following are the presentation styles -- edit away! */
+
+body {background: #FFF url(bodybg.gif) -16px 0 no-repeat; color: #000; font-size: 2em;}
+:link, :visited {text-decoration: none; color: #00C;}
+#controls :active {color: #88A !important;}
+#controls :focus {outline: 1px dotted #227;}
+h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;}
+ul, pre {margin: 0; line-height: 1em;}
+html, body {margin: 0; padding: 0;}
+
+blockquote, q {font-style: italic;}
+blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em; text-align: center; font-size: 1em;}
+blockquote p {margin: 0;}
+blockquote i {font-style: normal;}
+blockquote b {display: block; margin-top: 0.5em; font-weight: normal; font-size: smaller; font-style: normal;}
+blockquote b i {font-style: italic;}
+
+kbd {font-weight: bold; font-size: 1em;}
+sup {font-size: smaller; line-height: 1px;}
+
+.slide code {padding: 2px 0.25em; font-weight: bold; color: #533;}
+.slide code.bad, code del {color: red;}
+.slide code.old {color: silver;}
+.slide pre {padding: 0; margin: 0.25em 0 0.5em 0.5em; color: #533; font-size: 90%;}
+.slide pre code {display: block;}
+.slide ul {margin-left: 5%; margin-right: 7%; list-style: disc;}
+.slide li {margin-top: 0.75em; margin-right: 0;}
+.slide ul ul {line-height: 1;}
+.slide ul ul li {margin: .2em; font-size: 85%; list-style: square;}
+.slide img.leader {display: block; margin: 0 auto;}
+
+div#header, div#footer {background: #005; color: #AAB;
+ font-family: Verdana, Helvetica, sans-serif;}
+div#header {background: #005 url(bodybg.gif) -16px 0 no-repeat;
+ line-height: 1px;}
+div#footer {font-size: 0.5em; font-weight: bold; padding: 1em 0;}
+#footer h1, #footer h2 {display: block; padding: 0 1em;}
+#footer h2 {font-style: italic;}
+
+div.long {font-size: 0.75em;}
+.slide h1 {position: absolute; top: 0.7em; left: 87px; z-index: 1;
+ margin: 0; padding: 0.3em 0 0 50px; white-space: nowrap;
+ font: bold 150%/1em Helvetica, sans-serif; text-transform: capitalize;
+ color: #DDE; background: #005;}
+.slide h3 {font-size: 130%;}
+h1 abbr {font-variant: small-caps;}
+
+div#controls {position: absolute; left: 50%; bottom: 0;
+ width: 50%;
+ text-align: right; font: bold 0.9em Verdana, Helvetica, sans-serif;}
+html>body div#controls {position: fixed; padding: 0 0 1em 0;
+ top: auto;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0; padding: 0;}
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+ background: #005; border: none; color: #779;
+ cursor: pointer;}
+#controls #navList {height: 1em;}
+#controls #navList #jumplist {position: absolute; bottom: 0; right: 0; background: #DDD; color: #227;}
+
+#currentSlide {text-align: center; font-size: 0.5em; color: #449;}
+
+#slide0 {padding-top: 3.5em; font-size: 90%;}
+#slide0 h1 {position: static; margin: 1em 0 0; padding: 0;
+ font: bold 2em Helvetica, sans-serif; white-space: normal;
+ color: #000; background: transparent;}
+#slide0 h2 {font: bold italic 1em Helvetica, sans-serif; margin: 0.25em;}
+#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;}
+#slide0 h4 {margin-top: 0; font-size: 1em;}
+
+ul.urls {list-style: none; display: inline; margin: 0;}
+.urls li {display: inline; margin: 0;}
+.note {display: none;}
+.external {border-bottom: 1px dotted gray;}
+html>body .external {border-bottom: none;}
+.external:after {content: " \274F"; font-size: smaller; color: #77B;}
+
+.incremental, .incremental *, .incremental *:after {color: #DDE; visibility: visible;}
+img.incremental {visibility: hidden;}
+.slide .current {color: #B02;}
+
+
+/* diagnostics
+
+li:after {content: " [" attr(class) "]"; color: #F88;}
+*/
+
+</style>
+<style type="text/css" media="projection" id="operaFix">
+/* DO NOT CHANGE THESE unless you really want to break Opera Show */
+.slide {
+ visibility: visible !important;
+ position: static !important;
+ page-break-before: always;
+}
+#slide0 {page-break-before: avoid;}
+
+</style>
+<style type="text/css" media="screen" id="outlineStyle">
+/* don't change this unless you want the layout stuff to show up in the outline view! */
+
+.layout div, #footer *, #controlForm * {display: none;}
+#footer, #controls, #controlForm, #navLinks, #toggle {
+ display: block; visibility: visible; margin: 0; padding: 0;}
+#toggle {float: right; padding: 0.5em;}
+html>body #toggle {position: fixed; top: 0; right: 0;}
+
+/* making the outline look pretty-ish */
+
+#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;}
+#slide0 h1 {padding-top: 1.5em;}
+.slide h1 {margin: 1.5em 0 0; padding-top: 0.25em;
+ border-top: 1px solid #888; border-bottom: 1px solid #AAA;}
+#toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;}
+
+</style>
+<style type="text/css" media="print" id="slidePrint">
+/* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */
+.slide, ul {page-break-inside: avoid; visibility: visible !important;}
+h1 {page-break-after: avoid;}
+
+body {font-size: 12pt; background: white;}
+* {color: black;}
+
+#slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;}
+#slide0 h3 {margin: 0; padding: 0;}
+#slide0 h4 {margin: 0 0 0.5em; padding: 0;}
+#slide0 {margin-bottom: 3em;}
+
+h1 {border-top: 2pt solid gray; border-bottom: 1px dotted silver;}
+.extra {background: transparent !important;}
+div.extra, pre.extra, .example {font-size: 10pt; color: #333;}
+ul.extra a {font-weight: bold;}
+p.example {display: none;}
+
+#header {display: none;}
+#footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style: italic;}
+#footer h2, #controls {display: none;}
+
+/* The following rule keeps the layout stuff out of print. Remove at your own risk! */
+.layout, .layout * {display: none !important;}
+
+</style>
+<script type="text/javascript">
+// S5 v1.1 slides.js -- released into the Public Domain
+//
+// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information
+// about all the wonderful and talented contributors to this code!
+var undef;var slideCSS='';var snum=0;var smax=1;var incpos=0;var number=undef;var s5mode=true;var defaultView='slideshow';var controlVis='visible';var isIE=navigator.appName=='Microsoft Internet Explorer'&&navigator.userAgent.indexOf('Opera')<1?1:0;var isOp=navigator.userAgent.indexOf('Opera')>-1?1:0;var isGe=navigator.userAgent.indexOf('Gecko')>-1&&navigator.userAgent.indexOf('Safari')<1?1:0;function hasClass(object,className){if(!object.className)return false;return(object.className.search('(^|\\s)'+className+'(\\s|$)')!=-1);}
+function hasValue(object,value){if(!object)return false;return(object.search('(^|\\s)'+value+'(\\s|$)')!=-1);}
+function removeClass(object,className){if(!object)return;object.className=object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'),RegExp.$1+RegExp.$2);}
+function addClass(object,className){if(!object||hasClass(object,className))return;if(object.className){object.className+=' '+className;}else{object.className=className;}}
+function GetElementsWithClassName(elementName,className){var allElements=document.getElementsByTagName(elementName);var elemColl=new Array();for(var i=0;i<allElements.length;i++){if(hasClass(allElements[i],className)){elemColl[elemColl.length]=allElements[i];}}
+return elemColl;}
+function isParentOrSelf(element,id){if(element==null||element.nodeName=='BODY')return false;else if(element.id==id)return true;else return isParentOrSelf(element.parentNode,id);}
+function nodeValue(node){var result="";if(node.nodeType==1){var children=node.childNodes;for(var i=0;i<children.length;++i){result+=nodeValue(children[i]);}}
+else if(node.nodeType==3){result=node.nodeValue;}
+return(result);}
+function slideLabel(){var slideColl=GetElementsWithClassName('*','slide');var list=document.getElementById('jumplist');smax=slideColl.length;for(var n=0;n<smax;n++){var obj=slideColl[n];var did='slide'+n.toString();obj.setAttribute('id',did);if(isOp)continue;var otext='';var menu=obj.firstChild;if(!menu)continue;while(menu&&menu.nodeType==3){menu=menu.nextSibling;}
+if(!menu)continue;var menunodes=menu.childNodes;for(var o=0;o<menunodes.length;o++){otext+=nodeValue(menunodes[o]);}
+list.options[list.length]=new Option(n+' : '+otext,n);}}
+function currentSlide(){var cs;if(document.getElementById){cs=document.getElementById('currentSlide');}else{cs=document.currentSlide;}
+cs.innerHTML='<span id="csHere">'+snum+'<\/span> '+'<span id="csSep">\/<\/span> '+'<span id="csTotal">'+(smax-1)+'<\/span>';if(snum==0){cs.style.visibility='hidden';}else{cs.style.visibility='visible';}}
+function go(step){if(document.getElementById('slideProj').disabled||step==0)return;var jl=document.getElementById('jumplist');var cid='slide'+snum;var ce=document.getElementById(cid);if(incrementals[snum].length>0){for(var i=0;i<incrementals[snum].length;i++){removeClass(incrementals[snum][i],'current');removeClass(incrementals[snum][i],'incremental');}}
+if(step!='j'){snum+=step;lmax=smax-1;if(snum>lmax)snum=lmax;if(snum<0)snum=0;}else
+snum=parseInt(jl.value);var nid='slide'+snum;var ne=document.getElementById(nid);if(!ne){ne=document.getElementById('slide0');snum=0;}
+if(step<0){incpos=incrementals[snum].length}else{incpos=0;}
+if(incrementals[snum].length>0&&incpos==0){for(var i=0;i<incrementals[snum].length;i++){if(hasClass(incrementals[snum][i],'current'))
+incpos=i+1;else
+addClass(incrementals[snum][i],'incremental');}}
+if(incrementals[snum].length>0&&incpos>0)
+addClass(incrementals[snum][incpos-1],'current');ce.style.visibility='hidden';ne.style.visibility='visible';jl.selectedIndex=snum;currentSlide();number=0;}
+function goTo(target){if(target>=smax||target==snum)return;go(target-snum);}
+function subgo(step){if(step>0){removeClass(incrementals[snum][incpos-1],'current');removeClass(incrementals[snum][incpos],'incremental');addClass(incrementals[snum][incpos],'current');incpos++;}else{incpos--;removeClass(incrementals[snum][incpos],'current');addClass(incrementals[snum][incpos],'incremental');addClass(incrementals[snum][incpos-1],'current');}}
+function toggle(){var slideColl=GetElementsWithClassName('*','slide');var slides=document.getElementById('slideProj');var outline=document.getElementById('outlineStyle');if(!slides.disabled){slides.disabled=true;outline.disabled=false;s5mode=false;fontSize('1em');for(var n=0;n<smax;n++){var slide=slideColl[n];slide.style.visibility='visible';}}else{slides.disabled=false;outline.disabled=true;s5mode=true;fontScale();for(var n=0;n<smax;n++){var slide=slideColl[n];slide.style.visibility='hidden';}
+slideColl[snum].style.visibility='visible';}}
+function showHide(action){var obj=GetElementsWithClassName('*','hideme')[0];switch(action){case's':obj.style.visibility='visible';break;case'h':obj.style.visibility='hidden';break;case'k':if(obj.style.visibility!='visible'){obj.style.visibility='visible';}else{obj.style.visibility='hidden';}
+break;}}
+function keys(key){if(!key){key=event;key.which=key.keyCode;}
+if(key.which==84){toggle();return;}
+if(s5mode){switch(key.which){case 10:case 13:if(window.event&&isParentOrSelf(window.event.srcElement,'controls'))return;if(key.target&&isParentOrSelf(key.target,'controls'))return;if(number!=undef){goTo(number);break;}
+case 32:case 34:case 39:case 40:if(number!=undef){go(number);}else if(!incrementals[snum]||incpos>=incrementals[snum].length){go(1);}else{subgo(1);}
+break;case 33:case 37:case 38:if(number!=undef){go(-1*number);}else if(!incrementals[snum]||incpos<=0){go(-1);}else{subgo(-1);}
+break;case 36:goTo(0);break;case 35:goTo(smax-1);break;case 67:showHide('k');break;}
+if(key.which<48||key.which>57){number=undef;}else{if(window.event&&isParentOrSelf(window.event.srcElement,'controls'))return;if(key.target&&isParentOrSelf(key.target,'controls'))return;number=(((number!=undef)?number:0)*10)+(key.which-48);}}
+return false;}
+function clicker(e){number=undef;var target;if(window.event){target=window.event.srcElement;e=window.event;}else target=e.target;if(target.getAttribute('href')!=null||hasValue(target.rel,'external')||isParentOrSelf(target,'controls')||isParentOrSelf(target,'embed')||isParentOrSelf(target,'object'))return true;if(!e.which||e.which==1){if(!incrementals[snum]||incpos>=incrementals[snum].length){go(1);}else{subgo(1);}}}
+function findSlide(hash){var target=null;var slides=GetElementsWithClassName('*','slide');for(var i=0;i<slides.length;i++){var targetSlide=slides[i];if((targetSlide.name&&targetSlide.name==hash)||(targetSlide.id&&targetSlide.id==hash)){target=targetSlide;break;}}
+while(target!=null&&target.nodeName!='BODY'){if(hasClass(target,'slide')){return parseInt(target.id.slice(5));}
+target=target.parentNode;}
+return null;}
+function slideJump(){if(window.location.hash==null)return;var sregex=/^#slide(\d+)$/;var matches=sregex.exec(window.location.hash);var dest=null;if(matches!=null){dest=parseInt(matches[1]);}else{dest=findSlide(window.location.hash.slice(1));}
+if(dest!=null)
+go(dest-snum);}
+function fixLinks(){var thisUri=window.location.href;thisUri=thisUri.slice(0,thisUri.length-window.location.hash.length);var aelements=document.getElementsByTagName('A');for(var i=0;i<aelements.length;i++){var a=aelements[i].href;var slideID=a.match('\#slide[0-9]{1,2}');if((slideID)&&(slideID[0].slice(0,1)=='#')){var dest=findSlide(slideID[0].slice(1));if(dest!=null){if(aelements[i].addEventListener){aelements[i].addEventListener("click",new Function("e","if (document.getElementById('slideProj').disabled) return;"+"go("+dest+" - snum); "+"if (e.preventDefault) e.preventDefault();"),true);}else if(aelements[i].attachEvent){aelements[i].attachEvent("onclick",new Function("","if (document.getElementById('slideProj').disabled) return;"+"go("+dest+" - snum); "+"event.returnValue = false;"));}}}}}
+function externalLinks(){if(!document.getElementsByTagName)return;var anchors=document.getElementsByTagName('a');for(var i=0;i<anchors.length;i++){var anchor=anchors[i];if(anchor.getAttribute('href')&&hasValue(anchor.rel,'external')){anchor.target='_blank';addClass(anchor,'external');}}}
+function createControls(){var controlsDiv=document.getElementById("controls");if(!controlsDiv)return;var hider=' onmouseover="showHide(\'s\');" onmouseout="showHide(\'h\');"';var hideDiv,hideList='';if(controlVis=='hidden'){hideDiv=hider;}else{hideList=hider;}
+controlsDiv.innerHTML='<form action="#" id="controlForm"'+hideDiv+'>'+'<div id="navLinks">'+'<a accesskey="t" id="toggle" href="javascript:toggle();">&#216;<\/a>'+'<a accesskey="z" id="prev" href="javascript:go(-1);">&laquo;<\/a>'+'<a accesskey="x" id="next" href="javascript:go(1);">&raquo;<\/a>'+'<div id="navList"'+hideList+'><select id="jumplist" onchange="go(\'j\');"><\/select><\/div>'+'<\/div><\/form>';if(controlVis=='hidden'){var hidden=document.getElementById('navLinks');}else{var hidden=document.getElementById('jumplist');}
+addClass(hidden,'hideme');}
+function fontScale(){if(!s5mode)return false;var vScale=22;var hScale=32;if(window.innerHeight){var vSize=window.innerHeight;var hSize=window.innerWidth;}else if(document.documentElement.clientHeight){var vSize=document.documentElement.clientHeight;var hSize=document.documentElement.clientWidth;}else if(document.body.clientHeight){var vSize=document.body.clientHeight;var hSize=document.body.clientWidth;}else{var vSize=700;var hSize=1024;}
+var newSize=Math.min(Math.round(vSize/vScale),Math.round(hSize/hScale));fontSize(newSize+'px');if(isGe){var obj=document.getElementsByTagName('body')[0];obj.style.display='none';obj.style.display='block';}}
+function fontSize(value){if(!(s5ss=document.getElementById('s5ss'))){if(!isIE){document.getElementsByTagName('head')[0].appendChild(s5ss=document.createElement('style'));s5ss.setAttribute('media','screen, projection');s5ss.setAttribute('id','s5ss');}else{document.createStyleSheet();document.s5ss=document.styleSheets[document.styleSheets.length-1];}}
+if(!isIE){while(s5ss.lastChild)s5ss.removeChild(s5ss.lastChild);s5ss.appendChild(document.createTextNode('body {font-size: '+value+' !important;}'));}else{document.s5ss.addRule('body','font-size: '+value+' !important;');}}
+function notOperaFix(){slideCSS=document.getElementById('slideProj').href;var slides=document.getElementById('slideProj');var outline=document.getElementById('outlineStyle');slides.setAttribute('media','screen');outline.disabled=true;if(isGe){slides.setAttribute('href','null');slides.setAttribute('href',slideCSS);}
+if(isIE&&document.styleSheets&&document.styleSheets[0]){document.styleSheets[0].addRule('img','behavior: url(ui/default/iepngfix.htc)');document.styleSheets[0].addRule('div','behavior: url(ui/default/iepngfix.htc)');document.styleSheets[0].addRule('.slide','behavior: url(ui/default/iepngfix.htc)');}}
+function getIncrementals(obj){var incrementals=new Array();if(!obj)
+return incrementals;var children=obj.childNodes;for(var i=0;i<children.length;i++){var child=children[i];if(hasClass(child,'incremental')){if(child.nodeName=='OL'||child.nodeName=='UL'){removeClass(child,'incremental');for(var j=0;j<child.childNodes.length;j++){if(child.childNodes[j].nodeType==1){addClass(child.childNodes[j],'incremental');}}}else{incrementals[incrementals.length]=child;removeClass(child,'incremental');}}
+if(hasClass(child,'show-first')){if(child.nodeName=='OL'||child.nodeName=='UL'){removeClass(child,'show-first');if(child.childNodes[isGe].nodeType==1){removeClass(child.childNodes[isGe],'incremental');}}else{incrementals[incrementals.length]=child;}}
+incrementals=incrementals.concat(getIncrementals(child));}
+return incrementals;}
+function createIncrementals(){var incrementals=new Array();for(var i=0;i<smax;i++){incrementals[i]=getIncrementals(document.getElementById('slide'+i));}
+return incrementals;}
+function defaultCheck(){var allMetas=document.getElementsByTagName('meta');for(var i=0;i<allMetas.length;i++){if(allMetas[i].name=='defaultView'){defaultView=allMetas[i].content;}
+if(allMetas[i].name=='controlVis'){controlVis=allMetas[i].content;}}}
+function trap(e){if(!e){e=event;e.which=e.keyCode;}
+try{modifierKey=e.ctrlKey||e.altKey||e.metaKey;}
+catch(e){modifierKey=false;}
+return modifierKey||e.which==0;}
+function startup(){defaultCheck();if(!isOp)
+createControls();slideLabel();fixLinks();externalLinks();fontScale();if(!isOp){notOperaFix();incrementals=createIncrementals();slideJump();if(defaultView=='outline'){toggle();}
+document.onkeyup=keys;document.onkeypress=trap;document.onclick=clicker;}}
+window.onload=startup;window.onresize=function(){setTimeout('fontScale()',50);}
+</script>
+</head
+ ><body
+ ><div class="layout">
+<div id="controls"></div>
+<div id="currentSlide"></div>
+<div id="header"></div>
+<div id="footer">
+<h1
+ >July 15, 2006</h1
+ ><h2
+ >My S5 Document</h2
+ ></div>
+</div>
+<div class="presentation">
+
+<div class="slide">
+<h1
+ >My S5 Document</h1
+ ><h3
+ >Sam Smith, Jen Jones</h3
+ ><h4
+ >July 15, 2006</h4
+ ></div>
+<div class="slide">
+<h1
+ >First slide</h1
+ ><ul
+ ><li
+ >first bullet</li
+ ><li
+ >second bullet</li
+ ></ul
+ ></div>
+<div class="slide">
+<h1
+ >Math</h1
+ ><ul
+ ><li
+ ><span class="math"
+ >\frac{<em
+ >d</em
+ >}{<em
+ >dx</em
+ >}<em
+ >f</em
+ >(<em
+ >x</em
+ >)=\lim<sub
+ ><em
+ >h</em
+ >&#8201;&#8594;&#8201;0</sub
+ >\frac{<em
+ >f</em
+ >(<em
+ >x</em
+ >+<em
+ >h</em
+ >)-<em
+ >f</em
+ >(<em
+ >x</em
+ >)}{<em
+ >h</em
+ >}</span
+ ></li
+ ></ul
+ ></div>
+</div>
+</body
+ ></html
+>
+
diff --git a/tests/s5.fancy.html b/tests/s5.fancy.html
new file mode 100644
index 000000000..9b82feb35
--- /dev/null
+++ b/tests/s5.fancy.html
@@ -0,0 +1,527 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+><head
+ ><title
+ >My S5 Document</title
+ ><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
+ /><meta name="generator" content="pandoc"
+ /><meta name="author" content="Sam Smith"
+ /><meta name="author" content="Jen Jones"
+ /><meta name="date" content="July 15, 2006"
+ /><script type="text/javascript">
+/*
+LaTeXMathML.js from http://math.etsu.edu/LaTeXMathML/
+Adapted by Jeff Knisely and Douglas Woodall from ASCIIMathML.js v. 1.4.7,
+(c) 2005 Peter Jipsen http://www.chapman.edu/~jipsen.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License (at http://www.gnu.org/copyleft/gpl.html)
+for more details.
+*/
+
+var checkForMathML=true;var notifyIfNoMathML=true;var alertIfNoMathML=false;var mathcolor="";var mathfontfamily="";var showasciiformulaonhover=true;var isIE=document.createElementNS==null;if(document.getElementById==null)
+alert("This webpage requires a recent browser such as \nMozilla/Netscape 7+ or Internet Explorer 6+MathPlayer")
+function AMcreateElementXHTML(t){if(isIE)return document.createElement(t);else return document.createElementNS("http://www.w3.org/1999/xhtml",t);}
+function AMnoMathMLNote(){var nd=AMcreateElementXHTML("h3");nd.setAttribute("align","center")
+nd.appendChild(AMcreateElementXHTML("p"));nd.appendChild(document.createTextNode("To view the "));var an=AMcreateElementXHTML("a");an.appendChild(document.createTextNode("LaTeXMathML"));an.setAttribute("href","http://www.maths.nott.ac.uk/personal/drw/lm.html");nd.appendChild(an);nd.appendChild(document.createTextNode(" notation use Internet Explorer 6+"));an=AMcreateElementXHTML("a");an.appendChild(document.createTextNode("MathPlayer"));an.setAttribute("href","http://www.dessci.com/en/products/mathplayer/download.htm");nd.appendChild(an);nd.appendChild(document.createTextNode(" or Netscape/Mozilla/Firefox"));nd.appendChild(AMcreateElementXHTML("p"));return nd;}
+function AMisMathMLavailable(){if(navigator.appName.slice(0,8)=="Netscape")
+if(navigator.appVersion.slice(0,1)>="5")return null;else return AMnoMathMLNote();else if(navigator.appName.slice(0,9)=="Microsoft")
+try{var ActiveX=new ActiveXObject("MathPlayer.Factory.1");return null;}catch(e){return AMnoMathMLNote();}
+else return AMnoMathMLNote();}
+var AMcal=[0xEF35,0x212C,0xEF36,0xEF37,0x2130,0x2131,0xEF38,0x210B,0x2110,0xEF39,0xEF3A,0x2112,0x2133,0xEF3B,0xEF3C,0xEF3D,0xEF3E,0x211B,0xEF3F,0xEF40,0xEF41,0xEF42,0xEF43,0xEF44,0xEF45,0xEF46];var AMfrk=[0xEF5D,0xEF5E,0x212D,0xEF5F,0xEF60,0xEF61,0xEF62,0x210C,0x2111,0xEF63,0xEF64,0xEF65,0xEF66,0xEF67,0xEF68,0xEF69,0xEF6A,0x211C,0xEF6B,0xEF6C,0xEF6D,0xEF6E,0xEF6F,0xEF70,0xEF71,0x2128];var AMbbb=[0xEF8C,0xEF8D,0x2102,0xEF8E,0xEF8F,0xEF90,0xEF91,0x210D,0xEF92,0xEF93,0xEF94,0xEF95,0xEF96,0x2115,0xEF97,0x2119,0x211A,0x211D,0xEF98,0xEF99,0xEF9A,0xEF9B,0xEF9C,0xEF9D,0xEF9E,0x2124];var CONST=0,UNARY=1,BINARY=2,INFIX=3,LEFTBRACKET=4,RIGHTBRACKET=5,SPACE=6,UNDEROVER=7,DEFINITION=8,TEXT=9,BIG=10,LONG=11,STRETCHY=12,MATRIX=13;var AMsqrt={input:"\\sqrt",tag:"msqrt",output:"sqrt",ttype:UNARY},AMroot={input:"\\root",tag:"mroot",output:"root",ttype:BINARY},AMfrac={input:"\\frac",tag:"mfrac",output:"/",ttype:BINARY},AMover={input:"\\stackrel",tag:"mover",output:"stackrel",ttype:BINARY},AMatop={input:"\\atop",tag:"mfrac",output:"",ttype:INFIX},AMchoose={input:"\\choose",tag:"mfrac",output:"",ttype:INFIX},AMsub={input:"_",tag:"msub",output:"_",ttype:INFIX},AMsup={input:"^",tag:"msup",output:"^",ttype:INFIX},AMtext={input:"\\mathrm",tag:"mtext",output:"text",ttype:TEXT},AMmbox={input:"\\mbox",tag:"mtext",output:"mbox",ttype:TEXT};var AMsymbols=[{input:"\\alpha",tag:"mi",output:"\u03B1",ttype:CONST},{input:"\\beta",tag:"mi",output:"\u03B2",ttype:CONST},{input:"\\gamma",tag:"mi",output:"\u03B3",ttype:CONST},{input:"\\delta",tag:"mi",output:"\u03B4",ttype:CONST},{input:"\\epsilon",tag:"mi",output:"\u03B5",ttype:CONST},{input:"\\varepsilon",tag:"mi",output:"\u025B",ttype:CONST},{input:"\\zeta",tag:"mi",output:"\u03B6",ttype:CONST},{input:"\\eta",tag:"mi",output:"\u03B7",ttype:CONST},{input:"\\theta",tag:"mi",output:"\u03B8",ttype:CONST},{input:"\\vartheta",tag:"mi",output:"\u03D1",ttype:CONST},{input:"\\iota",tag:"mi",output:"\u03B9",ttype:CONST},{input:"\\kappa",tag:"mi",output:"\u03BA",ttype:CONST},{input:"\\lambda",tag:"mi",output:"\u03BB",ttype:CONST},{input:"\\mu",tag:"mi",output:"\u03BC",ttype:CONST},{input:"\\nu",tag:"mi",output:"\u03BD",ttype:CONST},{input:"\\xi",tag:"mi",output:"\u03BE",ttype:CONST},{input:"\\pi",tag:"mi",output:"\u03C0",ttype:CONST},{input:"\\varpi",tag:"mi",output:"\u03D6",ttype:CONST},{input:"\\rho",tag:"mi",output:"\u03C1",ttype:CONST},{input:"\\varrho",tag:"mi",output:"\u03F1",ttype:CONST},{input:"\\varsigma",tag:"mi",output:"\u03C2",ttype:CONST},{input:"\\sigma",tag:"mi",output:"\u03C3",ttype:CONST},{input:"\\tau",tag:"mi",output:"\u03C4",ttype:CONST},{input:"\\upsilon",tag:"mi",output:"\u03C5",ttype:CONST},{input:"\\phi",tag:"mi",output:"\u03C6",ttype:CONST},{input:"\\varphi",tag:"mi",output:"\u03D5",ttype:CONST},{input:"\\chi",tag:"mi",output:"\u03C7",ttype:CONST},{input:"\\psi",tag:"mi",output:"\u03C8",ttype:CONST},{input:"\\omega",tag:"mi",output:"\u03C9",ttype:CONST},{input:"\\Gamma",tag:"mo",output:"\u0393",ttype:CONST},{input:"\\Delta",tag:"mo",output:"\u0394",ttype:CONST},{input:"\\Theta",tag:"mo",output:"\u0398",ttype:CONST},{input:"\\Lambda",tag:"mo",output:"\u039B",ttype:CONST},{input:"\\Xi",tag:"mo",output:"\u039E",ttype:CONST},{input:"\\Pi",tag:"mo",output:"\u03A0",ttype:CONST},{input:"\\Sigma",tag:"mo",output:"\u03A3",ttype:CONST},{input:"\\Upsilon",tag:"mo",output:"\u03A5",ttype:CONST},{input:"\\Phi",tag:"mo",output:"\u03A6",ttype:CONST},{input:"\\Psi",tag:"mo",output:"\u03A8",ttype:CONST},{input:"\\Omega",tag:"mo",output:"\u03A9",ttype:CONST},{input:"\\frac12",tag:"mo",output:"\u00BD",ttype:CONST},{input:"\\frac14",tag:"mo",output:"\u00BC",ttype:CONST},{input:"\\frac34",tag:"mo",output:"\u00BE",ttype:CONST},{input:"\\frac13",tag:"mo",output:"\u2153",ttype:CONST},{input:"\\frac23",tag:"mo",output:"\u2154",ttype:CONST},{input:"\\frac15",tag:"mo",output:"\u2155",ttype:CONST},{input:"\\frac25",tag:"mo",output:"\u2156",ttype:CONST},{input:"\\frac35",tag:"mo",output:"\u2157",ttype:CONST},{input:"\\frac45",tag:"mo",output:"\u2158",ttype:CONST},{input:"\\frac16",tag:"mo",output:"\u2159",ttype:CONST},{input:"\\frac56",tag:"mo",output:"\u215A",ttype:CONST},{input:"\\frac18",tag:"mo",output:"\u215B",ttype:CONST},{input:"\\frac38",tag:"mo",output:"\u215C",ttype:CONST},{input:"\\frac58",tag:"mo",output:"\u215D",ttype:CONST},{input:"\\frac78",tag:"mo",output:"\u215E",ttype:CONST},{input:"\\pm",tag:"mo",output:"\u00B1",ttype:CONST},{input:"\\mp",tag:"mo",output:"\u2213",ttype:CONST},{input:"\\triangleleft",tag:"mo",output:"\u22B2",ttype:CONST},{input:"\\triangleright",tag:"mo",output:"\u22B3",ttype:CONST},{input:"\\cdot",tag:"mo",output:"\u22C5",ttype:CONST},{input:"\\star",tag:"mo",output:"\u22C6",ttype:CONST},{input:"\\ast",tag:"mo",output:"\u002A",ttype:CONST},{input:"\\times",tag:"mo",output:"\u00D7",ttype:CONST},{input:"\\div",tag:"mo",output:"\u00F7",ttype:CONST},{input:"\\circ",tag:"mo",output:"\u2218",ttype:CONST},{input:"\\bullet",tag:"mo",output:"\u2022",ttype:CONST},{input:"\\oplus",tag:"mo",output:"\u2295",ttype:CONST},{input:"\\ominus",tag:"mo",output:"\u2296",ttype:CONST},{input:"\\otimes",tag:"mo",output:"\u2297",ttype:CONST},{input:"\\bigcirc",tag:"mo",output:"\u25CB",ttype:CONST},{input:"\\oslash",tag:"mo",output:"\u2298",ttype:CONST},{input:"\\odot",tag:"mo",output:"\u2299",ttype:CONST},{input:"\\land",tag:"mo",output:"\u2227",ttype:CONST},{input:"\\wedge",tag:"mo",output:"\u2227",ttype:CONST},{input:"\\lor",tag:"mo",output:"\u2228",ttype:CONST},{input:"\\vee",tag:"mo",output:"\u2228",ttype:CONST},{input:"\\cap",tag:"mo",output:"\u2229",ttype:CONST},{input:"\\cup",tag:"mo",output:"\u222A",ttype:CONST},{input:"\\sqcap",tag:"mo",output:"\u2293",ttype:CONST},{input:"\\sqcup",tag:"mo",output:"\u2294",ttype:CONST},{input:"\\uplus",tag:"mo",output:"\u228E",ttype:CONST},{input:"\\amalg",tag:"mo",output:"\u2210",ttype:CONST},{input:"\\bigtriangleup",tag:"mo",output:"\u25B3",ttype:CONST},{input:"\\bigtriangledown",tag:"mo",output:"\u25BD",ttype:CONST},{input:"\\dag",tag:"mo",output:"\u2020",ttype:CONST},{input:"\\dagger",tag:"mo",output:"\u2020",ttype:CONST},{input:"\\ddag",tag:"mo",output:"\u2021",ttype:CONST},{input:"\\ddagger",tag:"mo",output:"\u2021",ttype:CONST},{input:"\\lhd",tag:"mo",output:"\u22B2",ttype:CONST},{input:"\\rhd",tag:"mo",output:"\u22B3",ttype:CONST},{input:"\\unlhd",tag:"mo",output:"\u22B4",ttype:CONST},{input:"\\unrhd",tag:"mo",output:"\u22B5",ttype:CONST},{input:"\\sum",tag:"mo",output:"\u2211",ttype:UNDEROVER},{input:"\\prod",tag:"mo",output:"\u220F",ttype:UNDEROVER},{input:"\\bigcap",tag:"mo",output:"\u22C2",ttype:UNDEROVER},{input:"\\bigcup",tag:"mo",output:"\u22C3",ttype:UNDEROVER},{input:"\\bigwedge",tag:"mo",output:"\u22C0",ttype:UNDEROVER},{input:"\\bigvee",tag:"mo",output:"\u22C1",ttype:UNDEROVER},{input:"\\bigsqcap",tag:"mo",output:"\u2A05",ttype:UNDEROVER},{input:"\\bigsqcup",tag:"mo",output:"\u2A06",ttype:UNDEROVER},{input:"\\coprod",tag:"mo",output:"\u2210",ttype:UNDEROVER},{input:"\\bigoplus",tag:"mo",output:"\u2A01",ttype:UNDEROVER},{input:"\\bigotimes",tag:"mo",output:"\u2A02",ttype:UNDEROVER},{input:"\\bigodot",tag:"mo",output:"\u2A00",ttype:UNDEROVER},{input:"\\biguplus",tag:"mo",output:"\u2A04",ttype:UNDEROVER},{input:"\\int",tag:"mo",output:"\u222B",ttype:CONST},{input:"\\oint",tag:"mo",output:"\u222E",ttype:CONST},{input:":=",tag:"mo",output:":=",ttype:CONST},{input:"\\lt",tag:"mo",output:"<",ttype:CONST},{input:"\\gt",tag:"mo",output:">",ttype:CONST},{input:"\\ne",tag:"mo",output:"\u2260",ttype:CONST},{input:"\\neq",tag:"mo",output:"\u2260",ttype:CONST},{input:"\\le",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\leq",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\leqslant",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\ge",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\geq",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\geqslant",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\equiv",tag:"mo",output:"\u2261",ttype:CONST},{input:"\\ll",tag:"mo",output:"\u226A",ttype:CONST},{input:"\\gg",tag:"mo",output:"\u226B",ttype:CONST},{input:"\\doteq",tag:"mo",output:"\u2250",ttype:CONST},{input:"\\prec",tag:"mo",output:"\u227A",ttype:CONST},{input:"\\succ",tag:"mo",output:"\u227B",ttype:CONST},{input:"\\preceq",tag:"mo",output:"\u227C",ttype:CONST},{input:"\\succeq",tag:"mo",output:"\u227D",ttype:CONST},{input:"\\subset",tag:"mo",output:"\u2282",ttype:CONST},{input:"\\supset",tag:"mo",output:"\u2283",ttype:CONST},{input:"\\subseteq",tag:"mo",output:"\u2286",ttype:CONST},{input:"\\supseteq",tag:"mo",output:"\u2287",ttype:CONST},{input:"\\sqsubset",tag:"mo",output:"\u228F",ttype:CONST},{input:"\\sqsupset",tag:"mo",output:"\u2290",ttype:CONST},{input:"\\sqsubseteq",tag:"mo",output:"\u2291",ttype:CONST},{input:"\\sqsupseteq",tag:"mo",output:"\u2292",ttype:CONST},{input:"\\sim",tag:"mo",output:"\u223C",ttype:CONST},{input:"\\simeq",tag:"mo",output:"\u2243",ttype:CONST},{input:"\\approx",tag:"mo",output:"\u2248",ttype:CONST},{input:"\\cong",tag:"mo",output:"\u2245",ttype:CONST},{input:"\\Join",tag:"mo",output:"\u22C8",ttype:CONST},{input:"\\bowtie",tag:"mo",output:"\u22C8",ttype:CONST},{input:"\\in",tag:"mo",output:"\u2208",ttype:CONST},{input:"\\ni",tag:"mo",output:"\u220B",ttype:CONST},{input:"\\owns",tag:"mo",output:"\u220B",ttype:CONST},{input:"\\propto",tag:"mo",output:"\u221D",ttype:CONST},{input:"\\vdash",tag:"mo",output:"\u22A2",ttype:CONST},{input:"\\dashv",tag:"mo",output:"\u22A3",ttype:CONST},{input:"\\models",tag:"mo",output:"\u22A8",ttype:CONST},{input:"\\perp",tag:"mo",output:"\u22A5",ttype:CONST},{input:"\\smile",tag:"mo",output:"\u2323",ttype:CONST},{input:"\\frown",tag:"mo",output:"\u2322",ttype:CONST},{input:"\\asymp",tag:"mo",output:"\u224D",ttype:CONST},{input:"\\notin",tag:"mo",output:"\u2209",ttype:CONST},{input:"\\begin{eqnarray}",output:"X",ttype:MATRIX,invisible:true},{input:"\\begin{array}",output:"X",ttype:MATRIX,invisible:true},{input:"\\\\",output:"}&{",ttype:DEFINITION},{input:"\\end{eqnarray}",output:"}}",ttype:DEFINITION},{input:"\\end{array}",output:"}}",ttype:DEFINITION},{input:"\\big",tag:"mo",output:"X",atval:"1.2",ieval:"2.2",ttype:BIG},{input:"\\Big",tag:"mo",output:"X",atval:"1.6",ieval:"2.6",ttype:BIG},{input:"\\bigg",tag:"mo",output:"X",atval:"2.2",ieval:"3.2",ttype:BIG},{input:"\\Bigg",tag:"mo",output:"X",atval:"2.9",ieval:"3.9",ttype:BIG},{input:"\\left",tag:"mo",output:"X",ttype:LEFTBRACKET},{input:"\\right",tag:"mo",output:"X",ttype:RIGHTBRACKET},{input:"{",output:"{",ttype:LEFTBRACKET,invisible:true},{input:"}",output:"}",ttype:RIGHTBRACKET,invisible:true},{input:"(",tag:"mo",output:"(",atval:"1",ttype:STRETCHY},{input:"[",tag:"mo",output:"[",atval:"1",ttype:STRETCHY},{input:"\\lbrack",tag:"mo",output:"[",atval:"1",ttype:STRETCHY},{input:"\\{",tag:"mo",output:"{",atval:"1",ttype:STRETCHY},{input:"\\lbrace",tag:"mo",output:"{",atval:"1",ttype:STRETCHY},{input:"\\langle",tag:"mo",output:"\u2329",atval:"1",ttype:STRETCHY},{input:"\\lfloor",tag:"mo",output:"\u230A",atval:"1",ttype:STRETCHY},{input:"\\lceil",tag:"mo",output:"\u2308",atval:"1",ttype:STRETCHY},{input:")",tag:"mo",output:")",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"]",tag:"mo",output:"]",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rbrack",tag:"mo",output:"]",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\}",tag:"mo",output:"}",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rbrace",tag:"mo",output:"}",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rangle",tag:"mo",output:"\u232A",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rfloor",tag:"mo",output:"\u230B",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rceil",tag:"mo",output:"\u2309",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"|",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\|",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"\\vert",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\Vert",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"\\mid",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\parallel",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"/",tag:"mo",output:"/",atval:"1.01",ttype:STRETCHY},{input:"\\backslash",tag:"mo",output:"\u2216",atval:"1",ttype:STRETCHY},{input:"\\setminus",tag:"mo",output:"\\",ttype:CONST},{input:"\\!",tag:"mspace",atname:"width",atval:"-0.167em",ttype:SPACE},{input:"\\,",tag:"mspace",atname:"width",atval:"0.167em",ttype:SPACE},{input:"\\>",tag:"mspace",atname:"width",atval:"0.222em",ttype:SPACE},{input:"\\:",tag:"mspace",atname:"width",atval:"0.222em",ttype:SPACE},{input:"\\;",tag:"mspace",atname:"width",atval:"0.278em",ttype:SPACE},{input:"~",tag:"mspace",atname:"width",atval:"0.333em",ttype:SPACE},{input:"\\quad",tag:"mspace",atname:"width",atval:"1em",ttype:SPACE},{input:"\\qquad",tag:"mspace",atname:"width",atval:"2em",ttype:SPACE},{input:"\\prime",tag:"mo",output:"\u2032",ttype:CONST},{input:"'",tag:"mo",output:"\u02B9",ttype:CONST},{input:"''",tag:"mo",output:"\u02BA",ttype:CONST},{input:"'''",tag:"mo",output:"\u2034",ttype:CONST},{input:"''''",tag:"mo",output:"\u2057",ttype:CONST},{input:"\\ldots",tag:"mo",output:"\u2026",ttype:CONST},{input:"\\cdots",tag:"mo",output:"\u22EF",ttype:CONST},{input:"\\vdots",tag:"mo",output:"\u22EE",ttype:CONST},{input:"\\ddots",tag:"mo",output:"\u22F1",ttype:CONST},{input:"\\forall",tag:"mo",output:"\u2200",ttype:CONST},{input:"\\exists",tag:"mo",output:"\u2203",ttype:CONST},{input:"\\Re",tag:"mo",output:"\u211C",ttype:CONST},{input:"\\Im",tag:"mo",output:"\u2111",ttype:CONST},{input:"\\aleph",tag:"mo",output:"\u2135",ttype:CONST},{input:"\\hbar",tag:"mo",output:"\u210F",ttype:CONST},{input:"\\ell",tag:"mo",output:"\u2113",ttype:CONST},{input:"\\wp",tag:"mo",output:"\u2118",ttype:CONST},{input:"\\emptyset",tag:"mo",output:"\u2205",ttype:CONST},{input:"\\infty",tag:"mo",output:"\u221E",ttype:CONST},{input:"\\surd",tag:"mo",output:"\\sqrt{}",ttype:DEFINITION},{input:"\\partial",tag:"mo",output:"\u2202",ttype:CONST},{input:"\\nabla",tag:"mo",output:"\u2207",ttype:CONST},{input:"\\triangle",tag:"mo",output:"\u25B3",ttype:CONST},{input:"\\therefore",tag:"mo",output:"\u2234",ttype:CONST},{input:"\\angle",tag:"mo",output:"\u2220",ttype:CONST},{input:"\\diamond",tag:"mo",output:"\u22C4",ttype:CONST},{input:"\\Diamond",tag:"mo",output:"\u25C7",ttype:CONST},{input:"\\neg",tag:"mo",output:"\u00AC",ttype:CONST},{input:"\\lnot",tag:"mo",output:"\u00AC",ttype:CONST},{input:"\\bot",tag:"mo",output:"\u22A5",ttype:CONST},{input:"\\top",tag:"mo",output:"\u22A4",ttype:CONST},{input:"\\square",tag:"mo",output:"\u25AB",ttype:CONST},{input:"\\Box",tag:"mo",output:"\u25A1",ttype:CONST},{input:"\\wr",tag:"mo",output:"\u2240",ttype:CONST},{input:"\\arccos",tag:"mi",output:"arccos",ttype:UNARY,func:true},{input:"\\arcsin",tag:"mi",output:"arcsin",ttype:UNARY,func:true},{input:"\\arctan",tag:"mi",output:"arctan",ttype:UNARY,func:true},{input:"\\arg",tag:"mi",output:"arg",ttype:UNARY,func:true},{input:"\\cos",tag:"mi",output:"cos",ttype:UNARY,func:true},{input:"\\cosh",tag:"mi",output:"cosh",ttype:UNARY,func:true},{input:"\\cot",tag:"mi",output:"cot",ttype:UNARY,func:true},{input:"\\coth",tag:"mi",output:"coth",ttype:UNARY,func:true},{input:"\\csc",tag:"mi",output:"csc",ttype:UNARY,func:true},{input:"\\deg",tag:"mi",output:"deg",ttype:UNARY,func:true},{input:"\\det",tag:"mi",output:"det",ttype:UNARY,func:true},{input:"\\dim",tag:"mi",output:"dim",ttype:UNARY,func:true},{input:"\\exp",tag:"mi",output:"exp",ttype:UNARY,func:true},{input:"\\gcd",tag:"mi",output:"gcd",ttype:UNARY,func:true},{input:"\\hom",tag:"mi",output:"hom",ttype:UNARY,func:true},{input:"\\inf",tag:"mo",output:"inf",ttype:UNDEROVER},{input:"\\ker",tag:"mi",output:"ker",ttype:UNARY,func:true},{input:"\\lg",tag:"mi",output:"lg",ttype:UNARY,func:true},{input:"\\lim",tag:"mo",output:"lim",ttype:UNDEROVER},{input:"\\liminf",tag:"mo",output:"liminf",ttype:UNDEROVER},{input:"\\limsup",tag:"mo",output:"limsup",ttype:UNDEROVER},{input:"\\ln",tag:"mi",output:"ln",ttype:UNARY,func:true},{input:"\\log",tag:"mi",output:"log",ttype:UNARY,func:true},{input:"\\max",tag:"mo",output:"max",ttype:UNDEROVER},{input:"\\min",tag:"mo",output:"min",ttype:UNDEROVER},{input:"\\Pr",tag:"mi",output:"Pr",ttype:UNARY,func:true},{input:"\\sec",tag:"mi",output:"sec",ttype:UNARY,func:true},{input:"\\sin",tag:"mi",output:"sin",ttype:UNARY,func:true},{input:"\\sinh",tag:"mi",output:"sinh",ttype:UNARY,func:true},{input:"\\sup",tag:"mo",output:"sup",ttype:UNDEROVER},{input:"\\tan",tag:"mi",output:"tan",ttype:UNARY,func:true},{input:"\\tanh",tag:"mi",output:"tanh",ttype:UNARY,func:true},{input:"\\gets",tag:"mo",output:"\u2190",ttype:CONST},{input:"\\leftarrow",tag:"mo",output:"\u2190",ttype:CONST},{input:"\\to",tag:"mo",output:"\u2192",ttype:CONST},{input:"\\rightarrow",tag:"mo",output:"\u2192",ttype:CONST},{input:"\\leftrightarrow",tag:"mo",output:"\u2194",ttype:CONST},{input:"\\uparrow",tag:"mo",output:"\u2191",ttype:CONST},{input:"\\downarrow",tag:"mo",output:"\u2193",ttype:CONST},{input:"\\updownarrow",tag:"mo",output:"\u2195",ttype:CONST},{input:"\\Leftarrow",tag:"mo",output:"\u21D0",ttype:CONST},{input:"\\Rightarrow",tag:"mo",output:"\u21D2",ttype:CONST},{input:"\\Leftrightarrow",tag:"mo",output:"\u21D4",ttype:CONST},{input:"\\iff",tag:"mo",output:"~\\Longleftrightarrow~",ttype:DEFINITION},{input:"\\Uparrow",tag:"mo",output:"\u21D1",ttype:CONST},{input:"\\Downarrow",tag:"mo",output:"\u21D3",ttype:CONST},{input:"\\Updownarrow",tag:"mo",output:"\u21D5",ttype:CONST},{input:"\\mapsto",tag:"mo",output:"\u21A6",ttype:CONST},{input:"\\longleftarrow",tag:"mo",output:"\u2190",ttype:LONG},{input:"\\longrightarrow",tag:"mo",output:"\u2192",ttype:LONG},{input:"\\longleftrightarrow",tag:"mo",output:"\u2194",ttype:LONG},{input:"\\Longleftarrow",tag:"mo",output:"\u21D0",ttype:LONG},{input:"\\Longrightarrow",tag:"mo",output:"\u21D2",ttype:LONG},{input:"\\Longleftrightarrow",tag:"mo",output:"\u21D4",ttype:LONG},{input:"\\longmapsto",tag:"mo",output:"\u21A6",ttype:CONST},AMsqrt,AMroot,AMfrac,AMover,AMsub,AMsup,AMtext,AMmbox,AMatop,AMchoose,{input:"\\acute",tag:"mover",output:"\u00B4",ttype:UNARY,acc:true},{input:"\\grave",tag:"mover",output:"\u0060",ttype:UNARY,acc:true},{input:"\\breve",tag:"mover",output:"\u02D8",ttype:UNARY,acc:true},{input:"\\check",tag:"mover",output:"\u02C7",ttype:UNARY,acc:true},{input:"\\dot",tag:"mover",output:".",ttype:UNARY,acc:true},{input:"\\ddot",tag:"mover",output:"..",ttype:UNARY,acc:true},{input:"\\mathring",tag:"mover",output:"\u00B0",ttype:UNARY,acc:true},{input:"\\vec",tag:"mover",output:"\u20D7",ttype:UNARY,acc:true},{input:"\\overrightarrow",tag:"mover",output:"\u20D7",ttype:UNARY,acc:true},{input:"\\overleftarrow",tag:"mover",output:"\u20D6",ttype:UNARY,acc:true},{input:"\\hat",tag:"mover",output:"\u005E",ttype:UNARY,acc:true},{input:"\\widehat",tag:"mover",output:"\u0302",ttype:UNARY,acc:true},{input:"\\tilde",tag:"mover",output:"~",ttype:UNARY,acc:true},{input:"\\widetilde",tag:"mover",output:"\u02DC",ttype:UNARY,acc:true},{input:"\\bar",tag:"mover",output:"\u203E",ttype:UNARY,acc:true},{input:"\\overbrace",tag:"mover",output:"\uFE37",ttype:UNARY,acc:true},{input:"\\overbracket",tag:"mover",output:"\u23B4",ttype:UNARY,acc:true},{input:"\\overline",tag:"mover",output:"\u00AF",ttype:UNARY,acc:true},{input:"\\underbrace",tag:"munder",output:"\uFE38",ttype:UNARY,acc:true},{input:"\\underbracket",tag:"munder",output:"\u23B5",ttype:UNARY,acc:true},{input:"\\underline",tag:"munder",output:"\u00AF",ttype:UNARY,acc:true},{input:"\\displaystyle",tag:"mstyle",atname:"displaystyle",atval:"true",ttype:UNARY},{input:"\\textstyle",tag:"mstyle",atname:"displaystyle",atval:"false",ttype:UNARY},{input:"\\scriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"1",ttype:UNARY},{input:"\\scriptscriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"2",ttype:UNARY},{input:"\\textrm",tag:"mstyle",output:"\\mathrm",ttype:DEFINITION},{input:"\\mathbf",tag:"mstyle",atname:"mathvariant",atval:"bold",ttype:UNARY},{input:"\\textbf",tag:"mstyle",atname:"mathvariant",atval:"bold",ttype:UNARY},{input:"\\mathit",tag:"mstyle",atname:"mathvariant",atval:"italic",ttype:UNARY},{input:"\\textit",tag:"mstyle",atname:"mathvariant",atval:"italic",ttype:UNARY},{input:"\\mathtt",tag:"mstyle",atname:"mathvariant",atval:"monospace",ttype:UNARY},{input:"\\texttt",tag:"mstyle",atname:"mathvariant",atval:"monospace",ttype:UNARY},{input:"\\mathsf",tag:"mstyle",atname:"mathvariant",atval:"sans-serif",ttype:UNARY},{input:"\\mathbb",tag:"mstyle",atname:"mathvariant",atval:"double-struck",ttype:UNARY,codes:AMbbb},{input:"\\mathcal",tag:"mstyle",atname:"mathvariant",atval:"script",ttype:UNARY,codes:AMcal},{input:"\\mathfrak",tag:"mstyle",atname:"mathvariant",atval:"fraktur",ttype:UNARY,codes:AMfrk},{input:"\\textcolor",tag:"mstyle",atname:"mathvariant",atval:"mathcolor",ttype:BINARY},{input:"\\colorbox",tag:"mstyle",atname:"mathvariant",atval:"background",ttype:BINARY}];function compareNames(s1,s2){if(s1.input>s2.input)return 1
+else return-1;}
+var AMnames=[];function AMinitSymbols(){AMsymbols.sort(compareNames);for(i=0;i<AMsymbols.length;i++)AMnames[i]=AMsymbols[i].input;}
+var AMmathml="http://www.w3.org/1998/Math/MathML";function AMcreateElementMathML(t){if(isIE)return document.createElement("m:"+t);else return document.createElementNS(AMmathml,t);}
+function AMcreateMmlNode(t,frag){if(isIE)var node=document.createElement("m:"+t);else var node=document.createElementNS(AMmathml,t);node.appendChild(frag);return node;}
+function newcommand(oldstr,newstr){AMsymbols=AMsymbols.concat([{input:oldstr,tag:"mo",output:newstr,ttype:DEFINITION}]);}
+function AMremoveCharsAndBlanks(str,n){var st;st=str.slice(n);for(var i=0;i<st.length&&st.charCodeAt(i)<=32;i=i+1);return st.slice(i);}
+function AMposition(arr,str,n){if(n==0){var h,m;n=-1;h=arr.length;while(n+1<h){m=(n+h)>>1;if(arr[m]<str)n=m;else h=m;}
+return h;}else
+for(var i=n;i<arr.length&&arr[i]<str;i++);return i;}
+function AMgetSymbol(str){var k=0;var j=0;var mk;var st;var tagst;var match="";var more=true;for(var i=1;i<=str.length&&more;i++){st=str.slice(0,i);j=k;k=AMposition(AMnames,st,j);if(k<AMnames.length&&str.slice(0,AMnames[k].length)==AMnames[k]){match=AMnames[k];mk=k;i=match.length;}
+more=k<AMnames.length&&str.slice(0,AMnames[k].length)>=AMnames[k];}
+AMpreviousSymbol=AMcurrentSymbol;if(match!=""){AMcurrentSymbol=AMsymbols[mk].ttype;return AMsymbols[mk];}
+AMcurrentSymbol=CONST;k=1;st=str.slice(0,1);if("0"<=st&&st<="9")tagst="mn";else tagst=(("A">st||st>"Z")&&("a">st||st>"z")?"mo":"mi");return{input:st,tag:tagst,output:st,ttype:CONST};}
+var AMpreviousSymbol,AMcurrentSymbol;function AMparseSexpr(str){var symbol,node,result,result2,i,st,newFrag=document.createDocumentFragment();str=AMremoveCharsAndBlanks(str,0);symbol=AMgetSymbol(str);if(symbol==null||symbol.ttype==RIGHTBRACKET)
+return[null,str,null];if(symbol.ttype==DEFINITION){str=symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length);symbol=AMgetSymbol(str);if(symbol==null||symbol.ttype==RIGHTBRACKET)
+return[null,str,null];}
+str=AMremoveCharsAndBlanks(str,symbol.input.length);switch(symbol.ttype){case SPACE:node=AMcreateElementMathML(symbol.tag);node.setAttribute(symbol.atname,symbol.atval);return[node,str,symbol.tag];case UNDEROVER:if(isIE){if(symbol.input.substr(0,4)=="\\big"){str="\\"+symbol.input.substr(4)+str;symbol=AMgetSymbol(str);symbol.ttype=UNDEROVER;str=AMremoveCharsAndBlanks(str,symbol.input.length);}}
+return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];case CONST:var output=symbol.output;if(isIE){if(symbol.input=="'")
+output="\u2032";else if(symbol.input=="''")
+output="\u2033";else if(symbol.input=="'''")
+output="\u2033\u2032";else if(symbol.input=="''''")
+output="\u2033\u2033";else if(symbol.input=="\\square")
+output="\u25A1";else if(symbol.input.substr(0,5)=="\\frac"){var denom=symbol.input.substr(6,1);if(denom=="5"||denom=="6"){str=symbol.input.replace(/\\frac/,"\\frac ")+str;return[node,str,symbol.tag];}}}
+node=AMcreateMmlNode(symbol.tag,document.createTextNode(output));return[node,str,symbol.tag];case LONG:node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));node.setAttribute("minsize","1.5");node.setAttribute("maxsize","1.5");node=AMcreateMmlNode("mover",node);node.appendChild(AMcreateElementMathML("mspace"));return[node,str,symbol.tag];case STRETCHY:if(isIE&&symbol.input=="\\backslash")
+symbol.output="\\";node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));if(symbol.input=="|"||symbol.input=="\\vert"||symbol.input=="\\|"||symbol.input=="\\Vert"){node.setAttribute("lspace","0em");node.setAttribute("rspace","0em");}
+node.setAttribute("maxsize",symbol.atval);if(symbol.rtag!=null)
+return[node,str,symbol.rtag];else
+return[node,str,symbol.tag];case BIG:var atval=symbol.atval;if(isIE)
+atval=symbol.ieval;symbol=AMgetSymbol(str);if(symbol==null)
+return[null,str,null];str=AMremoveCharsAndBlanks(str,symbol.input.length);node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("height",atval+"ex");node=AMcreateMmlNode("mrow",node);node.appendChild(space);}else{node.setAttribute("minsize",atval);node.setAttribute("maxsize",atval);}
+return[node,str,symbol.tag];case LEFTBRACKET:if(symbol.input=="\\left"){symbol=AMgetSymbol(str);if(symbol!=null){if(symbol.input==".")
+symbol.invisible=true;str=AMremoveCharsAndBlanks(str,symbol.input.length);}}
+result=AMparseExpr(str,true,false);if(symbol==null||(typeof symbol.invisible=="boolean"&&symbol.invisible))
+node=AMcreateMmlNode("mrow",result[0]);else{node=AMcreateMmlNode("mo",document.createTextNode(symbol.output));node=AMcreateMmlNode("mrow",node);node.appendChild(result[0]);}
+return[node,result[1],result[2]];case MATRIX:if(symbol.input=="\\begin{array}"){var mask="";symbol=AMgetSymbol(str);str=AMremoveCharsAndBlanks(str,0);if(symbol==null)
+mask="l";else{str=AMremoveCharsAndBlanks(str,symbol.input.length);if(symbol.input!="{")
+mask="l";else do{symbol=AMgetSymbol(str);if(symbol!=null){str=AMremoveCharsAndBlanks(str,symbol.input.length);if(symbol.input!="}")
+mask=mask+symbol.input;}}while(symbol!=null&&symbol.input!=""&&symbol.input!="}");}
+result=AMparseExpr("{"+str,true,true);node=AMcreateMmlNode("mtable",result[0]);mask=mask.replace(/l/g,"left ");mask=mask.replace(/r/g,"right ");mask=mask.replace(/c/g,"center ");node.setAttribute("columnalign",mask);node.setAttribute("displaystyle","false");if(isIE)
+return[node,result[1],null];var lspace=AMcreateElementMathML("mspace");lspace.setAttribute("width","0.167em");var rspace=AMcreateElementMathML("mspace");rspace.setAttribute("width","0.167em");var node1=AMcreateMmlNode("mrow",lspace);node1.appendChild(node);node1.appendChild(rspace);return[node1,result[1],null];}else{result=AMparseExpr("{"+str,true,true);node=AMcreateMmlNode("mtable",result[0]);if(isIE)
+node.setAttribute("columnspacing","0.25em");else
+node.setAttribute("columnspacing","0.167em");node.setAttribute("columnalign","right center left");node.setAttribute("displaystyle","true");node=AMcreateMmlNode("mrow",node);return[node,result[1],null];}
+case TEXT:if(str.charAt(0)=="{")i=str.indexOf("}");else i=0;if(i==-1)
+i=str.length;st=str.slice(1,i);if(st.charAt(0)==" "){node=AMcreateElementMathML("mspace");node.setAttribute("width","0.33em");newFrag.appendChild(node);}
+newFrag.appendChild(AMcreateMmlNode(symbol.tag,document.createTextNode(st)));if(st.charAt(st.length-1)==" "){node=AMcreateElementMathML("mspace");node.setAttribute("width","0.33em");newFrag.appendChild(node);}
+str=AMremoveCharsAndBlanks(str,i+1);return[AMcreateMmlNode("mrow",newFrag),str,null];case UNARY:result=AMparseSexpr(str);if(result[0]==null)return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str];if(typeof symbol.func=="boolean"&&symbol.func){st=str.charAt(0);if(st=="^"||st=="_"||st==","){return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];}else{node=AMcreateMmlNode("mrow",AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("width","0.167em");node.appendChild(space);}
+node.appendChild(result[0]);return[node,result[1],symbol.tag];}}
+if(symbol.input=="\\sqrt"){if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("height","1.2ex");space.setAttribute("width","0em");node=AMcreateMmlNode(symbol.tag,result[0])
+node.appendChild(space);return[node,result[1],symbol.tag];}else
+return[AMcreateMmlNode(symbol.tag,result[0]),result[1],symbol.tag];}else if(typeof symbol.acc=="boolean"&&symbol.acc){node=AMcreateMmlNode(symbol.tag,result[0]);var output=symbol.output;if(isIE){if(symbol.input=="\\hat")
+output="\u0302";else if(symbol.input=="\\widehat")
+output="\u005E";else if(symbol.input=="\\bar")
+output="\u00AF";else if(symbol.input=="\\grave")
+output="\u0300";else if(symbol.input=="\\tilde")
+output="\u0303";}
+var node1=AMcreateMmlNode("mo",document.createTextNode(output));if(symbol.input=="\\vec"||symbol.input=="\\check")
+node1.setAttribute("maxsize","1.2");if(isIE&&symbol.input=="\\bar")
+node1.setAttribute("maxsize","0.5");if(symbol.input=="\\underbrace"||symbol.input=="\\underline")
+node1.setAttribute("accentunder","true");else
+node1.setAttribute("accent","true");node.appendChild(node1);if(symbol.input=="\\overbrace"||symbol.input=="\\underbrace")
+node.ttype=UNDEROVER;return[node,result[1],symbol.tag];}else{if(!isIE&&typeof symbol.codes!="undefined"){for(i=0;i<result[0].childNodes.length;i++)
+if(result[0].childNodes[i].nodeName=="mi"||result[0].nodeName=="mi"){st=(result[0].nodeName=="mi"?result[0].firstChild.nodeValue:result[0].childNodes[i].firstChild.nodeValue);var newst=[];for(var j=0;j<st.length;j++)
+if(st.charCodeAt(j)>64&&st.charCodeAt(j)<91)newst=newst+
+String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]);else newst=newst+st.charAt(j);if(result[0].nodeName=="mi")
+result[0]=AMcreateElementMathML("mo").appendChild(document.createTextNode(newst));else result[0].replaceChild(AMcreateElementMathML("mo").appendChild(document.createTextNode(newst)),result[0].childNodes[i]);}}
+node=AMcreateMmlNode(symbol.tag,result[0]);node.setAttribute(symbol.atname,symbol.atval);if(symbol.input=="\\scriptstyle"||symbol.input=="\\scriptscriptstyle")
+node.setAttribute("displaystyle","false");return[node,result[1],symbol.tag];}
+case BINARY:result=AMparseSexpr(str);if(result[0]==null)return[AMcreateMmlNode("mo",document.createTextNode(symbol.input)),str,null];result2=AMparseSexpr(result[1]);if(result2[0]==null)return[AMcreateMmlNode("mo",document.createTextNode(symbol.input)),str,null];if(symbol.input=="\\textcolor"||symbol.input=="\\colorbox"){var tclr=str.match(/\{\s*([#\w]+)\s*\}/);str=str.replace(/\{\s*[#\w]+\s*\}/,"");if(tclr!=null){if(IsColorName.test(tclr[1].toLowerCase())){tclr=LaTeXColor[tclr[1].toLowerCase()];}else{tclr=tclr[1];}
+node=AMcreateElementMathML("mstyle");node.setAttribute(symbol.atval,tclr);node.appendChild(result2[0]);return[node,result2[1],symbol.tag];}}
+if(symbol.input=="\\root"||symbol.input=="\\stackrel")newFrag.appendChild(result2[0]);newFrag.appendChild(result[0]);if(symbol.input=="\\frac")newFrag.appendChild(result2[0]);return[AMcreateMmlNode(symbol.tag,newFrag),result2[1],symbol.tag];case INFIX:str=AMremoveCharsAndBlanks(str,symbol.input.length);return[AMcreateMmlNode("mo",document.createTextNode(symbol.output)),str,symbol.tag];default:return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];}}
+function AMparseIexpr(str){var symbol,sym1,sym2,node,result,tag,underover;str=AMremoveCharsAndBlanks(str,0);sym1=AMgetSymbol(str);result=AMparseSexpr(str);node=result[0];str=result[1];tag=result[2];symbol=AMgetSymbol(str);if(symbol.ttype==INFIX){str=AMremoveCharsAndBlanks(str,symbol.input.length);result=AMparseSexpr(str);if(result[0]==null)
+result[0]=AMcreateMmlNode("mo",document.createTextNode("\u25A1"));str=result[1];tag=result[2];if(symbol.input=="_"||symbol.input=="^"){sym2=AMgetSymbol(str);tag=null;underover=((sym1.ttype==UNDEROVER)||(node.ttype==UNDEROVER));if(symbol.input=="_"&&sym2.input=="^"){str=AMremoveCharsAndBlanks(str,sym2.input.length);var res2=AMparseSexpr(str);str=res2[1];tag=res2[2];node=AMcreateMmlNode((underover?"munderover":"msubsup"),node);node.appendChild(result[0]);node.appendChild(res2[0]);}else if(symbol.input=="_"){node=AMcreateMmlNode((underover?"munder":"msub"),node);node.appendChild(result[0]);}else{node=AMcreateMmlNode((underover?"mover":"msup"),node);node.appendChild(result[0]);}
+node=AMcreateMmlNode("mrow",node);}else{node=AMcreateMmlNode(symbol.tag,node);if(symbol.input=="\\atop"||symbol.input=="\\choose")
+node.setAttribute("linethickness","0ex");node.appendChild(result[0]);if(symbol.input=="\\choose")
+node=AMcreateMmlNode("mfenced",node);}}
+return[node,str,tag];}
+function AMparseExpr(str,rightbracket,matrix){var symbol,node,result,i,tag,newFrag=document.createDocumentFragment();do{str=AMremoveCharsAndBlanks(str,0);result=AMparseIexpr(str);node=result[0];str=result[1];tag=result[2];symbol=AMgetSymbol(str);if(node!=undefined){if((tag=="mn"||tag=="mi")&&symbol!=null&&typeof symbol.func=="boolean"&&symbol.func){var space=AMcreateElementMathML("mspace");space.setAttribute("width","0.167em");node=AMcreateMmlNode("mrow",node);node.appendChild(space);}
+newFrag.appendChild(node);}}while((symbol.ttype!=RIGHTBRACKET)&&symbol!=null&&symbol.output!="");tag=null;if(symbol.ttype==RIGHTBRACKET){if(symbol.input=="\\right"){str=AMremoveCharsAndBlanks(str,symbol.input.length);symbol=AMgetSymbol(str);if(symbol!=null&&symbol.input==".")
+symbol.invisible=true;if(symbol!=null)
+tag=symbol.rtag;}
+if(symbol!=null)
+str=AMremoveCharsAndBlanks(str,symbol.input.length);var len=newFrag.childNodes.length;if(matrix&&len>0&&newFrag.childNodes[len-1].nodeName=="mrow"&&len>1&&newFrag.childNodes[len-2].nodeName=="mo"&&newFrag.childNodes[len-2].firstChild.nodeValue=="&"){var pos=[];var m=newFrag.childNodes.length;for(i=0;matrix&&i<m;i=i+2){pos[i]=[];node=newFrag.childNodes[i];for(var j=0;j<node.childNodes.length;j++)
+if(node.childNodes[j].firstChild.nodeValue=="&")
+pos[i][pos[i].length]=j;}
+var row,frag,n,k,table=document.createDocumentFragment();for(i=0;i<m;i=i+2){row=document.createDocumentFragment();frag=document.createDocumentFragment();node=newFrag.firstChild;n=node.childNodes.length;k=0;for(j=0;j<n;j++){if(typeof pos[i][k]!="undefined"&&j==pos[i][k]){node.removeChild(node.firstChild);row.appendChild(AMcreateMmlNode("mtd",frag));k++;}else frag.appendChild(node.firstChild);}
+row.appendChild(AMcreateMmlNode("mtd",frag));if(newFrag.childNodes.length>2){newFrag.removeChild(newFrag.firstChild);newFrag.removeChild(newFrag.firstChild);}
+table.appendChild(AMcreateMmlNode("mtr",row));}
+return[table,str];}
+if(typeof symbol.invisible!="boolean"||!symbol.invisible){node=AMcreateMmlNode("mo",document.createTextNode(symbol.output));newFrag.appendChild(node);}}
+return[newFrag,str,tag];}
+function AMparseMath(str){var result,node=AMcreateElementMathML("mstyle");var cclr=str.match(/\\color\s*\{\s*([#\w]+)\s*\}/);str=str.replace(/\\color\s*\{\s*[#\w]+\s*\}/g,"");if(cclr!=null){if(IsColorName.test(cclr[1].toLowerCase())){cclr=LaTeXColor[cclr[1].toLowerCase()];}else{cclr=cclr[1];}
+node.setAttribute("mathcolor",cclr);}else{if(mathcolor!="")node.setAttribute("mathcolor",mathcolor);};if(mathfontfamily!="")node.setAttribute("fontfamily",mathfontfamily);node.appendChild(AMparseExpr(str.replace(/^\s+/g,""),false,false)[0]);node=AMcreateMmlNode("math",node);if(showasciiformulaonhover)
+node.setAttribute("title",str.replace(/\s+/g," "));if(false){var fnode=AMcreateElementXHTML("font");fnode.setAttribute("face",mathfontfamily);fnode.appendChild(node);return fnode;}
+return node;}
+function AMstrarr2docFrag(arr,linebreaks){var newFrag=document.createDocumentFragment();var expr=false;for(var i=0;i<arr.length;i++){if(expr)newFrag.appendChild(AMparseMath(arr[i]));else{var arri=(linebreaks?arr[i].split("\n\n"):[arr[i]]);newFrag.appendChild(AMcreateElementXHTML("span").appendChild(document.createTextNode(arri[0])));for(var j=1;j<arri.length;j++){newFrag.appendChild(AMcreateElementXHTML("p"));newFrag.appendChild(AMcreateElementXHTML("span").appendChild(document.createTextNode(arri[j])));}}
+expr=!expr;}
+return newFrag;}
+function AMprocessNodeR(n,linebreaks){var mtch,str,arr,frg,i;if(n.childNodes.length==0){if((n.nodeType!=8||linebreaks)&&n.parentNode.nodeName!="form"&&n.parentNode.nodeName!="FORM"&&n.parentNode.nodeName!="textarea"&&n.parentNode.nodeName!="TEXTAREA"&&n.parentNode.nodeName!="pre"&&n.parentNode.nodeName!="PRE"){str=n.nodeValue;if(!(str==null)){str=str.replace(/\r\n\r\n/g,"\n\n");str=str.replace(/\x20+/g," ");str=str.replace(/\s*\r\n/g," ");mtch=(str.indexOf("\$")==-1?false:true);str=str.replace(/([^\\])\$/g,"$1 \$");str=str.replace(/^\$/," \$");arr=str.split(" \$");for(i=0;i<arr.length;i++)
+arr[i]=arr[i].replace(/\\\$/g,"\$");if(arr.length>1||mtch){if(checkForMathML){checkForMathML=false;var nd=AMisMathMLavailable();AMnoMathML=nd!=null;if(AMnoMathML&&notifyIfNoMathML)
+if(alertIfNoMathML)
+alert("To view the ASCIIMathML notation use Internet Explorer 6 +\nMathPlayer (free from www.dessci.com)\nor Firefox/Mozilla/Netscape");else AMbody.insertBefore(nd,AMbody.childNodes[0]);}
+if(!AMnoMathML){frg=AMstrarr2docFrag(arr,n.nodeType==8);var len=frg.childNodes.length;n.parentNode.replaceChild(frg,n);return len-1;}else return 0;}}}else return 0;}else if(n.nodeName!="math"){for(i=0;i<n.childNodes.length;i++)
+i+=AMprocessNodeR(n.childNodes[i],linebreaks);}
+return 0;}
+function AMprocessNode(n,linebreaks,spanclassAM){var frag,st;if(spanclassAM!=null){frag=document.getElementsByTagName("span")
+for(var i=0;i<frag.length;i++)
+if(frag[i].className=="AM")
+AMprocessNodeR(frag[i],linebreaks);}else{try{st=n.innerHTML;}catch(err){}
+if(st==null||st.indexOf("\$")!=-1)
+AMprocessNodeR(n,linebreaks);}
+if(isIE){frag=document.getElementsByTagName('math');for(var i=0;i<frag.length;i++)frag[i].update()}}
+var inAppendix=false;var sectionCntr=0;var IEcommentWarning=true;var biblist=[];var bibcntr=0;var LaTeXCounter=[];LaTeXCounter["definition"]=0;LaTeXCounter["proposition"]=0;LaTeXCounter["lemma"]=0;LaTeXCounter["theorem"]=0;LaTeXCounter["corollary"]=0;LaTeXCounter["example"]=0;LaTeXCounter["exercise"]=0;LaTeXCounter["subsection"]=0;LaTeXCounter["subsubsection"]=0;LaTeXCounter["figure"]=0;LaTeXCounter["equation"]=0;LaTeXCounter["table"]=0;var LaTeXColor=[];LaTeXColor["greenyellow"]="#D9FF4F";LaTeXColor["yellow"]="#FFFF00";LaTeXColor["goldenrod"]="#FFE529";LaTeXColor["dandelion"]="#FFB529";LaTeXColor["apricot"]="#FFAD7A";LaTeXColor["peach"]="#FF804D";LaTeXColor["melon"]="#FF8A80";LaTeXColor["yelloworange"]="#FF9400";LaTeXColor["orange"]="#FF6321";LaTeXColor["burntorange"]="#FF7D00";LaTeXColor["bittersweet"]="#C20300";LaTeXColor["redorange"]="#FF3B21";LaTeXColor["mahogany"]="#A60000";LaTeXColor["maroon"]="#AD0000";LaTeXColor["brickred"]="#B80000";LaTeXColor["red"]="#FF0000";LaTeXColor["orangered"]="#FF0080";LaTeXColor["rubinered"]="#FF00DE";LaTeXColor["wildstrawberry"]="#FF0A9C";LaTeXColor["salmon"]="#FF789E";LaTeXColor["carnationpink"]="#FF5EFF";LaTeXColor["magenta"]="#FF00FF";LaTeXColor["violetred"]="#FF30FF";LaTeXColor["rhodamine"]="#FF2EFF";LaTeXColor["mulberry"]="#A314FA";LaTeXColor["redviolet"]="#9600A8";LaTeXColor["fuchsia"]="#7303EB";LaTeXColor["lavender"]="#FF85FF";LaTeXColor["thistle"]="#E069FF";LaTeXColor["orchid"]="#AD5CFF";LaTeXColor["darkorchid"]="#9933CC";LaTeXColor["purple"]="#8C24FF";LaTeXColor["plum"]="#8000FF";LaTeXColor["violet"]="#361FFF";LaTeXColor["royalpurple"]="#401AFF";LaTeXColor["blueviolet"]="#1A0DF5";LaTeXColor["periwinkle"]="#6E73FF";LaTeXColor["cadetblue"]="#616EC4";LaTeXColor["cornflowerblue"]="#59DEFF";LaTeXColor["midnightblue"]="#007091";LaTeXColor["navyblue"]="#0F75FF";LaTeXColor["royalblue"]="#0080FF";LaTeXColor["blue"]="#0000FF";LaTeXColor["cerulean"]="#0FE3FF";LaTeXColor["cyan"]="#00FFFF";LaTeXColor["processblue"]="#0AFFFF";LaTeXColor["skyblue"]="#61FFE0";LaTeXColor["turquoise"]="#26FFCC";LaTeXColor["tealblue"]="#1FFAA3";LaTeXColor["aquamarine"]="#2EFFB2";LaTeXColor["bluegreen"]="#26FFAB";LaTeXColor["emerald"]="#00FF80";LaTeXColor["junglegreen"]="#03FF7A";LaTeXColor["seagreen"]="#4FFF80";LaTeXColor["green"]="#00FF00";LaTeXColor["forestgreen"]="#00E000";LaTeXColor["pinegreen"]="#00BF29";LaTeXColor["limegreen"]="#80FF00";LaTeXColor["yellowgreen"]="#8FFF42";LaTeXColor["springgreen"]="#BDFF3D";LaTeXColor["olivegreen"]="#009900";LaTeXColor["rawsienna"]="#8C0000";LaTeXColor["sepia"]="#4D0000";LaTeXColor["brown"]="#660000";LaTeXColor["tan"]="#DB9470";LaTeXColor["gray"]="#808080";LaTeXColor["grey"]="#808080";LaTeXColor["black"]="#000000";LaTeXColor["white"]="#FFFFFF";var IsColorName=/^(?:greenyellow|yellow|goldenrod|dandelion|apricot|peach|melon|yelloworange|orange|burntorange|bittersweet|redorange|mahogany|maroon|brickred|red|orangered|rubinered|wildstrawberry|salmon|carnationpink|magenta|violetred|rhodamine|mulberry|redviolet|fuchsia|lavender|thistle|orchid|darkorchid|purple|plum|violet|royalpurple|blueviolet|periwinkle|cadetblue|cornflowerblue|midnightblue|navyblue|royalblue|blue|cerulean|cyan|processblue|skyblue|turquoise|tealblue|aquamarine|bluegreen|emerald|junglegreen|seagreen|green|forestgreen|pinegreen|limegreen|yellowgreen|springgreen|olivegreen|rawsienna|sepia|brown|tan|gray|grey|black|white)$/;var IsCounter=/^(?:definition|proposition|lemma|theorem|corollary|example|exercise|subsection|subsubsection|figure|equation|table)$/;var IsLaTeXElement=/^(?:displayequation|title|author|address|date|abstract|keyword|section|subsection|subsubsection|ref|cite|thebibliography|definition|proposition|lemma|theorem|corollary|example|exercise|itemize|enumerate|enddefinition|endproposition|endlemma|endtheorem|endcorollary|endexample|endexercise|enditemize|endenumerate|LaTeXMathMLlabel|LaTeXMathML|smallskip|medskip|bigskip|quote|quotation|endquote|endquotation|center|endcenter|description|enddescription|inlinemath)$/;var IsTextOnlyArea=/^(?:form|textarea|pre)$/i;var tableid=0;function makeNumberString(cntr){if(sectionCntr>0){if(inAppendix){return"A"+sectionCntr+"."+cntr;}else{return sectionCntr+"."+cntr;}}else{return""+cntr;}};function LaTeXpreProcess(thebody){var TheBody=thebody;if(TheBody.hasChildNodes()){if(!(IsLaTeXElement.test(TheBody.className)))
+{for(var i=0;i<TheBody.childNodes.length;i++){LaTeXpreProcess(TheBody.childNodes[i])}}}
+else{if(TheBody.nodeType==3&&!(IsTextOnlyArea.test(TheBody.parentNode.nodeName)))
+{var str=TheBody.nodeValue;if(!(str==null)){str=str.replace(/\\%/g,"<per>");str=str.replace(/%[^\n]*(?=\n)/g,"");str=str.replace(/%[^\r]*(?=\r)/g,"");str=str.replace(/%[^\n]*$/,"")
+if(isIE&&str.match(/%/g)!=null&&IEcommentWarning){alert("Comments may not have parsed properly. Try putting in <pre class='LaTeX><div>..</div></pre> structure.");IEcommentWarning=false;}
+str=str.replace(/<per>/g,"%");if(str.match(/XXX[\s\S]*/)!=null){var tmp=str.match(/XXX[\s\S]*/)[0];var tmpstr=tmp.charCodeAt(7)+"::"+tmp.charCodeAt(8)+"::"+tmp.charCodeAt(9)+"::"+tmp.charCodeAt(10)+"::"+tmp.charCodeAt(11)+"::"+tmp.charCodeAt(12)+"::"+tmp.charCodeAt(13);alert(tmpstr);}
+str=str.replace(/([^\\])\\(\s)/g,"$1\u00A0$2");str=str.replace(/\\quad/g,"\u2001");str=str.replace(/\\qquad/g,"\u2001\u2001");str=str.replace(/\\enspace/g,"\u2002");str=str.replace(/\\;/g,"\u2004");str=str.replace(/\\:/g,"\u2005");str=str.replace(/\\,/g,"\u2006");str=str.replace(/\\thinspace/g,"\u200A");str=str.replace(/([^\\])~/g,"$1\u00A0");str=str.replace(/\\~/g,"~");str=str.replace(/\\\[/g," <DEQ> $\\displaystyle{");str=str.replace(/\\\]/g,"}$ <DEQ> ");str=str.replace(/\$\$/g,"${$<DEQ>$}$");str=str.replace(/\\begin\s*\{\s*array\s*\}/g,"\\begin{array}");str=str.replace(/\\end\s*\{\s*array\s*\}/g,"\\end{array}");str=str.replace(/\\begin\s*\{\s*eqnarray\s*\}/g," <DEQ>eqno$\\begin{eqnarray}");str=str.replace(/\\end\s*\{\s*eqnarray\s*\}/g,"\\end{eqnarray}$<DEQ> ");str=str.replace(/\\begin\s*\{\s*eqnarray\*\s*\}/g," <DEQ>$\\begin{eqnarray}");str=str.replace(/\\end\s*\{\s*eqnarray\*\s*\}/g,"\\end{eqnarray}$<DEQ> ");str=str.replace(/\\begin\s*\{\s*displaymath\s*\}/g," <DEQ> $\\displaystyle{");str=str.replace(/\\end\s*\{\s*displaymath\s*\}/g,"}$ <DEQ> ");str=str.replace(/\\begin\s*\{\s*equation\s*\*\s*\}/g," <DEQ> $\\displaystyle{");str=str.replace(/\\end\s*\{\s*equation\s*\*\s*\}/g,"}$ <DEQ> ");str=str.replace(/\\begin\s*\{\s*equation\s*\}/g," <DEQ>eqno$\\displaystyle{");str=str.replace(/\\end\s*\{\s*equation\s*\}/g,"}$ <DEQ> ");str=str.split("<DEQ>");var newFrag=document.createDocumentFragment();for(var i=0;i<str.length;i++){if(i%2){var DEQtable=document.createElement("table");DEQtable.className='displayequation';var DEQtbody=document.createElement("tbody");var DEQtr=document.createElement("tr");var DEQtdeq=document.createElement("td");DEQtdeq.className='eq';str[i]=str[i].replace(/\$\}\$/g,"$\\displaystyle{");str[i]=str[i].replace(/\$\{\$/g,"}");var lbl=str[i].match(/\\label\s*\{\s*(\w+)\s*\}/);var ISeqno=str[i].match(/^eqno/);str[i]=str[i].replace(/^eqno/," ");str[i]=str[i].replace(/\\label\s*\{\s*\w+\s*\}/," ");DEQtdeq.appendChild(document.createTextNode(str[i]));DEQtr.appendChild(DEQtdeq);str[i]=str[i].replace(/\\nonumber/g,"");if(ISeqno!=null||lbl!=null){var DEQtdno=document.createElement("td");DEQtdno.className='eqno';LaTeXCounter["equation"]++;var eqnoString=makeNumberString(LaTeXCounter["equation"]);var DEQanchor=document.createElement("a");if(lbl!=null){DEQanchor.id=lbl[1]};DEQanchor.className="eqno";var anchorSpan=document.createElement("span");anchorSpan.className="eqno";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(eqnoString));DEQanchor.appendChild(anchorSpan);DEQtdno.appendChild(DEQanchor);var DEQspan=document.createElement("span");DEQspan.className="eqno";DEQspan.appendChild(document.createTextNode("("+eqnoString+")"));DEQtdno.appendChild(DEQspan);DEQtr.appendChild(DEQtdno);}
+DEQtbody.appendChild(DEQtr);DEQtable.appendChild(DEQtbody);newFrag.appendChild(DEQtable);}
+else{str[i]=str[i].replace(/\$\}\$/g,"");str[i]=str[i].replace(/\$\{\$/g,"");str[i]=str[i].replace(/\\maketitle/g,"");str[i]=str[i].replace(/\\begin\s*\{\s*document\s*\}/g,"");str[i]=str[i].replace(/\\end\s*\{\s*document\s*\}/g,"");str[i]=str[i].replace(/\\documentclass[^\}]*?\}/g,"");str[i]=str[i].replace(/\\usepackage[^\}]*?\}/g,"");str[i]=str[i].replace(/\\noindent/g,"");str[i]=str[i].replace(/\\notag/g,"");str[i]=str[i].replace(/\\ref\s*\{\s*(\w+)\}/g," \\[ref\\]$1\\[ ");str[i]=str[i].replace(/\\url\s*\{\s*([^\}\n]+)\}/g," \\[url\\]$1\\[ ");str[i]=str[i].replace(/\\href\s*\{\s*([^\}]+)\}\s*\{\s*([^\}]+)\}/g," \\[href\\]$1\\]$2\\[ ");str[i]=str[i].replace(/\\cite\s*\{\s*(\w+)\}/g," \\[cite\\]$1\\[ ");str[i]=str[i].replace(/\\qed/g,"\u220E");str[i]=str[i].replace(/\\endproof/g,"\u220E");str[i]=str[i].replace(/\\proof/g,"\\textbf{Proof: }");str[i]=str[i].replace(/\\n(?=\s)/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\newline/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\linebreak/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\smallskip/g," \\[logicalbreak\\]smallskip\\[ ");str[i]=str[i].replace(/\\medskip/g," \\[logicalbreak\\]medskip\\[ ");str[i]=str[i].replace(/\\bigskip/g," \\[logicalbreak\\]bigskip\\[ ");str[i]=str[i].replace(/[\n\r]+[ \f\n\r\t\v\u2028\u2029]*[\n\r]+/g," \\[logicalbreak\\]LaTeXMathML\\[ ");if(isIE){str[i]=str[i].replace(/\r/g," ");}
+str[i]=str[i].replace(/\\bibitem\s*([^\{]*\{\s*\w*\s*\})/g," \\[bibitem\\]$1\\[ ");str[i]=str[i].replace(/\\bibitem\s*/g," \\[bibitem\\] \\[ ");str[i]=str[i].replace(/\\item\s*\[\s*(\w+)\s*\]/g," \\[alistitem\\]$1\\[ ");str[i]=str[i].replace(/\\item\s*/g," \\[alistitem\\] \\[ ");str[i]=str[i].replace(/\\appendix/g," \\[appendix\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*figure\s*\}([\s\S]+?)\\end\s*\{\s*figure\s*\}/g," \\[figure\\]$1\\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*table\s*\}([\s\S]+?)\\end\s*\{\s*table\s*\}/g," \\[table\\]$1\\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*theorem\s*\}/g," \\[theorem\\]Theorem \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*theorem\s*\}/g," \\[endtheorem\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*definition\s*\}/g," \\[definition\\]Definition \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*definition\s*\}/g," \\[enddefinition\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*lemma\s*\}/g," \\[lemma\\]Lemma \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*lemma\s*\}/g," \\[endlemma\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*corollary\s*\}/g," \\[corollary\\]Corollary \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*corollary\s*\}/g," \\[endcorollary\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*proposition\s*\}/g," \\[proposition\\]Proposition \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*proposition\s*\}/g," \\[endproposition\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*example\s*\}/g," \\[example\\]Example \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*example\s*\}/g," \\[endexample\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*exercise\s*\}/g," \\[exercise\\]Exercise \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*exercise\s*\}/g," \\[endexercise\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*thebibliography\s*\}\s*\{\s*\w+\s*\}/g," \\[thebibliography\\]References \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*thebibliography\s*\}/g," \\[thebibliography\\]References \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*thebibliography\s*\}/g," \\[endthebibliography\\]References \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*proof\s*\}/g," \\[proof\\]Proof: \\[ ");if(isIE){str[i]=str[i].replace(/\\end\s*\{\s*proof\s*\}/g,"\u220E \\[endproof\\] \\[ ");}else{str[i]=str[i].replace(/\\end\s*\{\s*proof\s*\}/g," \\[endproof\\] \\[ ");}
+str[i]=str[i].replace(/\\title\s*\{\s*([^\}]+)\}/g," \\[title\\] \\[$1 \\[endtitle\\] \\[ ");str[i]=str[i].replace(/\\author\s*\{\s*([^\}]+)\}/g," \\[author\\] \\[$1 \\[endauthor\\] \\[ ");str[i]=str[i].replace(/\\address\s*\{\s*([^\}]+)\}/g," \\[address\\] \\[$1 \\[endaddress\\] \\[ ");str[i]=str[i].replace(/\\date\s*\{\s*([^\}]+)\}/g," \\[date\\] \\[$1 \\[enddate\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*keyword\s*\}/g," \\[keyword\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*keyword\s*\}/g," \\[endkeyword\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*abstract\s*\}/g," \\[abstract\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*abstract\s*\}/g," \\[endabstract\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*(?!array|tabular)(\w+)\s*\}/g," \\[$1\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*(?!array|tabular)(\w+)\s*\}/g," \\[end$1\\] \\[ ");var sectionIndex=str[i].search(/\\section\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\section\s*\{/," \\[section\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\section\s*\{\s*[\s\S]+\}/);}
+sectionIndex=str[i].search(/\\subsection\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\subsection\s*\{/," \\[subsection\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\subsection\s*\{\s*[\s\S]+\}/);}
+sectionIndex=str[i].search(/\\subsubsection\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\subsubsection\s*\{/," \\[subsubsection\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\subsubsection\s*\{\s*[\s\S]+\}/);}
+var CatToNextEven="";var strtmp=str[i].split("\\[");for(var j=0;j<strtmp.length;j++){if(j%2){var strtmparray=strtmp[j].split("\\]");switch(strtmparray[0]){case"section":var nodeTmp=document.createElement("H2");nodeTmp.className='section';sectionCntr++;for(var div in LaTeXCounter){LaTeXCounter[div]=0};var nodeAnchor=document.createElement("a");if(inAppendix){nodeAnchor.className='appendixsection';}else{nodeAnchor.className='section';}
+var nodeNumString=makeNumberString("");var anchorSpan=document.createElement("span");anchorSpan.className="section";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='section';nodeSpan.appendChild(document.createTextNode(nodeNumString+" "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"subsection":var nodeTmp=document.createElement("H3");nodeTmp.className='subsection';LaTeXCounter["subsection"]++;LaTeXCounter["subsubsection"]=0;var nodeAnchor=document.createElement("a");nodeAnchor.className='subsection';var nodeNumString=makeNumberString(LaTeXCounter["subsection"]);var anchorSpan=document.createElement("span");anchorSpan.className="subsection";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='subsection';nodeSpan.appendChild(document.createTextNode(nodeNumString+". "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"subsubsection":var nodeTmp=document.createElement("H4");nodeTmp.className='subsubsection';LaTeXCounter["subsubsection"]++;var nodeAnchor=document.createElement("a");nodeAnchor.className='subsubsection';var nodeNumString=makeNumberString(LaTeXCounter["subsection"]+"."+LaTeXCounter["subsubsection"]);var anchorSpan=document.createElement("span");anchorSpan.className="subsubsection";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='subsubsection';nodeSpan.appendChild(document.createTextNode(nodeNumString+". "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"href":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathML';nodeTmp.href=strtmparray[1];nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"url":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathML';nodeTmp.href=strtmparray[1];nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"figure":var nodeTmp=document.createElement("table");nodeTmp.className='figure';var FIGtbody=document.createElement("tbody");var FIGlbl=strtmparray[1].match(/\\label\s*\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\\label\s*\{\w+\}/g,"");var capIndex=strtmparray[1].search(/\\caption\s*\{[\s\S]+\}/);var FIGcap="";if(capIndex>=0){var tmp=strtmparray[1];var delimcnt=0;var capstart=-1;for(var pos=capIndex;pos<tmp.length;pos++){if(tmp.charAt(pos)=="{"){delimcnt++};if(tmp.charAt(pos)=="}"){delimcnt--};if(delimcnt==1&&capstart<0){capstart=pos+1};if(delimcnt==0&&capstart>0){capend=pos-1;FIGcap=tmp.substring(capstart,pos);break}}}
+var FIGtr2=document.createElement("tr");var FIGtd2=document.createElement("td");FIGtd2.className="caption";var FIGanchor=document.createElement("a");FIGanchor.className="figure";if(FIGlbl!=null){FIGanchor.id=FIGlbl[1];}
+LaTeXCounter["figure"]++;var fignmbr=makeNumberString(LaTeXCounter["figure"]);var anchorSpan=document.createElement("span");anchorSpan.className="figure";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(fignmbr));FIGanchor.appendChild(anchorSpan);FIGtd2.appendChild(FIGanchor);var FIGspan=document.createElement("span");FIGspan.className="figure";FIGspan.appendChild(document.createTextNode("Figure "+fignmbr+". "));FIGtd2.appendChild(FIGspan);FIGtd2.appendChild(document.createTextNode(""+FIGcap));FIGtr2.appendChild(FIGtd2);FIGtbody.appendChild(FIGtr2);var IsSpecial=false;var FIGinfo=strtmparray[1].match(/\\includegraphics\s*\{([^\}]+)\}/);if(FIGinfo==null){FIGinfo=strtmparray[1].match(/\\includegraphics\s*\[[^\]]*\]\s*\{\s*([^\}]+)\s*\}/);}
+if(FIGinfo==null){FIGinfo=strtmparray[1].match(/\\special\s*\{\s*([^\}]+)\}/);IsSpecial=true};if(FIGinfo!=null){var FIGtr1=document.createElement("tr");var FIGtd1=document.createElement("td");FIGtd1.className="image";var FIGimg=document.createElement("img");var FIGsrc=FIGinfo[1];FIGimg.src=FIGsrc;FIGimg.alt="Figure "+FIGsrc+" did not load";FIGimg.title="Figure "+fignmbr+". "+FIGcap;FIGimg.id="figure"+fignmbr;FIGtd1.appendChild(FIGimg);FIGtr1.appendChild(FIGtd1);FIGtbody.appendChild(FIGtr1);}
+nodeTmp.appendChild(FIGtbody);newFrag.appendChild(nodeTmp);break;case"table":var nodeTmp=document.createElement("table");if(strtmparray[1].search(/\\centering/)>=0){nodeTmp.className='LaTeXtable centered';nodeTmp.align="center";}else{nodeTmp.className='LaTeXtable';};tableid++;nodeTmp.id="LaTeXtable"+tableid;var TABlbl=strtmparray[1].match(/\\label\s*\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\\label\s*\{\w+\}/g,"");var capIndex=strtmparray[1].search(/\\caption\s*\{[\s\S]+\}/);var TABcap="";if(capIndex>=0){var tmp=strtmparray[1];var delimcnt=0;var capstart=-1;for(var pos=capIndex;pos<tmp.length;pos++){if(tmp.charAt(pos)=="{"){delimcnt++};if(tmp.charAt(pos)=="}"){delimcnt--};if(delimcnt==1&&capstart<0){capstart=pos+1};if(delimcnt==0&&capstart>0){capend=pos-1;TABcap=tmp.substring(capstart,pos);break}}}
+if(TABcap!=""){var TABtbody=document.createElement("tbody");var TABcaption=document.createElement("caption");TABcaption.className="LaTeXtable centered";var TABanchor=document.createElement("a");TABanchor.className="LaTeXtable";if(TABlbl!=null){TABanchor.id=TABlbl[1];}
+LaTeXCounter["table"]++;var tabnmbr=makeNumberString(LaTeXCounter["table"]);var anchorSpan=document.createElement("span");anchorSpan.className="LaTeXtable";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(tabnmbr));TABanchor.appendChild(anchorSpan);TABcaption.appendChild(TABanchor);var TABspan=document.createElement("span");TABspan.className="LaTeXtable";TABspan.appendChild(document.createTextNode("Table "+tabnmbr+". "));TABcaption.appendChild(TABspan);TABcaption.appendChild(document.createTextNode(""+TABcap));nodeTmp.appendChild(TABcaption);}
+var TABinfo=strtmparray[1].match(/\\begin\s*\{\s*tabular\s*\}([\s\S]+)\\end\s*\{\s*tabular\s*\}/);if(TABinfo!=null){var TABtbody=document.createElement('tbody');var TABrow=null;var TABcell=null;var row=0;var col=0;var TABalign=TABinfo[1].match(/^\s*\{([^\}]+)\}/);TABinfo=TABinfo[1].replace(/^\s*\{[^\}]+\}/,"");TABinfo=TABinfo.replace(/\\hline/g,"");TABalign[1]=TABalign[1].replace(/\|/g,"");TABalign[1]=TABalign[1].replace(/\s/g,"");TABinfo=TABinfo.split("\\\\");for(row=0;row<TABinfo.length;row++){TABrow=document.createElement("tr");TABinfo[row]=TABinfo[row].split("&");for(col=0;col<TABinfo[row].length;col++){TABcell=document.createElement("td");switch(TABalign[1].charAt(col)){case"l":TABcell.align="left";break;case"c":TABcell.align="center";break;case"r":TABcell.align="right";break;default:TABcell.align="left";};TABcell.appendChild(document.createTextNode(TABinfo[row][col]));TABrow.appendChild(TABcell);}
+TABtbody.appendChild(TABrow);}
+nodeTmp.appendChild(TABtbody);}
+newFrag.appendChild(nodeTmp);break;case"logicalbreak":var nodeTmp=document.createElement("p");nodeTmp.className=strtmparray[1];nodeTmp.appendChild(document.createTextNode("\u00A0"));newFrag.appendChild(nodeTmp);break;case"appendix":inAppendix=true;sectionCntr=0;break;case"alistitem":var EndDiv=document.createElement("div");EndDiv.className="endlistitem";newFrag.appendChild(EndDiv);var BegDiv=document.createElement("div");BegDiv.className="listitem";if(strtmparray[1]!=" "){var BegSpan=document.createElement("span");BegSpan.className="listitemmarker";var boldBegSpan=document.createElement("b");boldBegSpan.appendChild(document.createTextNode(strtmparray[1]+" "));BegSpan.appendChild(boldBegSpan);BegDiv.appendChild(BegSpan);}
+newFrag.appendChild(BegDiv);break;case"br":newFrag.appendChild(document.createElement("br"));break;case"bibitem":newFrag.appendChild(document.createElement("br"));var nodeTmp=document.createElement("a");nodeTmp.className='bibitem';var nodeSpan=document.createElement("span");nodeSpan.className='bibitem';bibcntr++;var lbl=strtmparray[1].match(/\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\s*\{\s*\w+\s*\}/g,"");strtmparray[1]=strtmparray[1].replace(/^\s*\[/,"");strtmparray[1]=strtmparray[1].replace(/\s*\]$/,"");strtmparray[1]=strtmparray[1].replace(/^\s+|\s+$/g,"");if(lbl==null){biblist[bibcntr]="bibitem"+bibcntr}else{biblist[bibcntr]=lbl[1];};nodeTmp.name=biblist[bibcntr];nodeTmp.id=biblist[bibcntr];if(strtmparray[1]!=""){nodeSpan.appendChild(document.createTextNode(strtmparray[1]));}else{nodeSpan.appendChild(document.createTextNode("["+bibcntr+"]"));}
+nodeTmp.appendChild(nodeSpan);newFrag.appendChild(nodeTmp);break;case"cite":var nodeTmp=document.createElement("a");nodeTmp.className='cite';nodeTmp.name='cite';nodeTmp.href="#"+strtmparray[1];newFrag.appendChild(nodeTmp);break;case"ref":var nodeTmp=document.createElement("a");nodeTmp.className='ref';nodeTmp.name='ref';nodeTmp.href="#"+strtmparray[1];newFrag.appendChild(nodeTmp);break;default:var nodeTmp=document.createElement("div");nodeTmp.className=strtmparray[0];if(IsCounter.test(strtmparray[0])){LaTeXCounter[strtmparray[0]]++;var nodeAnchor=document.createElement("a");nodeAnchor.className=strtmparray[0];var divnum=makeNumberString(LaTeXCounter[strtmparray[0]]);var anchorSpan=document.createElement("span");anchorSpan.className=strtmparray[0];anchorSpan.appendChild(document.createTextNode(divnum));anchorSpan.style.display="none";nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className=strtmparray[0];nodeSpan.appendChild(document.createTextNode(strtmparray[1]+" "+divnum+". "));nodeTmp.appendChild(nodeSpan);}
+if(isIE){if(strtmparray[0]==("thebibliography"||"abstract"||"keyword"||"proof")){var nodeSpan=document.createElement("span");nodeSpan.className=strtmparray[0];nodeSpan.appendChild(document.createTextNode(strtmparray[1]));nodeTmp.appendChild(nodeSpan);}}
+if(strtmparray[0]=="endenumerate"||strtmparray[0]=="enditemize"||strtmparray[0]=="enddescription"){var endDiv=document.createElement("div");endDiv.className="endlistitem";newFrag.appendChild(endDiv);}
+newFrag.appendChild(nodeTmp);if(strtmparray[0]=="enumerate"||strtmparray[0]=="itemize"||strtmparray[0]=="description"){var endDiv=document.createElement("div");endDiv.className="listitem";newFrag.appendChild(endDiv);}}}else{strtmp[j]=strtmp[j].replace(/\\\$/g,"<per>");strtmp[j]=strtmp[j].replace(/\$([^\$]+)\$/g," \\[$1\\[ ");strtmp[j]=strtmp[j].replace(/<per>/g,"\\$");strtmp[j]=strtmp[j].replace(/\\begin\s*\{\s*math\s*\}([\s\S]+?)\\end\s*\{\s*math\s*\}/g," \\[$1\\[ ");var strtmptmp=strtmp[j].split("\\[");for(var jjj=0;jjj<strtmptmp.length;jjj++){if(jjj%2){var nodeTmp=document.createElement("span");nodeTmp.className='inlinemath';nodeTmp.appendChild(document.createTextNode("$"+strtmptmp[jjj]+"$"));newFrag.appendChild(nodeTmp);}else{var TagIndex=strtmptmp[jjj].search(/\\\w+/);var tmpIndex=TagIndex;while(tmpIndex>-1){if(/^\\textcolor/.test(strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length))){strtmptmp[jjj]=strtmptmp[jjj].replace(/\\textcolor\s*\{\s*(\w+)\s*\}\s*/," \\[textcolor\\]$1\\]|");}else{if(/^\\colorbox/.test(strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length))){strtmptmp[jjj]=strtmptmp[jjj].replace(/\\colorbox\s*\{\s*(\w+)\s*\}\s*/," \\[colorbox\\]$1\\]|");}else{strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).replace(/\\\s*(\w+)\s*/," \\[$1\\]|");}}
+TagIndex+=strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).search(/\|/);TagIndex++;strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\]\|/,"\\] ");if(strtmptmp[jjj].charAt(TagIndex)=="{"){strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+strtmptmp[jjj].substring(TagIndex+1,strtmptmp[jjj].length);var delimcnt=1;for(var kk=TagIndex;kk<strtmptmp[jjj].length;kk++){if(strtmptmp[jjj].charAt(kk)=="{"){delimcnt++};if(strtmptmp[jjj].charAt(kk)=="}"){delimcnt--};if(delimcnt==0){break;}}
+strtmptmp[jjj]=strtmptmp[jjj].substring(0,kk)+"\\[ "+strtmptmp[jjj].substring(kk+1,strtmptmp[jjj].length);TagIndex=kk+3;}else{strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+"\\[ "+strtmptmp[jjj].substring(TagIndex+1,strtmptmp[jjj].length);TagIndex=TagIndex+3;}
+if(TagIndex<strtmptmp[jjj].length){tmpIndex=strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).search(/\\\w+/);}
+else{tmpIndex=-1};TagIndex+=tmpIndex;}
+strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\\\s*\\\\/g,"\\\\");strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\\/g," \\[br\\] \\[ ");strtmptmp[jjj]=strtmptmp[jjj].replace(/\\label\s*\{\s*(\w+)\s*\}/g," \\[a\\]$1\\[ ");var strlbls=strtmptmp[jjj].split("\\[");for(var jj=0;jj<strlbls.length;jj++){if(jj%2){var strtmparray=strlbls[jj].split("\\]");switch(strtmparray[0]){case"textcolor":var nodeTmp=document.createElement("span");nodeTmp.className='LaTeXColor';if(IsColorName.test(strtmparray[1].toLowerCase())){nodeTmp.style.color=LaTeXColor[strtmparray[1].toLowerCase()];}else{nodeTmp.style.color=strtmparray[1];};nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"colorbox":var nodeTmp=document.createElement("span");nodeTmp.className='LaTeXColor';if(IsColorName.test(strtmparray[1].toLowerCase())){nodeTmp.style.background=LaTeXColor[strtmparray[1].toLowerCase()];}else{nodeTmp.style.background=strtmparray[1];};nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"br":newFrag.appendChild(document.createElement("br"));break;case"a":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathMLlabel';nodeTmp.id=strtmparray[1];nodeTmp.style.display="none";newFrag.appendChild(nodeTmp);break;default:var nodeTmp=document.createElement("span");nodeTmp.className=strtmparray[0];nodeTmp.appendChild(document.createTextNode(strtmparray[1]))
+newFrag.appendChild(nodeTmp);}}else{newFrag.appendChild(document.createTextNode(strlbls[jj]));}}}}}}}};TheBody.parentNode.replaceChild(newFrag,TheBody);}}}
+return TheBody;}
+function LaTeXDivsAndRefs(thebody){var TheBody=thebody;var EndDivClass=null;var AllDivs=TheBody.getElementsByTagName("div");var lbl2id="";var lblnode=null;for(var i=AllDivs.length-1;i>=0;i--){EndDivClass=AllDivs[i].className.match(/end\w+/);if(EndDivClass!=null){EndDivClass=EndDivClass[0];var DivClass=EndDivClass.substring(3,EndDivClass.length);var EndDivNode=AllDivs[i];break;}}
+while(EndDivClass!=null){var newFrag=document.createDocumentFragment();var RootNode=EndDivNode.parentNode;var ClassCount=1;while(EndDivNode.previousSibling!=null&&ClassCount>0){switch(EndDivNode.previousSibling.className){case EndDivClass:ClassCount++;newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);break;case DivClass:if(EndDivNode.previousSibling.nodeName=="DIV"){ClassCount--;if(lbl2id!=""){EndDivNode.previousSibling.id=lbl2id;lbl2id=""}
+if(ClassCount==0){RootNode=EndDivNode.previousSibling;}else{newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);}};break;case'LaTeXMathMLlabel':lbl2id=EndDivNode.previousSibling.id;EndDivNode.parentNode.removeChild(EndDivNode.previousSibling);break;default:newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);}}
+RootNode.appendChild(newFrag);EndDivNode.parentNode.removeChild(EndDivNode);AllDivs=TheBody.getElementsByTagName("DIV");for(i=AllDivs.length-1;i>=0;i--){EndDivClass=AllDivs[i].className.match(/end\w+/);if(EndDivClass!=null){ClassCount=0;EndDivClass=EndDivClass[0];DivClass=EndDivClass.substring(3,EndDivClass.length);EndDivNode=AllDivs[i];RootNode=EndDivNode.parentNode;break;}}}
+var AllDivs=TheBody.getElementsByTagName("div");var DIV2LI=null;for(var i=0;i<AllDivs.length;i++){if(AllDivs[i].className=="itemize"||AllDivs[i].className=="enumerate"||AllDivs[i].className=="description"){if(AllDivs[i].className=="itemize"){RootNode=document.createElement("UL");}else{RootNode=document.createElement("OL");}
+RootNode.className='LaTeXMathML';if(AllDivs[i].hasChildNodes()){AllDivs[i].removeChild(AllDivs[i].firstChild)};while(AllDivs[i].hasChildNodes()){if(AllDivs[i].firstChild.hasChildNodes()){DIV2LI=document.createElement("LI");while(AllDivs[i].firstChild.hasChildNodes()){DIV2LI.appendChild(AllDivs[i].firstChild.firstChild);}
+if(DIV2LI.firstChild.className=="listitemmarker"){DIV2LI.style.listStyleType="none";}
+RootNode.appendChild(DIV2LI)}
+AllDivs[i].removeChild(AllDivs[i].firstChild);}
+AllDivs[i].appendChild(RootNode);}}
+var AllAnchors=TheBody.getElementsByTagName("a");for(var i=0;i<AllAnchors.length;i++){if(AllAnchors[i].className=="ref"||AllAnchors[i].className=="cite"){var label=AllAnchors[i].href.match(/\#(\w+)/);if(label!=null){var labelNode=document.getElementById(label[1]);if(labelNode!=null){var TheSpans=labelNode.getElementsByTagName("SPAN");if(TheSpans!=null){var refNode=TheSpans[0].cloneNode(true);refNode.style.display="inline"
+refNode.className=AllAnchors[i].className;AllAnchors[i].appendChild(refNode);}}}}}
+return TheBody;}
+var AMbody;var AMnoMathML=false,AMtranslated=false;function translate(spanclassAM){if(!AMtranslated){AMtranslated=true;AMinitSymbols();var LaTeXContainers=[];var AllContainers=document.getElementsByTagName('*');var ExtendName="";for(var k=0,l=0;k<AllContainers.length;k++){ExtendName=" "+AllContainers[k].className+" ";if(ExtendName.match(/\sLaTeX\s/)!=null){LaTeXContainers[l]=AllContainers[k];l++;}};if(LaTeXContainers.length>0){for(var m=0;m<LaTeXContainers.length;m++){AMbody=LaTeXContainers[m];try{AMbody=LaTeXDivsAndRefs(LaTeXpreProcess(AMbody));}catch(err){alert("Unknown Error: Defaulting to Original LaTeXMathML");}
+if(AMbody.tagName=="PRE"){var PreChilds=document.createDocumentFragment();var DivChilds=document.createElement("DIV");while(AMbody.hasChildNodes()){DivChilds.appendChild(AMbody.firstChild);}
+PreChilds.appendChild(DivChilds);AMbody.parentNode.replaceChild(PreChilds,AMbody);AMbody=DivChilds;}
+AMprocessNode(AMbody,false,spanclassAM);}}else{AMbody=document.getElementsByTagName("body")[0];try{AMbody=LaTeXDivsAndRefs(LaTeXpreProcess(AMbody));}catch(err){alert("Unknown Error: Defaulting to Original LaTeXMathML");}
+AMprocessNode(AMbody,false,spanclassAM);}}}
+if(isIE){document.write("<object id=\"mathplayer\" classid=\"clsid:32F66A20-7614-11D4-BD11-00104BD3F987\"></object>");document.write("<?import namespace=\"m\" implementation=\"#mathplayer\"?>");}
+function generic()
+{translate();};if(typeof window.addEventListener!='undefined')
+{window.addEventListener('load',generic,false);}
+else if(typeof document.addEventListener!='undefined')
+{document.addEventListener('load',generic,false);}
+else if(typeof window.attachEvent!='undefined')
+{window.attachEvent('onload',generic);}
+else
+{if(typeof window.onload=='function')
+{var existing=onload;window.onload=function()
+{existing();generic();};}
+else
+{window.onload=generic;}}</script>
+<!-- configuration parameters -->
+<meta name="defaultView" content="slideshow" />
+<meta name="controlVis" content="hidden" />
+<style type="text/css" media="projection" id="slideProj">
+/* Do not edit or override these styles! The system will likely break if you do. */
+
+div#header, div#footer, div#controls, .slide {position: absolute;}
+html>body div#header, html>body div#footer,
+ html>body div#controls, html>body .slide {position: fixed;}
+.handout {display: none;}
+.layout {display: block;}
+.slide, .hideme, .incremental {visibility: hidden;}
+#slide0 {visibility: visible;}
+
+/* The following styles size, place, and layer the slide components.
+ Edit these if you want to change the overall slide layout.
+ The commented lines can be uncommented (and modified, if necessary)
+ to help you with the rearrangement process. */
+
+/* target = 1024x768 */
+
+div#header, div#footer, .slide {width: 100%; top: 0; left: 0;}
+div#header {top: 0; height: 3em; z-index: 1;}
+div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;}
+.slide {top: 0; width: 92%; padding: 3.5em 4% 4%; z-index: 2; list-style: none;}
+div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0;}
+#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em; z-index: 10;}
+html>body #currentSlide {position: fixed;}
+
+/*
+div#header {background: #FCC;}
+div#footer {background: #CCF;}
+div#controls {background: #BBD;}
+div#currentSlide {background: #FFC;}
+*/
+
+/* Following are the presentation styles -- edit away! */
+
+body {background: #FFF url(bodybg.gif) -16px 0 no-repeat; color: #000; font-size: 2em;}
+:link, :visited {text-decoration: none; color: #00C;}
+#controls :active {color: #88A !important;}
+#controls :focus {outline: 1px dotted #227;}
+h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;}
+ul, pre {margin: 0; line-height: 1em;}
+html, body {margin: 0; padding: 0;}
+
+blockquote, q {font-style: italic;}
+blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em; text-align: center; font-size: 1em;}
+blockquote p {margin: 0;}
+blockquote i {font-style: normal;}
+blockquote b {display: block; margin-top: 0.5em; font-weight: normal; font-size: smaller; font-style: normal;}
+blockquote b i {font-style: italic;}
+
+kbd {font-weight: bold; font-size: 1em;}
+sup {font-size: smaller; line-height: 1px;}
+
+.slide code {padding: 2px 0.25em; font-weight: bold; color: #533;}
+.slide code.bad, code del {color: red;}
+.slide code.old {color: silver;}
+.slide pre {padding: 0; margin: 0.25em 0 0.5em 0.5em; color: #533; font-size: 90%;}
+.slide pre code {display: block;}
+.slide ul {margin-left: 5%; margin-right: 7%; list-style: disc;}
+.slide li {margin-top: 0.75em; margin-right: 0;}
+.slide ul ul {line-height: 1;}
+.slide ul ul li {margin: .2em; font-size: 85%; list-style: square;}
+.slide img.leader {display: block; margin: 0 auto;}
+
+div#header, div#footer {background: #005; color: #AAB;
+ font-family: Verdana, Helvetica, sans-serif;}
+div#header {background: #005 url(bodybg.gif) -16px 0 no-repeat;
+ line-height: 1px;}
+div#footer {font-size: 0.5em; font-weight: bold; padding: 1em 0;}
+#footer h1, #footer h2 {display: block; padding: 0 1em;}
+#footer h2 {font-style: italic;}
+
+div.long {font-size: 0.75em;}
+.slide h1 {position: absolute; top: 0.7em; left: 87px; z-index: 1;
+ margin: 0; padding: 0.3em 0 0 50px; white-space: nowrap;
+ font: bold 150%/1em Helvetica, sans-serif; text-transform: capitalize;
+ color: #DDE; background: #005;}
+.slide h3 {font-size: 130%;}
+h1 abbr {font-variant: small-caps;}
+
+div#controls {position: absolute; left: 50%; bottom: 0;
+ width: 50%;
+ text-align: right; font: bold 0.9em Verdana, Helvetica, sans-serif;}
+html>body div#controls {position: fixed; padding: 0 0 1em 0;
+ top: auto;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0; padding: 0;}
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+ background: #005; border: none; color: #779;
+ cursor: pointer;}
+#controls #navList {height: 1em;}
+#controls #navList #jumplist {position: absolute; bottom: 0; right: 0; background: #DDD; color: #227;}
+
+#currentSlide {text-align: center; font-size: 0.5em; color: #449;}
+
+#slide0 {padding-top: 3.5em; font-size: 90%;}
+#slide0 h1 {position: static; margin: 1em 0 0; padding: 0;
+ font: bold 2em Helvetica, sans-serif; white-space: normal;
+ color: #000; background: transparent;}
+#slide0 h2 {font: bold italic 1em Helvetica, sans-serif; margin: 0.25em;}
+#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;}
+#slide0 h4 {margin-top: 0; font-size: 1em;}
+
+ul.urls {list-style: none; display: inline; margin: 0;}
+.urls li {display: inline; margin: 0;}
+.note {display: none;}
+.external {border-bottom: 1px dotted gray;}
+html>body .external {border-bottom: none;}
+.external:after {content: " \274F"; font-size: smaller; color: #77B;}
+
+.incremental, .incremental *, .incremental *:after {color: #DDE; visibility: visible;}
+img.incremental {visibility: hidden;}
+.slide .current {color: #B02;}
+
+
+/* diagnostics
+
+li:after {content: " [" attr(class) "]"; color: #F88;}
+*/
+
+</style>
+<style type="text/css" media="projection" id="operaFix">
+/* DO NOT CHANGE THESE unless you really want to break Opera Show */
+.slide {
+ visibility: visible !important;
+ position: static !important;
+ page-break-before: always;
+}
+#slide0 {page-break-before: avoid;}
+
+</style>
+<style type="text/css" media="screen" id="outlineStyle">
+/* don't change this unless you want the layout stuff to show up in the outline view! */
+
+.layout div, #footer *, #controlForm * {display: none;}
+#footer, #controls, #controlForm, #navLinks, #toggle {
+ display: block; visibility: visible; margin: 0; padding: 0;}
+#toggle {float: right; padding: 0.5em;}
+html>body #toggle {position: fixed; top: 0; right: 0;}
+
+/* making the outline look pretty-ish */
+
+#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;}
+#slide0 h1 {padding-top: 1.5em;}
+.slide h1 {margin: 1.5em 0 0; padding-top: 0.25em;
+ border-top: 1px solid #888; border-bottom: 1px solid #AAA;}
+#toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;}
+
+</style>
+<style type="text/css" media="print" id="slidePrint">
+/* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */
+.slide, ul {page-break-inside: avoid; visibility: visible !important;}
+h1 {page-break-after: avoid;}
+
+body {font-size: 12pt; background: white;}
+* {color: black;}
+
+#slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;}
+#slide0 h3 {margin: 0; padding: 0;}
+#slide0 h4 {margin: 0 0 0.5em; padding: 0;}
+#slide0 {margin-bottom: 3em;}
+
+h1 {border-top: 2pt solid gray; border-bottom: 1px dotted silver;}
+.extra {background: transparent !important;}
+div.extra, pre.extra, .example {font-size: 10pt; color: #333;}
+ul.extra a {font-weight: bold;}
+p.example {display: none;}
+
+#header {display: none;}
+#footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style: italic;}
+#footer h2, #controls {display: none;}
+
+/* The following rule keeps the layout stuff out of print. Remove at your own risk! */
+.layout, .layout * {display: none !important;}
+
+</style>
+<script type="text/javascript">
+// S5 v1.1 slides.js -- released into the Public Domain
+//
+// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information
+// about all the wonderful and talented contributors to this code!
+var undef;var slideCSS='';var snum=0;var smax=1;var incpos=0;var number=undef;var s5mode=true;var defaultView='slideshow';var controlVis='visible';var isIE=navigator.appName=='Microsoft Internet Explorer'&&navigator.userAgent.indexOf('Opera')<1?1:0;var isOp=navigator.userAgent.indexOf('Opera')>-1?1:0;var isGe=navigator.userAgent.indexOf('Gecko')>-1&&navigator.userAgent.indexOf('Safari')<1?1:0;function hasClass(object,className){if(!object.className)return false;return(object.className.search('(^|\\s)'+className+'(\\s|$)')!=-1);}
+function hasValue(object,value){if(!object)return false;return(object.search('(^|\\s)'+value+'(\\s|$)')!=-1);}
+function removeClass(object,className){if(!object)return;object.className=object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'),RegExp.$1+RegExp.$2);}
+function addClass(object,className){if(!object||hasClass(object,className))return;if(object.className){object.className+=' '+className;}else{object.className=className;}}
+function GetElementsWithClassName(elementName,className){var allElements=document.getElementsByTagName(elementName);var elemColl=new Array();for(var i=0;i<allElements.length;i++){if(hasClass(allElements[i],className)){elemColl[elemColl.length]=allElements[i];}}
+return elemColl;}
+function isParentOrSelf(element,id){if(element==null||element.nodeName=='BODY')return false;else if(element.id==id)return true;else return isParentOrSelf(element.parentNode,id);}
+function nodeValue(node){var result="";if(node.nodeType==1){var children=node.childNodes;for(var i=0;i<children.length;++i){result+=nodeValue(children[i]);}}
+else if(node.nodeType==3){result=node.nodeValue;}
+return(result);}
+function slideLabel(){var slideColl=GetElementsWithClassName('*','slide');var list=document.getElementById('jumplist');smax=slideColl.length;for(var n=0;n<smax;n++){var obj=slideColl[n];var did='slide'+n.toString();obj.setAttribute('id',did);if(isOp)continue;var otext='';var menu=obj.firstChild;if(!menu)continue;while(menu&&menu.nodeType==3){menu=menu.nextSibling;}
+if(!menu)continue;var menunodes=menu.childNodes;for(var o=0;o<menunodes.length;o++){otext+=nodeValue(menunodes[o]);}
+list.options[list.length]=new Option(n+' : '+otext,n);}}
+function currentSlide(){var cs;if(document.getElementById){cs=document.getElementById('currentSlide');}else{cs=document.currentSlide;}
+cs.innerHTML='<span id="csHere">'+snum+'<\/span> '+'<span id="csSep">\/<\/span> '+'<span id="csTotal">'+(smax-1)+'<\/span>';if(snum==0){cs.style.visibility='hidden';}else{cs.style.visibility='visible';}}
+function go(step){if(document.getElementById('slideProj').disabled||step==0)return;var jl=document.getElementById('jumplist');var cid='slide'+snum;var ce=document.getElementById(cid);if(incrementals[snum].length>0){for(var i=0;i<incrementals[snum].length;i++){removeClass(incrementals[snum][i],'current');removeClass(incrementals[snum][i],'incremental');}}
+if(step!='j'){snum+=step;lmax=smax-1;if(snum>lmax)snum=lmax;if(snum<0)snum=0;}else
+snum=parseInt(jl.value);var nid='slide'+snum;var ne=document.getElementById(nid);if(!ne){ne=document.getElementById('slide0');snum=0;}
+if(step<0){incpos=incrementals[snum].length}else{incpos=0;}
+if(incrementals[snum].length>0&&incpos==0){for(var i=0;i<incrementals[snum].length;i++){if(hasClass(incrementals[snum][i],'current'))
+incpos=i+1;else
+addClass(incrementals[snum][i],'incremental');}}
+if(incrementals[snum].length>0&&incpos>0)
+addClass(incrementals[snum][incpos-1],'current');ce.style.visibility='hidden';ne.style.visibility='visible';jl.selectedIndex=snum;currentSlide();number=0;}
+function goTo(target){if(target>=smax||target==snum)return;go(target-snum);}
+function subgo(step){if(step>0){removeClass(incrementals[snum][incpos-1],'current');removeClass(incrementals[snum][incpos],'incremental');addClass(incrementals[snum][incpos],'current');incpos++;}else{incpos--;removeClass(incrementals[snum][incpos],'current');addClass(incrementals[snum][incpos],'incremental');addClass(incrementals[snum][incpos-1],'current');}}
+function toggle(){var slideColl=GetElementsWithClassName('*','slide');var slides=document.getElementById('slideProj');var outline=document.getElementById('outlineStyle');if(!slides.disabled){slides.disabled=true;outline.disabled=false;s5mode=false;fontSize('1em');for(var n=0;n<smax;n++){var slide=slideColl[n];slide.style.visibility='visible';}}else{slides.disabled=false;outline.disabled=true;s5mode=true;fontScale();for(var n=0;n<smax;n++){var slide=slideColl[n];slide.style.visibility='hidden';}
+slideColl[snum].style.visibility='visible';}}
+function showHide(action){var obj=GetElementsWithClassName('*','hideme')[0];switch(action){case's':obj.style.visibility='visible';break;case'h':obj.style.visibility='hidden';break;case'k':if(obj.style.visibility!='visible'){obj.style.visibility='visible';}else{obj.style.visibility='hidden';}
+break;}}
+function keys(key){if(!key){key=event;key.which=key.keyCode;}
+if(key.which==84){toggle();return;}
+if(s5mode){switch(key.which){case 10:case 13:if(window.event&&isParentOrSelf(window.event.srcElement,'controls'))return;if(key.target&&isParentOrSelf(key.target,'controls'))return;if(number!=undef){goTo(number);break;}
+case 32:case 34:case 39:case 40:if(number!=undef){go(number);}else if(!incrementals[snum]||incpos>=incrementals[snum].length){go(1);}else{subgo(1);}
+break;case 33:case 37:case 38:if(number!=undef){go(-1*number);}else if(!incrementals[snum]||incpos<=0){go(-1);}else{subgo(-1);}
+break;case 36:goTo(0);break;case 35:goTo(smax-1);break;case 67:showHide('k');break;}
+if(key.which<48||key.which>57){number=undef;}else{if(window.event&&isParentOrSelf(window.event.srcElement,'controls'))return;if(key.target&&isParentOrSelf(key.target,'controls'))return;number=(((number!=undef)?number:0)*10)+(key.which-48);}}
+return false;}
+function clicker(e){number=undef;var target;if(window.event){target=window.event.srcElement;e=window.event;}else target=e.target;if(target.getAttribute('href')!=null||hasValue(target.rel,'external')||isParentOrSelf(target,'controls')||isParentOrSelf(target,'embed')||isParentOrSelf(target,'object'))return true;if(!e.which||e.which==1){if(!incrementals[snum]||incpos>=incrementals[snum].length){go(1);}else{subgo(1);}}}
+function findSlide(hash){var target=null;var slides=GetElementsWithClassName('*','slide');for(var i=0;i<slides.length;i++){var targetSlide=slides[i];if((targetSlide.name&&targetSlide.name==hash)||(targetSlide.id&&targetSlide.id==hash)){target=targetSlide;break;}}
+while(target!=null&&target.nodeName!='BODY'){if(hasClass(target,'slide')){return parseInt(target.id.slice(5));}
+target=target.parentNode;}
+return null;}
+function slideJump(){if(window.location.hash==null)return;var sregex=/^#slide(\d+)$/;var matches=sregex.exec(window.location.hash);var dest=null;if(matches!=null){dest=parseInt(matches[1]);}else{dest=findSlide(window.location.hash.slice(1));}
+if(dest!=null)
+go(dest-snum);}
+function fixLinks(){var thisUri=window.location.href;thisUri=thisUri.slice(0,thisUri.length-window.location.hash.length);var aelements=document.getElementsByTagName('A');for(var i=0;i<aelements.length;i++){var a=aelements[i].href;var slideID=a.match('\#slide[0-9]{1,2}');if((slideID)&&(slideID[0].slice(0,1)=='#')){var dest=findSlide(slideID[0].slice(1));if(dest!=null){if(aelements[i].addEventListener){aelements[i].addEventListener("click",new Function("e","if (document.getElementById('slideProj').disabled) return;"+"go("+dest+" - snum); "+"if (e.preventDefault) e.preventDefault();"),true);}else if(aelements[i].attachEvent){aelements[i].attachEvent("onclick",new Function("","if (document.getElementById('slideProj').disabled) return;"+"go("+dest+" - snum); "+"event.returnValue = false;"));}}}}}
+function externalLinks(){if(!document.getElementsByTagName)return;var anchors=document.getElementsByTagName('a');for(var i=0;i<anchors.length;i++){var anchor=anchors[i];if(anchor.getAttribute('href')&&hasValue(anchor.rel,'external')){anchor.target='_blank';addClass(anchor,'external');}}}
+function createControls(){var controlsDiv=document.getElementById("controls");if(!controlsDiv)return;var hider=' onmouseover="showHide(\'s\');" onmouseout="showHide(\'h\');"';var hideDiv,hideList='';if(controlVis=='hidden'){hideDiv=hider;}else{hideList=hider;}
+controlsDiv.innerHTML='<form action="#" id="controlForm"'+hideDiv+'>'+'<div id="navLinks">'+'<a accesskey="t" id="toggle" href="javascript:toggle();">&#216;<\/a>'+'<a accesskey="z" id="prev" href="javascript:go(-1);">&laquo;<\/a>'+'<a accesskey="x" id="next" href="javascript:go(1);">&raquo;<\/a>'+'<div id="navList"'+hideList+'><select id="jumplist" onchange="go(\'j\');"><\/select><\/div>'+'<\/div><\/form>';if(controlVis=='hidden'){var hidden=document.getElementById('navLinks');}else{var hidden=document.getElementById('jumplist');}
+addClass(hidden,'hideme');}
+function fontScale(){if(!s5mode)return false;var vScale=22;var hScale=32;if(window.innerHeight){var vSize=window.innerHeight;var hSize=window.innerWidth;}else if(document.documentElement.clientHeight){var vSize=document.documentElement.clientHeight;var hSize=document.documentElement.clientWidth;}else if(document.body.clientHeight){var vSize=document.body.clientHeight;var hSize=document.body.clientWidth;}else{var vSize=700;var hSize=1024;}
+var newSize=Math.min(Math.round(vSize/vScale),Math.round(hSize/hScale));fontSize(newSize+'px');if(isGe){var obj=document.getElementsByTagName('body')[0];obj.style.display='none';obj.style.display='block';}}
+function fontSize(value){if(!(s5ss=document.getElementById('s5ss'))){if(!isIE){document.getElementsByTagName('head')[0].appendChild(s5ss=document.createElement('style'));s5ss.setAttribute('media','screen, projection');s5ss.setAttribute('id','s5ss');}else{document.createStyleSheet();document.s5ss=document.styleSheets[document.styleSheets.length-1];}}
+if(!isIE){while(s5ss.lastChild)s5ss.removeChild(s5ss.lastChild);s5ss.appendChild(document.createTextNode('body {font-size: '+value+' !important;}'));}else{document.s5ss.addRule('body','font-size: '+value+' !important;');}}
+function notOperaFix(){slideCSS=document.getElementById('slideProj').href;var slides=document.getElementById('slideProj');var outline=document.getElementById('outlineStyle');slides.setAttribute('media','screen');outline.disabled=true;if(isGe){slides.setAttribute('href','null');slides.setAttribute('href',slideCSS);}
+if(isIE&&document.styleSheets&&document.styleSheets[0]){document.styleSheets[0].addRule('img','behavior: url(ui/default/iepngfix.htc)');document.styleSheets[0].addRule('div','behavior: url(ui/default/iepngfix.htc)');document.styleSheets[0].addRule('.slide','behavior: url(ui/default/iepngfix.htc)');}}
+function getIncrementals(obj){var incrementals=new Array();if(!obj)
+return incrementals;var children=obj.childNodes;for(var i=0;i<children.length;i++){var child=children[i];if(hasClass(child,'incremental')){if(child.nodeName=='OL'||child.nodeName=='UL'){removeClass(child,'incremental');for(var j=0;j<child.childNodes.length;j++){if(child.childNodes[j].nodeType==1){addClass(child.childNodes[j],'incremental');}}}else{incrementals[incrementals.length]=child;removeClass(child,'incremental');}}
+if(hasClass(child,'show-first')){if(child.nodeName=='OL'||child.nodeName=='UL'){removeClass(child,'show-first');if(child.childNodes[isGe].nodeType==1){removeClass(child.childNodes[isGe],'incremental');}}else{incrementals[incrementals.length]=child;}}
+incrementals=incrementals.concat(getIncrementals(child));}
+return incrementals;}
+function createIncrementals(){var incrementals=new Array();for(var i=0;i<smax;i++){incrementals[i]=getIncrementals(document.getElementById('slide'+i));}
+return incrementals;}
+function defaultCheck(){var allMetas=document.getElementsByTagName('meta');for(var i=0;i<allMetas.length;i++){if(allMetas[i].name=='defaultView'){defaultView=allMetas[i].content;}
+if(allMetas[i].name=='controlVis'){controlVis=allMetas[i].content;}}}
+function trap(e){if(!e){e=event;e.which=e.keyCode;}
+try{modifierKey=e.ctrlKey||e.altKey||e.metaKey;}
+catch(e){modifierKey=false;}
+return modifierKey||e.which==0;}
+function startup(){defaultCheck();if(!isOp)
+createControls();slideLabel();fixLinks();externalLinks();fontScale();if(!isOp){notOperaFix();incrementals=createIncrementals();slideJump();if(defaultView=='outline'){toggle();}
+document.onkeyup=keys;document.onkeypress=trap;document.onclick=clicker;}}
+window.onload=startup;window.onresize=function(){setTimeout('fontScale()',50);}
+</script>
+</head
+ ><body
+ ><div class="layout">
+<div id="controls"></div>
+<div id="currentSlide"></div>
+<div id="header"></div>
+<div id="footer">
+<h1
+ >July 15, 2006</h1
+ ><h2
+ >My S5 Document</h2
+ ></div>
+</div>
+<div class="presentation">
+
+<div class="slide">
+<h1
+ >My S5 Document</h1
+ ><h3
+ >Sam Smith, Jen Jones</h3
+ ><h4
+ >July 15, 2006</h4
+ ></div>
+<div class="slide">
+<h1
+ >First slide</h1
+ ><ul class="incremental"
+ ><li
+ >first bullet</li
+ ><li
+ >second bullet</li
+ ></ul
+ ></div>
+<div class="slide">
+<h1
+ >Math</h1
+ ><ul class="incremental"
+ ><li
+ ><span class="LaTeX"
+ >$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span
+ ></li
+ ></ul
+ ></div>
+</div>
+</body
+ ></html
+>
+
diff --git a/tests/s5.fragment.html b/tests/s5.fragment.html
new file mode 100644
index 000000000..1d58e154a
--- /dev/null
+++ b/tests/s5.fragment.html
@@ -0,0 +1,45 @@
+<div id="first-slide"
+><h1
+ >First slide</h1
+ ><ul
+ ><li
+ >first bullet</li
+ ><li
+ >second bullet</li
+ ></ul
+ ></div
+><div id="math"
+><h1
+ >Math</h1
+ ><ul
+ ><li
+ ><span class="math"
+ >\frac{<em
+ >d</em
+ >}{<em
+ >dx</em
+ >}<em
+ >f</em
+ >(<em
+ >x</em
+ >)=\lim<sub
+ ><em
+ >h</em
+ >&#8201;&#8594;&#8201;0</sub
+ >\frac{<em
+ >f</em
+ >(<em
+ >x</em
+ >+<em
+ >h</em
+ >)-<em
+ >f</em
+ >(<em
+ >x</em
+ >)}{<em
+ >h</em
+ >}</span
+ ></li
+ ></ul
+ ></div
+>
diff --git a/tests/s5.inserts.html b/tests/s5.inserts.html
new file mode 100644
index 000000000..d6f0d6fbd
--- /dev/null
+++ b/tests/s5.inserts.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+><head
+ ><title
+ >My S5 Document</title
+ ><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
+ /><meta name="generator" content="pandoc"
+ /><meta name="author" content="Sam Smith"
+ /><meta name="author" content="Jen Jones"
+ /><meta name="date" content="July 15, 2006"
+ /><link rel="stylesheet" href="main.css" type="text/css" media="all" />
+STUFF INSERTED
+</head
+ ><body
+ >STUFF INSERTED
+<h1 class="title"
+ >My S5 Document</h1
+ ><div id="first-slide"
+ ><h1
+ >First slide</h1
+ ><ul
+ ><li
+ >first bullet</li
+ ><li
+ >second bullet</li
+ ></ul
+ ></div
+ ><div id="math"
+ ><h1
+ >Math</h1
+ ><ul
+ ><li
+ ><span class="math"
+ >\frac{<em
+ >d</em
+ >}{<em
+ >dx</em
+ >}<em
+ >f</em
+ >(<em
+ >x</em
+ >)=\lim<sub
+ ><em
+ >h</em
+ >&#8201;&#8594;&#8201;0</sub
+ >\frac{<em
+ >f</em
+ >(<em
+ >x</em
+ >+<em
+ >h</em
+ >)-<em
+ >f</em
+ >(<em
+ >x</em
+ >)}{<em
+ >h</em
+ >}</span
+ ></li
+ ></ul
+ ></div
+ >STUFF INSERTED
+</body
+ ></html
+>
+
diff --git a/tests/s5.native b/tests/s5.native
new file mode 100644
index 000000000..e314da12a
--- /dev/null
+++ b/tests/s5.native
@@ -0,0 +1,9 @@
+Pandoc (Meta [Str "My",Space,Str "S5",Space,Str "Document"] ["Sam Smith","Jen Jones"] "July 15, 2006")
+[ Header 1 [Str "First",Space,Str "slide"]
+, BulletList
+ [ [ Plain [Str "first",Space,Str "bullet"] ]
+ , [ Plain [Str "second",Space,Str "bullet"] ] ]
+, Header 1 [Str "Math"]
+, BulletList
+ [ [ Plain [Math InlineMath "\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}"] ]
+ ] ]
diff --git a/tests/tables.context b/tests/tables.context
new file mode 100644
index 000000000..87ed08e25
--- /dev/null
+++ b/tests/tables.context
@@ -0,0 +1,134 @@
+Simple table with caption:
+
+\placetable[here]{Demonstration of simple table syntax.}
+\starttable[|rp(0.15\textwidth)|lp(0.09\textwidth)|cp(0.16\textwidth)|lp(0.13\textwidth)|]
+\HL
+\NC Right
+\NC Left
+\NC Center
+\NC Default
+\NC\AR
+\HL
+\NC 12
+\NC 12
+\NC 12
+\NC 12
+\NC\AR
+\NC 123
+\NC 123
+\NC 123
+\NC 123
+\NC\AR
+\NC 1
+\NC 1
+\NC 1
+\NC 1
+\NC\AR
+\HL
+\stoptable
+
+Simple table without caption:
+
+\placetable[here]{none}
+\starttable[|rp(0.15\textwidth)|lp(0.09\textwidth)|cp(0.16\textwidth)|lp(0.13\textwidth)|]
+\HL
+\NC Right
+\NC Left
+\NC Center
+\NC Default
+\NC\AR
+\HL
+\NC 12
+\NC 12
+\NC 12
+\NC 12
+\NC\AR
+\NC 123
+\NC 123
+\NC 123
+\NC 123
+\NC\AR
+\NC 1
+\NC 1
+\NC 1
+\NC 1
+\NC\AR
+\HL
+\stoptable
+
+Simple table indented two spaces:
+
+\placetable[here]{Demonstration of simple table syntax.}
+\starttable[|rp(0.15\textwidth)|lp(0.09\textwidth)|cp(0.16\textwidth)|lp(0.13\textwidth)|]
+\HL
+\NC Right
+\NC Left
+\NC Center
+\NC Default
+\NC\AR
+\HL
+\NC 12
+\NC 12
+\NC 12
+\NC 12
+\NC\AR
+\NC 123
+\NC 123
+\NC 123
+\NC 123
+\NC\AR
+\NC 1
+\NC 1
+\NC 1
+\NC 1
+\NC\AR
+\HL
+\stoptable
+
+Multiline table with caption:
+
+\placetable[here]{Here's the caption. It may span multiple lines.}
+\starttable[|cp(0.15\textwidth)|lp(0.14\textwidth)|rp(0.16\textwidth)|lp(0.34\textwidth)|]
+\HL
+\NC Centered Header
+\NC Left Aligned
+\NC Right Aligned
+\NC Default aligned
+\NC\AR
+\HL
+\NC First
+\NC row
+\NC 12.0
+\NC Example of a row that spans multiple lines.
+\NC\AR
+\NC Second
+\NC row
+\NC 5.0
+\NC Here's another one. Note the blank line between rows.
+\NC\AR
+\HL
+\stoptable
+
+Multiline table without caption:
+
+\placetable[here]{none}
+\starttable[|cp(0.15\textwidth)|lp(0.14\textwidth)|rp(0.16\textwidth)|lp(0.34\textwidth)|]
+\HL
+\NC Centered Header
+\NC Left Aligned
+\NC Right Aligned
+\NC Default aligned
+\NC\AR
+\HL
+\NC First
+\NC row
+\NC 12.0
+\NC Example of a row that spans multiple lines.
+\NC\AR
+\NC Second
+\NC row
+\NC 5.0
+\NC Here's another one. Note the blank line between rows.
+\NC\AR
+\HL
+\stoptable
diff --git a/tests/tables.docbook b/tests/tables.docbook
new file mode 100644
index 000000000..ffeebdc57
--- /dev/null
+++ b/tests/tables.docbook
@@ -0,0 +1,287 @@
+<para>
+ Simple table with caption:
+</para>
+<table>
+ <caption>
+ Demonstration of simple table syntax.
+ </caption>
+ <tr>
+ <th align="right" style="{width: 15%;}">
+ Right
+ </th>
+ <th align="left" style="{width: 8%;}">
+ Left
+ </th>
+ <th align="center" style="{width: 16%;}">
+ Center
+ </th>
+ <th align="left" style="{width: 12%;}">
+ Default
+ </th>
+ </tr>
+ <tr>
+ <td align="right">
+ 12
+ </td>
+ <td align="left">
+ 12
+ </td>
+ <td align="center">
+ 12
+ </td>
+ <td align="left">
+ 12
+ </td>
+ </tr>
+ <tr>
+ <td align="right">
+ 123
+ </td>
+ <td align="left">
+ 123
+ </td>
+ <td align="center">
+ 123
+ </td>
+ <td align="left">
+ 123
+ </td>
+ </tr>
+ <tr>
+ <td align="right">
+ 1
+ </td>
+ <td align="left">
+ 1
+ </td>
+ <td align="center">
+ 1
+ </td>
+ <td align="left">
+ 1
+ </td>
+ </tr>
+</table>
+<para>
+ Simple table without caption:
+</para>
+<informaltable>
+ <tr>
+ <th align="right" style="{width: 15%;}">
+ Right
+ </th>
+ <th align="left" style="{width: 8%;}">
+ Left
+ </th>
+ <th align="center" style="{width: 16%;}">
+ Center
+ </th>
+ <th align="left" style="{width: 12%;}">
+ Default
+ </th>
+ </tr>
+ <tr>
+ <td align="right">
+ 12
+ </td>
+ <td align="left">
+ 12
+ </td>
+ <td align="center">
+ 12
+ </td>
+ <td align="left">
+ 12
+ </td>
+ </tr>
+ <tr>
+ <td align="right">
+ 123
+ </td>
+ <td align="left">
+ 123
+ </td>
+ <td align="center">
+ 123
+ </td>
+ <td align="left">
+ 123
+ </td>
+ </tr>
+ <tr>
+ <td align="right">
+ 1
+ </td>
+ <td align="left">
+ 1
+ </td>
+ <td align="center">
+ 1
+ </td>
+ <td align="left">
+ 1
+ </td>
+ </tr>
+</informaltable>
+<para>
+ Simple table indented two spaces:
+</para>
+<table>
+ <caption>
+ Demonstration of simple table syntax.
+ </caption>
+ <tr>
+ <th align="right" style="{width: 15%;}">
+ Right
+ </th>
+ <th align="left" style="{width: 8%;}">
+ Left
+ </th>
+ <th align="center" style="{width: 16%;}">
+ Center
+ </th>
+ <th align="left" style="{width: 12%;}">
+ Default
+ </th>
+ </tr>
+ <tr>
+ <td align="right">
+ 12
+ </td>
+ <td align="left">
+ 12
+ </td>
+ <td align="center">
+ 12
+ </td>
+ <td align="left">
+ 12
+ </td>
+ </tr>
+ <tr>
+ <td align="right">
+ 123
+ </td>
+ <td align="left">
+ 123
+ </td>
+ <td align="center">
+ 123
+ </td>
+ <td align="left">
+ 123
+ </td>
+ </tr>
+ <tr>
+ <td align="right">
+ 1
+ </td>
+ <td align="left">
+ 1
+ </td>
+ <td align="center">
+ 1
+ </td>
+ <td align="left">
+ 1
+ </td>
+ </tr>
+</table>
+<para>
+ Multiline table with caption:
+</para>
+<table>
+ <caption>
+ Here's the caption. It may span multiple lines.
+ </caption>
+ <tr>
+ <th align="center" style="{width: 15%;}">
+ Centered Header
+ </th>
+ <th align="left" style="{width: 13%;}">
+ Left Aligned
+ </th>
+ <th align="right" style="{width: 16%;}">
+ Right Aligned
+ </th>
+ <th align="left" style="{width: 33%;}">
+ Default aligned
+ </th>
+ </tr>
+ <tr>
+ <td align="center">
+ First
+ </td>
+ <td align="left">
+ row
+ </td>
+ <td align="right">
+ 12.0
+ </td>
+ <td align="left">
+ Example of a row that spans multiple lines.
+ </td>
+ </tr>
+ <tr>
+ <td align="center">
+ Second
+ </td>
+ <td align="left">
+ row
+ </td>
+ <td align="right">
+ 5.0
+ </td>
+ <td align="left">
+ Here's another one. Note the blank line between rows.
+ </td>
+ </tr>
+</table>
+<para>
+ Multiline table without caption:
+</para>
+<informaltable>
+ <tr>
+ <th align="center" style="{width: 15%;}">
+ Centered Header
+ </th>
+ <th align="left" style="{width: 13%;}">
+ Left Aligned
+ </th>
+ <th align="right" style="{width: 16%;}">
+ Right Aligned
+ </th>
+ <th align="left" style="{width: 33%;}">
+ Default aligned
+ </th>
+ </tr>
+ <tr>
+ <td align="center">
+ First
+ </td>
+ <td align="left">
+ row
+ </td>
+ <td align="right">
+ 12.0
+ </td>
+ <td align="left">
+ Example of a row that spans multiple lines.
+ </td>
+ </tr>
+ <tr>
+ <td align="center">
+ Second
+ </td>
+ <td align="left">
+ row
+ </td>
+ <td align="right">
+ 5.0
+ </td>
+ <td align="left">
+ Here's another one. Note the blank line between rows.
+ </td>
+ </tr>
+</informaltable>
+
diff --git a/tests/tables.html b/tests/tables.html
new file mode 100644
index 000000000..7626b326d
--- /dev/null
+++ b/tests/tables.html
@@ -0,0 +1,207 @@
+<p
+>Simple table with caption:</p
+><table
+><caption
+ >Demonstration of simple table syntax.</caption
+ ><tr class="header"
+ ><th align="right" style="width: 15%;"
+ >Right</th
+ ><th align="left" style="width: 8%;"
+ >Left</th
+ ><th align="center" style="width: 16%;"
+ >Center</th
+ ><th align="left" style="width: 12%;"
+ >Default</th
+ ></tr
+ ><tr class="odd"
+ ><td align="right"
+ >12</td
+ ><td align="left"
+ >12</td
+ ><td align="center"
+ >12</td
+ ><td align="left"
+ >12</td
+ ></tr
+ ><tr class="even"
+ ><td align="right"
+ >123</td
+ ><td align="left"
+ >123</td
+ ><td align="center"
+ >123</td
+ ><td align="left"
+ >123</td
+ ></tr
+ ><tr class="odd"
+ ><td align="right"
+ >1</td
+ ><td align="left"
+ >1</td
+ ><td align="center"
+ >1</td
+ ><td align="left"
+ >1</td
+ ></tr
+ ></table
+><p
+>Simple table without caption:</p
+><table
+><tr class="header"
+ ><th align="right" style="width: 15%;"
+ >Right</th
+ ><th align="left" style="width: 8%;"
+ >Left</th
+ ><th align="center" style="width: 16%;"
+ >Center</th
+ ><th align="left" style="width: 12%;"
+ >Default</th
+ ></tr
+ ><tr class="odd"
+ ><td align="right"
+ >12</td
+ ><td align="left"
+ >12</td
+ ><td align="center"
+ >12</td
+ ><td align="left"
+ >12</td
+ ></tr
+ ><tr class="even"
+ ><td align="right"
+ >123</td
+ ><td align="left"
+ >123</td
+ ><td align="center"
+ >123</td
+ ><td align="left"
+ >123</td
+ ></tr
+ ><tr class="odd"
+ ><td align="right"
+ >1</td
+ ><td align="left"
+ >1</td
+ ><td align="center"
+ >1</td
+ ><td align="left"
+ >1</td
+ ></tr
+ ></table
+><p
+>Simple table indented two spaces:</p
+><table
+><caption
+ >Demonstration of simple table syntax.</caption
+ ><tr class="header"
+ ><th align="right" style="width: 15%;"
+ >Right</th
+ ><th align="left" style="width: 8%;"
+ >Left</th
+ ><th align="center" style="width: 16%;"
+ >Center</th
+ ><th align="left" style="width: 12%;"
+ >Default</th
+ ></tr
+ ><tr class="odd"
+ ><td align="right"
+ >12</td
+ ><td align="left"
+ >12</td
+ ><td align="center"
+ >12</td
+ ><td align="left"
+ >12</td
+ ></tr
+ ><tr class="even"
+ ><td align="right"
+ >123</td
+ ><td align="left"
+ >123</td
+ ><td align="center"
+ >123</td
+ ><td align="left"
+ >123</td
+ ></tr
+ ><tr class="odd"
+ ><td align="right"
+ >1</td
+ ><td align="left"
+ >1</td
+ ><td align="center"
+ >1</td
+ ><td align="left"
+ >1</td
+ ></tr
+ ></table
+><p
+>Multiline table with caption:</p
+><table
+><caption
+ >Here's the caption. It may span multiple lines.</caption
+ ><tr class="header"
+ ><th align="center" style="width: 15%;"
+ >Centered Header</th
+ ><th align="left" style="width: 13%;"
+ >Left Aligned</th
+ ><th align="right" style="width: 16%;"
+ >Right Aligned</th
+ ><th align="left" style="width: 33%;"
+ >Default aligned</th
+ ></tr
+ ><tr class="odd"
+ ><td align="center"
+ >First</td
+ ><td align="left"
+ >row</td
+ ><td align="right"
+ >12.0</td
+ ><td align="left"
+ >Example of a row that spans multiple lines.</td
+ ></tr
+ ><tr class="even"
+ ><td align="center"
+ >Second</td
+ ><td align="left"
+ >row</td
+ ><td align="right"
+ >5.0</td
+ ><td align="left"
+ >Here's another one. Note the blank line between rows.</td
+ ></tr
+ ></table
+><p
+>Multiline table without caption:</p
+><table
+><tr class="header"
+ ><th align="center" style="width: 15%;"
+ >Centered Header</th
+ ><th align="left" style="width: 13%;"
+ >Left Aligned</th
+ ><th align="right" style="width: 16%;"
+ >Right Aligned</th
+ ><th align="left" style="width: 33%;"
+ >Default aligned</th
+ ></tr
+ ><tr class="odd"
+ ><td align="center"
+ >First</td
+ ><td align="left"
+ >row</td
+ ><td align="right"
+ >12.0</td
+ ><td align="left"
+ >Example of a row that spans multiple lines.</td
+ ></tr
+ ><tr class="even"
+ ><td align="center"
+ >Second</td
+ ><td align="left"
+ >row</td
+ ><td align="right"
+ >5.0</td
+ ><td align="left"
+ >Here's another one. Note the blank line between rows.</td
+ ></tr
+ ></table
+>
diff --git a/tests/tables.latex b/tests/tables.latex
new file mode 100644
index 000000000..d4466b9c0
--- /dev/null
+++ b/tests/tables.latex
@@ -0,0 +1,139 @@
+Simple table with caption:
+
+\begin{table}[h]
+\begin{center}
+\begin{tabular}{>{\PBS\raggedleft\hspace{0pt}}p{0.15\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.09\columnwidth}>{\PBS\centering\hspace{0pt}}p{0.16\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.13\columnwidth}}
+Right
+ & Left
+ & Center
+ & Default
+\\
+\hline
+12
+ & 12
+ & 12
+ & 12
+\\
+123
+ & 123
+ & 123
+ & 123
+\\
+1
+ & 1
+ & 1
+ & 1
+\\
+\end{tabular}
+\end{center}
+\caption{Demonstration of simple table syntax.}
+\end{table}
+
+Simple table without caption:
+
+\begin{center}
+\begin{tabular}{>{\PBS\raggedleft\hspace{0pt}}p{0.15\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.09\columnwidth}>{\PBS\centering\hspace{0pt}}p{0.16\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.13\columnwidth}}
+Right
+ & Left
+ & Center
+ & Default
+\\
+\hline
+12
+ & 12
+ & 12
+ & 12
+\\
+123
+ & 123
+ & 123
+ & 123
+\\
+1
+ & 1
+ & 1
+ & 1
+\\
+\end{tabular}
+\end{center}
+
+Simple table indented two spaces:
+
+\begin{table}[h]
+\begin{center}
+\begin{tabular}{>{\PBS\raggedleft\hspace{0pt}}p{0.15\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.09\columnwidth}>{\PBS\centering\hspace{0pt}}p{0.16\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.13\columnwidth}}
+Right
+ & Left
+ & Center
+ & Default
+\\
+\hline
+12
+ & 12
+ & 12
+ & 12
+\\
+123
+ & 123
+ & 123
+ & 123
+\\
+1
+ & 1
+ & 1
+ & 1
+\\
+\end{tabular}
+\end{center}
+\caption{Demonstration of simple table syntax.}
+\end{table}
+
+Multiline table with caption:
+
+\begin{table}[h]
+\begin{center}
+\begin{tabular}{>{\PBS\centering\hspace{0pt}}p{0.15\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.14\columnwidth}>{\PBS\raggedleft\hspace{0pt}}p{0.16\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.34\columnwidth}}
+Centered Header
+ & Left Aligned
+ & Right Aligned
+ & Default aligned
+\\
+\hline
+First
+ & row
+ & 12.0
+ & Example of a row that spans multiple lines.
+\\
+Second
+ & row
+ & 5.0
+ & Here's another one. Note the blank line between rows.
+\\
+\end{tabular}
+\end{center}
+\caption{Here's the caption. It may span multiple lines.}
+\end{table}
+
+Multiline table without caption:
+
+\begin{center}
+\begin{tabular}{>{\PBS\centering\hspace{0pt}}p{0.15\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.14\columnwidth}>{\PBS\raggedleft\hspace{0pt}}p{0.16\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.34\columnwidth}}
+Centered Header
+ & Left Aligned
+ & Right Aligned
+ & Default aligned
+\\
+\hline
+First
+ & row
+ & 12.0
+ & Example of a row that spans multiple lines.
+\\
+Second
+ & row
+ & 5.0
+ & Here's another one. Note the blank line between rows.
+\\
+\end{tabular}
+\end{center}
+
diff --git a/tests/tables.man b/tests/tables.man
new file mode 100644
index 000000000..019fa3d83
--- /dev/null
+++ b/tests/tables.man
@@ -0,0 +1,207 @@
+.PP
+Simple table with caption:
+.PP
+Demonstration of simple table syntax.
+.TS
+tab(@);
+rw(10.50n) lw(6.13n) cw(11.38n) lw(8.75n).
+T{
+Right
+T}@T{
+Left
+T}@T{
+Center
+T}@T{
+Default
+T}
+_
+T{
+12
+T}@T{
+12
+T}@T{
+12
+T}@T{
+12
+T}
+T{
+123
+T}@T{
+123
+T}@T{
+123
+T}@T{
+123
+T}
+T{
+1
+T}@T{
+1
+T}@T{
+1
+T}@T{
+1
+T}
+.TE
+.PP
+Simple table without caption:
+.PP
+.TS
+tab(@);
+rw(10.50n) lw(6.13n) cw(11.38n) lw(8.75n).
+T{
+Right
+T}@T{
+Left
+T}@T{
+Center
+T}@T{
+Default
+T}
+_
+T{
+12
+T}@T{
+12
+T}@T{
+12
+T}@T{
+12
+T}
+T{
+123
+T}@T{
+123
+T}@T{
+123
+T}@T{
+123
+T}
+T{
+1
+T}@T{
+1
+T}@T{
+1
+T}@T{
+1
+T}
+.TE
+.PP
+Simple table indented two spaces:
+.PP
+Demonstration of simple table syntax.
+.TS
+tab(@);
+rw(10.50n) lw(6.13n) cw(11.38n) lw(8.75n).
+T{
+Right
+T}@T{
+Left
+T}@T{
+Center
+T}@T{
+Default
+T}
+_
+T{
+12
+T}@T{
+12
+T}@T{
+12
+T}@T{
+12
+T}
+T{
+123
+T}@T{
+123
+T}@T{
+123
+T}@T{
+123
+T}
+T{
+1
+T}@T{
+1
+T}@T{
+1
+T}@T{
+1
+T}
+.TE
+.PP
+Multiline table with caption:
+.PP
+Here\[aq]s the caption. It may span multiple lines.
+.TS
+tab(@);
+cw(10.50n) lw(9.63n) rw(11.38n) lw(23.63n).
+T{
+Centered Header
+T}@T{
+Left Aligned
+T}@T{
+Right Aligned
+T}@T{
+Default aligned
+T}
+_
+T{
+First
+T}@T{
+row
+T}@T{
+12.0
+T}@T{
+Example of a row that spans multiple lines.
+T}
+T{
+Second
+T}@T{
+row
+T}@T{
+5.0
+T}@T{
+Here\[aq]s another one.
+Note the blank line between rows.
+T}
+.TE
+.PP
+Multiline table without caption:
+.PP
+.TS
+tab(@);
+cw(10.50n) lw(9.63n) rw(11.38n) lw(23.63n).
+T{
+Centered Header
+T}@T{
+Left Aligned
+T}@T{
+Right Aligned
+T}@T{
+Default aligned
+T}
+_
+T{
+First
+T}@T{
+row
+T}@T{
+12.0
+T}@T{
+Example of a row that spans multiple lines.
+T}
+T{
+Second
+T}@T{
+row
+T}@T{
+5.0
+T}@T{
+Here\[aq]s another one.
+Note the blank line between rows.
+T}
+.TE
diff --git a/tests/tables.markdown b/tests/tables.markdown
new file mode 100644
index 000000000..21fb015bc
--- /dev/null
+++ b/tests/tables.markdown
@@ -0,0 +1,60 @@
+Simple table with caption:
+
+ Right Left Center Default
+ ----------- ------ ------------ ---------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+ Table: Demonstration of simple table syntax.
+
+Simple table without caption:
+
+ Right Left Center Default
+ ----------- ------ ------------ ---------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+Simple table indented two spaces:
+
+ Right Left Center Default
+ ----------- ------ ------------ ---------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+ Table: Demonstration of simple table syntax.
+
+Multiline table with caption:
+
+ --------------------------------------------------------------
+ Centered Left Right Default aligned
+ Header Aligned Aligned
+ ----------- ---------- ------------ --------------------------
+ First row 12.0 Example of a row that
+ spans multiple lines.
+
+ Second row 5.0 Here's another one. Note
+ the blank line between
+ rows.
+ --------------------------------------------------------------
+
+ Table: Here's the caption. It may span multiple lines.
+
+Multiline table without caption:
+
+ --------------------------------------------------------------
+ Centered Left Right Default aligned
+ Header Aligned Aligned
+ ----------- ---------- ------------ --------------------------
+ First row 12.0 Example of a row that
+ spans multiple lines.
+
+ Second row 5.0 Here's another one. Note
+ the blank line between
+ rows.
+ --------------------------------------------------------------
+
+
+
diff --git a/tests/tables.mediawiki b/tests/tables.mediawiki
new file mode 100644
index 000000000..989159846
--- /dev/null
+++ b/tests/tables.mediawiki
@@ -0,0 +1,123 @@
+Simple table with caption:
+
+<table>
+<caption>Demonstration of simple table syntax.</caption><tr>
+<th align="right" style="width: 15%;">Right</th>
+<th align="left" style="width: 8%;">Left</th>
+<th align="center" style="width: 16%;">Center</th>
+<th align="left" style="width: 12%;">Default</th>
+</tr><tr>
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td align="left">12</td>
+</tr>
+<tr>
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td align="left">123</td>
+</tr>
+<tr>
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td align="left">1</td>
+</tr>
+</table>
+Simple table without caption:
+
+<table>
+<tr>
+<th align="right" style="width: 15%;">Right</th>
+<th align="left" style="width: 8%;">Left</th>
+<th align="center" style="width: 16%;">Center</th>
+<th align="left" style="width: 12%;">Default</th>
+</tr><tr>
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td align="left">12</td>
+</tr>
+<tr>
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td align="left">123</td>
+</tr>
+<tr>
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td align="left">1</td>
+</tr>
+</table>
+Simple table indented two spaces:
+
+<table>
+<caption>Demonstration of simple table syntax.</caption><tr>
+<th align="right" style="width: 15%;">Right</th>
+<th align="left" style="width: 8%;">Left</th>
+<th align="center" style="width: 16%;">Center</th>
+<th align="left" style="width: 12%;">Default</th>
+</tr><tr>
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td align="left">12</td>
+</tr>
+<tr>
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td align="left">123</td>
+</tr>
+<tr>
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td align="left">1</td>
+</tr>
+</table>
+Multiline table with caption:
+
+<table>
+<caption>Here's the caption. It may span multiple lines.</caption><tr>
+<th align="center" style="width: 15%;">Centered Header</th>
+<th align="left" style="width: 13%;">Left Aligned</th>
+<th align="right" style="width: 16%;">Right Aligned</th>
+<th align="left" style="width: 33%;">Default aligned</th>
+</tr><tr>
+<td align="center">First</td>
+<td align="left">row</td>
+<td align="right">12.0</td>
+<td align="left">Example of a row that spans multiple lines.</td>
+</tr>
+<tr>
+<td align="center">Second</td>
+<td align="left">row</td>
+<td align="right">5.0</td>
+<td align="left">Here's another one. Note the blank line between rows.</td>
+</tr>
+</table>
+Multiline table without caption:
+
+<table>
+<tr>
+<th align="center" style="width: 15%;">Centered Header</th>
+<th align="left" style="width: 13%;">Left Aligned</th>
+<th align="right" style="width: 16%;">Right Aligned</th>
+<th align="left" style="width: 33%;">Default aligned</th>
+</tr><tr>
+<td align="center">First</td>
+<td align="left">row</td>
+<td align="right">12.0</td>
+<td align="left">Example of a row that spans multiple lines.</td>
+</tr>
+<tr>
+<td align="center">Second</td>
+<td align="left">row</td>
+<td align="right">5.0</td>
+<td align="left">Here's another one. Note the blank line between rows.</td>
+</tr>
+</table>
diff --git a/tests/tables.native b/tests/tables.native
new file mode 100644
index 000000000..af3f11f94
--- /dev/null
+++ b/tests/tables.native
@@ -0,0 +1,84 @@
+Pandoc (Meta [] [] "")
+[ Para [Str "Simple",Space,Str "table",Space,Str "with",Space,Str "caption:"]
+, Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax",Str "."] [AlignRight,AlignLeft,AlignCenter,AlignDefault] [0.15,8.75e-2,0.1625,0.125]
+ [ [ Plain [Str "Right"] ]
+ , [ Plain [Str "Left"] ]
+ , [ Plain [Str "Center"] ]
+ , [ Plain [Str "Default"] ] ] [
+ [ [ Plain [Str "12"] ]
+ , [ Plain [Str "12"] ]
+ , [ Plain [Str "12"] ]
+ , [ Plain [Str "12"] ] ],
+ [ [ Plain [Str "123"] ]
+ , [ Plain [Str "123"] ]
+ , [ Plain [Str "123"] ]
+ , [ Plain [Str "123"] ] ],
+ [ [ Plain [Str "1"] ]
+ , [ Plain [Str "1"] ]
+ , [ Plain [Str "1"] ]
+ , [ Plain [Str "1"] ] ] ]
+, Para [Str "Simple",Space,Str "table",Space,Str "without",Space,Str "caption:"]
+, Table [] [AlignRight,AlignLeft,AlignCenter,AlignDefault] [0.15,8.75e-2,0.1625,0.125]
+ [ [ Plain [Str "Right"] ]
+ , [ Plain [Str "Left"] ]
+ , [ Plain [Str "Center"] ]
+ , [ Plain [Str "Default"] ] ] [
+ [ [ Plain [Str "12"] ]
+ , [ Plain [Str "12"] ]
+ , [ Plain [Str "12"] ]
+ , [ Plain [Str "12"] ] ],
+ [ [ Plain [Str "123"] ]
+ , [ Plain [Str "123"] ]
+ , [ Plain [Str "123"] ]
+ , [ Plain [Str "123"] ] ],
+ [ [ Plain [Str "1"] ]
+ , [ Plain [Str "1"] ]
+ , [ Plain [Str "1"] ]
+ , [ Plain [Str "1"] ] ] ]
+, Para [Str "Simple",Space,Str "table",Space,Str "indented",Space,Str "two",Space,Str "spaces:"]
+, Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax",Str "."] [AlignRight,AlignLeft,AlignCenter,AlignDefault] [0.15,8.75e-2,0.1625,0.125]
+ [ [ Plain [Str "Right"] ]
+ , [ Plain [Str "Left"] ]
+ , [ Plain [Str "Center"] ]
+ , [ Plain [Str "Default"] ] ] [
+ [ [ Plain [Str "12"] ]
+ , [ Plain [Str "12"] ]
+ , [ Plain [Str "12"] ]
+ , [ Plain [Str "12"] ] ],
+ [ [ Plain [Str "123"] ]
+ , [ Plain [Str "123"] ]
+ , [ Plain [Str "123"] ]
+ , [ Plain [Str "123"] ] ],
+ [ [ Plain [Str "1"] ]
+ , [ Plain [Str "1"] ]
+ , [ Plain [Str "1"] ]
+ , [ Plain [Str "1"] ] ] ]
+, Para [Str "Multiline",Space,Str "table",Space,Str "with",Space,Str "caption:"]
+, Table [Str "Here",Str "'",Str "s",Space,Str "the",Space,Str "caption",Str ".",Space,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines",Str "."] [AlignCenter,AlignLeft,AlignRight,AlignLeft] [0.15,0.1375,0.1625,0.3375]
+ [ [ Plain [Str "Centered",Space,Str "Header"] ]
+ , [ Plain [Str "Left",Space,Str "Aligned"] ]
+ , [ Plain [Str "Right",Space,Str "Aligned"] ]
+ , [ Plain [Str "Default",Space,Str "aligned"] ] ] [
+ [ [ Plain [Str "First"] ]
+ , [ Plain [Str "row"] ]
+ , [ Plain [Str "12",Str ".",Str "0"] ]
+ , [ Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",Space,Str "spans",Space,Str "multiple",Space,Str "lines",Str "."] ] ],
+ [ [ Plain [Str "Second"] ]
+ , [ Plain [Str "row"] ]
+ , [ Plain [Str "5",Str ".",Str "0"] ]
+ , [ Plain [Str "Here",Str "'",Str "s",Space,Str "another",Space,Str "one",Str ".",Space,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",Space,Str "rows",Str "."] ] ] ]
+, Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "caption:"]
+, Table [] [AlignCenter,AlignLeft,AlignRight,AlignLeft] [0.15,0.1375,0.1625,0.3375]
+ [ [ Plain [Str "Centered",Space,Str "Header"] ]
+ , [ Plain [Str "Left",Space,Str "Aligned"] ]
+ , [ Plain [Str "Right",Space,Str "Aligned"] ]
+ , [ Plain [Str "Default",Space,Str "aligned"] ] ] [
+ [ [ Plain [Str "First"] ]
+ , [ Plain [Str "row"] ]
+ , [ Plain [Str "12",Str ".",Str "0"] ]
+ , [ Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",Space,Str "spans",Space,Str "multiple",Space,Str "lines",Str "."] ] ],
+ [ [ Plain [Str "Second"] ]
+ , [ Plain [Str "row"] ]
+ , [ Plain [Str "5",Str ".",Str "0"] ]
+ , [ Plain [Str "Here",Str "'",Str "s",Space,Str "another",Space,Str "one",Str ".",Space,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",Space,Str "rows",Str "."] ] ] ] ]
+
diff --git a/tests/tables.opendocument b/tests/tables.opendocument
new file mode 100644
index 000000000..1b81cddf2
--- /dev/null
+++ b/tests/tables.opendocument
@@ -0,0 +1,466 @@
+<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" office:version="1.0">
+ <office:scripts />
+ <office:font-face-decls>
+ <style:font-face style:name="&amp;apos;Lucida Sans Unicode&amp;apos;" svg:font-family="Lucida Sans Unicode" />
+ <style:font-face style:name="&amp;apos;Tahoma&amp;apos;" svg:font-family="Tahoma" />
+ <style:font-face style:name="&amp;apos;Times New Roman&amp;apos;" svg:font-family="Times New Roman" />
+ </office:font-face-decls>
+ <office:automatic-styles>
+ <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Table_20_Heading">
+ <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Table_20_Heading">
+ <style:paragraph-properties fo:text-align="center" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P3" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P4" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:paragraph-properties fo:text-align="center" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P5" style:family="paragraph" style:parent-style-name="Table_20_Heading">
+ <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P6" style:family="paragraph" style:parent-style-name="Table_20_Heading">
+ <style:paragraph-properties fo:text-align="center" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P7" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P8" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:paragraph-properties fo:text-align="center" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P9" style:family="paragraph" style:parent-style-name="Table_20_Heading">
+ <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P10" style:family="paragraph" style:parent-style-name="Table_20_Heading">
+ <style:paragraph-properties fo:text-align="center" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P11" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P12" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:paragraph-properties fo:text-align="center" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P13" style:family="paragraph" style:parent-style-name="Table_20_Heading">
+ <style:paragraph-properties fo:text-align="center" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P14" style:family="paragraph" style:parent-style-name="Table_20_Heading">
+ <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P15" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:paragraph-properties fo:text-align="center" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P16" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P17" style:family="paragraph" style:parent-style-name="Table_20_Heading">
+ <style:paragraph-properties fo:text-align="center" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P18" style:family="paragraph" style:parent-style-name="Table_20_Heading">
+ <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P19" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:paragraph-properties fo:text-align="center" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="P20" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" />
+ </style:style>
+ <style:style style:name="Table1">
+ <style:table-properties style:rel-width="100%" table:align="center" />
+ </style:style>
+ <style:style style:name="Table1.A" style:family="table-column">
+ <style:table-column-properties style:column-width="1.05in" />
+ </style:style>
+ <style:style style:name="Table1.B" style:family="table-column">
+ <style:table-column-properties style:column-width="0.61in" />
+ </style:style>
+ <style:style style:name="Table1.C" style:family="table-column">
+ <style:table-column-properties style:column-width="1.14in" />
+ </style:style>
+ <style:style style:name="Table1.D" style:family="table-column">
+ <style:table-column-properties style:column-width="0.88in" />
+ </style:style>
+ <style:style style:name="Table1.A1" style:family="table-cell">
+ <style:table-cell-properties fo:border="none" />
+ </style:style>
+ <style:style style:name="Table2">
+ <style:table-properties style:rel-width="100%" table:align="center" />
+ </style:style>
+ <style:style style:name="Table2.A" style:family="table-column">
+ <style:table-column-properties style:column-width="1.05in" />
+ </style:style>
+ <style:style style:name="Table2.B" style:family="table-column">
+ <style:table-column-properties style:column-width="0.61in" />
+ </style:style>
+ <style:style style:name="Table2.C" style:family="table-column">
+ <style:table-column-properties style:column-width="1.14in" />
+ </style:style>
+ <style:style style:name="Table2.D" style:family="table-column">
+ <style:table-column-properties style:column-width="0.88in" />
+ </style:style>
+ <style:style style:name="Table2.A1" style:family="table-cell">
+ <style:table-cell-properties fo:border="none" />
+ </style:style>
+ <style:style style:name="Table3">
+ <style:table-properties style:rel-width="100%" table:align="center" />
+ </style:style>
+ <style:style style:name="Table3.A" style:family="table-column">
+ <style:table-column-properties style:column-width="1.05in" />
+ </style:style>
+ <style:style style:name="Table3.B" style:family="table-column">
+ <style:table-column-properties style:column-width="0.61in" />
+ </style:style>
+ <style:style style:name="Table3.C" style:family="table-column">
+ <style:table-column-properties style:column-width="1.14in" />
+ </style:style>
+ <style:style style:name="Table3.D" style:family="table-column">
+ <style:table-column-properties style:column-width="0.88in" />
+ </style:style>
+ <style:style style:name="Table3.A1" style:family="table-cell">
+ <style:table-cell-properties fo:border="none" />
+ </style:style>
+ <style:style style:name="Table4">
+ <style:table-properties style:rel-width="100%" table:align="center" />
+ </style:style>
+ <style:style style:name="Table4.A" style:family="table-column">
+ <style:table-column-properties style:column-width="1.05in" />
+ </style:style>
+ <style:style style:name="Table4.B" style:family="table-column">
+ <style:table-column-properties style:column-width="0.96in" />
+ </style:style>
+ <style:style style:name="Table4.C" style:family="table-column">
+ <style:table-column-properties style:column-width="1.14in" />
+ </style:style>
+ <style:style style:name="Table4.D" style:family="table-column">
+ <style:table-column-properties style:column-width="2.36in" />
+ </style:style>
+ <style:style style:name="Table4.A1" style:family="table-cell">
+ <style:table-cell-properties fo:border="none" />
+ </style:style>
+ <style:style style:name="Table5">
+ <style:table-properties style:rel-width="100%" table:align="center" />
+ </style:style>
+ <style:style style:name="Table5.A" style:family="table-column">
+ <style:table-column-properties style:column-width="1.05in" />
+ </style:style>
+ <style:style style:name="Table5.B" style:family="table-column">
+ <style:table-column-properties style:column-width="0.96in" />
+ </style:style>
+ <style:style style:name="Table5.C" style:family="table-column">
+ <style:table-column-properties style:column-width="1.14in" />
+ </style:style>
+ <style:style style:name="Table5.D" style:family="table-column">
+ <style:table-column-properties style:column-width="2.36in" />
+ </style:style>
+ <style:style style:name="Table5.A1" style:family="table-cell">
+ <style:table-cell-properties fo:border="none" />
+ </style:style>
+ </office:automatic-styles>
+ <text:p text:style-name="Text_20_body">Simple table with
+ caption:</text:p>
+ <table:table table:name="Table1" table:style-name="Table1">
+ <table:table-column table:style-name="Table1.A" />
+ <table:table-column table:style-name="Table1.B" />
+ <table:table-column table:style-name="Table1.C" />
+ <table:table-column table:style-name="Table1.D" />
+ <table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P1">Right</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Left</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P2">Center</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Default</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P3">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P4">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P3">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P4">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P3">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P4">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p text:style-name="Caption">Demonstration of simple table syntax.</text:p>
+ <text:p text:style-name="Text_20_body">Simple table without
+ caption:</text:p>
+ <table:table table:name="Table2" table:style-name="Table2">
+ <table:table-column table:style-name="Table2.A" />
+ <table:table-column table:style-name="Table2.B" />
+ <table:table-column table:style-name="Table2.C" />
+ <table:table-column table:style-name="Table2.D" />
+ <table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P5">Right</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Left</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P6">Center</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Default</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P7">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P8">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P7">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P8">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P7">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P8">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p text:style-name="Text_20_body">Simple table indented two
+ spaces:</text:p>
+ <table:table table:name="Table3" table:style-name="Table3">
+ <table:table-column table:style-name="Table3.A" />
+ <table:table-column table:style-name="Table3.B" />
+ <table:table-column table:style-name="Table3.C" />
+ <table:table-column table:style-name="Table3.D" />
+ <table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P9">Right</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Left</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P10">Center</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Default</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P11">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P12">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P11">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P12">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P11">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P12">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p text:style-name="Caption">Demonstration of simple table syntax.</text:p>
+ <text:p text:style-name="Text_20_body">Multiline table with
+ caption:</text:p>
+ <table:table table:name="Table4" table:style-name="Table4">
+ <table:table-column table:style-name="Table4.A" />
+ <table:table-column table:style-name="Table4.B" />
+ <table:table-column table:style-name="Table4.C" />
+ <table:table-column table:style-name="Table4.D" />
+ <table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="P13">Centered Header</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Left Aligned</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="P14">Right Aligned</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Default aligned</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="P15">First</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">row</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="P16">12.0</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">Example of a row that spans multiple lines.</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="P15">Second</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">row</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="P16">5.0</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">Here's another one. Note the blank line between rows.</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p text:style-name="Caption">Here's the caption. It may span multiple lines.</text:p>
+ <text:p text:style-name="Text_20_body">Multiline table without
+ caption:</text:p>
+ <table:table table:name="Table5" table:style-name="Table5">
+ <table:table-column table:style-name="Table5.A" />
+ <table:table-column table:style-name="Table5.B" />
+ <table:table-column table:style-name="Table5.C" />
+ <table:table-column table:style-name="Table5.D" />
+ <table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="P17">Centered Header</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Left Aligned</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="P18">Right Aligned</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Default aligned</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="P19">First</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">row</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="P20">12.0</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">Example of a row that spans multiple lines.</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="P19">Second</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">row</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="P20">5.0</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">Here's another one. Note the blank line between rows.</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+
+</office:document-content>
diff --git a/tests/tables.rst b/tests/tables.rst
new file mode 100644
index 000000000..db5c1c3d8
--- /dev/null
+++ b/tests/tables.rst
@@ -0,0 +1,71 @@
+Simple table with caption:
+
++-------------+--------+--------------+-----------+
+| Right | Left | Center | Default |
++=============+========+==============+===========+
+| 12 | 12 | 12 | 12 |
++-------------+--------+--------------+-----------+
+| 123 | 123 | 123 | 123 |
++-------------+--------+--------------+-----------+
+| 1 | 1 | 1 | 1 |
++-------------+--------+--------------+-----------+
+
+Table: Demonstration of simple table syntax.
+
+Simple table without caption:
+
++-------------+--------+--------------+-----------+
+| Right | Left | Center | Default |
++=============+========+==============+===========+
+| 12 | 12 | 12 | 12 |
++-------------+--------+--------------+-----------+
+| 123 | 123 | 123 | 123 |
++-------------+--------+--------------+-----------+
+| 1 | 1 | 1 | 1 |
++-------------+--------+--------------+-----------+
+
+Simple table indented two spaces:
+
++-------------+--------+--------------+-----------+
+| Right | Left | Center | Default |
++=============+========+==============+===========+
+| 12 | 12 | 12 | 12 |
++-------------+--------+--------------+-----------+
+| 123 | 123 | 123 | 123 |
++-------------+--------+--------------+-----------+
+| 1 | 1 | 1 | 1 |
++-------------+--------+--------------+-----------+
+
+Table: Demonstration of simple table syntax.
+
+Multiline table with caption:
+
++-------------+------------+--------------+----------------------------+
+| Centered | Left | Right | Default aligned |
+| Header | Aligned | Aligned | |
++=============+============+==============+============================+
+| First | row | 12.0 | Example of a row that |
+| | | | spans multiple lines. |
++-------------+------------+--------------+----------------------------+
+| Second | row | 5.0 | Here's another one. Note |
+| | | | the blank line between |
+| | | | rows. |
++-------------+------------+--------------+----------------------------+
+
+Table: Here's the caption. It may span multiple lines.
+
+Multiline table without caption:
+
++-------------+------------+--------------+----------------------------+
+| Centered | Left | Right | Default aligned |
+| Header | Aligned | Aligned | |
++=============+============+==============+============================+
+| First | row | 12.0 | Example of a row that |
+| | | | spans multiple lines. |
++-------------+------------+--------------+----------------------------+
+| Second | row | 5.0 | Here's another one. Note |
+| | | | the blank line between |
+| | | | rows. |
++-------------+------------+--------------+----------------------------+
+
+
diff --git a/tests/tables.rtf b/tests/tables.rtf
new file mode 100644
index 000000000..0485d4978
--- /dev/null
+++ b/tests/tables.rtf
@@ -0,0 +1,281 @@
+{\pard \ql \f0 \sa180 \li0 \fi0 Simple table with caption:\par}
+{
+\trowd \trgaph120
+\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2052\clbrdrb\brdrs\cellx3456\clbrdrb\brdrs\cellx4536
+\trkeep\intbl
+{
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 Right\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Left\par}
+\cell}
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 Center\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Default\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2052\cellx3456\cellx4536
+\trkeep\intbl
+{
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2052\cellx3456\cellx4536
+\trkeep\intbl
+{
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2052\cellx3456\cellx4536
+\trkeep\intbl
+{
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+}
+\intbl\row}
+{\pard \ql \f0 \sa180 \li0 \fi0 Demonstration of simple table syntax.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Simple table without caption:\par}
+{
+\trowd \trgaph120
+\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2052\clbrdrb\brdrs\cellx3456\clbrdrb\brdrs\cellx4536
+\trkeep\intbl
+{
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 Right\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Left\par}
+\cell}
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 Center\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Default\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2052\cellx3456\cellx4536
+\trkeep\intbl
+{
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2052\cellx3456\cellx4536
+\trkeep\intbl
+{
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2052\cellx3456\cellx4536
+\trkeep\intbl
+{
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+}
+\intbl\row}
+{\pard \ql \f0 \sa180 \li0 \fi0 \par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Simple table indented two spaces:\par}
+{
+\trowd \trgaph120
+\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2052\clbrdrb\brdrs\cellx3456\clbrdrb\brdrs\cellx4536
+\trkeep\intbl
+{
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 Right\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Left\par}
+\cell}
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 Center\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Default\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2052\cellx3456\cellx4536
+\trkeep\intbl
+{
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2052\cellx3456\cellx4536
+\trkeep\intbl
+{
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2052\cellx3456\cellx4536
+\trkeep\intbl
+{
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+}
+\intbl\row}
+{\pard \ql \f0 \sa180 \li0 \fi0 Demonstration of simple table syntax.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiline table with caption:\par}
+{
+\trowd \trgaph120
+\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2484\clbrdrb\brdrs\cellx3888\clbrdrb\brdrs\cellx6804
+\trkeep\intbl
+{
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 Centered Header\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Left Aligned\par}
+\cell}
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 Right Aligned\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Default aligned\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2484\cellx3888\cellx6804
+\trkeep\intbl
+{
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 First\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 row\par}
+\cell}
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 12.0\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Example of a row that spans multiple lines.\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2484\cellx3888\cellx6804
+\trkeep\intbl
+{
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 Second\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 row\par}
+\cell}
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 5.0\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Here's another one. Note the blank line between rows.\par}
+\cell}
+}
+\intbl\row}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here's the caption. It may span multiple lines.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiline table without caption:\par}
+{
+\trowd \trgaph120
+\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2484\clbrdrb\brdrs\cellx3888\clbrdrb\brdrs\cellx6804
+\trkeep\intbl
+{
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 Centered Header\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Left Aligned\par}
+\cell}
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 Right Aligned\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Default aligned\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2484\cellx3888\cellx6804
+\trkeep\intbl
+{
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 First\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 row\par}
+\cell}
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 12.0\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Example of a row that spans multiple lines.\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2484\cellx3888\cellx6804
+\trkeep\intbl
+{
+{\intbl {\pard \qc \f0 \sa0 \li0 \fi0 Second\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 row\par}
+\cell}
+{\intbl {\pard \qr \f0 \sa0 \li0 \fi0 5.0\par}
+\cell}
+{\intbl {\pard \ql \f0 \sa0 \li0 \fi0 Here's another one. Note the blank line between rows.\par}
+\cell}
+}
+\intbl\row}
+{\pard \ql \f0 \sa180 \li0 \fi0 \par}
+
diff --git a/tests/tables.texinfo b/tests/tables.texinfo
new file mode 100644
index 000000000..2b637d7d5
--- /dev/null
+++ b/tests/tables.texinfo
@@ -0,0 +1,124 @@
+@node Top
+@top Top
+
+Simple table with caption:
+
+@float
+@multitable @columnfractions 0.15 0.09 0.16 0.13
+@headitem
+Right
+ @tab Left
+ @tab Center
+ @tab Default
+@item
+12
+ @tab 12
+ @tab 12
+ @tab 12
+@item
+123
+ @tab 123
+ @tab 123
+ @tab 123
+@item
+1
+ @tab 1
+ @tab 1
+ @tab 1
+@end multitable
+@caption{Demonstration of simple table syntax.}
+@end float
+Simple table without caption:
+
+@multitable @columnfractions 0.15 0.09 0.16 0.13
+@headitem
+Right
+ @tab Left
+ @tab Center
+ @tab Default
+@item
+12
+ @tab 12
+ @tab 12
+ @tab 12
+@item
+123
+ @tab 123
+ @tab 123
+ @tab 123
+@item
+1
+ @tab 1
+ @tab 1
+ @tab 1
+@end multitable
+
+Simple table indented two spaces:
+
+@float
+@multitable @columnfractions 0.15 0.09 0.16 0.13
+@headitem
+Right
+ @tab Left
+ @tab Center
+ @tab Default
+@item
+12
+ @tab 12
+ @tab 12
+ @tab 12
+@item
+123
+ @tab 123
+ @tab 123
+ @tab 123
+@item
+1
+ @tab 1
+ @tab 1
+ @tab 1
+@end multitable
+@caption{Demonstration of simple table syntax.}
+@end float
+Multiline table with caption:
+
+@float
+@multitable @columnfractions 0.15 0.14 0.16 0.34
+@headitem
+Centered Header
+ @tab Left Aligned
+ @tab Right Aligned
+ @tab Default aligned
+@item
+First
+ @tab row
+ @tab 12.0
+ @tab Example of a row that spans multiple lines.
+@item
+Second
+ @tab row
+ @tab 5.0
+ @tab Here's another one. Note the blank line between rows.
+@end multitable
+@caption{Here's the caption. It may span multiple lines.}
+@end float
+Multiline table without caption:
+
+@multitable @columnfractions 0.15 0.14 0.16 0.34
+@headitem
+Centered Header
+ @tab Left Aligned
+ @tab Right Aligned
+ @tab Default aligned
+@item
+First
+ @tab row
+ @tab 12.0
+ @tab Example of a row that spans multiple lines.
+@item
+Second
+ @tab row
+ @tab 5.0
+ @tab Here's another one. Note the blank line between rows.
+@end multitable
+
diff --git a/tests/tables.txt b/tests/tables.txt
new file mode 100644
index 000000000..73b3b9cd7
--- /dev/null
+++ b/tests/tables.txt
@@ -0,0 +1,57 @@
+Simple table with caption:
+
+ Right Left Center Default
+------- ------ ---------- -------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+Table: Demonstration of simple table syntax.
+
+Simple table without caption:
+
+ Right Left Center Default
+------- ------ ---------- -------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+Simple table indented two spaces:
+
+ Right Left Center Default
+ ------- ------ ---------- -------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+ Table: Demonstration of simple table syntax.
+
+Multiline table with caption:
+
+---------------------------------------------------------------
+ Centered Left Right
+ Header Aligned Aligned Default aligned
+---------- --------- ----------- ---------------------------
+ First row 12.0 Example of a row that spans
+ multiple lines.
+
+ Second row 5.0 Here's another one. Note
+ the blank line between rows.
+---------------------------------------------------------------
+
+Table: Here's the caption.
+It may span multiple lines.
+
+Multiline table without caption:
+
+---------------------------------------------------------------
+ Centered Left Right
+ Header Aligned Aligned Default aligned
+---------- --------- ----------- ---------------------------
+ First row 12.0 Example of a row that spans
+ multiple lines.
+
+ Second row 5.0 Here's another one. Note
+ the blank line between rows.
+---------------------------------------------------------------
+
diff --git a/tests/testsuite.native b/tests/testsuite.native
new file mode 100644
index 000000000..5f2459ffb
--- /dev/null
+++ b/tests/testsuite.native
@@ -0,0 +1,387 @@
+Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] ["John MacFarlane","Anonymous"] "July 17, 2006")
+[ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc",Str ".",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber",Apostrophe,Str "s",Space,Str "markdown",Space,Str "test",Space,Str "suite",Str "."]
+, HorizontalRule
+, Header 1 [Str "Headers"]
+, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] ("/url","")]
+, Header 3 [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
+, Header 4 [Str "Level",Space,Str "4"]
+, Header 5 [Str "Level",Space,Str "5"]
+, Header 1 [Str "Level",Space,Str "1"]
+, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
+, Header 3 [Str "Level",Space,Str "3"]
+, Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+, Header 2 [Str "Level",Space,Str "2"]
+, Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+, HorizontalRule
+, Header 1 [Str "Paragraphs"]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "regular",Space,Str "paragraph",Str "."]
+, Para [Str "In",Space,Str "Markdown",Space,Str "1",Str ".",Str "0",Str ".",Str "0",Space,Str "and",Space,Str "earlier",Str ".",Space,Str "Version",Space,Str "8",Str ".",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item",Str ".",Space,Str "Because",Space,Str "a",Space,Str "hard",Str "-",Str "wrapped",Space,Str "line",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",Space,Str "list",Space,Str "item",Str "."]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet",Str ".",Space,Str "*",Space,Str "criminey",Str "."]
+, Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Str "here",Str "."]
+, HorizontalRule
+, Header 1 [Str "Block",Space,Str "Quotes"]
+, Para [Str "E",Str "-",Str "mail",Space,Str "style:"]
+, BlockQuote
+ [ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote",Str ".",Space,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short",Str "."] ]
+
+, BlockQuote
+ [ Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
+ , CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
+ , Para [Str "A",Space,Str "list:"]
+ , OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "item",Space,Str "one"] ]
+ , [ Plain [Str "item",Space,Str "two"] ] ]
+ , Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
+ , BlockQuote
+ [ Para [Str "nested"] ]
+
+ , BlockQuote
+ [ Para [Str "nested"] ]
+ ]
+, Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",Space,Str ">",Space,Str "1",Str "."]
+, Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph",Str "."]
+, HorizontalRule
+, Header 1 [Str "Code",Space,Str "Blocks"]
+, Para [Str "Code:"]
+, CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
+, Para [Str "And:"]
+, CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
+, HorizontalRule
+, Header 1 [Str "Lists"]
+, Header 2 [Str "Unordered"]
+, Para [Str "Asterisks",Space,Str "tight:"]
+, BulletList
+ [ [ Plain [Str "asterisk",Space,Str "1"] ]
+ , [ Plain [Str "asterisk",Space,Str "2"] ]
+ , [ Plain [Str "asterisk",Space,Str "3"] ] ]
+, Para [Str "Asterisks",Space,Str "loose:"]
+, BulletList
+ [ [ Para [Str "asterisk",Space,Str "1"] ]
+ , [ Para [Str "asterisk",Space,Str "2"] ]
+ , [ Para [Str "asterisk",Space,Str "3"] ] ]
+, Para [Str "Pluses",Space,Str "tight:"]
+, BulletList
+ [ [ Plain [Str "Plus",Space,Str "1"] ]
+ , [ Plain [Str "Plus",Space,Str "2"] ]
+ , [ Plain [Str "Plus",Space,Str "3"] ] ]
+, Para [Str "Pluses",Space,Str "loose:"]
+, BulletList
+ [ [ Para [Str "Plus",Space,Str "1"] ]
+ , [ Para [Str "Plus",Space,Str "2"] ]
+ , [ Para [Str "Plus",Space,Str "3"] ] ]
+, Para [Str "Minuses",Space,Str "tight:"]
+, BulletList
+ [ [ Plain [Str "Minus",Space,Str "1"] ]
+ , [ Plain [Str "Minus",Space,Str "2"] ]
+ , [ Plain [Str "Minus",Space,Str "3"] ] ]
+, Para [Str "Minuses",Space,Str "loose:"]
+, BulletList
+ [ [ Para [Str "Minus",Space,Str "1"] ]
+ , [ Para [Str "Minus",Space,Str "2"] ]
+ , [ Para [Str "Minus",Space,Str "3"] ] ]
+, Header 2 [Str "Ordered"]
+, Para [Str "Tight:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "First"] ]
+ , [ Plain [Str "Second"] ]
+ , [ Plain [Str "Third"] ] ]
+, Para [Str "and:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "One"] ]
+ , [ Plain [Str "Two"] ]
+ , [ Plain [Str "Three"] ] ]
+, Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "First"] ]
+ , [ Para [Str "Second"] ]
+ , [ Para [Str "Third"] ] ]
+, Para [Str "and",Space,Str "using",Space,Str "spaces:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "One"] ]
+ , [ Para [Str "Two"] ]
+ , [ Para [Str "Three"] ] ]
+, Para [Str "Multiple",Space,Str "paragraphs:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one",Str "."]
+ , Para [Str "Item",Space,Str "1",Str ".",Space,Str "graf",Space,Str "two",Str ".",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog",Apostrophe,Str "s",Space,Str "back",Str "."] ], [ Para [Str "Item",Space,Str "2",Str "."] ]
+ , [ Para [Str "Item",Space,Str "3",Str "."] ] ]
+, Header 2 [Str "Nested"]
+, BulletList
+ [ [ Plain [Str "Tab"]
+ , BulletList
+ [ [ Plain [Str "Tab"]
+ , BulletList
+ [ [ Plain [Str "Tab"] ]
+ ] ] ] ] ]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "another:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "First"] ]
+ , [ Plain [Str "Second:"]
+ , BulletList
+ [ [ Plain [Str "Fee"] ]
+ , [ Plain [Str "Fie"] ]
+ , [ Plain [Str "Foe"] ] ] ], [ Plain [Str "Third"] ] ]
+, Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "First"] ]
+ , [ Para [Str "Second:"]
+ , BulletList
+ [ [ Plain [Str "Fee"] ]
+ , [ Plain [Str "Fie"] ]
+ , [ Plain [Str "Foe"] ] ] ], [ Para [Str "Third"] ] ]
+, Header 2 [Str "Tabs",Space,Str "and",Space,Str "spaces"]
+, BulletList
+ [ [ Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"] ]
+ , [ Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]
+ , BulletList
+ [ [ Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"] ]
+ , [ Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"] ] ] ] ]
+, Header 2 [Str "Fancy",Space,Str "list",Space,Str "markers"]
+, OrderedList (2,Decimal,TwoParens)
+ [ [ Plain [Str "begins",Space,Str "with",Space,Str "2"] ]
+ , [ Para [Str "and",Space,Str "now",Space,Str "3"]
+ , Para [Str "with",Space,Str "a",Space,Str "continuation"]
+ , OrderedList (4,LowerRoman,Period)
+ [ [ Plain [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",Space,Str "starting",Space,Str "with",Space,Str "4"] ]
+ , [ Plain [Str "more",Space,Str "items"]
+ , OrderedList (1,UpperAlpha,TwoParens)
+ [ [ Plain [Str "a",Space,Str "subsublist"] ]
+ , [ Plain [Str "a",Space,Str "subsublist"] ] ] ] ] ] ]
+, Para [Str "Nesting:"]
+, OrderedList (1,UpperAlpha,Period)
+ [ [ Plain [Str "Upper",Space,Str "Alpha"]
+ , OrderedList (1,UpperRoman,Period)
+ [ [ Plain [Str "Upper",Space,Str "Roman",Str "."]
+ , OrderedList (6,Decimal,TwoParens)
+ [ [ Plain [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
+ , OrderedList (3,LowerAlpha,OneParen)
+ [ [ Plain [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"] ]
+ ] ] ] ] ] ] ]
+, Para [Str "Autonumbering:"]
+, OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "Autonumber",Str "."] ]
+ , [ Plain [Str "More",Str "."]
+ , OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "Nested",Str "."] ]
+ ] ] ]
+, Para [Str "Should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "list",Space,Str "item:"]
+, Para [Str "M.A.\160",Str "2007"]
+, Para [Str "B",Str ".",Space,Str "Williams"]
+, HorizontalRule
+, Header 1 [Str "Definition",Space,Str "Lists"]
+, Para [Str "Tight",Space,Str "using",Space,Str "spaces:"]
+, DefinitionList
+ [ ([Str "apple"],
+ [ Plain [Str "red",Space,Str "fruit"] ]
+ ),
+ ([Str "orange"],
+ [ Plain [Str "orange",Space,Str "fruit"] ]
+ ),
+ ([Str "banana"],
+ [ Plain [Str "yellow",Space,Str "fruit"] ]
+ ) ]
+, Para [Str "Tight",Space,Str "using",Space,Str "tabs:"]
+, DefinitionList
+ [ ([Str "apple"],
+ [ Plain [Str "red",Space,Str "fruit"] ]
+ ),
+ ([Str "orange"],
+ [ Plain [Str "orange",Space,Str "fruit"] ]
+ ),
+ ([Str "banana"],
+ [ Plain [Str "yellow",Space,Str "fruit"] ]
+ ) ]
+, Para [Str "Loose:"]
+, DefinitionList
+ [ ([Str "apple"],
+ [ Para [Str "red",Space,Str "fruit"] ]
+ ),
+ ([Str "orange"],
+ [ Para [Str "orange",Space,Str "fruit"] ]
+ ),
+ ([Str "banana"],
+ [ Para [Str "yellow",Space,Str "fruit"] ]
+ ) ]
+, Para [Str "Multiple",Space,Str "blocks",Space,Str "with",Space,Str "italics:"]
+, DefinitionList
+ [ ([Emph [Str "apple"]],
+ [ Para [Str "red",Space,Str "fruit"]
+ , Para [Str "contains",Space,Str "seeds,",Space,Str "crisp,",Space,Str "pleasant",Space,Str "to",Space,Str "taste"] ] ),
+ ([Emph [Str "orange"]],
+ [ Para [Str "orange",Space,Str "fruit"]
+ , CodeBlock ("",[],[]) "{ orange code block }"
+ , BlockQuote
+ [ Para [Str "orange",Space,Str "block",Space,Str "quote"] ]
+ ] ) ]
+, Header 1 [Str "HTML",Space,Str "Blocks"]
+, Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line:"]
+, RawHtml "<div>"
+, Plain [Str "foo"]
+, RawHtml "</div>\n"
+, Para [Str "And",Space,Str "nested",Space,Str "without",Space,Str "indentation:"]
+, RawHtml "<div>\n<div>\n<div>"
+, Plain [Str "foo"]
+, RawHtml "</div>\n</div>\n<div>"
+, Plain [Str "bar"]
+, RawHtml "</div>\n</div>\n"
+, Para [Str "Interpreted",Space,Str "markdown",Space,Str "in",Space,Str "a",Space,Str "table:"]
+, RawHtml "<table>\n<tr>\n<td>"
+, Plain [Str "This",Space,Str "is",Space,Emph [Str "emphasized"]]
+, RawHtml "</td>\n<td>"
+, Plain [Str "And",Space,Str "this",Space,Str "is",Space,Strong [Str "strong"]]
+, RawHtml "</td>\n</tr>\n</table>\n\n<script type=\"text/javascript\">document.write('This *should not* be interpreted as markdown');</script>\n"
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "simple",Space,Str "block:"]
+, RawHtml "<div>\n "
+, Plain [Str "foo"]
+, RawHtml "</div>\n"
+, Para [Str "This",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "code",Space,Str "block,",Space,Str "though:"]
+, CodeBlock ("",[],[]) "<div>\n foo\n</div>"
+, Para [Str "As",Space,Str "should",Space,Str "this:"]
+, CodeBlock ("",[],[]) "<div>foo</div>"
+, Para [Str "Now,",Space,Str "nested:"]
+, RawHtml "<div>\n <div>\n <div>\n "
+, Plain [Str "foo"]
+, RawHtml "</div>\n </div>\n</div>\n"
+, Para [Str "This",Space,Str "should",Space,Str "just",Space,Str "be",Space,Str "an",Space,Str "HTML",Space,Str "comment:"]
+, RawHtml "<!-- Comment -->\n"
+, Para [Str "Multiline:"]
+, RawHtml "<!--\nBlah\nBlah\n-->\n\n<!--\n This is another comment.\n-->\n"
+, Para [Str "Code",Space,Str "block:"]
+, CodeBlock ("",[],[]) "<!-- Comment -->"
+, Para [Str "Just",Space,Str "plain",Space,Str "comment,",Space,Str "with",Space,Str "trailing",Space,Str "spaces",Space,Str "on",Space,Str "the",Space,Str "line:"]
+, RawHtml "<!-- foo --> \n"
+, Para [Str "Code:"]
+, CodeBlock ("",[],[]) "<hr />"
+, Para [Str "Hr",Apostrophe,Str "s:"]
+, RawHtml "<hr>\n\n<hr />\n\n<hr />\n\n<hr> \n\n<hr /> \n\n<hr /> \n\n<hr class=\"foo\" id=\"bar\" />\n\n<hr class=\"foo\" id=\"bar\" />\n\n<hr class=\"foo\" id=\"bar\">\n"
+, HorizontalRule
+, Header 1 [Str "Inline",Space,Str "Markup"]
+, Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
+, Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
+, Para [Str "An",Space,Emph [Link [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
+, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em",Str "."]]]
+, Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word",Str "."]
+, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em",Str "."]]]
+, Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word",Str "."]
+, Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ">",Str ",",Space,Code "$",Str ",",Space,Code "\\",Str ",",Space,Code "\\$",Str ",",Space,Code "<html>",Str "."]
+, Para [Strikeout [Str "This",Space,Str "is",Space,Emph [Str "strikeout"],Str "."]]
+, Para [Str "Superscripts:",Space,Str "a",Superscript [Str "bc"],Str "d",Space,Str "a",Superscript [Emph [Str "hello"]],Space,Str "a",Superscript [Str "hello",Str "\160",Str "there"],Str "."]
+, Para [Str "Subscripts:",Space,Str "H",Subscript [Str "2"],Str "O,",Space,Str "H",Subscript [Str "23"],Str "O,",Space,Str "H",Subscript [Str "many",Str "\160",Str "of",Str "\160",Str "them"],Str "O",Str "."]
+, Para [Str "These",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "superscripts",Space,Str "or",Space,Str "subscripts,",Space,Str "because",Space,Str "of",Space,Str "the",Space,Str "unescaped",Space,Str "spaces:",Space,Str "a",Str "^",Str "b",Space,Str "c",Str "^",Str "d,",Space,Str "a",Str "~",Str "b",Space,Str "c",Str "~",Str "d",Str "."]
+, HorizontalRule
+, Header 1 [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
+, Para [Quoted DoubleQuote [Str "Hello,"],Space,Str "said",Space,Str "the",Space,Str "spider",Str ".",Space,Quoted DoubleQuote [Quoted SingleQuote [Str "Shelob"],Space,Str "is",Space,Str "my",Space,Str "name",Str "."]]
+, Para [Quoted SingleQuote [Str "A"],Str ",",Space,Quoted SingleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted SingleQuote [Str "C"],Space,Str "are",Space,Str "letters",Str "."]
+, Para [Quoted SingleQuote [Str "Oak,"],Space,Quoted SingleQuote [Str "elm,"],Space,Str "and",Space,Quoted SingleQuote [Str "beech"],Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees",Str ".",Space,Str "So",Space,Str "is",Space,Quoted SingleQuote [Str "pine",Str "."]]
+, Para [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go",Str "."]],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70",Apostrophe,Str "s?"]
+, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code "code"],Space,Str "and",Space,Str "a",Space,Quoted DoubleQuote [Link [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2","")],Str "."]
+, Para [Str "Some",Space,Str "dashes:",Space,Str "one",EmDash,Str "two",Space,EmDash,Space,Str "three",EmDash,Str "four",Space,EmDash,Space,Str "five",Str "."]
+, Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5",EnDash,Str "7,",Space,Str "255",EnDash,Str "66,",Space,Str "1987",EnDash,Str "1999",Str "."]
+, Para [Str "Ellipses",Ellipses,Str "and",Ellipses,Str "and",Ellipses,Str "."]
+, HorizontalRule
+, Header 1 [Str "LaTeX"]
+, BulletList
+ [ [ Plain [TeX "\\cite[22-23]{smith.1899}"] ]
+ , [ Plain [Math InlineMath "2+2=4"] ]
+ , [ Plain [Math InlineMath "x \\in y"] ]
+ , [ Plain [Math InlineMath "\\alpha \\wedge \\omega"] ]
+ , [ Plain [Math InlineMath "223"] ]
+ , [ Plain [Math InlineMath "p",Str "-",Str "Tree"] ]
+ , [ Plain [Str "Here",Apostrophe,Str "s",Space,Str "some",Space,Str "display",Space,Str "math:",Space,Math DisplayMath "\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}"] ]
+ , [ Plain [Str "Here",Apostrophe,Str "s",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",Space,Math InlineMath "\\alpha + \\omega \\times x^2",Str "."] ] ]
+, Para [Str "These",Space,Str "shouldn",Apostrophe,Str "t",Space,Str "be",Space,Str "math:"]
+, BulletList
+ [ [ Plain [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",Space,Code "$e = mc^2$",Str "."] ]
+ , [ Plain [Str "$",Str "22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money",Str ".",Space,Str "So",Space,Str "is",Space,Str "$",Str "34,000",Str ".",Space,Str "(It",Space,Str "worked",Space,Str "if",Space,Quoted DoubleQuote [Str "lot"],Space,Str "is",Space,Str "emphasized",Str ".",Str ")"] ]
+ , [ Plain [Str "Shoes",Space,Str "(",Str "$",Str "20)",Space,Str "and",Space,Str "socks",Space,Str "(",Str "$",Str "5)",Str "."] ]
+ , [ Plain [Str "Escaped",Space,Code "$",Str ":",Space,Str "$",Str "73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23",Str "$",Str "."] ] ]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
+, Para [TeX "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}"]
+, HorizontalRule
+, Header 1 [Str "Special",Space,Str "Characters"]
+, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
+, BulletList
+ [ [ Plain [Str "I",Space,Str "hat:",Space,Str "\206"] ]
+ , [ Plain [Str "o",Space,Str "umlaut:",Space,Str "\246"] ]
+ , [ Plain [Str "section:",Space,Str "\167"] ]
+ , [ Plain [Str "set",Space,Str "membership:",Space,Str "\8712"] ]
+ , [ Plain [Str "copyright:",Space,Str "\169"] ] ]
+, Para [Str "AT",Str "&",Str "T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name",Str "."]
+, Para [Str "AT",Str "&",Str "T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it",Str "."]
+, Para [Str "This",Space,Str "&",Space,Str "that",Str "."]
+, Para [Str "4",Space,Str "<",Space,Str "5",Str "."]
+, Para [Str "6",Space,Str ">",Space,Str "5",Str "."]
+, Para [Str "Backslash:",Space,Str "\\"]
+, Para [Str "Backtick:",Space,Str "`"]
+, Para [Str "Asterisk:",Space,Str "*"]
+, Para [Str "Underscore:",Space,Str "_"]
+, Para [Str "Left",Space,Str "brace:",Space,Str "{"]
+, Para [Str "Right",Space,Str "brace:",Space,Str "}"]
+, Para [Str "Left",Space,Str "bracket:",Space,Str "["]
+, Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
+, Para [Str "Left",Space,Str "paren:",Space,Str "("]
+, Para [Str "Right",Space,Str "paren:",Space,Str ")"]
+, Para [Str "Greater",Str "-",Str "than:",Space,Str ">"]
+, Para [Str "Hash:",Space,Str "#"]
+, Para [Str "Period:",Space,Str "."]
+, Para [Str "Bang:",Space,Str "!"]
+, Para [Str "Plus:",Space,Str "+"]
+, Para [Str "Minus:",Space,Str "-"]
+, HorizontalRule
+, Header 1 [Str "Links"]
+, Header 2 [Str "Explicit"]
+, Para [Str "Just",Space,Str "a",Space,Link [Str "URL"] ("/url/",""),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
+, Para [Link [Str "with",Str "_",Str "underscore"] ("/url/with_underscore","")]
+, Para [Link [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
+, Para [Link [Str "Empty"] ("",""),Str "."]
+, Header 2 [Str "Reference"]
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "With",Space,Link [Str "embedded",Space,Str "[",Str "brackets",Str "]"] ("/url/",""),Str "."]
+, Para [Link [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link",Str "."]
+, Para [Str "Indented",Space,Link [Str "once"] ("/url",""),Str "."]
+, Para [Str "Indented",Space,Link [Str "twice"] ("/url",""),Str "."]
+, Para [Str "Indented",Space,Link [Str "thrice"] ("/url",""),Str "."]
+, Para [Str "This",Space,Str "should",Space,Str "[",Str "not",Str "]",Str "[",Str "]",Space,Str "be",Space,Str "a",Space,Str "link",Str "."]
+, CodeBlock ("",[],[]) "[not]: /url"
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
+, Para [Str "Foo",Space,Link [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
+, Header 2 [Str "With",Space,Str "ampersands"]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link [Str "AT",Str "&",Str "T"] ("http://att.com/","AT&T"),Str "."]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
+, Header 2 [Str "Autolinks"]
+, Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link [Code "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
+, BulletList
+ [ [ Plain [Str "In",Space,Str "a",Space,Str "list?"] ]
+ , [ Plain [Link [Code "http://example.com/"] ("http://example.com/","")] ]
+ , [ Plain [Str "It",Space,Str "should",Str "."] ] ]
+, Para [Str "An",Space,Str "e",Str "-",Str "mail",Space,Str "address:",Space,Link [Code "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")]
+, BlockQuote
+ [ Para [Str "Blockquoted:",Space,Link [Code "http://example.com/"] ("http://example.com/","")] ]
+
+, Para [Str "Auto",Str "-",Str "links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code "<http://example.com/>"]
+, CodeBlock ("",[],[]) "or here: <http://example.com/>"
+, HorizontalRule
+, Header 1 [Str "Images"]
+, Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
+, Para [Image [Str "lalune"] ("lalune.jpg","Voyage dans la Lune")]
+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] ("movie.jpg",""),Space,Str "icon",Str "."]
+, HorizontalRule
+, Header 1 [Str "Footnotes"]
+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote",Str ".",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",Space,Str "reference",Str ".",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document",Str "."]],Space,Str "and",Space,Str "another",Str ".",Note [Para [Str "Here",Apostrophe,Str "s",Space,Str "the",Space,Str "long",Space,Str "note",Str ".",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks",Str "."],Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)",Str "."],CodeBlock ("",[],[]) " { <code> }",Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",Space,Str "lazy",Space,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block",Str "."]],Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space",Str ".",Str "[",Str "^",Str "my",Space,Str "note",Str "]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",Space,Str "note",Str ".",Note [Para [Str "This",Space,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type",Str ".",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",Space,Link [Str "links"] ("http://google.com",""),Space,Str "and",Space,Code "]",Space,Str "verbatim",Space,Str "characters,",Space,Str "as",Space,Str "well",Space,Str "as",Space,Str "[",Str "bracketed",Space,Str "text",Str "]",Str "."]]]
+, BlockQuote
+ [ Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes",Str ".",Note [Para [Str "In",Space,Str "quote",Str "."]]] ]
+
+, OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "And",Space,Str "in",Space,Str "list",Space,Str "items",Str ".",Note [Para [Str "In",Space,Str "list",Str "."]]] ]
+ ]
+, Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented",Str "."] ]
+
diff --git a/tests/testsuite.txt b/tests/testsuite.txt
new file mode 100644
index 000000000..357739e08
--- /dev/null
+++ b/tests/testsuite.txt
@@ -0,0 +1,683 @@
+% Pandoc Test Suite
+% John MacFarlane, Anonymous
+% July 17, 2006
+
+This is a set of tests for pandoc. Most of them are adapted from
+John Gruber's markdown test suite.
+
+-----
+
+# Headers
+
+## Level 2 with an [embedded link](/url)
+
+### Level 3 with *emphasis*
+
+#### Level 4
+
+##### Level 5
+
+Level 1
+=======
+
+Level 2 with *emphasis*
+-----------------------
+
+### Level 3
+with no blank line
+
+Level 2
+-------
+with no blank line
+
+----------
+
+# Paragraphs
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version
+8. This line turns into a list item.
+Because a hard-wrapped line in the
+middle of a paragraph looked like a
+list item.
+
+Here's one with a bullet.
+* criminey.
+
+There should be a hard line break
+here.
+
+---
+
+# Block Quotes
+
+E-mail style:
+
+> This is a block quote.
+> It is pretty short.
+
+> Code in a block quote:
+>
+> sub status {
+> print "working";
+> }
+>
+> A list:
+>
+> 1. item one
+> 2. item two
+>
+> Nested block quotes:
+>
+> > nested
+>
+>> nested
+>
+
+This should not be a block quote: 2
+> 1.
+
+And a following paragraph.
+
+* * * *
+
+# Code Blocks
+
+Code:
+
+ ---- (should be four hyphens)
+
+ sub status {
+ print "working";
+ }
+
+ this code block is indented by one tab
+
+And:
+
+ this code block is indented by two tabs
+
+ These should not be escaped: \$ \\ \> \[ \{
+
+___________
+
+# Lists
+
+## Unordered
+
+Asterisks tight:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+
+Asterisks loose:
+
+* asterisk 1
+
+* asterisk 2
+
+* asterisk 3
+
+Pluses tight:
+
++ Plus 1
++ Plus 2
++ Plus 3
+
+Pluses loose:
+
++ Plus 1
+
++ Plus 2
+
++ Plus 3
+
+Minuses tight:
+
+- Minus 1
+- Minus 2
+- Minus 3
+
+Minuses loose:
+
+- Minus 1
+
+- Minus 2
+
+- Minus 3
+
+## Ordered
+
+Tight:
+
+1. First
+2. Second
+3. Third
+
+and:
+
+1. One
+2. Two
+3. Three
+
+Loose using tabs:
+
+1. First
+
+2. Second
+
+3. Third
+
+and using spaces:
+
+1. One
+
+2. Two
+
+3. Three
+
+Multiple paragraphs:
+
+1. Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's
+ back.
+
+2. Item 2.
+
+3. Item 3.
+
+## Nested
+
+* Tab
+ * Tab
+ * Tab
+
+Here's another:
+
+1. First
+2. Second:
+ * Fee
+ * Fie
+ * Foe
+3. Third
+
+Same thing but with paragraphs:
+
+1. First
+
+2. Second:
+
+ * Fee
+ * Fie
+ * Foe
+
+3. Third
+
+## Tabs and spaces
+
++ this is a list item
+ indented with tabs
+
++ this is a list item
+ indented with spaces
+
+ + this is an example list item
+ indented with tabs
+
+ + this is an example list item
+ indented with spaces
+
+## Fancy list markers
+
+(2) begins with 2
+(3) and now 3
+
+ with a continuation
+
+ iv. sublist with roman numerals,
+ starting with 4
+ v. more items
+ (A) a subsublist
+ (B) a subsublist
+
+Nesting:
+
+A. Upper Alpha
+ I. Upper Roman.
+ (6) Decimal start with 6
+ c) Lower alpha with paren
+
+Autonumbering:
+
+ #. Autonumber.
+ #. More.
+ #. Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+ * * * * *
+
+# Definition Lists
+
+Tight using spaces:
+
+apple
+: red fruit
+orange
+: orange fruit
+banana
+: yellow fruit
+
+Tight using tabs:
+
+apple
+: red fruit
+orange
+: orange fruit
+banana
+: yellow fruit
+
+Loose:
+
+apple
+: red fruit
+
+orange
+: orange fruit
+
+banana
+: yellow fruit
+
+Multiple blocks with italics:
+
+*apple*
+: red fruit
+
+: contains seeds,
+ crisp, pleasant to taste
+
+*orange*
+: orange fruit
+
+: { orange code block }
+
+: > orange block quote
+
+# HTML Blocks
+
+Simple block on one line:
+
+<div>foo</div>
+
+And nested without indentation:
+
+<div>
+<div>
+<div>
+foo
+</div>
+</div>
+<div>bar</div>
+</div>
+
+Interpreted markdown in a table:
+
+<table>
+<tr>
+<td>This is *emphasized*</td>
+<td>And this is **strong**</td>
+</tr>
+</table>
+
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+
+Here's a simple block:
+
+<div>
+ foo
+</div>
+
+This should be a code block, though:
+
+ <div>
+ foo
+ </div>
+
+As should this:
+
+ <div>foo</div>
+
+Now, nested:
+
+<div>
+ <div>
+ <div>
+ foo
+ </div>
+ </div>
+</div>
+
+This should just be an HTML comment:
+
+<!-- Comment -->
+
+Multiline:
+
+<!--
+Blah
+Blah
+-->
+
+<!--
+ This is another comment.
+-->
+
+Code block:
+
+ <!-- Comment -->
+
+Just plain comment, with trailing spaces on the line:
+
+<!-- foo -->
+
+Code:
+
+ <hr />
+
+Hr's:
+
+<hr>
+
+<hr/>
+
+<hr />
+
+<hr>
+
+<hr/>
+
+<hr />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar"/>
+
+<hr class="foo" id="bar" >
+
+-----
+
+# Inline Markup
+
+This is *emphasized*, and so _is this_.
+
+This is **strong**, and so __is this__.
+
+An *[emphasized link](/url)*.
+
+***This is strong and em.***
+
+So is ***this*** word.
+
+___This is strong and em.___
+
+So is ___this___ word.
+
+This is code: `>`, `$`, `\`, `\$`, `<html>`.
+
+~~This is *strikeout*.~~
+
+Superscripts: a^bc^d a^*hello*^ a^hello\ there^.
+
+Subscripts: H~2~O, H~23~O, H~many\ of\ them~O.
+
+These should not be superscripts or subscripts,
+because of the unescaped spaces: a^b c^d, a~b c~d.
+
+-----
+
+# Smart quotes, ellipses, dashes
+
+"Hello," said the spider. "'Shelob' is my name."
+
+'A', 'B', and 'C' are letters.
+
+'Oak,' 'elm,' and 'beech' are names of trees.
+So is 'pine.'
+
+'He said, "I want to go."' Were you alive in the
+70's?
+
+Here is some quoted '`code`' and a "[quoted link][1]".
+
+Some dashes: one---two --- three--four -- five.
+
+Dashes between numbers: 5-7, 255-66, 1987-1999.
+
+Ellipses...and. . .and . . . .
+
+-----
+
+# LaTeX
+
+- \cite[22-23]{smith.1899}
+- $2+2=4$
+- $x \in y$
+- $\alpha \wedge \omega$
+- $223$
+- $p$-Tree
+- Here's some display math:
+ $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
+- Here's one that has a line break in it: $\alpha + \omega \times
+x^2$.
+
+These shouldn't be math:
+
+- To get the famous equation, write `$e = mc^2$`.
+- $22,000 is a *lot* of money. So is $34,000.
+ (It worked if "lot" is emphasized.)
+- Shoes ($20) and socks ($5).
+- Escaped `$`: $73 *this should be emphasized* 23\$.
+
+Here's a LaTeX table:
+
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+
+* * * * *
+
+# Special Characters
+
+Here is some unicode:
+
+- I hat: Î
+- o umlaut: ö
+- section: §
+- set membership: ∈
+- copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&amp;T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \\
+
+Backtick: \`
+
+Asterisk: \*
+
+Underscore: \_
+
+Left brace: \{
+
+Right brace: \}
+
+Left bracket: \[
+
+Right bracket: \]
+
+Left paren: \(
+
+Right paren: \)
+
+Greater-than: \>
+
+Hash: \#
+
+Period: \.
+
+Bang: \!
+
+Plus: \+
+
+Minus: \-
+
+- - - - - - - - - - - - -
+
+# Links
+
+## Explicit
+
+Just a [URL](/url/).
+
+[URL and title](/url/ "title").
+
+[URL and title](/url/ "title preceded by two spaces").
+
+[URL and title](/url/ "title preceded by a tab").
+
+[URL and title](/url/ "title with "quotes" in it")
+
+[URL and title](/url/ 'title with single quotes')
+
+[with\_underscore](/url/with_underscore)
+
+[Email link](mailto:nobody@nowhere.net)
+
+[Empty]().
+
+## Reference
+
+Foo [bar] [a].
+
+Foo [bar][a].
+
+Foo [bar]
+[a].
+
+[a]: /url/
+
+With [embedded [brackets]] [b].
+
+[b] by itself should be a link.
+
+Indented [once][].
+
+Indented [twice][].
+
+Indented [thrice][].
+
+This should [not][] be a link.
+
+ [once]: /url
+
+ [twice]: /url
+
+ [thrice]: /url
+
+ [not]: /url
+
+[b]: /url/
+
+Foo [bar][].
+
+Foo [biz](/url/ "Title with "quote" inside").
+
+ [bar]: /url/ "Title with "quotes" inside"
+
+## With ampersands
+
+Here's a [link with an ampersand in the URL] [1].
+
+Here's a link with an amersand in the link text: [AT&T] [2].
+
+Here's an [inline link](/script?foo=1&bar=2).
+
+Here's an [inline link in pointy braces](</script?foo=1&bar=2>).
+
+[1]: http://example.com/?foo=1&bar=2
+[2]: http://att.com/ "AT&T"
+
+## Autolinks
+
+With an ampersand: <http://example.com/?foo=1&bar=2>
+
+* In a list?
+* <http://example.com/>
+* It should.
+
+An e-mail address: <nobody@nowhere.net>
+
+> Blockquoted: <http://example.com/>
+
+Auto-links should not occur here: `<http://example.com/>`
+
+ or here: <http://example.com/>
+
+----
+
+# Images
+
+From "Voyage dans la Lune" by Georges Melies (1902):
+
+![lalune][]
+
+ [lalune]: lalune.jpg "Voyage dans la Lune"
+
+Here is a movie ![movie](movie.jpg) icon.
+
+----
+
+# Footnotes
+
+Here is a footnote reference,[^1] and another.[^longnote]
+This should *not* be a footnote reference, because it
+contains a space.[^my note] Here is an inline note.^[This
+is *easier* to type. Inline notes may contain
+[links](http://google.com) and `]` verbatim characters,
+as well as [bracketed text].]
+
+> Notes can go in quotes.^[In quote.]
+
+1. And in list items.^[In list.]
+
+[^longnote]: Here's the long note. This one contains multiple
+blocks.
+
+ Subsequent blocks are indented to show that they belong to the
+footnote (as with list items).
+
+ { <code> }
+
+ If you want, you can indent every line, but you can also be
+ lazy and just indent the first line of each block.
+
+This paragraph should not be part of the note, as it is not indented.
+
+[^1]: Here is the footnote. It can go anywhere after the footnote
+reference. It need not be placed at the end of the document.
diff --git a/tests/writer.context b/tests/writer.context
new file mode 100644
index 000000000..c5529a8df
--- /dev/null
+++ b/tests/writer.context
@@ -0,0 +1,884 @@
+\enableregime[utf] % use UTF-8
+
+\setupcolors[state=start]
+\setupinteraction[state=start, color=middleblue] % needed for hyperlinks
+
+\setuppapersize[letter][letter] % use letter paper
+\setuplayout[width=middle, backspace=1.5in, cutspace=1.5in,
+ height=middle, header=0.75in, footer=0.75in] % page layout
+\setuppagenumbering[location={footer,center}] % number pages
+\setupbodyfont[11pt] % 11pt font
+\setupwhitespace[medium] % inter-paragraph spacing
+
+\setuphead[section][style=\tfc]
+\setuphead[subsection][style=\tfb]
+\setuphead[subsubsection][style=\bf]
+
+% define title block commands
+\unprotect
+\def\doctitle#1{\gdef\@title{#1}}
+\def\author#1{\gdef\@author{#1}}
+\def\date#1{\gdef\@date{#1}}
+\date{\currentdate} % Default to today unless specified otherwise.
+\def\maketitle{%
+ \startalignment[center]
+ \blank[2*big]
+ {\tfd \@title}
+ \blank[3*medium]
+ {\tfa \@author}
+ \blank[2*medium]
+ {\tfa \@date}
+ \blank[3*medium]
+ \stopalignment}
+\protect
+
+% define descr (for definition lists)
+\definedescription[descr][
+ headstyle=bold,style=normal,align=left,location=hanging,
+ width=broad,margin=1cm]
+
+% prevent orphaned list intros
+\setupitemize[autointro]
+
+% define defaults for bulleted lists
+\setupitemize[1][symbol=1][indentnext=no]
+\setupitemize[2][symbol=2][indentnext=no]
+\setupitemize[3][symbol=3][indentnext=no]
+\setupitemize[4][symbol=4][indentnext=no]
+
+\setupthinrules[width=15em] % width of horizontal rules
+
+% for block quotations
+\unprotect
+
+\startvariables all
+blockquote: blockquote
+\stopvariables
+
+\definedelimitedtext
+[\v!blockquote][\v!quotation]
+
+\setupdelimitedtext
+[\v!blockquote]
+[\c!left=,
+\c!right=,
+before={\blank[medium]},
+after={\blank[medium]},
+]
+
+\protect
+
+
+\doctitle{Pandoc Test Suite}
+\author{John MacFarlane \& Anonymous}
+\date{July 17, 2006}
+\starttext
+\maketitle
+
+This is a set of tests for pandoc. Most of them are adapted from
+John Gruber's markdown test suite.
+
+\thinrule
+
+\subject{Headers}
+
+\subsubject{Level 2 with an \useURL[1][/url][][embedded link]\from[1]}
+
+\subsubsubject{Level 3 with {\em emphasis}}
+
+\subsubsubsubject{Level 4}
+
+\subsubsubsubsubject{Level 5}
+
+\subject{Level 1}
+
+\subsubject{Level 2 with {\em emphasis}}
+
+\subsubsubject{Level 3}
+
+with no blank line
+
+\subsubject{Level 2}
+
+with no blank line
+
+\thinrule
+
+\subject{Paragraphs}
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a
+list item. Because a hard-wrapped line in the middle of a paragraph
+looked like a list item.
+
+Here's one with a bullet. * criminey.
+
+There should be a hard line break\crlf
+here.
+
+\thinrule
+
+\subject{Block Quotes}
+
+E-mail style:
+
+\startblockquote
+This is a block quote. It is pretty short.
+\stopblockquote
+
+\startblockquote
+Code in a block quote:
+
+\starttyping
+sub status {
+ print "working";
+}
+\stoptyping
+
+A list:
+
+\startitemize[n][stopper=.]
+\item
+ item one
+\item
+ item two
+\stopitemize
+
+Nested block quotes:
+
+\startblockquote
+nested
+\stopblockquote
+
+\startblockquote
+nested
+\stopblockquote
+\stopblockquote
+
+This should not be a block quote: 2 \lettermore{} 1.
+
+And a following paragraph.
+
+\thinrule
+
+\subject{Code Blocks}
+
+Code:
+
+\starttyping
+---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+\stoptyping
+
+And:
+
+\starttyping
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+\stoptyping
+
+\thinrule
+
+\subject{Lists}
+
+\subsubject{Unordered}
+
+Asterisks tight:
+
+\startitemize
+\item
+ asterisk 1
+\item
+ asterisk 2
+\item
+ asterisk 3
+\stopitemize
+
+Asterisks loose:
+
+\startitemize
+\item
+ asterisk 1
+\item
+ asterisk 2
+\item
+ asterisk 3
+\stopitemize
+
+Pluses tight:
+
+\startitemize
+\item
+ Plus 1
+\item
+ Plus 2
+\item
+ Plus 3
+\stopitemize
+
+Pluses loose:
+
+\startitemize
+\item
+ Plus 1
+\item
+ Plus 2
+\item
+ Plus 3
+\stopitemize
+
+Minuses tight:
+
+\startitemize
+\item
+ Minus 1
+\item
+ Minus 2
+\item
+ Minus 3
+\stopitemize
+
+Minuses loose:
+
+\startitemize
+\item
+ Minus 1
+\item
+ Minus 2
+\item
+ Minus 3
+\stopitemize
+
+\subsubject{Ordered}
+
+Tight:
+
+\startitemize[n][stopper=.]
+\item
+ First
+\item
+ Second
+\item
+ Third
+\stopitemize
+
+and:
+
+\startitemize[n][stopper=.]
+\item
+ One
+\item
+ Two
+\item
+ Three
+\stopitemize
+
+Loose using tabs:
+
+\startitemize[n][stopper=.]
+\item
+ First
+\item
+ Second
+\item
+ Third
+\stopitemize
+
+and using spaces:
+
+\startitemize[n][stopper=.]
+\item
+ One
+\item
+ Two
+\item
+ Three
+\stopitemize
+
+Multiple paragraphs:
+
+\startitemize[n][stopper=.]
+\item
+ Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's
+ back.
+\item
+ Item 2.
+\item
+ Item 3.
+\stopitemize
+
+\subsubject{Nested}
+
+\startitemize
+\item
+ Tab
+ \startitemize
+ \item
+ Tab
+ \startitemize
+ \item
+ Tab
+ \stopitemize
+ \stopitemize
+\stopitemize
+
+Here's another:
+
+\startitemize[n][stopper=.]
+\item
+ First
+\item
+ Second:
+ \startitemize
+ \item
+ Fee
+ \item
+ Fie
+ \item
+ Foe
+ \stopitemize
+\item
+ Third
+\stopitemize
+
+Same thing but with paragraphs:
+
+\startitemize[n][stopper=.]
+\item
+ First
+\item
+ Second:
+
+ \startitemize
+ \item
+ Fee
+ \item
+ Fie
+ \item
+ Foe
+ \stopitemize
+\item
+ Third
+\stopitemize
+
+\subsubject{Tabs and spaces}
+
+\startitemize
+\item
+ this is a list item indented with tabs
+\item
+ this is a list item indented with spaces
+
+ \startitemize
+ \item
+ this is an example list item indented with tabs
+ \item
+ this is an example list item indented with spaces
+ \stopitemize
+\stopitemize
+
+\subsubject{Fancy list markers}
+
+\startitemize[n][start=2,left=(,stopper=),width=2.0em]
+\item
+ begins with 2
+\item
+ and now 3
+
+ with a continuation
+
+ \startitemize[r][start=4,stopper=.,width=2.0em]
+ \item
+ sublist with roman numerals, starting with 4
+ \item
+ more items
+ \startitemize[A][left=(,stopper=),width=2.0em]
+ \item
+ a subsublist
+ \item
+ a subsublist
+ \stopitemize
+ \stopitemize
+\stopitemize
+
+Nesting:
+
+\startitemize[A][stopper=.]
+\item
+ Upper Alpha
+ \startitemize[R][stopper=.]
+ \item
+ Upper Roman.
+ \startitemize[n][start=6,left=(,stopper=),width=2.0em]
+ \item
+ Decimal start with 6
+ \startitemize[a][start=3,stopper=)]
+ \item
+ Lower alpha with paren
+ \stopitemize
+ \stopitemize
+ \stopitemize
+\stopitemize
+
+Autonumbering:
+
+\startitemize[n]
+\item
+ Autonumber.
+\item
+ More.
+ \startitemize[a]
+ \item
+ Nested.
+ \stopitemize
+\stopitemize
+
+Should not be a list item:
+
+M.A.~2007
+
+B. Williams
+
+\thinrule
+
+\subject{Definition Lists}
+
+Tight using spaces:
+
+\startdescr{apple}
+red fruit
+\stopdescr
+
+\startdescr{orange}
+orange fruit
+\stopdescr
+
+\startdescr{banana}
+yellow fruit
+\stopdescr
+
+Tight using tabs:
+
+\startdescr{apple}
+red fruit
+\stopdescr
+
+\startdescr{orange}
+orange fruit
+\stopdescr
+
+\startdescr{banana}
+yellow fruit
+\stopdescr
+
+Loose:
+
+\startdescr{apple}
+red fruit
+\stopdescr
+
+\startdescr{orange}
+orange fruit
+\stopdescr
+
+\startdescr{banana}
+yellow fruit
+\stopdescr
+
+Multiple blocks with italics:
+
+\startdescr{{\em apple}}
+red fruit
+
+contains seeds, crisp, pleasant to taste
+\stopdescr
+
+\startdescr{{\em orange}}
+orange fruit
+
+\starttyping
+{ orange code block }
+\stoptyping
+
+\startblockquote
+orange block quote
+\stopblockquote
+\stopdescr
+
+\subject{HTML Blocks}
+
+Simple block on one line:
+
+foo
+And nested without indentation:
+
+foo
+bar
+Interpreted markdown in a table:
+
+This is {\em emphasized}
+And this is {\bf strong}
+Here's a simple block:
+
+foo
+This should be a code block, though:
+
+\starttyping
+<div>
+ foo
+</div>
+\stoptyping
+
+As should this:
+
+\starttyping
+<div>foo</div>
+\stoptyping
+
+Now, nested:
+
+foo
+This should just be an HTML comment:
+
+Multiline:
+
+Code block:
+
+\starttyping
+<!-- Comment -->
+\stoptyping
+
+Just plain comment, with trailing spaces on the line:
+
+Code:
+
+\starttyping
+<hr />
+\stoptyping
+
+Hr's:
+
+\thinrule
+
+\subject{Inline Markup}
+
+This is {\em emphasized}, and so {\em is this}.
+
+This is {\bf strong}, and so {\bf is this}.
+
+An {\em \useURL[2][/url][][emphasized link]\from[2]}.
+
+{\bf {\em This is strong and em.}}
+
+So is {\bf {\em this}} word.
+
+{\bf {\em This is strong and em.}}
+
+So is {\bf {\em this}} word.
+
+This is code: \type{>}, \type{$}, \type{\}, \type{\$},
+\type{<html>}.
+
+\overstrikes{This is {\em strikeout}.}
+
+Superscripts: a\high{bc}d a\high{{\em hello}} a\high{hello~there}.
+
+Subscripts: H\low{2}O, H\low{23}O, H\low{many~of~them}O.
+
+These should not be superscripts or subscripts, because of the
+unescaped spaces: a\letterhat{}b c\letterhat{}d, a\lettertilde{}b
+c\lettertilde{}d.
+
+\thinrule
+
+\subject{Smart quotes, ellipses, dashes}
+
+\quotation{Hello,} said the spider.
+\quotation{\quote{Shelob} is my name.}
+
+\quote{A}, \quote{B}, and \quote{C} are letters.
+
+\quote{Oak,} \quote{elm,} and \quote{beech} are names of trees. So
+is \quote{pine.}
+
+\quote{He said, \quotation{I want to go.}} Were you alive in the
+70's?
+
+Here is some quoted \quote{\type{code}} and a
+\quotation{\useURL[3][http://example.com/?foo=1&bar=2][][quoted link]\from[3]}.
+
+Some dashes: one---two --- three---four --- five.
+
+Dashes between numbers: 5--7, 255--66, 1987--1999.
+
+Ellipses\ldots{}and\ldots{}and\ldots{}.
+
+\thinrule
+
+\subject{LaTeX}
+
+\startitemize
+\item
+ \cite[22-23]{smith.1899}
+\item
+ $2+2=4$
+\item
+ $x \in y$
+\item
+ $\alpha \wedge \omega$
+\item
+ $223$
+\item
+ $p$-Tree
+\item
+ Here's some display math:
+ \startformula \frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h} \stopformula
+\item
+ Here's one that has a line break in it:
+ $\alpha + \omega \times x^2$.
+\stopitemize
+
+These shouldn't be math:
+
+\startitemize
+\item
+ To get the famous equation, write \type{$e = mc^2$}.
+\item
+ \$22,000 is a {\em lot} of money. So is \$34,000. (It worked if
+ \quotation{lot} is emphasized.)
+\item
+ Shoes (\$20) and socks (\$5).
+\item
+ Escaped \type{$}: \$73 {\em this should be emphasized} 23\$.
+\stopitemize
+
+Here's a LaTeX table:
+
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+
+\thinrule
+
+\subject{Special Characters}
+
+Here is some unicode:
+
+\startitemize
+\item
+ I hat: Î
+\item
+ o umlaut: ö
+\item
+ section: §
+\item
+ set membership: ∈
+\item
+ copyright: ©
+\stopitemize
+
+AT\&T has an ampersand in their name.
+
+AT\&T is another way to write it.
+
+This \& that.
+
+4 \letterless{} 5.
+
+6 \lettermore{} 5.
+
+Backslash: \letterbackslash{}
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: \letterunderscore{}
+
+Left brace: \letteropenbrace{}
+
+Right brace: \letterclosebrace{}
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: \lettermore{}
+
+Hash: \#
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+\thinrule
+
+\subject{Links}
+
+\subsubject{Explicit}
+
+Just a \useURL[4][/url/][][URL]\from[4].
+
+\useURL[5][/url/][][URL and title]\from[5].
+
+\useURL[6][/url/][][URL and title]\from[6].
+
+\useURL[7][/url/][][URL and title]\from[7].
+
+\useURL[8][/url/][][URL and title]\from[8]
+
+\useURL[9][/url/][][URL and title]\from[9]
+
+\useURL[10][/url/with_underscore][][with\letterunderscore{}underscore]\from[10]
+
+\useURL[11][mailto:nobody@nowhere.net][][Email link]\from[11]
+
+\useURL[12][][][Empty]\from[12].
+
+\subsubject{Reference}
+
+Foo \useURL[13][/url/][][bar]\from[13].
+
+Foo \useURL[14][/url/][][bar]\from[14].
+
+Foo \useURL[15][/url/][][bar]\from[15].
+
+With \useURL[16][/url/][][embedded [brackets]]\from[16].
+
+\useURL[17][/url/][][b]\from[17] by itself should be a link.
+
+Indented \useURL[18][/url][][once]\from[18].
+
+Indented \useURL[19][/url][][twice]\from[19].
+
+Indented \useURL[20][/url][][thrice]\from[20].
+
+This should [not][] be a link.
+
+\starttyping
+[not]: /url
+\stoptyping
+
+Foo \useURL[21][/url/][][bar]\from[21].
+
+Foo \useURL[22][/url/][][biz]\from[22].
+
+\subsubject{With ampersands}
+
+Here's a
+\useURL[23][http://example.com/?foo=1&bar=2][][link with an ampersand in the URL]\from[23].
+
+Here's a link with an amersand in the link text:
+\useURL[24][http://att.com/][][AT\&T]\from[24].
+
+Here's an \useURL[25][/script?foo=1&bar=2][][inline link]\from[25].
+
+Here's an
+\useURL[26][/script?foo=1&bar=2][][inline link in pointy braces]\from[26].
+
+\subsubject{Autolinks}
+
+With an ampersand:
+\useURL[27][http://example.com/?foo=1&bar=2][][http://example.com/?foo=1\&bar=2]\from[27]
+
+\startitemize
+\item
+ In a list?
+\item
+ \useURL[28][http://example.com/][][http://example.com/]\from[28]
+\item
+ It should.
+\stopitemize
+
+An e-mail address:
+\useURL[29][mailto:nobody@nowhere.net][][nobody@nowhere.net]\from[29]
+
+\startblockquote
+Blockquoted:
+\useURL[30][http://example.com/][][http://example.com/]\from[30]
+\stopblockquote
+
+Auto-links should not occur here: \type{<http://example.com/>}
+
+\starttyping
+or here: <http://example.com/>
+\stoptyping
+
+\thinrule
+
+\subject{Images}
+
+From \quotation{Voyage dans la Lune} by Georges Melies (1902):
+
+\placefigure
+[]
+[fig:lalune]
+{Voyage dans la Lune}
+{\externalfigure[lalune.jpg]}
+
+Here is a movie
+\placefigure
+[]
+[fig:movie]
+{}
+{\externalfigure[movie.jpg]} icon.
+
+\thinrule
+
+\subject{Footnotes}
+
+Here is a footnote reference,
+\footnote{Here is the footnote. It can go anywhere after the footnote
+reference. It need not be placed at the end of the document.}
+and another.
+\footnote{Here's the long note. This one contains multiple blocks.
+
+Subsequent blocks are indented to show that they belong to the
+footnote (as with list items).
+
+\starttyping
+ { <code> }
+\stoptyping
+
+If you want, you can indent every line, but you can also be lazy
+and just indent the first line of each block.}
+This should {\em not} be a footnote reference, because it contains
+a space.[\letterhat{}my note] Here is an inline note.
+\footnote{This is {\em easier} to type. Inline notes may contain
+\useURL[31][http://google.com][][links]\from[31] and \type{]}
+verbatim characters, as well as [bracketed text].}
+
+\startblockquote
+Notes can go in quotes.
+\footnote{In quote.}
+\stopblockquote
+
+\startitemize[n][stopper=.]
+\item
+ And in list items.
+ \footnote{In list.}
+\stopitemize
+
+This paragraph should not be part of the note, as it is not
+indented.
+\stoptext
+
diff --git a/tests/writer.docbook b/tests/writer.docbook
new file mode 100644
index 000000000..2371a2e1b
--- /dev/null
+++ b/tests/writer.docbook
@@ -0,0 +1,1368 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+ "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
+
+<article>
+ <articleinfo>
+ <title>Pandoc Test Suite</title>
+ <author>
+ <firstname>John</firstname>
+ <surname>MacFarlane</surname>
+ </author>
+ <author>
+ <firstname></firstname>
+ <surname>Anonymous</surname>
+ </author>
+ <date>July 17, 2006</date>
+ </articleinfo>
+ <para>
+ This is a set of tests for pandoc. Most of them are adapted from
+ John Gruber's markdown test suite.
+ </para>
+ <section>
+ <title>Headers</title>
+ <section>
+ <title>Level 2 with an
+ <ulink url="/url">embedded link</ulink></title>
+ <section>
+ <title>Level 3 with <emphasis>emphasis</emphasis></title>
+ <section>
+ <title>Level 4</title>
+ <section>
+ <title>Level 5</title>
+ <para>
+ </para>
+ </section>
+ </section>
+ </section>
+ </section>
+ </section>
+ <section>
+ <title>Level 1</title>
+ <section>
+ <title>Level 2 with <emphasis>emphasis</emphasis></title>
+ <section>
+ <title>Level 3</title>
+ <para>
+ with no blank line
+ </para>
+ </section>
+ </section>
+ <section>
+ <title>Level 2</title>
+ <para>
+ with no blank line
+ </para>
+ </section>
+ </section>
+ <section>
+ <title>Paragraphs</title>
+ <para>
+ Here's a regular paragraph.
+ </para>
+ <para>
+ In Markdown 1.0.0 and earlier. Version 8. This line turns into a
+ list item. Because a hard-wrapped line in the middle of a paragraph
+ looked like a list item.
+ </para>
+ <para>
+ Here's one with a bullet. * criminey.
+ </para>
+ <para>
+ There should be a hard line
+ break<literallayout></literallayout>here.
+ </para>
+ </section>
+ <section>
+ <title>Block Quotes</title>
+ <para>
+ E-mail style:
+ </para>
+ <blockquote>
+ <para>
+ This is a block quote. It is pretty short.
+ </para>
+ </blockquote>
+ <blockquote>
+ <para>
+ Code in a block quote:
+ </para>
+ <screen>
+sub status {
+ print &quot;working&quot;;
+}
+</screen>
+ <para>
+ A list:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ item one
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ item two
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Nested block quotes:
+ </para>
+ <blockquote>
+ <para>
+ nested
+ </para>
+ </blockquote>
+ <blockquote>
+ <para>
+ nested
+ </para>
+ </blockquote>
+ </blockquote>
+ <para>
+ This should not be a block quote: 2 &gt; 1.
+ </para>
+ <para>
+ And a following paragraph.
+ </para>
+ </section>
+ <section>
+ <title>Code Blocks</title>
+ <para>
+ Code:
+ </para>
+ <screen>
+---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab
+</screen>
+ <para>
+ And:
+ </para>
+ <screen>
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{
+</screen>
+ </section>
+ <section>
+ <title>Lists</title>
+ <section>
+ <title>Unordered</title>
+ <para>
+ Asterisks tight:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ asterisk 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ asterisk 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ asterisk 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Asterisks loose:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ asterisk 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ asterisk 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ asterisk 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Pluses tight:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Plus 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plus 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plus 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Pluses loose:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Plus 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plus 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plus 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Minuses tight:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Minus 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Minus 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Minus 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Minuses loose:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Minus 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Minus 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Minus 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section>
+ <title>Ordered</title>
+ <para>
+ Tight:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ First
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Second
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Third
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ and:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ One
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Two
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Three
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Loose using tabs:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ First
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Second
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Third
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ and using spaces:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ One
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Two
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Three
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Multiple paragraphs:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ Item 1, graf one.
+ </para>
+ <para>
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's
+ back.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Item 2.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Item 3.
+ </para>
+ </listitem>
+ </orderedlist>
+ </section>
+ <section>
+ <title>Nested</title>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Tab
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Tab
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Tab
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Here's another:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ First
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Second:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Fee
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Fie
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Foe
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>
+ Third
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Same thing but with paragraphs:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ First
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Second:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Fee
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Fie
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Foe
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>
+ Third
+ </para>
+ </listitem>
+ </orderedlist>
+ </section>
+ <section>
+ <title>Tabs and spaces</title>
+ <itemizedlist>
+ <listitem>
+ <para>
+ this is a list item indented with tabs
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ this is a list item indented with spaces
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ this is an example list item indented with tabs
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ this is an example list item indented with spaces
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section>
+ <title>Fancy list markers</title>
+ <orderedlist numeration="arabic">
+ <listitem override="2">
+ <para>
+ begins with 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ and now 3
+ </para>
+ <para>
+ with a continuation
+ </para>
+ <orderedlist numeration="lowerroman">
+ <listitem override="4">
+ <para>
+ sublist with roman numerals, starting with 4
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ more items
+ </para>
+ <orderedlist numeration="upperalpha">
+ <listitem>
+ <para>
+ a subsublist
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ a subsublist
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ <para>
+ Nesting:
+ </para>
+ <orderedlist numeration="upperalpha">
+ <listitem>
+ <para>
+ Upper Alpha
+ </para>
+ <orderedlist numeration="upperroman">
+ <listitem>
+ <para>
+ Upper Roman.
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem override="6">
+ <para>
+ Decimal start with 6
+ </para>
+ <orderedlist numeration="loweralpha">
+ <listitem override="3">
+ <para>
+ Lower alpha with paren
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ <para>
+ Autonumbering:
+ </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ Autonumber.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ More.
+ </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ Nested.
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ <para>
+ Should not be a list item:
+ </para>
+ <para>
+ M.A.&#160;2007
+ </para>
+ <para>
+ B. Williams
+ </para>
+ </section>
+ </section>
+ <section>
+ <title>Definition Lists</title>
+ <para>
+ Tight using spaces:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ banana
+ </term>
+ <listitem>
+ <para>
+ yellow fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Tight using tabs:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ banana
+ </term>
+ <listitem>
+ <para>
+ yellow fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Loose:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ banana
+ </term>
+ <listitem>
+ <para>
+ yellow fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Multiple blocks with italics:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <emphasis>apple</emphasis>
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ <para>
+ contains seeds, crisp, pleasant to taste
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <emphasis>orange</emphasis>
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ <screen>
+{ orange code block }
+</screen>
+ <blockquote>
+ <para>
+ orange block quote
+ </para>
+ </blockquote>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section>
+ <title>HTML Blocks</title>
+ <para>
+ Simple block on one line:
+ </para>
+ <div>
+ foo
+ </div>
+
+ <para>
+ And nested without indentation:
+ </para>
+ <div>
+<div>
+<div>
+ foo
+ </div>
+</div>
+<div>
+ bar
+ </div>
+</div>
+
+ <para>
+ Interpreted markdown in a table:
+ </para>
+ <table>
+<tr>
+<td>
+ This is <emphasis>emphasized</emphasis>
+ </td>
+<td>
+ And this is <emphasis role="strong">strong</emphasis>
+ </td>
+</tr>
+</table>
+
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+
+ <para>
+ Here's a simple block:
+ </para>
+ <div>
+
+ foo
+ </div>
+
+ <para>
+ This should be a code block, though:
+ </para>
+ <screen>
+&lt;div&gt;
+ foo
+&lt;/div&gt;
+</screen>
+ <para>
+ As should this:
+ </para>
+ <screen>
+&lt;div&gt;foo&lt;/div&gt;
+</screen>
+ <para>
+ Now, nested:
+ </para>
+ <div>
+ <div>
+ <div>
+
+ foo
+ </div>
+ </div>
+</div>
+
+ <para>
+ This should just be an HTML comment:
+ </para>
+ <!-- Comment -->
+
+ <para>
+ Multiline:
+ </para>
+ <!--
+Blah
+Blah
+-->
+
+<!--
+ This is another comment.
+-->
+
+ <para>
+ Code block:
+ </para>
+ <screen>
+&lt;!-- Comment --&gt;
+</screen>
+ <para>
+ Just plain comment, with trailing spaces on the line:
+ </para>
+ <!-- foo -->
+
+ <para>
+ Code:
+ </para>
+ <screen>
+&lt;hr /&gt;
+</screen>
+ <para>
+ Hr's:
+ </para>
+ <hr>
+
+<hr />
+
+<hr />
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar">
+
+ </section>
+ <section>
+ <title>Inline Markup</title>
+ <para>
+ This is <emphasis>emphasized</emphasis>, and so
+ <emphasis>is this</emphasis>.
+ </para>
+ <para>
+ This is <emphasis role="strong">strong</emphasis>, and so
+ <emphasis role="strong">is this</emphasis>.
+ </para>
+ <para>
+ An <emphasis><ulink url="/url">emphasized link</ulink></emphasis>.
+ </para>
+ <para>
+ <emphasis role="strong"><emphasis>This is strong and em.</emphasis></emphasis>
+ </para>
+ <para>
+ So is <emphasis role="strong"><emphasis>this</emphasis></emphasis>
+ word.
+ </para>
+ <para>
+ <emphasis role="strong"><emphasis>This is strong and em.</emphasis></emphasis>
+ </para>
+ <para>
+ So is <emphasis role="strong"><emphasis>this</emphasis></emphasis>
+ word.
+ </para>
+ <para>
+ This is code: <literal>&gt;</literal>, <literal>$</literal>,
+ <literal>\</literal>, <literal>\$</literal>,
+ <literal>&lt;html&gt;</literal>.
+ </para>
+ <para>
+ <emphasis role="strikethrough">This is <emphasis>strikeout</emphasis>.</emphasis>
+ </para>
+ <para>
+ Superscripts: a<superscript>bc</superscript>d
+ a<superscript><emphasis>hello</emphasis></superscript>
+ a<superscript>hello&#160;there</superscript>.
+ </para>
+ <para>
+ Subscripts: H<subscript>2</subscript>O,
+ H<subscript>23</subscript>O,
+ H<subscript>many&#160;of&#160;them</subscript>O.
+ </para>
+ <para>
+ These should not be superscripts or subscripts, because of the
+ unescaped spaces: a^b c^d, a~b c~d.
+ </para>
+ </section>
+ <section>
+ <title>Smart quotes, ellipses, dashes</title>
+ <para>
+ <quote>Hello,</quote> said the spider.
+ <quote><quote>Shelob</quote> is my name.</quote>
+ </para>
+ <para>
+ <quote>A</quote>, <quote>B</quote>, and <quote>C</quote> are
+ letters.
+ </para>
+ <para>
+ <quote>Oak,</quote> <quote>elm,</quote> and <quote>beech</quote>
+ are names of trees. So is <quote>pine.</quote>
+ </para>
+ <para>
+ <quote>He said, <quote>I want to go.</quote></quote> Were you alive
+ in the 70's?
+ </para>
+ <para>
+ Here is some quoted <quote><literal>code</literal></quote> and a
+ <quote><ulink url="http://example.com/?foo=1&amp;bar=2">quoted link</ulink></quote>.
+ </para>
+ <para>
+ Some dashes: one&#8212;two &#8212; three&#8212;four &#8212; five.
+ </para>
+ <para>
+ Dashes between numbers: 5&#8211;7, 255&#8211;66, 1987&#8211;1999.
+ </para>
+ <para>
+ Ellipses&#8230;and&#8230;and&#8230;.
+ </para>
+ </section>
+ <section>
+ <title>LaTeX</title>
+ <itemizedlist>
+ <listitem>
+ <para>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 2+2=4
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>x</emphasis> ∈ <emphasis>y</emphasis>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ α ∧ ω
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 223
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>p</emphasis>-Tree
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Here's some display math:
+ \frac{<emphasis>d</emphasis>}{<emphasis>dx</emphasis>}<emphasis>f</emphasis>(<emphasis>x</emphasis>)=\lim<subscript><emphasis>h</emphasis> → 0</subscript>\frac{<emphasis>f</emphasis>(<emphasis>x</emphasis>+<emphasis>h</emphasis>)-<emphasis>f</emphasis>(<emphasis>x</emphasis>)}{<emphasis>h</emphasis>}
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Here's one that has a line break in it:
+ α+ω × <emphasis>x</emphasis><superscript>2</superscript>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ These shouldn't be math:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ To get the famous equation, write <literal>$e = mc^2$</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ $22,000 is a <emphasis>lot</emphasis> of money. So is $34,000. (It
+ worked if <quote>lot</quote> is emphasized.)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Shoes ($20) and socks ($5).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Escaped <literal>$</literal>: $73
+ <emphasis>this should be emphasized</emphasis> 23$.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Here's a LaTeX table:
+ </para>
+ <para>
+ </para>
+ </section>
+ <section>
+ <title>Special Characters</title>
+ <para>
+ Here is some unicode:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ I hat: Î
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ o umlaut: ö
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ section: §
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ set membership: ∈
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ copyright: ©
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ AT&amp;T has an ampersand in their name.
+ </para>
+ <para>
+ AT&amp;T is another way to write it.
+ </para>
+ <para>
+ This &amp; that.
+ </para>
+ <para>
+ 4 &lt; 5.
+ </para>
+ <para>
+ 6 &gt; 5.
+ </para>
+ <para>
+ Backslash: \
+ </para>
+ <para>
+ Backtick: `
+ </para>
+ <para>
+ Asterisk: *
+ </para>
+ <para>
+ Underscore: _
+ </para>
+ <para>
+ Left brace: {
+ </para>
+ <para>
+ Right brace: }
+ </para>
+ <para>
+ Left bracket: [
+ </para>
+ <para>
+ Right bracket: ]
+ </para>
+ <para>
+ Left paren: (
+ </para>
+ <para>
+ Right paren: )
+ </para>
+ <para>
+ Greater-than: &gt;
+ </para>
+ <para>
+ Hash: #
+ </para>
+ <para>
+ Period: .
+ </para>
+ <para>
+ Bang: !
+ </para>
+ <para>
+ Plus: +
+ </para>
+ <para>
+ Minus: -
+ </para>
+ </section>
+ <section>
+ <title>Links</title>
+ <section>
+ <title>Explicit</title>
+ <para>
+ Just a <ulink url="/url/">URL</ulink>.
+ </para>
+ <para>
+ <ulink url="/url/">URL and title</ulink>.
+ </para>
+ <para>
+ <ulink url="/url/">URL and title</ulink>.
+ </para>
+ <para>
+ <ulink url="/url/">URL and title</ulink>.
+ </para>
+ <para>
+ <ulink url="/url/">URL and title</ulink>
+ </para>
+ <para>
+ <ulink url="/url/">URL and title</ulink>
+ </para>
+ <para>
+ <ulink url="/url/with_underscore">with_underscore</ulink>
+ </para>
+ <para>
+ Email link (<email>nobody@nowhere.net</email>)
+ </para>
+ <para>
+ <ulink url="">Empty</ulink>.
+ </para>
+ </section>
+ <section>
+ <title>Reference</title>
+ <para>
+ Foo <ulink url="/url/">bar</ulink>.
+ </para>
+ <para>
+ Foo <ulink url="/url/">bar</ulink>.
+ </para>
+ <para>
+ Foo <ulink url="/url/">bar</ulink>.
+ </para>
+ <para>
+ With <ulink url="/url/">embedded [brackets]</ulink>.
+ </para>
+ <para>
+ <ulink url="/url/">b</ulink> by itself should be a link.
+ </para>
+ <para>
+ Indented <ulink url="/url">once</ulink>.
+ </para>
+ <para>
+ Indented <ulink url="/url">twice</ulink>.
+ </para>
+ <para>
+ Indented <ulink url="/url">thrice</ulink>.
+ </para>
+ <para>
+ This should [not][] be a link.
+ </para>
+ <screen>
+[not]: /url
+</screen>
+ <para>
+ Foo <ulink url="/url/">bar</ulink>.
+ </para>
+ <para>
+ Foo <ulink url="/url/">biz</ulink>.
+ </para>
+ </section>
+ <section>
+ <title>With ampersands</title>
+ <para>
+ Here's a
+ <ulink url="http://example.com/?foo=1&amp;bar=2">link with an ampersand in the URL</ulink>.
+ </para>
+ <para>
+ Here's a link with an amersand in the link text:
+ <ulink url="http://att.com/">AT&amp;T</ulink>.
+ </para>
+ <para>
+ Here's an <ulink url="/script?foo=1&amp;bar=2">inline link</ulink>.
+ </para>
+ <para>
+ Here's an
+ <ulink url="/script?foo=1&amp;bar=2">inline link in pointy braces</ulink>.
+ </para>
+ </section>
+ <section>
+ <title>Autolinks</title>
+ <para>
+ With an ampersand:
+ <ulink url="http://example.com/?foo=1&amp;bar=2"><literal>http://example.com/?foo=1&amp;bar=2</literal></ulink>
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ In a list?
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="http://example.com/"><literal>http://example.com/</literal></ulink>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ It should.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ An e-mail address: <email>nobody@nowhere.net</email>
+ </para>
+ <blockquote>
+ <para>
+ Blockquoted:
+ <ulink url="http://example.com/"><literal>http://example.com/</literal></ulink>
+ </para>
+ </blockquote>
+ <para>
+ Auto-links should not occur here:
+ <literal>&lt;http://example.com/&gt;</literal>
+ </para>
+ <screen>
+or here: &lt;http://example.com/&gt;
+</screen>
+ </section>
+ </section>
+ <section>
+ <title>Images</title>
+ <para>
+ From <quote>Voyage dans la Lune</quote> by Georges Melies (1902):
+ </para>
+ <para>
+ <inlinemediaobject>
+ <imageobject>
+ <objectinfo>
+ <title>
+ Voyage dans la Lune
+ </title>
+ </objectinfo>
+ <imagedata fileref="lalune.jpg" />
+ </imageobject>
+ </inlinemediaobject>
+ </para>
+ <para>
+ Here is a movie
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="movie.jpg" />
+ </imageobject>
+ </inlinemediaobject>
+ icon.
+ </para>
+ </section>
+ <section>
+ <title>Footnotes</title>
+ <para>
+ Here is a footnote
+ reference,<footnote>
+ <para>
+ Here is the footnote. It can go anywhere after the footnote
+ reference. It need not be placed at the end of the document.
+ </para>
+ </footnote>
+ and
+ another.<footnote>
+ <para>
+ Here's the long note. This one contains multiple blocks.
+ </para>
+ <para>
+ Subsequent blocks are indented to show that they belong to the
+ footnote (as with list items).
+ </para>
+ <screen>
+ { &lt;code&gt; }
+</screen>
+ <para>
+ If you want, you can indent every line, but you can also be lazy
+ and just indent the first line of each block.
+ </para>
+ </footnote>
+ This should <emphasis>not</emphasis> be a footnote reference,
+ because it contains a space.[^my note] Here is an inline
+ note.<footnote>
+ <para>
+ This is <emphasis>easier</emphasis> to type. Inline notes may
+ contain <ulink url="http://google.com">links</ulink> and
+ <literal>]</literal> verbatim characters, as well as [bracketed
+ text].
+ </para>
+ </footnote>
+ </para>
+ <blockquote>
+ <para>
+ Notes can go in
+ quotes.<footnote>
+ <para>
+ In quote.
+ </para>
+ </footnote>
+ </para>
+ </blockquote>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ And in list
+ items.<footnote>
+ <para>
+ In list.
+ </para>
+ </footnote>
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ This paragraph should not be part of the note, as it is not
+ indented.
+ </para>
+ </section>
+</article>
+
diff --git a/tests/writer.html b/tests/writer.html
new file mode 100644
index 000000000..ece782f81
--- /dev/null
+++ b/tests/writer.html
@@ -0,0 +1,1184 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+><head
+ ><title
+ >Pandoc Test Suite</title
+ ><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
+ /><meta name="generator" content="pandoc"
+ /><meta name="author" content="John MacFarlane"
+ /><meta name="author" content="Anonymous"
+ /><meta name="date" content="July 17, 2006"
+ /></head
+ ><body
+ ><h1 class="title"
+ >Pandoc Test Suite</h1
+ ><p
+ >This is a set of tests for pandoc. Most of them are adapted from John Gruber&rsquo;s markdown test suite.</p
+ ><hr
+ /><div id="headers"
+ ><h1
+ >Headers</h1
+ ><div id="level-2-with-an-embedded-link"
+ ><h2
+ >Level 2 with an <a href="/url"
+ >embedded link</a
+ ></h2
+ ><div id="level-3-with-emphasis"
+ ><h3
+ >Level 3 with <em
+ >emphasis</em
+ ></h3
+ ><div id="level-4"
+ ><h4
+ >Level 4</h4
+ ><div id="level-5"
+ ><h5
+ >Level 5</h5
+ ></div
+ ></div
+ ></div
+ ></div
+ ></div
+ ><div id="level-1"
+ ><h1
+ >Level 1</h1
+ ><div id="level-2-with-emphasis"
+ ><h2
+ >Level 2 with <em
+ >emphasis</em
+ ></h2
+ ><div id="level-3"
+ ><h3
+ >Level 3</h3
+ ><p
+ >with no blank line</p
+ ></div
+ ></div
+ ><div id="level-2"
+ ><h2
+ >Level 2</h2
+ ><p
+ >with no blank line</p
+ ><hr
+ /></div
+ ></div
+ ><div id="paragraphs"
+ ><h1
+ >Paragraphs</h1
+ ><p
+ >Here&rsquo;s a regular paragraph.</p
+ ><p
+ >In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.</p
+ ><p
+ >Here&rsquo;s one with a bullet. * criminey.</p
+ ><p
+ >There should be a hard line break<br
+ />here.</p
+ ><hr
+ /></div
+ ><div id="block-quotes"
+ ><h1
+ >Block Quotes</h1
+ ><p
+ >E-mail style:</p
+ ><blockquote
+ ><p
+ >This is a block quote. It is pretty short.</p
+ ></blockquote
+ ><blockquote
+ ><p
+ >Code in a block quote:</p
+ ><pre
+ ><code
+ >sub status {
+ print &quot;working&quot;;
+}
+</code
+ ></pre
+ ><p
+ >A list:</p
+ ><ol style="list-style-type: decimal;"
+ ><li
+ >item one</li
+ ><li
+ >item two</li
+ ></ol
+ ><p
+ >Nested block quotes:</p
+ ><blockquote
+ ><p
+ >nested</p
+ ></blockquote
+ ><blockquote
+ ><p
+ >nested</p
+ ></blockquote
+ ></blockquote
+ ><p
+ >This should not be a block quote: 2 &gt; 1.</p
+ ><p
+ >And a following paragraph.</p
+ ><hr
+ /></div
+ ><div id="code-blocks"
+ ><h1
+ >Code Blocks</h1
+ ><p
+ >Code:</p
+ ><pre
+ ><code
+ >---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab
+</code
+ ></pre
+ ><p
+ >And:</p
+ ><pre
+ ><code
+ > this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{
+</code
+ ></pre
+ ><hr
+ /></div
+ ><div id="lists"
+ ><h1
+ >Lists</h1
+ ><div id="unordered"
+ ><h2
+ >Unordered</h2
+ ><p
+ >Asterisks tight:</p
+ ><ul
+ ><li
+ >asterisk 1</li
+ ><li
+ >asterisk 2</li
+ ><li
+ >asterisk 3</li
+ ></ul
+ ><p
+ >Asterisks loose:</p
+ ><ul
+ ><li
+ ><p
+ >asterisk 1</p
+ ></li
+ ><li
+ ><p
+ >asterisk 2</p
+ ></li
+ ><li
+ ><p
+ >asterisk 3</p
+ ></li
+ ></ul
+ ><p
+ >Pluses tight:</p
+ ><ul
+ ><li
+ >Plus 1</li
+ ><li
+ >Plus 2</li
+ ><li
+ >Plus 3</li
+ ></ul
+ ><p
+ >Pluses loose:</p
+ ><ul
+ ><li
+ ><p
+ >Plus 1</p
+ ></li
+ ><li
+ ><p
+ >Plus 2</p
+ ></li
+ ><li
+ ><p
+ >Plus 3</p
+ ></li
+ ></ul
+ ><p
+ >Minuses tight:</p
+ ><ul
+ ><li
+ >Minus 1</li
+ ><li
+ >Minus 2</li
+ ><li
+ >Minus 3</li
+ ></ul
+ ><p
+ >Minuses loose:</p
+ ><ul
+ ><li
+ ><p
+ >Minus 1</p
+ ></li
+ ><li
+ ><p
+ >Minus 2</p
+ ></li
+ ><li
+ ><p
+ >Minus 3</p
+ ></li
+ ></ul
+ ></div
+ ><div id="ordered"
+ ><h2
+ >Ordered</h2
+ ><p
+ >Tight:</p
+ ><ol style="list-style-type: decimal;"
+ ><li
+ >First</li
+ ><li
+ >Second</li
+ ><li
+ >Third</li
+ ></ol
+ ><p
+ >and:</p
+ ><ol style="list-style-type: decimal;"
+ ><li
+ >One</li
+ ><li
+ >Two</li
+ ><li
+ >Three</li
+ ></ol
+ ><p
+ >Loose using tabs:</p
+ ><ol style="list-style-type: decimal;"
+ ><li
+ ><p
+ >First</p
+ ></li
+ ><li
+ ><p
+ >Second</p
+ ></li
+ ><li
+ ><p
+ >Third</p
+ ></li
+ ></ol
+ ><p
+ >and using spaces:</p
+ ><ol style="list-style-type: decimal;"
+ ><li
+ ><p
+ >One</p
+ ></li
+ ><li
+ ><p
+ >Two</p
+ ></li
+ ><li
+ ><p
+ >Three</p
+ ></li
+ ></ol
+ ><p
+ >Multiple paragraphs:</p
+ ><ol style="list-style-type: decimal;"
+ ><li
+ ><p
+ >Item 1, graf one.</p
+ ><p
+ >Item 1. graf two. The quick brown fox jumped over the lazy dog&rsquo;s back.</p
+ ></li
+ ><li
+ ><p
+ >Item 2.</p
+ ></li
+ ><li
+ ><p
+ >Item 3.</p
+ ></li
+ ></ol
+ ></div
+ ><div id="nested"
+ ><h2
+ >Nested</h2
+ ><ul
+ ><li
+ >Tab<ul
+ ><li
+ >Tab<ul
+ ><li
+ >Tab</li
+ ></ul
+ ></li
+ ></ul
+ ></li
+ ></ul
+ ><p
+ >Here&rsquo;s another:</p
+ ><ol style="list-style-type: decimal;"
+ ><li
+ >First</li
+ ><li
+ >Second:<ul
+ ><li
+ >Fee</li
+ ><li
+ >Fie</li
+ ><li
+ >Foe</li
+ ></ul
+ ></li
+ ><li
+ >Third</li
+ ></ol
+ ><p
+ >Same thing but with paragraphs:</p
+ ><ol style="list-style-type: decimal;"
+ ><li
+ ><p
+ >First</p
+ ></li
+ ><li
+ ><p
+ >Second:</p
+ ><ul
+ ><li
+ >Fee</li
+ ><li
+ >Fie</li
+ ><li
+ >Foe</li
+ ></ul
+ ></li
+ ><li
+ ><p
+ >Third</p
+ ></li
+ ></ol
+ ></div
+ ><div id="tabs-and-spaces"
+ ><h2
+ >Tabs and spaces</h2
+ ><ul
+ ><li
+ ><p
+ >this is a list item indented with tabs</p
+ ></li
+ ><li
+ ><p
+ >this is a list item indented with spaces</p
+ ><ul
+ ><li
+ ><p
+ >this is an example list item indented with tabs</p
+ ></li
+ ><li
+ ><p
+ >this is an example list item indented with spaces</p
+ ></li
+ ></ul
+ ></li
+ ></ul
+ ></div
+ ><div id="fancy-list-markers"
+ ><h2
+ >Fancy list markers</h2
+ ><ol start="2" style="list-style-type: decimal;"
+ ><li
+ >begins with 2</li
+ ><li
+ ><p
+ >and now 3</p
+ ><p
+ >with a continuation</p
+ ><ol start="4" style="list-style-type: lower-roman;"
+ ><li
+ >sublist with roman numerals, starting with 4</li
+ ><li
+ >more items<ol style="list-style-type: upper-alpha;"
+ ><li
+ >a subsublist</li
+ ><li
+ >a subsublist</li
+ ></ol
+ ></li
+ ></ol
+ ></li
+ ></ol
+ ><p
+ >Nesting:</p
+ ><ol style="list-style-type: upper-alpha;"
+ ><li
+ >Upper Alpha<ol style="list-style-type: upper-roman;"
+ ><li
+ >Upper Roman.<ol start="6" style="list-style-type: decimal;"
+ ><li
+ >Decimal start with 6<ol start="3" style="list-style-type: lower-alpha;"
+ ><li
+ >Lower alpha with paren</li
+ ></ol
+ ></li
+ ></ol
+ ></li
+ ></ol
+ ></li
+ ></ol
+ ><p
+ >Autonumbering:</p
+ ><ol
+ ><li
+ >Autonumber.</li
+ ><li
+ >More.<ol
+ ><li
+ >Nested.</li
+ ></ol
+ ></li
+ ></ol
+ ><p
+ >Should not be a list item:</p
+ ><p
+ >M.A.&nbsp;2007</p
+ ><p
+ >B. Williams</p
+ ><hr
+ /></div
+ ></div
+ ><div id="definition-lists"
+ ><h1
+ >Definition Lists</h1
+ ><p
+ >Tight using spaces:</p
+ ><dl
+ ><dt
+ >apple</dt
+ ><dd
+ >red fruit</dd
+ ><dt
+ >orange</dt
+ ><dd
+ >orange fruit</dd
+ ><dt
+ >banana</dt
+ ><dd
+ >yellow fruit</dd
+ ></dl
+ ><p
+ >Tight using tabs:</p
+ ><dl
+ ><dt
+ >apple</dt
+ ><dd
+ >red fruit</dd
+ ><dt
+ >orange</dt
+ ><dd
+ >orange fruit</dd
+ ><dt
+ >banana</dt
+ ><dd
+ >yellow fruit</dd
+ ></dl
+ ><p
+ >Loose:</p
+ ><dl
+ ><dt
+ >apple</dt
+ ><dd
+ ><p
+ >red fruit</p
+ ></dd
+ ><dt
+ >orange</dt
+ ><dd
+ ><p
+ >orange fruit</p
+ ></dd
+ ><dt
+ >banana</dt
+ ><dd
+ ><p
+ >yellow fruit</p
+ ></dd
+ ></dl
+ ><p
+ >Multiple blocks with italics:</p
+ ><dl
+ ><dt
+ ><em
+ >apple</em
+ ></dt
+ ><dd
+ ><p
+ >red fruit</p
+ ><p
+ >contains seeds, crisp, pleasant to taste</p
+ ></dd
+ ><dt
+ ><em
+ >orange</em
+ ></dt
+ ><dd
+ ><p
+ >orange fruit</p
+ ><pre
+ ><code
+ >{ orange code block }
+</code
+ ></pre
+ ><blockquote
+ ><p
+ >orange block quote</p
+ ></blockquote
+ ></dd
+ ></dl
+ ></div
+ ><div id="html-blocks"
+ ><h1
+ >HTML Blocks</h1
+ ><p
+ >Simple block on one line:</p
+ ><div>foo</div>
+<p
+ >And nested without indentation:</p
+ ><div>
+<div>
+<div>foo</div>
+</div>
+<div>bar</div>
+</div>
+<p
+ >Interpreted markdown in a table:</p
+ ><table>
+<tr>
+<td>This is <em
+ >emphasized</em
+ ></td>
+<td>And this is <strong
+ >strong</strong
+ ></td>
+</tr>
+</table>
+
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+<p
+ >Here&rsquo;s a simple block:</p
+ ><div>
+ foo</div>
+<p
+ >This should be a code block, though:</p
+ ><pre
+ ><code
+ >&lt;div&gt;
+ foo
+&lt;/div&gt;
+</code
+ ></pre
+ ><p
+ >As should this:</p
+ ><pre
+ ><code
+ >&lt;div&gt;foo&lt;/div&gt;
+</code
+ ></pre
+ ><p
+ >Now, nested:</p
+ ><div>
+ <div>
+ <div>
+ foo</div>
+ </div>
+</div>
+<p
+ >This should just be an HTML comment:</p
+ ><!-- Comment -->
+<p
+ >Multiline:</p
+ ><!--
+Blah
+Blah
+-->
+
+<!--
+ This is another comment.
+-->
+<p
+ >Code block:</p
+ ><pre
+ ><code
+ >&lt;!-- Comment --&gt;
+</code
+ ></pre
+ ><p
+ >Just plain comment, with trailing spaces on the line:</p
+ ><!-- foo -->
+<p
+ >Code:</p
+ ><pre
+ ><code
+ >&lt;hr /&gt;
+</code
+ ></pre
+ ><p
+ >Hr&rsquo;s:</p
+ ><hr>
+
+<hr />
+
+<hr />
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar">
+<hr
+ /></div
+ ><div id="inline-markup"
+ ><h1
+ >Inline Markup</h1
+ ><p
+ >This is <em
+ >emphasized</em
+ >, and so <em
+ >is this</em
+ >.</p
+ ><p
+ >This is <strong
+ >strong</strong
+ >, and so <strong
+ >is this</strong
+ >.</p
+ ><p
+ >An <em
+ ><a href="/url"
+ >emphasized link</a
+ ></em
+ >.</p
+ ><p
+ ><strong
+ ><em
+ >This is strong and em.</em
+ ></strong
+ ></p
+ ><p
+ >So is <strong
+ ><em
+ >this</em
+ ></strong
+ > word.</p
+ ><p
+ ><strong
+ ><em
+ >This is strong and em.</em
+ ></strong
+ ></p
+ ><p
+ >So is <strong
+ ><em
+ >this</em
+ ></strong
+ > word.</p
+ ><p
+ >This is code: <code
+ >&gt;</code
+ >, <code
+ >$</code
+ >, <code
+ >\</code
+ >, <code
+ >\$</code
+ >, <code
+ >&lt;html&gt;</code
+ >.</p
+ ><p
+ ><span style="text-decoration: line-through;"
+ >This is <em
+ >strikeout</em
+ >.</span
+ ></p
+ ><p
+ >Superscripts: a<sup
+ >bc</sup
+ >d a<sup
+ ><em
+ >hello</em
+ ></sup
+ > a<sup
+ >hello&nbsp;there</sup
+ >.</p
+ ><p
+ >Subscripts: H<sub
+ >2</sub
+ >O, H<sub
+ >23</sub
+ >O, H<sub
+ >many&nbsp;of&nbsp;them</sub
+ >O.</p
+ ><p
+ >These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.</p
+ ><hr
+ /></div
+ ><div id="smart-quotes-ellipses-dashes"
+ ><h1
+ >Smart quotes, ellipses, dashes</h1
+ ><p
+ >&ldquo;Hello,&rdquo; said the spider. &ldquo;&lsquo;Shelob&rsquo; is my name.&rdquo;</p
+ ><p
+ >&lsquo;A&rsquo;, &lsquo;B&rsquo;, and &lsquo;C&rsquo; are letters.</p
+ ><p
+ >&lsquo;Oak,&rsquo; &lsquo;elm,&rsquo; and &lsquo;beech&rsquo; are names of trees. So is &lsquo;pine.&rsquo;</p
+ ><p
+ >&lsquo;He said, &ldquo;I want to go.&rdquo;&rsquo; Were you alive in the 70&rsquo;s?</p
+ ><p
+ >Here is some quoted &lsquo;<code
+ >code</code
+ >&rsquo; and a &ldquo;<a href="http://example.com/?foo=1&amp;bar=2"
+ >quoted link</a
+ >&rdquo;.</p
+ ><p
+ >Some dashes: one&mdash;two &mdash; three&mdash;four &mdash; five.</p
+ ><p
+ >Dashes between numbers: 5&ndash;7, 255&ndash;66, 1987&ndash;1999.</p
+ ><p
+ >Ellipses&hellip;and&hellip;and&hellip;.</p
+ ><hr
+ /></div
+ ><div id="latex"
+ ><h1
+ >LaTeX</h1
+ ><ul
+ ><li
+ ></li
+ ><li
+ ><span class="math"
+ >2+2=4</span
+ ></li
+ ><li
+ ><span class="math"
+ ><em
+ >x</em
+ >&#8201;&#8712;&#8201;<em
+ >y</em
+ ></span
+ ></li
+ ><li
+ ><span class="math"
+ >&#945;&#8201;&#8743;&#8201;&#969;</span
+ ></li
+ ><li
+ ><span class="math"
+ >223</span
+ ></li
+ ><li
+ ><span class="math"
+ ><em
+ >p</em
+ ></span
+ >-Tree</li
+ ><li
+ >Here&rsquo;s some display math: <span class="math"
+ >\frac{<em
+ >d</em
+ >}{<em
+ >dx</em
+ >}<em
+ >f</em
+ >(<em
+ >x</em
+ >)=\lim<sub
+ ><em
+ >h</em
+ >&#8201;&#8594;&#8201;0</sub
+ >\frac{<em
+ >f</em
+ >(<em
+ >x</em
+ >+<em
+ >h</em
+ >)-<em
+ >f</em
+ >(<em
+ >x</em
+ >)}{<em
+ >h</em
+ >}</span
+ ></li
+ ><li
+ >Here&rsquo;s one that has a line break in it: <span class="math"
+ >&#945;+&#969;&#8201;×&#8201;<em
+ >x</em
+ ><sup
+ >2</sup
+ ></span
+ >.</li
+ ></ul
+ ><p
+ >These shouldn&rsquo;t be math:</p
+ ><ul
+ ><li
+ >To get the famous equation, write <code
+ >$e = mc^2$</code
+ >.</li
+ ><li
+ >$22,000 is a <em
+ >lot</em
+ > of money. So is $34,000. (It worked if &ldquo;lot&rdquo; is emphasized.)</li
+ ><li
+ >Shoes ($20) and socks ($5).</li
+ ><li
+ >Escaped <code
+ >$</code
+ >: $73 <em
+ >this should be emphasized</em
+ > 23$.</li
+ ></ul
+ ><p
+ >Here&rsquo;s a LaTeX table:</p
+ ><p
+ ></p
+ ><hr
+ /></div
+ ><div id="special-characters"
+ ><h1
+ >Special Characters</h1
+ ><p
+ >Here is some unicode:</p
+ ><ul
+ ><li
+ >I hat: Î</li
+ ><li
+ >o umlaut: ö</li
+ ><li
+ >section: §</li
+ ><li
+ >set membership: &#8712;</li
+ ><li
+ >copyright: ©</li
+ ></ul
+ ><p
+ >AT&amp;T has an ampersand in their name.</p
+ ><p
+ >AT&amp;T is another way to write it.</p
+ ><p
+ >This &amp; that.</p
+ ><p
+ >4 &lt; 5.</p
+ ><p
+ >6 &gt; 5.</p
+ ><p
+ >Backslash: \</p
+ ><p
+ >Backtick: `</p
+ ><p
+ >Asterisk: *</p
+ ><p
+ >Underscore: _</p
+ ><p
+ >Left brace: {</p
+ ><p
+ >Right brace: }</p
+ ><p
+ >Left bracket: [</p
+ ><p
+ >Right bracket: ]</p
+ ><p
+ >Left paren: (</p
+ ><p
+ >Right paren: )</p
+ ><p
+ >Greater-than: &gt;</p
+ ><p
+ >Hash: #</p
+ ><p
+ >Period: .</p
+ ><p
+ >Bang: !</p
+ ><p
+ >Plus: +</p
+ ><p
+ >Minus: -</p
+ ><hr
+ /></div
+ ><div id="links"
+ ><h1
+ >Links</h1
+ ><div id="explicit"
+ ><h2
+ >Explicit</h2
+ ><p
+ >Just a <a href="/url/"
+ >URL</a
+ >.</p
+ ><p
+ ><a href="/url/" title="title"
+ >URL and title</a
+ >.</p
+ ><p
+ ><a href="/url/" title="title preceded by two spaces"
+ >URL and title</a
+ >.</p
+ ><p
+ ><a href="/url/" title="title preceded by a tab"
+ >URL and title</a
+ >.</p
+ ><p
+ ><a href="/url/" title="title with &quot;quotes&quot; in it"
+ >URL and title</a
+ ></p
+ ><p
+ ><a href="/url/" title="title with single quotes"
+ >URL and title</a
+ ></p
+ ><p
+ ><a href="/url/with_underscore"
+ >with_underscore</a
+ ></p
+ ><p
+ ><script type="text/javascript"
+ >
+<!--
+h='&#110;&#x6f;&#x77;&#104;&#x65;&#114;&#x65;&#46;&#110;&#x65;&#116;';a='&#64;';n='&#110;&#x6f;&#98;&#x6f;&#100;&#x79;';e=n+a+h;
+document.write('<a h'+'ref'+'="ma'+'ilto'+':'+e+'">'+'Email link'+'<\/'+'a'+'>');
+// -->
+</script
+ ><noscript
+ >&#x45;&#x6d;&#x61;&#x69;&#108;&#32;&#108;&#x69;&#110;&#x6b;&#32;&#40;&#110;&#x6f;&#98;&#x6f;&#100;&#x79;&#32;&#x61;&#116;&#32;&#110;&#x6f;&#x77;&#104;&#x65;&#114;&#x65;&#32;&#100;&#x6f;&#116;&#32;&#110;&#x65;&#116;&#x29;</noscript
+ ></p
+ ><p
+ ><a href=""
+ >Empty</a
+ >.</p
+ ></div
+ ><div id="reference"
+ ><h2
+ >Reference</h2
+ ><p
+ >Foo <a href="/url/"
+ >bar</a
+ >.</p
+ ><p
+ >Foo <a href="/url/"
+ >bar</a
+ >.</p
+ ><p
+ >Foo <a href="/url/"
+ >bar</a
+ >.</p
+ ><p
+ >With <a href="/url/"
+ >embedded [brackets]</a
+ >.</p
+ ><p
+ ><a href="/url/"
+ >b</a
+ > by itself should be a link.</p
+ ><p
+ >Indented <a href="/url"
+ >once</a
+ >.</p
+ ><p
+ >Indented <a href="/url"
+ >twice</a
+ >.</p
+ ><p
+ >Indented <a href="/url"
+ >thrice</a
+ >.</p
+ ><p
+ >This should [not][] be a link.</p
+ ><pre
+ ><code
+ >[not]: /url
+</code
+ ></pre
+ ><p
+ >Foo <a href="/url/" title="Title with &quot;quotes&quot; inside"
+ >bar</a
+ >.</p
+ ><p
+ >Foo <a href="/url/" title="Title with &quot;quote&quot; inside"
+ >biz</a
+ >.</p
+ ></div
+ ><div id="with-ampersands"
+ ><h2
+ >With ampersands</h2
+ ><p
+ >Here&rsquo;s a <a href="http://example.com/?foo=1&amp;bar=2"
+ >link with an ampersand in the URL</a
+ >.</p
+ ><p
+ >Here&rsquo;s a link with an amersand in the link text: <a href="http://att.com/" title="AT&amp;T"
+ >AT&amp;T</a
+ >.</p
+ ><p
+ >Here&rsquo;s an <a href="/script?foo=1&amp;bar=2"
+ >inline link</a
+ >.</p
+ ><p
+ >Here&rsquo;s an <a href="/script?foo=1&amp;bar=2"
+ >inline link in pointy braces</a
+ >.</p
+ ></div
+ ><div id="autolinks"
+ ><h2
+ >Autolinks</h2
+ ><p
+ >With an ampersand: <a href="http://example.com/?foo=1&amp;bar=2"
+ ><code
+ >http://example.com/?foo=1&amp;bar=2</code
+ ></a
+ ></p
+ ><ul
+ ><li
+ >In a list?</li
+ ><li
+ ><a href="http://example.com/"
+ ><code
+ >http://example.com/</code
+ ></a
+ ></li
+ ><li
+ >It should.</li
+ ></ul
+ ><p
+ >An e-mail address: <script type="text/javascript"
+ >
+<!--
+h='&#110;&#x6f;&#x77;&#104;&#x65;&#114;&#x65;&#46;&#110;&#x65;&#116;';a='&#64;';n='&#110;&#x6f;&#98;&#x6f;&#100;&#x79;';e=n+a+h;
+document.write('<a h'+'ref'+'="ma'+'ilto'+':'+e+'">'+'<code>'+e+'</code>'+'<\/'+'a'+'>');
+// -->
+</script
+ ><noscript
+ >&#110;&#x6f;&#98;&#x6f;&#100;&#x79;&#32;&#x61;&#116;&#32;&#110;&#x6f;&#x77;&#104;&#x65;&#114;&#x65;&#32;&#100;&#x6f;&#116;&#32;&#110;&#x65;&#116;</noscript
+ ></p
+ ><blockquote
+ ><p
+ >Blockquoted: <a href="http://example.com/"
+ ><code
+ >http://example.com/</code
+ ></a
+ ></p
+ ></blockquote
+ ><p
+ >Auto-links should not occur here: <code
+ >&lt;http://example.com/&gt;</code
+ ></p
+ ><pre
+ ><code
+ >or here: &lt;http://example.com/&gt;
+</code
+ ></pre
+ ><hr
+ /></div
+ ></div
+ ><div id="images"
+ ><h1
+ >Images</h1
+ ><p
+ >From &ldquo;Voyage dans la Lune&rdquo; by Georges Melies (1902):</p
+ ><p
+ ><img src="lalune.jpg" title="Voyage dans la Lune" alt="lalune"
+ /></p
+ ><p
+ >Here is a movie <img src="movie.jpg" alt="movie"
+ /> icon.</p
+ ><hr
+ /></div
+ ><div id="footnotes"
+ ><h1
+ >Footnotes</h1
+ ><p
+ >Here is a footnote reference,<a href="#fn1" class="footnoteRef" id="fnref1"
+ ><sup
+ >1</sup
+ ></a
+ > and another.<a href="#fn2" class="footnoteRef" id="fnref2"
+ ><sup
+ >2</sup
+ ></a
+ > This should <em
+ >not</em
+ > be a footnote reference, because it contains a space.[^my note] Here is an inline note.<a href="#fn3" class="footnoteRef" id="fnref3"
+ ><sup
+ >3</sup
+ ></a
+ ></p
+ ><blockquote
+ ><p
+ >Notes can go in quotes.<a href="#fn4" class="footnoteRef" id="fnref4"
+ ><sup
+ >4</sup
+ ></a
+ ></p
+ ></blockquote
+ ><ol style="list-style-type: decimal;"
+ ><li
+ >And in list items.<a href="#fn5" class="footnoteRef" id="fnref5"
+ ><sup
+ >5</sup
+ ></a
+ ></li
+ ></ol
+ ><p
+ >This paragraph should not be part of the note, as it is not indented.</p
+ ></div
+ ><div class="footnotes"
+ ><hr
+ /><ol
+ ><li id="fn1"
+ ><p
+ >Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document. <a href="#fnref1" class="footnoteBackLink" title="Jump back to footnote 1">&#8617;</a></p
+ ></li
+ ><li id="fn2"
+ ><p
+ >Here&rsquo;s the long note. This one contains multiple blocks.</p
+ ><p
+ >Subsequent blocks are indented to show that they belong to the footnote (as with list items).</p
+ ><pre
+ ><code
+ > { &lt;code&gt; }
+</code
+ ></pre
+ ><p
+ >If you want, you can indent every line, but you can also be lazy and just indent the first line of each block. <a href="#fnref2" class="footnoteBackLink" title="Jump back to footnote 2">&#8617;</a></p
+ ></li
+ ><li id="fn3"
+ ><p
+ >This is <em
+ >easier</em
+ > to type. Inline notes may contain <a href="http://google.com"
+ >links</a
+ > and <code
+ >]</code
+ > verbatim characters, as well as [bracketed text]. <a href="#fnref3" class="footnoteBackLink" title="Jump back to footnote 3">&#8617;</a></p
+ ></li
+ ><li id="fn4"
+ ><p
+ >In quote. <a href="#fnref4" class="footnoteBackLink" title="Jump back to footnote 4">&#8617;</a></p
+ ></li
+ ><li id="fn5"
+ ><p
+ >In list. <a href="#fnref5" class="footnoteBackLink" title="Jump back to footnote 5">&#8617;</a></p
+ ></li
+ ></ol
+ ></div
+ ></body
+ ></html
+>
+
diff --git a/tests/writer.latex b/tests/writer.latex
new file mode 100644
index 000000000..b1c76bc01
--- /dev/null
+++ b/tests/writer.latex
@@ -0,0 +1,802 @@
+\documentclass{article}
+\usepackage{amsmath}
+\usepackage[mathletters]{ucs}
+\usepackage[utf8x]{inputenc}
+\usepackage{listings}
+\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+
+\newcommand{\textsubscr}[1]{\ensuremath{_{\scriptsize\textrm{#1}}}}
+\usepackage[breaklinks=true]{hyperref}
+\usepackage[normalem]{ulem}
+\usepackage{enumerate}
+\usepackage{fancyvrb}
+\usepackage{graphicx}
+\usepackage{url}
+
+\setcounter{secnumdepth}{0}
+\VerbatimFootnotes % allows verbatim text in footnotes
+\title{Pandoc Test Suite}
+\author{John MacFarlane\\Anonymous}
+\date{July 17, 2006}
+\begin{document}
+\maketitle
+
+This is a set of tests for pandoc. Most of them are adapted from
+John Gruber's markdown test suite.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Headers}
+
+\subsection{Level 2 with an \href{/url}{embedded link}}
+
+\subsubsection{Level 3 with \emph{emphasis}}
+
+Level 4
+
+Level 5
+
+\section{Level 1}
+
+\subsection{Level 2 with \emph{emphasis}}
+
+\subsubsection{Level 3}
+
+with no blank line
+
+\subsection{Level 2}
+
+with no blank line
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Paragraphs}
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a
+list item. Because a hard-wrapped line in the middle of a paragraph
+looked like a list item.
+
+Here's one with a bullet. * criminey.
+
+There should be a hard line break\\here.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Block Quotes}
+
+E-mail style:
+
+\begin{quote}
+This is a block quote. It is pretty short.
+
+\end{quote}
+\begin{quote}
+Code in a block quote:
+
+\begin{verbatim}
+sub status {
+ print "working";
+}
+\end{verbatim}
+A list:
+
+\begin{enumerate}[1.]
+\item
+ item one
+\item
+ item two
+\end{enumerate}
+Nested block quotes:
+
+\begin{quote}
+nested
+
+\end{quote}
+\begin{quote}
+nested
+
+\end{quote}
+\end{quote}
+This should not be a block quote: 2 \textgreater{} 1.
+
+And a following paragraph.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Code Blocks}
+
+Code:
+
+\begin{verbatim}
+---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+\end{verbatim}
+And:
+
+\begin{verbatim}
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+\end{verbatim}
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Lists}
+
+\subsection{Unordered}
+
+Asterisks tight:
+
+\begin{itemize}
+\item
+ asterisk 1
+\item
+ asterisk 2
+\item
+ asterisk 3
+\end{itemize}
+Asterisks loose:
+
+\begin{itemize}
+\item
+ asterisk 1
+
+\item
+ asterisk 2
+
+\item
+ asterisk 3
+
+\end{itemize}
+Pluses tight:
+
+\begin{itemize}
+\item
+ Plus 1
+\item
+ Plus 2
+\item
+ Plus 3
+\end{itemize}
+Pluses loose:
+
+\begin{itemize}
+\item
+ Plus 1
+
+\item
+ Plus 2
+
+\item
+ Plus 3
+
+\end{itemize}
+Minuses tight:
+
+\begin{itemize}
+\item
+ Minus 1
+\item
+ Minus 2
+\item
+ Minus 3
+\end{itemize}
+Minuses loose:
+
+\begin{itemize}
+\item
+ Minus 1
+
+\item
+ Minus 2
+
+\item
+ Minus 3
+
+\end{itemize}
+\subsection{Ordered}
+
+Tight:
+
+\begin{enumerate}[1.]
+\item
+ First
+\item
+ Second
+\item
+ Third
+\end{enumerate}
+and:
+
+\begin{enumerate}[1.]
+\item
+ One
+\item
+ Two
+\item
+ Three
+\end{enumerate}
+Loose using tabs:
+
+\begin{enumerate}[1.]
+\item
+ First
+
+\item
+ Second
+
+\item
+ Third
+
+\end{enumerate}
+and using spaces:
+
+\begin{enumerate}[1.]
+\item
+ One
+
+\item
+ Two
+
+\item
+ Three
+
+\end{enumerate}
+Multiple paragraphs:
+
+\begin{enumerate}[1.]
+\item
+ Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's
+ back.
+
+\item
+ Item 2.
+
+\item
+ Item 3.
+
+\end{enumerate}
+\subsection{Nested}
+
+\begin{itemize}
+\item
+ Tab
+ \begin{itemize}
+ \item
+ Tab
+ \begin{itemize}
+ \item
+ Tab
+ \end{itemize}
+ \end{itemize}
+\end{itemize}
+Here's another:
+
+\begin{enumerate}[1.]
+\item
+ First
+\item
+ Second:
+ \begin{itemize}
+ \item
+ Fee
+ \item
+ Fie
+ \item
+ Foe
+ \end{itemize}
+\item
+ Third
+\end{enumerate}
+Same thing but with paragraphs:
+
+\begin{enumerate}[1.]
+\item
+ First
+
+\item
+ Second:
+
+ \begin{itemize}
+ \item
+ Fee
+ \item
+ Fie
+ \item
+ Foe
+ \end{itemize}
+\item
+ Third
+
+\end{enumerate}
+\subsection{Tabs and spaces}
+
+\begin{itemize}
+\item
+ this is a list item indented with tabs
+
+\item
+ this is a list item indented with spaces
+
+ \begin{itemize}
+ \item
+ this is an example list item indented with tabs
+
+ \item
+ this is an example list item indented with spaces
+
+ \end{itemize}
+\end{itemize}
+\subsection{Fancy list markers}
+
+\begin{enumerate}[(1)]
+\setcounter{enumi}{1}
+\item
+ begins with 2
+\item
+ and now 3
+
+ with a continuation
+
+ \begin{enumerate}[i.]
+ \setcounter{enumii}{3}
+ \item
+ sublist with roman numerals, starting with 4
+ \item
+ more items
+ \begin{enumerate}[(A)]
+ \item
+ a subsublist
+ \item
+ a subsublist
+ \end{enumerate}
+ \end{enumerate}
+\end{enumerate}
+Nesting:
+
+\begin{enumerate}[A.]
+\item
+ Upper Alpha
+ \begin{enumerate}[I.]
+ \item
+ Upper Roman.
+ \begin{enumerate}[(1)]
+ \setcounter{enumiii}{5}
+ \item
+ Decimal start with 6
+ \begin{enumerate}[a)]
+ \setcounter{enumiv}{2}
+ \item
+ Lower alpha with paren
+ \end{enumerate}
+ \end{enumerate}
+ \end{enumerate}
+\end{enumerate}
+Autonumbering:
+
+\begin{enumerate}
+\item
+ Autonumber.
+\item
+ More.
+ \begin{enumerate}
+ \item
+ Nested.
+ \end{enumerate}
+\end{enumerate}
+Should not be a list item:
+
+M.A.~2007
+
+B. Williams
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Definition Lists}
+
+Tight using spaces:
+
+\begin{description}
+\item[apple]
+red fruit
+\item[orange]
+orange fruit
+\item[banana]
+yellow fruit
+\end{description}
+Tight using tabs:
+
+\begin{description}
+\item[apple]
+red fruit
+\item[orange]
+orange fruit
+\item[banana]
+yellow fruit
+\end{description}
+Loose:
+
+\begin{description}
+\item[apple]
+red fruit
+
+\item[orange]
+orange fruit
+
+\item[banana]
+yellow fruit
+
+\end{description}
+Multiple blocks with italics:
+
+\begin{description}
+\item[\emph{apple}]
+red fruit
+
+contains seeds, crisp, pleasant to taste
+
+\item[\emph{orange}]
+orange fruit
+
+\begin{verbatim}
+{ orange code block }
+\end{verbatim}
+\begin{quote}
+orange block quote
+
+\end{quote}
+\end{description}
+\section{HTML Blocks}
+
+Simple block on one line:
+
+foo
+And nested without indentation:
+
+foo
+bar
+Interpreted markdown in a table:
+
+This is \emph{emphasized}
+And this is \textbf{strong}
+Here's a simple block:
+
+foo
+This should be a code block, though:
+
+\begin{verbatim}
+<div>
+ foo
+</div>
+\end{verbatim}
+As should this:
+
+\begin{verbatim}
+<div>foo</div>
+\end{verbatim}
+Now, nested:
+
+foo
+This should just be an HTML comment:
+
+Multiline:
+
+Code block:
+
+\begin{verbatim}
+<!-- Comment -->
+\end{verbatim}
+Just plain comment, with trailing spaces on the line:
+
+Code:
+
+\begin{verbatim}
+<hr />
+\end{verbatim}
+Hr's:
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Inline Markup}
+
+This is \emph{emphasized}, and so \emph{is this}.
+
+This is \textbf{strong}, and so \textbf{is this}.
+
+An \emph{\href{/url}{emphasized link}}.
+
+\textbf{\emph{This is strong and em.}}
+
+So is \textbf{\emph{this}} word.
+
+\textbf{\emph{This is strong and em.}}
+
+So is \textbf{\emph{this}} word.
+
+This is code: \verb!>!, \verb!$!, \verb!\!, \verb!\$!,
+\verb!<html>!.
+
+\sout{This is \emph{strikeout}.}
+
+Superscripts: a\textsuperscript{bc}d
+a\textsuperscript{\emph{hello}} a\textsuperscript{hello~there}.
+
+Subscripts: H\textsubscr{2}O, H\textsubscr{23}O,
+H\textsubscr{many~of~them}O.
+
+These should not be superscripts or subscripts, because of the
+unescaped spaces: a\^{}b c\^{}d, a\ensuremath{\sim}b
+c\ensuremath{\sim}d.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Smart quotes, ellipses, dashes}
+
+``Hello,'' said the spider. ``\,`Shelob' is my name.''
+
+`A', `B', and `C' are letters.
+
+`Oak,' `elm,' and `beech' are names of trees. So is `pine.'
+
+`He said, ``I want to go.''\,' Were you alive in the 70's?
+
+Here is some quoted `\verb!code!' and a
+``\href{http://example.com/?foo=1&bar=2}{quoted link}''.
+
+Some dashes: one---two --- three---four --- five.
+
+Dashes between numbers: 5--7, 255--66, 1987--1999.
+
+Ellipses\ldots{}and\ldots{}and\ldots{}.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{LaTeX}
+
+\begin{itemize}
+\item
+ \cite[22-23]{smith.1899}
+\item
+ $2+2=4$
+\item
+ $x \in y$
+\item
+ $\alpha \wedge \omega$
+\item
+ $223$
+\item
+ $p$-Tree
+\item
+ Here's some display math:
+ \[\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}\]
+\item
+ Here's one that has a line break in it:
+ $\alpha + \omega \times x^2$.
+\end{itemize}
+These shouldn't be math:
+
+\begin{itemize}
+\item
+ To get the famous equation, write \verb!$e = mc^2$!.
+\item
+ \$22,000 is a \emph{lot} of money. So is \$34,000. (It worked if
+ ``lot'' is emphasized.)
+\item
+ Shoes (\$20) and socks (\$5).
+\item
+ Escaped \verb!$!: \$73 \emph{this should be emphasized} 23\$.
+\end{itemize}
+Here's a LaTeX table:
+
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Special Characters}
+
+Here is some unicode:
+
+\begin{itemize}
+\item
+ I hat: Î
+\item
+ o umlaut: ö
+\item
+ section: §
+\item
+ set membership: ∈
+\item
+ copyright: ©
+\end{itemize}
+AT\&T has an ampersand in their name.
+
+AT\&T is another way to write it.
+
+This \& that.
+
+4 \textless{} 5.
+
+6 \textgreater{} 5.
+
+Backslash: \textbackslash{}
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: \_
+
+Left brace: \{
+
+Right brace: \}
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: \textgreater{}
+
+Hash: \#
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Links}
+
+\subsection{Explicit}
+
+Just a \href{/url/}{URL}.
+
+\href{/url/}{URL and title}.
+
+\href{/url/}{URL and title}.
+
+\href{/url/}{URL and title}.
+
+\href{/url/}{URL and title}
+
+\href{/url/}{URL and title}
+
+\href{/url/with_underscore}{with\_underscore}
+
+\href{mailto:nobody@nowhere.net}{Email link}
+
+\href{}{Empty}.
+
+\subsection{Reference}
+
+Foo \href{/url/}{bar}.
+
+Foo \href{/url/}{bar}.
+
+Foo \href{/url/}{bar}.
+
+With \href{/url/}{embedded [brackets]}.
+
+\href{/url/}{b} by itself should be a link.
+
+Indented \href{/url}{once}.
+
+Indented \href{/url}{twice}.
+
+Indented \href{/url}{thrice}.
+
+This should [not][] be a link.
+
+\begin{verbatim}
+[not]: /url
+\end{verbatim}
+Foo \href{/url/}{bar}.
+
+Foo \href{/url/}{biz}.
+
+\subsection{With ampersands}
+
+Here's a
+\href{http://example.com/?foo=1&bar=2}{link with an ampersand in the URL}.
+
+Here's a link with an amersand in the link text:
+\href{http://att.com/}{AT\&T}.
+
+Here's an \href{/script?foo=1&bar=2}{inline link}.
+
+Here's an
+\href{/script?foo=1&bar=2}{inline link in pointy braces}.
+
+\subsection{Autolinks}
+
+With an ampersand: \url{http://example.com/?foo=1&bar=2}
+
+\begin{itemize}
+\item
+ In a list?
+\item
+ \url{http://example.com/}
+\item
+ It should.
+\end{itemize}
+An e-mail address:
+\href{mailto:nobody@nowhere.net}{\texttt{nobody@nowhere.net}}
+
+\begin{quote}
+Blockquoted: \url{http://example.com/}
+
+\end{quote}
+Auto-links should not occur here: \verb!<http://example.com/>!
+
+\begin{verbatim}
+or here: <http://example.com/>
+\end{verbatim}
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Images}
+
+From ``Voyage dans la Lune'' by Georges Melies (1902):
+
+\includegraphics{lalune.jpg}
+
+Here is a movie \includegraphics{movie.jpg} icon.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Footnotes}
+
+Here is a footnote reference,%
+\footnote{Here is the footnote. It can go anywhere after the footnote
+reference. It need not be placed at the end of the document.}
+and another.%
+\footnote{Here's the long note. This one contains multiple blocks.
+
+Subsequent blocks are indented to show that they belong to the
+footnote (as with list items).
+
+\begin{Verbatim}
+ { <code> }
+\end{Verbatim}
+If you want, you can indent every line, but you can also be lazy
+and just indent the first line of each block.}
+This should \emph{not} be a footnote reference, because it contains
+a space.[\^{}my note] Here is an inline note.%
+\footnote{This is \emph{easier} to type. Inline notes may contain
+\href{http://google.com}{links} and \verb!]! verbatim characters,
+as well as [bracketed text].}
+
+\begin{quote}
+Notes can go in quotes.%
+\footnote{In quote.}
+
+\end{quote}
+\begin{enumerate}[1.]
+\item
+ And in list items.%
+ \footnote{In list.}
+\end{enumerate}
+This paragraph should not be part of the note, as it is not
+indented.
+
+\end{document}
diff --git a/tests/writer.man b/tests/writer.man
new file mode 100644
index 000000000..a53e891e3
--- /dev/null
+++ b/tests/writer.man
@@ -0,0 +1,790 @@
+.TH Pandoc "" "July 17, 2006" "Test Suite"
+.PP
+This is a set of tests for pandoc.
+Most of them are adapted from John Gruber's markdown test suite.
+.PP
+ * * * * *
+.SH Headers
+.SS Level 2 with an embedded link (/url)
+.SS Level 3 with \f[I]emphasis\f[]
+.SS Level 4
+.SS Level 5
+.SH Level 1
+.SS Level 2 with \f[I]emphasis\f[]
+.SS Level 3
+.PP
+with no blank line
+.SS Level 2
+.PP
+with no blank line
+.PP
+ * * * * *
+.SH Paragraphs
+.PP
+Here's a regular paragraph.
+.PP
+In Markdown 1.0.0 and earlier.
+Version 8.
+This line turns into a list item.
+Because a hard-wrapped line in the middle of a paragraph looked
+like a list item.
+.PP
+Here's one with a bullet.
+* criminey.
+.PP
+There should be a hard line break
+.PD 0
+.P
+.PD
+here.
+.PP
+ * * * * *
+.SH Block Quotes
+.PP
+E-mail style:
+.RS
+.PP
+This is a block quote.
+It is pretty short.
+.RE
+.RS
+.PP
+Code in a block quote:
+.PP
+\f[CR]
+ sub\ status\ {
+ \ \ \ \ print\ "working";
+ }
+\f[]
+.PP
+A list:
+.IP "1." 3
+item one
+.IP "2." 3
+item two
+.PP
+Nested block quotes:
+.RS
+.PP
+nested
+.RE
+.RS
+.PP
+nested
+.RE
+.RE
+.PP
+This should not be a block quote: 2 > 1.
+.PP
+And a following paragraph.
+.PP
+ * * * * *
+.SH Code Blocks
+.PP
+Code:
+.PP
+\f[CR]
+ ----\ (should\ be\ four\ hyphens)
+
+ sub\ status\ {
+ \ \ \ \ print\ "working";
+ }
+
+ this\ code\ block\ is\ indented\ by\ one\ tab
+\f[]
+.PP
+And:
+.PP
+\f[CR]
+ \ \ \ \ this\ code\ block\ is\ indented\ by\ two\ tabs
+
+ These\ should\ not\ be\ escaped:\ \ \\$\ \\\\\ \\>\ \\[\ \\{
+\f[]
+.PP
+ * * * * *
+.SH Lists
+.SS Unordered
+.PP
+Asterisks tight:
+.IP \[bu] 2
+asterisk 1
+.IP \[bu] 2
+asterisk 2
+.IP \[bu] 2
+asterisk 3
+.PP
+Asterisks loose:
+.IP \[bu] 2
+asterisk 1
+.IP \[bu] 2
+asterisk 2
+.IP \[bu] 2
+asterisk 3
+.PP
+Pluses tight:
+.IP \[bu] 2
+Plus 1
+.IP \[bu] 2
+Plus 2
+.IP \[bu] 2
+Plus 3
+.PP
+Pluses loose:
+.IP \[bu] 2
+Plus 1
+.IP \[bu] 2
+Plus 2
+.IP \[bu] 2
+Plus 3
+.PP
+Minuses tight:
+.IP \[bu] 2
+Minus 1
+.IP \[bu] 2
+Minus 2
+.IP \[bu] 2
+Minus 3
+.PP
+Minuses loose:
+.IP \[bu] 2
+Minus 1
+.IP \[bu] 2
+Minus 2
+.IP \[bu] 2
+Minus 3
+.SS Ordered
+.PP
+Tight:
+.IP "1." 3
+First
+.IP "2." 3
+Second
+.IP "3." 3
+Third
+.PP
+and:
+.IP "1." 3
+One
+.IP "2." 3
+Two
+.IP "3." 3
+Three
+.PP
+Loose using tabs:
+.IP "1." 3
+First
+.IP "2." 3
+Second
+.IP "3." 3
+Third
+.PP
+and using spaces:
+.IP "1." 3
+One
+.IP "2." 3
+Two
+.IP "3." 3
+Three
+.PP
+Multiple paragraphs:
+.IP "1." 3
+Item 1, graf one.
+.RS 4
+.PP
+Item 1.
+graf two.
+The quick brown fox jumped over the lazy dog's back.
+.RE
+.IP "2." 3
+Item 2.
+.IP "3." 3
+Item 3.
+.SS Nested
+.IP \[bu] 2
+Tab
+.RS 2
+.IP \[bu] 2
+Tab
+.RS 2
+.IP \[bu] 2
+Tab
+.RE
+.RE
+.PP
+Here's another:
+.IP "1." 3
+First
+.IP "2." 3
+Second:
+.RS 4
+.IP \[bu] 2
+Fee
+.IP \[bu] 2
+Fie
+.IP \[bu] 2
+Foe
+.RE
+.IP "3." 3
+Third
+.PP
+Same thing but with paragraphs:
+.IP "1." 3
+First
+.IP "2." 3
+Second:
+.RS 4
+.IP \[bu] 2
+Fee
+.IP \[bu] 2
+Fie
+.IP \[bu] 2
+Foe
+.RE
+.IP "3." 3
+Third
+.SS Tabs and spaces
+.IP \[bu] 2
+this is a list item indented with tabs
+.IP \[bu] 2
+this is a list item indented with spaces
+.RS 2
+.IP \[bu] 2
+this is an example list item indented with tabs
+.IP \[bu] 2
+this is an example list item indented with spaces
+.RE
+.SS Fancy list markers
+.IP "(2)" 4
+begins with 2
+.IP "(3)" 4
+and now 3
+.RS 4
+.PP
+with a continuation
+.IP "iv." 4
+sublist with roman numerals, starting with 4
+.IP " v." 4
+more items
+.RS 4
+.IP "(A)" 4
+a subsublist
+.IP "(B)" 4
+a subsublist
+.RE
+.RE
+.PP
+Nesting:
+.IP "A." 3
+Upper Alpha
+.RS 4
+.IP "I." 3
+Upper Roman.
+.RS 4
+.IP "(6)" 4
+Decimal start with 6
+.RS 4
+.IP "c)" 3
+Lower alpha with paren
+.RE
+.RE
+.RE
+.PP
+Autonumbering:
+.IP "1." 3
+Autonumber.
+.IP "2." 3
+More.
+.RS 4
+.IP "1." 3
+Nested.
+.RE
+.PP
+Should not be a list item:
+.PP
+M.A.\ 2007
+.PP
+B.
+Williams
+.PP
+ * * * * *
+.SH Definition Lists
+.PP
+Tight using spaces:
+.TP
+.B apple
+red fruit
+.RS
+.RE
+.TP
+.B orange
+orange fruit
+.RS
+.RE
+.TP
+.B banana
+yellow fruit
+.RS
+.RE
+.PP
+Tight using tabs:
+.TP
+.B apple
+red fruit
+.RS
+.RE
+.TP
+.B orange
+orange fruit
+.RS
+.RE
+.TP
+.B banana
+yellow fruit
+.RS
+.RE
+.PP
+Loose:
+.TP
+.B apple
+red fruit
+.RS
+.RE
+.TP
+.B orange
+orange fruit
+.RS
+.RE
+.TP
+.B banana
+yellow fruit
+.RS
+.RE
+.PP
+Multiple blocks with italics:
+.TP
+.B \f[I]apple\f[]
+red fruit
+.RS
+.PP
+contains seeds, crisp, pleasant to taste
+.RE
+.TP
+.B \f[I]orange\f[]
+orange fruit
+.RS
+.PP
+\f[CR]
+ {\ orange\ code\ block\ }
+\f[]
+.RS
+.PP
+orange block quote
+.RE
+.RE
+.SH HTML Blocks
+.PP
+Simple block on one line:
+<div>
+foo
+</div>
+
+.PP
+And nested without indentation:
+<div>
+<div>
+<div>
+foo
+</div>
+</div>
+<div>
+bar
+</div>
+</div>
+
+.PP
+Interpreted markdown in a table:
+<table>
+<tr>
+<td>
+This is \f[I]emphasized\f[]
+</td>
+<td>
+And this is \f[B]strong\f[]
+</td>
+</tr>
+</table>
+
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+
+.PP
+Here's a simple block:
+<div>
+
+foo
+</div>
+
+.PP
+This should be a code block, though:
+.PP
+\f[CR]
+ <div>
+ \ \ \ \ foo
+ </div>
+\f[]
+.PP
+As should this:
+.PP
+\f[CR]
+ <div>foo</div>
+\f[]
+.PP
+Now, nested:
+<div>
+ <div>
+ <div>
+
+foo
+</div>
+ </div>
+</div>
+
+.PP
+This should just be an HTML comment:
+<!-- Comment -->
+
+.PP
+Multiline:
+<!--
+Blah
+Blah
+-->
+
+<!--
+ This is another comment.
+-->
+
+.PP
+Code block:
+.PP
+\f[CR]
+ <!--\ Comment\ -->
+\f[]
+.PP
+Just plain comment, with trailing spaces on the line:
+<!-- foo -->
+
+.PP
+Code:
+.PP
+\f[CR]
+ <hr\ />
+\f[]
+.PP
+Hr's:
+<hr>
+
+<hr />
+
+<hr />
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar">
+
+.PP
+ * * * * *
+.SH Inline Markup
+.PP
+This is \f[I]emphasized\f[], and so \f[I]is this\f[].
+.PP
+This is \f[B]strong\f[], and so \f[B]is this\f[].
+.PP
+An \f[I]emphasized link (/url)\f[].
+.PP
+\f[B]\f[I]This is strong and em.\f[]\f[]
+.PP
+So is \f[B]\f[I]this\f[]\f[] word.
+.PP
+\f[B]\f[I]This is strong and em.\f[]\f[]
+.PP
+So is \f[B]\f[I]this\f[]\f[] word.
+.PP
+This is code: \f[B]>\f[], \f[B]$\f[], \f[B]\\\f[], \f[B]\\$\f[],
+\f[B]<html>\f[].
+.PP
+[STRIKEOUT:This is \f[I]strikeout\f[].]
+.PP
+Superscripts: a^bc^d a^\f[I]hello\f[]^ a^hello\ there^.
+.PP
+Subscripts: H~2~O, H~23~O, H~many\ of\ them~O.
+.PP
+These should not be superscripts or subscripts, because of the
+unescaped spaces: a^b c^d, a~b c~d.
+.PP
+ * * * * *
+.SH Smart quotes, ellipses, dashes
+.PP
+\[lq]Hello,\[rq] said the spider.
+\[lq]`Shelob' is my name.\[rq]
+.PP
+`A', `B', and `C' are letters.
+.PP
+`Oak,' `elm,' and `beech' are names of trees.
+So is `pine.'
+.PP
+`He said, \[lq]I want to go.\[rq]' Were you alive in the 70's?
+.PP
+Here is some quoted `\f[B]code\f[]' and a
+\[lq]quoted link (http://example.com/?foo=1&bar=2)\[rq].
+.PP
+Some dashes: one\[em]two \[em] three\[em]four \[em] five.
+.PP
+Dashes between numbers: 5\[en]7, 255\[en]66, 1987\[en]1999.
+.PP
+Ellipses\&...and\&...and\&....
+.PP
+ * * * * *
+.SH LaTeX
+.IP \[bu] 2
+.IP \[bu] 2
+\f[B]2+2=4\f[]
+.IP \[bu] 2
+\f[B]x\ \\in\ y\f[]
+.IP \[bu] 2
+\f[B]\\alpha\ \\wedge\ \\omega\f[]
+.IP \[bu] 2
+\f[B]223\f[]
+.IP \[bu] 2
+\f[B]p\f[]-Tree
+.IP \[bu] 2
+Here's some display math:
+.RS
+\f[B]\\frac{d}{dx}f(x)=\\lim_{h\\to\ 0}\\frac{f(x+h)-f(x)}{h}\f[]
+.RE
+.IP \[bu] 2
+Here's one that has a line break in it:
+\f[B]\\alpha\ +\ \\omega\ \\times\ x^2\f[].
+.PP
+These shouldn't be math:
+.IP \[bu] 2
+To get the famous equation, write \f[B]$e\ =\ mc^2$\f[].
+.IP \[bu] 2
+$22,000 is a \f[I]lot\f[] of money.
+So is $34,000.
+(It worked if \[lq]lot\[rq] is emphasized.)
+.IP \[bu] 2
+Shoes ($20) and socks ($5).
+.IP \[bu] 2
+Escaped \f[B]$\f[]: $73 \f[I]this should be emphasized\f[] 23$.
+.PP
+Here's a LaTeX table:
+.PP
+.PP
+ * * * * *
+.SH Special Characters
+.PP
+Here is some unicode:
+.IP \[bu] 2
+I hat: Î
+.IP \[bu] 2
+o umlaut: ö
+.IP \[bu] 2
+section: §
+.IP \[bu] 2
+set membership: ∈
+.IP \[bu] 2
+copyright: ©
+.PP
+AT&T has an ampersand in their name.
+.PP
+AT&T is another way to write it.
+.PP
+This & that.
+.PP
+4 < 5.
+.PP
+6 > 5.
+.PP
+Backslash: \\
+.PP
+Backtick: `
+.PP
+Asterisk: *
+.PP
+Underscore: _
+.PP
+Left brace: {
+.PP
+Right brace: }
+.PP
+Left bracket: [
+.PP
+Right bracket: ]
+.PP
+Left paren: (
+.PP
+Right paren: )
+.PP
+Greater-than: >
+.PP
+Hash: #
+.PP
+Period: \&.
+.PP
+Bang: !
+.PP
+Plus: +
+.PP
+Minus: -
+.PP
+ * * * * *
+.SH Links
+.SS Explicit
+.PP
+Just a URL (/url/).
+.PP
+URL and title (/url/).
+.PP
+URL and title (/url/).
+.PP
+URL and title (/url/).
+.PP
+URL and title (/url/)
+.PP
+URL and title (/url/)
+.PP
+with_underscore (/url/with_underscore)
+.PP
+Email link (mailto:nobody@nowhere.net)
+.PP
+Empty ().
+.SS Reference
+.PP
+Foo bar (/url/).
+.PP
+Foo bar (/url/).
+.PP
+Foo bar (/url/).
+.PP
+With embedded [brackets] (/url/).
+.PP
+b (/url/) by itself should be a link.
+.PP
+Indented once (/url).
+.PP
+Indented twice (/url).
+.PP
+Indented thrice (/url).
+.PP
+This should [not][] be a link.
+.PP
+\f[CR]
+ [not]:\ /url
+\f[]
+.PP
+Foo bar (/url/).
+.PP
+Foo biz (/url/).
+.SS With ampersands
+.PP
+Here's a
+link with an ampersand in the URL (http://example.com/?foo=1&bar=2).
+.PP
+Here's a link with an amersand in the link text:
+AT&T (http://att.com/).
+.PP
+Here's an inline link (/script?foo=1&bar=2).
+.PP
+Here's an inline link in pointy braces (/script?foo=1&bar=2).
+.SS Autolinks
+.PP
+With an ampersand: <http://example.com/?foo=1&bar=2>
+.IP \[bu] 2
+In a list?
+.IP \[bu] 2
+<http://example.com/>
+.IP \[bu] 2
+It should.
+.PP
+An e-mail address: <nobody@nowhere.net>
+.RS
+.PP
+Blockquoted: <http://example.com/>
+.RE
+.PP
+Auto-links should not occur here: \f[B]<http://example.com/>\f[]
+.PP
+\f[CR]
+ or\ here:\ <http://example.com/>
+\f[]
+.PP
+ * * * * *
+.SH Images
+.PP
+From \[lq]Voyage dans la Lune\[rq] by Georges Melies (1902):
+.PP
+[IMAGE: lalune (lalune.jpg)]
+.PP
+Here is a movie [IMAGE: movie (movie.jpg)] icon.
+.PP
+ * * * * *
+.SH Footnotes
+.PP
+Here is a footnote reference,[1] and another.[2] This should
+\f[I]not\f[] be a footnote reference, because it contains a
+space.[^my note] Here is an inline note.[3]
+.RS
+.PP
+Notes can go in quotes.[4]
+.RE
+.IP "1." 3
+And in list items.[5]
+.PP
+This paragraph should not be part of the note, as it is not
+indented.
+.SH NOTES
+
+.SS [1]
+.PP
+Here is the footnote.
+It can go anywhere after the footnote reference.
+It need not be placed at the end of the document.
+
+.SS [2]
+.PP
+Here's the long note.
+This one contains multiple blocks.
+.PP
+Subsequent blocks are indented to show that they belong to the
+footnote (as with list items).
+.PP
+\f[CR]
+ \ \ {\ <code>\ }
+\f[]
+.PP
+If you want, you can indent every line, but you can also be lazy
+and just indent the first line of each block.
+
+.SS [3]
+.PP
+This is \f[I]easier\f[] to type.
+Inline notes may contain links (http://google.com) and \f[B]]\f[]
+verbatim characters, as well as [bracketed text].
+
+.SS [4]
+.PP
+In quote.
+
+.SS [5]
+.PP
+In list.
+.SH AUTHORS
+John MacFarlane, Anonymous
diff --git a/tests/writer.markdown b/tests/writer.markdown
new file mode 100644
index 000000000..f377816c6
--- /dev/null
+++ b/tests/writer.markdown
@@ -0,0 +1,709 @@
+% Pandoc Test Suite
+% John MacFarlane, Anonymous
+% July 17, 2006
+
+This is a set of tests for pandoc. Most of them are adapted from
+John Gruber's markdown test suite.
+
+
+* * * * *
+
+# Headers
+
+## Level 2 with an [embedded link](/url)
+
+### Level 3 with *emphasis*
+
+#### Level 4
+
+##### Level 5
+
+# Level 1
+
+## Level 2 with *emphasis*
+
+### Level 3
+
+with no blank line
+
+## Level 2
+
+with no blank line
+
+
+* * * * *
+
+# Paragraphs
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a
+list item. Because a hard-wrapped line in the middle of a paragraph
+looked like a list item.
+
+Here's one with a bullet. \* criminey.
+
+There should be a hard line break
+here.
+
+
+* * * * *
+
+# Block Quotes
+
+E-mail style:
+
+> This is a block quote. It is pretty short.
+
+> Code in a block quote:
+>
+> sub status {
+> print "working";
+> }
+>
+> A list:
+>
+> 1. item one
+> 2. item two
+>
+> Nested block quotes:
+>
+> > nested
+>
+> > nested
+
+This should not be a block quote: 2 \> 1.
+
+And a following paragraph.
+
+
+* * * * *
+
+# Code Blocks
+
+Code:
+
+ ---- (should be four hyphens)
+
+ sub status {
+ print "working";
+ }
+
+ this code block is indented by one tab
+
+And:
+
+ this code block is indented by two tabs
+
+ These should not be escaped: \$ \\ \> \[ \{
+
+
+* * * * *
+
+# Lists
+
+## Unordered
+
+Asterisks tight:
+
+- asterisk 1
+- asterisk 2
+- asterisk 3
+
+Asterisks loose:
+
+- asterisk 1
+
+- asterisk 2
+
+- asterisk 3
+
+
+Pluses tight:
+
+- Plus 1
+- Plus 2
+- Plus 3
+
+Pluses loose:
+
+- Plus 1
+
+- Plus 2
+
+- Plus 3
+
+
+Minuses tight:
+
+- Minus 1
+- Minus 2
+- Minus 3
+
+Minuses loose:
+
+- Minus 1
+
+- Minus 2
+
+- Minus 3
+
+
+## Ordered
+
+Tight:
+
+1. First
+2. Second
+3. Third
+
+and:
+
+1. One
+2. Two
+3. Three
+
+Loose using tabs:
+
+1. First
+
+2. Second
+
+3. Third
+
+
+and using spaces:
+
+1. One
+
+2. Two
+
+3. Three
+
+
+Multiple paragraphs:
+
+1. Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's
+ back.
+
+2. Item 2.
+
+3. Item 3.
+
+
+## Nested
+
+- Tab
+ - Tab
+ - Tab
+
+
+
+Here's another:
+
+1. First
+2. Second:
+ - Fee
+ - Fie
+ - Foe
+
+3. Third
+
+Same thing but with paragraphs:
+
+1. First
+
+2. Second:
+
+ - Fee
+ - Fie
+ - Foe
+
+3. Third
+
+
+## Tabs and spaces
+
+- this is a list item indented with tabs
+
+- this is a list item indented with spaces
+
+ - this is an example list item indented with tabs
+
+ - this is an example list item indented with spaces
+
+
+
+## Fancy list markers
+
+(2) begins with 2
+(3) and now 3
+
+ with a continuation
+
+ iv. sublist with roman numerals, starting with 4
+ v. more items
+ (A) a subsublist
+ (B) a subsublist
+
+
+
+Nesting:
+
+A. Upper Alpha
+ I. Upper Roman.
+ (6) Decimal start with 6
+ c) Lower alpha with paren
+
+
+
+
+Autonumbering:
+
+1. Autonumber.
+2. More.
+ 1. Nested.
+
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+
+* * * * *
+
+# Definition Lists
+
+Tight using spaces:
+
+apple
+: red fruit
+orange
+: orange fruit
+banana
+: yellow fruit
+
+Tight using tabs:
+
+apple
+: red fruit
+orange
+: orange fruit
+banana
+: yellow fruit
+
+Loose:
+
+apple
+: red fruit
+
+orange
+: orange fruit
+
+banana
+: yellow fruit
+
+
+Multiple blocks with italics:
+
+*apple*
+: red fruit
+
+: contains seeds, crisp, pleasant to taste
+
+*orange*
+: orange fruit
+
+: { orange code block }
+
+: > orange block quote
+
+
+# HTML Blocks
+
+Simple block on one line:
+
+<div>
+foo
+</div>
+
+And nested without indentation:
+
+<div>
+<div>
+<div>
+foo
+</div>
+</div>
+<div>
+bar
+</div>
+</div>
+
+Interpreted markdown in a table:
+
+<table>
+<tr>
+<td>
+This is *emphasized*
+</td>
+<td>
+And this is **strong**
+</td>
+</tr>
+</table>
+
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+
+Here's a simple block:
+
+<div>
+
+foo
+</div>
+
+This should be a code block, though:
+
+ <div>
+ foo
+ </div>
+
+As should this:
+
+ <div>foo</div>
+
+Now, nested:
+
+<div>
+ <div>
+ <div>
+
+foo
+</div>
+ </div>
+</div>
+
+This should just be an HTML comment:
+
+<!-- Comment -->
+
+Multiline:
+
+<!--
+Blah
+Blah
+-->
+
+<!--
+ This is another comment.
+-->
+
+Code block:
+
+ <!-- Comment -->
+
+Just plain comment, with trailing spaces on the line:
+
+<!-- foo -->
+
+Code:
+
+ <hr />
+
+Hr's:
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar">
+
+
+* * * * *
+
+# Inline Markup
+
+This is *emphasized*, and so *is this*.
+
+This is **strong**, and so **is this**.
+
+An *[emphasized link](/url)*.
+
+***This is strong and em.***
+
+So is ***this*** word.
+
+***This is strong and em.***
+
+So is ***this*** word.
+
+This is code: `>`, `$`, `\`, `\$`, `<html>`.
+
+~~This is *strikeout*.~~
+
+Superscripts: a^bc^d a^*hello*^ a^hello there^.
+
+Subscripts: H~2~O, H~23~O, H~many of them~O.
+
+These should not be superscripts or subscripts, because of the
+unescaped spaces: a\^b c\^d, a\~b c\~d.
+
+
+* * * * *
+
+# Smart quotes, ellipses, dashes
+
+"Hello," said the spider. "'Shelob' is my name."
+
+'A', 'B', and 'C' are letters.
+
+'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'
+
+'He said, "I want to go."' Were you alive in the 70's?
+
+Here is some quoted '`code`' and a
+"[quoted link](http://example.com/?foo=1&bar=2)".
+
+Some dashes: one--two -- three--four -- five.
+
+Dashes between numbers: 5-7, 255-66, 1987-1999.
+
+Ellipses...and...and....
+
+
+* * * * *
+
+# LaTeX
+
+- \cite[22-23]{smith.1899}
+- $2+2=4$
+- $x \in y$
+- $\alpha \wedge \omega$
+- $223$
+- $p$-Tree
+- Here's some display math:
+ $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
+- Here's one that has a line break in it:
+ $\alpha + \omega \times x^2$.
+
+These shouldn't be math:
+
+- To get the famous equation, write `$e = mc^2$`.
+- $22,000 is a *lot* of money. So is $34,000. (It worked if "lot"
+ is emphasized.)
+- Shoes ($20) and socks ($5).
+- Escaped `$`: $73 *this should be emphasized* 23$.
+
+Here's a LaTeX table:
+
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+
+
+* * * * *
+
+# Special Characters
+
+Here is some unicode:
+
+- I hat: Î
+- o umlaut: ö
+- section: §
+- set membership: ∈
+- copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 \> 5.
+
+Backslash: \\
+
+Backtick: \`
+
+Asterisk: \*
+
+Underscore: \_
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: \>
+
+Hash: \#
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+
+* * * * *
+
+# Links
+
+## Explicit
+
+Just a [URL](/url/).
+
+[URL and title](/url/ "title").
+
+[URL and title](/url/ "title preceded by two spaces").
+
+[URL and title](/url/ "title preceded by a tab").
+
+[URL and title](/url/ "title with "quotes" in it")
+
+[URL and title](/url/ "title with single quotes")
+
+[with\_underscore](/url/with_underscore)
+
+[Email link](mailto:nobody@nowhere.net)
+
+[Empty]().
+
+## Reference
+
+Foo [bar](/url/).
+
+Foo [bar](/url/).
+
+Foo [bar](/url/).
+
+With [embedded [brackets]](/url/).
+
+[b](/url/) by itself should be a link.
+
+Indented [once](/url).
+
+Indented [twice](/url).
+
+Indented [thrice](/url).
+
+This should [not][] be a link.
+
+ [not]: /url
+
+Foo [bar](/url/ "Title with "quotes" inside").
+
+Foo [biz](/url/ "Title with "quote" inside").
+
+## With ampersands
+
+Here's a
+[link with an ampersand in the URL](http://example.com/?foo=1&bar=2).
+
+Here's a link with an amersand in the link text:
+[AT&T](http://att.com/ "AT&T").
+
+Here's an [inline link](/script?foo=1&bar=2).
+
+Here's an [inline link in pointy braces](/script?foo=1&bar=2).
+
+## Autolinks
+
+With an ampersand: <http://example.com/?foo=1&bar=2>
+
+- In a list?
+- <http://example.com/>
+- It should.
+
+An e-mail address: <nobody@nowhere.net>
+
+> Blockquoted: <http://example.com/>
+
+Auto-links should not occur here: `<http://example.com/>`
+
+ or here: <http://example.com/>
+
+
+* * * * *
+
+# Images
+
+From "Voyage dans la Lune" by Georges Melies (1902):
+
+![lalune](lalune.jpg "Voyage dans la Lune")
+
+Here is a movie ![movie](movie.jpg) icon.
+
+
+* * * * *
+
+# Footnotes
+
+Here is a footnote reference,[^1] and another.[^2] This should
+*not* be a footnote reference, because it contains a space.[\^my
+note] Here is an inline note.[^3]
+
+> Notes can go in quotes.[^4]
+
+1. And in list items.[^5]
+
+This paragraph should not be part of the note, as it is not
+indented.
+
+
+[^1]:
+ Here is the footnote. It can go anywhere after the footnote
+ reference. It need not be placed at the end of the document.
+
+[^2]:
+ Here's the long note. This one contains multiple blocks.
+
+ Subsequent blocks are indented to show that they belong to the
+ footnote (as with list items).
+
+ { <code> }
+
+ If you want, you can indent every line, but you can also be lazy
+ and just indent the first line of each block.
+
+[^3]:
+ This is *easier* to type. Inline notes may contain
+ [links](http://google.com) and `]` verbatim characters, as well as
+ [bracketed text].
+
+[^4]:
+ In quote.
+
+[^5]:
+ In list.
+
+
diff --git a/tests/writer.mediawiki b/tests/writer.mediawiki
new file mode 100644
index 000000000..fc9db6faa
--- /dev/null
+++ b/tests/writer.mediawiki
@@ -0,0 +1,604 @@
+This is a set of tests for pandoc. Most of them are adapted from John Gruber&rsquo;s markdown test suite.
+
+
+-----
+
+== Headers ==
+
+=== Level 2 with an [http://{{SERVERNAME}}/url embedded link] ===
+
+==== Level 3 with ''emphasis'' ====
+
+===== Level 4 =====
+
+====== Level 5 ======
+
+== Level 1 ==
+
+=== Level 2 with ''emphasis'' ===
+
+==== Level 3 ====
+
+with no blank line
+
+=== Level 2 ===
+
+with no blank line
+
+
+-----
+
+== Paragraphs ==
+
+Here&rsquo;s a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.
+
+Here&rsquo;s one with a bullet. * criminey.
+
+There should be a hard line break<br />
+here.
+
+
+-----
+
+== Block Quotes ==
+
+E-mail style:
+
+<blockquote>This is a block quote. It is pretty short.
+</blockquote>
+<blockquote>Code in a block quote:
+
+<pre>sub status {
+ print &quot;working&quot;;
+}</pre>
+A list:
+
+# item one
+# item two
+Nested block quotes:
+
+<blockquote>nested
+</blockquote>
+<blockquote>nested
+</blockquote></blockquote>
+This should not be a block quote: 2 &gt; 1.
+
+And a following paragraph.
+
+
+-----
+
+== Code Blocks ==
+
+Code:
+
+<pre>---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab</pre>
+And:
+
+<pre> this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{</pre>
+
+-----
+
+== Lists ==
+
+=== Unordered ===
+
+Asterisks tight:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+Asterisks loose:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+Pluses tight:
+
+* Plus 1
+* Plus 2
+* Plus 3
+Pluses loose:
+
+* Plus 1
+* Plus 2
+* Plus 3
+Minuses tight:
+
+* Minus 1
+* Minus 2
+* Minus 3
+Minuses loose:
+
+* Minus 1
+* Minus 2
+* Minus 3
+=== Ordered ===
+
+Tight:
+
+# First
+# Second
+# Third
+and:
+
+# One
+# Two
+# Three
+Loose using tabs:
+
+# First
+# Second
+# Third
+and using spaces:
+
+# One
+# Two
+# Three
+Multiple paragraphs:
+
+<ol style="list-style-type: decimal;">
+<li><p>Item 1, graf one.</p>
+<p>Item 1. graf two. The quick brown fox jumped over the lazy dog&rsquo;s back.</p></li>
+<li><p>Item 2.</p></li>
+<li><p>Item 3.</p></li></ol>
+
+=== Nested ===
+
+* Tab
+** Tab
+*** Tab
+Here&rsquo;s another:
+
+# First
+# Second:
+#* Fee
+#* Fie
+#* Foe
+# Third
+Same thing but with paragraphs:
+
+# First
+# Second:
+#* Fee
+#* Fie
+#* Foe
+# Third
+=== Tabs and spaces ===
+
+* this is a list item indented with tabs
+* this is a list item indented with spaces
+** this is an example list item indented with tabs
+** this is an example list item indented with spaces
+=== Fancy list markers ===
+
+<ol start="2" style="list-style-type: decimal;">
+<li>begins with 2</li>
+<li><p>and now 3</p>
+<p>with a continuation</p>
+<ol start="4" style="list-style-type: lower-roman;">
+<li>sublist with roman numerals, starting with 4</li>
+<li>more items
+<ol style="list-style-type: upper-alpha;">
+<li>a subsublist</li>
+<li>a subsublist</li></ol>
+</li></ol>
+</li></ol>
+
+Nesting:
+
+<ol style="list-style-type: upper-alpha;">
+<li>Upper Alpha
+<ol style="list-style-type: upper-roman;">
+<li>Upper Roman.
+<ol start="6" style="list-style-type: decimal;">
+<li>Decimal start with 6
+<ol start="3" style="list-style-type: lower-alpha;">
+<li>Lower alpha with paren</li></ol>
+</li></ol>
+</li></ol>
+</li></ol>
+
+Autonumbering:
+
+# Autonumber.
+# More.
+## Nested.
+Should not be a list item:
+
+M.A.&#160;2007
+
+B. Williams
+
+
+-----
+
+== Definition Lists ==
+
+Tight using spaces:
+
+; apple
+: red fruit
+; orange
+: orange fruit
+; banana
+: yellow fruit
+Tight using tabs:
+
+; apple
+: red fruit
+; orange
+: orange fruit
+; banana
+: yellow fruit
+Loose:
+
+; apple
+: red fruit
+; orange
+: orange fruit
+; banana
+: yellow fruit
+Multiple blocks with italics:
+
+<dl>
+<dt>''apple''</dt>
+<dd><p>red fruit</p>
+<p>contains seeds, crisp, pleasant to taste</p></dd>
+<dt>''orange''</dt>
+<dd><p>orange fruit</p>
+<pre>{ orange code block }</pre>
+<blockquote><p>orange block quote</p></blockquote></dd></dl>
+
+== HTML Blocks ==
+
+Simple block on one line:
+
+<div>
+foo
+</div>
+
+And nested without indentation:
+
+<div>
+<div>
+<div>
+foo
+</div>
+</div>
+<div>
+bar
+</div>
+</div>
+
+Interpreted markdown in a table:
+
+<table>
+<tr>
+<td>
+This is ''emphasized''
+</td>
+<td>
+And this is '''strong'''
+</td>
+</tr>
+</table>
+
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+
+Here&rsquo;s a simple block:
+
+<div>
+
+foo
+</div>
+
+This should be a code block, though:
+
+<pre>&lt;div&gt;
+ foo
+&lt;/div&gt;</pre>
+As should this:
+
+<pre>&lt;div&gt;foo&lt;/div&gt;</pre>
+Now, nested:
+
+<div>
+ <div>
+ <div>
+
+foo
+</div>
+ </div>
+</div>
+
+This should just be an HTML comment:
+
+<!-- Comment -->
+
+Multiline:
+
+<!--
+Blah
+Blah
+-->
+
+<!--
+ This is another comment.
+-->
+
+Code block:
+
+<pre>&lt;!-- Comment --&gt;</pre>
+Just plain comment, with trailing spaces on the line:
+
+<!-- foo -->
+
+Code:
+
+<pre>&lt;hr /&gt;</pre>
+Hr&rsquo;s:
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar">
+
+
+-----
+
+== Inline Markup ==
+
+This is ''emphasized'', and so ''is this''.
+
+This is '''strong''', and so '''is this'''.
+
+An ''[http://{{SERVERNAME}}/url emphasized link]''.
+
+'''''This is strong and em.'''''
+
+So is '''''this''''' word.
+
+'''''This is strong and em.'''''
+
+So is '''''this''''' word.
+
+This is code: <tt>&gt;</tt>, <tt>$</tt>, <tt>\</tt>, <tt>\$</tt>, <tt>&lt;html&gt;</tt>.
+
+<s>This is ''strikeout''.</s>
+
+Superscripts: a<sup>bc</sup>d a<sup>''hello''</sup> a<sup>hello&#160;there</sup>.
+
+Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many&#160;of&#160;them</sub>O.
+
+These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
+
+
+-----
+
+== Smart quotes, ellipses, dashes ==
+
+&ldquo;Hello,&rdquo; said the spider. &ldquo;&lsquo;Shelob&rsquo; is my name.&rdquo;
+
+&lsquo;A&rsquo;, &lsquo;B&rsquo;, and &lsquo;C&rsquo; are letters.
+
+&lsquo;Oak,&rsquo; &lsquo;elm,&rsquo; and &lsquo;beech&rsquo; are names of trees. So is &lsquo;pine.&rsquo;
+
+&lsquo;He said, &ldquo;I want to go.&rdquo;&rsquo; Were you alive in the 70&rsquo;s?
+
+Here is some quoted &lsquo;<tt>code</tt>&rsquo; and a &ldquo;[http://example.com/?foo=1&bar=2 quoted link]&rdquo;.
+
+Some dashes: one&mdash;two &mdash; three&mdash;four &mdash; five.
+
+Dashes between numbers: 5&ndash;7, 255&ndash;66, 1987&ndash;1999.
+
+Ellipses&hellip;and&hellip;and&hellip;.
+
+
+-----
+
+== LaTeX ==
+
+*
+* <math>2+2=4</math>
+* <math>x \in y</math>
+* <math>\alpha \wedge \omega</math>
+* <math>223</math>
+* <math>p</math>-Tree
+* Here&rsquo;s some display math: <math>\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</math>
+* Here&rsquo;s one that has a line break in it: <math>\alpha + \omega \times x^2</math>.
+These shouldn&rsquo;t be math:
+
+* To get the famous equation, write <tt>$e = mc^2$</tt>.
+* $22,000 is a ''lot'' of money. So is $34,000. (It worked if &ldquo;lot&rdquo; is emphasized.)
+* Shoes ($20) and socks ($5).
+* Escaped <tt>$</tt>: $73 ''this should be emphasized'' 23$.
+Here&rsquo;s a LaTeX table:
+
+
+
+
+-----
+
+== Special Characters ==
+
+Here is some unicode:
+
+* I hat: Î
+* o umlaut: ö
+* section: §
+* set membership: ∈
+* copyright: ©
+AT&amp;T has an ampersand in their name.
+
+AT&amp;T is another way to write it.
+
+This &amp; that.
+
+4 &lt; 5.
+
+6 &gt; 5.
+
+Backslash: \
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: _
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: &gt;
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+
+-----
+
+== Links ==
+
+=== Explicit ===
+
+Just a [http://{{SERVERNAME}}/url/ URL].
+
+[http://{{SERVERNAME}}/url/ URL and title].
+
+[http://{{SERVERNAME}}/url/ URL and title].
+
+[http://{{SERVERNAME}}/url/ URL and title].
+
+[http://{{SERVERNAME}}/url/ URL and title]
+
+[http://{{SERVERNAME}}/url/ URL and title]
+
+[http://{{SERVERNAME}}/url/with_underscore with_underscore]
+
+[mailto:nobody@nowhere.net Email link]
+
+[http://{{SERVERNAME}}/ Empty].
+
+=== Reference ===
+
+Foo [http://{{SERVERNAME}}/url/ bar].
+
+Foo [http://{{SERVERNAME}}/url/ bar].
+
+Foo [http://{{SERVERNAME}}/url/ bar].
+
+With [http://{{SERVERNAME}}/url/ embedded [brackets]].
+
+[http://{{SERVERNAME}}/url/ b] by itself should be a link.
+
+Indented [http://{{SERVERNAME}}/url once].
+
+Indented [http://{{SERVERNAME}}/url twice].
+
+Indented [http://{{SERVERNAME}}/url thrice].
+
+This should [not][] be a link.
+
+<pre>[not]: /url</pre>
+Foo [http://{{SERVERNAME}}/url/ bar].
+
+Foo [http://{{SERVERNAME}}/url/ biz].
+
+=== With ampersands ===
+
+Here&rsquo;s a [http://example.com/?foo=1&bar=2 link with an ampersand in the URL].
+
+Here&rsquo;s a link with an amersand in the link text: [http://att.com/ AT&amp;T].
+
+Here&rsquo;s an [http://{{SERVERNAME}}/script?foo=1&bar=2 inline link].
+
+Here&rsquo;s an [http://{{SERVERNAME}}/script?foo=1&bar=2 inline link in pointy braces].
+
+=== Autolinks ===
+
+With an ampersand: http://example.com/?foo=1&bar=2
+
+* In a list?
+* http://example.com/
+* It should.
+An e-mail address: [mailto:nobody@nowhere.net <tt>nobody@nowhere.net</tt>]
+
+<blockquote>Blockquoted: http://example.com/
+</blockquote>
+Auto-links should not occur here: <tt>&lt;http://example.com/&gt;</tt>
+
+<pre>or here: &lt;http://example.com/&gt;</pre>
+
+-----
+
+== Images ==
+
+From &ldquo;Voyage dans la Lune&rdquo; by Georges Melies (1902):
+
+[[Image:lalune.jpg|Voyage dans la Lune]]
+
+Here is a movie [[Image:movie.jpg|movie]] icon.
+
+
+-----
+
+== Footnotes ==
+
+Here is a footnote reference,<ref>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.
+</ref> and another.<ref>Here&rsquo;s the long note. This one contains multiple blocks.
+
+Subsequent blocks are indented to show that they belong to the footnote (as with list items).
+
+<pre> { &lt;code&gt; }</pre>
+If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.
+</ref> This should ''not'' be a footnote reference, because it contains a space.[^my note] Here is an inline note.<ref>This is ''easier'' to type. Inline notes may contain [http://google.com links] and <tt>]</tt> verbatim characters, as well as [bracketed text].
+</ref>
+
+<blockquote>Notes can go in quotes.<ref>In quote.
+</ref>
+</blockquote>
+# And in list items.<ref>In list.</ref>
+This paragraph should not be part of the note, as it is not indented.
+
+== Notes ==
+<references />
diff --git a/tests/writer.native b/tests/writer.native
new file mode 100644
index 000000000..5f2459ffb
--- /dev/null
+++ b/tests/writer.native
@@ -0,0 +1,387 @@
+Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] ["John MacFarlane","Anonymous"] "July 17, 2006")
+[ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc",Str ".",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber",Apostrophe,Str "s",Space,Str "markdown",Space,Str "test",Space,Str "suite",Str "."]
+, HorizontalRule
+, Header 1 [Str "Headers"]
+, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] ("/url","")]
+, Header 3 [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
+, Header 4 [Str "Level",Space,Str "4"]
+, Header 5 [Str "Level",Space,Str "5"]
+, Header 1 [Str "Level",Space,Str "1"]
+, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
+, Header 3 [Str "Level",Space,Str "3"]
+, Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+, Header 2 [Str "Level",Space,Str "2"]
+, Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+, HorizontalRule
+, Header 1 [Str "Paragraphs"]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "regular",Space,Str "paragraph",Str "."]
+, Para [Str "In",Space,Str "Markdown",Space,Str "1",Str ".",Str "0",Str ".",Str "0",Space,Str "and",Space,Str "earlier",Str ".",Space,Str "Version",Space,Str "8",Str ".",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item",Str ".",Space,Str "Because",Space,Str "a",Space,Str "hard",Str "-",Str "wrapped",Space,Str "line",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",Space,Str "list",Space,Str "item",Str "."]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet",Str ".",Space,Str "*",Space,Str "criminey",Str "."]
+, Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Str "here",Str "."]
+, HorizontalRule
+, Header 1 [Str "Block",Space,Str "Quotes"]
+, Para [Str "E",Str "-",Str "mail",Space,Str "style:"]
+, BlockQuote
+ [ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote",Str ".",Space,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short",Str "."] ]
+
+, BlockQuote
+ [ Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
+ , CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
+ , Para [Str "A",Space,Str "list:"]
+ , OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "item",Space,Str "one"] ]
+ , [ Plain [Str "item",Space,Str "two"] ] ]
+ , Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
+ , BlockQuote
+ [ Para [Str "nested"] ]
+
+ , BlockQuote
+ [ Para [Str "nested"] ]
+ ]
+, Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",Space,Str ">",Space,Str "1",Str "."]
+, Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph",Str "."]
+, HorizontalRule
+, Header 1 [Str "Code",Space,Str "Blocks"]
+, Para [Str "Code:"]
+, CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
+, Para [Str "And:"]
+, CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
+, HorizontalRule
+, Header 1 [Str "Lists"]
+, Header 2 [Str "Unordered"]
+, Para [Str "Asterisks",Space,Str "tight:"]
+, BulletList
+ [ [ Plain [Str "asterisk",Space,Str "1"] ]
+ , [ Plain [Str "asterisk",Space,Str "2"] ]
+ , [ Plain [Str "asterisk",Space,Str "3"] ] ]
+, Para [Str "Asterisks",Space,Str "loose:"]
+, BulletList
+ [ [ Para [Str "asterisk",Space,Str "1"] ]
+ , [ Para [Str "asterisk",Space,Str "2"] ]
+ , [ Para [Str "asterisk",Space,Str "3"] ] ]
+, Para [Str "Pluses",Space,Str "tight:"]
+, BulletList
+ [ [ Plain [Str "Plus",Space,Str "1"] ]
+ , [ Plain [Str "Plus",Space,Str "2"] ]
+ , [ Plain [Str "Plus",Space,Str "3"] ] ]
+, Para [Str "Pluses",Space,Str "loose:"]
+, BulletList
+ [ [ Para [Str "Plus",Space,Str "1"] ]
+ , [ Para [Str "Plus",Space,Str "2"] ]
+ , [ Para [Str "Plus",Space,Str "3"] ] ]
+, Para [Str "Minuses",Space,Str "tight:"]
+, BulletList
+ [ [ Plain [Str "Minus",Space,Str "1"] ]
+ , [ Plain [Str "Minus",Space,Str "2"] ]
+ , [ Plain [Str "Minus",Space,Str "3"] ] ]
+, Para [Str "Minuses",Space,Str "loose:"]
+, BulletList
+ [ [ Para [Str "Minus",Space,Str "1"] ]
+ , [ Para [Str "Minus",Space,Str "2"] ]
+ , [ Para [Str "Minus",Space,Str "3"] ] ]
+, Header 2 [Str "Ordered"]
+, Para [Str "Tight:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "First"] ]
+ , [ Plain [Str "Second"] ]
+ , [ Plain [Str "Third"] ] ]
+, Para [Str "and:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "One"] ]
+ , [ Plain [Str "Two"] ]
+ , [ Plain [Str "Three"] ] ]
+, Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "First"] ]
+ , [ Para [Str "Second"] ]
+ , [ Para [Str "Third"] ] ]
+, Para [Str "and",Space,Str "using",Space,Str "spaces:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "One"] ]
+ , [ Para [Str "Two"] ]
+ , [ Para [Str "Three"] ] ]
+, Para [Str "Multiple",Space,Str "paragraphs:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one",Str "."]
+ , Para [Str "Item",Space,Str "1",Str ".",Space,Str "graf",Space,Str "two",Str ".",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog",Apostrophe,Str "s",Space,Str "back",Str "."] ], [ Para [Str "Item",Space,Str "2",Str "."] ]
+ , [ Para [Str "Item",Space,Str "3",Str "."] ] ]
+, Header 2 [Str "Nested"]
+, BulletList
+ [ [ Plain [Str "Tab"]
+ , BulletList
+ [ [ Plain [Str "Tab"]
+ , BulletList
+ [ [ Plain [Str "Tab"] ]
+ ] ] ] ] ]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "another:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "First"] ]
+ , [ Plain [Str "Second:"]
+ , BulletList
+ [ [ Plain [Str "Fee"] ]
+ , [ Plain [Str "Fie"] ]
+ , [ Plain [Str "Foe"] ] ] ], [ Plain [Str "Third"] ] ]
+, Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
+, OrderedList (1,Decimal,Period)
+ [ [ Para [Str "First"] ]
+ , [ Para [Str "Second:"]
+ , BulletList
+ [ [ Plain [Str "Fee"] ]
+ , [ Plain [Str "Fie"] ]
+ , [ Plain [Str "Foe"] ] ] ], [ Para [Str "Third"] ] ]
+, Header 2 [Str "Tabs",Space,Str "and",Space,Str "spaces"]
+, BulletList
+ [ [ Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"] ]
+ , [ Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]
+ , BulletList
+ [ [ Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"] ]
+ , [ Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"] ] ] ] ]
+, Header 2 [Str "Fancy",Space,Str "list",Space,Str "markers"]
+, OrderedList (2,Decimal,TwoParens)
+ [ [ Plain [Str "begins",Space,Str "with",Space,Str "2"] ]
+ , [ Para [Str "and",Space,Str "now",Space,Str "3"]
+ , Para [Str "with",Space,Str "a",Space,Str "continuation"]
+ , OrderedList (4,LowerRoman,Period)
+ [ [ Plain [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",Space,Str "starting",Space,Str "with",Space,Str "4"] ]
+ , [ Plain [Str "more",Space,Str "items"]
+ , OrderedList (1,UpperAlpha,TwoParens)
+ [ [ Plain [Str "a",Space,Str "subsublist"] ]
+ , [ Plain [Str "a",Space,Str "subsublist"] ] ] ] ] ] ]
+, Para [Str "Nesting:"]
+, OrderedList (1,UpperAlpha,Period)
+ [ [ Plain [Str "Upper",Space,Str "Alpha"]
+ , OrderedList (1,UpperRoman,Period)
+ [ [ Plain [Str "Upper",Space,Str "Roman",Str "."]
+ , OrderedList (6,Decimal,TwoParens)
+ [ [ Plain [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
+ , OrderedList (3,LowerAlpha,OneParen)
+ [ [ Plain [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"] ]
+ ] ] ] ] ] ] ]
+, Para [Str "Autonumbering:"]
+, OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "Autonumber",Str "."] ]
+ , [ Plain [Str "More",Str "."]
+ , OrderedList (1,DefaultStyle,DefaultDelim)
+ [ [ Plain [Str "Nested",Str "."] ]
+ ] ] ]
+, Para [Str "Should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "list",Space,Str "item:"]
+, Para [Str "M.A.\160",Str "2007"]
+, Para [Str "B",Str ".",Space,Str "Williams"]
+, HorizontalRule
+, Header 1 [Str "Definition",Space,Str "Lists"]
+, Para [Str "Tight",Space,Str "using",Space,Str "spaces:"]
+, DefinitionList
+ [ ([Str "apple"],
+ [ Plain [Str "red",Space,Str "fruit"] ]
+ ),
+ ([Str "orange"],
+ [ Plain [Str "orange",Space,Str "fruit"] ]
+ ),
+ ([Str "banana"],
+ [ Plain [Str "yellow",Space,Str "fruit"] ]
+ ) ]
+, Para [Str "Tight",Space,Str "using",Space,Str "tabs:"]
+, DefinitionList
+ [ ([Str "apple"],
+ [ Plain [Str "red",Space,Str "fruit"] ]
+ ),
+ ([Str "orange"],
+ [ Plain [Str "orange",Space,Str "fruit"] ]
+ ),
+ ([Str "banana"],
+ [ Plain [Str "yellow",Space,Str "fruit"] ]
+ ) ]
+, Para [Str "Loose:"]
+, DefinitionList
+ [ ([Str "apple"],
+ [ Para [Str "red",Space,Str "fruit"] ]
+ ),
+ ([Str "orange"],
+ [ Para [Str "orange",Space,Str "fruit"] ]
+ ),
+ ([Str "banana"],
+ [ Para [Str "yellow",Space,Str "fruit"] ]
+ ) ]
+, Para [Str "Multiple",Space,Str "blocks",Space,Str "with",Space,Str "italics:"]
+, DefinitionList
+ [ ([Emph [Str "apple"]],
+ [ Para [Str "red",Space,Str "fruit"]
+ , Para [Str "contains",Space,Str "seeds,",Space,Str "crisp,",Space,Str "pleasant",Space,Str "to",Space,Str "taste"] ] ),
+ ([Emph [Str "orange"]],
+ [ Para [Str "orange",Space,Str "fruit"]
+ , CodeBlock ("",[],[]) "{ orange code block }"
+ , BlockQuote
+ [ Para [Str "orange",Space,Str "block",Space,Str "quote"] ]
+ ] ) ]
+, Header 1 [Str "HTML",Space,Str "Blocks"]
+, Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line:"]
+, RawHtml "<div>"
+, Plain [Str "foo"]
+, RawHtml "</div>\n"
+, Para [Str "And",Space,Str "nested",Space,Str "without",Space,Str "indentation:"]
+, RawHtml "<div>\n<div>\n<div>"
+, Plain [Str "foo"]
+, RawHtml "</div>\n</div>\n<div>"
+, Plain [Str "bar"]
+, RawHtml "</div>\n</div>\n"
+, Para [Str "Interpreted",Space,Str "markdown",Space,Str "in",Space,Str "a",Space,Str "table:"]
+, RawHtml "<table>\n<tr>\n<td>"
+, Plain [Str "This",Space,Str "is",Space,Emph [Str "emphasized"]]
+, RawHtml "</td>\n<td>"
+, Plain [Str "And",Space,Str "this",Space,Str "is",Space,Strong [Str "strong"]]
+, RawHtml "</td>\n</tr>\n</table>\n\n<script type=\"text/javascript\">document.write('This *should not* be interpreted as markdown');</script>\n"
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "simple",Space,Str "block:"]
+, RawHtml "<div>\n "
+, Plain [Str "foo"]
+, RawHtml "</div>\n"
+, Para [Str "This",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "code",Space,Str "block,",Space,Str "though:"]
+, CodeBlock ("",[],[]) "<div>\n foo\n</div>"
+, Para [Str "As",Space,Str "should",Space,Str "this:"]
+, CodeBlock ("",[],[]) "<div>foo</div>"
+, Para [Str "Now,",Space,Str "nested:"]
+, RawHtml "<div>\n <div>\n <div>\n "
+, Plain [Str "foo"]
+, RawHtml "</div>\n </div>\n</div>\n"
+, Para [Str "This",Space,Str "should",Space,Str "just",Space,Str "be",Space,Str "an",Space,Str "HTML",Space,Str "comment:"]
+, RawHtml "<!-- Comment -->\n"
+, Para [Str "Multiline:"]
+, RawHtml "<!--\nBlah\nBlah\n-->\n\n<!--\n This is another comment.\n-->\n"
+, Para [Str "Code",Space,Str "block:"]
+, CodeBlock ("",[],[]) "<!-- Comment -->"
+, Para [Str "Just",Space,Str "plain",Space,Str "comment,",Space,Str "with",Space,Str "trailing",Space,Str "spaces",Space,Str "on",Space,Str "the",Space,Str "line:"]
+, RawHtml "<!-- foo --> \n"
+, Para [Str "Code:"]
+, CodeBlock ("",[],[]) "<hr />"
+, Para [Str "Hr",Apostrophe,Str "s:"]
+, RawHtml "<hr>\n\n<hr />\n\n<hr />\n\n<hr> \n\n<hr /> \n\n<hr /> \n\n<hr class=\"foo\" id=\"bar\" />\n\n<hr class=\"foo\" id=\"bar\" />\n\n<hr class=\"foo\" id=\"bar\">\n"
+, HorizontalRule
+, Header 1 [Str "Inline",Space,Str "Markup"]
+, Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
+, Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
+, Para [Str "An",Space,Emph [Link [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
+, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em",Str "."]]]
+, Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word",Str "."]
+, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em",Str "."]]]
+, Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word",Str "."]
+, Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ">",Str ",",Space,Code "$",Str ",",Space,Code "\\",Str ",",Space,Code "\\$",Str ",",Space,Code "<html>",Str "."]
+, Para [Strikeout [Str "This",Space,Str "is",Space,Emph [Str "strikeout"],Str "."]]
+, Para [Str "Superscripts:",Space,Str "a",Superscript [Str "bc"],Str "d",Space,Str "a",Superscript [Emph [Str "hello"]],Space,Str "a",Superscript [Str "hello",Str "\160",Str "there"],Str "."]
+, Para [Str "Subscripts:",Space,Str "H",Subscript [Str "2"],Str "O,",Space,Str "H",Subscript [Str "23"],Str "O,",Space,Str "H",Subscript [Str "many",Str "\160",Str "of",Str "\160",Str "them"],Str "O",Str "."]
+, Para [Str "These",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "superscripts",Space,Str "or",Space,Str "subscripts,",Space,Str "because",Space,Str "of",Space,Str "the",Space,Str "unescaped",Space,Str "spaces:",Space,Str "a",Str "^",Str "b",Space,Str "c",Str "^",Str "d,",Space,Str "a",Str "~",Str "b",Space,Str "c",Str "~",Str "d",Str "."]
+, HorizontalRule
+, Header 1 [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
+, Para [Quoted DoubleQuote [Str "Hello,"],Space,Str "said",Space,Str "the",Space,Str "spider",Str ".",Space,Quoted DoubleQuote [Quoted SingleQuote [Str "Shelob"],Space,Str "is",Space,Str "my",Space,Str "name",Str "."]]
+, Para [Quoted SingleQuote [Str "A"],Str ",",Space,Quoted SingleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted SingleQuote [Str "C"],Space,Str "are",Space,Str "letters",Str "."]
+, Para [Quoted SingleQuote [Str "Oak,"],Space,Quoted SingleQuote [Str "elm,"],Space,Str "and",Space,Quoted SingleQuote [Str "beech"],Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees",Str ".",Space,Str "So",Space,Str "is",Space,Quoted SingleQuote [Str "pine",Str "."]]
+, Para [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go",Str "."]],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70",Apostrophe,Str "s?"]
+, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code "code"],Space,Str "and",Space,Str "a",Space,Quoted DoubleQuote [Link [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2","")],Str "."]
+, Para [Str "Some",Space,Str "dashes:",Space,Str "one",EmDash,Str "two",Space,EmDash,Space,Str "three",EmDash,Str "four",Space,EmDash,Space,Str "five",Str "."]
+, Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5",EnDash,Str "7,",Space,Str "255",EnDash,Str "66,",Space,Str "1987",EnDash,Str "1999",Str "."]
+, Para [Str "Ellipses",Ellipses,Str "and",Ellipses,Str "and",Ellipses,Str "."]
+, HorizontalRule
+, Header 1 [Str "LaTeX"]
+, BulletList
+ [ [ Plain [TeX "\\cite[22-23]{smith.1899}"] ]
+ , [ Plain [Math InlineMath "2+2=4"] ]
+ , [ Plain [Math InlineMath "x \\in y"] ]
+ , [ Plain [Math InlineMath "\\alpha \\wedge \\omega"] ]
+ , [ Plain [Math InlineMath "223"] ]
+ , [ Plain [Math InlineMath "p",Str "-",Str "Tree"] ]
+ , [ Plain [Str "Here",Apostrophe,Str "s",Space,Str "some",Space,Str "display",Space,Str "math:",Space,Math DisplayMath "\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}"] ]
+ , [ Plain [Str "Here",Apostrophe,Str "s",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",Space,Math InlineMath "\\alpha + \\omega \\times x^2",Str "."] ] ]
+, Para [Str "These",Space,Str "shouldn",Apostrophe,Str "t",Space,Str "be",Space,Str "math:"]
+, BulletList
+ [ [ Plain [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",Space,Code "$e = mc^2$",Str "."] ]
+ , [ Plain [Str "$",Str "22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money",Str ".",Space,Str "So",Space,Str "is",Space,Str "$",Str "34,000",Str ".",Space,Str "(It",Space,Str "worked",Space,Str "if",Space,Quoted DoubleQuote [Str "lot"],Space,Str "is",Space,Str "emphasized",Str ".",Str ")"] ]
+ , [ Plain [Str "Shoes",Space,Str "(",Str "$",Str "20)",Space,Str "and",Space,Str "socks",Space,Str "(",Str "$",Str "5)",Str "."] ]
+ , [ Plain [Str "Escaped",Space,Code "$",Str ":",Space,Str "$",Str "73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23",Str "$",Str "."] ] ]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
+, Para [TeX "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}"]
+, HorizontalRule
+, Header 1 [Str "Special",Space,Str "Characters"]
+, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
+, BulletList
+ [ [ Plain [Str "I",Space,Str "hat:",Space,Str "\206"] ]
+ , [ Plain [Str "o",Space,Str "umlaut:",Space,Str "\246"] ]
+ , [ Plain [Str "section:",Space,Str "\167"] ]
+ , [ Plain [Str "set",Space,Str "membership:",Space,Str "\8712"] ]
+ , [ Plain [Str "copyright:",Space,Str "\169"] ] ]
+, Para [Str "AT",Str "&",Str "T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name",Str "."]
+, Para [Str "AT",Str "&",Str "T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it",Str "."]
+, Para [Str "This",Space,Str "&",Space,Str "that",Str "."]
+, Para [Str "4",Space,Str "<",Space,Str "5",Str "."]
+, Para [Str "6",Space,Str ">",Space,Str "5",Str "."]
+, Para [Str "Backslash:",Space,Str "\\"]
+, Para [Str "Backtick:",Space,Str "`"]
+, Para [Str "Asterisk:",Space,Str "*"]
+, Para [Str "Underscore:",Space,Str "_"]
+, Para [Str "Left",Space,Str "brace:",Space,Str "{"]
+, Para [Str "Right",Space,Str "brace:",Space,Str "}"]
+, Para [Str "Left",Space,Str "bracket:",Space,Str "["]
+, Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
+, Para [Str "Left",Space,Str "paren:",Space,Str "("]
+, Para [Str "Right",Space,Str "paren:",Space,Str ")"]
+, Para [Str "Greater",Str "-",Str "than:",Space,Str ">"]
+, Para [Str "Hash:",Space,Str "#"]
+, Para [Str "Period:",Space,Str "."]
+, Para [Str "Bang:",Space,Str "!"]
+, Para [Str "Plus:",Space,Str "+"]
+, Para [Str "Minus:",Space,Str "-"]
+, HorizontalRule
+, Header 1 [Str "Links"]
+, Header 2 [Str "Explicit"]
+, Para [Str "Just",Space,Str "a",Space,Link [Str "URL"] ("/url/",""),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
+, Para [Link [Str "with",Str "_",Str "underscore"] ("/url/with_underscore","")]
+, Para [Link [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
+, Para [Link [Str "Empty"] ("",""),Str "."]
+, Header 2 [Str "Reference"]
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
+, Para [Str "With",Space,Link [Str "embedded",Space,Str "[",Str "brackets",Str "]"] ("/url/",""),Str "."]
+, Para [Link [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link",Str "."]
+, Para [Str "Indented",Space,Link [Str "once"] ("/url",""),Str "."]
+, Para [Str "Indented",Space,Link [Str "twice"] ("/url",""),Str "."]
+, Para [Str "Indented",Space,Link [Str "thrice"] ("/url",""),Str "."]
+, Para [Str "This",Space,Str "should",Space,Str "[",Str "not",Str "]",Str "[",Str "]",Space,Str "be",Space,Str "a",Space,Str "link",Str "."]
+, CodeBlock ("",[],[]) "[not]: /url"
+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
+, Para [Str "Foo",Space,Link [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
+, Header 2 [Str "With",Space,Str "ampersands"]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link [Str "AT",Str "&",Str "T"] ("http://att.com/","AT&T"),Str "."]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
+, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
+, Header 2 [Str "Autolinks"]
+, Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link [Code "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
+, BulletList
+ [ [ Plain [Str "In",Space,Str "a",Space,Str "list?"] ]
+ , [ Plain [Link [Code "http://example.com/"] ("http://example.com/","")] ]
+ , [ Plain [Str "It",Space,Str "should",Str "."] ] ]
+, Para [Str "An",Space,Str "e",Str "-",Str "mail",Space,Str "address:",Space,Link [Code "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")]
+, BlockQuote
+ [ Para [Str "Blockquoted:",Space,Link [Code "http://example.com/"] ("http://example.com/","")] ]
+
+, Para [Str "Auto",Str "-",Str "links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code "<http://example.com/>"]
+, CodeBlock ("",[],[]) "or here: <http://example.com/>"
+, HorizontalRule
+, Header 1 [Str "Images"]
+, Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
+, Para [Image [Str "lalune"] ("lalune.jpg","Voyage dans la Lune")]
+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] ("movie.jpg",""),Space,Str "icon",Str "."]
+, HorizontalRule
+, Header 1 [Str "Footnotes"]
+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote",Str ".",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",Space,Str "reference",Str ".",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document",Str "."]],Space,Str "and",Space,Str "another",Str ".",Note [Para [Str "Here",Apostrophe,Str "s",Space,Str "the",Space,Str "long",Space,Str "note",Str ".",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks",Str "."],Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)",Str "."],CodeBlock ("",[],[]) " { <code> }",Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",Space,Str "lazy",Space,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block",Str "."]],Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space",Str ".",Str "[",Str "^",Str "my",Space,Str "note",Str "]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",Space,Str "note",Str ".",Note [Para [Str "This",Space,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type",Str ".",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",Space,Link [Str "links"] ("http://google.com",""),Space,Str "and",Space,Code "]",Space,Str "verbatim",Space,Str "characters,",Space,Str "as",Space,Str "well",Space,Str "as",Space,Str "[",Str "bracketed",Space,Str "text",Str "]",Str "."]]]
+, BlockQuote
+ [ Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes",Str ".",Note [Para [Str "In",Space,Str "quote",Str "."]]] ]
+
+, OrderedList (1,Decimal,Period)
+ [ [ Plain [Str "And",Space,Str "in",Space,Str "list",Space,Str "items",Str ".",Note [Para [Str "In",Space,Str "list",Str "."]]] ]
+ ]
+, Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented",Str "."] ]
+
diff --git a/tests/writer.opendocument b/tests/writer.opendocument
new file mode 100644
index 000000000..587f9efe0
--- /dev/null
+++ b/tests/writer.opendocument
@@ -0,0 +1,1576 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" office:version="1.0">
+ <office:scripts />
+ <office:font-face-decls>
+ <style:font-face style:name="&amp;apos;Lucida Sans Unicode&amp;apos;" svg:font-family="Lucida Sans Unicode" />
+ <style:font-face style:name="&amp;apos;Tahoma&amp;apos;" svg:font-family="Tahoma" />
+ <style:font-face style:name="&amp;apos;Times New Roman&amp;apos;" svg:font-family="Times New Roman" />
+ </office:font-face-decls>
+ <office:automatic-styles>
+ <text:list-style style:name="L1">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L2">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L3">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L4">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L5">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L6">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L7">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L8">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L9">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L10">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L11">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L12">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L13">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L14">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L15">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L16">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L17">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L18">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L19">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L20">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L21">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L22">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="2" style:num-prefix="(" style:num-suffix=")">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-format="i" text:start-value="4" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-format="A" text:start-value="1" style:num-prefix="(" style:num-suffix=")">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L23">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="A" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-format="I" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="6" style:num-prefix="(" style:num-suffix=")">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-format="a" text:start-value="3" style:num-suffix=")">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L24">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L25">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L26">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L27">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L28">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
+ <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L29">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <style:style style:name="T1" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T2" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T3" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T4" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T5" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T6" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T7" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T8" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T9" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T10" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T11" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T12" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T13" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T14" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T15" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T16" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T17" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T18" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T19" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T20" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T21" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T22" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T23" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T24" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T25" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T26" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T27" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T28" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T29" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T30" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T31" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T32" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T33" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T34" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T35" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T36" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T37" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T38" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T39" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T40" style:family="text"><style:text-properties style:text-line-through-style="solid" /></style:style>
+ <style:style style:name="T41" style:family="text"><style:text-properties style:text-line-through-style="solid" /></style:style>
+ <style:style style:name="T42" style:family="text"><style:text-properties style:text-line-through-style="solid" /></style:style>
+ <style:style style:name="T43" style:family="text"><style:text-properties style:text-line-through-style="solid" /></style:style>
+ <style:style style:name="T44" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" style:text-line-through-style="solid" /></style:style>
+ <style:style style:name="T45" style:family="text"><style:text-properties style:text-line-through-style="solid" /></style:style>
+ <style:style style:name="T46" style:family="text"><style:text-properties style:text-position="super 58%" /></style:style>
+ <style:style style:name="T47" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" style:text-position="super 58%" /></style:style>
+ <style:style style:name="T48" style:family="text"><style:text-properties style:text-position="super 58%" /></style:style>
+ <style:style style:name="T49" style:family="text"><style:text-properties style:text-position="super 58%" /></style:style>
+ <style:style style:name="T50" style:family="text"><style:text-properties style:text-position="super 58%" /></style:style>
+ <style:style style:name="T51" style:family="text"><style:text-properties style:text-position="sub 58%" /></style:style>
+ <style:style style:name="T52" style:family="text"><style:text-properties style:text-position="sub 58%" /></style:style>
+ <style:style style:name="T53" style:family="text"><style:text-properties style:text-position="sub 58%" /></style:style>
+ <style:style style:name="T54" style:family="text"><style:text-properties style:text-position="sub 58%" /></style:style>
+ <style:style style:name="T55" style:family="text"><style:text-properties style:text-position="sub 58%" /></style:style>
+ <style:style style:name="T56" style:family="text"><style:text-properties style:text-position="sub 58%" /></style:style>
+ <style:style style:name="T57" style:family="text"><style:text-properties style:text-position="sub 58%" /></style:style>
+ <style:style style:name="T58" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T59" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T60" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T61" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T62" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T63" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T64" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T65" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" style:text-position="sub 58%" /></style:style>
+ <style:style style:name="T66" style:family="text"><style:text-properties style:text-position="sub 58%" /></style:style>
+ <style:style style:name="T67" style:family="text"><style:text-properties style:text-position="sub 58%" /></style:style>
+ <style:style style:name="T68" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T69" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T70" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T71" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T72" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T73" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T74" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T75" style:family="text"><style:text-properties style:text-position="super 58%" /></style:style>
+ <style:style style:name="T76" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T77" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T78" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T79" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T80" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T81" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T82" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T83" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T84" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T85" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P3" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P4" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P5" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P6" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L1">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P7" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="1.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P8" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="1.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P9" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P10" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P11" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P12" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P13" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P14" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P15" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P16" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P17" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P18" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P19" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L2">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P20" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L3">
+ </style:style>
+ <style:style style:name="P21" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L4">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P22" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L5">
+ </style:style>
+ <style:style style:name="P23" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L6">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P24" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L7">
+ </style:style>
+ <style:style style:name="P25" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L8">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P26" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L9">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P27" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L10">
+ </style:style>
+ <style:style style:name="P28" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L11">
+ </style:style>
+ <style:style style:name="P29" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L12">
+ </style:style>
+ <style:style style:name="P30" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L13">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P31" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L14">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P32" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L15">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P33" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L16">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P34" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L17">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P35" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L18">
+ </style:style>
+ <style:style style:name="P36" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L19">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P37" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L20">
+ </style:style>
+ <style:style style:name="P38" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L21">
+ </style:style>
+ <style:style style:name="P39" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L22">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P40" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L23">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P41" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L24">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P42" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P43" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P44" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P45" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P46" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P47" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P48" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P49" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P50" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L25">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P51" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L26">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P52" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L27">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P53" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P54" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L28">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P55" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P56" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P57" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P58" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P59" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L29">
+ <style:paragraph-properties fo:margin-left="0.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Pandoc
+ Test Suite</text:h>
+ <text:p text:style-name="Author">John MacFarlane</text:p>
+ <text:p text:style-name="Author"> Anonymous</text:p>
+ <text:p text:style-name="Date">July 17, 2006</text:p>
+ <text:p text:style-name="Text_20_body">This is a set of tests for
+ pandoc. Most of them are adapted from John
+ Gruber&#8217;s markdown test suite.</text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Headers</text:h>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2">Level
+ 2 with an
+ <text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition">embedded link</text:span></text:a></text:h>
+ <text:h text:style-name="Heading_20_3" text:outline-level="3">Level
+ 3 with
+ <text:span text:style-name="T1">emphasis</text:span></text:h>
+ <text:h text:style-name="Heading_20_4" text:outline-level="4">Level
+ 4</text:h>
+ <text:h text:style-name="Heading_20_5" text:outline-level="5">Level
+ 5</text:h>
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Level
+ 1</text:h>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2">Level
+ 2 with
+ <text:span text:style-name="T2">emphasis</text:span></text:h>
+ <text:h text:style-name="Heading_20_3" text:outline-level="3">Level
+ 3</text:h>
+ <text:p text:style-name="Text_20_body">with no blank line</text:p>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2">Level
+ 2</text:h>
+ <text:p text:style-name="Text_20_body">with no blank line</text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Paragraphs</text:h>
+ <text:p text:style-name="Text_20_body">Here&#8217;s a regular
+ paragraph.</text:p>
+ <text:p text:style-name="Text_20_body">In Markdown 1.0.0 and
+ earlier. Version 8. This line turns into a list item.
+ Because a hard-wrapped line in the middle of a
+ paragraph looked like a list item.</text:p>
+ <text:p text:style-name="Text_20_body">Here&#8217;s one with a
+ bullet. * criminey.</text:p>
+ <text:p text:style-name="Text_20_body">There should be a hard line
+ break<text:line-break />here.</text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Block
+ Quotes</text:h>
+ <text:p text:style-name="Text_20_body">E-mail style:</text:p>
+ <text:p text:style-name="P1">This is a block quote. It is pretty short.</text:p>
+ <text:p text:style-name="P2">Code in a block quote:</text:p>
+ <text:p text:style-name="P3">sub status {</text:p>
+ <text:p text:style-name="P4"><text:s text:c="4" />print &quot;working&quot;;</text:p>
+ <text:p text:style-name="P5">}</text:p>
+ <text:p text:style-name="P2">A list:</text:p>
+ <text:list text:style-name="L1">
+ <text:list-item>
+ <text:p text:style-name="P6">item one</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P6">item two</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="P2">Nested block quotes:</text:p>
+ <text:p text:style-name="P7">nested</text:p>
+ <text:p text:style-name="P8">nested</text:p>
+ <text:p text:style-name="Text_20_body">This should not be a block
+ quote: 2 &gt; 1.</text:p>
+ <text:p text:style-name="Text_20_body">And a following
+ paragraph.</text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Code
+ Blocks</text:h>
+ <text:p text:style-name="Text_20_body">Code:</text:p>
+ <text:p text:style-name="P9">---- (should be four hyphens)</text:p>
+ <text:p text:style-name="P10"></text:p>
+ <text:p text:style-name="P11">sub status {</text:p>
+ <text:p text:style-name="P12"><text:s text:c="4" />print &quot;working&quot;;</text:p>
+ <text:p text:style-name="P13">}</text:p>
+ <text:p text:style-name="P14"></text:p>
+ <text:p text:style-name="P15">this code block is indented by one tab</text:p>
+ <text:p text:style-name="Text_20_body">And:</text:p>
+ <text:p text:style-name="P16"><text:s text:c="4" />this code block is indented by two tabs</text:p>
+ <text:p text:style-name="P17"></text:p>
+ <text:p text:style-name="P18">These should not be escaped: <text:s text:c="1" />\$ \\ \&gt; \[ \{</text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Lists</text:h>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2">Unordered</text:h>
+ <text:p text:style-name="Text_20_body">Asterisks tight:</text:p>
+ <text:list text:style-name="L2">
+ <text:list-item>
+ <text:p text:style-name="P19">asterisk 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P19">asterisk 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P19">asterisk 3</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Asterisks loose:</text:p>
+ <text:list text:style-name="L3">
+ <text:list-item>
+ <text:p text:style-name="P20">asterisk 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P20">asterisk 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P20">asterisk 3</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Pluses tight:</text:p>
+ <text:list text:style-name="L4">
+ <text:list-item>
+ <text:p text:style-name="P21">Plus 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P21">Plus 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P21">Plus 3</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Pluses loose:</text:p>
+ <text:list text:style-name="L5">
+ <text:list-item>
+ <text:p text:style-name="P22">Plus 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P22">Plus 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P22">Plus 3</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Minuses tight:</text:p>
+ <text:list text:style-name="L6">
+ <text:list-item>
+ <text:p text:style-name="P23">Minus 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P23">Minus 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P23">Minus 3</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Minuses loose:</text:p>
+ <text:list text:style-name="L7">
+ <text:list-item>
+ <text:p text:style-name="P24">Minus 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P24">Minus 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P24">Minus 3</text:p>
+ </text:list-item>
+ </text:list>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2">Ordered</text:h>
+ <text:p text:style-name="Text_20_body">Tight:</text:p>
+ <text:list text:style-name="L8">
+ <text:list-item>
+ <text:p text:style-name="P25">First</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P25">Second</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P25">Third</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">and:</text:p>
+ <text:list text:style-name="L9">
+ <text:list-item>
+ <text:p text:style-name="P26">One</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P26">Two</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P26">Three</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Loose using tabs:</text:p>
+ <text:list text:style-name="L10">
+ <text:list-item>
+ <text:p text:style-name="P27">First</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P27">Second</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P27">Third</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">and using spaces:</text:p>
+ <text:list text:style-name="L11">
+ <text:list-item>
+ <text:p text:style-name="P28">One</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P28">Two</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P28">Three</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Multiple
+ paragraphs:</text:p>
+ <text:list text:style-name="L12">
+ <text:list-item>
+ <text:p text:style-name="P29">Item 1, graf one.</text:p>
+ <text:p text:style-name="P29">Item 1. graf two. The quick brown fox jumped over the lazy dog&#8217;s back.</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P29">Item 2.</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P29">Item 3.</text:p>
+ </text:list-item>
+ </text:list>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2">Nested</text:h>
+ <text:list text:style-name="L13">
+ <text:list-item>
+ <text:p text:style-name="P30">Tab</text:p>
+ <text:list text:style-name="L14">
+ <text:list-item>
+ <text:p text:style-name="P31">Tab</text:p>
+ <text:list text:style-name="L15">
+ <text:list-item>
+ <text:p text:style-name="P32">Tab</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Here&#8217;s
+ another:</text:p>
+ <text:list text:style-name="L16">
+ <text:list-item>
+ <text:p text:style-name="P33">First</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P33">Second:</text:p>
+ <text:list text:style-name="L17">
+ <text:list-item>
+ <text:p text:style-name="P34">Fee</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P34">Fie</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P34">Foe</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P33">Third</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Same thing but with
+ paragraphs:</text:p>
+ <text:list text:style-name="L18">
+ <text:list-item>
+ <text:p text:style-name="P35">First</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P35">Second:</text:p>
+ <text:list text:style-name="L19">
+ <text:list-item>
+ <text:p text:style-name="P36">Fee</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P36">Fie</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P36">Foe</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P35">Third</text:p>
+ </text:list-item>
+ </text:list>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2">Tabs
+ and spaces</text:h>
+ <text:list text:style-name="L20">
+ <text:list-item>
+ <text:p text:style-name="P37">this is a list item indented with tabs</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P37">this is a list item indented with spaces</text:p>
+ <text:list text:style-name="L21">
+ <text:list-item>
+ <text:p text:style-name="P38">this is an example list item indented with tabs</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P38">this is an example list item indented with spaces</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2">Fancy
+ list markers</text:h>
+ <text:list text:style-name="L22">
+ <text:list-item>
+ <text:p text:style-name="P39">begins with 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P39">and now 3</text:p>
+ <text:p text:style-name="P39">with a continuation</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P39">sublist with roman numerals, starting with 4</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P39">more items</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P39">a subsublist</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P39">a subsublist</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Nesting:</text:p>
+ <text:list text:style-name="L23">
+ <text:list-item>
+ <text:p text:style-name="P40">Upper Alpha</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P40">Upper Roman.</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P40">Decimal start with 6</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P40">Lower alpha with paren</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Autonumbering:</text:p>
+ <text:list text:style-name="L24">
+ <text:list-item>
+ <text:p text:style-name="P41">Autonumber.</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P41">More.</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P41">Nested.</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Should not be a list
+ item:</text:p>
+ <text:p text:style-name="Text_20_body">M.A.&#160;2007</text:p>
+ <text:p text:style-name="Text_20_body">B. Williams</text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Definition
+ Lists</text:h>
+ <text:p text:style-name="Text_20_body">Tight using spaces:</text:p>
+ <text:p text:style-name="Definition_20_Term_20_Tight">apple</text:p>
+ <text:p text:style-name="Definition_20_Definition_20_Tight">red fruit</text:p>
+ <text:p text:style-name="Definition_20_Term_20_Tight">orange</text:p>
+ <text:p text:style-name="Definition_20_Definition_20_Tight">orange fruit</text:p>
+ <text:p text:style-name="Definition_20_Term_20_Tight">banana</text:p>
+ <text:p text:style-name="Definition_20_Definition_20_Tight">yellow fruit</text:p>
+ <text:p text:style-name="Text_20_body">Tight using tabs:</text:p>
+ <text:p text:style-name="Definition_20_Term_20_Tight">apple</text:p>
+ <text:p text:style-name="Definition_20_Definition_20_Tight">red fruit</text:p>
+ <text:p text:style-name="Definition_20_Term_20_Tight">orange</text:p>
+ <text:p text:style-name="Definition_20_Definition_20_Tight">orange fruit</text:p>
+ <text:p text:style-name="Definition_20_Term_20_Tight">banana</text:p>
+ <text:p text:style-name="Definition_20_Definition_20_Tight">yellow fruit</text:p>
+ <text:p text:style-name="Text_20_body">Loose:</text:p>
+ <text:p text:style-name="Definition_20_Term">apple</text:p>
+ <text:p text:style-name="Definition_20_Definition">red fruit</text:p>
+ <text:p text:style-name="Definition_20_Term">orange</text:p>
+ <text:p text:style-name="Definition_20_Definition">orange fruit</text:p>
+ <text:p text:style-name="Definition_20_Term">banana</text:p>
+ <text:p text:style-name="Definition_20_Definition">yellow fruit</text:p>
+ <text:p text:style-name="Text_20_body">Multiple blocks with
+ italics:</text:p>
+ <text:p text:style-name="Definition_20_Term"><text:span text:style-name="T3">apple</text:span></text:p>
+ <text:p text:style-name="Definition_20_Definition">red fruit</text:p>
+ <text:p text:style-name="Definition_20_Definition">contains seeds, crisp, pleasant to taste</text:p>
+ <text:p text:style-name="Definition_20_Term"><text:span text:style-name="T4">orange</text:span></text:p>
+ <text:p text:style-name="Definition_20_Definition">orange fruit</text:p>
+ <text:p text:style-name="P42">{ orange code block }</text:p>
+ <text:p text:style-name="P43">orange block quote</text:p>
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">HTML
+ Blocks</text:h>
+ <text:p text:style-name="Text_20_body">Simple block on one
+ line:</text:p>
+ <text:p text:style-name="Text_20_body">foo</text:p>
+ <text:p text:style-name="Text_20_body">And nested without
+ indentation:</text:p>
+ <text:p text:style-name="Text_20_body">foo</text:p>
+ <text:p text:style-name="Text_20_body">bar</text:p>
+ <text:p text:style-name="Text_20_body">Interpreted markdown in a
+ table:</text:p>
+ <text:p text:style-name="Text_20_body">This is
+ <text:span text:style-name="T5">emphasized</text:span></text:p>
+ <text:p text:style-name="Text_20_body">And this is
+ <text:span text:style-name="T6">strong</text:span></text:p>
+ <text:p text:style-name="Text_20_body">Here&#8217;s a simple
+ block:</text:p>
+ <text:p text:style-name="Text_20_body">foo</text:p>
+ <text:p text:style-name="Text_20_body">This should be a code block,
+ though:</text:p>
+ <text:p text:style-name="P44">&lt;div&gt;</text:p>
+ <text:p text:style-name="P45"><text:s text:c="4" />foo</text:p>
+ <text:p text:style-name="P46">&lt;/div&gt;</text:p>
+ <text:p text:style-name="Text_20_body">As should this:</text:p>
+ <text:p text:style-name="P47">&lt;div&gt;foo&lt;/div&gt;</text:p>
+ <text:p text:style-name="Text_20_body">Now, nested:</text:p>
+ <text:p text:style-name="Text_20_body">foo</text:p>
+ <text:p text:style-name="Text_20_body">This should just be an HTML
+ comment:</text:p>
+ <text:p text:style-name="Text_20_body">Multiline:</text:p>
+ <text:p text:style-name="Text_20_body">Code block:</text:p>
+ <text:p text:style-name="P48">&lt;!-- Comment --&gt;</text:p>
+ <text:p text:style-name="Text_20_body">Just plain comment, with
+ trailing spaces on the line:</text:p>
+ <text:p text:style-name="Text_20_body">Code:</text:p>
+ <text:p text:style-name="P49">&lt;hr /&gt;</text:p>
+ <text:p text:style-name="Text_20_body">Hr&#8217;s:</text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Inline
+ Markup</text:h>
+ <text:p text:style-name="Text_20_body">This is
+ <text:span text:style-name="T7">emphasized</text:span>,
+ and so
+ <text:span text:style-name="T8">is</text:span><text:span text:style-name="T9"> </text:span><text:span text:style-name="T10">this</text:span>.</text:p>
+ <text:p text:style-name="Text_20_body">This is
+ <text:span text:style-name="T11">strong</text:span>,
+ and so
+ <text:span text:style-name="T12">is</text:span><text:span text:style-name="T13"> </text:span><text:span text:style-name="T14">this</text:span>.</text:p>
+ <text:p text:style-name="Text_20_body">An
+ <text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition"><text:span text:style-name="T15">emphasized</text:span><text:span text:style-name="T16"> </text:span><text:span text:style-name="T17">link</text:span></text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body"><text:span text:style-name="T18">This</text:span><text:span text:style-name="T19"> </text:span><text:span text:style-name="T20">is</text:span><text:span text:style-name="T21"> </text:span><text:span text:style-name="T22">strong</text:span><text:span text:style-name="T23"> </text:span><text:span text:style-name="T24">and</text:span><text:span text:style-name="T25"> </text:span><text:span text:style-name="T26">em</text:span><text:span text:style-name="T27">.</text:span></text:p>
+ <text:p text:style-name="Text_20_body">So is
+ <text:span text:style-name="T28">this</text:span>
+ word.</text:p>
+ <text:p text:style-name="Text_20_body"><text:span text:style-name="T29">This</text:span><text:span text:style-name="T30"> </text:span><text:span text:style-name="T31">is</text:span><text:span text:style-name="T32"> </text:span><text:span text:style-name="T33">strong</text:span><text:span text:style-name="T34"> </text:span><text:span text:style-name="T35">and</text:span><text:span text:style-name="T36"> </text:span><text:span text:style-name="T37">em</text:span><text:span text:style-name="T38">.</text:span></text:p>
+ <text:p text:style-name="Text_20_body">So is
+ <text:span text:style-name="T39">this</text:span>
+ word.</text:p>
+ <text:p text:style-name="Text_20_body">This is code:
+ <text:span text:style-name="Teletype">&gt;</text:span>,
+ <text:span text:style-name="Teletype">$</text:span>,
+ <text:span text:style-name="Teletype">\</text:span>,
+ <text:span text:style-name="Teletype">\$</text:span>,
+ <text:span text:style-name="Teletype">&lt;html&gt;</text:span>.</text:p>
+ <text:p text:style-name="Text_20_body"><text:span text:style-name="T40">This</text:span><text:span text:style-name="T41"> </text:span><text:span text:style-name="T42">is</text:span><text:span text:style-name="T43"> </text:span><text:span text:style-name="T44">strikeout</text:span><text:span text:style-name="T45">.</text:span></text:p>
+ <text:p text:style-name="Text_20_body">Superscripts:
+ a<text:span text:style-name="T46">bc</text:span>d
+ a<text:span text:style-name="T47">hello</text:span>
+ a<text:span text:style-name="T48">hello</text:span><text:span text:style-name="T49">&#160;</text:span><text:span text:style-name="T50">there</text:span>.</text:p>
+ <text:p text:style-name="Text_20_body">Subscripts:
+ H<text:span text:style-name="T51">2</text:span>O,
+ H<text:span text:style-name="T52">23</text:span>O,
+ H<text:span text:style-name="T53">many</text:span><text:span text:style-name="T54">&#160;</text:span><text:span text:style-name="T55">of</text:span><text:span text:style-name="T56">&#160;</text:span><text:span text:style-name="T57">them</text:span>O.</text:p>
+ <text:p text:style-name="Text_20_body">These should not be
+ superscripts or subscripts, because of the unescaped
+ spaces: a^b c^d, a~b c~d.</text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Smart
+ quotes, ellipses,
+ dashes</text:h>
+ <text:p text:style-name="Text_20_body">&#8220;Hello,&#8221; said
+ the spider.
+ &#8220;&#8216;Shelob&#8217; is my name.&#8221;</text:p>
+ <text:p text:style-name="Text_20_body">&#8216;A&#8217;,
+ &#8216;B&#8217;, and &#8216;C&#8217; are
+ letters.</text:p>
+ <text:p text:style-name="Text_20_body">&#8216;Oak,&#8217;
+ &#8216;elm,&#8217; and &#8216;beech&#8217; are names of
+ trees. So is &#8216;pine.&#8217;</text:p>
+ <text:p text:style-name="Text_20_body">&#8216;He said, &#8220;I want to go.&#8221;&#8217;
+ Were you alive in the 70&#8217;s?</text:p>
+ <text:p text:style-name="Text_20_body">Here is some quoted
+ &#8216;<text:span text:style-name="Teletype">code</text:span>&#8217;
+ and a
+ &#8220;<text:a xlink:type="simple" xlink:href="http://example.com/?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">quoted link</text:span></text:a>&#8221;.</text:p>
+ <text:p text:style-name="Text_20_body">Some dashes: one&#8212;two
+ &#8212; three&#8212;four &#8212; five.</text:p>
+ <text:p text:style-name="Text_20_body">Dashes between numbers:
+ 5&#8211;7, 255&#8211;66, 1987&#8211;1999.</text:p>
+ <text:p text:style-name="Text_20_body">Ellipses&#8230;and&#8230;and&#8230;.</text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">LaTeX</text:h>
+ <text:list text:style-name="L25">
+ <text:list-item>
+ <text:p text:style-name="P50"><text:span text:style-name="Teletype">\cite[22-23]{smith.1899}</text:span></text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P50">2+2=4</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P50"><text:span text:style-name="T58">x</text:span> ∈ <text:span text:style-name="T59">y</text:span></text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P50">α ∧ ω</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P50">223</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P50"><text:span text:style-name="T60">p</text:span>-Tree</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P50">Here&#8217;s some display math: \frac{<text:span text:style-name="T61">d</text:span>}{<text:span text:style-name="T62">dx</text:span>}<text:span text:style-name="T63">f</text:span>(<text:span text:style-name="T64">x</text:span>)=\lim<text:span text:style-name="T65">h</text:span><text:span text:style-name="T66"> → </text:span><text:span text:style-name="T67">0</text:span>\frac{<text:span text:style-name="T68">f</text:span>(<text:span text:style-name="T69">x</text:span>+<text:span text:style-name="T70">h</text:span>)-<text:span text:style-name="T71">f</text:span>(<text:span text:style-name="T72">x</text:span>)}{<text:span text:style-name="T73">h</text:span>}</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P50">Here&#8217;s one that has a line break in it: α+ω × <text:span text:style-name="T74">x</text:span><text:span text:style-name="T75">2</text:span>.</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">These shouldn&#8217;t be
+ math:</text:p>
+ <text:list text:style-name="L26">
+ <text:list-item>
+ <text:p text:style-name="P51">To get the famous equation, write <text:span text:style-name="Teletype">$e = mc^2$</text:span>.</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P51">$22,000 is a <text:span text:style-name="T76">lot</text:span> of money. So is $34,000. (It worked if &#8220;lot&#8221; is emphasized.)</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P51">Shoes ($20) and socks ($5).</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P51">Escaped <text:span text:style-name="Teletype">$</text:span>: $73 <text:span text:style-name="T77">this</text:span><text:span text:style-name="T78"> </text:span><text:span text:style-name="T79">should</text:span><text:span text:style-name="T80"> </text:span><text:span text:style-name="T81">be</text:span><text:span text:style-name="T82"> </text:span><text:span text:style-name="T83">emphasized</text:span> 23$.</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">Here&#8217;s a LaTeX
+ table:</text:p>
+ <text:p text:style-name="Text_20_body"><text:span text:style-name="Teletype">\begin{tabular}{|l|l|}\hline
+Animal &amp; Number \\ \hline
+Dog <text:s text:c="3" />&amp; 2 <text:s text:c="5" />\\
+Cat <text:s text:c="3" />&amp; 1 <text:s text:c="5" />\\ \hline
+\end{tabular}</text:span></text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Special
+ Characters</text:h>
+ <text:p text:style-name="Text_20_body">Here is some
+ unicode:</text:p>
+ <text:list text:style-name="L27">
+ <text:list-item>
+ <text:p text:style-name="P52">I hat: Î</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P52">o umlaut: ö</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P52">section: §</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P52">set membership: ∈</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P52">copyright: ©</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">AT&amp;T has an ampersand in
+ their name.</text:p>
+ <text:p text:style-name="Text_20_body">AT&amp;T is another way to
+ write it.</text:p>
+ <text:p text:style-name="Text_20_body">This &amp; that.</text:p>
+ <text:p text:style-name="Text_20_body">4 &lt; 5.</text:p>
+ <text:p text:style-name="Text_20_body">6 &gt; 5.</text:p>
+ <text:p text:style-name="Text_20_body">Backslash: \</text:p>
+ <text:p text:style-name="Text_20_body">Backtick: `</text:p>
+ <text:p text:style-name="Text_20_body">Asterisk: *</text:p>
+ <text:p text:style-name="Text_20_body">Underscore: _</text:p>
+ <text:p text:style-name="Text_20_body">Left brace: {</text:p>
+ <text:p text:style-name="Text_20_body">Right brace: }</text:p>
+ <text:p text:style-name="Text_20_body">Left bracket: [</text:p>
+ <text:p text:style-name="Text_20_body">Right bracket: ]</text:p>
+ <text:p text:style-name="Text_20_body">Left paren: (</text:p>
+ <text:p text:style-name="Text_20_body">Right paren: )</text:p>
+ <text:p text:style-name="Text_20_body">Greater-than: &gt;</text:p>
+ <text:p text:style-name="Text_20_body">Hash: #</text:p>
+ <text:p text:style-name="Text_20_body">Period: .</text:p>
+ <text:p text:style-name="Text_20_body">Bang: !</text:p>
+ <text:p text:style-name="Text_20_body">Plus: +</text:p>
+ <text:p text:style-name="Text_20_body">Minus: -</text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Links</text:h>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2">Explicit</text:h>
+ <text:p text:style-name="Text_20_body">Just a
+ <text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">URL</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title"><text:span text:style-name="Definition">URL and title</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title preceded by two spaces"><text:span text:style-name="Definition">URL and title</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title preceded by a tab"><text:span text:style-name="Definition">URL and title</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title with &quot;quotes&quot; in it"><text:span text:style-name="Definition">URL and title</text:span></text:a></text:p>
+ <text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title with single quotes"><text:span text:style-name="Definition">URL and title</text:span></text:a></text:p>
+ <text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/with_underscore" office:name=""><text:span text:style-name="Definition">with_underscore</text:span></text:a></text:p>
+ <text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="mailto:nobody@nowhere.net" office:name=""><text:span text:style-name="Definition">Email link</text:span></text:a></text:p>
+ <text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="" office:name=""><text:span text:style-name="Definition">Empty</text:span></text:a>.</text:p>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2">Reference</text:h>
+ <text:p text:style-name="Text_20_body">Foo
+ <text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body">Foo
+ <text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body">Foo
+ <text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body">With
+ <text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">embedded [brackets]</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">b</text:span></text:a>
+ by itself should be a link.</text:p>
+ <text:p text:style-name="Text_20_body">Indented
+ <text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition">once</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body">Indented
+ <text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition">twice</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body">Indented
+ <text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition">thrice</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body">This should [not][] be a
+ link.</text:p>
+ <text:p text:style-name="P53">[not]: /url</text:p>
+ <text:p text:style-name="Text_20_body">Foo
+ <text:a xlink:type="simple" xlink:href="/url/" office:name="Title with &quot;quotes&quot; inside"><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body">Foo
+ <text:a xlink:type="simple" xlink:href="/url/" office:name="Title with &quot;quote&quot; inside"><text:span text:style-name="Definition">biz</text:span></text:a>.</text:p>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2">With
+ ampersands</text:h>
+ <text:p text:style-name="Text_20_body">Here&#8217;s a
+ <text:a xlink:type="simple" xlink:href="http://example.com/?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">link with an ampersand in the URL</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body">Here&#8217;s a link with an
+ amersand in the link text:
+ <text:a xlink:type="simple" xlink:href="http://att.com/" office:name="AT&amp;T"><text:span text:style-name="Definition">AT&amp;T</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body">Here&#8217;s an
+ <text:a xlink:type="simple" xlink:href="/script?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">inline link</text:span></text:a>.</text:p>
+ <text:p text:style-name="Text_20_body">Here&#8217;s an
+ <text:a xlink:type="simple" xlink:href="/script?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">inline link in pointy braces</text:span></text:a>.</text:p>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2">Autolinks</text:h>
+ <text:p text:style-name="Text_20_body">With an ampersand:
+ <text:a xlink:type="simple" xlink:href="http://example.com/?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition"><text:span text:style-name="Teletype">http://example.com/?foo=1&amp;bar=2</text:span></text:span></text:a></text:p>
+ <text:list text:style-name="L28">
+ <text:list-item>
+ <text:p text:style-name="P54">In a list?</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P54"><text:a xlink:type="simple" xlink:href="http://example.com/" office:name=""><text:span text:style-name="Definition"><text:span text:style-name="Teletype">http://example.com/</text:span></text:span></text:a></text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P54">It should.</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">An e-mail address:
+ <text:a xlink:type="simple" xlink:href="mailto:nobody@nowhere.net" office:name=""><text:span text:style-name="Definition"><text:span text:style-name="Teletype">nobody@nowhere.net</text:span></text:span></text:a></text:p>
+ <text:p text:style-name="P55">Blockquoted: <text:a xlink:type="simple" xlink:href="http://example.com/" office:name=""><text:span text:style-name="Definition"><text:span text:style-name="Teletype">http://example.com/</text:span></text:span></text:a></text:p>
+ <text:p text:style-name="Text_20_body">Auto-links should not occur
+ here:
+ <text:span text:style-name="Teletype">&lt;http://example.com/&gt;</text:span></text:p>
+ <text:p text:style-name="P56">or here: &lt;http://example.com/&gt;</text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Images</text:h>
+ <text:p text:style-name="Text_20_body">From
+ &#8220;Voyage dans la Lune&#8221; by Georges Melies
+ (1902):</text:p>
+ <text:p text:style-name="Text_20_body"><draw:frame><draw:image xlink:href="lalune.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" /></draw:frame></text:p>
+ <text:p text:style-name="Text_20_body">Here is a movie
+ <draw:frame><draw:image xlink:href="movie.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" /></draw:frame>
+ icon.</text:p>
+ <text:p text:style-name="Horizontal_20_Line" />
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Footnotes</text:h>
+ <text:p text:style-name="Text_20_body">Here is a footnote
+ reference,<text:note text:id="ftn0" text:note-class="footnote"><text:note-citation>1</text:note-citation>
+ <text:note-body><text:p text:style-name="Footnote">Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.</text:p></text:note-body></text:note>
+ and
+ another.<text:note text:id="ftn1" text:note-class="footnote"><text:note-citation>2</text:note-citation>
+ <text:note-body><text:p text:style-name="Footnote">Here&#8217;s the long note. This one contains multiple blocks.</text:p>
+ <text:p text:style-name="Footnote">Subsequent blocks are indented to show that they belong to the footnote (as with list items).</text:p>
+ <text:p text:style-name="P57"><text:s text:c="2" />{ &lt;code&gt; }</text:p>
+ <text:p text:style-name="Footnote">If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.</text:p></text:note-body></text:note>
+ This should
+ <text:span text:style-name="T84">not</text:span> be a
+ footnote reference, because it contains a space.[^my
+ note] Here is an inline
+ note.<text:note text:id="ftn2" text:note-class="footnote"><text:note-citation>3</text:note-citation>
+ <text:note-body><text:p text:style-name="Footnote">This is <text:span text:style-name="T85">easier</text:span> to type. Inline notes may contain <text:a xlink:type="simple" xlink:href="http://google.com" office:name=""><text:span text:style-name="Definition">links</text:span></text:a> and <text:span text:style-name="Teletype">]</text:span> verbatim characters, as well as [bracketed text].</text:p></text:note-body></text:note></text:p>
+ <text:p text:style-name="P58">Notes can go in quotes.<text:note text:id="ftn3" text:note-class="footnote"><text:note-citation>4</text:note-citation>
+ <text:note-body><text:p text:style-name="Footnote">In quote.</text:p></text:note-body></text:note></text:p>
+ <text:list text:style-name="L29">
+ <text:list-item>
+ <text:p text:style-name="P59">And in list items.<text:note text:id="ftn4" text:note-class="footnote"><text:note-citation>5</text:note-citation>
+ <text:note-body><text:p text:style-name="Footnote">In list.</text:p></text:note-body></text:note></text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="Text_20_body">This paragraph should not be
+ part of the note, as it is not indented.</text:p>
+ </office:text>
+ </office:body>
+
+</office:document-content>
diff --git a/tests/writer.rst b/tests/writer.rst
new file mode 100644
index 000000000..408ca357c
--- /dev/null
+++ b/tests/writer.rst
@@ -0,0 +1,852 @@
+=================
+Pandoc Test Suite
+=================
+
+:Author: John MacFarlane
+:Author: Anonymous
+:Date: July 17, 2006
+
+.. role:: math(raw)
+ :format: html latex
+
+This is a set of tests for pandoc. Most of them are adapted from
+John Gruber's markdown test suite.
+
+--------------
+
+Headers
+=======
+
+Level 2 with an `embedded link </url>`_
+---------------------------------------
+
+Level 3 with *emphasis*
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Level 4
+^^^^^^^
+
+Level 5
+'''''''
+
+Level 1
+=======
+
+Level 2 with *emphasis*
+-----------------------
+
+Level 3
+~~~~~~~
+
+with no blank line
+
+Level 2
+-------
+
+with no blank line
+
+--------------
+
+Paragraphs
+==========
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a
+list item. Because a hard-wrapped line in the middle of a paragraph
+looked like a list item.
+
+Here's one with a bullet. \* criminey.
+
+There should be a hard line break
+here.
+
+--------------
+
+Block Quotes
+============
+
+E-mail style:
+
+ This is a block quote. It is pretty short.
+
+
+ Code in a block quote:
+
+ ::
+
+ sub status {
+ print "working";
+ }
+
+ A list:
+
+
+ 1. item one
+ 2. item two
+
+ Nested block quotes:
+
+ nested
+
+
+ nested
+
+
+
+This should not be a block quote: 2 > 1.
+
+And a following paragraph.
+
+--------------
+
+Code Blocks
+===========
+
+Code:
+
+::
+
+ ---- (should be four hyphens)
+
+ sub status {
+ print "working";
+ }
+
+ this code block is indented by one tab
+
+And:
+
+::
+
+ this code block is indented by two tabs
+
+ These should not be escaped: \$ \\ \> \[ \{
+
+--------------
+
+Lists
+=====
+
+Unordered
+---------
+
+Asterisks tight:
+
+
+- asterisk 1
+- asterisk 2
+- asterisk 3
+
+Asterisks loose:
+
+
+- asterisk 1
+
+- asterisk 2
+
+- asterisk 3
+
+
+Pluses tight:
+
+
+- Plus 1
+- Plus 2
+- Plus 3
+
+Pluses loose:
+
+
+- Plus 1
+
+- Plus 2
+
+- Plus 3
+
+
+Minuses tight:
+
+
+- Minus 1
+- Minus 2
+- Minus 3
+
+Minuses loose:
+
+
+- Minus 1
+
+- Minus 2
+
+- Minus 3
+
+
+Ordered
+-------
+
+Tight:
+
+
+1. First
+2. Second
+3. Third
+
+and:
+
+
+1. One
+2. Two
+3. Three
+
+Loose using tabs:
+
+
+1. First
+
+2. Second
+
+3. Third
+
+
+and using spaces:
+
+
+1. One
+
+2. Two
+
+3. Three
+
+
+Multiple paragraphs:
+
+
+1. Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's
+ back.
+
+2. Item 2.
+
+3. Item 3.
+
+
+Nested
+------
+
+
+- Tab
+
+ - Tab
+
+ - Tab
+
+
+
+Here's another:
+
+
+1. First
+2. Second:
+
+ - Fee
+ - Fie
+ - Foe
+
+3. Third
+
+Same thing but with paragraphs:
+
+
+1. First
+
+2. Second:
+
+
+ - Fee
+ - Fie
+ - Foe
+
+3. Third
+
+
+Tabs and spaces
+---------------
+
+
+- this is a list item indented with tabs
+
+- this is a list item indented with spaces
+
+
+ - this is an example list item indented with tabs
+
+ - this is an example list item indented with spaces
+
+
+
+Fancy list markers
+------------------
+
+
+(2) begins with 2
+(3) and now 3
+
+ with a continuation
+
+
+ iv. sublist with roman numerals, starting with 4
+ v. more items
+
+ (A) a subsublist
+ (B) a subsublist
+
+
+
+Nesting:
+
+
+A. Upper Alpha
+
+ I. Upper Roman.
+
+ (6) Decimal start with 6
+
+ c) Lower alpha with paren
+
+
+
+
+Autonumbering:
+
+
+#. Autonumber.
+#. More.
+
+ #. Nested.
+
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+--------------
+
+Definition Lists
+================
+
+Tight using spaces:
+
+apple
+ red fruit
+orange
+ orange fruit
+banana
+ yellow fruit
+
+Tight using tabs:
+
+apple
+ red fruit
+orange
+ orange fruit
+banana
+ yellow fruit
+
+Loose:
+
+apple
+ red fruit
+
+orange
+ orange fruit
+
+banana
+ yellow fruit
+
+
+Multiple blocks with italics:
+
+*apple*
+ red fruit
+
+ contains seeds, crisp, pleasant to taste
+
+*orange*
+ orange fruit
+
+ ::
+
+ { orange code block }
+
+ orange block quote
+
+
+
+HTML Blocks
+===========
+
+Simple block on one line:
+
+
+.. raw:: html
+
+ <div>
+
+foo
+
+.. raw:: html
+
+ </div>
+
+And nested without indentation:
+
+
+.. raw:: html
+
+ <div>
+ <div>
+ <div>
+
+foo
+
+.. raw:: html
+
+ </div>
+ </div>
+ <div>
+
+bar
+
+.. raw:: html
+
+ </div>
+ </div>
+
+Interpreted markdown in a table:
+
+
+.. raw:: html
+
+ <table>
+ <tr>
+ <td>
+
+This is *emphasized*
+
+.. raw:: html
+
+ </td>
+ <td>
+
+And this is **strong**
+
+.. raw:: html
+
+ </td>
+ </tr>
+ </table>
+
+ <script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+
+Here's a simple block:
+
+
+.. raw:: html
+
+ <div>
+
+
+foo
+
+.. raw:: html
+
+ </div>
+
+This should be a code block, though:
+
+::
+
+ <div>
+ foo
+ </div>
+
+As should this:
+
+::
+
+ <div>foo</div>
+
+Now, nested:
+
+
+.. raw:: html
+
+ <div>
+ <div>
+ <div>
+
+
+foo
+
+.. raw:: html
+
+ </div>
+ </div>
+ </div>
+
+This should just be an HTML comment:
+
+
+.. raw:: html
+
+ <!-- Comment -->
+
+Multiline:
+
+
+.. raw:: html
+
+ <!--
+ Blah
+ Blah
+ -->
+
+ <!--
+ This is another comment.
+ -->
+
+Code block:
+
+::
+
+ <!-- Comment -->
+
+Just plain comment, with trailing spaces on the line:
+
+
+.. raw:: html
+
+ <!-- foo -->
+
+Code:
+
+::
+
+ <hr />
+
+Hr's:
+
+
+.. raw:: html
+
+ <hr>
+
+ <hr />
+
+ <hr />
+
+ <hr>
+
+ <hr />
+
+ <hr />
+
+ <hr class="foo" id="bar" />
+
+ <hr class="foo" id="bar" />
+
+ <hr class="foo" id="bar">
+
+--------------
+
+Inline Markup
+=============
+
+This is *emphasized*, and so *is this*.
+
+This is **strong**, and so **is this**.
+
+An *`emphasized link </url>`_*.
+
+***This is strong and em.***
+
+So is ***this*** word.
+
+***This is strong and em.***
+
+So is ***this*** word.
+
+This is code: ``>``, ``$``, ``\``, ``\$``, ``<html>``.
+
+[STRIKEOUT:This is *strikeout*.]
+
+Superscripts: a\ :sup:`bc`\ d a\ :sup:`*hello*`\
+a\ :sup:`hello there`\ .
+
+Subscripts: H\ :sub:`2`\ O, H\ :sub:`23`\ O,
+H\ :sub:`many of them`\ O.
+
+These should not be superscripts or subscripts, because of the
+unescaped spaces: a^b c^d, a~b c~d.
+
+--------------
+
+Smart quotes, ellipses, dashes
+==============================
+
+"Hello," said the spider. "'Shelob' is my name."
+
+'A', 'B', and 'C' are letters.
+
+'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'
+
+'He said, "I want to go."' Were you alive in the 70's?
+
+Here is some quoted '``code``' and a
+"`quoted link <http://example.com/?foo=1&bar=2>`_".
+
+Some dashes: one--two -- three--four -- five.
+
+Dashes between numbers: 5-7, 255-66, 1987-1999.
+
+Ellipses...and...and....
+
+--------------
+
+LaTeX
+=====
+
+
+-
+- :math:`$2+2=4$`
+- :math:`$x \in y$`
+- :math:`$\alpha \wedge \omega$`
+- :math:`$223$`
+- :math:`$p$`-Tree
+- Here's some display math:
+ :math:`$$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$`
+- Here's one that has a line break in it:
+ :math:`$\alpha + \omega \times x^2$`.
+
+These shouldn't be math:
+
+
+- To get the famous equation, write ``$e = mc^2$``.
+- $22,000 is a *lot* of money. So is $34,000. (It worked if "lot"
+ is emphasized.)
+- Shoes ($20) and socks ($5).
+- Escaped ``$``: $73 *this should be emphasized* 23$.
+
+Here's a LaTeX table:
+
+
+
+--------------
+
+Special Characters
+==================
+
+Here is some unicode:
+
+
+- I hat: Î
+- o umlaut: ö
+- section: §
+- set membership: ∈
+- copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \\
+
+Backtick: \`
+
+Asterisk: \*
+
+Underscore: \_
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: >
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+--------------
+
+Links
+=====
+
+Explicit
+--------
+
+Just a `URL </url/>`_.
+
+`URL and title </url/>`_.
+
+`URL and title </url/>`_.
+
+`URL and title </url/>`_.
+
+`URL and title </url/>`_
+
+`URL and title </url/>`_
+
+`with\_underscore </url/with_underscore>`_
+
+`Email link <mailto:nobody@nowhere.net>`_
+
+`Empty <>`_.
+
+Reference
+---------
+
+Foo `bar </url/>`_.
+
+Foo `bar </url/>`_.
+
+Foo `bar </url/>`_.
+
+With `embedded [brackets] </url/>`_.
+
+`b </url/>`_ by itself should be a link.
+
+Indented `once </url>`_.
+
+Indented `twice </url>`_.
+
+Indented `thrice </url>`_.
+
+This should [not][] be a link.
+
+::
+
+ [not]: /url
+
+Foo `bar </url/>`_.
+
+Foo `biz </url/>`_.
+
+With ampersands
+---------------
+
+Here's a
+`link with an ampersand in the URL <http://example.com/?foo=1&bar=2>`_.
+
+Here's a link with an amersand in the link text:
+`AT&T <http://att.com/>`_.
+
+Here's an `inline link </script?foo=1&bar=2>`_.
+
+Here's an `inline link in pointy braces </script?foo=1&bar=2>`_.
+
+Autolinks
+---------
+
+With an ampersand: http://example.com/?foo=1&bar=2
+
+
+- In a list?
+- http://example.com/
+- It should.
+
+An e-mail address: nobody@nowhere.net
+
+ Blockquoted: http://example.com/
+
+
+Auto-links should not occur here: ``<http://example.com/>``
+
+::
+
+ or here: <http://example.com/>
+
+--------------
+
+Images
+======
+
+From "Voyage dans la Lune" by Georges Melies (1902):
+
+|lalune|
+
+Here is a movie |movie| icon.
+
+--------------
+
+Footnotes
+=========
+
+Here is a footnote reference, [1]_ and another. [2]_ This should
+*not* be a footnote reference, because it contains a space.[^my
+note] Here is an inline note. [3]_
+
+ Notes can go in quotes. [4]_
+
+
+
+1. And in list items. [5]_
+
+This paragraph should not be part of the note, as it is not
+indented.
+
+.. [1]
+ Here is the footnote. It can go anywhere after the footnote
+ reference. It need not be placed at the end of the document.
+
+.. [2]
+ Here's the long note. This one contains multiple blocks.
+
+ Subsequent blocks are indented to show that they belong to the
+ footnote (as with list items).
+
+ ::
+
+ { <code> }
+
+ If you want, you can indent every line, but you can also be lazy
+ and just indent the first line of each block.
+
+.. [3]
+ This is *easier* to type. Inline notes may contain
+ `links <http://google.com>`_ and ``]`` verbatim characters, as well
+ as [bracketed text].
+
+.. [4]
+ In quote.
+
+.. [5]
+ In list.
+
+
+.. |lalune| image:: lalune.jpg
+.. |movie| image:: movie.jpg
diff --git a/tests/writer.rtf b/tests/writer.rtf
new file mode 100644
index 000000000..6ee7bfae0
--- /dev/null
+++ b/tests/writer.rtf
@@ -0,0 +1,431 @@
+{\rtf1\ansi\deff0{\fonttbl{\f0 \fswiss Helvetica;}{\f1 Courier;}}
+{\colortbl;\red255\green0\blue0;\red0\green0\blue255;}
+\widowctrl\hyphauto
+
+{\pard \qc \f0 \sa180 \li0 \fi0 \b \fs36 Pandoc Test Suite\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 John MacFarlane\Anonymous\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 July 17, 2006\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This is a set of tests for pandoc. Most of them are adapted from John Gruber\u8217's markdown test suite.\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Headers\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Level 2 with an {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
+embedded link
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Level 3 with {\i emphasis}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Level 4\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs20 Level 5\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Level 1\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Level 2 with {\i emphasis}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Level 3\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 with no blank line\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Level 2\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 with no blank line\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Paragraphs\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a regular paragraph.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's one with a bullet. * criminey.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 There should be a hard line break\line here.\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Block Quotes\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 E-mail style:\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 This is a block quote. It is pretty short.\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 Code in a block quote:\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 \f1 sub status \{\line
+ print "working";\line
+\}\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 A list:\par}
+{\pard \ql \f0 \sa0 \li1080 \fi-360 1.\tx360\tab item one\par}
+{\pard \ql \f0 \sa0 \li1080 \fi-360 2.\tx360\tab item two\sa180\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 Nested block quotes:\par}
+{\pard \ql \f0 \sa180 \li1440 \fi0 nested\par}
+{\pard \ql \f0 \sa180 \li1440 \fi0 nested\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This should not be a block quote: 2 > 1.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 And a following paragraph.\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Code Blocks\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Code:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 ---- (should be four hyphens)\line
+\line
+sub status \{\line
+ print "working";\line
+\}\line
+\line
+this code block is indented by one tab\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 And:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 this code block is indented by two tabs\line
+\line
+These should not be escaped: \\$ \\\\ \\> \\[ \\\{\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Lists\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Unordered\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Asterisks tight:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab asterisk 1\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab asterisk 2\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab asterisk 3\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Asterisks loose:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab asterisk 1\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab asterisk 2\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab asterisk 3\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Pluses tight:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Plus 1\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Plus 2\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Plus 3\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Pluses loose:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Plus 1\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Plus 2\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Plus 3\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Minuses tight:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Minus 1\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Minus 2\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Minus 3\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Minuses loose:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Minus 1\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Minus 2\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Minus 3\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Ordered\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Tight:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab First\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab Second\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 3.\tx360\tab Third\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 and:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab One\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab Two\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 3.\tx360\tab Three\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Loose using tabs:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 1.\tx360\tab First\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 2.\tx360\tab Second\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 3.\tx360\tab Third\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 and using spaces:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 1.\tx360\tab One\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 2.\tx360\tab Two\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 3.\tx360\tab Three\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiple paragraphs:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 1.\tx360\tab Item 1, graf one.\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 Item 1. graf two. The quick brown fox jumped over the lazy dog\u8217's back.\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 2.\tx360\tab Item 2.\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 3.\tx360\tab Item 3.\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Nested\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Tab\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Tab\par}
+{\pard \ql \f0 \sa0 \li1080 \fi-360 \bullet \tx360\tab Tab\sa180\sa180\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's another:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab First\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab Second:\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Fee\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Fie\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Foe\sa180\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 3.\tx360\tab Third\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Same thing but with paragraphs:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 1.\tx360\tab First\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 2.\tx360\tab Second:\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Fee\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Fie\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Foe\sa180\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 3.\tx360\tab Third\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Tabs and spaces\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab this is a list item indented with tabs\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab this is a list item indented with spaces\par}
+{\pard \ql \f0 \sa180 \li720 \fi-360 \endash \tx360\tab this is an example list item indented with tabs\par}
+{\pard \ql \f0 \sa180 \li720 \fi-360 \endash \tx360\tab this is an example list item indented with spaces\sa180\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Fancy list markers\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 (2)\tx360\tab begins with 2\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 (3)\tx360\tab and now 3\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 with a continuation\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 iv.\tx360\tab sublist with roman numerals, starting with 4\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 v.\tx360\tab more items\par}
+{\pard \ql \f0 \sa0 \li1080 \fi-360 (A)\tx360\tab a subsublist\par}
+{\pard \ql \f0 \sa0 \li1080 \fi-360 (B)\tx360\tab a subsublist\sa180\sa180\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Nesting:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 A.\tx360\tab Upper Alpha\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 I.\tx360\tab Upper Roman.\par}
+{\pard \ql \f0 \sa0 \li1080 \fi-360 (6)\tx360\tab Decimal start with 6\par}
+{\pard \ql \f0 \sa0 \li1440 \fi-360 c)\tx360\tab Lower alpha with paren\sa180\sa180\sa180\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Autonumbering:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab Autonumber.\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab More.\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 a.\tx360\tab Nested.\sa180\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Should not be a list item:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 M.A.\u160?2007\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 B. Williams\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Definition Lists\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Tight using spaces:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 red fruit\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 orange fruit\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 banana\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 yellow fruit\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Tight using tabs:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 red fruit\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 orange fruit\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 banana\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 yellow fruit\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Loose:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 red fruit\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 orange fruit\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 banana\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 yellow fruit\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiple blocks with italics:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 {\i apple}\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 red fruit\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 contains seeds, crisp, pleasant to taste\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 {\i orange}\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 orange fruit\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 \f1 \{ orange code block \}\par}
+{\pard \ql \f0 \sa180 \li1080 \fi0 orange block quote\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 HTML Blocks\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Simple block on one line:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 foo\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 And nested without indentation:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 foo\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 bar\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Interpreted markdown in a table:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 This is {\i emphasized}\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 And this is {\b strong}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a simple block:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 foo\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This should be a code block, though:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 <div>\line
+ foo\line
+</div>\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 As should this:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 <div>foo</div>\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Now, nested:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 foo\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This should just be an HTML comment:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiline:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Code block:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 <!-- Comment -->\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Just plain comment, with trailing spaces on the line:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Code:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 <hr />\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Hr\u8217's:\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Inline Markup\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This is {\i emphasized}, and so {\i is this}.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This is {\b strong}, and so {\b is this}.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 An {\i {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
+emphasized link
+}}}
+}.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\b {\i This is strong and em.}}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 So is {\b {\i this}} word.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\b {\i This is strong and em.}}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 So is {\b {\i this}} word.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This is code: {\f1 >}, {\f1 $}, {\f1 \\}, {\f1 \\$}, {\f1 <html>}.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\strike This is {\i strikeout}.}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Superscripts: a{\super bc}d a{\super {\i hello}} a{\super hello\u160?there}.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Subscripts: H{\sub 2}O, H{\sub 23}O, H{\sub many\u160?of\u160?them}O.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Smart quotes, ellipses, dashes\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \u8220"Hello,\u8221" said the spider. \u8220"\u8216'Shelob\u8217' is my name.\u8221"\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \u8216'A\u8217', \u8216'B\u8217', and \u8216'C\u8217' are letters.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \u8216'Oak,\u8217' \u8216'elm,\u8217' and \u8216'beech\u8217' are names of trees. So is \u8216'pine.\u8217'\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \u8216'He said, \u8220"I want to go.\u8221"\u8217' Were you alive in the 70\u8217's?\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here is some quoted \u8216'{\f1 code}\u8217' and a \u8220"{\field{\*\fldinst{HYPERLINK "http://example.com/?foo=1&bar=2"}}{\fldrslt{\ul
+quoted link
+}}}
+\u8221".\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Some dashes: one\u8212-two \u8212- three\u8212-four \u8212- five.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Dashes between numbers: 5\u8211-7, 255\u8211-66, 1987\u8211-1999.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Ellipses\u8230?and\u8230?and\u8230?.\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 LaTeX\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab \par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab 2+2=4\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\i x}\u8201?\u8712?\u8201?{\i y}\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab \u945?\u8201?\u8743?\u8201?\u969?\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab 223\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\i p}-Tree\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Here\u8217's some display math: \\frac\{{\i d}\}\{{\i dx}\}{\i f}({\i x})=\\lim{\sub {\i h}\u8201?\u8594?\u8201?0}\\frac\{{\i f}({\i x}+{\i h})-{\i f}({\i x})\}\{{\i h}\}\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Here\u8217's one that has a line break in it: \u945?+\u969?\u8201?\u215?\u8201?{\i x}{\super 2}.\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 These shouldn\u8217't be math:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab To get the famous equation, write {\f1 $e = mc^2$}.\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab $22,000 is a {\i lot} of money. So is $34,000. (It worked if \u8220"lot\u8221" is emphasized.)\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Shoes ($20) and socks ($5).\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Escaped {\f1 $}: $73 {\i this should be emphasized} 23$.\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a LaTeX table:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Special Characters\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here is some unicode:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab I hat: \u206?\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab o umlaut: \u246?\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab section: \u167?\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab set membership: \u8712?\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab copyright: \u169?\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 AT&T has an ampersand in their name.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 AT&T is another way to write it.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This & that.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 4 < 5.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 6 > 5.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Backslash: \\\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Backtick: `\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Asterisk: *\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Underscore: _\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Left brace: \{\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Right brace: \}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Left bracket: [\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Right bracket: ]\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Left paren: (\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Right paren: )\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Greater-than: >\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Hash: #\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Period: .\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Bang: !\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Plus: +\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Minus: -\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Links\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Explicit\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Just a {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+URL
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+URL and title
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+URL and title
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+URL and title
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+URL and title
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+URL and title
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/with_underscore"}}{\fldrslt{\ul
+with_underscore
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "mailto:nobody@nowhere.net"}}{\fldrslt{\ul
+Email link
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK ""}}{\fldrslt{\ul
+Empty
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Reference\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+bar
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+bar
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+bar
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 With {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+embedded [brackets]
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+b
+}}}
+ by itself should be a link.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Indented {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
+once
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Indented {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
+twice
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Indented {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
+thrice
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This should [not][] be a link.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 [not]: /url\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+bar
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+biz
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 With ampersands\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a {\field{\*\fldinst{HYPERLINK "http://example.com/?foo=1&bar=2"}}{\fldrslt{\ul
+link with an ampersand in the URL
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a link with an amersand in the link text: {\field{\*\fldinst{HYPERLINK "http://att.com/"}}{\fldrslt{\ul
+AT&T
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's an {\field{\*\fldinst{HYPERLINK "/script?foo=1&bar=2"}}{\fldrslt{\ul
+inline link
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's an {\field{\*\fldinst{HYPERLINK "/script?foo=1&bar=2"}}{\fldrslt{\ul
+inline link in pointy braces
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Autolinks\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 With an ampersand: {\field{\*\fldinst{HYPERLINK "http://example.com/?foo=1&bar=2"}}{\fldrslt{\ul
+{\f1 http://example.com/?foo=1&bar=2}
+}}}
+\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab In a list?\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\field{\*\fldinst{HYPERLINK "http://example.com/"}}{\fldrslt{\ul
+{\f1 http://example.com/}
+}}}
+\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab It should.\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 An e-mail address: {\field{\*\fldinst{HYPERLINK "mailto:nobody@nowhere.net"}}{\fldrslt{\ul
+{\f1 nobody@nowhere.net}
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 Blockquoted: {\field{\*\fldinst{HYPERLINK "http://example.com/"}}{\fldrslt{\ul
+{\f1 http://example.com/}
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Auto-links should not occur here: {\f1 <http://example.com/>}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 or here: <http://example.com/>\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Images\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 From \u8220"Voyage dans la Lune\u8221" by Georges Melies (1902):\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\cf1 [image: lalune.jpg]\cf0}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here is a movie {\cf1 [image: movie.jpg]\cf0} icon.\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Footnotes\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here is a footnote reference,{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.\par}
+} and another.{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's the long note. This one contains multiple blocks.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Subsequent blocks are indented to show that they belong to the footnote (as with list items).\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 \{ <code> \}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.\par}
+} This should {\i not} be a footnote reference, because it contains a space.[^my note] Here is an inline note.{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 This is {\i easier} to type. Inline notes may contain {\field{\*\fldinst{HYPERLINK "http://google.com"}}{\fldrslt{\ul
+links
+}}}
+ and {\f1 ]} verbatim characters, as well as [bracketed text].\par}
+}\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 Notes can go in quotes.{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 In quote.\par}
+}\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab And in list items.{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 In list.\par}
+}\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This paragraph should not be part of the note, as it is not indented.\par}
+
+}
+
diff --git a/tests/writer.texinfo b/tests/writer.texinfo
new file mode 100644
index 000000000..025319ac9
--- /dev/null
+++ b/tests/writer.texinfo
@@ -0,0 +1,960 @@
+\input texinfo
+
+@macro textstrikeout{text}
+~~\text\~~
+@end macro
+
+@macro textsubscript{text}
+@iftex
+@textsubscript{\text\}
+@end iftex
+@ifnottex
+_@{\text\@}
+@end ifnottex
+@end macro
+
+@macro textsuperscript{text}
+@iftex
+@textsuperscript{\text\}
+@end iftex
+@ifnottex
+^@{\text\@}
+@end ifnottex
+@end macro
+
+
+@ifnottex
+@paragraphindent 0
+@end ifnottex
+@titlepage
+@title Pandoc Test Suite
+@author John MacFarlane
+@author Anonymous
+July 17@comma{} 2006
+@end titlepage
+@node Top
+@top Pandoc Test Suite
+
+This is a set of tests for pandoc. Most of them are adapted from John Gruber's markdown test suite.
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+@menu
+* Headers::
+* Level 1::
+* Paragraphs::
+* Block Quotes::
+* Code Blocks::
+* Lists::
+* Definition Lists::
+* HTML Blocks::
+* Inline Markup::
+* Smart quotes ellipses dashes::
+* LaTeX::
+* Special Characters::
+* Links::
+* Images::
+* Footnotes::
+@end menu
+
+@node Headers
+@chapter Headers
+@menu
+* Level 2 with an embedded link::
+@end menu
+
+@node Level 2 with an embedded link
+@section Level 2 with an @uref{/url,embedded link}
+@menu
+* Level 3 with emphasis::
+@end menu
+
+@node Level 3 with emphasis
+@subsection Level 3 with @emph{emphasis}
+@menu
+* Level 4::
+@end menu
+
+@node Level 4
+@subsubsection Level 4
+Level 5
+
+@node Level 1
+@chapter Level 1
+@menu
+* Level 2 with emphasis::
+* Level 2::
+@end menu
+
+@node Level 2 with emphasis
+@section Level 2 with @emph{emphasis}
+@menu
+* Level 3::
+@end menu
+
+@node Level 3
+@subsection Level 3
+with no blank line
+
+
+@node Level 2
+@section Level 2
+with no blank line
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Paragraphs
+@chapter Paragraphs
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.
+
+Here's one with a bullet. * criminey.
+
+There should be a hard line break@*here.
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Block Quotes
+@chapter Block Quotes
+E-mail style:
+
+@quotation
+This is a block quote. It is pretty short.
+
+@end quotation
+@quotation
+Code in a block quote:
+@verbatim
+sub status {
+ print "working";
+}
+@end verbatim
+
+A list:
+
+@enumerate
+@item
+item one
+@item
+item two
+@end enumerate
+
+Nested block quotes:
+
+@quotation
+nested
+
+@end quotation
+@quotation
+nested
+
+@end quotation
+@end quotation
+This should not be a block quote: 2 > 1.
+
+And a following paragraph.
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Code Blocks
+@chapter Code Blocks
+Code:
+@verbatim
+---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+@end verbatim
+
+And:
+@verbatim
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+@end verbatim
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Lists
+@chapter Lists
+@menu
+* Unordered::
+* Ordered::
+* Nested::
+* Tabs and spaces::
+* Fancy list markers::
+@end menu
+
+@node Unordered
+@section Unordered
+Asterisks tight:
+
+@itemize
+@item
+asterisk 1
+@item
+asterisk 2
+@item
+asterisk 3
+@end itemize
+
+Asterisks loose:
+
+@itemize
+@item
+asterisk 1
+
+@item
+asterisk 2
+
+@item
+asterisk 3
+
+@end itemize
+
+Pluses tight:
+
+@itemize
+@item
+Plus 1
+@item
+Plus 2
+@item
+Plus 3
+@end itemize
+
+Pluses loose:
+
+@itemize
+@item
+Plus 1
+
+@item
+Plus 2
+
+@item
+Plus 3
+
+@end itemize
+
+Minuses tight:
+
+@itemize
+@item
+Minus 1
+@item
+Minus 2
+@item
+Minus 3
+@end itemize
+
+Minuses loose:
+
+@itemize
+@item
+Minus 1
+
+@item
+Minus 2
+
+@item
+Minus 3
+
+@end itemize
+
+
+@node Ordered
+@section Ordered
+Tight:
+
+@enumerate
+@item
+First
+@item
+Second
+@item
+Third
+@end enumerate
+
+and:
+
+@enumerate
+@item
+One
+@item
+Two
+@item
+Three
+@end enumerate
+
+Loose using tabs:
+
+@enumerate
+@item
+First
+
+@item
+Second
+
+@item
+Third
+
+@end enumerate
+
+and using spaces:
+
+@enumerate
+@item
+One
+
+@item
+Two
+
+@item
+Three
+
+@end enumerate
+
+Multiple paragraphs:
+
+@enumerate
+@item
+Item 1@comma{} graf one.
+
+Item 1. graf two. The quick brown fox jumped over the lazy dog's back.
+
+@item
+Item 2.
+
+@item
+Item 3.
+
+@end enumerate
+
+
+@node Nested
+@section Nested
+@itemize
+@item
+Tab
+@itemize
+@item
+Tab
+@itemize
+@item
+Tab
+@end itemize
+
+@end itemize
+
+@end itemize
+
+Here's another:
+
+@enumerate
+@item
+First
+@item
+Second:
+@itemize
+@item
+Fee
+@item
+Fie
+@item
+Foe
+@end itemize
+
+@item
+Third
+@end enumerate
+
+Same thing but with paragraphs:
+
+@enumerate
+@item
+First
+
+@item
+Second:
+
+@itemize
+@item
+Fee
+@item
+Fie
+@item
+Foe
+@end itemize
+
+@item
+Third
+
+@end enumerate
+
+
+@node Tabs and spaces
+@section Tabs and spaces
+@itemize
+@item
+this is a list item indented with tabs
+
+@item
+this is a list item indented with spaces
+
+@itemize
+@item
+this is an example list item indented with tabs
+
+@item
+this is an example list item indented with spaces
+
+@end itemize
+
+@end itemize
+
+
+@node Fancy list markers
+@section Fancy list markers
+@enumerate 2
+@item
+begins with 2
+@item
+and now 3
+
+with a continuation
+
+@enumerate 4
+@item
+sublist with roman numerals@comma{} starting with 4
+@item
+more items
+@enumerate A
+@item
+a subsublist
+@item
+a subsublist
+@end enumerate
+
+@end enumerate
+
+@end enumerate
+
+Nesting:
+
+@enumerate A
+@item
+Upper Alpha
+@enumerate
+@item
+Upper Roman.
+@enumerate 6
+@item
+Decimal start with 6
+@enumerate c
+@item
+Lower alpha with paren
+@end enumerate
+
+@end enumerate
+
+@end enumerate
+
+@end enumerate
+
+Autonumbering:
+
+@enumerate
+@item
+Autonumber.
+@item
+More.
+@enumerate
+@item
+Nested.
+@end enumerate
+
+@end enumerate
+
+Should not be a list item:
+
+M.A.@ 2007
+
+B. Williams
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Definition Lists
+@chapter Definition Lists
+Tight using spaces:
+
+@table @asis
+@item apple
+
+red fruit
+@item orange
+
+orange fruit
+@item banana
+
+yellow fruit
+@end table
+
+Tight using tabs:
+
+@table @asis
+@item apple
+
+red fruit
+@item orange
+
+orange fruit
+@item banana
+
+yellow fruit
+@end table
+
+Loose:
+
+@table @asis
+@item apple
+
+red fruit
+
+@item orange
+
+orange fruit
+
+@item banana
+
+yellow fruit
+
+@end table
+
+Multiple blocks with italics:
+
+@table @asis
+@item @emph{apple}
+
+red fruit
+
+contains seeds@comma{} crisp@comma{} pleasant to taste
+
+@item @emph{orange}
+
+orange fruit
+@verbatim
+{ orange code block }
+@end verbatim
+
+@quotation
+orange block quote
+
+@end quotation
+@end table
+
+
+@node HTML Blocks
+@chapter HTML Blocks
+Simple block on one line:
+
+foo
+And nested without indentation:
+
+foo
+bar
+Interpreted markdown in a table:
+
+This is @emph{emphasized}
+And this is @strong{strong}
+Here's a simple block:
+
+foo
+This should be a code block@comma{} though:
+@verbatim
+<div>
+ foo
+</div>
+@end verbatim
+
+As should this:
+@verbatim
+<div>foo</div>
+@end verbatim
+
+Now@comma{} nested:
+
+foo
+This should just be an HTML comment:
+
+Multiline:
+
+Code block:
+@verbatim
+<!-- Comment -->
+@end verbatim
+
+Just plain comment@comma{} with trailing spaces on the line:
+
+Code:
+@verbatim
+<hr />
+@end verbatim
+
+Hr's:
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Inline Markup
+@chapter Inline Markup
+This is @emph{emphasized}@comma{} and so @emph{is this}.
+
+This is @strong{strong}@comma{} and so @strong{is this}.
+
+An @emph{@uref{/url,emphasized link}}.
+
+@strong{@emph{This is strong and em.}}
+
+So is @strong{@emph{this}} word.
+
+@strong{@emph{This is strong and em.}}
+
+So is @strong{@emph{this}} word.
+
+This is code: @code{>}@comma{} @code{$}@comma{} @code{\}@comma{} @code{\$}@comma{} @code{<html>}.
+
+@textstrikeout{This is @emph{strikeout}.}
+
+Superscripts: a@textsuperscript{bc}d a@textsuperscript{@emph{hello}} a@textsuperscript{hello@ there}.
+
+Subscripts: H@textsubscript{2}O@comma{} H@textsubscript{23}O@comma{} H@textsubscript{many@ of@ them}O.
+
+These should not be superscripts or subscripts@comma{} because of the unescaped spaces: a^b c^d@comma{} a~b c~d.
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Smart quotes ellipses dashes
+@chapter Smart quotes@comma{} ellipses@comma{} dashes
+``Hello@comma{}'' said the spider. ```Shelob' is my name.''
+
+`A'@comma{} `B'@comma{} and `C' are letters.
+
+`Oak@comma{}' `elm@comma{}' and `beech' are names of trees. So is `pine.'
+
+`He said@comma{} ``I want to go.''' Were you alive in the 70's?
+
+Here is some quoted `@code{code}' and a ``@uref{http://example.com/?foo=1&bar=2,quoted link}''.
+
+Some dashes: one---two --- three---four --- five.
+
+Dashes between numbers: 5--7@comma{} 255--66@comma{} 1987--1999.
+
+Ellipses@dots{}and@dots{}and@dots{}.
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node LaTeX
+@chapter LaTeX
+@itemize
+@item
+@tex
+\cite[22-23]{smith.1899}
+@end tex
+@item
+@math{2+2=4}
+@item
+@math{x \in y}
+@item
+@math{\alpha \wedge \omega}
+@item
+@math{223}
+@item
+@math{p}-Tree
+@item
+Here's some display math: @math{\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}}
+@item
+Here's one that has a line break in it: @math{\alpha + \omega \times x^2}.
+@end itemize
+
+These shouldn't be math:
+
+@itemize
+@item
+To get the famous equation@comma{} write @code{$e = mc^2$}.
+@item
+$22@comma{}000 is a @emph{lot} of money. So is $34@comma{}000. (It worked if ``lot'' is emphasized.)
+@item
+Shoes ($20) and socks ($5).
+@item
+Escaped @code{$}: $73 @emph{this should be emphasized} 23$.
+@end itemize
+
+Here's a LaTeX table:
+
+@tex
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+@end tex
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Special Characters
+@chapter Special Characters
+Here is some unicode:
+
+@itemize
+@item
+I hat: Î
+@item
+o umlaut: ö
+@item
+section: §
+@item
+set membership: ∈
+@item
+copyright: ©
+@end itemize
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: _
+
+Left brace: @{
+
+Right brace: @}
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: >
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Links
+@chapter Links
+@menu
+* Explicit::
+* Reference::
+* With ampersands::
+* Autolinks::
+@end menu
+
+@node Explicit
+@section Explicit
+Just a @uref{/url/,URL}.
+
+@uref{/url/,URL and title}.
+
+@uref{/url/,URL and title}.
+
+@uref{/url/,URL and title}.
+
+@uref{/url/,URL and title}
+
+@uref{/url/,URL and title}
+
+@uref{/url/with_underscore,with_underscore}
+
+@uref{mailto:nobody@@nowhere.net,Email link}
+
+@uref{,Empty}.
+
+
+@node Reference
+@section Reference
+Foo @uref{/url/,bar}.
+
+Foo @uref{/url/,bar}.
+
+Foo @uref{/url/,bar}.
+
+With @uref{/url/,embedded [brackets]}.
+
+@uref{/url/,b} by itself should be a link.
+
+Indented @uref{/url,once}.
+
+Indented @uref{/url,twice}.
+
+Indented @uref{/url,thrice}.
+
+This should [not][] be a link.
+@verbatim
+[not]: /url
+@end verbatim
+
+Foo @uref{/url/,bar}.
+
+Foo @uref{/url/,biz}.
+
+
+@node With ampersands
+@section With ampersands
+Here's a @uref{http://example.com/?foo=1&bar=2,link with an ampersand in the URL}.
+
+Here's a link with an amersand in the link text: @uref{http://att.com/,AT&T}.
+
+Here's an @uref{/script?foo=1&bar=2,inline link}.
+
+Here's an @uref{/script?foo=1&bar=2,inline link in pointy braces}.
+
+
+@node Autolinks
+@section Autolinks
+With an ampersand: @url{http://example.com/?foo=1&bar=2}
+
+@itemize
+@item
+In a list?
+@item
+@url{http://example.com/}
+@item
+It should.
+@end itemize
+
+An e-mail address: @uref{mailto:nobody@@nowhere.net,@code{nobody@@nowhere.net}}
+
+@quotation
+Blockquoted: @url{http://example.com/}
+
+@end quotation
+Auto-links should not occur here: @code{<http://example.com/>}
+@verbatim
+or here: <http://example.com/>
+@end verbatim
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Images
+@chapter Images
+From ``Voyage dans la Lune'' by Georges Melies (1902):
+
+@image{lalune,,,lalune,jpg}
+
+Here is a movie @image{movie,,,movie,jpg} icon.
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Footnotes
+@chapter Footnotes
+Here is a footnote reference@comma{}@footnote{Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.} and another.@footnote{Here's the long note. This one contains multiple blocks.
+
+Subsequent blocks are indented to show that they belong to the footnote (as with list items).
+@verbatim
+ { <code> }
+@end verbatim
+
+If you want@comma{} you can indent every line@comma{} but you can also be lazy and just indent the first line of each block.} This should @emph{not} be a footnote reference@comma{} because it contains a space.[^my note] Here is an inline note.@footnote{This is @emph{easier} to type. Inline notes may contain @uref{http://google.com,links} and @code{]} verbatim characters@comma{} as well as [bracketed text].}
+
+@quotation
+Notes can go in quotes.@footnote{In quote.}
+
+@end quotation
+@enumerate
+@item
+And in list items.@footnote{In list.}
+@end enumerate
+
+This paragraph should not be part of the note@comma{} as it is not indented.
+
+@bye