diff env/lib/python3.7/site-packages/docutils/utils/math/math2html.py @ 5:9b1c78e6ba9c draft default tip

"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author shellac
date Mon, 01 Jun 2020 08:59:25 -0400
parents 79f47841a781
children
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/docutils/utils/math/math2html.py	Thu May 14 16:47:39 2020 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5383 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: utf-8 -*-
-
-#   math2html: convert LaTeX equations to HTML output.
-#
-#   Copyright (C) 2009-2011 Alex Fernández
-#
-#   Released under the terms of the `2-Clause BSD license'_, in short:
-#   Copying and distribution of this file, with or without modification,
-#   are permitted in any medium without royalty provided the copyright
-#   notice and this notice are preserved.
-#   This file is offered as-is, without any warranty.
-#
-# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause
-
-#   Based on eLyXer: convert LyX source files to HTML output.
-#   http://alexfernandez.github.io/elyxer/
-
-# --end--
-# Alex 20101110
-# eLyXer standalone formula conversion to HTML.
-
-import codecs
-import datetime
-import gettext
-import io
-import os.path
-import sys
-import unicodedata
-
-if sys.version_info >= (3, 0):
-    from urllib.parse import quote_plus
-else:
-    from urllib import quote_plus
-
-
-if sys.version_info >= (3, 0):
-    unicode = str  #noqa
-    basestring = str  # noqa
-    file = io.IOBase  # noqa
-
-
-class Trace(object):
-  "A tracing class"
-
-  debugmode = False
-  quietmode = False
-  showlinesmode = False
-
-  prefix = None
-
-  def debug(cls, message):
-    "Show a debug message"
-    if not Trace.debugmode or Trace.quietmode:
-      return
-    Trace.show(message, sys.stdout)
-
-  def message(cls, message):
-    "Show a trace message"
-    if Trace.quietmode:
-      return
-    if Trace.prefix and Trace.showlinesmode:
-      message = Trace.prefix + message
-    Trace.show(message, sys.stdout)
-
-  def error(cls, message):
-    "Show an error message"
-    message = '* ' + message
-    if Trace.prefix and Trace.showlinesmode:
-      message = Trace.prefix + message
-    Trace.show(message, sys.stderr)
-
-  def fatal(cls, message):
-    "Show an error message and terminate"
-    Trace.error('FATAL: ' + message)
-    exit(-1)
-
-  def show(cls, message, channel):
-    "Show a message out of a channel"
-    if sys.version_info < (3, 0):
-      message = message.encode('utf-8')
-    channel.write(message + '\n')
-
-  debug = classmethod(debug)
-  message = classmethod(message)
-  error = classmethod(error)
-  fatal = classmethod(fatal)
-  show = classmethod(show)
-
-
-class BibStylesConfig(object):
-  "Configuration class from elyxer.config file"
-
-  abbrvnat = {
-      u'@article': u'$authors. $title. <i>$journal</i>,{ {$volume:}$pages,} $month $year.{ doi: $doi.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'cite': u'$surname($year)',
-      u'default': u'$authors. <i>$title</i>. $publisher, $year.{ URL <a href="$url">$url</a>.}{ $note.}',
-      }
-
-  alpha = {
-      u'@article': u'$authors. $title.{ <i>$journal</i>{, {$volume}{($number)}}{: $pages}{, $year}.}{ <a href="$url">$url</a>.}{ <a href="$filename">$filename</a>.}{ $note.}',
-      u'cite': u'$Sur$YY',
-      u'default': u'$authors. $title.{ <i>$journal</i>,} $year.{ <a href="$url">$url</a>.}{ <a href="$filename">$filename</a>.}{ $note.}',
-      }
-
-  authordate2 = {
-      u'@article': u'$authors. $year. $title. <i>$journal</i>, <b>$volume</b>($number), $pages.{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@book': u'$authors. $year. <i>$title</i>. $publisher.{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'cite': u'$surname, $year',
-      u'default': u'$authors. $year. <i>$title</i>. $publisher.{ URL <a href="$url">$url</a>.}{ $note.}',
-      }
-
-  default = {
-      u'@article': u'$authors: “$title”, <i>$journal</i>,{ pp. $pages,} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@book': u'{$authors: }<i>$title</i>{ ($editor, ed.)}.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@booklet': u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@conference': u'$authors: “$title”, <i>$journal</i>,{ pp. $pages,} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@inbook': u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@incollection': u'$authors: <i>$title</i>{ in <i>$booktitle</i>{ ($editor, ed.)}}.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@inproceedings': u'$authors: “$title”, <i>$booktitle</i>,{ pp. $pages,} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@manual': u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@mastersthesis': u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@misc': u'$authors: <i>$title</i>.{{ $publisher,}{ $howpublished,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@phdthesis': u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@proceedings': u'$authors: “$title”, <i>$journal</i>,{ pp. $pages,} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@techreport': u'$authors: <i>$title</i>, $year.{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@unpublished': u'$authors: “$title”, <i>$journal</i>, $year.{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'cite': u'$index',
-      u'default': u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      }
-
-  defaulttags = {
-      u'YY': u'??', u'authors': u'', u'surname': u'',
-      }
-
-  ieeetr = {
-      u'@article': u'$authors, “$title”, <i>$journal</i>, vol. $volume, no. $number, pp. $pages, $year.{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@book': u'$authors, <i>$title</i>. $publisher, $year.{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'cite': u'$index',
-      u'default': u'$authors, “$title”. $year.{ URL <a href="$url">$url</a>.}{ $note.}',
-      }
-
-  plain = {
-      u'@article': u'$authors. $title.{ <i>$journal</i>{, {$volume}{($number)}}{:$pages}{, $year}.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@book': u'$authors. <i>$title</i>. $publisher,{ $month} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@incollection': u'$authors. $title.{ In <i>$booktitle</i> {($editor, ed.)}.} $publisher,{ $month} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'@inproceedings': u'$authors. $title. { <i>$booktitle</i>{, {$volume}{($number)}}{:$pages}{, $year}.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      u'cite': u'$index',
-      u'default': u'{$authors. }$title.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
-      }
-
-  vancouver = {
-      u'@article': u'$authors. $title. <i>$journal</i>, $year{;{<b>$volume</b>}{($number)}{:$pages}}.{ URL: <a href="$url">$url</a>.}{ $note.}',
-      u'@book': u'$authors. $title. {$publisher, }$year.{ URL: <a href="$url">$url</a>.}{ $note.}',
-      u'cite': u'$index',
-      u'default': u'$authors. $title; {$publisher, }$year.{ $howpublished.}{ URL: <a href="$url">$url</a>.}{ $note.}',
-      }
-
-class BibTeXConfig(object):
-  "Configuration class from elyxer.config file"
-
-  replaced = {
-      u'--': u'—', u'..': u'.',
-      }
-
-class ContainerConfig(object):
-  "Configuration class from elyxer.config file"
-
-  endings = {
-      u'Align': u'\\end_layout', u'BarredText': u'\\bar',
-      u'BoldText': u'\\series', u'Cell': u'</cell',
-      u'ChangeDeleted': u'\\change_unchanged',
-      u'ChangeInserted': u'\\change_unchanged', u'ColorText': u'\\color',
-      u'EmphaticText': u'\\emph', u'Hfill': u'\\hfill', u'Inset': u'\\end_inset',
-      u'Layout': u'\\end_layout', u'LyXFooter': u'\\end_document',
-      u'LyXHeader': u'\\end_header', u'Row': u'</row', u'ShapedText': u'\\shape',
-      u'SizeText': u'\\size', u'StrikeOut': u'\\strikeout',
-      u'TextFamily': u'\\family', u'VersalitasText': u'\\noun',
-      }
-
-  extracttext = {
-      u'allowed': [u'StringContainer', u'Constant', u'FormulaConstant',],
-      u'cloned': [u'',],
-      u'extracted': [u'PlainLayout', u'TaggedText', u'Align', u'Caption', u'TextFamily', u'EmphaticText', u'VersalitasText', u'BarredText', u'SizeText', u'ColorText', u'LangLine', u'Formula', u'Bracket', u'RawText', u'BibTag', u'FormulaNumber', u'AlphaCommand', u'EmptyCommand', u'OneParamFunction', u'SymbolFunction', u'TextFunction', u'FontFunction', u'CombiningFunction', u'DecoratingFunction', u'FormulaSymbol', u'BracketCommand', u'TeXCode',],
-      }
-
-  startendings = {
-      u'\\begin_deeper': u'\\end_deeper', u'\\begin_inset': u'\\end_inset',
-      u'\\begin_layout': u'\\end_layout',
-      }
-
-  starts = {
-      u'': u'StringContainer', u'#LyX': u'BlackBox', u'</lyxtabular': u'BlackBox',
-      u'<cell': u'Cell', u'<column': u'Column', u'<row': u'Row',
-      u'\\align': u'Align', u'\\bar': u'BarredText',
-      u'\\bar default': u'BlackBox', u'\\bar no': u'BlackBox',
-      u'\\begin_body': u'BlackBox', u'\\begin_deeper': u'DeeperList',
-      u'\\begin_document': u'BlackBox', u'\\begin_header': u'LyXHeader',
-      u'\\begin_inset Argument': u'ShortTitle',
-      u'\\begin_inset Box': u'BoxInset', u'\\begin_inset Branch': u'Branch',
-      u'\\begin_inset Caption': u'Caption',
-      u'\\begin_inset CommandInset bibitem': u'BiblioEntry',
-      u'\\begin_inset CommandInset bibtex': u'BibTeX',
-      u'\\begin_inset CommandInset citation': u'BiblioCitation',
-      u'\\begin_inset CommandInset href': u'URL',
-      u'\\begin_inset CommandInset include': u'IncludeInset',
-      u'\\begin_inset CommandInset index_print': u'PrintIndex',
-      u'\\begin_inset CommandInset label': u'Label',
-      u'\\begin_inset CommandInset line': u'LineInset',
-      u'\\begin_inset CommandInset nomencl_print': u'PrintNomenclature',
-      u'\\begin_inset CommandInset nomenclature': u'NomenclatureEntry',
-      u'\\begin_inset CommandInset ref': u'Reference',
-      u'\\begin_inset CommandInset toc': u'TableOfContents',
-      u'\\begin_inset ERT': u'ERT', u'\\begin_inset Flex': u'FlexInset',
-      u'\\begin_inset Flex Chunkref': u'NewfangledChunkRef',
-      u'\\begin_inset Flex Marginnote': u'SideNote',
-      u'\\begin_inset Flex Sidenote': u'SideNote',
-      u'\\begin_inset Flex URL': u'FlexURL', u'\\begin_inset Float': u'Float',
-      u'\\begin_inset FloatList': u'ListOf', u'\\begin_inset Foot': u'Footnote',
-      u'\\begin_inset Formula': u'Formula',
-      u'\\begin_inset FormulaMacro': u'FormulaMacro',
-      u'\\begin_inset Graphics': u'Image',
-      u'\\begin_inset Index': u'IndexReference',
-      u'\\begin_inset Info': u'InfoInset',
-      u'\\begin_inset LatexCommand bibitem': u'BiblioEntry',
-      u'\\begin_inset LatexCommand bibtex': u'BibTeX',
-      u'\\begin_inset LatexCommand cite': u'BiblioCitation',
-      u'\\begin_inset LatexCommand citealt': u'BiblioCitation',
-      u'\\begin_inset LatexCommand citep': u'BiblioCitation',
-      u'\\begin_inset LatexCommand citet': u'BiblioCitation',
-      u'\\begin_inset LatexCommand htmlurl': u'URL',
-      u'\\begin_inset LatexCommand index': u'IndexReference',
-      u'\\begin_inset LatexCommand label': u'Label',
-      u'\\begin_inset LatexCommand nomenclature': u'NomenclatureEntry',
-      u'\\begin_inset LatexCommand prettyref': u'Reference',
-      u'\\begin_inset LatexCommand printindex': u'PrintIndex',
-      u'\\begin_inset LatexCommand printnomenclature': u'PrintNomenclature',
-      u'\\begin_inset LatexCommand ref': u'Reference',
-      u'\\begin_inset LatexCommand tableofcontents': u'TableOfContents',
-      u'\\begin_inset LatexCommand url': u'URL',
-      u'\\begin_inset LatexCommand vref': u'Reference',
-      u'\\begin_inset Marginal': u'SideNote',
-      u'\\begin_inset Newline': u'NewlineInset',
-      u'\\begin_inset Newpage': u'NewPageInset', u'\\begin_inset Note': u'Note',
-      u'\\begin_inset OptArg': u'ShortTitle',
-      u'\\begin_inset Phantom': u'PhantomText',
-      u'\\begin_inset Quotes': u'QuoteContainer',
-      u'\\begin_inset Tabular': u'Table', u'\\begin_inset Text': u'InsetText',
-      u'\\begin_inset VSpace': u'VerticalSpace', u'\\begin_inset Wrap': u'Wrap',
-      u'\\begin_inset listings': u'Listing',
-      u'\\begin_inset script': u'ScriptInset', u'\\begin_inset space': u'Space',
-      u'\\begin_layout': u'Layout', u'\\begin_layout Abstract': u'Abstract',
-      u'\\begin_layout Author': u'Author',
-      u'\\begin_layout Bibliography': u'Bibliography',
-      u'\\begin_layout Chunk': u'NewfangledChunk',
-      u'\\begin_layout Description': u'Description',
-      u'\\begin_layout Enumerate': u'ListItem',
-      u'\\begin_layout Itemize': u'ListItem', u'\\begin_layout List': u'List',
-      u'\\begin_layout LyX-Code': u'LyXCode',
-      u'\\begin_layout Plain': u'PlainLayout',
-      u'\\begin_layout Standard': u'StandardLayout',
-      u'\\begin_layout Title': u'Title', u'\\begin_preamble': u'LyXPreamble',
-      u'\\change_deleted': u'ChangeDeleted',
-      u'\\change_inserted': u'ChangeInserted',
-      u'\\change_unchanged': u'BlackBox', u'\\color': u'ColorText',
-      u'\\color inherit': u'BlackBox', u'\\color none': u'BlackBox',
-      u'\\emph default': u'BlackBox', u'\\emph off': u'BlackBox',
-      u'\\emph on': u'EmphaticText', u'\\emph toggle': u'EmphaticText',
-      u'\\end_body': u'LyXFooter', u'\\family': u'TextFamily',
-      u'\\family default': u'BlackBox', u'\\family roman': u'BlackBox',
-      u'\\hfill': u'Hfill', u'\\labelwidthstring': u'BlackBox',
-      u'\\lang': u'LangLine', u'\\length': u'InsetLength',
-      u'\\lyxformat': u'LyXFormat', u'\\lyxline': u'LyXLine',
-      u'\\newline': u'Newline', u'\\newpage': u'NewPage',
-      u'\\noindent': u'BlackBox', u'\\noun default': u'BlackBox',
-      u'\\noun off': u'BlackBox', u'\\noun on': u'VersalitasText',
-      u'\\paragraph_spacing': u'BlackBox', u'\\series bold': u'BoldText',
-      u'\\series default': u'BlackBox', u'\\series medium': u'BlackBox',
-      u'\\shape': u'ShapedText', u'\\shape default': u'BlackBox',
-      u'\\shape up': u'BlackBox', u'\\size': u'SizeText',
-      u'\\size normal': u'BlackBox', u'\\start_of_appendix': u'StartAppendix',
-      u'\\strikeout default': u'BlackBox', u'\\strikeout on': u'StrikeOut',
-      }
-
-  string = {
-      u'startcommand': u'\\',
-      }
-
-  table = {
-      u'headers': [u'<lyxtabular', u'<features',],
-      }
-
-class EscapeConfig(object):
-  "Configuration class from elyxer.config file"
-
-  chars = {
-      u'\n': u'', u' -- ': u' — ', u' --- ': u' — ', u'\'': u'’', u'`': u'‘',
-      }
-
-  commands = {
-      u'\\InsetSpace \\space{}': u' ', u'\\InsetSpace \\thinspace{}': u' ',
-      u'\\InsetSpace ~': u' ', u'\\SpecialChar \\-': u'',
-      u'\\SpecialChar \\@.': u'.', u'\\SpecialChar \\ldots{}': u'…',
-      u'\\SpecialChar \\menuseparator': u' ▷ ',
-      u'\\SpecialChar \\nobreakdash-': u'-', u'\\SpecialChar \\slash{}': u'/',
-      u'\\SpecialChar \\textcompwordmark{}': u'', u'\\backslash': u'\\',
-      }
-
-  entities = {
-      u'&': u'&amp;', u'<': u'&lt;', u'>': u'&gt;',
-      }
-
-  html = {
-      u'/>': u'>',
-      }
-
-  iso885915 = {
-      u' ': u'&nbsp;', u' ': u'&emsp;', u' ': u'&#8197;',
-      }
-
-  nonunicode = {
-      u' ': u' ',
-      }
-
-class FormulaConfig(object):
-  "Configuration class from elyxer.config file"
-
-  alphacommands = {
-      u'\\AA': u'Å', u'\\AE': u'Æ',
-      u'\\AmS': u'<span class="versalitas">AmS</span>', u'\\Angstroem': u'Å',
-      u'\\DH': u'Ð', u'\\Koppa': u'Ϟ', u'\\L': u'Ł', u'\\Micro': u'µ', u'\\O': u'Ø',
-      u'\\OE': u'Œ', u'\\Sampi': u'Ϡ', u'\\Stigma': u'Ϛ', u'\\TH': u'Þ',
-      u'\\aa': u'å', u'\\ae': u'æ', u'\\alpha': u'α', u'\\beta': u'β',
-      u'\\delta': u'δ', u'\\dh': u'ð', u'\\digamma': u'ϝ', u'\\epsilon': u'ϵ',
-      u'\\eta': u'η', u'\\eth': u'ð', u'\\gamma': u'γ', u'\\i': u'ı',
-      u'\\imath': u'ı', u'\\iota': u'ι', u'\\j': u'ȷ', u'\\jmath': u'ȷ',
-      u'\\kappa': u'κ', u'\\koppa': u'ϟ', u'\\l': u'ł', u'\\lambda': u'λ',
-      u'\\mu': u'μ', u'\\nu': u'ν', u'\\o': u'ø', u'\\oe': u'œ', u'\\omega': u'ω',
-      u'\\phi': u'φ', u'\\pi': u'π', u'\\psi': u'ψ', u'\\rho': u'ρ',
-      u'\\sampi': u'ϡ', u'\\sigma': u'σ', u'\\ss': u'ß', u'\\stigma': u'ϛ',
-      u'\\tau': u'τ', u'\\tcohm': u'Ω', u'\\textcrh': u'ħ', u'\\th': u'þ',
-      u'\\theta': u'θ', u'\\upsilon': u'υ', u'\\varDelta': u'∆',
-      u'\\varGamma': u'Γ', u'\\varLambda': u'Λ', u'\\varOmega': u'Ω',
-      u'\\varPhi': u'Φ', u'\\varPi': u'Π', u'\\varPsi': u'Ψ', u'\\varSigma': u'Σ',
-      u'\\varTheta': u'Θ', u'\\varUpsilon': u'Υ', u'\\varXi': u'Ξ',
-      u'\\varbeta': u'ϐ', u'\\varepsilon': u'ε', u'\\varkappa': u'ϰ',
-      u'\\varphi': u'φ', u'\\varpi': u'ϖ', u'\\varrho': u'ϱ', u'\\varsigma': u'ς',
-      u'\\vartheta': u'ϑ', u'\\xi': u'ξ', u'\\zeta': u'ζ',
-      }
-
-  array = {
-      u'begin': u'\\begin', u'cellseparator': u'&', u'end': u'\\end',
-      u'rowseparator': u'\\\\',
-      }
-
-  bigbrackets = {
-      u'(': [u'⎛', u'⎜', u'⎝',], u')': [u'⎞', u'⎟', u'⎠',], u'[': [u'⎡', u'⎢', u'⎣',],
-      u']': [u'⎤', u'⎥', u'⎦',], u'{': [u'⎧', u'⎪', u'⎨', u'⎩',], u'|': [u'|',],
-      u'}': [u'⎫', u'⎪', u'⎬', u'⎭',], u'∥': [u'∥',],
-      }
-
-  bigsymbols = {
-      u'∑': [u'⎲', u'⎳',], u'∫': [u'⌠', u'⌡',],
-      }
-
-  bracketcommands = {
-      u'\\left': u'span class="symbol"',
-      u'\\left.': u'<span class="leftdot"></span>',
-      u'\\middle': u'span class="symbol"', u'\\right': u'span class="symbol"',
-      u'\\right.': u'<span class="rightdot"></span>',
-      }
-
-  combiningfunctions = {
-      u'\\"': u'̈', u'\\\'': u'́', u'\\^': u'̂', u'\\`': u'̀', u'\\acute': u'́',
-      u'\\bar': u'̄', u'\\breve': u'̆', u'\\c': u'̧', u'\\check': u'̌',
-      u'\\dddot': u'⃛', u'\\ddot': u'̈', u'\\dot': u'̇', u'\\grave': u'̀',
-      u'\\hat': u'̂', u'\\mathring': u'̊', u'\\overleftarrow': u'⃖',
-      u'\\overrightarrow': u'⃗', u'\\r': u'̊', u'\\s': u'̩',
-      u'\\textcircled': u'⃝', u'\\textsubring': u'̥', u'\\tilde': u'̃',
-      u'\\v': u'̌', u'\\vec': u'⃗', u'\\~': u'̃',
-      }
-
-  commands = {
-      u'\\ ': u' ', u'\\!': u'', u'\\#': u'#', u'\\$': u'$', u'\\%': u'%',
-      u'\\&': u'&', u'\\,': u' ', u'\\:': u' ', u'\\;': u' ', u'\\AC': u'∿',
-      u'\\APLcomment': u'⍝', u'\\APLdownarrowbox': u'⍗', u'\\APLinput': u'⍞',
-      u'\\APLinv': u'⌹', u'\\APLleftarrowbox': u'⍇', u'\\APLlog': u'⍟',
-      u'\\APLrightarrowbox': u'⍈', u'\\APLuparrowbox': u'⍐', u'\\Box': u'□',
-      u'\\Bumpeq': u'≎', u'\\CIRCLE': u'●', u'\\Cap': u'⋒',
-      u'\\CapitalDifferentialD': u'ⅅ', u'\\CheckedBox': u'☑', u'\\Circle': u'○',
-      u'\\Coloneqq': u'⩴', u'\\ComplexI': u'ⅈ', u'\\ComplexJ': u'ⅉ',
-      u'\\Corresponds': u'≙', u'\\Cup': u'⋓', u'\\Delta': u'Δ', u'\\Diamond': u'◇',
-      u'\\Diamondblack': u'◆', u'\\Diamonddot': u'⟐', u'\\DifferentialD': u'ⅆ',
-      u'\\Downarrow': u'⇓', u'\\EUR': u'€', u'\\Euler': u'ℇ',
-      u'\\ExponetialE': u'ⅇ', u'\\Finv': u'Ⅎ', u'\\Game': u'⅁', u'\\Gamma': u'Γ',
-      u'\\Im': u'ℑ', u'\\Join': u'⨝', u'\\LEFTCIRCLE': u'◖', u'\\LEFTcircle': u'◐',
-      u'\\LHD': u'◀', u'\\Lambda': u'Λ', u'\\Lbag': u'⟅', u'\\Leftarrow': u'⇐',
-      u'\\Lleftarrow': u'⇚', u'\\Longleftarrow': u'⟸',
-      u'\\Longleftrightarrow': u'⟺', u'\\Longrightarrow': u'⟹', u'\\Lparen': u'⦅',
-      u'\\Lsh': u'↰', u'\\Mapsfrom': u'⇐|', u'\\Mapsto': u'|⇒', u'\\Omega': u'Ω',
-      u'\\P': u'¶', u'\\Phi': u'Φ', u'\\Pi': u'Π', u'\\Pr': u'Pr', u'\\Psi': u'Ψ',
-      u'\\Qoppa': u'Ϙ', u'\\RHD': u'▶', u'\\RIGHTCIRCLE': u'◗',
-      u'\\RIGHTcircle': u'◑', u'\\Rbag': u'⟆', u'\\Re': u'ℜ', u'\\Rparen': u'⦆',
-      u'\\Rrightarrow': u'⇛', u'\\Rsh': u'↱', u'\\S': u'§', u'\\Sigma': u'Σ',
-      u'\\Square': u'☐', u'\\Subset': u'⋐', u'\\Sun': u'☉', u'\\Supset': u'⋑',
-      u'\\Theta': u'Θ', u'\\Uparrow': u'⇑', u'\\Updownarrow': u'⇕',
-      u'\\Upsilon': u'Υ', u'\\Vdash': u'⊩', u'\\Vert': u'∥', u'\\Vvdash': u'⊪',
-      u'\\XBox': u'☒', u'\\Xi': u'Ξ', u'\\Yup': u'⅄', u'\\\\': u'<br/>',
-      u'\\_': u'_', u'\\aleph': u'ℵ', u'\\amalg': u'∐', u'\\anchor': u'⚓',
-      u'\\angle': u'∠', u'\\aquarius': u'♒', u'\\arccos': u'arccos',
-      u'\\arcsin': u'arcsin', u'\\arctan': u'arctan', u'\\arg': u'arg',
-      u'\\aries': u'♈', u'\\arrowbullet': u'➢', u'\\ast': u'∗', u'\\asymp': u'≍',
-      u'\\backepsilon': u'∍', u'\\backprime': u'‵', u'\\backsimeq': u'⋍',
-      u'\\backslash': u'\\', u'\\ballotx': u'✗', u'\\barwedge': u'⊼',
-      u'\\because': u'∵', u'\\beth': u'ℶ', u'\\between': u'≬', u'\\bigcap': u'∩',
-      u'\\bigcirc': u'○', u'\\bigcup': u'∪', u'\\bigodot': u'⊙',
-      u'\\bigoplus': u'⊕', u'\\bigotimes': u'⊗', u'\\bigsqcup': u'⊔',
-      u'\\bigstar': u'★', u'\\bigtriangledown': u'▽', u'\\bigtriangleup': u'△',
-      u'\\biguplus': u'⊎', u'\\bigvee': u'∨', u'\\bigwedge': u'∧',
-      u'\\biohazard': u'☣', u'\\blacklozenge': u'⧫', u'\\blacksmiley': u'☻',
-      u'\\blacksquare': u'■', u'\\blacktriangle': u'▲',
-      u'\\blacktriangledown': u'▼', u'\\blacktriangleleft': u'◂',
-      u'\\blacktriangleright': u'▶', u'\\blacktriangleup': u'▴', u'\\bot': u'⊥',
-      u'\\bowtie': u'⋈', u'\\box': u'▫', u'\\boxast': u'⧆', u'\\boxbar': u'◫',
-      u'\\boxbox': u'⧈', u'\\boxbslash': u'⧅', u'\\boxcircle': u'⧇',
-      u'\\boxdot': u'⊡', u'\\boxminus': u'⊟', u'\\boxplus': u'⊞',
-      u'\\boxslash': u'⧄', u'\\boxtimes': u'⊠', u'\\bullet': u'•',
-      u'\\bumpeq': u'≏', u'\\cancer': u'♋', u'\\cap': u'∩', u'\\capricornus': u'♑',
-      u'\\cat': u'⁀', u'\\cdot': u'⋅', u'\\cdots': u'⋯', u'\\cent': u'¢',
-      u'\\centerdot': u'∙', u'\\checkmark': u'✓', u'\\chi': u'χ', u'\\circ': u'∘',
-      u'\\circeq': u'≗', u'\\circlearrowleft': u'↺', u'\\circlearrowright': u'↻',
-      u'\\circledR': u'®', u'\\circledast': u'⊛', u'\\circledbslash': u'⦸',
-      u'\\circledcirc': u'⊚', u'\\circleddash': u'⊝', u'\\circledgtr': u'⧁',
-      u'\\circledless': u'⧀', u'\\clubsuit': u'♣', u'\\colon': u': ', u'\\coloneqq': u'≔',
-      u'\\complement': u'∁', u'\\cong': u'≅', u'\\coprod': u'∐',
-      u'\\copyright': u'©', u'\\cos': u'cos', u'\\cosh': u'cosh', u'\\cot': u'cot',
-      u'\\coth': u'coth', u'\\csc': u'csc', u'\\cup': u'∪', u'\\curlyvee': u'⋎',
-      u'\\curlywedge': u'⋏', u'\\curvearrowleft': u'↶',
-      u'\\curvearrowright': u'↷', u'\\dag': u'†', u'\\dagger': u'†',
-      u'\\daleth': u'ℸ', u'\\dashleftarrow': u'⇠', u'\\dashv': u'⊣',
-      u'\\ddag': u'‡', u'\\ddagger': u'‡', u'\\ddots': u'⋱', u'\\deg': u'deg',
-      u'\\det': u'det', u'\\diagdown': u'╲', u'\\diagup': u'╱',
-      u'\\diameter': u'⌀', u'\\diamond': u'◇', u'\\diamondsuit': u'♦',
-      u'\\dim': u'dim', u'\\div': u'÷', u'\\divideontimes': u'⋇',
-      u'\\dotdiv': u'∸', u'\\doteq': u'≐', u'\\doteqdot': u'≑', u'\\dotplus': u'∔',
-      u'\\dots': u'…', u'\\doublebarwedge': u'⌆', u'\\downarrow': u'↓',
-      u'\\downdownarrows': u'⇊', u'\\downharpoonleft': u'⇃',
-      u'\\downharpoonright': u'⇂', u'\\dsub': u'⩤', u'\\earth': u'♁',
-      u'\\eighthnote': u'♪', u'\\ell': u'ℓ', u'\\emptyset': u'∅',
-      u'\\eqcirc': u'≖', u'\\eqcolon': u'≕', u'\\eqsim': u'≂', u'\\euro': u'€',
-      u'\\exists': u'∃', u'\\exp': u'exp', u'\\fallingdotseq': u'≒',
-      u'\\fcmp': u'⨾', u'\\female': u'♀', u'\\flat': u'♭', u'\\forall': u'∀',
-      u'\\fourth': u'⁗', u'\\frown': u'⌢', u'\\frownie': u'☹', u'\\gcd': u'gcd',
-      u'\\gemini': u'♊', u'\\geq)': u'≥', u'\\geqq': u'≧', u'\\geqslant': u'≥',
-      u'\\gets': u'←', u'\\gg': u'≫', u'\\ggg': u'⋙', u'\\gimel': u'ℷ',
-      u'\\gneqq': u'≩', u'\\gnsim': u'⋧', u'\\gtrdot': u'⋗', u'\\gtreqless': u'⋚',
-      u'\\gtreqqless': u'⪌', u'\\gtrless': u'≷', u'\\gtrsim': u'≳',
-      u'\\guillemotleft': u'«', u'\\guillemotright': u'»', u'\\hbar': u'ℏ',
-      u'\\heartsuit': u'♥', u'\\hfill': u'<span class="hfill"> </span>',
-      u'\\hom': u'hom', u'\\hookleftarrow': u'↩', u'\\hookrightarrow': u'↪',
-      u'\\hslash': u'ℏ', u'\\idotsint': u'<span class="bigsymbol">∫⋯∫</span>',
-      u'\\iiint': u'<span class="bigsymbol">∭</span>',
-      u'\\iint': u'<span class="bigsymbol">∬</span>', u'\\imath': u'ı',
-      u'\\inf': u'inf', u'\\infty': u'∞', u'\\intercal': u'⊺',
-      u'\\interleave': u'⫴', u'\\invamp': u'⅋', u'\\invneg': u'⌐',
-      u'\\jmath': u'ȷ', u'\\jupiter': u'♃', u'\\ker': u'ker', u'\\land': u'∧',
-      u'\\landupint': u'<span class="bigsymbol">∱</span>', u'\\lang': u'⟪',
-      u'\\langle': u'⟨', u'\\lblot': u'⦉', u'\\lbrace': u'{', u'\\lbrace)': u'{',
-      u'\\lbrack': u'[', u'\\lceil': u'⌈', u'\\ldots': u'…', u'\\leadsto': u'⇝',
-      u'\\leftarrow)': u'←', u'\\leftarrowtail': u'↢', u'\\leftarrowtobar': u'⇤',
-      u'\\leftharpoondown': u'↽', u'\\leftharpoonup': u'↼',
-      u'\\leftleftarrows': u'⇇', u'\\leftleftharpoons': u'⥢', u'\\leftmoon': u'☾',
-      u'\\leftrightarrow': u'↔', u'\\leftrightarrows': u'⇆',
-      u'\\leftrightharpoons': u'⇋', u'\\leftthreetimes': u'⋋', u'\\leo': u'♌',
-      u'\\leq)': u'≤', u'\\leqq': u'≦', u'\\leqslant': u'≤', u'\\lessdot': u'⋖',
-      u'\\lesseqgtr': u'⋛', u'\\lesseqqgtr': u'⪋', u'\\lessgtr': u'≶',
-      u'\\lesssim': u'≲', u'\\lfloor': u'⌊', u'\\lg': u'lg', u'\\lgroup': u'⟮',
-      u'\\lhd': u'⊲', u'\\libra': u'♎', u'\\lightning': u'↯', u'\\limg': u'⦇',
-      u'\\liminf': u'liminf', u'\\limsup': u'limsup', u'\\ll': u'≪',
-      u'\\llbracket': u'⟦', u'\\llcorner': u'⌞', u'\\lll': u'⋘', u'\\ln': u'ln',
-      u'\\lneqq': u'≨', u'\\lnot': u'¬', u'\\lnsim': u'⋦', u'\\log': u'log',
-      u'\\longleftarrow': u'⟵', u'\\longleftrightarrow': u'⟷',
-      u'\\longmapsto': u'⟼', u'\\longrightarrow': u'⟶', u'\\looparrowleft': u'↫',
-      u'\\looparrowright': u'↬', u'\\lor': u'∨', u'\\lozenge': u'◊',
-      u'\\lrcorner': u'⌟', u'\\ltimes': u'⋉', u'\\lyxlock': u'', u'\\male': u'♂',
-      u'\\maltese': u'✠', u'\\mapsfrom': u'↤', u'\\mapsto': u'↦',
-      u'\\mathcircumflex': u'^', u'\\max': u'max', u'\\measuredangle': u'∡',
-      u'\\medbullet': u'⚫', u'\\medcirc': u'⚪', u'\\mercury': u'☿', u'\\mho': u'℧',
-      u'\\mid': u'∣', u'\\min': u'min', u'\\models': u'⊨', u'\\mp': u'∓',
-      u'\\multimap': u'⊸', u'\\nLeftarrow': u'⇍', u'\\nLeftrightarrow': u'⇎',
-      u'\\nRightarrow': u'⇏', u'\\nVDash': u'⊯', u'\\nabla': u'∇',
-      u'\\napprox': u'≉', u'\\natural': u'♮', u'\\ncong': u'≇', u'\\nearrow': u'↗',
-      u'\\neg': u'¬', u'\\neg)': u'¬', u'\\neptune': u'♆', u'\\nequiv': u'≢',
-      u'\\newline': u'<br/>', u'\\nexists': u'∄', u'\\ngeqslant': u'≱',
-      u'\\ngtr': u'≯', u'\\ngtrless': u'≹', u'\\ni': u'∋', u'\\ni)': u'∋',
-      u'\\nleftarrow': u'↚', u'\\nleftrightarrow': u'↮', u'\\nleqslant': u'≰',
-      u'\\nless': u'≮', u'\\nlessgtr': u'≸', u'\\nmid': u'∤', u'\\nolimits': u'',
-      u'\\nonumber': u'', u'\\not': u'¬', u'\\not<': u'≮', u'\\not=': u'≠',
-      u'\\not>': u'≯', u'\\notbackslash': u'⍀', u'\\notin': u'∉', u'\\notni': u'∌',
-      u'\\notslash': u'⌿', u'\\nparallel': u'∦', u'\\nprec': u'⊀',
-      u'\\nrightarrow': u'↛', u'\\nsim': u'≁', u'\\nsimeq': u'≄',
-      u'\\nsqsubset': u'⊏̸', u'\\nsubseteq': u'⊈', u'\\nsucc': u'⊁',
-      u'\\nsucccurlyeq': u'⋡', u'\\nsupset': u'⊅', u'\\nsupseteq': u'⊉',
-      u'\\ntriangleleft': u'⋪', u'\\ntrianglelefteq': u'⋬',
-      u'\\ntriangleright': u'⋫', u'\\ntrianglerighteq': u'⋭', u'\\nvDash': u'⊭',
-      u'\\nvdash': u'⊬', u'\\nwarrow': u'↖', u'\\odot': u'⊙',
-      u'\\officialeuro': u'€', u'\\oiiint': u'<span class="bigsymbol">∰</span>',
-      u'\\oiint': u'<span class="bigsymbol">∯</span>',
-      u'\\oint': u'<span class="bigsymbol">∮</span>',
-      u'\\ointclockwise': u'<span class="bigsymbol">∲</span>',
-      u'\\ointctrclockwise': u'<span class="bigsymbol">∳</span>',
-      u'\\ominus': u'⊖', u'\\oplus': u'⊕', u'\\oslash': u'⊘', u'\\otimes': u'⊗',
-      u'\\owns': u'∋', u'\\parallel': u'∥', u'\\partial': u'∂', u'\\pencil': u'✎',
-      u'\\perp': u'⊥', u'\\pisces': u'♓', u'\\pitchfork': u'⋔', u'\\pluto': u'♇',
-      u'\\pm': u'±', u'\\pointer': u'➪', u'\\pointright': u'☞', u'\\pounds': u'£',
-      u'\\prec': u'≺', u'\\preccurlyeq': u'≼', u'\\preceq': u'≼',
-      u'\\precsim': u'≾', u'\\prime': u'′', u'\\prompto': u'∝', u'\\qoppa': u'ϙ',
-      u'\\qquad': u'  ', u'\\quad': u' ', u'\\quarternote': u'♩',
-      u'\\radiation': u'☢', u'\\rang': u'⟫', u'\\rangle': u'⟩', u'\\rblot': u'⦊',
-      u'\\rbrace': u'}', u'\\rbrace)': u'}', u'\\rbrack': u']', u'\\rceil': u'⌉',
-      u'\\recycle': u'♻', u'\\rfloor': u'⌋', u'\\rgroup': u'⟯', u'\\rhd': u'⊳',
-      u'\\rightangle': u'∟', u'\\rightarrow)': u'→', u'\\rightarrowtail': u'↣',
-      u'\\rightarrowtobar': u'⇥', u'\\rightharpoondown': u'⇁',
-      u'\\rightharpoonup': u'⇀', u'\\rightharpooondown': u'⇁',
-      u'\\rightharpooonup': u'⇀', u'\\rightleftarrows': u'⇄',
-      u'\\rightleftharpoons': u'⇌', u'\\rightmoon': u'☽',
-      u'\\rightrightarrows': u'⇉', u'\\rightrightharpoons': u'⥤',
-      u'\\rightthreetimes': u'⋌', u'\\rimg': u'⦈', u'\\risingdotseq': u'≓',
-      u'\\rrbracket': u'⟧', u'\\rsub': u'⩥', u'\\rtimes': u'⋊',
-      u'\\sagittarius': u'♐', u'\\saturn': u'♄', u'\\scorpio': u'♏',
-      u'\\searrow': u'↘', u'\\sec': u'sec', u'\\second': u'″', u'\\setminus': u'∖',
-      u'\\sharp': u'♯', u'\\simeq': u'≃', u'\\sin': u'sin', u'\\sinh': u'sinh',
-      u'\\sixteenthnote': u'♬', u'\\skull': u'☠', u'\\slash': u'∕',
-      u'\\smallsetminus': u'∖', u'\\smalltriangledown': u'▿',
-      u'\\smalltriangleleft': u'◃', u'\\smalltriangleright': u'▹',
-      u'\\smalltriangleup': u'▵', u'\\smile': u'⌣', u'\\smiley': u'☺',
-      u'\\spadesuit': u'♠', u'\\spddot': u'¨', u'\\sphat': u'',
-      u'\\sphericalangle': u'∢', u'\\spot': u'⦁', u'\\sptilde': u'~',
-      u'\\sqcap': u'⊓', u'\\sqcup': u'⊔', u'\\sqsubset': u'⊏',
-      u'\\sqsubseteq': u'⊑', u'\\sqsupset': u'⊐', u'\\sqsupseteq': u'⊒',
-      u'\\square': u'□', u'\\sslash': u'⫽', u'\\star': u'⋆', u'\\steaming': u'☕',
-      u'\\subseteqq': u'⫅', u'\\subsetneqq': u'⫋', u'\\succ': u'≻',
-      u'\\succcurlyeq': u'≽', u'\\succeq': u'≽', u'\\succnsim': u'⋩',
-      u'\\succsim': u'≿', u'\\sun': u'☼', u'\\sup': u'sup', u'\\supseteqq': u'⫆',
-      u'\\supsetneqq': u'⫌', u'\\surd': u'√', u'\\swarrow': u'↙',
-      u'\\swords': u'⚔', u'\\talloblong': u'⫾', u'\\tan': u'tan',
-      u'\\tanh': u'tanh', u'\\taurus': u'♉', u'\\textasciicircum': u'^',
-      u'\\textasciitilde': u'~', u'\\textbackslash': u'\\',
-      u'\\textcopyright': u'©\'', u'\\textdegree': u'°', u'\\textellipsis': u'…',
-      u'\\textemdash': u'—', u'\\textendash': u'—', u'\\texteuro': u'€',
-      u'\\textgreater': u'>', u'\\textless': u'<', u'\\textordfeminine': u'ª',
-      u'\\textordmasculine': u'º', u'\\textquotedblleft': u'“',
-      u'\\textquotedblright': u'”', u'\\textquoteright': u'’',
-      u'\\textregistered': u'®', u'\\textrightarrow': u'→',
-      u'\\textsection': u'§', u'\\texttrademark': u'™',
-      u'\\texttwosuperior': u'²', u'\\textvisiblespace': u' ',
-      u'\\therefore': u'∴', u'\\third': u'‴', u'\\top': u'⊤', u'\\triangle': u'△',
-      u'\\triangleleft': u'⊲', u'\\trianglelefteq': u'⊴', u'\\triangleq': u'≜',
-      u'\\triangleright': u'▷', u'\\trianglerighteq': u'⊵',
-      u'\\twoheadleftarrow': u'↞', u'\\twoheadrightarrow': u'↠',
-      u'\\twonotes': u'♫', u'\\udot': u'⊍', u'\\ulcorner': u'⌜', u'\\unlhd': u'⊴',
-      u'\\unrhd': u'⊵', u'\\unrhl': u'⊵', u'\\uparrow': u'↑',
-      u'\\updownarrow': u'↕', u'\\upharpoonleft': u'↿', u'\\upharpoonright': u'↾',
-      u'\\uplus': u'⊎', u'\\upuparrows': u'⇈', u'\\uranus': u'♅',
-      u'\\urcorner': u'⌝', u'\\vDash': u'⊨', u'\\varclubsuit': u'♧',
-      u'\\vardiamondsuit': u'♦', u'\\varheartsuit': u'♥', u'\\varnothing': u'∅',
-      u'\\varspadesuit': u'♤', u'\\vdash': u'⊢', u'\\vdots': u'⋮', u'\\vee': u'∨',
-      u'\\vee)': u'∨', u'\\veebar': u'⊻', u'\\vert': u'∣', u'\\virgo': u'♍',
-      u'\\warning': u'⚠', u'\\wasylozenge': u'⌑', u'\\wedge': u'∧',
-      u'\\wedge)': u'∧', u'\\wp': u'℘', u'\\wr': u'≀', u'\\yen': u'¥',
-      u'\\yinyang': u'☯', u'\\{': u'{', u'\\|': u'∥', u'\\}': u'}',
-      }
-
-  decoratedcommand = {
-      }
-
-  decoratingfunctions = {
-      u'\\overleftarrow': u'⟵', u'\\overrightarrow': u'⟶', u'\\widehat': u'^',
-      }
-
-  endings = {
-      u'bracket': u'}', u'complex': u'\\]', u'endafter': u'}',
-      u'endbefore': u'\\end{', u'squarebracket': u']',
-      }
-
-  environments = {
-      u'align': [u'r', u'l',], u'eqnarray': [u'r', u'c', u'l',],
-      u'gathered': [u'l', u'l',],
-      }
-
-  fontfunctions = {
-      u'\\boldsymbol': u'b', u'\\mathbb': u'span class="blackboard"',
-      u'\\mathbb{A}': u'𝔸', u'\\mathbb{B}': u'𝔹', u'\\mathbb{C}': u'ℂ',
-      u'\\mathbb{D}': u'𝔻', u'\\mathbb{E}': u'𝔼', u'\\mathbb{F}': u'𝔽',
-      u'\\mathbb{G}': u'𝔾', u'\\mathbb{H}': u'ℍ', u'\\mathbb{J}': u'𝕁',
-      u'\\mathbb{K}': u'𝕂', u'\\mathbb{L}': u'𝕃', u'\\mathbb{N}': u'ℕ',
-      u'\\mathbb{O}': u'𝕆', u'\\mathbb{P}': u'ℙ', u'\\mathbb{Q}': u'ℚ',
-      u'\\mathbb{R}': u'ℝ', u'\\mathbb{S}': u'𝕊', u'\\mathbb{T}': u'𝕋',
-      u'\\mathbb{W}': u'𝕎', u'\\mathbb{Z}': u'ℤ', u'\\mathbf': u'b',
-      u'\\mathcal': u'span class="scriptfont"', u'\\mathcal{B}': u'ℬ',
-      u'\\mathcal{E}': u'ℰ', u'\\mathcal{F}': u'ℱ', u'\\mathcal{H}': u'ℋ',
-      u'\\mathcal{I}': u'ℐ', u'\\mathcal{L}': u'ℒ', u'\\mathcal{M}': u'ℳ',
-      u'\\mathcal{R}': u'ℛ', u'\\mathfrak': u'span class="fraktur"',
-      u'\\mathfrak{C}': u'ℭ', u'\\mathfrak{F}': u'𝔉', u'\\mathfrak{H}': u'ℌ',
-      u'\\mathfrak{I}': u'ℑ', u'\\mathfrak{R}': u'ℜ', u'\\mathfrak{Z}': u'ℨ',
-      u'\\mathit': u'i', u'\\mathring{A}': u'Å', u'\\mathring{U}': u'Ů',
-      u'\\mathring{a}': u'å', u'\\mathring{u}': u'ů', u'\\mathring{w}': u'ẘ',
-      u'\\mathring{y}': u'ẙ', u'\\mathrm': u'span class="mathrm"',
-      u'\\mathscr': u'span class="scriptfont"', u'\\mathscr{B}': u'ℬ',
-      u'\\mathscr{E}': u'ℰ', u'\\mathscr{F}': u'ℱ', u'\\mathscr{H}': u'ℋ',
-      u'\\mathscr{I}': u'ℐ', u'\\mathscr{L}': u'ℒ', u'\\mathscr{M}': u'ℳ',
-      u'\\mathscr{R}': u'ℛ', u'\\mathsf': u'span class="mathsf"',
-      u'\\mathtt': u'tt',
-      }
-
-  hybridfunctions = {
-      u'\\addcontentsline': [u'{$p!}{$q!}{$r!}', u'f0{}', u'ignored',],
-      u'\\addtocontents': [u'{$p!}{$q!}', u'f0{}', u'ignored',],
-      u'\\backmatter': [u'', u'f0{}', u'ignored',],
-      u'\\binom': [u'{$1}{$2}', u'f2{(}f0{f1{$1}f1{$2}}f2{)}', u'span class="binom"', u'span class="binomstack"', u'span class="bigsymbol"',],
-      u'\\boxed': [u'{$1}', u'f0{$1}', u'span class="boxed"',],
-      u'\\cfrac': [u'[$p!]{$1}{$2}', u'f0{f3{(}f1{$1}f3{)/(}f2{$2}f3{)}}', u'span class="fullfraction"', u'span class="numerator align-$p"', u'span class="denominator"', u'span class="ignored"',],
-      u'\\color': [u'{$p!}{$1}', u'f0{$1}', u'span style="color: $p;"',],
-      u'\\colorbox': [u'{$p!}{$1}', u'f0{$1}', u'span class="colorbox" style="background: $p;"',],
-      u'\\dbinom': [u'{$1}{$2}', u'(f0{f1{f2{$1}}f1{f2{ }}f1{f2{$2}}})', u'span class="binomial"', u'span class="binomrow"', u'span class="binomcell"',],
-      u'\\dfrac': [u'{$1}{$2}', u'f0{f3{(}f1{$1}f3{)/(}f2{$2}f3{)}}', u'span class="fullfraction"', u'span class="numerator"', u'span class="denominator"', u'span class="ignored"',],
-      u'\\displaystyle': [u'{$1}', u'f0{$1}', u'span class="displaystyle"',],
-      u'\\fancyfoot': [u'[$p!]{$q!}', u'f0{}', u'ignored',],
-      u'\\fancyhead': [u'[$p!]{$q!}', u'f0{}', u'ignored',],
-      u'\\fbox': [u'{$1}', u'f0{$1}', u'span class="fbox"',],
-      u'\\fboxrule': [u'{$p!}', u'f0{}', u'ignored',],
-      u'\\fboxsep': [u'{$p!}', u'f0{}', u'ignored',],
-      u'\\fcolorbox': [u'{$p!}{$q!}{$1}', u'f0{$1}', u'span class="boxed" style="border-color: $p; background: $q;"',],
-      u'\\frac': [u'{$1}{$2}', u'f0{f3{(}f1{$1}f3{)/(}f2{$2}f3{)}}', u'span class="fraction"', u'span class="numerator"', u'span class="denominator"', u'span class="ignored"',],
-      u'\\framebox': [u'[$p!][$q!]{$1}', u'f0{$1}', u'span class="framebox align-$q" style="width: $p;"',],
-      u'\\frontmatter': [u'', u'f0{}', u'ignored',],
-      u'\\href': [u'[$o]{$u!}{$t!}', u'f0{$t}', u'a href="$u"',],
-      u'\\hspace': [u'{$p!}', u'f0{ }', u'span class="hspace" style="width: $p;"',],
-      u'\\leftroot': [u'{$p!}', u'f0{ }', u'span class="leftroot" style="width: $p;px"',],
-      u'\\mainmatter': [u'', u'f0{}', u'ignored',],
-      u'\\markboth': [u'{$p!}{$q!}', u'f0{}', u'ignored',],
-      u'\\markright': [u'{$p!}', u'f0{}', u'ignored',],
-      u'\\nicefrac': [u'{$1}{$2}', u'f0{f1{$1}⁄f2{$2}}', u'span class="fraction"', u'sup class="numerator"', u'sub class="denominator"', u'span class="ignored"',],
-      u'\\parbox': [u'[$p!]{$w!}{$1}', u'f0{1}', u'div class="Boxed" style="width: $w;"',],
-      u'\\raisebox': [u'{$p!}{$1}', u'f0{$1.font}', u'span class="raisebox" style="vertical-align: $p;"',],
-      u'\\renewenvironment': [u'{$1!}{$2!}{$3!}', u'',],
-      u'\\rule': [u'[$v!]{$w!}{$h!}', u'f0/', u'hr class="line" style="width: $w; height: $h;"',],
-      u'\\scriptscriptstyle': [u'{$1}', u'f0{$1}', u'span class="scriptscriptstyle"',],
-      u'\\scriptstyle': [u'{$1}', u'f0{$1}', u'span class="scriptstyle"',],
-      u'\\sqrt': [u'[$0]{$1}', u'f0{f1{$0}f2{√}f4{(}f3{$1}f4{)}}', u'span class="sqrt"', u'sup class="root"', u'span class="radical"', u'span class="root"', u'span class="ignored"',],
-      u'\\stackrel': [u'{$1}{$2}', u'f0{f1{$1}f2{$2}}', u'span class="stackrel"', u'span class="upstackrel"', u'span class="downstackrel"',],
-      u'\\tbinom': [u'{$1}{$2}', u'(f0{f1{f2{$1}}f1{f2{ }}f1{f2{$2}}})', u'span class="binomial"', u'span class="binomrow"', u'span class="binomcell"',],
-      u'\\textcolor': [u'{$p!}{$1}', u'f0{$1}', u'span style="color: $p;"',],
-      u'\\textstyle': [u'{$1}', u'f0{$1}', u'span class="textstyle"',],
-      u'\\thispagestyle': [u'{$p!}', u'f0{}', u'ignored',],
-      u'\\unit': [u'[$0]{$1}', u'$0f0{$1.font}', u'span class="unit"',],
-      u'\\unitfrac': [u'[$0]{$1}{$2}', u'$0f0{f1{$1.font}⁄f2{$2.font}}', u'span class="fraction"', u'sup class="unit"', u'sub class="unit"',],
-      u'\\uproot': [u'{$p!}', u'f0{ }', u'span class="uproot" style="width: $p;px"',],
-      u'\\url': [u'{$u!}', u'f0{$u}', u'a href="$u"',],
-      u'\\vspace': [u'{$p!}', u'f0{ }', u'span class="vspace" style="height: $p;"',],
-      }
-
-  hybridsizes = {
-      u'\\binom': u'$1+$2', u'\\cfrac': u'$1+$2', u'\\dbinom': u'$1+$2+1',
-      u'\\dfrac': u'$1+$2', u'\\frac': u'$1+$2', u'\\tbinom': u'$1+$2+1',
-      }
-
-  labelfunctions = {
-      u'\\label': u'a name="#"',
-      }
-
-  limitcommands = {
-      u'\\biginterleave': u'⫼', u'\\bigsqcap': u'⨅', u'\\fint': u'⨏',
-      u'\\iiiint': u'⨌', u'\\int': u'∫', u'\\intop': u'∫', u'\\lim': u'lim',
-      u'\\prod': u'∏', u'\\smallint': u'∫', u'\\sqint': u'⨖', u'\\sum': u'∑',
-      u'\\varointclockwise': u'∲', u'\\varprod': u'⨉', u'\\zcmp': u'⨟',
-      u'\\zhide': u'⧹', u'\\zpipe': u'⨠', u'\\zproject': u'⨡',
-      }
-
-  misccommands = {
-      u'\\limits': u'LimitPreviousCommand', u'\\newcommand': u'MacroDefinition',
-      u'\\renewcommand': u'MacroDefinition',
-      u'\\setcounter': u'SetCounterFunction', u'\\tag': u'FormulaTag',
-      u'\\tag*': u'FormulaTag', u'\\today': u'TodayCommand',
-      }
-
-  modified = {
-      u'\n': u'', u' ': u'', u'$': u'', u'&': u'	', u'\'': u'’', u'+': u' + ',
-      u',': u', ', u'-': u' − ', u'/': u' ⁄ ', u':': u' : ', u'<': u' &lt; ',
-      u'=': u' = ', u'>': u' &gt; ', u'@': u'', u'~': u'',
-      }
-
-  onefunctions = {
-      u'\\Big': u'span class="bigsymbol"', u'\\Bigg': u'span class="hugesymbol"',
-      u'\\bar': u'span class="bar"', u'\\begin{array}': u'span class="arraydef"',
-      u'\\big': u'span class="symbol"', u'\\bigg': u'span class="largesymbol"',
-      u'\\bigl': u'span class="bigsymbol"', u'\\bigr': u'span class="bigsymbol"',
-      u'\\centering': u'span class="align-center"',
-      u'\\ensuremath': u'span class="ensuremath"',
-      u'\\hphantom': u'span class="phantom"',
-      u'\\noindent': u'span class="noindent"',
-      u'\\overbrace': u'span class="overbrace"',
-      u'\\overline': u'span class="overline"',
-      u'\\phantom': u'span class="phantom"',
-      u'\\underbrace': u'span class="underbrace"', u'\\underline': u'u',
-      u'\\vphantom': u'span class="phantom"',
-      }
-
-  spacedcommands = {
-      u'\\Bot': u'⫫', u'\\Doteq': u'≑', u'\\DownArrowBar': u'⤓',
-      u'\\DownLeftTeeVector': u'⥞', u'\\DownLeftVectorBar': u'⥖',
-      u'\\DownRightTeeVector': u'⥟', u'\\DownRightVectorBar': u'⥗',
-      u'\\Equal': u'⩵', u'\\LeftArrowBar': u'⇤', u'\\LeftDownTeeVector': u'⥡',
-      u'\\LeftDownVectorBar': u'⥙', u'\\LeftTeeVector': u'⥚',
-      u'\\LeftTriangleBar': u'⧏', u'\\LeftUpTeeVector': u'⥠',
-      u'\\LeftUpVectorBar': u'⥘', u'\\LeftVectorBar': u'⥒',
-      u'\\Leftrightarrow': u'⇔', u'\\Longmapsfrom': u'⟽', u'\\Longmapsto': u'⟾',
-      u'\\MapsDown': u'↧', u'\\MapsUp': u'↥', u'\\Nearrow': u'⇗',
-      u'\\NestedGreaterGreater': u'⪢', u'\\NestedLessLess': u'⪡',
-      u'\\NotGreaterLess': u'≹', u'\\NotGreaterTilde': u'≵',
-      u'\\NotLessTilde': u'≴', u'\\Nwarrow': u'⇖', u'\\Proportion': u'∷',
-      u'\\RightArrowBar': u'⇥', u'\\RightDownTeeVector': u'⥝',
-      u'\\RightDownVectorBar': u'⥕', u'\\RightTeeVector': u'⥛',
-      u'\\RightTriangleBar': u'⧐', u'\\RightUpTeeVector': u'⥜',
-      u'\\RightUpVectorBar': u'⥔', u'\\RightVectorBar': u'⥓',
-      u'\\Rightarrow': u'⇒', u'\\Same': u'⩶', u'\\Searrow': u'⇘',
-      u'\\Swarrow': u'⇙', u'\\Top': u'⫪', u'\\UpArrowBar': u'⤒', u'\\VDash': u'⊫',
-      u'\\approx': u'≈', u'\\approxeq': u'≊', u'\\backsim': u'∽', u'\\barin': u'⋶',
-      u'\\barleftharpoon': u'⥫', u'\\barrightharpoon': u'⥭', u'\\bij': u'⤖',
-      u'\\coloneq': u'≔', u'\\corresponds': u'≙', u'\\curlyeqprec': u'⋞',
-      u'\\curlyeqsucc': u'⋟', u'\\dashrightarrow': u'⇢', u'\\dlsh': u'↲',
-      u'\\downdownharpoons': u'⥥', u'\\downuparrows': u'⇵',
-      u'\\downupharpoons': u'⥯', u'\\drsh': u'↳', u'\\eqslantgtr': u'⪖',
-      u'\\eqslantless': u'⪕', u'\\equiv': u'≡', u'\\ffun': u'⇻', u'\\finj': u'⤕',
-      u'\\ge': u'≥', u'\\geq': u'≥', u'\\ggcurly': u'⪼', u'\\gnapprox': u'⪊',
-      u'\\gneq': u'⪈', u'\\gtrapprox': u'⪆', u'\\hash': u'⋕', u'\\iddots': u'⋰',
-      u'\\implies': u' ⇒ ', u'\\in': u'∈', u'\\le': u'≤', u'\\leftarrow': u'←',
-      u'\\leftarrowtriangle': u'⇽', u'\\leftbarharpoon': u'⥪',
-      u'\\leftrightarrowtriangle': u'⇿', u'\\leftrightharpoon': u'⥊',
-      u'\\leftrightharpoondown': u'⥐', u'\\leftrightharpoonup': u'⥎',
-      u'\\leftrightsquigarrow': u'↭', u'\\leftslice': u'⪦',
-      u'\\leftsquigarrow': u'⇜', u'\\leftupdownharpoon': u'⥑', u'\\leq': u'≤',
-      u'\\lessapprox': u'⪅', u'\\llcurly': u'⪻', u'\\lnapprox': u'⪉',
-      u'\\lneq': u'⪇', u'\\longmapsfrom': u'⟻', u'\\multimapboth': u'⧟',
-      u'\\multimapdotbothA': u'⊶', u'\\multimapdotbothB': u'⊷',
-      u'\\multimapinv': u'⟜', u'\\nVdash': u'⊮', u'\\ne': u'≠', u'\\neq': u'≠',
-      u'\\ngeq': u'≱', u'\\nleq': u'≰', u'\\nni': u'∌', u'\\not\\in': u'∉',
-      u'\\notasymp': u'≭', u'\\npreceq': u'⋠', u'\\nsqsubseteq': u'⋢',
-      u'\\nsqsupseteq': u'⋣', u'\\nsubset': u'⊄', u'\\nsucceq': u'⋡',
-      u'\\pfun': u'⇸', u'\\pinj': u'⤔', u'\\precapprox': u'⪷', u'\\preceqq': u'⪳',
-      u'\\precnapprox': u'⪹', u'\\precnsim': u'⋨', u'\\propto': u'∝',
-      u'\\psur': u'⤀', u'\\rightarrow': u'→', u'\\rightarrowtriangle': u'⇾',
-      u'\\rightbarharpoon': u'⥬', u'\\rightleftharpoon': u'⥋',
-      u'\\rightslice': u'⪧', u'\\rightsquigarrow': u'⇝',
-      u'\\rightupdownharpoon': u'⥏', u'\\sim': u'~', u'\\strictfi': u'⥼',
-      u'\\strictif': u'⥽', u'\\subset': u'⊂', u'\\subseteq': u'⊆',
-      u'\\subsetneq': u'⊊', u'\\succapprox': u'⪸', u'\\succeqq': u'⪴',
-      u'\\succnapprox': u'⪺', u'\\supset': u'⊃', u'\\supseteq': u'⊇',
-      u'\\supsetneq': u'⊋', u'\\times': u'×', u'\\to': u'→',
-      u'\\updownarrows': u'⇅', u'\\updownharpoons': u'⥮', u'\\upupharpoons': u'⥣',
-      u'\\vartriangleleft': u'⊲', u'\\vartriangleright': u'⊳',
-      }
-
-  starts = {
-      u'beginafter': u'}', u'beginbefore': u'\\begin{', u'bracket': u'{',
-      u'command': u'\\', u'comment': u'%', u'complex': u'\\[', u'simple': u'$',
-      u'squarebracket': u'[', u'unnumbered': u'*',
-      }
-
-  symbolfunctions = {
-      u'^': u'sup', u'_': u'sub',
-      }
-
-  textfunctions = {
-      u'\\mbox': u'span class="mbox"', u'\\text': u'span class="text"',
-      u'\\textbf': u'b', u'\\textipa': u'span class="textipa"', u'\\textit': u'i',
-      u'\\textnormal': u'span class="textnormal"',
-      u'\\textrm': u'span class="textrm"',
-      u'\\textsc': u'span class="versalitas"',
-      u'\\textsf': u'span class="textsf"', u'\\textsl': u'i', u'\\texttt': u'tt',
-      u'\\textup': u'span class="normal"',
-      }
-
-  unmodified = {
-      u'characters': [u'.', u'*', u'€', u'(', u')', u'[', u']', u'·', u'!', u';', u'|', u'§', u'"',],
-      }
-
-  urls = {
-      u'googlecharts': u'http://chart.googleapis.com/chart?cht=tx&chl=',
-      }
-
-class GeneralConfig(object):
-  "Configuration class from elyxer.config file"
-
-  version = {
-      u'date': u'2015-02-26', u'lyxformat': u'413', u'number': u'1.2.5',
-      }
-
-class HeaderConfig(object):
-  "Configuration class from elyxer.config file"
-
-  parameters = {
-      u'beginpreamble': u'\\begin_preamble', u'branch': u'\\branch',
-      u'documentclass': u'\\textclass', u'endbranch': u'\\end_branch',
-      u'endpreamble': u'\\end_preamble', u'language': u'\\language',
-      u'lstset': u'\\lstset', u'outputchanges': u'\\output_changes',
-      u'paragraphseparation': u'\\paragraph_separation',
-      u'pdftitle': u'\\pdf_title', u'secnumdepth': u'\\secnumdepth',
-      u'tocdepth': u'\\tocdepth',
-      }
-
-  styles = {
-      u'article': [u'article', u'aastex', u'aapaper', u'acmsiggraph', u'sigplanconf', u'achemso', u'amsart', u'apa', u'arab-article', u'armenian-article', u'article-beamer', u'chess', u'dtk', u'elsarticle', u'heb-article', u'IEEEtran', u'iopart', u'kluwer', u'scrarticle-beamer', u'scrartcl', u'extarticle', u'paper', u'mwart', u'revtex4', u'spie', u'svglobal3', u'ltugboat', u'agu-dtd', u'jgrga', u'agums', u'entcs', u'egs', u'ijmpc', u'ijmpd', u'singlecol-new', u'doublecol-new', u'isprs', u'tarticle', u'jsarticle', u'jarticle', u'jss', u'literate-article', u'siamltex', u'cl2emult', u'llncs', u'svglobal', u'svjog', u'svprobth',],
-      u'book': [u'book', u'amsbook', u'scrbook', u'extbook', u'tufte-book', u'report', u'extreport', u'scrreprt', u'memoir', u'tbook', u'jsbook', u'jbook', u'mwbk', u'svmono', u'svmult', u'treport', u'jreport', u'mwrep',],
-      }
-
-class ImageConfig(object):
-  "Configuration class from elyxer.config file"
-
-  converters = {
-      u'imagemagick': u'convert[ -density $scale][ -define $format:use-cropbox=true] "$input" "$output"',
-      u'inkscape': u'inkscape "$input" --export-png="$output"',
-      u'lyx': u'lyx -C "$input" "$output"',
-      }
-
-  cropboxformats = {
-      u'.eps': u'ps', u'.pdf': u'pdf', u'.ps': u'ps',
-      }
-
-  formats = {
-      u'default': u'.png', u'vector': [u'.svg', u'.eps',],
-      }
-
-class LayoutConfig(object):
-  "Configuration class from elyxer.config file"
-
-  groupable = {
-      u'allowed': [u'StringContainer', u'Constant', u'TaggedText', u'Align', u'TextFamily', u'EmphaticText', u'VersalitasText', u'BarredText', u'SizeText', u'ColorText', u'LangLine', u'Formula',],
-      }
-
-class NewfangleConfig(object):
-  "Configuration class from elyxer.config file"
-
-  constants = {
-      u'chunkref': u'chunkref{', u'endcommand': u'}', u'endmark': u'&gt;',
-      u'startcommand': u'\\', u'startmark': u'=&lt;',
-      }
-
-class NumberingConfig(object):
-  "Configuration class from elyxer.config file"
-
-  layouts = {
-      u'ordered': [u'Chapter', u'Section', u'Subsection', u'Subsubsection', u'Paragraph',],
-      u'roman': [u'Part', u'Book',],
-      }
-
-  sequence = {
-      u'symbols': [u'*', u'**', u'†', u'‡', u'§', u'§§', u'¶', u'¶¶', u'#', u'##',],
-      }
-
-class StyleConfig(object):
-  "Configuration class from elyxer.config file"
-
-  hspaces = {
-      u'\\enskip{}': u' ', u'\\hfill{}': u'<span class="hfill"> </span>',
-      u'\\hspace*{\\fill}': u' ', u'\\hspace*{}': u'', u'\\hspace{}': u' ',
-      u'\\negthinspace{}': u'', u'\\qquad{}': u'  ', u'\\quad{}': u' ',
-      u'\\space{}': u' ', u'\\thinspace{}': u' ', u'~': u' ',
-      }
-
-  quotes = {
-      u'ald': u'»', u'als': u'›', u'ard': u'«', u'ars': u'‹', u'eld': u'&ldquo;',
-      u'els': u'&lsquo;', u'erd': u'&rdquo;', u'ers': u'&rsquo;', u'fld': u'«',
-      u'fls': u'‹', u'frd': u'»', u'frs': u'›', u'gld': u'„', u'gls': u'‚',
-      u'grd': u'“', u'grs': u'‘', u'pld': u'„', u'pls': u'‚', u'prd': u'”',
-      u'prs': u'’', u'sld': u'”', u'srd': u'”',
-      }
-
-  referenceformats = {
-      u'eqref': u'(@↕)', u'formatted': u'¶↕', u'nameref': u'$↕', u'pageref': u'#↕',
-      u'ref': u'@↕', u'vpageref': u'on-page#↕', u'vref': u'@on-page#↕',
-      }
-
-  size = {
-      u'ignoredtexts': [u'col', u'text', u'line', u'page', u'theight', u'pheight',],
-      }
-
-  vspaces = {
-      u'bigskip': u'<div class="bigskip"> </div>',
-      u'defskip': u'<div class="defskip"> </div>',
-      u'medskip': u'<div class="medskip"> </div>',
-      u'smallskip': u'<div class="smallskip"> </div>',
-      u'vfill': u'<div class="vfill"> </div>',
-      }
-
-class TOCConfig(object):
-  "Configuration class from elyxer.config file"
-
-  extractplain = {
-      u'allowed': [u'StringContainer', u'Constant', u'TaggedText', u'Align', u'TextFamily', u'EmphaticText', u'VersalitasText', u'BarredText', u'SizeText', u'ColorText', u'LangLine', u'Formula',],
-      u'cloned': [u'',], u'extracted': [u'',],
-      }
-
-  extracttitle = {
-      u'allowed': [u'StringContainer', u'Constant', u'Space',],
-      u'cloned': [u'TextFamily', u'EmphaticText', u'VersalitasText', u'BarredText', u'SizeText', u'ColorText', u'LangLine', u'Formula',],
-      u'extracted': [u'PlainLayout', u'TaggedText', u'Align', u'Caption', u'StandardLayout', u'FlexInset',],
-      }
-
-class TagConfig(object):
-  "Configuration class from elyxer.config file"
-
-  barred = {
-      u'under': u'u',
-      }
-
-  family = {
-      u'sans': u'span class="sans"', u'typewriter': u'tt',
-      }
-
-  flex = {
-      u'CharStyle:Code': u'span class="code"',
-      u'CharStyle:MenuItem': u'span class="menuitem"',
-      u'Code': u'span class="code"', u'MenuItem': u'span class="menuitem"',
-      u'Noun': u'span class="noun"', u'Strong': u'span class="strong"',
-      }
-
-  group = {
-      u'layouts': [u'Quotation', u'Quote',],
-      }
-
-  layouts = {
-      u'Center': u'div', u'Chapter': u'h?', u'Date': u'h2', u'Paragraph': u'div',
-      u'Part': u'h1', u'Quotation': u'blockquote', u'Quote': u'blockquote',
-      u'Section': u'h?', u'Subsection': u'h?', u'Subsubsection': u'h?',
-      }
-
-  listitems = {
-      u'Enumerate': u'ol', u'Itemize': u'ul',
-      }
-
-  notes = {
-      u'Comment': u'', u'Greyedout': u'span class="greyedout"', u'Note': u'',
-      }
-
-  script = {
-      u'subscript': u'sub', u'superscript': u'sup',
-      }
-
-  shaped = {
-      u'italic': u'i', u'slanted': u'i', u'smallcaps': u'span class="versalitas"',
-      }
-
-class TranslationConfig(object):
-  "Configuration class from elyxer.config file"
-
-  constants = {
-      u'Appendix': u'Appendix', u'Book': u'Book', u'Chapter': u'Chapter',
-      u'Paragraph': u'Paragraph', u'Part': u'Part', u'Section': u'Section',
-      u'Subsection': u'Subsection', u'Subsubsection': u'Subsubsection',
-      u'abstract': u'Abstract', u'bibliography': u'Bibliography',
-      u'figure': u'figure', u'float-algorithm': u'Algorithm ',
-      u'float-figure': u'Figure ', u'float-listing': u'Listing ',
-      u'float-table': u'Table ', u'float-tableau': u'Tableau ',
-      u'footnotes': u'Footnotes', u'generated-by': u'Document generated by ',
-      u'generated-on': u' on ', u'index': u'Index',
-      u'jsmath-enable': u'Please enable JavaScript on your browser.',
-      u'jsmath-requires': u' requires JavaScript to correctly process the mathematics on this page. ',
-      u'jsmath-warning': u'Warning: ', u'list-algorithm': u'List of Algorithms',
-      u'list-figure': u'List of Figures', u'list-table': u'List of Tables',
-      u'list-tableau': u'List of Tableaux', u'main-page': u'Main page',
-      u'next': u'Next', u'nomenclature': u'Nomenclature',
-      u'on-page': u' on page ', u'prev': u'Prev', u'references': u'References',
-      u'toc': u'Table of Contents', u'toc-for': u'Contents for ', u'up': u'Up',
-      }
-
-  languages = {
-      u'american': u'en', u'british': u'en', u'deutsch': u'de', u'dutch': u'nl',
-      u'english': u'en', u'french': u'fr', u'ngerman': u'de', u'russian': u'ru',
-      u'spanish': u'es',
-      }
-
-
-class CommandLineParser(object):
-  "A parser for runtime options"
-
-  def __init__(self, options):
-    self.options = options
-
-  def parseoptions(self, args):
-    "Parse command line options"
-    if len(args) == 0:
-      return None
-    while len(args) > 0 and args[0].startswith('--'):
-      key, value = self.readoption(args)
-      if not key:
-        return 'Option ' + value + ' not recognized'
-      if not value:
-        return 'Option ' + key + ' needs a value'
-      setattr(self.options, key, value)
-    return None
-
-  def readoption(self, args):
-    "Read the key and value for an option"
-    arg = args[0][2:]
-    del args[0]
-    if '=' in arg:
-      key = self.readequalskey(arg, args)
-    else:
-      key = arg.replace('-', '')
-    if not hasattr(self.options, key):
-      return None, key
-    current = getattr(self.options, key)
-    if isinstance(current, bool):
-      return key, True
-    # read value
-    if len(args) == 0:
-      return key, None
-    if args[0].startswith('"'):
-      initial = args[0]
-      del args[0]
-      return key, self.readquoted(args, initial)
-    value = args[0].decode('utf-8')
-    del args[0]
-    if isinstance(current, list):
-      current.append(value)
-      return key, current
-    return key, value
-
-  def readquoted(self, args, initial):
-    "Read a value between quotes"
-    Trace.error('Oops')
-    value = initial[1:]
-    while len(args) > 0 and not args[0].endswith('"') and not args[0].startswith('--'):
-      Trace.error('Appending ' + args[0])
-      value += ' ' + args[0]
-      del args[0]
-    if len(args) == 0 or args[0].startswith('--'):
-      return None
-    value += ' ' + args[0:-1]
-    return value
-
-  def readequalskey(self, arg, args):
-    "Read a key using equals"
-    split = arg.split('=', 1)
-    key = split[0]
-    value = split[1]
-    args.insert(0, value)
-    return key
-
-
-class Options(object):
-  "A set of runtime options"
-
-  instance = None
-
-  location = None
-  nocopy = False
-  copyright = False
-  debug = False
-  quiet = False
-  version = False
-  hardversion = False
-  versiondate = False
-  html = False
-  help = False
-  showlines = True
-  unicode = False
-  iso885915 = False
-  css = []
-  favicon = ''
-  title = None
-  directory = None
-  destdirectory = None
-  toc = False
-  toctarget = ''
-  tocfor = None
-  forceformat = None
-  lyxformat = False
-  target = None
-  splitpart = None
-  memory = True
-  lowmem = False
-  nobib = False
-  converter = 'imagemagick'
-  raw = False
-  jsmath = None
-  mathjax = None
-  nofooter = False
-  simplemath = False
-  template = None
-  noconvert = False
-  notoclabels = False
-  letterfoot = True
-  numberfoot = False
-  symbolfoot = False
-  hoverfoot = True
-  marginfoot = False
-  endfoot = False
-  supfoot = True
-  alignfoot = False
-  footnotes = None
-  imageformat = None
-  copyimages = False
-  googlecharts = False
-  embedcss = []
-
-  branches = dict()
-
-  def parseoptions(self, args):
-    "Parse command line options"
-    Options.location = args[0]
-    del args[0]
-    parser = CommandLineParser(Options)
-    result = parser.parseoptions(args)
-    if result:
-      Trace.error(result)
-      self.usage()
-    self.processoptions()
-
-  def processoptions(self):
-    "Process all options parsed."
-    if Options.help:
-      self.usage()
-    if Options.version:
-      self.showversion()
-    if Options.hardversion:
-      self.showhardversion()
-    if Options.versiondate:
-      self.showversiondate()
-    if Options.lyxformat:
-      self.showlyxformat()
-    if Options.splitpart:
-      try:
-        Options.splitpart = int(Options.splitpart)
-        if Options.splitpart <= 0:
-          Trace.error('--splitpart requires a number bigger than zero')
-          self.usage()
-      except:
-        Trace.error('--splitpart needs a numeric argument, not ' + Options.splitpart)
-        self.usage()
-    if Options.lowmem or Options.toc or Options.tocfor:
-      Options.memory = False
-    self.parsefootnotes()
-    if Options.forceformat and not Options.imageformat:
-      Options.imageformat = Options.forceformat
-    if Options.imageformat == 'copy':
-      Options.copyimages = True
-    if Options.css == []:
-      Options.css = ['http://elyxer.nongnu.org/lyx.css']
-    if Options.favicon == '':
-      pass # no default favicon
-    if Options.html:
-      Options.simplemath = True
-    if Options.toc and not Options.tocfor:
-      Trace.error('Option --toc is deprecated; use --tocfor "page" instead')
-      Options.tocfor = Options.toctarget
-    if Options.nocopy:
-      Trace.error('Option --nocopy is deprecated; it is no longer needed')
-    if Options.jsmath:
-      Trace.error('Option --jsmath is deprecated; use --mathjax instead')
-    # set in Trace if necessary
-    for param in dir(Trace):
-      if param.endswith('mode'):
-        setattr(Trace, param, getattr(self, param[:-4]))
-
-  def usage(self):
-    "Show correct usage"
-    Trace.error('Usage: ' + os.path.basename(Options.location) + ' [options] [filein] [fileout]')
-    Trace.error('Convert LyX input file "filein" to HTML file "fileout".')
-    Trace.error('If filein (or fileout) is not given use standard input (or output).')
-    Trace.error('Main program of the eLyXer package (http://elyxer.nongnu.org/).')
-    self.showoptions()
-
-  def parsefootnotes(self):
-    "Parse footnotes options."
-    if not Options.footnotes:
-      return
-    Options.marginfoot = False
-    Options.letterfoot = False
-    Options.hoverfoot = False
-    options = Options.footnotes.split(',')
-    for option in options:
-      footoption = option + 'foot'
-      if hasattr(Options, footoption):
-        setattr(Options, footoption, True)
-      else:
-        Trace.error('Unknown footnotes option: ' + option)
-    if not Options.endfoot and not Options.marginfoot and not Options.hoverfoot:
-      Options.hoverfoot = True
-    if not Options.numberfoot and not Options.symbolfoot:
-      Options.letterfoot = True
-
-  def showoptions(self):
-    "Show all possible options"
-    Trace.error('  Common options:')
-    Trace.error('    --help:                 show this online help')
-    Trace.error('    --quiet:                disables all runtime messages')
-    Trace.error('')
-    Trace.error('  Advanced options:')
-    Trace.error('    --debug:                enable debugging messages (for developers)')
-    Trace.error('    --version:              show version number and release date')
-    Trace.error('    --lyxformat:            return the highest LyX version supported')
-    Trace.error('  Options for HTML output:')
-    Trace.error('    --title "title":        set the generated page title')
-    Trace.error('    --css "file.css":       use a custom CSS file')
-    Trace.error('    --embedcss "file.css":  embed styles from a CSS file into the output')
-    Trace.error('    --favicon "icon.ico":   insert the specified favicon in the header.')
-    Trace.error('    --html:                 output HTML 4.0 instead of the default XHTML')
-    Trace.error('    --unicode:              full Unicode output')
-    Trace.error('    --iso885915:            output a document with ISO-8859-15 encoding')
-    Trace.error('    --nofooter:             remove the footer "generated by eLyXer"')
-    Trace.error('    --simplemath:           do not generate fancy math constructions')
-    Trace.error('  Options for image output:')
-    Trace.error('    --directory "img_dir":  look for images in the specified directory')
-    Trace.error('    --destdirectory "dest": put converted images into this directory')
-    Trace.error('    --imageformat ".ext":   image output format, or "copy" to copy images')
-    Trace.error('    --noconvert:            do not convert images, use in original locations')
-    Trace.error('    --converter "inkscape": use an alternative program to convert images')
-    Trace.error('  Options for footnote display:')
-    Trace.error('    --numberfoot:           mark footnotes with numbers instead of letters')
-    Trace.error('    --symbolfoot:           mark footnotes with symbols (*, **...)')
-    Trace.error('    --hoverfoot:            show footnotes as hovering text (default)')
-    Trace.error('    --marginfoot:           show footnotes on the page margin')
-    Trace.error('    --endfoot:              show footnotes at the end of the page')
-    Trace.error('    --supfoot:              use superscript for footnote markers (default)')
-    Trace.error('    --alignfoot:            use aligned text for footnote markers')
-    Trace.error('    --footnotes "options":  specify several comma-separated footnotes options')
-    Trace.error('      Available options are: "number", "symbol", "hover", "margin", "end",')
-    Trace.error('        "sup", "align"')
-    Trace.error('  Advanced output options:')
-    Trace.error('    --splitpart "depth":    split the resulting webpage at the given depth')
-    Trace.error('    --tocfor "page":        generate a TOC that points to the given page')
-    Trace.error('    --target "frame":       make all links point to the given frame')
-    Trace.error('    --notoclabels:          omit the part labels in the TOC, such as Chapter')
-    Trace.error('    --lowmem:               do the conversion on the fly (conserve memory)')
-    Trace.error('    --raw:                  generate HTML without header or footer.')
-    Trace.error('    --mathjax remote:       use MathJax remotely to display equations')
-    Trace.error('    --mathjax "URL":        use MathJax from the given URL to display equations')
-    Trace.error('    --googlecharts:         use Google Charts to generate formula images')
-    Trace.error('    --template "file":      use a template, put everything in <!--$content-->')
-    Trace.error('    --copyright:            add a copyright notice at the bottom')
-    Trace.error('  Deprecated options:')
-    Trace.error('    --toc:                  (deprecated) create a table of contents')
-    Trace.error('    --toctarget "page":     (deprecated) generate a TOC for the given page')
-    Trace.error('    --nocopy:               (deprecated) maintained for backwards compatibility')
-    Trace.error('    --jsmath "URL":         use jsMath from the given URL to display equations')
-    sys.exit()
-
-  def showversion(self):
-    "Return the current eLyXer version string"
-    string = 'eLyXer version ' + GeneralConfig.version['number']
-    string += ' (' + GeneralConfig.version['date'] + ')'
-    Trace.error(string)
-    sys.exit()
-
-  def showhardversion(self):
-    "Return just the version string"
-    Trace.message(GeneralConfig.version['number'])
-    sys.exit()
-
-  def showversiondate(self):
-    "Return just the version dte"
-    Trace.message(GeneralConfig.version['date'])
-    sys.exit()
-
-  def showlyxformat(self):
-    "Return just the lyxformat parameter"
-    Trace.message(GeneralConfig.version['lyxformat'])
-    sys.exit()
-
-class BranchOptions(object):
-  "A set of options for a branch"
-
-  def __init__(self, name):
-    self.name = name
-    self.options = {'color':'#ffffff'}
-
-  def set(self, key, value):
-    "Set a branch option"
-    if not key.startswith(ContainerConfig.string['startcommand']):
-      Trace.error('Invalid branch option ' + key)
-      return
-    key = key.replace(ContainerConfig.string['startcommand'], '')
-    self.options[key] = value
-
-  def isselected(self):
-    "Return if the branch is selected"
-    if not 'selected' in self.options:
-      return False
-    return self.options['selected'] == '1'
-
-  def __unicode__(self):
-    "String representation"
-    return 'options for ' + self.name + ': ' + unicode(self.options)
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class Cloner(object):
-  "An object used to clone other objects."
-
-  def clone(cls, original):
-    "Return an exact copy of an object."
-    "The original object must have an empty constructor."
-    return cls.create(original.__class__)
-
-  def create(cls, type):
-    "Create an object of a given class."
-    clone = type.__new__(type)
-    clone.__init__()
-    return clone
-
-  clone = classmethod(clone)
-  create = classmethod(create)
-
-class ContainerExtractor(object):
-  "A class to extract certain containers."
-
-  def __init__(self, config):
-    "The config parameter is a map containing three lists: allowed, copied and extracted."
-    "Each of the three is a list of class names for containers."
-    "Allowed containers are included as is into the result."
-    "Cloned containers are cloned and placed into the result."
-    "Extracted containers are looked into."
-    "All other containers are silently ignored."
-    self.allowed = config['allowed']
-    self.cloned = config['cloned']
-    self.extracted = config['extracted']
-
-  def extract(self, container):
-    "Extract a group of selected containers from elyxer.a container."
-    list = []
-    locate = lambda c: c.__class__.__name__ in self.allowed + self.cloned
-    recursive = lambda c: c.__class__.__name__ in self.extracted
-    process = lambda c: self.process(c, list)
-    container.recursivesearch(locate, recursive, process)
-    return list
-
-  def process(self, container, list):
-    "Add allowed containers, clone cloned containers and add the clone."
-    name = container.__class__.__name__
-    if name in self.allowed:
-      list.append(container)
-    elif name in self.cloned:
-      list.append(self.safeclone(container))
-    else:
-      Trace.error('Unknown container class ' + name)
-
-  def safeclone(self, container):
-    "Return a new container with contents only in a safe list, recursively."
-    clone = Cloner.clone(container)
-    clone.output = container.output
-    clone.contents = self.extract(container)
-    return clone
-
-
-
-
-
-
-class Parser(object):
-  "A generic parser"
-
-  def __init__(self):
-    self.begin = 0
-    self.parameters = dict()
-
-  def parseheader(self, reader):
-    "Parse the header"
-    header = reader.currentline().split()
-    reader.nextline()
-    self.begin = reader.linenumber
-    return header
-
-  def parseparameter(self, reader):
-    "Parse a parameter"
-    if reader.currentline().strip().startswith('<'):
-      key, value = self.parsexml(reader)
-      self.parameters[key] = value
-      return
-    split = reader.currentline().strip().split(' ', 1)
-    reader.nextline()
-    if len(split) == 0:
-      return
-    key = split[0]
-    if len(split) == 1:
-      self.parameters[key] = True
-      return
-    if not '"' in split[1]:
-      self.parameters[key] = split[1].strip()
-      return
-    doublesplit = split[1].split('"')
-    self.parameters[key] = doublesplit[1]
-
-  def parsexml(self, reader):
-    "Parse a parameter in xml form: <param attr1=value...>"
-    strip = reader.currentline().strip()
-    reader.nextline()
-    if not strip.endswith('>'):
-      Trace.error('XML parameter ' + strip + ' should be <...>')
-    split = strip[1:-1].split()
-    if len(split) == 0:
-      Trace.error('Empty XML parameter <>')
-      return None, None
-    key = split[0]
-    del split[0]
-    if len(split) == 0:
-      return key, dict()
-    attrs = dict()
-    for attr in split:
-      if not '=' in attr:
-        Trace.error('Erroneous attribute for ' + key + ': ' + attr)
-        attr += '="0"'
-      parts = attr.split('=')
-      attrkey = parts[0]
-      value = parts[1].split('"')[1]
-      attrs[attrkey] = value
-    return key, attrs
-
-  def parseending(self, reader, process):
-    "Parse until the current ending is found"
-    if not self.ending:
-      Trace.error('No ending for ' + unicode(self))
-      return
-    while not reader.currentline().startswith(self.ending):
-      process()
-
-  def parsecontainer(self, reader, contents):
-    container = self.factory.createcontainer(reader)
-    if container:
-      container.parent = self.parent
-      contents.append(container)
-
-  def __unicode__(self):
-    "Return a description"
-    return self.__class__.__name__ + ' (' + unicode(self.begin) + ')'
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class LoneCommand(Parser):
-  "A parser for just one command line"
-
-  def parse(self, reader):
-    "Read nothing"
-    return []
-
-class TextParser(Parser):
-  "A parser for a command and a bit of text"
-
-  stack = []
-
-  def __init__(self, container):
-    Parser.__init__(self)
-    self.ending = None
-    if container.__class__.__name__ in ContainerConfig.endings:
-      self.ending = ContainerConfig.endings[container.__class__.__name__]
-    self.endings = []
-
-  def parse(self, reader):
-    "Parse lines as long as they are text"
-    TextParser.stack.append(self.ending)
-    self.endings = TextParser.stack + [ContainerConfig.endings['Layout'],
-        ContainerConfig.endings['Inset'], self.ending]
-    contents = []
-    while not self.isending(reader):
-      self.parsecontainer(reader, contents)
-    return contents
-
-  def isending(self, reader):
-    "Check if text is ending"
-    current = reader.currentline().split()
-    if len(current) == 0:
-      return False
-    if current[0] in self.endings:
-      if current[0] in TextParser.stack:
-        TextParser.stack.remove(current[0])
-      else:
-        TextParser.stack = []
-      return True
-    return False
-
-class ExcludingParser(Parser):
-  "A parser that excludes the final line"
-
-  def parse(self, reader):
-    "Parse everything up to (and excluding) the final line"
-    contents = []
-    self.parseending(reader, lambda: self.parsecontainer(reader, contents))
-    return contents
-
-class BoundedParser(ExcludingParser):
-  "A parser bound by a final line"
-
-  def parse(self, reader):
-    "Parse everything, including the final line"
-    contents = ExcludingParser.parse(self, reader)
-    # skip last line
-    reader.nextline()
-    return contents
-
-class BoundedDummy(Parser):
-  "A bound parser that ignores everything"
-
-  def parse(self, reader):
-    "Parse the contents of the container"
-    self.parseending(reader, lambda: reader.nextline())
-    # skip last line
-    reader.nextline()
-    return []
-
-class StringParser(Parser):
-  "Parses just a string"
-
-  def parseheader(self, reader):
-    "Do nothing, just take note"
-    self.begin = reader.linenumber + 1
-    return []
-
-  def parse(self, reader):
-    "Parse a single line"
-    contents = reader.currentline()
-    reader.nextline()
-    return contents
-
-class InsetParser(BoundedParser):
-  "Parses a LyX inset"
-
-  def parse(self, reader):
-    "Parse inset parameters into a dictionary"
-    startcommand = ContainerConfig.string['startcommand']
-    while reader.currentline() != '' and not reader.currentline().startswith(startcommand):
-      self.parseparameter(reader)
-    return BoundedParser.parse(self, reader)
-
-
-
-
-
-
-class ContainerOutput(object):
-  "The generic HTML output for a container."
-
-  def gethtml(self, container):
-    "Show an error."
-    Trace.error('gethtml() not implemented for ' + unicode(self))
-
-  def isempty(self):
-    "Decide if the output is empty: by default, not empty."
-    return False
-
-class EmptyOutput(ContainerOutput):
-
-  def gethtml(self, container):
-    "Return empty HTML code."
-    return []
-
-  def isempty(self):
-    "This output is particularly empty."
-    return True
-
-class FixedOutput(ContainerOutput):
-  "Fixed output"
-
-  def gethtml(self, container):
-    "Return constant HTML code"
-    return container.html
-
-class ContentsOutput(ContainerOutput):
-  "Outputs the contents converted to HTML"
-
-  def gethtml(self, container):
-    "Return the HTML code"
-    html = []
-    if container.contents == None:
-      return html
-    for element in container.contents:
-      if not hasattr(element, 'gethtml'):
-        Trace.error('No html in ' + element.__class__.__name__ + ': ' + unicode(element))
-        return html
-      html += element.gethtml()
-    return html
-
-class TaggedOutput(ContentsOutput):
-  "Outputs an HTML tag surrounding the contents."
-
-  tag = None
-  breaklines = False
-  empty = False
-
-  def settag(self, tag, breaklines=False, empty=False):
-    "Set the value for the tag and other attributes."
-    self.tag = tag
-    if breaklines:
-      self.breaklines = breaklines
-    if empty:
-      self.empty = empty
-    return self
-
-  def setbreaklines(self, breaklines):
-    "Set the value for breaklines."
-    self.breaklines = breaklines
-    return self
-
-  def gethtml(self, container):
-    "Return the HTML code."
-    if self.empty:
-      return [self.selfclosing(container)]
-    html = [self.open(container)]
-    html += ContentsOutput.gethtml(self, container)
-    html.append(self.close(container))
-    return html
-
-  def open(self, container):
-    "Get opening line."
-    if not self.checktag(container):
-      return ''
-    open = '<' + self.tag + '>'
-    if self.breaklines:
-      return open + '\n'
-    return open
-
-  def close(self, container):
-    "Get closing line."
-    if not self.checktag(container):
-      return ''
-    close = '</' + self.tag.split()[0] + '>'
-    if self.breaklines:
-      return '\n' + close + '\n'
-    return close
-
-  def selfclosing(self, container):
-    "Get self-closing line."
-    if not self.checktag(container):
-      return ''
-    selfclosing = '<' + self.tag + '/>'
-    if self.breaklines:
-      return selfclosing + '\n'
-    return selfclosing
-
-  def checktag(self, container):
-    "Check that the tag is valid."
-    if not self.tag:
-      Trace.error('No tag in ' + unicode(container))
-      return False
-    if self.tag == '':
-      return False
-    return True
-
-class FilteredOutput(ContentsOutput):
-  "Returns the output in the contents, but filtered:"
-  "some strings are replaced by others."
-
-  def __init__(self):
-    "Initialize the filters."
-    self.filters = []
-
-  def addfilter(self, original, replacement):
-    "Add a new filter: replace the original by the replacement."
-    self.filters.append((original, replacement))
-
-  def gethtml(self, container):
-    "Return the HTML code"
-    result = []
-    html = ContentsOutput.gethtml(self, container)
-    for line in html:
-      result.append(self.filter(line))
-    return result
-
-  def filter(self, line):
-    "Filter a single line with all available filters."
-    for original, replacement in self.filters:
-      if original in line:
-        line = line.replace(original, replacement)
-    return line
-
-class StringOutput(ContainerOutput):
-  "Returns a bare string as output"
-
-  def gethtml(self, container):
-    "Return a bare string"
-    return [container.string]
-
-
-class LineReader(object):
-  "Reads a file line by line"
-
-  def __init__(self, filename):
-    if isinstance(filename, file):
-      self.file = filename
-    else:
-      self.file = codecs.open(filename, 'rU', 'utf-8')
-    self.linenumber = 1
-    self.lastline = None
-    self.current = None
-    self.mustread = True
-    self.depleted = False
-    try:
-      self.readline()
-    except UnicodeDecodeError:
-      # try compressed file
-      import gzip
-      self.file = gzip.open(filename, 'rb')
-      self.readline()
-
-  def setstart(self, firstline):
-    "Set the first line to read."
-    for i in range(firstline):
-      self.file.readline()
-    self.linenumber = firstline
-
-  def setend(self, lastline):
-    "Set the last line to read."
-    self.lastline = lastline
-
-  def currentline(self):
-    "Get the current line"
-    if self.mustread:
-      self.readline()
-    return self.current
-
-  def nextline(self):
-    "Go to next line"
-    if self.depleted:
-      Trace.fatal('Read beyond file end')
-    self.mustread = True
-
-  def readline(self):
-    "Read a line from elyxer.file"
-    self.current = self.file.readline()
-    if not isinstance(self.file, codecs.StreamReaderWriter):
-      self.current = self.current.decode('utf-8')
-    if len(self.current) == 0:
-      self.depleted = True
-    self.current = self.current.rstrip('\n\r')
-    self.linenumber += 1
-    self.mustread = False
-    Trace.prefix = 'Line ' + unicode(self.linenumber) + ': '
-    if self.linenumber % 1000 == 0:
-      Trace.message('Parsing')
-
-  def finished(self):
-    "Find out if the file is finished"
-    if self.lastline and self.linenumber == self.lastline:
-      return True
-    if self.mustread:
-      self.readline()
-    return self.depleted
-
-  def close(self):
-    self.file.close()
-
-class LineWriter(object):
-  "Writes a file as a series of lists"
-
-  file = False
-
-  def __init__(self, filename):
-    if isinstance(filename, file):
-      self.file = filename
-      self.filename = None
-    else:
-      self.filename = filename
-
-  def write(self, strings):
-    "Write a list of strings"
-    for string in strings:
-      if not isinstance(string, basestring):
-        Trace.error('Not a string: ' + unicode(string) + ' in ' + unicode(strings))
-        return
-      self.writestring(string)
-
-  def writestring(self, string):
-    "Write a string"
-    if not self.file:
-      self.file = codecs.open(self.filename, 'w', "utf-8")
-    if self.file == sys.stdout and sys.version_info < (3, 0):
-      string = string.encode('utf-8')
-    self.file.write(string)
-
-  def writeline(self, line):
-    "Write a line to file"
-    self.writestring(line + '\n')
-
-  def close(self):
-    self.file.close()
-
-
-
-
-
-
-class Globable(object):
-  """A bit of text which can be globbed (lumped together in bits).
-  Methods current(), skipcurrent(), checkfor() and isout() have to be
-  implemented by subclasses."""
-
-  leavepending = False
-
-  def __init__(self):
-    self.endinglist = EndingList()
-
-  def checkbytemark(self):
-    "Check for a Unicode byte mark and skip it."
-    if self.finished():
-      return
-    if ord(self.current()) == 0xfeff:
-      self.skipcurrent()
-
-  def isout(self):
-    "Find out if we are out of the position yet."
-    Trace.error('Unimplemented isout()')
-    return True
-
-  def current(self):
-    "Return the current character."
-    Trace.error('Unimplemented current()')
-    return ''
-
-  def checkfor(self, string):
-    "Check for the given string in the current position."
-    Trace.error('Unimplemented checkfor()')
-    return False
-
-  def finished(self):
-    "Find out if the current text has finished."
-    if self.isout():
-      if not self.leavepending:
-        self.endinglist.checkpending()
-      return True
-    return self.endinglist.checkin(self)
-
-  def skipcurrent(self):
-    "Return the current character and skip it."
-    Trace.error('Unimplemented skipcurrent()')
-    return ''
-
-  def glob(self, currentcheck):
-    "Glob a bit of text that satisfies a check on the current char."
-    glob = ''
-    while not self.finished() and currentcheck():
-      glob += self.skipcurrent()
-    return glob
-
-  def globalpha(self):
-    "Glob a bit of alpha text"
-    return self.glob(lambda: self.current().isalpha())
-
-  def globnumber(self):
-    "Glob a row of digits."
-    return self.glob(lambda: self.current().isdigit())
-
-  def isidentifier(self):
-    "Return if the current character is alphanumeric or _."
-    if self.current().isalnum() or self.current() == '_':
-      return True
-    return False
-
-  def globidentifier(self):
-    "Glob alphanumeric and _ symbols."
-    return self.glob(self.isidentifier)
-
-  def isvalue(self):
-    "Return if the current character is a value character:"
-    "not a bracket or a space."
-    if self.current().isspace():
-      return False
-    if self.current() in '{}()':
-      return False
-    return True
-
-  def globvalue(self):
-    "Glob a value: any symbols but brackets."
-    return self.glob(self.isvalue)
-
-  def skipspace(self):
-    "Skip all whitespace at current position."
-    return self.glob(lambda: self.current().isspace())
-
-  def globincluding(self, magicchar):
-    "Glob a bit of text up to (including) the magic char."
-    glob = self.glob(lambda: self.current() != magicchar) + magicchar
-    self.skip(magicchar)
-    return glob
-
-  def globexcluding(self, excluded):
-    "Glob a bit of text up until (excluding) any excluded character."
-    return self.glob(lambda: self.current() not in excluded)
-
-  def pushending(self, ending, optional = False):
-    "Push a new ending to the bottom"
-    self.endinglist.add(ending, optional)
-
-  def popending(self, expected = None):
-    "Pop the ending found at the current position"
-    if self.isout() and self.leavepending:
-      return expected
-    ending = self.endinglist.pop(self)
-    if expected and expected != ending:
-      Trace.error('Expected ending ' + expected + ', got ' + ending)
-    self.skip(ending)
-    return ending
-
-  def nextending(self):
-    "Return the next ending in the queue."
-    nextending = self.endinglist.findending(self)
-    if not nextending:
-      return None
-    return nextending.ending
-
-class EndingList(object):
-  "A list of position endings"
-
-  def __init__(self):
-    self.endings = []
-
-  def add(self, ending, optional = False):
-    "Add a new ending to the list"
-    self.endings.append(PositionEnding(ending, optional))
-
-  def pickpending(self, pos):
-    "Pick any pending endings from a parse position."
-    self.endings += pos.endinglist.endings
-
-  def checkin(self, pos):
-    "Search for an ending"
-    if self.findending(pos):
-      return True
-    return False
-
-  def pop(self, pos):
-    "Remove the ending at the current position"
-    if pos.isout():
-      Trace.error('No ending out of bounds')
-      return ''
-    ending = self.findending(pos)
-    if not ending:
-      Trace.error('No ending at ' + pos.current())
-      return ''
-    for each in reversed(self.endings):
-      self.endings.remove(each)
-      if each == ending:
-        return each.ending
-      elif not each.optional:
-        Trace.error('Removed non-optional ending ' + each)
-    Trace.error('No endings left')
-    return ''
-
-  def findending(self, pos):
-    "Find the ending at the current position"
-    if len(self.endings) == 0:
-      return None
-    for index, ending in enumerate(reversed(self.endings)):
-      if ending.checkin(pos):
-        return ending
-      if not ending.optional:
-        return None
-    return None
-
-  def checkpending(self):
-    "Check if there are any pending endings"
-    if len(self.endings) != 0:
-      Trace.error('Pending ' + unicode(self) + ' left open')
-
-  def __unicode__(self):
-    "Printable representation"
-    string = 'endings ['
-    for ending in self.endings:
-      string += unicode(ending) + ','
-    if len(self.endings) > 0:
-      string = string[:-1]
-    return string + ']'
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class PositionEnding(object):
-  "An ending for a parsing position"
-
-  def __init__(self, ending, optional):
-    self.ending = ending
-    self.optional = optional
-
-  def checkin(self, pos):
-    "Check for the ending"
-    return pos.checkfor(self.ending)
-
-  def __unicode__(self):
-    "Printable representation"
-    string = 'Ending ' + self.ending
-    if self.optional:
-      string += ' (optional)'
-    return string
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class Position(Globable):
-  """A position in a text to parse.
-  Including those in Globable, functions to implement by subclasses are:
-  skip(), identifier(), extract(), isout() and current()."""
-
-  def __init__(self):
-    Globable.__init__(self)
-
-  def skip(self, string):
-    "Skip a string"
-    Trace.error('Unimplemented skip()')
-
-  def identifier(self):
-    "Return an identifier for the current position."
-    Trace.error('Unimplemented identifier()')
-    return 'Error'
-
-  def extract(self, length):
-    "Extract the next string of the given length, or None if not enough text,"
-    "without advancing the parse position."
-    Trace.error('Unimplemented extract()')
-    return None
-
-  def checkfor(self, string):
-    "Check for a string at the given position."
-    return string == self.extract(len(string))
-
-  def checkforlower(self, string):
-    "Check for a string in lower case."
-    extracted = self.extract(len(string))
-    if not extracted:
-      return False
-    return string.lower() == self.extract(len(string)).lower()
-
-  def skipcurrent(self):
-    "Return the current character and skip it."
-    current = self.current()
-    self.skip(current)
-    return current
-
-  def __next__(self):
-    "Advance the position and return the next character."
-    self.skipcurrent()
-    return self.current()
-
-  if sys.version_info < (3, 0):
-      next = __next__
-
-  def checkskip(self, string):
-    "Check for a string at the given position; if there, skip it"
-    if not self.checkfor(string):
-      return False
-    self.skip(string)
-    return True
-
-  def error(self, message):
-    "Show an error message and the position identifier."
-    Trace.error(message + ': ' + self.identifier())
-
-class TextPosition(Position):
-  "A parse position based on a raw text."
-
-  def __init__(self, text):
-    "Create the position from elyxer.some text."
-    Position.__init__(self)
-    self.pos = 0
-    self.text = text
-    self.checkbytemark()
-
-  def skip(self, string):
-    "Skip a string of characters."
-    self.pos += len(string)
-
-  def identifier(self):
-    "Return a sample of the remaining text."
-    length = 30
-    if self.pos + length > len(self.text):
-      length = len(self.text) - self.pos
-    return '*' + self.text[self.pos:self.pos + length] + '*'
-
-  def isout(self):
-    "Find out if we are out of the text yet."
-    return self.pos >= len(self.text)
-
-  def current(self):
-    "Return the current character, assuming we are not out."
-    return self.text[self.pos]
-
-  def extract(self, length):
-    "Extract the next string of the given length, or None if not enough text."
-    if self.pos + length > len(self.text):
-      return None
-    return self.text[self.pos : self.pos + length]
-
-class FilePosition(Position):
-  "A parse position based on an underlying file."
-
-  def __init__(self, filename):
-    "Create the position from a file."
-    Position.__init__(self)
-    self.reader = LineReader(filename)
-    self.pos = 0
-    self.checkbytemark()
-
-  def skip(self, string):
-    "Skip a string of characters."
-    length = len(string)
-    while self.pos + length > len(self.reader.currentline()):
-      length -= len(self.reader.currentline()) - self.pos + 1
-      self.nextline()
-    self.pos += length
-
-  def currentline(self):
-    "Get the current line of the underlying file."
-    return self.reader.currentline()
-
-  def nextline(self):
-    "Go to the next line."
-    self.reader.nextline()
-    self.pos = 0
-
-  def linenumber(self):
-    "Return the line number of the file."
-    return self.reader.linenumber + 1
-
-  def identifier(self):
-    "Return the current line and line number in the file."
-    before = self.reader.currentline()[:self.pos - 1]
-    after = self.reader.currentline()[self.pos:]
-    return 'line ' + unicode(self.getlinenumber()) + ': ' + before + '*' + after
-
-  def isout(self):
-    "Find out if we are out of the text yet."
-    if self.pos > len(self.reader.currentline()):
-      if self.pos > len(self.reader.currentline()) + 1:
-        Trace.error('Out of the line ' + self.reader.currentline() + ': ' + unicode(self.pos))
-      self.nextline()
-    return self.reader.finished()
-
-  def current(self):
-    "Return the current character, assuming we are not out."
-    if self.pos == len(self.reader.currentline()):
-      return '\n'
-    if self.pos > len(self.reader.currentline()):
-      Trace.error('Out of the line ' + self.reader.currentline() + ': ' + unicode(self.pos))
-      return '*'
-    return self.reader.currentline()[self.pos]
-
-  def extract(self, length):
-    "Extract the next string of the given length, or None if not enough text."
-    if self.pos + length > len(self.reader.currentline()):
-      return None
-    return self.reader.currentline()[self.pos : self.pos + length]
-
-
-
-class Container(object):
-  "A container for text and objects in a lyx file"
-
-  partkey = None
-  parent = None
-  begin = None
-
-  def __init__(self):
-    self.contents = list()
-
-  def process(self):
-    "Process contents"
-    pass
-
-  def gethtml(self):
-    "Get the resulting HTML"
-    html = self.output.gethtml(self)
-    if isinstance(html, basestring):
-      Trace.error('Raw string ' + html)
-      html = [html]
-    return self.escapeall(html)
-
-  def escapeall(self, lines):
-    "Escape all lines in an array according to the output options."
-    result = []
-    for line in lines:
-      if Options.html:
-        line = self.escape(line, EscapeConfig.html)
-      if Options.iso885915:
-        line = self.escape(line, EscapeConfig.iso885915)
-        line = self.escapeentities(line)
-      elif not Options.unicode:
-        line = self.escape(line, EscapeConfig.nonunicode)
-      result.append(line)
-    return result
-
-  def escape(self, line, replacements = EscapeConfig.entities):
-    "Escape a line with replacements from elyxer.a map"
-    pieces = sorted(replacements.keys())
-    # do them in order
-    for piece in pieces:
-      if piece in line:
-        line = line.replace(piece, replacements[piece])
-    return line
-
-  def escapeentities(self, line):
-    "Escape all Unicode characters to HTML entities."
-    result = ''
-    pos = TextPosition(line)
-    while not pos.finished():
-      if ord(pos.current()) > 128:
-        codepoint = hex(ord(pos.current()))
-        if codepoint == '0xd835':
-          codepoint = hex(ord(next(pos)) + 0xf800)
-        result += '&#' + codepoint[1:] + ';'
-      else:
-        result += pos.current()
-      pos.skipcurrent()
-    return result
-
-  def searchall(self, type):
-    "Search for all embedded containers of a given type"
-    list = []
-    self.searchprocess(type, lambda container: list.append(container))
-    return list
-
-  def searchremove(self, type):
-    "Search for all containers of a type and remove them"
-    list = self.searchall(type)
-    for container in list:
-      container.parent.contents.remove(container)
-    return list
-
-  def searchprocess(self, type, process):
-    "Search for elements of a given type and process them"
-    self.locateprocess(lambda container: isinstance(container, type), process)
-
-  def locateprocess(self, locate, process):
-    "Search for all embedded containers and process them"
-    for container in self.contents:
-      container.locateprocess(locate, process)
-      if locate(container):
-        process(container)
-
-  def recursivesearch(self, locate, recursive, process):
-    "Perform a recursive search in the container."
-    for container in self.contents:
-      if recursive(container):
-        container.recursivesearch(locate, recursive, process)
-      if locate(container):
-        process(container)
-
-  def extracttext(self):
-    "Extract all text from elyxer.allowed containers."
-    result = ''
-    constants = ContainerExtractor(ContainerConfig.extracttext).extract(self)
-    for constant in constants:
-      result += constant.string
-    return result
-
-  def group(self, index, group, isingroup):
-    "Group some adjoining elements into a group"
-    if index >= len(self.contents):
-      return
-    if hasattr(self.contents[index], 'grouped'):
-      return
-    while index < len(self.contents) and isingroup(self.contents[index]):
-      self.contents[index].grouped = True
-      group.contents.append(self.contents[index])
-      self.contents.pop(index)
-    self.contents.insert(index, group)
-
-  def remove(self, index):
-    "Remove a container but leave its contents"
-    container = self.contents[index]
-    self.contents.pop(index)
-    while len(container.contents) > 0:
-      self.contents.insert(index, container.contents.pop())
-
-  def tree(self, level = 0):
-    "Show in a tree"
-    Trace.debug("  " * level + unicode(self))
-    for container in self.contents:
-      container.tree(level + 1)
-
-  def getparameter(self, name):
-    "Get the value of a parameter, if present."
-    if not name in self.parameters:
-      return None
-    return self.parameters[name]
-
-  def getparameterlist(self, name):
-    "Get the value of a comma-separated parameter as a list."
-    paramtext = self.getparameter(name)
-    if not paramtext:
-      return []
-    return paramtext.split(',')
-
-  def hasemptyoutput(self):
-    "Check if the parent's output is empty."
-    current = self.parent
-    while current:
-      if current.output.isempty():
-        return True
-      current = current.parent
-    return False
-
-  def __unicode__(self):
-    "Get a description"
-    if not self.begin:
-      return self.__class__.__name__
-    return self.__class__.__name__ + '@' + unicode(self.begin)
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class BlackBox(Container):
-  "A container that does not output anything"
-
-  def __init__(self):
-    self.parser = LoneCommand()
-    self.output = EmptyOutput()
-    self.contents = []
-
-class LyXFormat(BlackBox):
-  "Read the lyxformat command"
-
-  def process(self):
-    "Show warning if version < 276"
-    version = int(self.header[1])
-    if version < 276:
-      Trace.error('Warning: unsupported old format version ' + str(version))
-    if version > int(GeneralConfig.version['lyxformat']):
-      Trace.error('Warning: unsupported new format version ' + str(version))
-
-class StringContainer(Container):
-  "A container for a single string"
-
-  parsed = None
-
-  def __init__(self):
-    self.parser = StringParser()
-    self.output = StringOutput()
-    self.string = ''
-
-  def process(self):
-    "Replace special chars from elyxer.the contents."
-    if self.parsed:
-      self.string = self.replacespecial(self.parsed)
-      self.parsed = None
-
-  def replacespecial(self, line):
-    "Replace all special chars from elyxer.a line"
-    replaced = self.escape(line, EscapeConfig.entities)
-    replaced = self.changeline(replaced)
-    if ContainerConfig.string['startcommand'] in replaced and len(replaced) > 1:
-      # unprocessed commands
-      if self.begin:
-        message = 'Unknown command at ' + unicode(self.begin) + ': '
-      else:
-        message = 'Unknown command: '
-      Trace.error(message + replaced.strip())
-    return replaced
-
-  def changeline(self, line):
-    line = self.escape(line, EscapeConfig.chars)
-    if not ContainerConfig.string['startcommand'] in line:
-      return line
-    line = self.escape(line, EscapeConfig.commands)
-    return line
-
-  def extracttext(self):
-    "Return all text."
-    return self.string
-
-  def __unicode__(self):
-    "Return a printable representation."
-    result = 'StringContainer'
-    if self.begin:
-      result += '@' + unicode(self.begin)
-    ellipsis = '...'
-    if len(self.string.strip()) <= 15:
-      ellipsis = ''
-    return result + ' (' + self.string.strip()[:15] + ellipsis + ')'
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class Constant(StringContainer):
-  "A constant string"
-
-  def __init__(self, text):
-    self.contents = []
-    self.string = text
-    self.output = StringOutput()
-
-  def __unicode__(self):
-    return 'Constant: ' + self.string
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class TaggedText(Container):
-  "Text inside a tag"
-
-  output = None
-
-  def __init__(self):
-    self.parser = TextParser(self)
-    self.output = TaggedOutput()
-
-  def complete(self, contents, tag, breaklines=False):
-    "Complete the tagged text and return it"
-    self.contents = contents
-    self.output.tag = tag
-    self.output.breaklines = breaklines
-    return self
-
-  def constant(self, text, tag, breaklines=False):
-    "Complete the tagged text with a constant"
-    constant = Constant(text)
-    return self.complete([constant], tag, breaklines)
-
-  def __unicode__(self):
-    "Return a printable representation."
-    if not hasattr(self.output, 'tag'):
-      return 'Emtpy tagged text'
-    if not self.output.tag:
-      return 'Tagged <unknown tag>'
-    return 'Tagged <' + self.output.tag + '>'
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class DocumentParameters(object):
-  "Global parameters for the document."
-
-  pdftitle = None
-  indentstandard = False
-  tocdepth = 10
-  startinglevel = 0
-  maxdepth = 10
-  language = None
-  bibliography = None
-  outputchanges = False
-  displaymode = False
-
-
-
-
-
-
-class FormulaParser(Parser):
-  "Parses a formula"
-
-  def parseheader(self, reader):
-    "See if the formula is inlined"
-    self.begin = reader.linenumber + 1
-    type = self.parsetype(reader)
-    if not type:
-      reader.nextline()
-      type = self.parsetype(reader)
-      if not type:
-        Trace.error('Unknown formula type in ' + reader.currentline().strip())
-        return ['unknown']
-    return [type]
-
-  def parsetype(self, reader):
-    "Get the formula type from the first line."
-    if reader.currentline().find(FormulaConfig.starts['simple']) >= 0:
-      return 'inline'
-    if reader.currentline().find(FormulaConfig.starts['complex']) >= 0:
-      return 'block'
-    if reader.currentline().find(FormulaConfig.starts['unnumbered']) >= 0:
-      return 'block'
-    if reader.currentline().find(FormulaConfig.starts['beginbefore']) >= 0:
-      return 'numbered'
-    return None
-
-  def parse(self, reader):
-    "Parse the formula until the end"
-    formula = self.parseformula(reader)
-    while not reader.currentline().startswith(self.ending):
-      stripped = reader.currentline().strip()
-      if len(stripped) > 0:
-        Trace.error('Unparsed formula line ' + stripped)
-      reader.nextline()
-    reader.nextline()
-    return formula
-
-  def parseformula(self, reader):
-    "Parse the formula contents"
-    simple = FormulaConfig.starts['simple']
-    if simple in reader.currentline():
-      rest = reader.currentline().split(simple, 1)[1]
-      if simple in rest:
-        # formula is $...$
-        return self.parsesingleliner(reader, simple, simple)
-      # formula is multiline $...$
-      return self.parsemultiliner(reader, simple, simple)
-    if FormulaConfig.starts['complex'] in reader.currentline():
-      # formula of the form \[...\]
-      return self.parsemultiliner(reader, FormulaConfig.starts['complex'],
-          FormulaConfig.endings['complex'])
-    beginbefore = FormulaConfig.starts['beginbefore']
-    beginafter = FormulaConfig.starts['beginafter']
-    if beginbefore in reader.currentline():
-      if reader.currentline().strip().endswith(beginafter):
-        current = reader.currentline().strip()
-        endsplit = current.split(beginbefore)[1].split(beginafter)
-        startpiece = beginbefore + endsplit[0] + beginafter
-        endbefore = FormulaConfig.endings['endbefore']
-        endafter = FormulaConfig.endings['endafter']
-        endpiece = endbefore + endsplit[0] + endafter
-        return startpiece + self.parsemultiliner(reader, startpiece, endpiece) + endpiece
-      Trace.error('Missing ' + beginafter + ' in ' + reader.currentline())
-      return ''
-    begincommand = FormulaConfig.starts['command']
-    beginbracket = FormulaConfig.starts['bracket']
-    if begincommand in reader.currentline() and beginbracket in reader.currentline():
-      endbracket = FormulaConfig.endings['bracket']
-      return self.parsemultiliner(reader, beginbracket, endbracket)
-    Trace.error('Formula beginning ' + reader.currentline() + ' is unknown')
-    return ''
-
-  def parsesingleliner(self, reader, start, ending):
-    "Parse a formula in one line"
-    line = reader.currentline().strip()
-    if not start in line:
-      Trace.error('Line ' + line + ' does not contain formula start ' + start)
-      return ''
-    if not line.endswith(ending):
-      Trace.error('Formula ' + line + ' does not end with ' + ending)
-      return ''
-    index = line.index(start)
-    rest = line[index + len(start):-len(ending)]
-    reader.nextline()
-    return rest
-
-  def parsemultiliner(self, reader, start, ending):
-    "Parse a formula in multiple lines"
-    formula = ''
-    line = reader.currentline()
-    if not start in line:
-      Trace.error('Line ' + line.strip() + ' does not contain formula start ' + start)
-      return ''
-    index = line.index(start)
-    line = line[index + len(start):].strip()
-    while not line.endswith(ending):
-      formula += line + '\n'
-      reader.nextline()
-      line = reader.currentline()
-    formula += line[:-len(ending)]
-    reader.nextline()
-    return formula
-
-class MacroParser(FormulaParser):
-  "A parser for a formula macro."
-
-  def parseheader(self, reader):
-    "See if the formula is inlined"
-    self.begin = reader.linenumber + 1
-    return ['inline']
-
-  def parse(self, reader):
-    "Parse the formula until the end"
-    formula = self.parsemultiliner(reader, self.parent.start, self.ending)
-    reader.nextline()
-    return formula
-
-
-class FormulaBit(Container):
-  "A bit of a formula"
-
-  type = None
-  size = 1
-  original = ''
-
-  def __init__(self):
-    "The formula bit type can be 'alpha', 'number', 'font'."
-    self.contents = []
-    self.output = ContentsOutput()
-
-  def setfactory(self, factory):
-    "Set the internal formula factory."
-    self.factory = factory
-    return self
-
-  def add(self, bit):
-    "Add any kind of formula bit already processed"
-    self.contents.append(bit)
-    self.original += bit.original
-    bit.parent = self
-
-  def skiporiginal(self, string, pos):
-    "Skip a string and add it to the original formula"
-    self.original += string
-    if not pos.checkskip(string):
-      Trace.error('String ' + string + ' not at ' + pos.identifier())
-
-  def computesize(self):
-    "Compute the size of the bit as the max of the sizes of all contents."
-    if len(self.contents) == 0:
-      return 1
-    self.size = max([element.size for element in self.contents])
-    return self.size
-
-  def clone(self):
-    "Return a copy of itself."
-    return self.factory.parseformula(self.original)
-
-  def __unicode__(self):
-    "Get a string representation"
-    return self.__class__.__name__ + ' read in ' + self.original
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class TaggedBit(FormulaBit):
-  "A tagged string in a formula"
-
-  def constant(self, constant, tag):
-    "Set the constant and the tag"
-    self.output = TaggedOutput().settag(tag)
-    self.add(FormulaConstant(constant))
-    return self
-
-  def complete(self, contents, tag, breaklines = False):
-    "Set the constant and the tag"
-    self.contents = contents
-    self.output = TaggedOutput().settag(tag, breaklines)
-    return self
-
-  def selfcomplete(self, tag):
-    "Set the self-closing tag, no contents (as in <hr/>)."
-    self.output = TaggedOutput().settag(tag, empty = True)
-    return self
-
-class FormulaConstant(Constant):
-  "A constant string in a formula"
-
-  def __init__(self, string):
-    "Set the constant string"
-    Constant.__init__(self, string)
-    self.original = string
-    self.size = 1
-    self.type = None
-
-  def computesize(self):
-    "Compute the size of the constant: always 1."
-    return self.size
-
-  def clone(self):
-    "Return a copy of itself."
-    return FormulaConstant(self.original)
-
-  def __unicode__(self):
-    "Return a printable representation."
-    return 'Formula constant: ' + self.string
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class RawText(FormulaBit):
-  "A bit of text inside a formula"
-
-  def detect(self, pos):
-    "Detect a bit of raw text"
-    return pos.current().isalpha()
-
-  def parsebit(self, pos):
-    "Parse alphabetic text"
-    alpha = pos.globalpha()
-    self.add(FormulaConstant(alpha))
-    self.type = 'alpha'
-
-class FormulaSymbol(FormulaBit):
-  "A symbol inside a formula"
-
-  modified = FormulaConfig.modified
-  unmodified = FormulaConfig.unmodified['characters']
-
-  def detect(self, pos):
-    "Detect a symbol"
-    if pos.current() in FormulaSymbol.unmodified:
-      return True
-    if pos.current() in FormulaSymbol.modified:
-      return True
-    return False
-
-  def parsebit(self, pos):
-    "Parse the symbol"
-    if pos.current() in FormulaSymbol.unmodified:
-      self.addsymbol(pos.current(), pos)
-      return
-    if pos.current() in FormulaSymbol.modified:
-      self.addsymbol(FormulaSymbol.modified[pos.current()], pos)
-      return
-    Trace.error('Symbol ' + pos.current() + ' not found')
-
-  def addsymbol(self, symbol, pos):
-    "Add a symbol"
-    self.skiporiginal(pos.current(), pos)
-    self.contents.append(FormulaConstant(symbol))
-
-class FormulaNumber(FormulaBit):
-  "A string of digits in a formula"
-
-  def detect(self, pos):
-    "Detect a digit"
-    return pos.current().isdigit()
-
-  def parsebit(self, pos):
-    "Parse a bunch of digits"
-    digits = pos.glob(lambda: pos.current().isdigit())
-    self.add(FormulaConstant(digits))
-    self.type = 'number'
-
-class Comment(FormulaBit):
-  "A LaTeX comment: % to the end of the line."
-
-  start = FormulaConfig.starts['comment']
-
-  def detect(self, pos):
-    "Detect the %."
-    return pos.current() == self.start
-
-  def parsebit(self, pos):
-    "Parse to the end of the line."
-    self.original += pos.globincluding('\n')
-
-class WhiteSpace(FormulaBit):
-  "Some white space inside a formula."
-
-  def detect(self, pos):
-    "Detect the white space."
-    return pos.current().isspace()
-
-  def parsebit(self, pos):
-    "Parse all whitespace."
-    self.original += pos.skipspace()
-
-  def __unicode__(self):
-    "Return a printable representation."
-    return 'Whitespace: *' + self.original + '*'
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class Bracket(FormulaBit):
-  "A {} bracket inside a formula"
-
-  start = FormulaConfig.starts['bracket']
-  ending = FormulaConfig.endings['bracket']
-
-  def __init__(self):
-    "Create a (possibly literal) new bracket"
-    FormulaBit.__init__(self)
-    self.inner = None
-
-  def detect(self, pos):
-    "Detect the start of a bracket"
-    return pos.checkfor(self.start)
-
-  def parsebit(self, pos):
-    "Parse the bracket"
-    self.parsecomplete(pos, self.innerformula)
-    return self
-
-  def parsetext(self, pos):
-    "Parse a text bracket"
-    self.parsecomplete(pos, self.innertext)
-    return self
-
-  def parseliteral(self, pos):
-    "Parse a literal bracket"
-    self.parsecomplete(pos, self.innerliteral)
-    return self
-
-  def parsecomplete(self, pos, innerparser):
-    "Parse the start and end marks"
-    if not pos.checkfor(self.start):
-      Trace.error('Bracket should start with ' + self.start + ' at ' + pos.identifier())
-      return None
-    self.skiporiginal(self.start, pos)
-    pos.pushending(self.ending)
-    innerparser(pos)
-    self.original += pos.popending(self.ending)
-    self.computesize()
-
-  def innerformula(self, pos):
-    "Parse a whole formula inside the bracket"
-    while not pos.finished():
-      self.add(self.factory.parseany(pos))
-
-  def innertext(self, pos):
-    "Parse some text inside the bracket, following textual rules."
-    specialchars = list(FormulaConfig.symbolfunctions.keys())
-    specialchars.append(FormulaConfig.starts['command'])
-    specialchars.append(FormulaConfig.starts['bracket'])
-    specialchars.append(Comment.start)
-    while not pos.finished():
-      if pos.current() in specialchars:
-        self.add(self.factory.parseany(pos))
-        if pos.checkskip(' '):
-          self.original += ' '
-      else:
-        self.add(FormulaConstant(pos.skipcurrent()))
-
-  def innerliteral(self, pos):
-    "Parse a literal inside the bracket, which does not generate HTML."
-    self.literal = ''
-    while not pos.finished() and not pos.current() == self.ending:
-      if pos.current() == self.start:
-        self.parseliteral(pos)
-      else:
-        self.literal += pos.skipcurrent()
-    self.original += self.literal
-
-class SquareBracket(Bracket):
-  "A [] bracket inside a formula"
-
-  start = FormulaConfig.starts['squarebracket']
-  ending = FormulaConfig.endings['squarebracket']
-
-  def clone(self):
-    "Return a new square bracket with the same contents."
-    bracket = SquareBracket()
-    bracket.contents = self.contents
-    return bracket
-
-
-class MathsProcessor(object):
-  "A processor for a maths construction inside the FormulaProcessor."
-
-  def process(self, contents, index):
-    "Process an element inside a formula."
-    Trace.error('Unimplemented process() in ' + unicode(self))
-
-  def __unicode__(self):
-    "Return a printable description."
-    return 'Maths processor ' + self.__class__.__name__
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class FormulaProcessor(object):
-  "A processor specifically for formulas."
-
-  processors = []
-
-  def process(self, bit):
-    "Process the contents of every formula bit, recursively."
-    self.processcontents(bit)
-    self.processinsides(bit)
-    self.traversewhole(bit)
-
-  def processcontents(self, bit):
-    "Process the contents of a formula bit."
-    if not isinstance(bit, FormulaBit):
-      return
-    bit.process()
-    for element in bit.contents:
-      self.processcontents(element)
-
-  def processinsides(self, bit):
-    "Process the insides (limits, brackets) in a formula bit."
-    if not isinstance(bit, FormulaBit):
-      return
-    for index, element in enumerate(bit.contents):
-      for processor in self.processors:
-        processor.process(bit.contents, index)
-      # continue with recursive processing
-      self.processinsides(element)
-
-  def traversewhole(self, formula):
-    "Traverse over the contents to alter variables and space units."
-    last = None
-    for bit, contents in self.traverse(formula):
-      if bit.type == 'alpha':
-        self.italicize(bit, contents)
-      elif bit.type == 'font' and last and last.type == 'number':
-        bit.contents.insert(0, FormulaConstant(u' '))
-      last = bit
-
-  def traverse(self, bit):
-    "Traverse a formula and yield a flattened structure of (bit, list) pairs."
-    for element in bit.contents:
-      if hasattr(element, 'type') and element.type:
-        yield (element, bit.contents)
-      elif isinstance(element, FormulaBit):
-        for pair in self.traverse(element):
-          yield pair
-
-  def italicize(self, bit, contents):
-    "Italicize the given bit of text."
-    index = contents.index(bit)
-    contents[index] = TaggedBit().complete([bit], 'i')
-
-
-
-
-class Formula(Container):
-  "A LaTeX formula"
-
-  def __init__(self):
-    self.parser = FormulaParser()
-    self.output = TaggedOutput().settag('span class="formula"')
-
-  def process(self):
-    "Convert the formula to tags"
-    if self.header[0] == 'inline':
-      DocumentParameters.displaymode = False
-    else:
-      DocumentParameters.displaymode = True
-      self.output.settag('div class="formula"', True)
-    if Options.jsmath:
-      self.jsmath()
-    elif Options.mathjax:
-      self.mathjax()
-    elif Options.googlecharts:
-      self.googlecharts()
-    else:
-      self.classic()
-
-  def jsmath(self):
-    "Make the contents for jsMath."
-    if self.header[0] != 'inline':
-      self.output = TaggedOutput().settag('div class="math"')
-    else:
-      self.output = TaggedOutput().settag('span class="math"')
-    self.contents = [Constant(self.parsed)]
-
-  def mathjax(self):
-    "Make the contents for MathJax."
-    self.output.tag = 'span class="MathJax_Preview"'
-    tag = 'script type="math/tex'
-    if self.header[0] != 'inline':
-      tag += ';mode=display'
-    self.contents = [TaggedText().constant(self.parsed, tag + '"', True)]
-
-  def googlecharts(self):
-    "Make the contents using Google Charts http://code.google.com/apis/chart/."
-    url = FormulaConfig.urls['googlecharts'] + quote_plus(self.parsed)
-    img = '<img class="chart" src="' + url + '" alt="' + self.parsed + '"/>'
-    self.contents = [Constant(img)]
-
-  def classic(self):
-    "Make the contents using classic output generation with XHTML and CSS."
-    whole = FormulaFactory().parseformula(self.parsed)
-    FormulaProcessor().process(whole)
-    whole.parent = self
-    self.contents = [whole]
-
-  def parse(self, pos):
-    "Parse using a parse position instead of self.parser."
-    if pos.checkskip('$$'):
-      self.parsedollarblock(pos)
-    elif pos.checkskip('$'):
-      self.parsedollarinline(pos)
-    elif pos.checkskip('\\('):
-      self.parseinlineto(pos, '\\)')
-    elif pos.checkskip('\\['):
-      self.parseblockto(pos, '\\]')
-    else:
-      pos.error('Unparseable formula')
-    self.process()
-    return self
-
-  def parsedollarinline(self, pos):
-    "Parse a $...$ formula."
-    self.header = ['inline']
-    self.parsedollar(pos)
-
-  def parsedollarblock(self, pos):
-    "Parse a $$...$$ formula."
-    self.header = ['block']
-    self.parsedollar(pos)
-    if not pos.checkskip('$'):
-      pos.error('Formula should be $$...$$, but last $ is missing.')
-
-  def parsedollar(self, pos):
-    "Parse to the next $."
-    pos.pushending('$')
-    self.parsed = pos.globexcluding('$')
-    pos.popending('$')
-
-  def parseinlineto(self, pos, limit):
-    "Parse a \\(...\\) formula."
-    self.header = ['inline']
-    self.parseupto(pos, limit)
-
-  def parseblockto(self, pos, limit):
-    "Parse a \\[...\\] formula."
-    self.header = ['block']
-    self.parseupto(pos, limit)
-
-  def parseupto(self, pos, limit):
-    "Parse a formula that ends with the given command."
-    pos.pushending(limit)
-    self.parsed = pos.glob(lambda: True)
-    pos.popending(limit)
-
-  def __unicode__(self):
-    "Return a printable representation."
-    if self.partkey and self.partkey.number:
-      return 'Formula (' + self.partkey.number + ')'
-    return 'Unnumbered formula'
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class WholeFormula(FormulaBit):
-  "Parse a whole formula"
-
-  def detect(self, pos):
-    "Not outside the formula is enough."
-    return not pos.finished()
-
-  def parsebit(self, pos):
-    "Parse with any formula bit"
-    while not pos.finished():
-      self.add(self.factory.parseany(pos))
-
-class FormulaFactory(object):
-  "Construct bits of formula"
-
-  # bit types will be appended later
-  types = [FormulaSymbol, RawText, FormulaNumber, Bracket, Comment, WhiteSpace]
-  skippedtypes = [Comment, WhiteSpace]
-  defining = False
-
-  def __init__(self):
-    "Initialize the map of instances."
-    self.instances = dict()
-
-  def detecttype(self, type, pos):
-    "Detect a bit of a given type."
-    if pos.finished():
-      return False
-    return self.instance(type).detect(pos)
-
-  def instance(self, type):
-    "Get an instance of the given type."
-    if not type in self.instances or not self.instances[type]:
-      self.instances[type] = self.create(type)
-    return self.instances[type]
-
-  def create(self, type):
-    "Create a new formula bit of the given type."
-    return Cloner.create(type).setfactory(self)
-
-  def clearskipped(self, pos):
-    "Clear any skipped types."
-    while not pos.finished():
-      if not self.skipany(pos):
-        return
-    return
-
-  def skipany(self, pos):
-    "Skip any skipped types."
-    for type in self.skippedtypes:
-      if self.instance(type).detect(pos):
-        return self.parsetype(type, pos)
-    return None
-
-  def parseany(self, pos):
-    "Parse any formula bit at the current location."
-    for type in self.types + self.skippedtypes:
-      if self.detecttype(type, pos):
-        return self.parsetype(type, pos)
-    Trace.error('Unrecognized formula at ' + pos.identifier())
-    return FormulaConstant(pos.skipcurrent())
-
-  def parsetype(self, type, pos):
-    "Parse the given type and return it."
-    bit = self.instance(type)
-    self.instances[type] = None
-    returnedbit = bit.parsebit(pos)
-    if returnedbit:
-      return returnedbit.setfactory(self)
-    return bit
-
-  def parseformula(self, formula):
-    "Parse a string of text that contains a whole formula."
-    pos = TextPosition(formula)
-    whole = self.create(WholeFormula)
-    if whole.detect(pos):
-      whole.parsebit(pos)
-      return whole
-    # no formula found
-    if not pos.finished():
-      Trace.error('Unknown formula at: ' + pos.identifier())
-      whole.add(TaggedBit().constant(formula, 'span class="unknown"'))
-    return whole
-
-
-class Translator(object):
-  "Reads the configuration file and tries to find a translation."
-  "Otherwise falls back to the messages in the config file."
-
-  instance = None
-
-  def translate(cls, key):
-    "Get the translated message for a key."
-    return cls.instance.getmessage(key)
-
-  translate = classmethod(translate)
-
-  def __init__(self):
-    self.translation = None
-    self.first = True
-
-  def findtranslation(self):
-    "Find the translation for the document language."
-    self.langcodes = None
-    if not DocumentParameters.language:
-      Trace.error('No language in document')
-      return
-    if not DocumentParameters.language in TranslationConfig.languages:
-      Trace.error('Unknown language ' + DocumentParameters.language)
-      return
-    if TranslationConfig.languages[DocumentParameters.language] == 'en':
-      return
-    langcodes = [TranslationConfig.languages[DocumentParameters.language]]
-    try:
-      self.translation = gettext.translation('elyxer', None, langcodes)
-    except IOError:
-      Trace.error('No translation for ' + unicode(langcodes))
-
-  def getmessage(self, key):
-    "Get the translated message for the given key."
-    if self.first:
-      self.findtranslation()
-      self.first = False
-    message = self.getuntranslated(key)
-    if not self.translation:
-      return message
-    try:
-      message = self.translation.ugettext(message)
-    except IOError:
-      pass
-    return message
-
-  def getuntranslated(self, key):
-    "Get the untranslated message."
-    if not key in TranslationConfig.constants:
-      Trace.error('Cannot translate ' + key)
-      return key
-    return TranslationConfig.constants[key]
-
-Translator.instance = Translator()
-
-
-
-class NumberCounter(object):
-  "A counter for numbers (by default)."
-  "The type can be changed to return letters, roman numbers..."
-
-  name = None
-  value = None
-  mode = None
-  master = None
-
-  letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-  symbols = NumberingConfig.sequence['symbols']
-  romannumerals = [
-      ('M', 1000), ('CM', 900), ('D', 500), ('CD', 400), ('C', 100),
-      ('XC', 90), ('L', 50), ('XL', 40), ('X', 10), ('IX', 9), ('V', 5),
-      ('IV', 4), ('I', 1)
-      ]
-
-  def __init__(self, name):
-    "Give a name to the counter."
-    self.name = name
-
-  def setmode(self, mode):
-    "Set the counter mode. Can be changed at runtime."
-    self.mode = mode
-    return self
-
-  def init(self, value):
-    "Set an initial value."
-    self.value = value
-
-  def gettext(self):
-    "Get the next value as a text string."
-    return unicode(self.value)
-
-  def getletter(self):
-    "Get the next value as a letter."
-    return self.getsequence(self.letters)
-
-  def getsymbol(self):
-    "Get the next value as a symbol."
-    return self.getsequence(self.symbols)
-
-  def getsequence(self, sequence):
-    "Get the next value from elyxer.a sequence."
-    return sequence[(self.value - 1) % len(sequence)]
-
-  def getroman(self):
-    "Get the next value as a roman number."
-    result = ''
-    number = self.value
-    for numeral, value in self.romannumerals:
-      if number >= value:
-        result += numeral * (number / value)
-        number = number % value
-    return result
-
-  def getvalue(self):
-    "Get the current value as configured in the current mode."
-    if not self.mode or self.mode in ['text', '1']:
-      return self.gettext()
-    if self.mode == 'A':
-      return self.getletter()
-    if self.mode == 'a':
-      return self.getletter().lower()
-    if self.mode == 'I':
-      return self.getroman()
-    if self.mode == '*':
-      return self.getsymbol()
-    Trace.error('Unknown counter mode ' + self.mode)
-    return self.gettext()
-
-  def getnext(self):
-    "Increase the current value and get the next value as configured."
-    if not self.value:
-      self.value = 0
-    self.value += 1
-    return self.getvalue()
-
-  def reset(self):
-    "Reset the counter."
-    self.value = 0
-
-  def __unicode__(self):
-    "Return a printable representation."
-    result = 'Counter ' + self.name
-    if self.mode:
-      result += ' in mode ' + self.mode
-    return result
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class DependentCounter(NumberCounter):
-  "A counter which depends on another one (the master)."
-
-  def setmaster(self, master):
-    "Set the master counter."
-    self.master = master
-    self.last = self.master.getvalue()
-    return self
-
-  def getnext(self):
-    "Increase or, if the master counter has changed, restart."
-    if self.last != self.master.getvalue():
-      self.reset()
-    value = NumberCounter.getnext(self)
-    self.last = self.master.getvalue()
-    return value
-
-  def getvalue(self):
-    "Get the value of the combined counter: master.dependent."
-    return self.master.getvalue() + '.' + NumberCounter.getvalue(self)
-
-class NumberGenerator(object):
-  "A number generator for unique sequences and hierarchical structures. Used in:"
-  "  * ordered part numbers: Chapter 3, Section 5.3."
-  "  * unique part numbers: Footnote 15, Bibliography cite [15]."
-  "  * chaptered part numbers: Figure 3.15, Equation (8.3)."
-  "  * unique roman part numbers: Part I, Book IV."
-
-  chaptered = None
-  generator = None
-
-  romanlayouts = [x.lower() for x in NumberingConfig.layouts['roman']]
-  orderedlayouts = [x.lower() for x in NumberingConfig.layouts['ordered']]
-
-  counters = dict()
-  appendix = None
-
-  def deasterisk(self, type):
-    "Remove the possible asterisk in a layout type."
-    return type.replace('*', '')
-
-  def isunique(self, type):
-    "Find out if the layout type corresponds to a unique part."
-    return self.isroman(type)
-
-  def isroman(self, type):
-    "Find out if the layout type should have roman numeration."
-    return self.deasterisk(type).lower() in self.romanlayouts
-
-  def isinordered(self, type):
-    "Find out if the layout type corresponds to an (un)ordered part."
-    return self.deasterisk(type).lower() in self.orderedlayouts
-
-  def isnumbered(self, type):
-    "Find out if the type for a layout corresponds to a numbered layout."
-    if '*' in type:
-      return False
-    if self.isroman(type):
-      return True
-    if not self.isinordered(type):
-      return False
-    if self.getlevel(type) > DocumentParameters.maxdepth:
-      return False
-    return True
-
-  def isunordered(self, type):
-    "Find out if the type contains an asterisk, basically."
-    return '*' in type
-
-  def getlevel(self, type):
-    "Get the level that corresponds to a layout type."
-    if self.isunique(type):
-      return 0
-    if not self.isinordered(type):
-      Trace.error('Unknown layout type ' + type)
-      return 0
-    type = self.deasterisk(type).lower()
-    level = self.orderedlayouts.index(type) + 1
-    return level - DocumentParameters.startinglevel
-
-  def getparttype(self, type):
-    "Obtain the type for the part: without the asterisk, "
-    "and switched to Appendix if necessary."
-    if NumberGenerator.appendix and self.getlevel(type) == 1:
-      return 'Appendix'
-    return self.deasterisk(type)
-
-  def generate(self, type):
-    "Generate a number for a layout type."
-    "Unique part types such as Part or Book generate roman numbers: Part I."
-    "Ordered part types return dot-separated tuples: Chapter 5, Subsection 2.3.5."
-    "Everything else generates unique numbers: Bibliography [1]."
-    "Each invocation results in a new number."
-    return self.getcounter(type).getnext()
-
-  def getcounter(self, type):
-    "Get the counter for the given type."
-    type = type.lower()
-    if not type in self.counters:
-      self.counters[type] = self.create(type)
-    return self.counters[type]
-
-  def create(self, type):
-    "Create a counter for the given type."
-    if self.isnumbered(type) and self.getlevel(type) > 1:
-      index = self.orderedlayouts.index(type)
-      above = self.orderedlayouts[index - 1]
-      master = self.getcounter(above)
-      return self.createdependent(type, master)
-    counter = NumberCounter(type)
-    if self.isroman(type):
-      counter.setmode('I')
-    return counter
-
-  def getdependentcounter(self, type, master):
-    "Get (or create) a counter of the given type that depends on another."
-    if not type in self.counters or not self.counters[type].master:
-      self.counters[type] = self.createdependent(type, master)
-    return self.counters[type]
-
-  def createdependent(self, type, master):
-    "Create a dependent counter given the master."
-    return DependentCounter(type).setmaster(master)
-
-  def startappendix(self):
-    "Start appendices here."
-    firsttype = self.orderedlayouts[DocumentParameters.startinglevel]
-    counter = self.getcounter(firsttype)
-    counter.setmode('A').reset()
-    NumberGenerator.appendix = True
-
-class ChapteredGenerator(NumberGenerator):
-  "Generate chaptered numbers, as in Chapter.Number."
-  "Used in equations, figures: Equation (5.3), figure 8.15."
-
-  def generate(self, type):
-    "Generate a number which goes with first-level numbers (chapters). "
-    "For the article classes a unique number is generated."
-    if DocumentParameters.startinglevel > 0:
-      return NumberGenerator.generator.generate(type)
-    chapter = self.getcounter('Chapter')
-    return self.getdependentcounter(type, chapter).getnext()
-
-
-NumberGenerator.chaptered = ChapteredGenerator()
-NumberGenerator.generator = NumberGenerator()
-
-
-
-
-
-
-class ContainerSize(object):
-  "The size of a container."
-
-  width = None
-  height = None
-  maxwidth = None
-  maxheight = None
-  scale = None
-
-  def set(self, width = None, height = None):
-    "Set the proper size with width and height."
-    self.setvalue('width', width)
-    self.setvalue('height', height)
-    return self
-
-  def setmax(self, maxwidth = None, maxheight = None):
-    "Set max width and/or height."
-    self.setvalue('maxwidth', maxwidth)
-    self.setvalue('maxheight', maxheight)
-    return self
-
-  def readparameters(self, container):
-    "Read some size parameters off a container."
-    self.setparameter(container, 'width')
-    self.setparameter(container, 'height')
-    self.setparameter(container, 'scale')
-    self.checkvalidheight(container)
-    return self
-
-  def setparameter(self, container, name):
-    "Read a size parameter off a container, and set it if present."
-    value = container.getparameter(name)
-    self.setvalue(name, value)
-
-  def setvalue(self, name, value):
-    "Set the value of a parameter name, only if it's valid."
-    value = self.processparameter(value)
-    if value:
-      setattr(self, name, value)
-
-  def checkvalidheight(self, container):
-    "Check if the height parameter is valid; otherwise erase it."
-    heightspecial = container.getparameter('height_special')
-    if self.height and self.extractnumber(self.height) == '1' and heightspecial == 'totalheight':
-      self.height = None
-
-  def processparameter(self, value):
-    "Do the full processing on a parameter."
-    if not value:
-      return None
-    if self.extractnumber(value) == '0':
-      return None
-    for ignored in StyleConfig.size['ignoredtexts']:
-      if ignored in value:
-        value = value.replace(ignored, '')
-    return value
-
-  def extractnumber(self, text):
-    "Extract the first number in the given text."
-    result = ''
-    decimal = False
-    for char in text:
-      if char.isdigit():
-        result += char
-      elif char == '.' and not decimal:
-        result += char
-        decimal = True
-      else:
-        return result
-    return result
-
-  def checkimage(self, width, height):
-    "Check image dimensions, set them if possible."
-    if width:
-      self.maxwidth = unicode(width) + 'px'
-      if self.scale and not self.width:
-        self.width = self.scalevalue(width)
-    if height:
-      self.maxheight = unicode(height) + 'px'
-      if self.scale and not self.height:
-        self.height = self.scalevalue(height)
-    if self.width and not self.height:
-      self.height = 'auto'
-    if self.height and not self.width:
-      self.width = 'auto'
-
-  def scalevalue(self, value):
-    "Scale the value according to the image scale and return it as unicode."
-    scaled = value * int(self.scale) / 100
-    return unicode(int(scaled)) + 'px'
-
-  def removepercentwidth(self):
-    "Remove percent width if present, to set it at the figure level."
-    if not self.width:
-      return None
-    if not '%' in self.width:
-      return None
-    width = self.width
-    self.width = None
-    if self.height == 'auto':
-      self.height = None
-    return width
-
-  def addstyle(self, container):
-    "Add the proper style attribute to the output tag."
-    if not isinstance(container.output, TaggedOutput):
-      Trace.error('No tag to add style, in ' + unicode(container))
-    if not self.width and not self.height and not self.maxwidth and not self.maxheight:
-      # nothing to see here; move along
-      return
-    tag = ' style="'
-    tag += self.styleparameter('width')
-    tag += self.styleparameter('maxwidth')
-    tag += self.styleparameter('height')
-    tag += self.styleparameter('maxheight')
-    if tag[-1] == ' ':
-      tag = tag[:-1]
-    tag += '"'
-    container.output.tag += tag
-
-  def styleparameter(self, name):
-    "Get the style for a single parameter."
-    value = getattr(self, name)
-    if value:
-      return name.replace('max', 'max-') + ': ' + value + '; '
-    return ''
-
-
-
-class QuoteContainer(Container):
-  "A container for a pretty quote"
-
-  def __init__(self):
-    self.parser = BoundedParser()
-    self.output = FixedOutput()
-
-  def process(self):
-    "Process contents"
-    self.type = self.header[2]
-    if not self.type in StyleConfig.quotes:
-      Trace.error('Quote type ' + self.type + ' not found')
-      self.html = ['"']
-      return
-    self.html = [StyleConfig.quotes[self.type]]
-
-class LyXLine(Container):
-  "A Lyx line"
-
-  def __init__(self):
-    self.parser = LoneCommand()
-    self.output = FixedOutput()
-
-  def process(self):
-    self.html = ['<hr class="line" />']
-
-class EmphaticText(TaggedText):
-  "Text with emphatic mode"
-
-  def process(self):
-    self.output.tag = 'i'
-
-class ShapedText(TaggedText):
-  "Text shaped (italic, slanted)"
-
-  def process(self):
-    self.type = self.header[1]
-    if not self.type in TagConfig.shaped:
-      Trace.error('Unrecognized shape ' + self.header[1])
-      self.output.tag = 'span'
-      return
-    self.output.tag = TagConfig.shaped[self.type]
-
-class VersalitasText(TaggedText):
-  "Text in versalitas"
-
-  def process(self):
-    self.output.tag = 'span class="versalitas"'
-
-class ColorText(TaggedText):
-  "Colored text"
-
-  def process(self):
-    self.color = self.header[1]
-    self.output.tag = 'span class="' + self.color + '"'
-
-class SizeText(TaggedText):
-  "Sized text"
-
-  def process(self):
-    self.size = self.header[1]
-    self.output.tag = 'span class="' + self.size + '"'
-
-class BoldText(TaggedText):
-  "Bold text"
-
-  def process(self):
-    self.output.tag = 'b'
-
-class TextFamily(TaggedText):
-  "A bit of text from elyxer.a different family"
-
-  def process(self):
-    "Parse the type of family"
-    self.type = self.header[1]
-    if not self.type in TagConfig.family:
-      Trace.error('Unrecognized family ' + type)
-      self.output.tag = 'span'
-      return
-    self.output.tag = TagConfig.family[self.type]
-
-class Hfill(TaggedText):
-  "Horizontall fill"
-
-  def process(self):
-    self.output.tag = 'span class="hfill"'
-
-class BarredText(TaggedText):
-  "Text with a bar somewhere"
-
-  def process(self):
-    "Parse the type of bar"
-    self.type = self.header[1]
-    if not self.type in TagConfig.barred:
-      Trace.error('Unknown bar type ' + self.type)
-      self.output.tag = 'span'
-      return
-    self.output.tag = TagConfig.barred[self.type]
-
-class LangLine(TaggedText):
-  "A line with language information"
-
-  def process(self):
-    "Only generate a span with lang info when the language is recognized."
-    lang = self.header[1]
-    if not lang in TranslationConfig.languages:
-      self.output = ContentsOutput()
-      return
-    isolang = TranslationConfig.languages[lang]
-    self.output = TaggedOutput().settag('span lang="' + isolang + '"', False)
-
-class InsetLength(BlackBox):
-  "A length measure inside an inset."
-
-  def process(self):
-    self.length = self.header[1]
-
-class Space(Container):
-  "A space of several types"
-
-  def __init__(self):
-    self.parser = InsetParser()
-    self.output = FixedOutput()
-
-  def process(self):
-    self.type = self.header[2]
-    if self.type not in StyleConfig.hspaces:
-      Trace.error('Unknown space type ' + self.type)
-      self.html = [' ']
-      return
-    self.html = [StyleConfig.hspaces[self.type]]
-    length = self.getlength()
-    if not length:
-      return
-    self.output = TaggedOutput().settag('span class="hspace"', False)
-    ContainerSize().set(length).addstyle(self)
-
-  def getlength(self):
-    "Get the space length from elyxer.the contents or parameters."
-    if len(self.contents) == 0 or not isinstance(self.contents[0], InsetLength):
-      return None
-    return self.contents[0].length
-
-class VerticalSpace(Container):
-  "An inset that contains a vertical space."
-
-  def __init__(self):
-    self.parser = InsetParser()
-    self.output = FixedOutput()
-
-  def process(self):
-    "Set the correct tag"
-    self.type = self.header[2]
-    if self.type not in StyleConfig.vspaces:
-      self.output = TaggedOutput().settag('div class="vspace" style="height: ' + self.type + ';"', True)
-      return
-    self.html = [StyleConfig.vspaces[self.type]]
-
-class Align(Container):
-  "Bit of aligned text"
-
-  def __init__(self):
-    self.parser = ExcludingParser()
-    self.output = TaggedOutput().setbreaklines(True)
-
-  def process(self):
-    self.output.tag = 'div class="' + self.header[1] + '"'
-
-class Newline(Container):
-  "A newline"
-
-  def __init__(self):
-    self.parser = LoneCommand()
-    self.output = FixedOutput()
-
-  def process(self):
-    "Process contents"
-    self.html = ['<br/>\n']
-
-class NewPage(Newline):
-  "A new page"
-
-  def process(self):
-    "Process contents"
-    self.html = ['<p><br/>\n</p>\n']
-
-class Separator(Container):
-  "A separator string which is not extracted by extracttext()."
-
-  def __init__(self, constant):
-    self.output = FixedOutput()
-    self.contents = []
-    self.html = [constant]
-
-class StrikeOut(TaggedText):
-  "Striken out text."
-
-  def process(self):
-    "Set the output tag to strike."
-    self.output.tag = 'strike'
-
-class StartAppendix(BlackBox):
-  "Mark to start an appendix here."
-  "From this point on, all chapters become appendices."
-
-  def process(self):
-    "Activate the special numbering scheme for appendices, using letters."
-    NumberGenerator.generator.startappendix()
-
-
-
-
-
-
-class Link(Container):
-  "A link to another part of the document"
-
-  anchor = None
-  url = None
-  type = None
-  page = None
-  target = None
-  destination = None
-  title = None
-
-  def __init__(self):
-    "Initialize the link, add target if configured."
-    self.contents = []
-    self.parser = InsetParser()
-    self.output = LinkOutput()
-    if Options.target:
-      self.target = Options.target
-
-  def complete(self, text, anchor = None, url = None, type = None, title = None):
-    "Complete the link."
-    self.contents = [Constant(text)]
-    if anchor:
-      self.anchor = anchor
-    if url:
-      self.url = url
-    if type:
-      self.type = type
-    if title:
-      self.title = title
-    return self
-
-  def computedestination(self):
-    "Use the destination link to fill in the destination URL."
-    if not self.destination:
-      return
-    self.url = ''
-    if self.destination.anchor:
-      self.url = '#' + self.destination.anchor
-    if self.destination.page:
-      self.url = self.destination.page + self.url
-
-  def setmutualdestination(self, destination):
-    "Set another link as destination, and set its destination to this one."
-    self.destination = destination
-    destination.destination = self
-
-  def __unicode__(self):
-    "Return a printable representation."
-    result = 'Link'
-    if self.anchor:
-      result += ' #' + self.anchor
-    if self.url:
-      result += ' to ' + self.url
-    return result
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class URL(Link):
-  "A clickable URL"
-
-  def process(self):
-    "Read URL from elyxer.parameters"
-    target = self.escape(self.getparameter('target'))
-    self.url = target
-    type = self.getparameter('type')
-    if type:
-      self.url = self.escape(type) + target
-    name = self.getparameter('name')
-    if not name:
-      name = target
-    self.contents = [Constant(name)]
-
-class FlexURL(URL):
-  "A flexible URL"
-
-  def process(self):
-    "Read URL from elyxer.contents"
-    self.url = self.extracttext()
-
-class LinkOutput(ContainerOutput):
-  "A link pointing to some destination"
-  "Or an anchor (destination)"
-
-  def gethtml(self, link):
-    "Get the HTML code for the link"
-    type = link.__class__.__name__
-    if link.type:
-      type = link.type
-    tag = 'a class="' + type + '"'
-    if link.anchor:
-      tag += ' name="' + link.anchor + '"'
-    if link.destination:
-      link.computedestination()
-    if link.url:
-      tag += ' href="' + link.url + '"'
-    if link.target:
-      tag += ' target="' + link.target + '"'
-    if link.title:
-      tag += ' title="' + link.title + '"'
-    return TaggedOutput().settag(tag).gethtml(link)
-
-
-
-
-
-class Postprocessor(object):
-  "Postprocess a container keeping some context"
-
-  stages = []
-
-  def __init__(self):
-    self.stages = StageDict(Postprocessor.stages, self)
-    self.current = None
-    self.last = None
-
-  def postprocess(self, next):
-    "Postprocess a container and its contents."
-    self.postrecursive(self.current)
-    result = self.postcurrent(next)
-    self.last = self.current
-    self.current = next
-    return result
-
-  def postrecursive(self, container):
-    "Postprocess the container contents recursively"
-    if not hasattr(container, 'contents'):
-      return
-    if len(container.contents) == 0:
-      return
-    if hasattr(container, 'postprocess'):
-      if not container.postprocess:
-        return
-    postprocessor = Postprocessor()
-    contents = []
-    for element in container.contents:
-      post = postprocessor.postprocess(element)
-      if post:
-        contents.append(post)
-    # two rounds to empty the pipeline
-    for i in range(2):
-      post = postprocessor.postprocess(None)
-      if post:
-        contents.append(post)
-    container.contents = contents
-
-  def postcurrent(self, next):
-    "Postprocess the current element taking into account next and last."
-    stage = self.stages.getstage(self.current)
-    if not stage:
-      return self.current
-    return stage.postprocess(self.last, self.current, next)
-
-class StageDict(object):
-  "A dictionary of stages corresponding to classes"
-
-  def __init__(self, classes, postprocessor):
-    "Instantiate an element from elyxer.each class and store as a dictionary"
-    instances = self.instantiate(classes, postprocessor)
-    self.stagedict = dict([(x.processedclass, x) for x in instances])
-
-  def instantiate(self, classes, postprocessor):
-    "Instantiate an element from elyxer.each class"
-    stages = [x.__new__(x) for x in classes]
-    for element in stages:
-      element.__init__()
-      element.postprocessor = postprocessor
-    return stages
-
-  def getstage(self, element):
-    "Get the stage for a given element, if the type is in the dict"
-    if not element.__class__ in self.stagedict:
-      return None
-    return self.stagedict[element.__class__]
-
-
-
-class Label(Link):
-  "A label to be referenced"
-
-  names = dict()
-  lastlayout = None
-
-  def __init__(self):
-    Link.__init__(self)
-    self.lastnumbered = None
-
-  def process(self):
-    "Process a label container."
-    key = self.getparameter('name')
-    self.create(' ', key)
-    self.lastnumbered = Label.lastlayout
-
-  def create(self, text, key, type = 'Label'):
-    "Create the label for a given key."
-    self.key = key
-    self.complete(text, anchor = key, type = type)
-    Label.names[key] = self
-    if key in Reference.references:
-      for reference in Reference.references[key]:
-        reference.destination = self
-    return self
-
-  def findpartkey(self):
-    "Get the part key for the latest numbered container seen."
-    numbered = self.numbered(self)
-    if numbered and numbered.partkey:
-      return numbered.partkey
-    return ''
-
-  def numbered(self, container):
-    "Get the numbered container for the label."
-    if container.partkey:
-      return container
-    if not container.parent:
-      if self.lastnumbered:
-        return self.lastnumbered
-      return None
-    return self.numbered(container.parent)
-
-  def __unicode__(self):
-    "Return a printable representation."
-    if not hasattr(self, 'key'):
-      return 'Unnamed label'
-    return 'Label ' + self.key
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class Reference(Link):
-  "A reference to a label."
-
-  references = dict()
-  key = 'none'
-
-  def process(self):
-    "Read the reference and set the arrow."
-    self.key = self.getparameter('reference')
-    if self.key in Label.names:
-      self.direction = u'↑'
-      label = Label.names[self.key]
-    else:
-      self.direction = u'↓'
-      label = Label().complete(' ', self.key, 'preref')
-    self.destination = label
-    self.formatcontents()
-    if not self.key in Reference.references:
-      Reference.references[self.key] = []
-    Reference.references[self.key].append(self)
-
-  def formatcontents(self):
-    "Format the reference contents."
-    formatkey = self.getparameter('LatexCommand')
-    if not formatkey:
-      formatkey = 'ref'
-    self.formatted = u'↕'
-    if formatkey in StyleConfig.referenceformats:
-      self.formatted = StyleConfig.referenceformats[formatkey]
-    else:
-      Trace.error('Unknown reference format ' + formatkey)
-    self.replace(u'↕', self.direction)
-    self.replace('#', '1')
-    self.replace('on-page', Translator.translate('on-page'))
-    partkey = self.destination.findpartkey()
-    # only if partkey and partkey.number are not null, send partkey.number
-    self.replace('@', partkey and partkey.number)
-    self.replace(u'¶', partkey and partkey.tocentry)
-    if not '$' in self.formatted or not partkey or not partkey.titlecontents:
-      # there is a $ left, but it should go away on preprocessing
-      self.contents = [Constant(self.formatted)]
-      return
-    pieces = self.formatted.split('$')
-    self.contents = [Constant(pieces[0])]
-    for piece in pieces[1:]:
-      self.contents += partkey.titlecontents
-      self.contents.append(Constant(piece))
-
-  def replace(self, key, value):
-    "Replace a key in the format template with a value."
-    if not key in self.formatted:
-      return
-    if not value:
-      value = ''
-    self.formatted = self.formatted.replace(key, value)
-
-  def __unicode__(self):
-    "Return a printable representation."
-    return 'Reference ' + self.key
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class FormulaCommand(FormulaBit):
-  "A LaTeX command inside a formula"
-
-  types = []
-  start = FormulaConfig.starts['command']
-  commandmap = None
-
-  def detect(self, pos):
-    "Find the current command."
-    return pos.checkfor(FormulaCommand.start)
-
-  def parsebit(self, pos):
-    "Parse the command."
-    command = self.extractcommand(pos)
-    bit = self.parsewithcommand(command, pos)
-    if bit:
-      return bit
-    if command.startswith('\\up') or command.startswith('\\Up'):
-      upgreek = self.parseupgreek(command, pos)
-      if upgreek:
-        return upgreek
-    if not self.factory.defining:
-      Trace.error('Unknown command ' + command)
-    self.output = TaggedOutput().settag('span class="unknown"')
-    self.add(FormulaConstant(command))
-    return None
-
-  def parsewithcommand(self, command, pos):
-    "Parse the command type once we have the command."
-    for type in FormulaCommand.types:
-      if command in type.commandmap:
-        return self.parsecommandtype(command, type, pos)
-    return None
-
-  def parsecommandtype(self, command, type, pos):
-    "Parse a given command type."
-    bit = self.factory.create(type)
-    bit.setcommand(command)
-    returned = bit.parsebit(pos)
-    if returned:
-      return returned
-    return bit
-
-  def extractcommand(self, pos):
-    "Extract the command from elyxer.the current position."
-    if not pos.checkskip(FormulaCommand.start):
-      pos.error('Missing command start ' + FormulaCommand.start)
-      return
-    if pos.finished():
-      return self.emptycommand(pos)
-    if pos.current().isalpha():
-      # alpha command
-      command = FormulaCommand.start + pos.globalpha()
-      # skip mark of short command
-      pos.checkskip('*')
-      return command
-    # symbol command
-    return FormulaCommand.start + pos.skipcurrent()
-
-  def emptycommand(self, pos):
-    """Check for an empty command: look for command disguised as ending.
-    Special case against '{ \\{ \\} }' situation."""
-    command = ''
-    if not pos.isout():
-      ending = pos.nextending()
-      if ending and pos.checkskip(ending):
-        command = ending
-    return FormulaCommand.start + command
-
-  def parseupgreek(self, command, pos):
-    "Parse the Greek \\up command.."
-    if len(command) < 4:
-      return None
-    if command.startswith('\\up'):
-      upcommand = '\\' + command[3:]
-    elif pos.checkskip('\\Up'):
-      upcommand = '\\' + command[3:4].upper() + command[4:]
-    else:
-      Trace.error('Impossible upgreek command: ' + command)
-      return
-    upgreek = self.parsewithcommand(upcommand, pos)
-    if upgreek:
-      upgreek.type = 'font'
-    return upgreek
-
-class CommandBit(FormulaCommand):
-  "A formula bit that includes a command"
-
-  def setcommand(self, command):
-    "Set the command in the bit"
-    self.command = command
-    if self.commandmap:
-      self.original += command
-      self.translated = self.commandmap[self.command]
-
-  def parseparameter(self, pos):
-    "Parse a parameter at the current position"
-    self.factory.clearskipped(pos)
-    if pos.finished():
-      return None
-    parameter = self.factory.parseany(pos)
-    self.add(parameter)
-    return parameter
-
-  def parsesquare(self, pos):
-    "Parse a square bracket"
-    self.factory.clearskipped(pos)
-    if not self.factory.detecttype(SquareBracket, pos):
-      return None
-    bracket = self.factory.parsetype(SquareBracket, pos)
-    self.add(bracket)
-    return bracket
-
-  def parseliteral(self, pos):
-    "Parse a literal bracket."
-    self.factory.clearskipped(pos)
-    if not self.factory.detecttype(Bracket, pos):
-      if not pos.isvalue():
-        Trace.error('No literal parameter found at: ' + pos.identifier())
-        return None
-      return pos.globvalue()
-    bracket = Bracket().setfactory(self.factory)
-    self.add(bracket.parseliteral(pos))
-    return bracket.literal
-
-  def parsesquareliteral(self, pos):
-    "Parse a square bracket literally."
-    self.factory.clearskipped(pos)
-    if not self.factory.detecttype(SquareBracket, pos):
-      return None
-    bracket = SquareBracket().setfactory(self.factory)
-    self.add(bracket.parseliteral(pos))
-    return bracket.literal
-
-  def parsetext(self, pos):
-    "Parse a text parameter."
-    self.factory.clearskipped(pos)
-    if not self.factory.detecttype(Bracket, pos):
-      Trace.error('No text parameter for ' + self.command)
-      return None
-    bracket = Bracket().setfactory(self.factory).parsetext(pos)
-    self.add(bracket)
-    return bracket
-
-class EmptyCommand(CommandBit):
-  "An empty command (without parameters)"
-
-  commandmap = FormulaConfig.commands
-
-  def parsebit(self, pos):
-    "Parse a command without parameters"
-    self.contents = [FormulaConstant(self.translated)]
-
-class SpacedCommand(CommandBit):
-  "An empty command which should have math spacing in formulas."
-
-  commandmap = FormulaConfig.spacedcommands
-
-  def parsebit(self, pos):
-    "Place as contents the command translated and spaced."
-    self.contents = [FormulaConstant(u' ' + self.translated + u' ')]
-
-class AlphaCommand(EmptyCommand):
-  "A command without paramters whose result is alphabetical"
-
-  commandmap = FormulaConfig.alphacommands
-
-  def parsebit(self, pos):
-    "Parse the command and set type to alpha"
-    EmptyCommand.parsebit(self, pos)
-    self.type = 'alpha'
-
-class OneParamFunction(CommandBit):
-  "A function of one parameter"
-
-  commandmap = FormulaConfig.onefunctions
-  simplified = False
-
-  def parsebit(self, pos):
-    "Parse a function with one parameter"
-    self.output = TaggedOutput().settag(self.translated)
-    self.parseparameter(pos)
-    self.simplifyifpossible()
-
-  def simplifyifpossible(self):
-    "Try to simplify to a single character."
-    if self.original in self.commandmap:
-      self.output = FixedOutput()
-      self.html = [self.commandmap[self.original]]
-      self.simplified = True
-
-class SymbolFunction(CommandBit):
-  "Find a function which is represented by a symbol (like _ or ^)"
-
-  commandmap = FormulaConfig.symbolfunctions
-
-  def detect(self, pos):
-    "Find the symbol"
-    return pos.current() in SymbolFunction.commandmap
-
-  def parsebit(self, pos):
-    "Parse the symbol"
-    self.setcommand(pos.current())
-    pos.skip(self.command)
-    self.output = TaggedOutput().settag(self.translated)
-    self.parseparameter(pos)
-
-class TextFunction(CommandBit):
-  "A function where parameters are read as text."
-
-  commandmap = FormulaConfig.textfunctions
-
-  def parsebit(self, pos):
-    "Parse a text parameter"
-    self.output = TaggedOutput().settag(self.translated)
-    self.parsetext(pos)
-
-  def process(self):
-    "Set the type to font"
-    self.type = 'font'
-
-class LabelFunction(CommandBit):
-  "A function that acts as a label"
-
-  commandmap = FormulaConfig.labelfunctions
-
-  def parsebit(self, pos):
-    "Parse a literal parameter"
-    self.key = self.parseliteral(pos)
-
-  def process(self):
-    "Add an anchor with the label contents."
-    self.type = 'font'
-    self.label = Label().create(' ', self.key, type = 'eqnumber')
-    self.contents = [self.label]
-    # store as a Label so we know it's been seen
-    Label.names[self.key] = self.label
-
-class FontFunction(OneParamFunction):
-  "A function of one parameter that changes the font"
-
-  commandmap = FormulaConfig.fontfunctions
-
-  def process(self):
-    "Simplify if possible using a single character."
-    self.type = 'font'
-    self.simplifyifpossible()
-
-FormulaFactory.types += [FormulaCommand, SymbolFunction]
-FormulaCommand.types = [
-    AlphaCommand, EmptyCommand, OneParamFunction, FontFunction, LabelFunction,
-    TextFunction, SpacedCommand,
-    ]
-
-
-
-
-
-
-
-
-
-
-
-
-class BigSymbol(object):
-  "A big symbol generator."
-
-  symbols = FormulaConfig.bigsymbols
-
-  def __init__(self, symbol):
-    "Create the big symbol."
-    self.symbol = symbol
-
-  def getpieces(self):
-    "Get an array with all pieces."
-    if not self.symbol in self.symbols:
-      return [self.symbol]
-    if self.smalllimit():
-      return [self.symbol]
-    return self.symbols[self.symbol]
-
-  def smalllimit(self):
-    "Decide if the limit should be a small, one-line symbol."
-    if not DocumentParameters.displaymode:
-      return True
-    if len(self.symbols[self.symbol]) == 1:
-      return True
-    return Options.simplemath
-
-class BigBracket(BigSymbol):
-  "A big bracket generator."
-
-  def __init__(self, size, bracket, alignment='l'):
-    "Set the size and symbol for the bracket."
-    self.size = size
-    self.original = bracket
-    self.alignment = alignment
-    self.pieces = None
-    if bracket in FormulaConfig.bigbrackets:
-      self.pieces = FormulaConfig.bigbrackets[bracket]
-
-  def getpiece(self, index):
-    "Return the nth piece for the bracket."
-    function = getattr(self, 'getpiece' + unicode(len(self.pieces)))
-    return function(index)
-
-  def getpiece1(self, index):
-    "Return the only piece for a single-piece bracket."
-    return self.pieces[0]
-
-  def getpiece3(self, index):
-    "Get the nth piece for a 3-piece bracket: parenthesis or square bracket."
-    if index == 0:
-      return self.pieces[0]
-    if index == self.size - 1:
-      return self.pieces[-1]
-    return self.pieces[1]
-
-  def getpiece4(self, index):
-    "Get the nth piece for a 4-piece bracket: curly bracket."
-    if index == 0:
-      return self.pieces[0]
-    if index == self.size - 1:
-      return self.pieces[3]
-    if index == (self.size - 1)/2:
-      return self.pieces[2]
-    return self.pieces[1]
-
-  def getcell(self, index):
-    "Get the bracket piece as an array cell."
-    piece = self.getpiece(index)
-    span = 'span class="bracket align-' + self.alignment + '"'
-    return TaggedBit().constant(piece, span)
-
-  def getcontents(self):
-    "Get the bracket as an array or as a single bracket."
-    if self.size == 1 or not self.pieces:
-      return self.getsinglebracket()
-    rows = []
-    for index in range(self.size):
-      cell = self.getcell(index)
-      rows.append(TaggedBit().complete([cell], 'span class="arrayrow"'))
-    return [TaggedBit().complete(rows, 'span class="array"')]
-
-  def getsinglebracket(self):
-    "Return the bracket as a single sign."
-    if self.original == '.':
-      return [TaggedBit().constant('', 'span class="emptydot"')]
-    return [TaggedBit().constant(self.original, 'span class="symbol"')]
-
-
-
-
-
-
-class FormulaEquation(CommandBit):
-  "A simple numbered equation."
-
-  piece = 'equation'
-
-  def parsebit(self, pos):
-    "Parse the array"
-    self.output = ContentsOutput()
-    self.add(self.factory.parsetype(WholeFormula, pos))
-
-class FormulaCell(FormulaCommand):
-  "An array cell inside a row"
-
-  def setalignment(self, alignment):
-    self.alignment = alignment
-    self.output = TaggedOutput().settag('span class="arraycell align-' + alignment +'"', True)
-    return self
-
-  def parsebit(self, pos):
-    self.factory.clearskipped(pos)
-    if pos.finished():
-      return
-    self.add(self.factory.parsetype(WholeFormula, pos))
-
-class FormulaRow(FormulaCommand):
-  "An array row inside an array"
-
-  cellseparator = FormulaConfig.array['cellseparator']
-
-  def setalignments(self, alignments):
-    self.alignments = alignments
-    self.output = TaggedOutput().settag('span class="arrayrow"', True)
-    return self
-
-  def parsebit(self, pos):
-    "Parse a whole row"
-    index = 0
-    pos.pushending(self.cellseparator, optional=True)
-    while not pos.finished():
-      cell = self.createcell(index)
-      cell.parsebit(pos)
-      self.add(cell)
-      index += 1
-      pos.checkskip(self.cellseparator)
-    if len(self.contents) == 0:
-      self.output = EmptyOutput()
-
-  def createcell(self, index):
-    "Create the cell that corresponds to the given index."
-    alignment = self.alignments[index % len(self.alignments)]
-    return self.factory.create(FormulaCell).setalignment(alignment)
-
-class MultiRowFormula(CommandBit):
-  "A formula with multiple rows."
-
-  def parserows(self, pos):
-    "Parse all rows, finish when no more row ends"
-    self.rows = []
-    first = True
-    for row in self.iteraterows(pos):
-      if first:
-        first = False
-      else:
-        # intersparse empty rows
-        self.addempty()
-      row.parsebit(pos)
-      self.addrow(row)
-    self.size = len(self.rows)
-
-  def iteraterows(self, pos):
-    "Iterate over all rows, end when no more row ends"
-    rowseparator = FormulaConfig.array['rowseparator']
-    while True:
-      pos.pushending(rowseparator, True)
-      row = self.factory.create(FormulaRow)
-      yield row.setalignments(self.alignments)
-      if pos.checkfor(rowseparator):
-        self.original += pos.popending(rowseparator)
-      else:
-        return
-
-  def addempty(self):
-    "Add an empty row."
-    row = self.factory.create(FormulaRow).setalignments(self.alignments)
-    for index, originalcell in enumerate(self.rows[-1].contents):
-      cell = row.createcell(index)
-      cell.add(FormulaConstant(u' '))
-      row.add(cell)
-    self.addrow(row)
-
-  def addrow(self, row):
-    "Add a row to the contents and to the list of rows."
-    self.rows.append(row)
-    self.add(row)
-
-class FormulaArray(MultiRowFormula):
-  "An array within a formula"
-
-  piece = 'array'
-
-  def parsebit(self, pos):
-    "Parse the array"
-    self.output = TaggedOutput().settag('span class="array"', False)
-    self.parsealignments(pos)
-    self.parserows(pos)
-
-  def parsealignments(self, pos):
-    "Parse the different alignments"
-    # vertical
-    self.valign = 'c'
-    literal = self.parsesquareliteral(pos)
-    if literal:
-      self.valign = literal
-    # horizontal
-    literal = self.parseliteral(pos)
-    self.alignments = []
-    for l in literal:
-      self.alignments.append(l)
-
-class FormulaMatrix(MultiRowFormula):
-  "A matrix (array with center alignment)."
-
-  piece = 'matrix'
-
-  def parsebit(self, pos):
-    "Parse the matrix, set alignments to 'c'."
-    self.output = TaggedOutput().settag('span class="array"', False)
-    self.valign = 'c'
-    self.alignments = ['c']
-    self.parserows(pos)
-
-class FormulaCases(MultiRowFormula):
-  "A cases statement"
-
-  piece = 'cases'
-
-  def parsebit(self, pos):
-    "Parse the cases"
-    self.output = ContentsOutput()
-    self.alignments = ['l', 'l']
-    self.parserows(pos)
-    for row in self.contents:
-      for cell in row.contents:
-        cell.output.settag('span class="case align-l"', True)
-        cell.contents.append(FormulaConstant(u' '))
-    array = TaggedBit().complete(self.contents, 'span class="bracketcases"', True)
-    brace = BigBracket(len(self.contents), '{', 'l')
-    self.contents = brace.getcontents() + [array]
-
-class EquationEnvironment(MultiRowFormula):
-  "A \\begin{}...\\end equation environment with rows and cells."
-
-  def parsebit(self, pos):
-    "Parse the whole environment."
-    self.output = TaggedOutput().settag('span class="environment"', False)
-    environment = self.piece.replace('*', '')
-    if environment in FormulaConfig.environments:
-      self.alignments = FormulaConfig.environments[environment]
-    else:
-      Trace.error('Unknown equation environment ' + self.piece)
-      self.alignments = ['l']
-    self.parserows(pos)
-
-class BeginCommand(CommandBit):
-  "A \\begin{}...\\end command and what it entails (array, cases, aligned)"
-
-  commandmap = {FormulaConfig.array['begin']:''}
-
-  types = [FormulaEquation, FormulaArray, FormulaCases, FormulaMatrix]
-
-  def parsebit(self, pos):
-    "Parse the begin command"
-    command = self.parseliteral(pos)
-    bit = self.findbit(command)
-    ending = FormulaConfig.array['end'] + '{' + command + '}'
-    pos.pushending(ending)
-    bit.parsebit(pos)
-    self.add(bit)
-    self.original += pos.popending(ending)
-    self.size = bit.size
-
-  def findbit(self, piece):
-    "Find the command bit corresponding to the \\begin{piece}"
-    for type in BeginCommand.types:
-      if piece.replace('*', '') == type.piece:
-        return self.factory.create(type)
-    bit = self.factory.create(EquationEnvironment)
-    bit.piece = piece
-    return bit
-
-FormulaCommand.types += [BeginCommand]
-
-
-
-class CombiningFunction(OneParamFunction):
-
-  commandmap = FormulaConfig.combiningfunctions
-
-  def parsebit(self, pos):
-    "Parse a combining function."
-    self.type = 'alpha'
-    combining = self.translated
-    parameter = self.parsesingleparameter(pos)
-    if not parameter:
-      Trace.error('Empty parameter for combining function ' + self.command)
-    elif len(parameter.extracttext()) != 1:
-      Trace.error('Applying combining function ' + self.command + ' to invalid string "' + parameter.extracttext() + '"')
-    self.contents.append(Constant(combining))
-
-  def parsesingleparameter(self, pos):
-    "Parse a parameter, or a single letter."
-    self.factory.clearskipped(pos)
-    if pos.finished():
-      Trace.error('Error while parsing single parameter at ' + pos.identifier())
-      return None
-    if self.factory.detecttype(Bracket, pos) \
-        or self.factory.detecttype(FormulaCommand, pos):
-      return self.parseparameter(pos)
-    letter = FormulaConstant(pos.skipcurrent())
-    self.add(letter)
-    return letter
-
-class DecoratingFunction(OneParamFunction):
-  "A function that decorates some bit of text"
-
-  commandmap = FormulaConfig.decoratingfunctions
-
-  def parsebit(self, pos):
-    "Parse a decorating function"
-    self.type = 'alpha'
-    symbol = self.translated
-    self.symbol = TaggedBit().constant(symbol, 'span class="symbolover"')
-    self.parameter = self.parseparameter(pos)
-    self.output = TaggedOutput().settag('span class="withsymbol"')
-    self.contents.insert(0, self.symbol)
-    self.parameter.output = TaggedOutput().settag('span class="undersymbol"')
-    self.simplifyifpossible()
-
-class LimitCommand(EmptyCommand):
-  "A command which accepts limits above and below, in display mode."
-
-  commandmap = FormulaConfig.limitcommands
-
-  def parsebit(self, pos):
-    "Parse a limit command."
-    pieces = BigSymbol(self.translated).getpieces()
-    self.output = TaggedOutput().settag('span class="limits"')
-    for piece in pieces:
-      self.contents.append(TaggedBit().constant(piece, 'span class="limit"'))
-
-class LimitPreviousCommand(LimitCommand):
-  "A command to limit the previous command."
-
-  commandmap = None
-
-  def parsebit(self, pos):
-    "Do nothing."
-    self.output = TaggedOutput().settag('span class="limits"')
-    self.factory.clearskipped(pos)
-
-  def __unicode__(self):
-    "Return a printable representation."
-    return 'Limit previous command'
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class LimitsProcessor(MathsProcessor):
-  "A processor for limits inside an element."
-
-  def process(self, contents, index):
-    "Process the limits for an element."
-    if Options.simplemath:
-      return
-    if self.checklimits(contents, index):
-      self.modifylimits(contents, index)
-    if self.checkscript(contents, index) and self.checkscript(contents, index + 1):
-      self.modifyscripts(contents, index)
-
-  def checklimits(self, contents, index):
-    "Check if the current position has a limits command."
-    if not DocumentParameters.displaymode:
-      return False
-    if self.checkcommand(contents, index + 1, LimitPreviousCommand):
-      self.limitsahead(contents, index)
-      return False
-    if not isinstance(contents[index], LimitCommand):
-      return False
-    return self.checkscript(contents, index + 1)
-
-  def limitsahead(self, contents, index):
-    "Limit the current element based on the next."
-    contents[index + 1].add(contents[index].clone())
-    contents[index].output = EmptyOutput()
-
-  def modifylimits(self, contents, index):
-    "Modify a limits commands so that the limits appear above and below."
-    limited = contents[index]
-    subscript = self.getlimit(contents, index + 1)
-    limited.contents.append(subscript)
-    if self.checkscript(contents, index + 1):
-      superscript = self.getlimit(contents, index  + 1)
-    else:
-      superscript = TaggedBit().constant(u' ', 'sup class="limit"')
-    limited.contents.insert(0, superscript)
-
-  def getlimit(self, contents, index):
-    "Get the limit for a limits command."
-    limit = self.getscript(contents, index)
-    limit.output.tag = limit.output.tag.replace('script', 'limit')
-    return limit
-
-  def modifyscripts(self, contents, index):
-    "Modify the super- and subscript to appear vertically aligned."
-    subscript = self.getscript(contents, index)
-    # subscript removed so instead of index + 1 we get index again
-    superscript = self.getscript(contents, index)
-    scripts = TaggedBit().complete([superscript, subscript], 'span class="scripts"')
-    contents.insert(index, scripts)
-
-  def checkscript(self, contents, index):
-    "Check if the current element is a sub- or superscript."
-    return self.checkcommand(contents, index, SymbolFunction)
-
-  def checkcommand(self, contents, index, type):
-    "Check for the given type as the current element."
-    if len(contents) <= index:
-      return False
-    return isinstance(contents[index], type)
-
-  def getscript(self, contents, index):
-    "Get the sub- or superscript."
-    bit = contents[index]
-    bit.output.tag += ' class="script"'
-    del contents[index]
-    return bit
-
-class BracketCommand(OneParamFunction):
-  "A command which defines a bracket."
-
-  commandmap = FormulaConfig.bracketcommands
-
-  def parsebit(self, pos):
-    "Parse the bracket."
-    OneParamFunction.parsebit(self, pos)
-
-  def create(self, direction, character):
-    "Create the bracket for the given character."
-    self.original = character
-    self.command = '\\' + direction
-    self.contents = [FormulaConstant(character)]
-    return self
-
-class BracketProcessor(MathsProcessor):
-  "A processor for bracket commands."
-
-  def process(self, contents, index):
-    "Convert the bracket using Unicode pieces, if possible."
-    if Options.simplemath:
-      return
-    if self.checkleft(contents, index):
-      return self.processleft(contents, index)
-
-  def processleft(self, contents, index):
-    "Process a left bracket."
-    rightindex = self.findright(contents, index + 1)
-    if not rightindex:
-      return
-    size = self.findmax(contents, index, rightindex)
-    self.resize(contents[index], size)
-    self.resize(contents[rightindex], size)
-
-  def checkleft(self, contents, index):
-    "Check if the command at the given index is left."
-    return self.checkdirection(contents[index], '\\left')
-
-  def checkright(self, contents, index):
-    "Check if the command at the given index is right."
-    return self.checkdirection(contents[index], '\\right')
-
-  def checkdirection(self, bit, command):
-    "Check if the given bit is the desired bracket command."
-    if not isinstance(bit, BracketCommand):
-      return False
-    return bit.command == command
-
-  def findright(self, contents, index):
-    "Find the right bracket starting at the given index, or 0."
-    depth = 1
-    while index < len(contents):
-      if self.checkleft(contents, index):
-        depth += 1
-      if self.checkright(contents, index):
-        depth -= 1
-      if depth == 0:
-        return index
-      index += 1
-    return None
-
-  def findmax(self, contents, leftindex, rightindex):
-    "Find the max size of the contents between the two given indices."
-    sliced = contents[leftindex:rightindex]
-    return max([element.size for element in sliced])
-
-  def resize(self, command, size):
-    "Resize a bracket command to the given size."
-    character = command.extracttext()
-    alignment = command.command.replace('\\', '')
-    bracket = BigBracket(size, character, alignment)
-    command.output = ContentsOutput()
-    command.contents = bracket.getcontents()
-
-class TodayCommand(EmptyCommand):
-  "Shows today's date."
-
-  commandmap = None
-
-  def parsebit(self, pos):
-    "Parse a command without parameters"
-    self.output = FixedOutput()
-    self.html = [datetime.date.today().strftime('%b %d, %Y')]
-
-
-FormulaCommand.types += [
-    DecoratingFunction, CombiningFunction, LimitCommand, BracketCommand,
-    ]
-
-FormulaProcessor.processors += [
-    LimitsProcessor(), BracketProcessor(),
-    ]
-
-
-
-class ParameterDefinition(object):
-  "The definition of a parameter in a hybrid function."
-  "[] parameters are optional, {} parameters are mandatory."
-  "Each parameter has a one-character name, like {$1} or {$p}."
-  "A parameter that ends in ! like {$p!} is a literal."
-  "Example: [$1]{$p!} reads an optional parameter $1 and a literal mandatory parameter p."
-
-  parambrackets = [('[', ']'), ('{', '}')]
-
-  def __init__(self):
-    self.name = None
-    self.literal = False
-    self.optional = False
-    self.value = None
-    self.literalvalue = None
-
-  def parse(self, pos):
-    "Parse a parameter definition: [$0], {$x}, {$1!}..."
-    for (opening, closing) in ParameterDefinition.parambrackets:
-      if pos.checkskip(opening):
-        if opening == '[':
-          self.optional = True
-        if not pos.checkskip('$'):
-          Trace.error('Wrong parameter name, did you mean $' + pos.current() + '?')
-          return None
-        self.name = pos.skipcurrent()
-        if pos.checkskip('!'):
-          self.literal = True
-        if not pos.checkskip(closing):
-          Trace.error('Wrong parameter closing ' + pos.skipcurrent())
-          return None
-        return self
-    Trace.error('Wrong character in parameter template: ' + pos.skipcurrent())
-    return None
-
-  def read(self, pos, function):
-    "Read the parameter itself using the definition."
-    if self.literal:
-      if self.optional:
-        self.literalvalue = function.parsesquareliteral(pos)
-      else:
-        self.literalvalue = function.parseliteral(pos)
-      if self.literalvalue:
-        self.value = FormulaConstant(self.literalvalue)
-    elif self.optional:
-      self.value = function.parsesquare(pos)
-    else:
-      self.value = function.parseparameter(pos)
-
-  def __unicode__(self):
-    "Return a printable representation."
-    result = 'param ' + self.name
-    if self.value:
-      result += ': ' + unicode(self.value)
-    else:
-      result += ' (empty)'
-    return result
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-class ParameterFunction(CommandBit):
-  "A function with a variable number of parameters defined in a template."
-  "The parameters are defined as a parameter definition."
-
-  def readparams(self, readtemplate, pos):
-    "Read the params according to the template."
-    self.params = dict()
-    for paramdef in self.paramdefs(readtemplate):
-      paramdef.read(pos, self)
-      self.params['$' + paramdef.name] = paramdef
-
-  def paramdefs(self, readtemplate):
-    "Read each param definition in the template"
-    pos = TextPosition(readtemplate)
-    while not pos.finished():
-      paramdef = ParameterDefinition().parse(pos)
-      if paramdef:
-        yield paramdef
-
-  def getparam(self, name):
-    "Get a parameter as parsed."
-    if not name in self.params:
-      return None
-    return self.params[name]
-
-  def getvalue(self, name):
-    "Get the value of a parameter."
-    return self.getparam(name).value
-
-  def getliteralvalue(self, name):
-    "Get the literal value of a parameter."
-    param = self.getparam(name)
-    if not param or not param.literalvalue:
-      return None
-    return param.literalvalue
-
-class HybridFunction(ParameterFunction):
-  """
-  A parameter function where the output is also defined using a template.
-  The template can use a number of functions; each function has an associated
-  tag.
-  Example: [f0{$1},span class="fbox"] defines a function f0 which corresponds
-  to a span of class fbox, yielding <span class="fbox">$1</span>.
-  Literal parameters can be used in tags definitions:
-    [f0{$1},span style="color: $p;"]
-  yields <span style="color: $p;">$1</span>, where $p is a literal parameter.
-  Sizes can be specified in hybridsizes, e.g. adding parameter sizes. By
-  default the resulting size is the max of all arguments. Sizes are used
-  to generate the right parameters.
-  A function followed by a single / is output as a self-closing XHTML tag:
-    [f0/,hr]
-  will generate <hr/>.
-  """
-
-  commandmap = FormulaConfig.hybridfunctions
-
-  def parsebit(self, pos):
-    "Parse a function with [] and {} parameters"
-    readtemplate = self.translated[0]
-    writetemplate = self.translated[1]
-    self.readparams(readtemplate, pos)
-    self.contents = self.writeparams(writetemplate)
-    self.computehybridsize()
-
-  def writeparams(self, writetemplate):
-    "Write all params according to the template"
-    return self.writepos(TextPosition(writetemplate))
-
-  def writepos(self, pos):
-    "Write all params as read in the parse position."
-    result = []
-    while not pos.finished():
-      if pos.checkskip('$'):
-        param = self.writeparam(pos)
-        if param:
-          result.append(param)
-      elif pos.checkskip('f'):
-        function = self.writefunction(pos)
-        if function:
-          function.type = None
-          result.append(function)
-      elif pos.checkskip('('):
-        result.append(self.writebracket('left', '('))
-      elif pos.checkskip(')'):
-        result.append(self.writebracket('right', ')'))
-      else:
-        result.append(FormulaConstant(pos.skipcurrent()))
-    return result
-
-  def writeparam(self, pos):
-    "Write a single param of the form $0, $x..."
-    name = '$' + pos.skipcurrent()
-    if not name in self.params:
-      Trace.error('Unknown parameter ' + name)
-      return None
-    if not self.params[name]:
-      return None
-    if pos.checkskip('.'):
-      self.params[name].value.type = pos.globalpha()
-    return self.params[name].value
-
-  def writefunction(self, pos):
-    "Write a single function f0,...,fn."
-    tag = self.readtag(pos)
-    if not tag:
-      return None
-    if pos.checkskip('/'):
-      # self-closing XHTML tag, such as <hr/>
-      return TaggedBit().selfcomplete(tag)
-    if not pos.checkskip('{'):
-      Trace.error('Function should be defined in {}')
-      return None
-    pos.pushending('}')
-    contents = self.writepos(pos)
-    pos.popending()
-    if len(contents) == 0:
-      return None
-    return TaggedBit().complete(contents, tag)
-
-  def readtag(self, pos):
-    "Get the tag corresponding to the given index. Does parameter substitution."
-    if not pos.current().isdigit():
-      Trace.error('Function should be f0,...,f9: f' + pos.current())
-      return None
-    index = int(pos.skipcurrent())
-    if 2 + index > len(self.translated):
-      Trace.error('Function f' + unicode(index) + ' is not defined')
-      return None
-    tag = self.translated[2 + index]
-    if not '$' in tag:
-      return tag
-    for variable in self.params:
-      if variable in tag:
-        param = self.params[variable]
-        if not param.literal:
-          Trace.error('Parameters in tag ' + tag + ' should be literal: {' + variable + '!}')
-          continue
-        if param.literalvalue:
-          value = param.literalvalue
-        else:
-          value = ''
-        tag = tag.replace(variable, value)
-    return tag
-
-  def writebracket(self, direction, character):
-    "Return a new bracket looking at the given direction."
-    return self.factory.create(BracketCommand).create(direction, character)
-
-  def computehybridsize(self):
-    "Compute the size of the hybrid function."
-    if not self.command in HybridSize.configsizes:
-      self.computesize()
-      return
-    self.size = HybridSize().getsize(self)
-    # set the size in all elements at first level
-    for element in self.contents:
-      element.size = self.size
-
-class HybridSize(object):
-  "The size associated with a hybrid function."
-
-  configsizes = FormulaConfig.hybridsizes
-
-  def getsize(self, function):
-    "Read the size for a function and parse it."
-    sizestring = self.configsizes[function.command]
-    for name in function.params:
-      if name in sizestring:
-        size = function.params[name].value.computesize()
-        sizestring = sizestring.replace(name, unicode(size))
-    if '$' in sizestring:
-      Trace.error('Unconverted variable in hybrid size: ' + sizestring)
-      return 1
-    return eval(sizestring)
-
-
-FormulaCommand.types += [HybridFunction]
-
-
-
-
-
-
-
-
-
-class HeaderParser(Parser):
-  "Parses the LyX header"
-
-  def parse(self, reader):
-    "Parse header parameters into a dictionary, return the preamble."
-    contents = []
-    self.parseending(reader, lambda: self.parseline(reader, contents))
-    # skip last line
-    reader.nextline()
-    return contents
-
-  def parseline(self, reader, contents):
-    "Parse a single line as a parameter or as a start"
-    line = reader.currentline()
-    if line.startswith(HeaderConfig.parameters['branch']):
-      self.parsebranch(reader)
-      return
-    elif line.startswith(HeaderConfig.parameters['lstset']):
-      LstParser().parselstset(reader)
-      return
-    elif line.startswith(HeaderConfig.parameters['beginpreamble']):
-      contents.append(self.factory.createcontainer(reader))
-      return
-    # no match
-    self.parseparameter(reader)
-
-  def parsebranch(self, reader):
-    "Parse all branch definitions."
-    branch = reader.currentline().split()[1]
-    reader.nextline()
-    subparser = HeaderParser().complete(HeaderConfig.parameters['endbranch'])
-    subparser.parse(reader)
-    options = BranchOptions(branch)
-    for key in subparser.parameters:
-      options.set(key, subparser.parameters[key])
-    Options.branches[branch] = options
-
-  def complete(self, ending):
-    "Complete the parser with the given ending."
-    self.ending = ending
-    return self
-
-class PreambleParser(Parser):
-  "A parser for the LyX preamble."
-
-  preamble = []
-
-  def parse(self, reader):
-    "Parse the full preamble with all statements."
-    self.ending = HeaderConfig.parameters['endpreamble']
-    self.parseending(reader, lambda: self.parsepreambleline(reader))
-    return []
-
-  def parsepreambleline(self, reader):
-    "Parse a single preamble line."
-    PreambleParser.preamble.append(reader.currentline())
-    reader.nextline()
-
-class LstParser(object):
-  "Parse global and local lstparams."
-
-  globalparams = dict()
-
-  def parselstset(self, reader):
-    "Parse a declaration of lstparams in lstset."
-    paramtext = self.extractlstset(reader)
-    if not '{' in paramtext:
-      Trace.error('Missing opening bracket in lstset: ' + paramtext)
-      return
-    lefttext = paramtext.split('{')[1]
-    croppedtext = lefttext[:-1]
-    LstParser.globalparams = self.parselstparams(croppedtext)
-
-  def extractlstset(self, reader):
-    "Extract the global lstset parameters."
-    paramtext = ''
-    while not reader.finished():
-      paramtext += reader.currentline()
-      reader.nextline()
-      if paramtext.endswith('}'):
-        return paramtext
-    Trace.error('Could not find end of \\lstset settings; aborting')
-
-  def parsecontainer(self, container):
-    "Parse some lstparams from elyxer.a container."
-    container.lstparams = LstParser.globalparams.copy()
-    paramlist = container.getparameterlist('lstparams')
-    container.lstparams.update(self.parselstparams(paramlist))
-
-  def parselstparams(self, paramlist):
-    "Process a number of lstparams from elyxer.a list."
-    paramdict = dict()
-    for param in paramlist:
-      if not '=' in param:
-        if len(param.strip()) > 0:
-          Trace.error('Invalid listing parameter ' + param)
-      else:
-        key, value = param.split('=', 1)
-        paramdict[key] = value
-    return paramdict
-
-
-
-
-class MacroDefinition(CommandBit):
-  "A function that defines a new command (a macro)."
-
-  macros = dict()
-
-  def parsebit(self, pos):
-    "Parse the function that defines the macro."
-    self.output = EmptyOutput()
-    self.parameternumber = 0
-    self.defaults = []
-    self.factory.defining = True
-    self.parseparameters(pos)
-    self.factory.defining = False
-    Trace.debug('New command ' + self.newcommand + ' (' + \
-        unicode(self.parameternumber) + ' parameters)')
-    self.macros[self.newcommand] = self
-
-  def parseparameters(self, pos):
-    "Parse all optional parameters (number of parameters, default values)"
-    "and the mandatory definition."
-    self.newcommand = self.parsenewcommand(pos)
-    # parse number of parameters
-    literal = self.parsesquareliteral(pos)
-    if literal:
-      self.parameternumber = int(literal)
-    # parse all default values
-    bracket = self.parsesquare(pos)
-    while bracket:
-      self.defaults.append(bracket)
-      bracket = self.parsesquare(pos)
-    # parse mandatory definition
-    self.definition = self.parseparameter(pos)
-
-  def parsenewcommand(self, pos):
-    "Parse the name of the new command."
-    self.factory.clearskipped(pos)
-    if self.factory.detecttype(Bracket, pos):
-      return self.parseliteral(pos)
-    if self.factory.detecttype(FormulaCommand, pos):
-      return self.factory.create(FormulaCommand).extractcommand(pos)
-    Trace.error('Unknown formula bit in defining function at ' + pos.identifier())
-    return 'unknown'
-
-  def instantiate(self):
-    "Return an instance of the macro."
-    return self.definition.clone()
-
-class MacroParameter(FormulaBit):
-  "A parameter from elyxer.a macro."
-
-  def detect(self, pos):
-    "Find a macro parameter: #n."
-    return pos.checkfor('#')
-
-  def parsebit(self, pos):
-    "Parse the parameter: #n."
-    if not pos.checkskip('#'):
-      Trace.error('Missing parameter start #.')
-      return
-    self.number = int(pos.skipcurrent())
-    self.original = '#' + unicode(self.number)
-    self.contents = [TaggedBit().constant('#' + unicode(self.number), 'span class="unknown"')]
-
-class MacroFunction(CommandBit):
-  "A function that was defined using a macro."
-
-  commandmap = MacroDefinition.macros
-
-  def parsebit(self, pos):
-    "Parse a number of input parameters."
-    self.output = FilteredOutput()
-    self.values = []
-    macro = self.translated
-    self.parseparameters(pos, macro)
-    self.completemacro(macro)
-
-  def parseparameters(self, pos, macro):
-    "Parse as many parameters as are needed."
-    self.parseoptional(pos, list(macro.defaults))
-    self.parsemandatory(pos, macro.parameternumber - len(macro.defaults))
-    if len(self.values) < macro.parameternumber:
-      Trace.error('Missing parameters in macro ' + unicode(self))
-
-  def parseoptional(self, pos, defaults):
-    "Parse optional parameters."
-    optional = []
-    while self.factory.detecttype(SquareBracket, pos):
-      optional.append(self.parsesquare(pos))
-      if len(optional) > len(defaults):
-        break
-    for value in optional:
-      default = defaults.pop()
-      if len(value.contents) > 0:
-        self.values.append(value)
-      else:
-        self.values.append(default)
-    self.values += defaults
-
-  def parsemandatory(self, pos, number):
-    "Parse a number of mandatory parameters."
-    for index in range(number):
-      parameter = self.parsemacroparameter(pos, number - index)
-      if not parameter:
-        return
-      self.values.append(parameter)
-
-  def parsemacroparameter(self, pos, remaining):
-    "Parse a macro parameter. Could be a bracket or a single letter."
-    "If there are just two values remaining and there is a running number,"
-    "parse as two separater numbers."
-    self.factory.clearskipped(pos)
-    if pos.finished():
-      return None
-    if self.factory.detecttype(FormulaNumber, pos):
-      return self.parsenumbers(pos, remaining)
-    return self.parseparameter(pos)
-
-  def parsenumbers(self, pos, remaining):
-    "Parse the remaining parameters as a running number."
-    "For example, 12 would be {1}{2}."
-    number = self.factory.parsetype(FormulaNumber, pos)
-    if not len(number.original) == remaining:
-      return number
-    for digit in number.original:
-      value = self.factory.create(FormulaNumber)
-      value.add(FormulaConstant(digit))
-      value.type = number
-      self.values.append(value)
-    return None
-
-  def completemacro(self, macro):
-    "Complete the macro with the parameters read."
-    self.contents = [macro.instantiate()]
-    replaced = [False] * len(self.values)
-    for parameter in self.searchall(MacroParameter):
-      index = parameter.number - 1
-      if index >= len(self.values):
-        Trace.error('Macro parameter index out of bounds: ' + unicode(index))
-        return
-      replaced[index] = True
-      parameter.contents = [self.values[index].clone()]
-    for index in range(len(self.values)):
-      if not replaced[index]:
-        self.addfilter(index, self.values[index])
-
-  def addfilter(self, index, value):
-    "Add a filter for the given parameter number and parameter value."
-    original = '#' + unicode(index + 1)
-    value = ''.join(self.values[0].gethtml())
-    self.output.addfilter(original, value)
-
-class FormulaMacro(Formula):
-  "A math macro defined in an inset."
-
-  def __init__(self):
-    self.parser = MacroParser()
-    self.output = EmptyOutput()
-
-  def __unicode__(self):
-    "Return a printable representation."
-    return 'Math macro'
-
-  if sys.version_info >= (3, 0):
-    __str__ = __unicode__
-
-
-FormulaFactory.types += [ MacroParameter ]
-
-FormulaCommand.types += [
-    MacroFunction,
-    ]
-
-
-
-def math2html(formula):
-  "Convert some TeX math to HTML."
-  factory = FormulaFactory()
-  whole = factory.parseformula(formula)
-  FormulaProcessor().process(whole)
-  whole.process()
-  return ''.join(whole.gethtml())
-
-def main():
-  "Main function, called if invoked from elyxer.the command line"
-  args = sys.argv
-  Options().parseoptions(args)
-  if len(args) != 1:
-    Trace.error('Usage: math2html.py escaped_string')
-    exit()
-  result = math2html(args[0])
-  Trace.message(result)
-
-if __name__ == '__main__':
-  main()
-