summaryrefslogtreecommitdiff
path: root/docutils/writers
diff options
context:
space:
mode:
authorwiemann <wiemann@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2006-01-09 20:44:25 +0000
committerwiemann <wiemann@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2006-01-09 20:44:25 +0000
commitd77fdfef70e08114f57cbef5d91707df8717ea9f (patch)
tree49444e3486c0c333cb7b33dfa721296c08ee4ece /docutils/writers
parent53cd16ca6ca5f638cbe5956988e88f9339e355cf (diff)
parent3993c4097756e9885bcfbd07cb1cc1e4e95e50e4 (diff)
downloaddocutils-0.4.tar.gz
Release 0.4: tagging released revisiondocutils-0.4
git-svn-id: http://svn.code.sf.net/p/docutils/code/tags/docutils-0.4@4268 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
Diffstat (limited to 'docutils/writers')
-rw-r--r--docutils/writers/__init__.py133
-rw-r--r--docutils/writers/docutils_xml.py75
-rw-r--r--docutils/writers/html4css1/__init__.py1601
-rw-r--r--docutils/writers/html4css1/html4css1.css279
-rw-r--r--docutils/writers/latex2e/__init__.py2048
-rw-r--r--docutils/writers/latex2e/latex2e.tex74
-rw-r--r--docutils/writers/newlatex2e/__init__.py788
-rw-r--r--docutils/writers/newlatex2e/base.tex1108
-rw-r--r--docutils/writers/newlatex2e/unicode_map.py2371
-rw-r--r--docutils/writers/null.py23
-rw-r--r--docutils/writers/pep_html/__init__.py108
-rw-r--r--docutils/writers/pep_html/pep.css348
-rw-r--r--docutils/writers/pep_html/template.txt28
-rw-r--r--docutils/writers/pseudoxml.py33
-rw-r--r--docutils/writers/s5_html/__init__.py326
-rw-r--r--docutils/writers/s5_html/themes/README.txt6
-rw-r--r--docutils/writers/s5_html/themes/big-black/__base__2
-rw-r--r--docutils/writers/s5_html/themes/big-black/framing.css25
-rw-r--r--docutils/writers/s5_html/themes/big-black/pretty.css109
-rw-r--r--docutils/writers/s5_html/themes/big-white/framing.css24
-rw-r--r--docutils/writers/s5_html/themes/big-white/pretty.css107
-rw-r--r--docutils/writers/s5_html/themes/default/blank.gifbin0 -> 49 bytes
-rw-r--r--docutils/writers/s5_html/themes/default/framing.css25
-rw-r--r--docutils/writers/s5_html/themes/default/iepngfix.htc42
-rw-r--r--docutils/writers/s5_html/themes/default/opera.css8
-rw-r--r--docutils/writers/s5_html/themes/default/outline.css16
-rw-r--r--docutils/writers/s5_html/themes/default/pretty.css120
-rw-r--r--docutils/writers/s5_html/themes/default/print.css24
-rw-r--r--docutils/writers/s5_html/themes/default/s5-core.css11
-rw-r--r--docutils/writers/s5_html/themes/default/slides.css10
-rw-r--r--docutils/writers/s5_html/themes/default/slides.js558
-rw-r--r--docutils/writers/s5_html/themes/medium-black/__base__2
-rw-r--r--docutils/writers/s5_html/themes/medium-black/pretty.css115
-rw-r--r--docutils/writers/s5_html/themes/medium-white/framing.css24
-rw-r--r--docutils/writers/s5_html/themes/medium-white/pretty.css113
-rw-r--r--docutils/writers/s5_html/themes/small-black/__base__2
-rw-r--r--docutils/writers/s5_html/themes/small-black/pretty.css116
-rw-r--r--docutils/writers/s5_html/themes/small-white/framing.css24
-rw-r--r--docutils/writers/s5_html/themes/small-white/pretty.css114
39 files changed, 10940 insertions, 0 deletions
diff --git a/docutils/writers/__init__.py b/docutils/writers/__init__.py
new file mode 100644
index 000000000..5482cad42
--- /dev/null
+++ b/docutils/writers/__init__.py
@@ -0,0 +1,133 @@
+# Authors: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+This package contains Docutils Writer modules.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+import os.path
+import docutils
+from docutils import languages, Component
+from docutils.transforms import universal
+
+
+class Writer(Component):
+
+ """
+ Abstract base class for docutils Writers.
+
+ Each writer module or package must export a subclass also called 'Writer'.
+ Each writer must support all standard node types listed in
+ `docutils.nodes.node_class_names`.
+
+ The `write()` method is the main entry point.
+ """
+
+ component_type = 'writer'
+ config_section = 'writers'
+
+ def get_transforms(self):
+ return Component.get_transforms(self) + [
+ universal.Messages,
+ universal.FilterMessages,
+ ]
+
+ document = None
+ """The document to write (Docutils doctree); set by `write`."""
+
+ output = None
+ """Final translated form of `document` (Unicode string for text, binary
+ string for other forms); set by `translate`."""
+
+ language = None
+ """Language module for the document; set by `write`."""
+
+ destination = None
+ """`docutils.io` Output object; where to write the document.
+ Set by `write`."""
+
+ def __init__(self):
+
+ # Currently only used by HTML writer for output fragments:
+ self.parts = {}
+ """Mapping of document part names to fragments of `self.output`.
+ Values are Unicode strings; encoding is up to the client. The 'whole'
+ key should contain the entire document output.
+ """
+
+ def write(self, document, destination):
+ """
+ Process a document into its final form.
+
+ Translate `document` (a Docutils document tree) into the Writer's
+ native format, and write it out to its `destination` (a
+ `docutils.io.Output` subclass object).
+
+ Normally not overridden or extended in subclasses.
+ """
+ self.document = document
+ self.language = languages.get_language(
+ document.settings.language_code)
+ self.destination = destination
+ self.translate()
+ output = self.destination.write(self.output)
+ return output
+
+ def translate(self):
+ """
+ Do final translation of `self.document` into `self.output`. Called
+ from `write`. Override in subclasses.
+
+ Usually done with a `docutils.nodes.NodeVisitor` subclass, in
+ combination with a call to `docutils.nodes.Node.walk()` or
+ `docutils.nodes.Node.walkabout()`. The ``NodeVisitor`` subclass must
+ support all standard elements (listed in
+ `docutils.nodes.node_class_names`) and possibly non-standard elements
+ used by the current Reader as well.
+ """
+ raise NotImplementedError('subclass must override this method')
+
+ def assemble_parts(self):
+ """Assemble the `self.parts` dictionary. Extend in subclasses."""
+ self.parts['whole'] = self.output
+
+
+class UnfilteredWriter(Writer):
+
+ """
+ A writer that passes the document tree on unchanged (e.g. a
+ serializer.)
+
+ Documents written by UnfilteredWriters are typically reused at a
+ later date using a subclass of `readers.ReReader`.
+ """
+
+ def get_transforms(self):
+ # Do not add any transforms. When the document is reused
+ # later, the then-used writer will add the appropriate
+ # transforms.
+ return Component.get_transforms(self)
+
+
+_writer_aliases = {
+ 'html': 'html4css1',
+ 'latex': 'latex2e',
+ 'pprint': 'pseudoxml',
+ 'pformat': 'pseudoxml',
+ 'pdf': 'rlpdf',
+ 'xml': 'docutils_xml',
+ 's5': 's5_html'}
+
+def get_writer_class(writer_name):
+ """Return the Writer class from the `writer_name` module."""
+ writer_name = writer_name.lower()
+ if _writer_aliases.has_key(writer_name):
+ writer_name = _writer_aliases[writer_name]
+ module = __import__(writer_name, globals(), locals())
+ return module.Writer
diff --git a/docutils/writers/docutils_xml.py b/docutils/writers/docutils_xml.py
new file mode 100644
index 000000000..2362e6b78
--- /dev/null
+++ b/docutils/writers/docutils_xml.py
@@ -0,0 +1,75 @@
+# Authors: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Simple internal document tree Writer, writes Docutils XML.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+import docutils
+from docutils import frontend, writers
+
+
+class Writer(writers.Writer):
+
+ supported = ('xml',)
+ """Formats this writer supports."""
+
+ settings_spec = (
+ '"Docutils XML" Writer Options',
+ 'Warning: the --newlines and --indents options may adversely affect '
+ 'whitespace; use them only for reading convenience.',
+ (('Generate XML with newlines before and after tags.',
+ ['--newlines'],
+ {'action': 'store_true', 'validator': frontend.validate_boolean}),
+ ('Generate XML with indents and newlines.',
+ ['--indents'],
+ {'action': 'store_true', 'validator': frontend.validate_boolean}),
+ ('Omit the XML declaration. Use with caution.',
+ ['--no-xml-declaration'],
+ {'dest': 'xml_declaration', 'default': 1, 'action': 'store_false',
+ 'validator': frontend.validate_boolean}),
+ ('Omit the DOCTYPE declaration.',
+ ['--no-doctype'],
+ {'dest': 'doctype_declaration', 'default': 1,
+ 'action': 'store_false', 'validator': frontend.validate_boolean}),))
+
+ settings_defaults = {'output_encoding_error_handler': 'xmlcharrefreplace'}
+
+ config_section = 'docutils_xml writer'
+ config_section_dependencies = ('writers',)
+
+ output = None
+ """Final translated form of `document`."""
+
+ xml_declaration = '<?xml version="1.0" encoding="%s"?>\n'
+ #xml_stylesheet = '<?xml-stylesheet type="text/xsl" href="%s"?>\n'
+ doctype = (
+ '<!DOCTYPE document PUBLIC'
+ ' "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML"'
+ ' "http://docutils.sourceforge.net/docs/ref/docutils.dtd">\n')
+ generator = '<!-- Generated by Docutils %s -->\n'
+
+ def translate(self):
+ settings = self.document.settings
+ indent = newline = ''
+ if settings.newlines:
+ newline = '\n'
+ if settings.indents:
+ newline = '\n'
+ indent = ' '
+ output_prefix = []
+ if settings.xml_declaration:
+ output_prefix.append(
+ self.xml_declaration % settings.output_encoding)
+ if settings.doctype_declaration:
+ output_prefix.append(self.doctype)
+ output_prefix.append(self.generator % docutils.__version__)
+ docnode = self.document.asdom().childNodes[0]
+ self.output = (''.join(output_prefix)
+ + docnode.toprettyxml(indent, newline))
diff --git a/docutils/writers/html4css1/__init__.py b/docutils/writers/html4css1/__init__.py
new file mode 100644
index 000000000..02833d66a
--- /dev/null
+++ b/docutils/writers/html4css1/__init__.py
@@ -0,0 +1,1601 @@
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Simple HyperText Markup Language document tree Writer.
+
+The output conforms to the XHTML version 1.0 Transitional DTD
+(*almost* strict). The output contains a minimum of formatting
+information. The cascading style sheet "html4css1.css" is required
+for proper viewing with a modern graphical browser.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+import sys
+import os
+import os.path
+import time
+import re
+from types import ListType
+try:
+ import Image # check for the Python Imaging Library
+except ImportError:
+ Image = None
+import docutils
+from docutils import frontend, nodes, utils, writers, languages
+
+
+class Writer(writers.Writer):
+
+ supported = ('html', 'html4css1', 'xhtml')
+ """Formats this writer supports."""
+
+ default_stylesheet = 'html4css1.css'
+
+ default_stylesheet_path = utils.relative_path(
+ os.path.join(os.getcwd(), 'dummy'),
+ os.path.join(os.path.dirname(__file__), default_stylesheet))
+
+ settings_spec = (
+ 'HTML-Specific Options',
+ None,
+ (('Specify a stylesheet URL, used verbatim. Overrides '
+ '--stylesheet-path.',
+ ['--stylesheet'],
+ {'metavar': '<URL>', 'overrides': 'stylesheet_path'}),
+ ('Specify a stylesheet file, relative to the current working '
+ 'directory. The path is adjusted relative to the output HTML '
+ 'file. Overrides --stylesheet. Default: "%s"'
+ % default_stylesheet_path,
+ ['--stylesheet-path'],
+ {'metavar': '<file>', 'overrides': 'stylesheet',
+ 'default': default_stylesheet_path}),
+ ('Embed the stylesheet in the output HTML file. The stylesheet '
+ 'file must be accessible during processing (--stylesheet-path is '
+ 'recommended). This is the default.',
+ ['--embed-stylesheet'],
+ {'default': 1, 'action': 'store_true',
+ 'validator': frontend.validate_boolean}),
+ ('Link to the stylesheet in the output HTML file. Default: '
+ 'embed the stylesheet, do not link to it.',
+ ['--link-stylesheet'],
+ {'dest': 'embed_stylesheet', 'action': 'store_false',
+ 'validator': frontend.validate_boolean}),
+ ('Specify the initial header level. Default is 1 for "<h1>". '
+ 'Does not affect document title & subtitle (see --no-doc-title).',
+ ['--initial-header-level'],
+ {'choices': '1 2 3 4 5 6'.split(), 'default': '1',
+ 'metavar': '<level>'}),
+ ('Specify the maximum width (in characters) for one-column field '
+ 'names. Longer field names will span an entire row of the table '
+ 'used to render the field list. Default is 14 characters. '
+ 'Use 0 for "no limit".',
+ ['--field-name-limit'],
+ {'default': 14, 'metavar': '<level>',
+ 'validator': frontend.validate_nonnegative_int}),
+ ('Specify the maximum width (in characters) for options in option '
+ 'lists. Longer options will span an entire row of the table used '
+ 'to render the option list. Default is 14 characters. '
+ 'Use 0 for "no limit".',
+ ['--option-limit'],
+ {'default': 14, 'metavar': '<level>',
+ 'validator': frontend.validate_nonnegative_int}),
+ ('Format for footnote references: one of "superscript" or '
+ '"brackets". Default is "brackets".',
+ ['--footnote-references'],
+ {'choices': ['superscript', 'brackets'], 'default': 'brackets',
+ 'metavar': '<format>',
+ 'overrides': 'trim_footnote_reference_space'}),
+ ('Format for block quote attributions: one of "dash" (em-dash '
+ 'prefix), "parentheses"/"parens", or "none". Default is "dash".',
+ ['--attribution'],
+ {'choices': ['dash', 'parentheses', 'parens', 'none'],
+ 'default': 'dash', 'metavar': '<format>'}),
+ ('Remove extra vertical whitespace between items of "simple" bullet '
+ 'lists and enumerated lists. Default: enabled.',
+ ['--compact-lists'],
+ {'default': 1, 'action': 'store_true',
+ 'validator': frontend.validate_boolean}),
+ ('Disable compact simple bullet and enumerated lists.',
+ ['--no-compact-lists'],
+ {'dest': 'compact_lists', 'action': 'store_false'}),
+ ('Remove extra vertical whitespace between items of simple field '
+ 'lists. Default: enabled.',
+ ['--compact-field-lists'],
+ {'default': 1, 'action': 'store_true',
+ 'validator': frontend.validate_boolean}),
+ ('Disable compact simple field lists.',
+ ['--no-compact-field-lists'],
+ {'dest': 'compact_field_lists', 'action': 'store_false'}),
+ ('Omit the XML declaration. Use with caution.',
+ ['--no-xml-declaration'],
+ {'dest': 'xml_declaration', 'default': 1, 'action': 'store_false',
+ 'validator': frontend.validate_boolean}),
+ ('Obfuscate email addresses to confuse harvesters while still '
+ 'keeping email links usable with standards-compliant browsers.',
+ ['--cloak-email-addresses'],
+ {'action': 'store_true', 'validator': frontend.validate_boolean}),))
+
+ settings_defaults = {'output_encoding_error_handler': 'xmlcharrefreplace'}
+
+ relative_path_settings = ('stylesheet_path',)
+
+ config_section = 'html4css1 writer'
+ config_section_dependencies = ('writers',)
+
+ def __init__(self):
+ writers.Writer.__init__(self)
+ self.translator_class = HTMLTranslator
+
+ def translate(self):
+ self.visitor = visitor = self.translator_class(self.document)
+ self.document.walkabout(visitor)
+ self.output = visitor.astext()
+ for attr in ('head_prefix', 'stylesheet', 'head', 'body_prefix',
+ 'body_pre_docinfo', 'docinfo', 'body', 'fragment',
+ 'body_suffix'):
+ setattr(self, attr, getattr(visitor, attr))
+
+ def assemble_parts(self):
+ writers.Writer.assemble_parts(self)
+ for part in ('title', 'subtitle', 'docinfo', 'body', 'header',
+ 'footer', 'meta', 'stylesheet', 'fragment',
+ 'html_prolog', 'html_head', 'html_title', 'html_subtitle',
+ 'html_body'):
+ self.parts[part] = ''.join(getattr(self.visitor, part))
+
+
+class HTMLTranslator(nodes.NodeVisitor):
+
+ """
+ This HTML writer has been optimized to produce visually compact
+ lists (less vertical whitespace). HTML's mixed content models
+ allow list items to contain "<li><p>body elements</p></li>" or
+ "<li>just text</li>" or even "<li>text<p>and body
+ elements</p>combined</li>", each with different effects. It would
+ be best to stick with strict body elements in list items, but they
+ affect vertical spacing in browsers (although they really
+ shouldn't).
+
+ Here is an outline of the optimization:
+
+ - Check for and omit <p> tags in "simple" lists: list items
+ contain either a single paragraph, a nested simple list, or a
+ paragraph followed by a nested simple list. This means that
+ this list can be compact:
+
+ - Item 1.
+ - Item 2.
+
+ But this list cannot be compact:
+
+ - Item 1.
+
+ This second paragraph forces space between list items.
+
+ - Item 2.
+
+ - In non-list contexts, omit <p> tags on a paragraph if that
+ paragraph is the only child of its parent (footnotes & citations
+ are allowed a label first).
+
+ - Regardless of the above, in definitions, table cells, field bodies,
+ option descriptions, and list items, mark the first child with
+ 'class="first"' and the last child with 'class="last"'. The stylesheet
+ sets the margins (top & bottom respectively) to 0 for these elements.
+
+ The ``no_compact_lists`` setting (``--no-compact-lists`` command-line
+ option) disables list whitespace optimization.
+ """
+
+ xml_declaration = '<?xml version="1.0" encoding="%s" ?>\n'
+ doctype = ('<!DOCTYPE html'
+ ' PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
+ ' "http://www.w3.org/TR/xhtml1/DTD/'
+ 'xhtml1-transitional.dtd">\n')
+ head_prefix_template = ('<html xmlns="http://www.w3.org/1999/xhtml"'
+ ' xml:lang="%s" lang="%s">\n<head>\n')
+ content_type = ('<meta http-equiv="Content-Type"'
+ ' content="text/html; charset=%s" />\n')
+ generator = ('<meta name="generator" content="Docutils %s: '
+ 'http://docutils.sourceforge.net/" />\n')
+ stylesheet_link = '<link rel="stylesheet" href="%s" type="text/css" />\n'
+ embedded_stylesheet = '<style type="text/css">\n\n%s\n</style>\n'
+ named_tags = ['a', 'applet', 'form', 'frame', 'iframe', 'img', 'map']
+ words_and_spaces = re.compile(r'\S+| +|\n')
+
+ def __init__(self, document):
+ nodes.NodeVisitor.__init__(self, document)
+ self.settings = settings = document.settings
+ lcode = settings.language_code
+ self.language = languages.get_language(lcode)
+ self.meta = [self.content_type % settings.output_encoding,
+ self.generator % docutils.__version__]
+ self.head_prefix = []
+ self.html_prolog = []
+ if settings.xml_declaration:
+ self.head_prefix.append(self.xml_declaration
+ % settings.output_encoding)
+ # encoding not interpolated:
+ self.html_prolog.append(self.xml_declaration)
+ self.head_prefix.extend([self.doctype,
+ self.head_prefix_template % (lcode, lcode)])
+ self.html_prolog.append(self.doctype)
+ self.head = self.meta[:]
+ stylesheet = utils.get_stylesheet_reference(settings)
+ self.stylesheet = []
+ if stylesheet:
+ if settings.embed_stylesheet:
+ stylesheet = utils.get_stylesheet_reference(
+ settings, os.path.join(os.getcwd(), 'dummy'))
+ settings.record_dependencies.add(stylesheet)
+ stylesheet_text = open(stylesheet).read()
+ self.stylesheet = [self.embedded_stylesheet % stylesheet_text]
+ else:
+ self.stylesheet = [self.stylesheet_link
+ % self.encode(stylesheet)]
+ self.body_prefix = ['</head>\n<body>\n']
+ # document title, subtitle display
+ self.body_pre_docinfo = []
+ # author, date, etc.
+ self.docinfo = []
+ self.body = []
+ self.fragment = []
+ self.body_suffix = ['</body>\n</html>\n']
+ self.section_level = 0
+ self.initial_header_level = int(settings.initial_header_level)
+ # A heterogenous stack used in conjunction with the tree traversal.
+ # Make sure that the pops correspond to the pushes:
+ self.context = []
+ self.topic_classes = []
+ self.colspecs = []
+ self.compact_p = 1
+ self.compact_simple = None
+ self.compact_field_list = None
+ self.in_docinfo = None
+ self.in_sidebar = None
+ self.title = []
+ self.subtitle = []
+ self.header = []
+ self.footer = []
+ self.html_head = [self.content_type] # charset not interpolated
+ self.html_title = []
+ self.html_subtitle = []
+ self.html_body = []
+ self.in_document_title = 0
+ self.in_mailto = 0
+ self.author_in_authors = None
+
+ def astext(self):
+ return ''.join(self.head_prefix + self.head
+ + self.stylesheet + self.body_prefix
+ + self.body_pre_docinfo + self.docinfo
+ + self.body + self.body_suffix)
+
+ def encode(self, text):
+ """Encode special characters in `text` & return."""
+ # @@@ A codec to do these and all other HTML entities would be nice.
+ text = text.replace("&", "&amp;")
+ text = text.replace("<", "&lt;")
+ text = text.replace('"', "&quot;")
+ text = text.replace(">", "&gt;")
+ text = text.replace("@", "&#64;") # may thwart some address harvesters
+ # Replace the non-breaking space character with the HTML entity:
+ text = text.replace(u'\u00a0', "&nbsp;")
+ return text
+
+ def cloak_mailto(self, uri):
+ """Try to hide a mailto: URL from harvesters."""
+ # Encode "@" using a URL octet reference (see RFC 1738).
+ # Further cloaking with HTML entities will be done in the
+ # `attval` function.
+ return uri.replace('@', '%40')
+
+ def cloak_email(self, addr):
+ """Try to hide the link text of a email link from harversters."""
+ # Surround at-signs and periods with <span> tags. ("@" has
+ # already been encoded to "&#64;" by the `encode` method.)
+ addr = addr.replace('&#64;', '<span>&#64;</span>')
+ addr = addr.replace('.', '<span>&#46;</span>')
+ return addr
+
+ def attval(self, text,
+ whitespace=re.compile('[\n\r\t\v\f]')):
+ """Cleanse, HTML encode, and return attribute value text."""
+ encoded = self.encode(whitespace.sub(' ', text))
+ if self.in_mailto and self.settings.cloak_email_addresses:
+ # Cloak at-signs ("%40") and periods with HTML entities.
+ encoded = encoded.replace('%40', '&#37;&#52;&#48;')
+ encoded = encoded.replace('.', '&#46;')
+ return encoded
+
+ def starttag(self, node, tagname, suffix='\n', empty=0, **attributes):
+ """
+ Construct and return a start tag given a node (id & class attributes
+ are extracted), tag name, and optional attributes.
+ """
+ tagname = tagname.lower()
+ prefix = []
+ atts = {}
+ ids = []
+ for (name, value) in attributes.items():
+ atts[name.lower()] = value
+ classes = node.get('classes', [])
+ if atts.has_key('class'):
+ classes.append(atts['class'])
+ if classes:
+ atts['class'] = ' '.join(classes)
+ assert not atts.has_key('id')
+ ids.extend(node.get('ids', []))
+ if atts.has_key('ids'):
+ ids.extend(atts['ids'])
+ del atts['ids']
+ if ids:
+ atts['id'] = ids[0]
+ for id in ids[1:]:
+ # Add empty "span" elements for additional IDs. Note
+ # that we cannot use empty "a" elements because there
+ # may be targets inside of references, but nested "a"
+ # elements aren't allowed in XHTML (even if they do
+ # not all have a "href" attribute).
+ if empty:
+ # Empty tag. Insert target right in front of element.
+ prefix.append('<span id="%s"></span>' % id)
+ else:
+ # Non-empty tag. Place the auxiliary <span> tag
+ # *inside* the element, as the first child.
+ suffix += '<span id="%s"></span>' % id
+ # !!! next 2 lines to be removed in Docutils 0.5:
+ if atts.has_key('id') and tagname in self.named_tags:
+ atts['name'] = atts['id'] # for compatibility with old browsers
+ attlist = atts.items()
+ attlist.sort()
+ parts = [tagname]
+ for name, value in attlist:
+ # value=None was used for boolean attributes without
+ # value, but this isn't supported by XHTML.
+ assert value is not None
+ if isinstance(value, ListType):
+ values = [unicode(v) for v in value]
+ parts.append('%s="%s"' % (name.lower(),
+ self.attval(' '.join(values))))
+ else:
+ try:
+ uval = unicode(value)
+ except TypeError: # for Python 2.1 compatibility:
+ uval = unicode(str(value))
+ parts.append('%s="%s"' % (name.lower(), self.attval(uval)))
+ if empty:
+ infix = ' /'
+ else:
+ infix = ''
+ return ''.join(prefix) + '<%s%s>' % (' '.join(parts), infix) + suffix
+
+ def emptytag(self, node, tagname, suffix='\n', **attributes):
+ """Construct and return an XML-compatible empty tag."""
+ return self.starttag(node, tagname, suffix, empty=1, **attributes)
+
+ # !!! to be removed in Docutils 0.5 (change calls to use "starttag"):
+ def start_tag_with_title(self, node, tagname, **atts):
+ """ID and NAME attributes will be handled in the title."""
+ node = {'classes': node.get('classes', [])}
+ return self.starttag(node, tagname, **atts)
+
+ def set_class_on_child(self, node, class_, index=0):
+ """
+ Set class `class_` on the visible child no. index of `node`.
+ Do nothing if node has fewer children than `index`.
+ """
+ children = [n for n in node if not isinstance(n, nodes.Invisible)]
+ try:
+ child = children[index]
+ except IndexError:
+ return
+ child['classes'].append(class_)
+
+ def set_first_last(self, node):
+ self.set_class_on_child(node, 'first', 0)
+ self.set_class_on_child(node, 'last', -1)
+
+ def visit_Text(self, node):
+ text = node.astext()
+ encoded = self.encode(text)
+ if self.in_mailto and self.settings.cloak_email_addresses:
+ encoded = self.cloak_email(encoded)
+ self.body.append(encoded)
+
+ def depart_Text(self, node):
+ pass
+
+ def visit_abbreviation(self, node):
+ # @@@ implementation incomplete ("title" attribute)
+ self.body.append(self.starttag(node, 'abbr', ''))
+
+ def depart_abbreviation(self, node):
+ self.body.append('</abbr>')
+
+ def visit_acronym(self, node):
+ # @@@ implementation incomplete ("title" attribute)
+ self.body.append(self.starttag(node, 'acronym', ''))
+
+ def depart_acronym(self, node):
+ self.body.append('</acronym>')
+
+ def visit_address(self, node):
+ self.visit_docinfo_item(node, 'address', meta=None)
+ self.body.append(self.starttag(node, 'pre', CLASS='address'))
+
+ def depart_address(self, node):
+ self.body.append('\n</pre>\n')
+ self.depart_docinfo_item()
+
+ def visit_admonition(self, node, name=''):
+ self.body.append(self.start_tag_with_title(
+ node, 'div', CLASS=(name or 'admonition')))
+ if name:
+ node.insert(0, nodes.title(name, self.language.labels[name]))
+ self.set_first_last(node)
+
+ def depart_admonition(self, node=None):
+ self.body.append('</div>\n')
+
+ def visit_attention(self, node):
+ self.visit_admonition(node, 'attention')
+
+ def depart_attention(self, node):
+ self.depart_admonition()
+
+ attribution_formats = {'dash': ('&mdash;', ''),
+ 'parentheses': ('(', ')'),
+ 'parens': ('(', ')'),
+ 'none': ('', '')}
+
+ def visit_attribution(self, node):
+ prefix, suffix = self.attribution_formats[self.settings.attribution]
+ self.context.append(suffix)
+ self.body.append(
+ self.starttag(node, 'p', prefix, CLASS='attribution'))
+
+ def depart_attribution(self, node):
+ self.body.append(self.context.pop() + '</p>\n')
+
+ def visit_author(self, node):
+ if isinstance(node.parent, nodes.authors):
+ if self.author_in_authors:
+ self.body.append('\n<br />')
+ else:
+ self.visit_docinfo_item(node, 'author')
+
+ def depart_author(self, node):
+ if isinstance(node.parent, nodes.authors):
+ self.author_in_authors += 1
+ else:
+ self.depart_docinfo_item()
+
+ def visit_authors(self, node):
+ self.visit_docinfo_item(node, 'authors')
+ self.author_in_authors = 0 # initialize counter
+
+ def depart_authors(self, node):
+ self.depart_docinfo_item()
+ self.author_in_authors = None
+
+ def visit_block_quote(self, node):
+ self.body.append(self.starttag(node, 'blockquote'))
+
+ def depart_block_quote(self, node):
+ self.body.append('</blockquote>\n')
+
+ def check_simple_list(self, node):
+ """Check for a simple list that can be rendered compactly."""
+ visitor = SimpleListChecker(self.document)
+ try:
+ node.walk(visitor)
+ except nodes.NodeFound:
+ return None
+ else:
+ return 1
+
+ def is_compactable(self, node):
+ return ('compact' in node['classes']
+ or (self.settings.compact_lists
+ and 'open' not in node['classes']
+ and (self.compact_simple
+ or self.topic_classes == ['contents']
+ or self.check_simple_list(node))))
+
+ def visit_bullet_list(self, node):
+ atts = {}
+ old_compact_simple = self.compact_simple
+ self.context.append((self.compact_simple, self.compact_p))
+ self.compact_p = None
+ self.compact_simple = self.is_compactable(node)
+ if self.compact_simple and not old_compact_simple:
+ atts['class'] = 'simple'
+ self.body.append(self.starttag(node, 'ul', **atts))
+
+ def depart_bullet_list(self, node):
+ self.compact_simple, self.compact_p = self.context.pop()
+ self.body.append('</ul>\n')
+
+ def visit_caption(self, node):
+ self.body.append(self.starttag(node, 'p', '', CLASS='caption'))
+
+ def depart_caption(self, node):
+ self.body.append('</p>\n')
+
+ def visit_caution(self, node):
+ self.visit_admonition(node, 'caution')
+
+ def depart_caution(self, node):
+ self.depart_admonition()
+
+ def visit_citation(self, node):
+ self.body.append(self.starttag(node, 'table',
+ CLASS='docutils citation',
+ frame="void", rules="none"))
+ self.body.append('<colgroup><col class="label" /><col /></colgroup>\n'
+ '<tbody valign="top">\n'
+ '<tr>')
+ self.footnote_backrefs(node)
+
+ def depart_citation(self, node):
+ self.body.append('</td></tr>\n'
+ '</tbody>\n</table>\n')
+
+ def visit_citation_reference(self, node):
+ href = '#' + node['refid']
+ self.body.append(self.starttag(
+ node, 'a', '[', CLASS='citation-reference', href=href))
+
+ def depart_citation_reference(self, node):
+ self.body.append(']</a>')
+
+ def visit_classifier(self, node):
+ self.body.append(' <span class="classifier-delimiter">:</span> ')
+ self.body.append(self.starttag(node, 'span', '', CLASS='classifier'))
+
+ def depart_classifier(self, node):
+ self.body.append('</span>')
+
+ def visit_colspec(self, node):
+ self.colspecs.append(node)
+ # "stubs" list is an attribute of the tgroup element:
+ node.parent.stubs.append(node.attributes.get('stub'))
+
+ def depart_colspec(self, node):
+ pass
+
+ def write_colspecs(self):
+ width = 0
+ for node in self.colspecs:
+ width += node['colwidth']
+ for node in self.colspecs:
+ colwidth = int(node['colwidth'] * 100.0 / width + 0.5)
+ self.body.append(self.emptytag(node, 'col',
+ width='%i%%' % colwidth))
+ self.colspecs = []
+
+ def visit_comment(self, node,
+ sub=re.compile('-(?=-)').sub):
+ """Escape double-dashes in comment text."""
+ self.body.append('<!-- %s -->\n' % sub('- ', node.astext()))
+ # Content already processed:
+ raise nodes.SkipNode
+
+ def visit_compound(self, node):
+ self.body.append(self.starttag(node, 'div', CLASS='compound'))
+ if len(node) > 1:
+ node[0]['classes'].append('compound-first')
+ node[-1]['classes'].append('compound-last')
+ for child in node[1:-1]:
+ child['classes'].append('compound-middle')
+
+ def depart_compound(self, node):
+ self.body.append('</div>\n')
+
+ def visit_container(self, node):
+ self.body.append(self.starttag(node, 'div', CLASS='container'))
+
+ def depart_container(self, node):
+ self.body.append('</div>\n')
+
+ def visit_contact(self, node):
+ self.visit_docinfo_item(node, 'contact', meta=None)
+
+ def depart_contact(self, node):
+ self.depart_docinfo_item()
+
+ def visit_copyright(self, node):
+ self.visit_docinfo_item(node, 'copyright')
+
+ def depart_copyright(self, node):
+ self.depart_docinfo_item()
+
+ def visit_danger(self, node):
+ self.visit_admonition(node, 'danger')
+
+ def depart_danger(self, node):
+ self.depart_admonition()
+
+ def visit_date(self, node):
+ self.visit_docinfo_item(node, 'date')
+
+ def depart_date(self, node):
+ self.depart_docinfo_item()
+
+ def visit_decoration(self, node):
+ pass
+
+ def depart_decoration(self, node):
+ pass
+
+ def visit_definition(self, node):
+ self.body.append('</dt>\n')
+ self.body.append(self.starttag(node, 'dd', ''))
+ self.set_first_last(node)
+
+ def depart_definition(self, node):
+ self.body.append('</dd>\n')
+
+ def visit_definition_list(self, node):
+ self.body.append(self.starttag(node, 'dl', CLASS='docutils'))
+
+ def depart_definition_list(self, node):
+ self.body.append('</dl>\n')
+
+ def visit_definition_list_item(self, node):
+ pass
+
+ def depart_definition_list_item(self, node):
+ pass
+
+ def visit_description(self, node):
+ self.body.append(self.starttag(node, 'td', ''))
+ self.set_first_last(node)
+
+ def depart_description(self, node):
+ self.body.append('</td>')
+
+ def visit_docinfo(self, node):
+ self.context.append(len(self.body))
+ self.body.append(self.starttag(node, 'table',
+ CLASS='docinfo',
+ frame="void", rules="none"))
+ self.body.append('<col class="docinfo-name" />\n'
+ '<col class="docinfo-content" />\n'
+ '<tbody valign="top">\n')
+ self.in_docinfo = 1
+
+ def depart_docinfo(self, node):
+ self.body.append('</tbody>\n</table>\n')
+ self.in_docinfo = None
+ start = self.context.pop()
+ self.docinfo = self.body[start:]
+ self.body = []
+
+ def visit_docinfo_item(self, node, name, meta=1):
+ if meta:
+ meta_tag = '<meta name="%s" content="%s" />\n' \
+ % (name, self.attval(node.astext()))
+ self.add_meta(meta_tag)
+ self.body.append(self.starttag(node, 'tr', ''))
+ self.body.append('<th class="docinfo-name">%s:</th>\n<td>'
+ % self.language.labels[name])
+ if len(node):
+ if isinstance(node[0], nodes.Element):
+ node[0]['classes'].append('first')
+ if isinstance(node[-1], nodes.Element):
+ node[-1]['classes'].append('last')
+
+ def depart_docinfo_item(self):
+ self.body.append('</td></tr>\n')
+
+ def visit_doctest_block(self, node):
+ self.body.append(self.starttag(node, 'pre', CLASS='doctest-block'))
+
+ def depart_doctest_block(self, node):
+ self.body.append('\n</pre>\n')
+
+ def visit_document(self, node):
+ self.head.append('<title>%s</title>\n'
+ % self.encode(node.get('title', '')))
+
+ def depart_document(self, node):
+ self.fragment.extend(self.body)
+ self.body_prefix.append(self.starttag(node, 'div', CLASS='document'))
+ self.body_suffix.insert(0, '</div>\n')
+ # skip content-type meta tag with interpolated charset value:
+ self.html_head.extend(self.head[1:])
+ self.html_body.extend(self.body_prefix[1:] + self.body_pre_docinfo
+ + self.docinfo + self.body
+ + self.body_suffix[:-1])
+
+ def visit_emphasis(self, node):
+ self.body.append('<em>')
+
+ def depart_emphasis(self, node):
+ self.body.append('</em>')
+
+ def visit_entry(self, node):
+ atts = {'class': []}
+ if isinstance(node.parent.parent, nodes.thead):
+ atts['class'].append('head')
+ if node.parent.parent.parent.stubs[node.parent.column]:
+ # "stubs" list is an attribute of the tgroup element
+ atts['class'].append('stub')
+ if atts['class']:
+ tagname = 'th'
+ atts['class'] = ' '.join(atts['class'])
+ else:
+ tagname = 'td'
+ del atts['class']
+ node.parent.column += 1
+ if node.has_key('morerows'):
+ atts['rowspan'] = node['morerows'] + 1
+ if node.has_key('morecols'):
+ atts['colspan'] = node['morecols'] + 1
+ node.parent.column += node['morecols']
+ self.body.append(self.starttag(node, tagname, '', **atts))
+ self.context.append('</%s>\n' % tagname.lower())
+ if len(node) == 0: # empty cell
+ self.body.append('&nbsp;')
+ self.set_first_last(node)
+
+ def depart_entry(self, node):
+ self.body.append(self.context.pop())
+
+ def visit_enumerated_list(self, node):
+ """
+ The 'start' attribute does not conform to HTML 4.01's strict.dtd, but
+ CSS1 doesn't help. CSS2 isn't widely enough supported yet to be
+ usable.
+ """
+ atts = {}
+ if node.has_key('start'):
+ atts['start'] = node['start']
+ if node.has_key('enumtype'):
+ atts['class'] = node['enumtype']
+ # @@@ To do: prefix, suffix. How? Change prefix/suffix to a
+ # single "format" attribute? Use CSS2?
+ old_compact_simple = self.compact_simple
+ self.context.append((self.compact_simple, self.compact_p))
+ self.compact_p = None
+ self.compact_simple = self.is_compactable(node)
+ if self.compact_simple and not old_compact_simple:
+ atts['class'] = (atts.get('class', '') + ' simple').strip()
+ self.body.append(self.starttag(node, 'ol', **atts))
+
+ def depart_enumerated_list(self, node):
+ self.compact_simple, self.compact_p = self.context.pop()
+ self.body.append('</ol>\n')
+
+ def visit_error(self, node):
+ self.visit_admonition(node, 'error')
+
+ def depart_error(self, node):
+ self.depart_admonition()
+
+ def visit_field(self, node):
+ self.body.append(self.starttag(node, 'tr', '', CLASS='field'))
+
+ def depart_field(self, node):
+ self.body.append('</tr>\n')
+
+ def visit_field_body(self, node):
+ self.body.append(self.starttag(node, 'td', '', CLASS='field-body'))
+ self.set_class_on_child(node, 'first', 0)
+ field = node.parent
+ if (self.compact_field_list or
+ isinstance(field.parent, nodes.docinfo) or
+ field.parent.index(field) == len(field.parent) - 1):
+ # If we are in a compact list, the docinfo, or if this is
+ # the last field of the field list, do not add vertical
+ # space after last element.
+ self.set_class_on_child(node, 'last', -1)
+
+ def depart_field_body(self, node):
+ self.body.append('</td>\n')
+
+ def visit_field_list(self, node):
+ self.context.append((self.compact_field_list, self.compact_p))
+ self.compact_p = None
+ if 'compact' in node['classes']:
+ self.compact_field_list = 1
+ elif (self.settings.compact_field_lists
+ and 'open' not in node['classes']):
+ self.compact_field_list = 1
+ if self.compact_field_list:
+ for field in node:
+ field_body = field[-1]
+ assert isinstance(field_body, nodes.field_body)
+ children = [n for n in field_body
+ if not isinstance(n, nodes.Invisible)]
+ if not (len(children) == 0 or
+ len(children) == 1 and
+ isinstance(children[0], nodes.paragraph)):
+ self.compact_field_list = 0
+ break
+ self.body.append(self.starttag(node, 'table', frame='void',
+ rules='none',
+ CLASS='docutils field-list'))
+ self.body.append('<col class="field-name" />\n'
+ '<col class="field-body" />\n'
+ '<tbody valign="top">\n')
+
+ def depart_field_list(self, node):
+ self.body.append('</tbody>\n</table>\n')
+ self.compact_field_list, self.compact_p = self.context.pop()
+
+ def visit_field_name(self, node):
+ atts = {}
+ if self.in_docinfo:
+ atts['class'] = 'docinfo-name'
+ else:
+ atts['class'] = 'field-name'
+ if ( self.settings.field_name_limit
+ and len(node.astext()) > self.settings.field_name_limit):
+ atts['colspan'] = 2
+ self.context.append('</tr>\n<tr><td>&nbsp;</td>')
+ else:
+ self.context.append('')
+ self.body.append(self.starttag(node, 'th', '', **atts))
+
+ def depart_field_name(self, node):
+ self.body.append(':</th>')
+ self.body.append(self.context.pop())
+
+ def visit_figure(self, node):
+ atts = {'class': 'figure'}
+ if node.get('width'):
+ atts['style'] = 'width: %spx' % node['width']
+ if node.get('align'):
+ atts['align'] = node['align']
+ self.body.append(self.starttag(node, 'div', **atts))
+
+ def depart_figure(self, node):
+ self.body.append('</div>\n')
+
+ def visit_footer(self, node):
+ self.context.append(len(self.body))
+
+ def depart_footer(self, node):
+ start = self.context.pop()
+ footer = [self.starttag(node, 'div', CLASS='footer'),
+ '<hr class="footer" />\n']
+ footer.extend(self.body[start:])
+ footer.append('\n</div>\n')
+ self.footer.extend(footer)
+ self.body_suffix[:0] = footer
+ del self.body[start:]
+
+ def visit_footnote(self, node):
+ self.body.append(self.starttag(node, 'table',
+ CLASS='docutils footnote',
+ frame="void", rules="none"))
+ self.body.append('<colgroup><col class="label" /><col /></colgroup>\n'
+ '<tbody valign="top">\n'
+ '<tr>')
+ self.footnote_backrefs(node)
+
+ def footnote_backrefs(self, node):
+ backlinks = []
+ backrefs = node['backrefs']
+ if self.settings.footnote_backlinks and backrefs:
+ if len(backrefs) == 1:
+ self.context.append('')
+ self.context.append(
+ '<a class="fn-backref" href="#%s" name="%s">'
+ % (backrefs[0], node['ids'][0]))
+ else:
+ i = 1
+ for backref in backrefs:
+ backlinks.append('<a class="fn-backref" href="#%s">%s</a>'
+ % (backref, i))
+ i += 1
+ self.context.append('<em>(%s)</em> ' % ', '.join(backlinks))
+ self.context.append('<a name="%s">' % node['ids'][0])
+ else:
+ self.context.append('')
+ self.context.append('<a name="%s">' % node['ids'][0])
+ # If the node does not only consist of a label.
+ if len(node) > 1:
+ # If there are preceding backlinks, we do not set class
+ # 'first', because we need to retain the top-margin.
+ if not backlinks:
+ node[1]['classes'].append('first')
+ node[-1]['classes'].append('last')
+
+ def depart_footnote(self, node):
+ self.body.append('</td></tr>\n'
+ '</tbody>\n</table>\n')
+
+ def visit_footnote_reference(self, node):
+ href = '#' + node['refid']
+ format = self.settings.footnote_references
+ if format == 'brackets':
+ suffix = '['
+ self.context.append(']')
+ else:
+ assert format == 'superscript'
+ suffix = '<sup>'
+ self.context.append('</sup>')
+ self.body.append(self.starttag(node, 'a', suffix,
+ CLASS='footnote-reference', href=href))
+
+ def depart_footnote_reference(self, node):
+ self.body.append(self.context.pop() + '</a>')
+
+ def visit_generated(self, node):
+ pass
+
+ def depart_generated(self, node):
+ pass
+
+ def visit_header(self, node):
+ self.context.append(len(self.body))
+
+ def depart_header(self, node):
+ start = self.context.pop()
+ header = [self.starttag(node, 'div', CLASS='header')]
+ header.extend(self.body[start:])
+ header.append('\n<hr class="header"/>\n</div>\n')
+ self.body_prefix.extend(header)
+ self.header.extend(header)
+ del self.body[start:]
+
+ def visit_hint(self, node):
+ self.visit_admonition(node, 'hint')
+
+ def depart_hint(self, node):
+ self.depart_admonition()
+
+ def visit_image(self, node):
+ atts = {}
+ atts['src'] = node['uri']
+ if node.has_key('width'):
+ atts['width'] = node['width']
+ if node.has_key('height'):
+ atts['height'] = node['height']
+ if node.has_key('scale'):
+ if Image and not (node.has_key('width')
+ and node.has_key('height')):
+ try:
+ im = Image.open(str(atts['src']))
+ except (IOError, # Source image can't be found or opened
+ UnicodeError): # PIL doesn't like Unicode paths.
+ pass
+ else:
+ if not atts.has_key('width'):
+ atts['width'] = str(im.size[0])
+ if not atts.has_key('height'):
+ atts['height'] = str(im.size[1])
+ del im
+ for att_name in 'width', 'height':
+ if atts.has_key(att_name):
+ match = re.match(r'([0-9.]+)(\S*)$', atts[att_name])
+ assert match
+ atts[att_name] = '%s%s' % (
+ float(match.group(1)) * (float(node['scale']) / 100),
+ match.group(2))
+ style = []
+ for att_name in 'width', 'height':
+ if atts.has_key(att_name):
+ if re.match(r'^[0-9.]+$', atts[att_name]):
+ # Interpret unitless values as pixels.
+ atts[att_name] += 'px'
+ style.append('%s: %s;' % (att_name, atts[att_name]))
+ del atts[att_name]
+ if style:
+ atts['style'] = ' '.join(style)
+ atts['alt'] = node.get('alt', atts['src'])
+ if (isinstance(node.parent, nodes.TextElement) or
+ (isinstance(node.parent, nodes.reference) and
+ not isinstance(node.parent.parent, nodes.TextElement))):
+ # Inline context or surrounded by <a>...</a>.
+ suffix = ''
+ else:
+ suffix = '\n'
+ if node.has_key('align'):
+ if node['align'] == 'center':
+ # "align" attribute is set in surrounding "div" element.
+ self.body.append('<div align="center" class="align-center">')
+ self.context.append('</div>\n')
+ suffix = ''
+ else:
+ # "align" attribute is set in "img" element.
+ atts['align'] = node['align']
+ self.context.append('')
+ atts['class'] = 'align-%s' % node['align']
+ else:
+ self.context.append('')
+ self.body.append(self.emptytag(node, 'img', suffix, **atts))
+
+ def depart_image(self, node):
+ self.body.append(self.context.pop())
+
+ def visit_important(self, node):
+ self.visit_admonition(node, 'important')
+
+ def depart_important(self, node):
+ self.depart_admonition()
+
+ def visit_inline(self, node):
+ self.body.append(self.starttag(node, 'span', ''))
+
+ def depart_inline(self, node):
+ self.body.append('</span>')
+
+ def visit_label(self, node):
+ self.body.append(self.starttag(node, 'td', '%s[' % self.context.pop(),
+ CLASS='label'))
+
+ def depart_label(self, node):
+ self.body.append(']</a></td><td>%s' % self.context.pop())
+
+ def visit_legend(self, node):
+ self.body.append(self.starttag(node, 'div', CLASS='legend'))
+
+ def depart_legend(self, node):
+ self.body.append('</div>\n')
+
+ def visit_line(self, node):
+ self.body.append(self.starttag(node, 'div', suffix='', CLASS='line'))
+ if not len(node):
+ self.body.append('<br />')
+
+ def depart_line(self, node):
+ self.body.append('</div>\n')
+
+ def visit_line_block(self, node):
+ self.body.append(self.starttag(node, 'div', CLASS='line-block'))
+
+ def depart_line_block(self, node):
+ self.body.append('</div>\n')
+
+ def visit_list_item(self, node):
+ self.body.append(self.starttag(node, 'li', ''))
+ if len(node):
+ node[0]['classes'].append('first')
+
+ def depart_list_item(self, node):
+ self.body.append('</li>\n')
+
+ def visit_literal(self, node):
+ """Process text to prevent tokens from wrapping."""
+ self.body.append(
+ self.starttag(node, 'tt', '', CLASS='docutils literal'))
+ text = node.astext()
+ for token in self.words_and_spaces.findall(text):
+ if token.strip():
+ # Protect text like "--an-option" from bad line wrapping:
+ self.body.append('<span class="pre">%s</span>'
+ % self.encode(token))
+ elif token in ('\n', ' '):
+ # Allow breaks at whitespace:
+ self.body.append(token)
+ else:
+ # Protect runs of multiple spaces; the last space can wrap:
+ self.body.append('&nbsp;' * (len(token) - 1) + ' ')
+ self.body.append('</tt>')
+ # Content already processed:
+ raise nodes.SkipNode
+
+ def visit_literal_block(self, node):
+ self.body.append(self.starttag(node, 'pre', CLASS='literal-block'))
+
+ def depart_literal_block(self, node):
+ self.body.append('\n</pre>\n')
+
+ def visit_meta(self, node):
+ meta = self.emptytag(node, 'meta', **node.non_default_attributes())
+ self.add_meta(meta)
+
+ def depart_meta(self, node):
+ pass
+
+ def add_meta(self, tag):
+ self.meta.append(tag)
+ self.head.append(tag)
+
+ def visit_note(self, node):
+ self.visit_admonition(node, 'note')
+
+ def depart_note(self, node):
+ self.depart_admonition()
+
+ def visit_option(self, node):
+ if self.context[-1]:
+ self.body.append(', ')
+ self.body.append(self.starttag(node, 'span', '', CLASS='option'))
+
+ def depart_option(self, node):
+ self.body.append('</span>')
+ self.context[-1] += 1
+
+ def visit_option_argument(self, node):
+ self.body.append(node.get('delimiter', ' '))
+ self.body.append(self.starttag(node, 'var', ''))
+
+ def depart_option_argument(self, node):
+ self.body.append('</var>')
+
+ def visit_option_group(self, node):
+ atts = {}
+ if ( self.settings.option_limit
+ and len(node.astext()) > self.settings.option_limit):
+ atts['colspan'] = 2
+ self.context.append('</tr>\n<tr><td>&nbsp;</td>')
+ else:
+ self.context.append('')
+ self.body.append(
+ self.starttag(node, 'td', CLASS='option-group', **atts))
+ self.body.append('<kbd>')
+ self.context.append(0) # count number of options
+
+ def depart_option_group(self, node):
+ self.context.pop()
+ self.body.append('</kbd></td>\n')
+ self.body.append(self.context.pop())
+
+ def visit_option_list(self, node):
+ self.body.append(
+ self.starttag(node, 'table', CLASS='docutils option-list',
+ frame="void", rules="none"))
+ self.body.append('<col class="option" />\n'
+ '<col class="description" />\n'
+ '<tbody valign="top">\n')
+
+ def depart_option_list(self, node):
+ self.body.append('</tbody>\n</table>\n')
+
+ def visit_option_list_item(self, node):
+ self.body.append(self.starttag(node, 'tr', ''))
+
+ def depart_option_list_item(self, node):
+ self.body.append('</tr>\n')
+
+ def visit_option_string(self, node):
+ pass
+
+ def depart_option_string(self, node):
+ pass
+
+ def visit_organization(self, node):
+ self.visit_docinfo_item(node, 'organization')
+
+ def depart_organization(self, node):
+ self.depart_docinfo_item()
+
+ def should_be_compact_paragraph(self, node):
+ """
+ Determine if the <p> tags around paragraph ``node`` can be omitted.
+ """
+ if (isinstance(node.parent, nodes.document) or
+ isinstance(node.parent, nodes.compound)):
+ # Never compact paragraphs in document or compound.
+ return 0
+ for key, value in node.attlist():
+ if (node.is_not_default(key) and
+ not (key == 'classes' and value in
+ ([], ['first'], ['last'], ['first', 'last']))):
+ # Attribute which needs to survive.
+ return 0
+ first = isinstance(node.parent[0], nodes.label) # skip label
+ for child in node.parent.children[first:]:
+ # only first paragraph can be compact
+ if isinstance(child, nodes.Invisible):
+ continue
+ if child is node:
+ break
+ return 0
+ if ( self.compact_simple
+ or self.compact_field_list
+ or (self.compact_p
+ and (len(node.parent) == 1
+ or len(node.parent) == 2
+ and isinstance(node.parent[0], nodes.label)))):
+ return 1
+ return 0
+
+ def visit_paragraph(self, node):
+ if self.should_be_compact_paragraph(node):
+ self.context.append('')
+ else:
+ self.body.append(self.starttag(node, 'p', ''))
+ self.context.append('</p>\n')
+
+ def depart_paragraph(self, node):
+ self.body.append(self.context.pop())
+
+ def visit_problematic(self, node):
+ if node.hasattr('refid'):
+ self.body.append('<a href="#%s" name="%s">' % (node['refid'],
+ node['ids'][0]))
+ self.context.append('</a>')
+ else:
+ self.context.append('')
+ self.body.append(self.starttag(node, 'span', '', CLASS='problematic'))
+
+ def depart_problematic(self, node):
+ self.body.append('</span>')
+ self.body.append(self.context.pop())
+
+ def visit_raw(self, node):
+ if 'html' in node.get('format', '').split():
+ t = isinstance(node.parent, nodes.TextElement) and 'span' or 'div'
+ if node['classes']:
+ self.body.append(self.starttag(node, t, suffix=''))
+ self.body.append(node.astext())
+ if node['classes']:
+ self.body.append('</%s>' % t)
+ # Keep non-HTML raw text out of output:
+ raise nodes.SkipNode
+
+ def visit_reference(self, node):
+ if node.has_key('refuri'):
+ href = node['refuri']
+ if ( self.settings.cloak_email_addresses
+ and href.startswith('mailto:')):
+ href = self.cloak_mailto(href)
+ self.in_mailto = 1
+ else:
+ assert node.has_key('refid'), \
+ 'References must have "refuri" or "refid" attribute.'
+ href = '#' + node['refid']
+ atts = {'href': href, 'class': 'reference'}
+ if not isinstance(node.parent, nodes.TextElement):
+ assert len(node) == 1 and isinstance(node[0], nodes.image)
+ atts['class'] += ' image-reference'
+ self.body.append(self.starttag(node, 'a', '', **atts))
+
+ def depart_reference(self, node):
+ self.body.append('</a>')
+ if not isinstance(node.parent, nodes.TextElement):
+ self.body.append('\n')
+ self.in_mailto = 0
+
+ def visit_revision(self, node):
+ self.visit_docinfo_item(node, 'revision', meta=None)
+
+ def depart_revision(self, node):
+ self.depart_docinfo_item()
+
+ def visit_row(self, node):
+ self.body.append(self.starttag(node, 'tr', ''))
+ node.column = 0
+
+ def depart_row(self, node):
+ self.body.append('</tr>\n')
+
+ def visit_rubric(self, node):
+ self.body.append(self.starttag(node, 'p', '', CLASS='rubric'))
+
+ def depart_rubric(self, node):
+ self.body.append('</p>\n')
+
+ def visit_section(self, node):
+ self.section_level += 1
+ self.body.append(
+ self.start_tag_with_title(node, 'div', CLASS='section'))
+
+ def depart_section(self, node):
+ self.section_level -= 1
+ self.body.append('</div>\n')
+
+ def visit_sidebar(self, node):
+ self.body.append(
+ self.start_tag_with_title(node, 'div', CLASS='sidebar'))
+ self.set_first_last(node)
+ self.in_sidebar = 1
+
+ def depart_sidebar(self, node):
+ self.body.append('</div>\n')
+ self.in_sidebar = None
+
+ def visit_status(self, node):
+ self.visit_docinfo_item(node, 'status', meta=None)
+
+ def depart_status(self, node):
+ self.depart_docinfo_item()
+
+ def visit_strong(self, node):
+ self.body.append('<strong>')
+
+ def depart_strong(self, node):
+ self.body.append('</strong>')
+
+ def visit_subscript(self, node):
+ self.body.append(self.starttag(node, 'sub', ''))
+
+ def depart_subscript(self, node):
+ self.body.append('</sub>')
+
+ def visit_substitution_definition(self, node):
+ """Internal only."""
+ raise nodes.SkipNode
+
+ def visit_substitution_reference(self, node):
+ self.unimplemented_visit(node)
+
+ def visit_subtitle(self, node):
+ if isinstance(node.parent, nodes.sidebar):
+ self.body.append(self.starttag(node, 'p', '',
+ CLASS='sidebar-subtitle'))
+ self.context.append('</p>\n')
+ elif isinstance(node.parent, nodes.document):
+ self.body.append(self.starttag(node, 'h2', '', CLASS='subtitle'))
+ self.context.append('</h2>\n')
+ self.in_document_title = len(self.body)
+ elif isinstance(node.parent, nodes.section):
+ tag = 'h%s' % (self.section_level + self.initial_header_level - 1)
+ self.body.append(
+ self.starttag(node, tag, '', CLASS='section-subtitle') +
+ self.starttag({}, 'span', '', CLASS='section-subtitle'))
+ self.context.append('</span></%s>\n' % tag)
+
+ def depart_subtitle(self, node):
+ self.body.append(self.context.pop())
+ if self.in_document_title:
+ self.subtitle = self.body[self.in_document_title:-1]
+ self.in_document_title = 0
+ self.body_pre_docinfo.extend(self.body)
+ self.html_subtitle.extend(self.body)
+ del self.body[:]
+
+ def visit_superscript(self, node):
+ self.body.append(self.starttag(node, 'sup', ''))
+
+ def depart_superscript(self, node):
+ self.body.append('</sup>')
+
+ def visit_system_message(self, node):
+ self.body.append(self.starttag(node, 'div', CLASS='system-message'))
+ self.body.append('<p class="system-message-title">')
+ attr = {}
+ backref_text = ''
+ if node['ids']:
+ attr['name'] = node['ids'][0]
+ if len(node['backrefs']):
+ backrefs = node['backrefs']
+ if len(backrefs) == 1:
+ backref_text = ('; <em><a href="#%s">backlink</a></em>'
+ % backrefs[0])
+ else:
+ i = 1
+ backlinks = []
+ for backref in backrefs:
+ backlinks.append('<a href="#%s">%s</a>' % (backref, i))
+ i += 1
+ backref_text = ('; <em>backlinks: %s</em>'
+ % ', '.join(backlinks))
+ if node.hasattr('line'):
+ line = ', line %s' % node['line']
+ else:
+ line = ''
+ if attr:
+ a_start = self.starttag({}, 'a', '', **attr)
+ a_end = '</a>'
+ else:
+ a_start = a_end = ''
+ self.body.append('System Message: %s%s/%s%s '
+ '(<tt class="docutils">%s</tt>%s)%s</p>\n'
+ % (a_start, node['type'], node['level'], a_end,
+ self.encode(node['source']), line, backref_text))
+
+ def depart_system_message(self, node):
+ self.body.append('</div>\n')
+
+ def visit_table(self, node):
+ self.body.append(
+ self.starttag(node, 'table', CLASS='docutils', border="1"))
+
+ def depart_table(self, node):
+ self.body.append('</table>\n')
+
+ def visit_target(self, node):
+ if not (node.has_key('refuri') or node.has_key('refid')
+ or node.has_key('refname')):
+ self.body.append(self.starttag(node, 'span', '', CLASS='target'))
+ self.context.append('</span>')
+ else:
+ self.context.append('')
+
+ def depart_target(self, node):
+ self.body.append(self.context.pop())
+
+ def visit_tbody(self, node):
+ self.write_colspecs()
+ self.body.append(self.context.pop()) # '</colgroup>\n' or ''
+ self.body.append(self.starttag(node, 'tbody', valign='top'))
+
+ def depart_tbody(self, node):
+ self.body.append('</tbody>\n')
+
+ def visit_term(self, node):
+ self.body.append(self.starttag(node, 'dt', ''))
+
+ def depart_term(self, node):
+ """
+ Leave the end tag to `self.visit_definition()`, in case there's a
+ classifier.
+ """
+ pass
+
+ def visit_tgroup(self, node):
+ # Mozilla needs <colgroup>:
+ self.body.append(self.starttag(node, 'colgroup'))
+ # Appended by thead or tbody:
+ self.context.append('</colgroup>\n')
+ node.stubs = []
+
+ def depart_tgroup(self, node):
+ pass
+
+ def visit_thead(self, node):
+ self.write_colspecs()
+ self.body.append(self.context.pop()) # '</colgroup>\n'
+ # There may or may not be a <thead>; this is for <tbody> to use:
+ self.context.append('')
+ self.body.append(self.starttag(node, 'thead', valign='bottom'))
+
+ def depart_thead(self, node):
+ self.body.append('</thead>\n')
+
+ def visit_tip(self, node):
+ self.visit_admonition(node, 'tip')
+
+ def depart_tip(self, node):
+ self.depart_admonition()
+
+ def visit_title(self, node, move_ids=1):
+ """Only 6 section levels are supported by HTML."""
+ check_id = 0
+ close_tag = '</p>\n'
+ if isinstance(node.parent, nodes.topic):
+ self.body.append(
+ self.starttag(node, 'p', '', CLASS='topic-title first'))
+ check_id = 1
+ elif isinstance(node.parent, nodes.sidebar):
+ self.body.append(
+ self.starttag(node, 'p', '', CLASS='sidebar-title'))
+ check_id = 1
+ elif isinstance(node.parent, nodes.Admonition):
+ self.body.append(
+ self.starttag(node, 'p', '', CLASS='admonition-title'))
+ check_id = 1
+ elif isinstance(node.parent, nodes.table):
+ self.body.append(
+ self.starttag(node, 'caption', ''))
+ check_id = 1
+ close_tag = '</caption>\n'
+ elif isinstance(node.parent, nodes.document):
+ self.body.append(self.starttag(node, 'h1', '', CLASS='title'))
+ self.context.append('</h1>\n')
+ self.in_document_title = len(self.body)
+ else:
+ assert isinstance(node.parent, nodes.section)
+ h_level = self.section_level + self.initial_header_level - 1
+ atts = {}
+ if (len(node.parent) >= 2 and
+ isinstance(node.parent[1], nodes.subtitle)):
+ atts['CLASS'] = 'with-subtitle'
+ self.body.append(
+ self.starttag(node, 'h%s' % h_level, '', **atts))
+ atts = {}
+ # !!! conditional to be removed in Docutils 0.5:
+ if move_ids:
+ if node.parent['ids']:
+ atts['ids'] = node.parent['ids']
+ if node.hasattr('refid'):
+ atts['class'] = 'toc-backref'
+ atts['href'] = '#' + node['refid']
+ if atts:
+ self.body.append(self.starttag({}, 'a', '', **atts))
+ self.context.append('</a></h%s>\n' % (h_level))
+ else:
+ self.context.append('</h%s>\n' % (h_level))
+ # !!! conditional to be removed in Docutils 0.5:
+ if check_id:
+ if node.parent['ids']:
+ atts={'ids': node.parent['ids']}
+ self.body.append(
+ self.starttag({}, 'a', '', **atts))
+ self.context.append('</a>' + close_tag)
+ else:
+ self.context.append(close_tag)
+
+ def depart_title(self, node):
+ self.body.append(self.context.pop())
+ if self.in_document_title:
+ self.title = self.body[self.in_document_title:-1]
+ self.in_document_title = 0
+ self.body_pre_docinfo.extend(self.body)
+ self.html_title.extend(self.body)
+ del self.body[:]
+
+ def visit_title_reference(self, node):
+ self.body.append(self.starttag(node, 'cite', ''))
+
+ def depart_title_reference(self, node):
+ self.body.append('</cite>')
+
+ def visit_topic(self, node):
+ self.body.append(self.start_tag_with_title(node, 'div', CLASS='topic'))
+ self.topic_classes = node['classes']
+
+ def depart_topic(self, node):
+ self.body.append('</div>\n')
+ self.topic_classes = []
+
+ def visit_transition(self, node):
+ self.body.append(self.emptytag(node, 'hr', CLASS='docutils'))
+
+ def depart_transition(self, node):
+ pass
+
+ def visit_version(self, node):
+ self.visit_docinfo_item(node, 'version', meta=None)
+
+ def depart_version(self, node):
+ self.depart_docinfo_item()
+
+ def visit_warning(self, node):
+ self.visit_admonition(node, 'warning')
+
+ def depart_warning(self, node):
+ self.depart_admonition()
+
+ def unimplemented_visit(self, node):
+ raise NotImplementedError('visiting unimplemented node type: %s'
+ % node.__class__.__name__)
+
+
+class SimpleListChecker(nodes.GenericNodeVisitor):
+
+ """
+ Raise `nodes.NodeFound` if non-simple list item is encountered.
+
+ Here "simple" means a list item containing nothing other than a single
+ paragraph, a simple list, or a paragraph followed by a simple list.
+ """
+
+ def default_visit(self, node):
+ raise nodes.NodeFound
+
+ def visit_bullet_list(self, node):
+ pass
+
+ def visit_enumerated_list(self, node):
+ pass
+
+ def visit_list_item(self, node):
+ children = []
+ for child in node.children:
+ if not isinstance(child, nodes.Invisible):
+ children.append(child)
+ if (children and isinstance(children[0], nodes.paragraph)
+ and (isinstance(children[-1], nodes.bullet_list)
+ or isinstance(children[-1], nodes.enumerated_list))):
+ children.pop()
+ if len(children) <= 1:
+ return
+ else:
+ raise nodes.NodeFound
+
+ def visit_paragraph(self, node):
+ raise nodes.SkipNode
+
+ def invisible_visit(self, node):
+ """Invisible nodes should be ignored."""
+ raise nodes.SkipNode
+
+ visit_comment = invisible_visit
+ visit_substitution_definition = invisible_visit
+ visit_target = invisible_visit
+ visit_pending = invisible_visit
diff --git a/docutils/writers/html4css1/html4css1.css b/docutils/writers/html4css1/html4css1.css
new file mode 100644
index 000000000..e94df1546
--- /dev/null
+++ b/docutils/writers/html4css1/html4css1.css
@@ -0,0 +1,279 @@
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Date: $Date$
+:Revision: $Revision$
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+*/
+
+/* used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+ border: 0 }
+
+table.borderless td, table.borderless th {
+ /* Override padding for "table.docutils td" with "! important".
+ The right padding separates the table cells. */
+ padding: 0 0.5em 0 0 ! important }
+
+.first {
+ /* Override more specific margin styles with "! important". */
+ margin-top: 0 ! important }
+
+.last, .with-subtitle {
+ margin-bottom: 0 ! important }
+
+.hidden {
+ display: none }
+
+a.toc-backref {
+ text-decoration: none ;
+ color: black }
+
+blockquote.epigraph {
+ margin: 2em 5em ; }
+
+dl.docutils dd {
+ margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+ font-weight: bold }
+*/
+
+div.abstract {
+ margin: 2em 5em }
+
+div.abstract p.topic-title {
+ font-weight: bold ;
+ text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+ margin: 2em ;
+ border: medium outset ;
+ padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+ color: red ;
+ font-weight: bold ;
+ font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+ compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+ margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+ margin-top: 0.5em }
+*/
+
+div.dedication {
+ margin: 2em 5em ;
+ text-align: center ;
+ font-style: italic }
+
+div.dedication p.topic-title {
+ font-weight: bold ;
+ font-style: normal }
+
+div.figure {
+ margin-left: 2em ;
+ margin-right: 2em }
+
+div.footer, div.header {
+ clear: both;
+ font-size: smaller }
+
+div.line-block {
+ display: block ;
+ margin-top: 1em ;
+ margin-bottom: 1em }
+
+div.line-block div.line-block {
+ margin-top: 0 ;
+ margin-bottom: 0 ;
+ margin-left: 1.5em }
+
+div.sidebar {
+ margin-left: 1em ;
+ border: medium outset ;
+ padding: 1em ;
+ background-color: #ffffee ;
+ width: 40% ;
+ float: right ;
+ clear: right }
+
+div.sidebar p.rubric {
+ font-family: sans-serif ;
+ font-size: medium }
+
+div.system-messages {
+ margin: 5em }
+
+div.system-messages h1 {
+ color: red }
+
+div.system-message {
+ border: medium outset ;
+ padding: 1em }
+
+div.system-message p.system-message-title {
+ color: red ;
+ font-weight: bold }
+
+div.topic {
+ margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+ margin-top: 0.4em }
+
+h1.title {
+ text-align: center }
+
+h2.subtitle {
+ text-align: center }
+
+hr.docutils {
+ width: 75% }
+
+img.align-left {
+ clear: left }
+
+img.align-right {
+ clear: right }
+
+ol.simple, ul.simple {
+ margin-bottom: 1em }
+
+ol.arabic {
+ list-style: decimal }
+
+ol.loweralpha {
+ list-style: lower-alpha }
+
+ol.upperalpha {
+ list-style: upper-alpha }
+
+ol.lowerroman {
+ list-style: lower-roman }
+
+ol.upperroman {
+ list-style: upper-roman }
+
+p.attribution {
+ text-align: right ;
+ margin-left: 50% }
+
+p.caption {
+ font-style: italic }
+
+p.credits {
+ font-style: italic ;
+ font-size: smaller }
+
+p.label {
+ white-space: nowrap }
+
+p.rubric {
+ font-weight: bold ;
+ font-size: larger ;
+ color: maroon ;
+ text-align: center }
+
+p.sidebar-title {
+ font-family: sans-serif ;
+ font-weight: bold ;
+ font-size: larger }
+
+p.sidebar-subtitle {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+p.topic-title {
+ font-weight: bold }
+
+pre.address {
+ margin-bottom: 0 ;
+ margin-top: 0 ;
+ font-family: serif ;
+ font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+ margin-left: 2em ;
+ margin-right: 2em ;
+ background-color: #eeeeee }
+
+span.classifier {
+ font-family: sans-serif ;
+ font-style: oblique }
+
+span.classifier-delimiter {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+span.interpreted {
+ font-family: sans-serif }
+
+span.option {
+ white-space: nowrap }
+
+span.pre {
+ white-space: pre }
+
+span.problematic {
+ color: red }
+
+span.section-subtitle {
+ /* font-size relative to parent (h1..h6 element) */
+ font-size: 80% }
+
+table.citation {
+ border-left: solid 1px gray;
+ margin-left: 1px }
+
+table.docinfo {
+ margin: 2em 4em }
+
+table.docutils {
+ margin-top: 0.5em ;
+ margin-bottom: 0.5em }
+
+table.footnote {
+ border-left: solid 1px black;
+ margin-left: 1px }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+ padding-left: 0.5em ;
+ padding-right: 0.5em ;
+ vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+ font-weight: bold ;
+ text-align: left ;
+ white-space: nowrap ;
+ padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+ font-size: 100% }
+
+tt.docutils {
+ background-color: #eeeeee }
+
+ul.auto-toc {
+ list-style-type: none }
diff --git a/docutils/writers/latex2e/__init__.py b/docutils/writers/latex2e/__init__.py
new file mode 100644
index 000000000..cf7af05fd
--- /dev/null
+++ b/docutils/writers/latex2e/__init__.py
@@ -0,0 +1,2048 @@
+# Author: Engelbert Gruber
+# Contact: grubert@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+LaTeX2e document tree Writer.
+"""
+
+__docformat__ = 'reStructuredText'
+
+# code contributions from several people included, thanks to all.
+# some named: David Abrahams, Julien Letessier, Lele Gaifax, and others.
+#
+# convention deactivate code by two # e.g. ##.
+
+import sys
+import time
+import re
+import string
+from types import ListType
+from docutils import frontend, nodes, languages, writers, utils
+
+
+class Writer(writers.Writer):
+
+ supported = ('latex','latex2e')
+ """Formats this writer supports."""
+
+ settings_spec = (
+ 'LaTeX-Specific Options',
+ 'The LaTeX "--output-encoding" default is "latin-1:strict".',
+ (('Specify documentclass. Default is "article".',
+ ['--documentclass'],
+ {'default': 'article', }),
+ ('Specify document options. Multiple options can be given, '
+ 'separated by commas. Default is "10pt,a4paper".',
+ ['--documentoptions'],
+ {'default': '10pt,a4paper', }),
+ ('Use LaTeX footnotes. LaTeX supports only numbered footnotes (does it?). '
+ 'Default: no, uses figures.',
+ ['--use-latex-footnotes'],
+ {'default': 0, 'action': 'store_true',
+ 'validator': frontend.validate_boolean}),
+ ('Format for footnote references: one of "superscript" or '
+ '"brackets". Default is "superscript".',
+ ['--footnote-references'],
+ {'choices': ['superscript', 'brackets'], 'default': 'superscript',
+ 'metavar': '<format>',
+ 'overrides': 'trim_footnote_reference_space'}),
+ ('Use LaTeX citations. '
+ 'Default: no, uses figures which might get mixed with images.',
+ ['--use-latex-citations'],
+ {'default': 0, 'action': 'store_true',
+ 'validator': frontend.validate_boolean}),
+ ('Format for block quote attributions: one of "dash" (em-dash '
+ 'prefix), "parentheses"/"parens", or "none". Default is "dash".',
+ ['--attribution'],
+ {'choices': ['dash', 'parentheses', 'parens', 'none'],
+ 'default': 'dash', 'metavar': '<format>'}),
+ ('Specify a stylesheet file. The file will be "input" by latex in '
+ 'the document header. Default is no stylesheet (""). '
+ 'Overrides --stylesheet-path.',
+ ['--stylesheet'],
+ {'default': '', 'metavar': '<file>',
+ 'overrides': 'stylesheet_path'}),
+ ('Specify a stylesheet file, relative to the current working '
+ 'directory. Overrides --stylesheet.',
+ ['--stylesheet-path'],
+ {'metavar': '<file>', 'overrides': 'stylesheet'}),
+ ('Table of contents by docutils (default) or latex. Latex (writer) '
+ 'supports only one ToC per document, but docutils does not write '
+ 'pagenumbers.',
+ ['--use-latex-toc'],
+ {'default': 0, 'action': 'store_true',
+ 'validator': frontend.validate_boolean}),
+ ('Let LaTeX print author and date, do not show it in docutils '
+ 'document info.',
+ ['--use-latex-docinfo'],
+ {'default': 0, 'action': 'store_true',
+ 'validator': frontend.validate_boolean}),
+ ('Color of any hyperlinks embedded in text '
+ '(default: "blue", "0" to disable).',
+ ['--hyperlink-color'], {'default': 'blue'}),
+ ('Enable compound enumerators for nested enumerated lists '
+ '(e.g. "1.2.a.ii"). Default: disabled.',
+ ['--compound-enumerators'],
+ {'default': None, 'action': 'store_true',
+ 'validator': frontend.validate_boolean}),
+ ('Disable compound enumerators for nested enumerated lists. This is '
+ 'the default.',
+ ['--no-compound-enumerators'],
+ {'action': 'store_false', 'dest': 'compound_enumerators'}),
+ ('Enable section ("." subsection ...) prefixes for compound '
+ 'enumerators. This has no effect without --compound-enumerators. '
+ 'Default: disabled.',
+ ['--section-prefix-for-enumerators'],
+ {'default': None, 'action': 'store_true',
+ 'validator': frontend.validate_boolean}),
+ ('Disable section prefixes for compound enumerators. '
+ 'This is the default.',
+ ['--no-section-prefix-for-enumerators'],
+ {'action': 'store_false', 'dest': 'section_prefix_for_enumerators'}),
+ ('Set the separator between section number and enumerator '
+ 'for compound enumerated lists. Default is "-".',
+ ['--section-enumerator-separator'],
+ {'default': '-', 'metavar': '<char>'}),
+ ('When possibile, use verbatim for literal-blocks. '
+ 'Default is to always use the mbox environment.',
+ ['--use-verbatim-when-possible'],
+ {'default': 0, 'action': 'store_true',
+ 'validator': frontend.validate_boolean}),
+ ('Table style. "standard" with horizontal and vertical lines, '
+ '"booktabs" (LaTeX booktabs style) only horizontal lines '
+ 'above and below the table and below the header or "nolines". '
+ 'Default: "standard"',
+ ['--table-style'],
+ {'choices': ['standard', 'booktabs','nolines'], 'default': 'standard',
+ 'metavar': '<format>'}),
+ ('LaTeX graphicx package option. '
+ 'Possible values are "dvips", "pdftex". "auto" includes LaTeX code '
+ 'to use "pdftex" if processing with pdf(la)tex and dvips otherwise. '
+ 'Default is no option.',
+ ['--graphicx-option'],
+ {'default': ''}),
+ ('LaTeX font encoding. '
+ 'Possible values are "T1", "OT1", "" or some other fontenc option. '
+ 'The font encoding influences available symbols, e.g. "<<" as one '
+ 'character. Default is "" which leads to package "ae" (a T1 '
+ 'emulation using CM fonts).',
+ ['--font-encoding'],
+ {'default': ''}),
+ ),)
+
+ settings_defaults = {'output_encoding': 'latin-1'}
+
+ relative_path_settings = ('stylesheet_path',)
+
+ config_section = 'latex2e writer'
+ config_section_dependencies = ('writers',)
+
+ output = None
+ """Final translated form of `document`."""
+
+ def __init__(self):
+ writers.Writer.__init__(self)
+ self.translator_class = LaTeXTranslator
+
+ def translate(self):
+ visitor = self.translator_class(self.document)
+ self.document.walkabout(visitor)
+ self.output = visitor.astext()
+ self.head_prefix = visitor.head_prefix
+ self.head = visitor.head
+ self.body_prefix = visitor.body_prefix
+ self.body = visitor.body
+ self.body_suffix = visitor.body_suffix
+
+"""
+Notes on LaTeX
+--------------
+
+* latex does not support multiple tocs in one document.
+ (might be no limitation except for docutils documentation)
+
+* width
+
+ * linewidth - width of a line in the local environment
+ * textwidth - the width of text on the page
+
+ Maybe always use linewidth ?
+
+ *Bug* inside a minipage a (e.g. Sidebar) the linewidth is
+ not changed, needs fix in docutils so that tables
+ are not too wide.
+
+ So we add locallinewidth set it initially and
+ on entering sidebar and reset on exit.
+"""
+
+class Babel:
+ """Language specifics for LaTeX."""
+ # country code by a.schlock.
+ # partly manually converted from iso and babel stuff, dialects and some
+ _ISO639_TO_BABEL = {
+ 'no': 'norsk', #XXX added by hand ( forget about nynorsk?)
+ 'gd': 'scottish', #XXX added by hand
+ 'hu': 'magyar', #XXX added by hand
+ 'pt': 'portuguese',#XXX added by hand
+ 'sl': 'slovenian',
+ 'af': 'afrikaans',
+ 'bg': 'bulgarian',
+ 'br': 'breton',
+ 'ca': 'catalan',
+ 'cs': 'czech',
+ 'cy': 'welsh',
+ 'da': 'danish',
+ 'fr': 'french',
+ # french, francais, canadien, acadian
+ 'de': 'ngerman', #XXX rather than german
+ # ngerman, naustrian, german, germanb, austrian
+ 'el': 'greek',
+ 'en': 'english',
+ # english, USenglish, american, UKenglish, british, canadian
+ 'eo': 'esperanto',
+ 'es': 'spanish',
+ 'et': 'estonian',
+ 'eu': 'basque',
+ 'fi': 'finnish',
+ 'ga': 'irish',
+ 'gl': 'galician',
+ 'he': 'hebrew',
+ 'hr': 'croatian',
+ 'hu': 'hungarian',
+ 'is': 'icelandic',
+ 'it': 'italian',
+ 'la': 'latin',
+ 'nl': 'dutch',
+ 'pl': 'polish',
+ 'pt': 'portuguese',
+ 'ro': 'romanian',
+ 'ru': 'russian',
+ 'sk': 'slovak',
+ 'sr': 'serbian',
+ 'sv': 'swedish',
+ 'tr': 'turkish',
+ 'uk': 'ukrainian'
+ }
+
+ def __init__(self,lang):
+ self.language = lang
+ # pdflatex does not produce double quotes for ngerman in tt.
+ self.double_quote_replacment = None
+ if re.search('^de',self.language):
+ #self.quotes = ("\"`", "\"'")
+ self.quotes = ('{\\glqq}', '{\\grqq}')
+ self.double_quote_replacment = "{\\dq}"
+ else:
+ self.quotes = ("``", "''")
+ self.quote_index = 0
+
+ def next_quote(self):
+ q = self.quotes[self.quote_index]
+ self.quote_index = (self.quote_index+1)%2
+ return q
+
+ def quote_quotes(self,text):
+ t = None
+ for part in text.split('"'):
+ if t == None:
+ t = part
+ else:
+ t += self.next_quote() + part
+ return t
+
+ def double_quotes_in_tt (self,text):
+ if not self.double_quote_replacment:
+ return text
+ return text.replace('"', self.double_quote_replacment)
+
+ def get_language(self):
+ if self._ISO639_TO_BABEL.has_key(self.language):
+ return self._ISO639_TO_BABEL[self.language]
+ else:
+ # support dialects.
+ l = self.language.split("_")[0]
+ if self._ISO639_TO_BABEL.has_key(l):
+ return self._ISO639_TO_BABEL[l]
+ return None
+
+
+latex_headings = {
+ 'optionlist_environment' : [
+ '\\newcommand{\\optionlistlabel}[1]{\\bf #1 \\hfill}\n'
+ '\\newenvironment{optionlist}[1]\n'
+ '{\\begin{list}{}\n'
+ ' {\\setlength{\\labelwidth}{#1}\n'
+ ' \\setlength{\\rightmargin}{1cm}\n'
+ ' \\setlength{\\leftmargin}{\\rightmargin}\n'
+ ' \\addtolength{\\leftmargin}{\\labelwidth}\n'
+ ' \\addtolength{\\leftmargin}{\\labelsep}\n'
+ ' \\renewcommand{\\makelabel}{\\optionlistlabel}}\n'
+ '}{\\end{list}}\n',
+ ],
+ 'lineblock_environment' : [
+ '\\newlength{\\lineblockindentation}\n'
+ '\\setlength{\\lineblockindentation}{2.5em}\n'
+ '\\newenvironment{lineblock}[1]\n'
+ '{\\begin{list}{}\n'
+ ' {\\setlength{\\partopsep}{\\parskip}\n'
+ ' \\addtolength{\\partopsep}{\\baselineskip}\n'
+ ' \\topsep0pt\\itemsep0.15\\baselineskip\\parsep0pt\n'
+ ' \\leftmargin#1}\n'
+ ' \\raggedright}\n'
+ '{\\end{list}}\n'
+ ],
+ 'footnote_floats' : [
+ '% begin: floats for footnotes tweaking.\n',
+ '\\setlength{\\floatsep}{0.5em}\n',
+ '\\setlength{\\textfloatsep}{\\fill}\n',
+ '\\addtolength{\\textfloatsep}{3em}\n',
+ '\\renewcommand{\\textfraction}{0.5}\n',
+ '\\renewcommand{\\topfraction}{0.5}\n',
+ '\\renewcommand{\\bottomfraction}{0.5}\n',
+ '\\setcounter{totalnumber}{50}\n',
+ '\\setcounter{topnumber}{50}\n',
+ '\\setcounter{bottomnumber}{50}\n',
+ '% end floats for footnotes\n',
+ ],
+ 'some_commands' : [
+ '% some commands, that could be overwritten in the style file.\n'
+ '\\newcommand{\\rubric}[1]'
+ '{\\subsection*{~\\hfill {\\it #1} \\hfill ~}}\n'
+ '\\newcommand{\\titlereference}[1]{\\textsl{#1}}\n'
+ '% end of "some commands"\n',
+ ]
+ }
+
+class DocumentClass:
+ """Details of a LaTeX document class."""
+
+ # BUG: LaTeX has no deeper sections (actually paragrah is no
+ # section either).
+ # BUG: No support for unknown document classes. Make 'article'
+ # default?
+ _class_sections = {
+ 'book': ( 'chapter', 'section', 'subsection', 'subsubsection' ),
+ 'scrbook': ( 'chapter', 'section', 'subsection', 'subsubsection' ),
+ 'report': ( 'chapter', 'section', 'subsection', 'subsubsection' ),
+ 'scrreprt': ( 'chapter', 'section', 'subsection', 'subsubsection' ),
+ 'article': ( 'section', 'subsection', 'subsubsection' ),
+ 'scrartcl': ( 'section', 'subsection', 'subsubsection' ),
+ }
+ _deepest_section = 'subsubsection'
+
+ def __init__(self, document_class):
+ self.document_class = document_class
+
+ def section(self, level):
+ """ Return the section name at the given level for the specific
+ document class.
+
+ Level is 1,2,3..., as level 0 is the title."""
+
+ sections = self._class_sections[self.document_class]
+ if level <= len(sections):
+ return sections[level-1]
+ else:
+ return self._deepest_section
+
+class Table:
+ """ Manage a table while traversing.
+ Maybe change to a mixin defining the visit/departs, but then
+ class Table internal variables are in the Translator.
+ """
+ def __init__(self,latex_type,table_style):
+ self._latex_type = latex_type
+ self._table_style = table_style
+ self._open = 0
+ # miscellaneous attributes
+ self._attrs = {}
+ self._col_width = []
+ self._rowspan = []
+
+ def open(self):
+ self._open = 1
+ self._col_specs = []
+ self.caption = None
+ self._attrs = {}
+ self._in_head = 0 # maybe context with search
+ def close(self):
+ self._open = 0
+ self._col_specs = None
+ self.caption = None
+ self._attrs = {}
+ def is_open(self):
+ return self._open
+ def used_packages(self):
+ if self._table_style == 'booktabs':
+ return '\\usepackage{booktabs}\n'
+ return ''
+ def get_latex_type(self):
+ return self._latex_type
+
+ def set(self,attr,value):
+ self._attrs[attr] = value
+ def get(self,attr):
+ if self._attrs.has_key(attr):
+ return self._attrs[attr]
+ return None
+ def get_vertical_bar(self):
+ if self._table_style == 'standard':
+ return '|'
+ return ''
+ # horizontal lines are drawn below a row, because we.
+ def get_opening(self):
+ return '\\begin{%s}[c]' % self._latex_type
+ def get_closing(self):
+ line = ""
+ if self._table_style == 'booktabs':
+ line = '\\bottomrule\n'
+ elif self._table_style == 'standard':
+ lines = '\\hline\n'
+ return '%s\\end{%s}' % (line,self._latex_type)
+
+ def visit_colspec(self,node):
+ self._col_specs.append(node)
+
+ def get_colspecs(self):
+ """
+ Return column specification for longtable.
+
+ Assumes reST line length being 80 characters.
+ Table width is hairy.
+
+ === ===
+ ABC DEF
+ === ===
+
+ usually gets to narrow, therefore we add 1 (fiddlefactor).
+ """
+ width = 80
+
+ total_width = 0.0
+ # first see if we get too wide.
+ for node in self._col_specs:
+ colwidth = float(node['colwidth']+1) / width
+ total_width += colwidth
+ self._col_width = []
+ self._rowspan = []
+ # donot make it full linewidth
+ factor = 0.93
+ if total_width > 1.0:
+ factor /= total_width
+ bar = self.get_vertical_bar()
+ latex_table_spec = ""
+ for node in self._col_specs:
+ colwidth = factor * float(node['colwidth']+1) / width
+ self._col_width.append(colwidth+0.005)
+ self._rowspan.append(0)
+ latex_table_spec += "%sp{%.2f\\locallinewidth}" % (bar,colwidth+0.005)
+ return latex_table_spec+bar
+
+ def get_column_width(self):
+ """ return columnwidth for current cell (not multicell)
+ """
+ return "%.2f\\locallinewidth" % self._col_width[self._cell_in_row-1]
+
+ def visit_thead(self):
+ self._in_thead = 1
+ if self._table_style == 'standard':
+ return ['\\hline\n']
+ elif self._table_style == 'booktabs':
+ return ['\\toprule\n']
+ return []
+ def depart_thead(self):
+ a = []
+ #if self._table_style == 'standard':
+ # a.append('\\hline\n')
+ if self._table_style == 'booktabs':
+ a.append('\\midrule\n')
+ a.append('\\endhead\n')
+ # for longtable one could add firsthead, foot and lastfoot
+ self._in_thead = 0
+ return a
+ def visit_row(self):
+ self._cell_in_row = 0
+ def depart_row(self):
+ res = [' \\\\\n']
+ self._cell_in_row = None # remove cell counter
+ for i in range(len(self._rowspan)):
+ if (self._rowspan[i]>0):
+ self._rowspan[i] -= 1
+
+ if self._table_style == 'standard':
+ rowspans = []
+ for i in range(len(self._rowspan)):
+ if (self._rowspan[i]<=0):
+ rowspans.append(i+1)
+ if len(rowspans)==len(self._rowspan):
+ res.append('\\hline\n')
+ else:
+ cline = ''
+ rowspans.reverse()
+ # TODO merge clines
+ while 1:
+ try:
+ c_start = rowspans.pop()
+ except:
+ break
+ cline += '\\cline{%d-%d}\n' % (c_start,c_start)
+ res.append(cline)
+ return res
+
+ def set_rowspan(self,cell,value):
+ try:
+ self._rowspan[cell] = value
+ except:
+ pass
+ def get_rowspan(self,cell):
+ try:
+ return self._rowspan[cell]
+ except:
+ return 0
+ def get_entry_number(self):
+ return self._cell_in_row
+ def visit_entry(self):
+ self._cell_in_row += 1
+
+
+class LaTeXTranslator(nodes.NodeVisitor):
+
+ # When options are given to the documentclass, latex will pass them
+ # to other packages, as done with babel.
+ # Dummy settings might be taken from document settings
+
+ latex_head = '\\documentclass[%s]{%s}\n'
+ encoding = '\\usepackage[%s]{inputenc}\n'
+ linking = '\\usepackage[colorlinks=%s,linkcolor=%s,urlcolor=%s]{hyperref}\n'
+ stylesheet = '\\input{%s}\n'
+ # add a generated on day , machine by user using docutils version.
+ generator = '%% generator Docutils: http://docutils.sourceforge.net/\n'
+
+ # use latex tableofcontents or let docutils do it.
+ use_latex_toc = 0
+
+ # TODO: use mixins for different implementations.
+ # list environment for option-list. else tabularx
+ use_optionlist_for_option_list = 1
+ # list environment for docinfo. else tabularx
+ use_optionlist_for_docinfo = 0 # NOT YET IN USE
+
+ # Use compound enumerations (1.A.1.)
+ compound_enumerators = 0
+
+ # If using compound enumerations, include section information.
+ section_prefix_for_enumerators = 0
+
+ # This is the character that separates the section ("." subsection ...)
+ # prefix from the regular list enumerator.
+ section_enumerator_separator = '-'
+
+ # default link color
+ hyperlink_color = "blue"
+
+ def __init__(self, document):
+ nodes.NodeVisitor.__init__(self, document)
+ self.settings = settings = document.settings
+ self.latex_encoding = self.to_latex_encoding(settings.output_encoding)
+ self.use_latex_toc = settings.use_latex_toc
+ self.use_latex_docinfo = settings.use_latex_docinfo
+ self.use_latex_footnotes = settings.use_latex_footnotes
+ self._use_latex_citations = settings.use_latex_citations
+ self.hyperlink_color = settings.hyperlink_color
+ self.compound_enumerators = settings.compound_enumerators
+ self.font_encoding = settings.font_encoding
+ self.section_prefix_for_enumerators = (
+ settings.section_prefix_for_enumerators)
+ self.section_enumerator_separator = (
+ settings.section_enumerator_separator.replace('_', '\\_'))
+ if self.hyperlink_color == '0':
+ self.hyperlink_color = 'black'
+ self.colorlinks = 'false'
+ else:
+ self.colorlinks = 'true'
+
+ # language: labels, bibliographic_fields, and author_separators.
+ # to allow writing labes for specific languages.
+ self.language = languages.get_language(settings.language_code)
+ self.babel = Babel(settings.language_code)
+ self.author_separator = self.language.author_separators[0]
+ self.d_options = self.settings.documentoptions
+ if self.babel.get_language():
+ self.d_options += ',%s' % \
+ self.babel.get_language()
+
+ self.d_class = DocumentClass(settings.documentclass)
+ # object for a table while proccessing.
+ self.active_table = Table('longtable',settings.table_style)
+
+ # HACK. Should have more sophisticated typearea handling.
+ if settings.documentclass.find('scr') == -1:
+ self.typearea = '\\usepackage[DIV12]{typearea}\n'
+ else:
+ if self.d_options.find('DIV') == -1 and self.d_options.find('BCOR') == -1:
+ self.typearea = '\\typearea{12}\n'
+ else:
+ self.typearea = ''
+
+ if self.font_encoding == 'OT1':
+ fontenc_header = ''
+ elif self.font_encoding == '':
+ fontenc_header = '\\usepackage{ae}\n\\usepackage{aeguill}\n'
+ else:
+ fontenc_header = '\\usepackage[%s]{fontenc}\n' % (self.font_encoding,)
+ input_encoding = self.encoding % self.latex_encoding
+ if self.settings.graphicx_option == '':
+ self.graphicx_package = '\\usepackage{graphicx}\n'
+ elif self.settings.graphicx_option.lower() == 'auto':
+ self.graphicx_package = '\n'.join(
+ ('%Check if we are compiling under latex or pdflatex',
+ '\\ifx\\pdftexversion\\undefined',
+ ' \\usepackage{graphicx}',
+ '\\else',
+ ' \\usepackage[pdftex]{graphicx}',
+ '\\fi\n'))
+ else:
+ self.graphicx_package = (
+ '\\usepackage[%s]{graphicx}\n' % self.settings.graphicx_option)
+
+ self.head_prefix = [
+ self.latex_head % (self.d_options,self.settings.documentclass),
+ '\\usepackage{babel}\n', # language is in documents settings.
+ fontenc_header,
+ '\\usepackage{shortvrb}\n', # allows verb in footnotes.
+ input_encoding,
+ # * tabularx: for docinfo, automatic width of columns, always on one page.
+ '\\usepackage{tabularx}\n',
+ '\\usepackage{longtable}\n',
+ self.active_table.used_packages(),
+ # possible other packages.
+ # * fancyhdr
+ # * ltxtable is a combination of tabularx and longtable (pagebreaks).
+ # but ??
+ #
+ # extra space between text in tables and the line above them
+ '\\setlength{\\extrarowheight}{2pt}\n',
+ '\\usepackage{amsmath}\n', # what fore amsmath.
+ self.graphicx_package,
+ '\\usepackage{color}\n',
+ '\\usepackage{multirow}\n',
+ '\\usepackage{ifthen}\n', # before hyperref!
+ self.linking % (self.colorlinks, self.hyperlink_color, self.hyperlink_color),
+ self.typearea,
+ self.generator,
+ # latex lengths
+ '\\newlength{\\admonitionwidth}\n',
+ '\\setlength{\\admonitionwidth}{0.9\\textwidth}\n'
+ # width for docinfo tablewidth
+ '\\newlength{\\docinfowidth}\n',
+ '\\setlength{\\docinfowidth}{0.9\\textwidth}\n'
+ # linewidth of current environment, so tables are not wider
+ # than the sidebar: using locallinewidth seems to defer evaluation
+ # of linewidth, this is fixing it.
+ '\\newlength{\\locallinewidth}\n',
+ # will be set later.
+ ]
+ self.head_prefix.extend( latex_headings['optionlist_environment'] )
+ self.head_prefix.extend( latex_headings['lineblock_environment'] )
+ self.head_prefix.extend( latex_headings['footnote_floats'] )
+ self.head_prefix.extend( latex_headings['some_commands'] )
+ ## stylesheet is last: so it might be possible to overwrite defaults.
+ stylesheet = utils.get_stylesheet_reference(settings)
+ if stylesheet:
+ settings.record_dependencies.add(stylesheet)
+ self.head_prefix.append(self.stylesheet % (stylesheet))
+
+ if self.linking: # and maybe check for pdf
+ self.pdfinfo = [ ]
+ self.pdfauthor = None
+ # pdftitle, pdfsubject, pdfauthor, pdfkeywords, pdfcreator, pdfproducer
+ else:
+ self.pdfinfo = None
+ # NOTE: Latex wants a date and an author, rst puts this into
+ # docinfo, so normally we donot want latex author/date handling.
+ # latex article has its own handling of date and author, deactivate.
+ # So we always emit \title{...} \author{...} \date{...}, even if the
+ # "..." are empty strings.
+ self.head = [ ]
+ # separate title, so we can appen subtitle.
+ self.title = ''
+ # if use_latex_docinfo: collects lists of author/organization/contact/address lines
+ self.author_stack = []
+ self.date = ''
+
+ self.body_prefix = ['\\raggedbottom\n']
+ self.body = []
+ self.body_suffix = ['\n']
+ self.section_level = 0
+ self.context = []
+ self.topic_classes = []
+ # column specification for tables
+ self.table_caption = None
+
+ # Flags to encode
+ # ---------------
+ # verbatim: to tell encode not to encode.
+ self.verbatim = 0
+ # insert_newline: to tell encode to replace blanks by "~".
+ self.insert_none_breaking_blanks = 0
+ # insert_newline: to tell encode to add latex newline.
+ self.insert_newline = 0
+ # mbox_newline: to tell encode to add mbox and newline.
+ self.mbox_newline = 0
+
+ # enumeration is done by list environment.
+ self._enum_cnt = 0
+
+ # Stack of section counters so that we don't have to use_latex_toc.
+ # This will grow and shrink as processing occurs.
+ # Initialized for potential first-level sections.
+ self._section_number = [0]
+
+ # The current stack of enumerations so that we can expand
+ # them into a compound enumeration
+ self._enumeration_counters = []
+
+ self._bibitems = []
+
+ # docinfo.
+ self.docinfo = None
+ # inside literal block: no quote mangling.
+ self.literal_block = 0
+ self.literal_block_stack = []
+ self.literal = 0
+ # true when encoding in math mode
+ self.mathmode = 0
+
+ def to_latex_encoding(self,docutils_encoding):
+ """
+ Translate docutils encoding name into latex's.
+
+ Default fallback method is remove "-" and "_" chars from docutils_encoding.
+
+ """
+ tr = { "iso-8859-1": "latin1", # west european
+ "iso-8859-2": "latin2", # east european
+ "iso-8859-3": "latin3", # esperanto, maltese
+ "iso-8859-4": "latin4", # north european,scandinavian, baltic
+ "iso-8859-5": "iso88595", # cyrillic (ISO)
+ "iso-8859-9": "latin5", # turkish
+ "iso-8859-15": "latin9", # latin9, update to latin1.
+ "mac_cyrillic": "maccyr", # cyrillic (on Mac)
+ "windows-1251": "cp1251", # cyrillic (on Windows)
+ "koi8-r": "koi8-r", # cyrillic (Russian)
+ "koi8-u": "koi8-u", # cyrillic (Ukrainian)
+ "windows-1250": "cp1250", #
+ "windows-1252": "cp1252", #
+ "us-ascii": "ascii", # ASCII (US)
+ # unmatched encodings
+ #"": "applemac",
+ #"": "ansinew", # windows 3.1 ansi
+ #"": "ascii", # ASCII encoding for the range 32--127.
+ #"": "cp437", # dos latine us
+ #"": "cp850", # dos latin 1
+ #"": "cp852", # dos latin 2
+ #"": "decmulti",
+ #"": "latin10",
+ #"iso-8859-6": "" # arabic
+ #"iso-8859-7": "" # greek
+ #"iso-8859-8": "" # hebrew
+ #"iso-8859-10": "" # latin6, more complete iso-8859-4
+ }
+ if tr.has_key(docutils_encoding.lower()):
+ return tr[docutils_encoding.lower()]
+ return docutils_encoding.translate(string.maketrans("",""),"_-").lower()
+
+ def language_label(self, docutil_label):
+ return self.language.labels[docutil_label]
+
+ latex_equivalents = {
+ u'\u00A0' : '~',
+ u'\u2013' : '{--}',
+ u'\u2014' : '{---}',
+ u'\u2018' : '`',
+ u'\u2019' : '\'',
+ u'\u201A' : ',',
+ u'\u201C' : '``',
+ u'\u201D' : '\'\'',
+ u'\u201E' : ',,',
+ u'\u2020' : '{\\dag}',
+ u'\u2021' : '{\\ddag}',
+ u'\u2026' : '{\\dots}',
+ u'\u2122' : '{\\texttrademark}',
+ u'\u21d4' : '{$\\Leftrightarrow$}',
+ }
+
+ def unicode_to_latex(self,text):
+ # see LaTeX codec
+ # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252124
+ # Only some special chracters are translated, for documents with many
+ # utf-8 chars one should use the LaTeX unicode package.
+ for uchar in self.latex_equivalents.keys():
+ text = text.replace(uchar,self.latex_equivalents[uchar])
+ return text
+
+ def encode(self, text):
+ """
+ Encode special characters (``# $ % & ~ _ ^ \ { }``) in `text` & return
+ """
+ # Escaping with a backslash does not help with backslashes, ~ and ^.
+
+ # < > are only available in math-mode or tt font. (really ?)
+ # $ starts math- mode.
+ # AND quotes
+ if self.verbatim:
+ return text
+ # compile the regexps once. do it here so one can see them.
+ #
+ # first the braces.
+ if not self.__dict__.has_key('encode_re_braces'):
+ self.encode_re_braces = re.compile(r'([{}])')
+ text = self.encode_re_braces.sub(r'{\\\1}',text)
+ if not self.__dict__.has_key('encode_re_bslash'):
+ # find backslash: except in the form '{\{}' or '{\}}'.
+ self.encode_re_bslash = re.compile(r'(?<!{)(\\)(?![{}]})')
+ # then the backslash: except in the form from line above:
+ # either '{\{}' or '{\}}'.
+ text = self.encode_re_bslash.sub(r'{\\textbackslash}', text)
+
+ # then dollar
+ text = text.replace("$", '{\\$}')
+ if not ( self.literal_block or self.literal or self.mathmode ):
+ # the vertical bar: in mathmode |,\vert or \mid
+ # in textmode \textbar
+ text = text.replace("|", '{\\textbar}')
+ text = text.replace("<", '{\\textless}')
+ text = text.replace(">", '{\\textgreater}')
+ # then
+ text = text.replace("&", '{\\&}')
+ # the ^:
+ # * verb|^| does not work in mbox.
+ # * mathmode has wedge. hat{~} would also work.
+ # text = text.replace("^", '{\\ensuremath{^\\wedge}}')
+ text = text.replace("^", '{\\textasciicircum}')
+ text = text.replace("%", '{\\%}')
+ text = text.replace("#", '{\\#}')
+ text = text.replace("~", '{\\textasciitilde}')
+ # Separate compound characters, e.g. "--" to "-{}-". (The
+ # actual separation is done later; see below.)
+ separate_chars = '-'
+ if self.literal_block or self.literal:
+ # In monospace-font, we also separate ",,", "``" and "''"
+ # and some other characters which can't occur in
+ # non-literal text.
+ separate_chars += ',`\'"<>'
+ # pdflatex does not produce doublequotes for ngerman.
+ text = self.babel.double_quotes_in_tt(text)
+ if self.font_encoding == 'OT1':
+ # We're using OT1 font-encoding and have to replace
+ # underscore by underlined blank, because this has
+ # correct width.
+ text = text.replace('_', '{\\underline{ }}')
+ # And the tt-backslash doesn't work in OT1, so we use
+ # a mirrored slash.
+ text = text.replace('\\textbackslash', '\\reflectbox{/}')
+ else:
+ text = text.replace('_', '{\\_}')
+ else:
+ text = self.babel.quote_quotes(text)
+ text = text.replace("_", '{\\_}')
+ for char in separate_chars * 2:
+ # Do it twice ("* 2") becaues otherwise we would replace
+ # "---" by "-{}--".
+ text = text.replace(char + char, char + '{}' + char)
+ if self.insert_newline or self.literal_block:
+ # Insert a blank before the newline, to avoid
+ # ! LaTeX Error: There's no line here to end.
+ text = text.replace("\n", '~\\\\\n')
+ elif self.mbox_newline:
+ if self.literal_block:
+ closings = "}" * len(self.literal_block_stack)
+ openings = "".join(self.literal_block_stack)
+ else:
+ closings = ""
+ openings = ""
+ text = text.replace("\n", "%s}\\\\\n\\mbox{%s" % (closings,openings))
+ text = text.replace('[', '{[}').replace(']', '{]}')
+ if self.insert_none_breaking_blanks:
+ text = text.replace(' ', '~')
+ if self.latex_encoding != 'utf8':
+ text = self.unicode_to_latex(text)
+ return text
+
+ def attval(self, text,
+ whitespace=re.compile('[\n\r\t\v\f]')):
+ """Cleanse, encode, and return attribute value text."""
+ return self.encode(whitespace.sub(' ', text))
+
+ def astext(self):
+ if self.pdfinfo is not None:
+ if self.pdfauthor:
+ self.pdfinfo.append('pdfauthor={%s}' % self.pdfauthor)
+ if self.pdfinfo:
+ pdfinfo = '\\hypersetup{\n' + ',\n'.join(self.pdfinfo) + '\n}\n'
+ else:
+ pdfinfo = ''
+ head = '\\title{%s}\n\\author{%s}\n\\date{%s}\n' % \
+ (self.title,
+ ' \\and\n'.join(['~\\\\\n'.join(author_lines)
+ for author_lines in self.author_stack]),
+ self.date)
+ return ''.join(self.head_prefix + [head] + self.head + [pdfinfo]
+ + self.body_prefix + self.body + self.body_suffix)
+
+ def visit_Text(self, node):
+ self.body.append(self.encode(node.astext()))
+
+ def depart_Text(self, node):
+ pass
+
+ def visit_address(self, node):
+ self.visit_docinfo_item(node, 'address')
+
+ def depart_address(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_admonition(self, node, name=''):
+ self.body.append('\\begin{center}\\begin{sffamily}\n')
+ self.body.append('\\fbox{\\parbox{\\admonitionwidth}{\n')
+ if name:
+ self.body.append('\\textbf{\\large '+ self.language.labels[name] + '}\n');
+ self.body.append('\\vspace{2mm}\n')
+
+
+ def depart_admonition(self, node=None):
+ self.body.append('}}\n') # end parbox fbox
+ self.body.append('\\end{sffamily}\n\\end{center}\n');
+
+ def visit_attention(self, node):
+ self.visit_admonition(node, 'attention')
+
+ def depart_attention(self, node):
+ self.depart_admonition()
+
+ def visit_author(self, node):
+ self.visit_docinfo_item(node, 'author')
+
+ def depart_author(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_authors(self, node):
+ # not used: visit_author is called anyway for each author.
+ pass
+
+ def depart_authors(self, node):
+ pass
+
+ def visit_block_quote(self, node):
+ self.body.append( '\\begin{quote}\n')
+
+ def depart_block_quote(self, node):
+ self.body.append( '\\end{quote}\n')
+
+ def visit_bullet_list(self, node):
+ if 'contents' in self.topic_classes:
+ if not self.use_latex_toc:
+ self.body.append( '\\begin{list}{}{}\n' )
+ else:
+ self.body.append( '\\begin{itemize}\n' )
+
+ def depart_bullet_list(self, node):
+ if 'contents' in self.topic_classes:
+ if not self.use_latex_toc:
+ self.body.append( '\\end{list}\n' )
+ else:
+ self.body.append( '\\end{itemize}\n' )
+
+ # Imperfect superscript/subscript handling: mathmode italicizes
+ # all letters by default.
+ def visit_superscript(self, node):
+ self.body.append('$^{')
+ self.mathmode = 1
+
+ def depart_superscript(self, node):
+ self.body.append('}$')
+ self.mathmode = 0
+
+ def visit_subscript(self, node):
+ self.body.append('$_{')
+ self.mathmode = 1
+
+ def depart_subscript(self, node):
+ self.body.append('}$')
+ self.mathmode = 0
+
+ def visit_caption(self, node):
+ self.body.append( '\\caption{' )
+
+ def depart_caption(self, node):
+ self.body.append('}')
+
+ def visit_caution(self, node):
+ self.visit_admonition(node, 'caution')
+
+ def depart_caution(self, node):
+ self.depart_admonition()
+
+ def visit_title_reference(self, node):
+ self.body.append( '\\titlereference{' )
+
+ def depart_title_reference(self, node):
+ self.body.append( '}' )
+
+ def visit_citation(self, node):
+ # TODO maybe use cite bibitems
+ if self._use_latex_citations:
+ self.context.append(len(self.body))
+ else:
+ self.body.append('\\begin{figure}[b]')
+ for id in node['ids']:
+ self.body.append('\\hypertarget{%s}' % id)
+
+ def depart_citation(self, node):
+ if self._use_latex_citations:
+ size = self.context.pop()
+ label = self.body[size]
+ text = ''.join(self.body[size+1:])
+ del self.body[size:]
+ self._bibitems.append([label, text])
+ else:
+ self.body.append('\\end{figure}\n')
+
+ def visit_citation_reference(self, node):
+ if self._use_latex_citations:
+ self.body.append('\\cite{')
+ else:
+ href = ''
+ if node.has_key('refid'):
+ href = node['refid']
+ elif node.has_key('refname'):
+ href = self.document.nameids[node['refname']]
+ self.body.append('[\\hyperlink{%s}{' % href)
+
+ def depart_citation_reference(self, node):
+ if self._use_latex_citations:
+ self.body.append('}')
+ else:
+ self.body.append('}]')
+
+ def visit_classifier(self, node):
+ self.body.append( '(\\textbf{' )
+
+ def depart_classifier(self, node):
+ self.body.append( '})\n' )
+
+ def visit_colspec(self, node):
+ self.active_table.visit_colspec(node)
+
+ def depart_colspec(self, node):
+ pass
+
+ def visit_comment(self, node):
+ # Escape end of line by a new comment start in comment text.
+ self.body.append('%% %s \n' % node.astext().replace('\n', '\n% '))
+ raise nodes.SkipNode
+
+ def visit_compound(self, node):
+ pass
+
+ def depart_compound(self, node):
+ pass
+
+ def visit_contact(self, node):
+ self.visit_docinfo_item(node, 'contact')
+
+ def depart_contact(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_container(self, node):
+ pass
+
+ def depart_container(self, node):
+ pass
+
+ def visit_copyright(self, node):
+ self.visit_docinfo_item(node, 'copyright')
+
+ def depart_copyright(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_danger(self, node):
+ self.visit_admonition(node, 'danger')
+
+ def depart_danger(self, node):
+ self.depart_admonition()
+
+ def visit_date(self, node):
+ self.visit_docinfo_item(node, 'date')
+
+ def depart_date(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_decoration(self, node):
+ pass
+
+ def depart_decoration(self, node):
+ pass
+
+ def visit_definition(self, node):
+ self.body.append('%[visit_definition]\n')
+
+ def depart_definition(self, node):
+ self.body.append('\n')
+ self.body.append('%[depart_definition]\n')
+
+ def visit_definition_list(self, node):
+ self.body.append( '\\begin{description}\n' )
+
+ def depart_definition_list(self, node):
+ self.body.append( '\\end{description}\n' )
+
+ def visit_definition_list_item(self, node):
+ self.body.append('%[visit_definition_list_item]\n')
+
+ def depart_definition_list_item(self, node):
+ self.body.append('%[depart_definition_list_item]\n')
+
+ def visit_description(self, node):
+ if self.use_optionlist_for_option_list:
+ self.body.append( ' ' )
+ else:
+ self.body.append( ' & ' )
+
+ def depart_description(self, node):
+ pass
+
+ def visit_docinfo(self, node):
+ self.docinfo = []
+ self.docinfo.append('%' + '_'*75 + '\n')
+ self.docinfo.append('\\begin{center}\n')
+ self.docinfo.append('\\begin{tabularx}{\\docinfowidth}{lX}\n')
+
+ def depart_docinfo(self, node):
+ self.docinfo.append('\\end{tabularx}\n')
+ self.docinfo.append('\\end{center}\n')
+ self.body = self.docinfo + self.body
+ # clear docinfo, so field names are no longer appended.
+ self.docinfo = None
+
+ def visit_docinfo_item(self, node, name):
+ if name == 'author':
+ if not self.pdfinfo == None:
+ if not self.pdfauthor:
+ self.pdfauthor = self.attval(node.astext())
+ else:
+ self.pdfauthor += self.author_separator + self.attval(node.astext())
+ if self.use_latex_docinfo:
+ if name in ('author', 'organization', 'contact', 'address'):
+ # We attach these to the last author. If any of them precedes
+ # the first author, put them in a separate "author" group (for
+ # no better semantics).
+ if name == 'author' or not self.author_stack:
+ self.author_stack.append([])
+ if name == 'address': # newlines are meaningful
+ self.insert_newline = 1
+ text = self.encode(node.astext())
+ self.insert_newline = 0
+ else:
+ text = self.attval(node.astext())
+ self.author_stack[-1].append(text)
+ raise nodes.SkipNode
+ elif name == 'date':
+ self.date = self.attval(node.astext())
+ raise nodes.SkipNode
+ self.docinfo.append('\\textbf{%s}: &\n\t' % self.language_label(name))
+ if name == 'address':
+ self.insert_newline = 1
+ self.docinfo.append('{\\raggedright\n')
+ self.context.append(' } \\\\\n')
+ else:
+ self.context.append(' \\\\\n')
+ self.context.append(self.docinfo)
+ self.context.append(len(self.body))
+
+ def depart_docinfo_item(self, node):
+ size = self.context.pop()
+ dest = self.context.pop()
+ tail = self.context.pop()
+ tail = self.body[size:] + [tail]
+ del self.body[size:]
+ dest.extend(tail)
+ # for address we did set insert_newline
+ self.insert_newline = 0
+
+ def visit_doctest_block(self, node):
+ self.body.append( '\\begin{verbatim}' )
+ self.verbatim = 1
+
+ def depart_doctest_block(self, node):
+ self.body.append( '\\end{verbatim}\n' )
+ self.verbatim = 0
+
+ def visit_document(self, node):
+ self.body_prefix.append('\\begin{document}\n')
+ # titled document?
+ if self.use_latex_docinfo or len(node) and isinstance(node[0], nodes.title):
+ self.body_prefix.append('\\maketitle\n\n')
+ # alternative use titlepage environment.
+ # \begin{titlepage}
+ self.body.append('\n\\setlength{\\locallinewidth}{\\linewidth}\n')
+
+ def depart_document(self, node):
+ # TODO insertion point of bibliography should none automatic.
+ if self._use_latex_citations and len(self._bibitems)>0:
+ widest_label = ""
+ for bi in self._bibitems:
+ if len(widest_label)<len(bi[0]):
+ widest_label = bi[0]
+ self.body.append('\n\\begin{thebibliography}{%s}\n'%widest_label)
+ for bi in self._bibitems:
+ # cite_key: underscores must not be escaped
+ cite_key = bi[0].replace(r"{\_}","_")
+ self.body.append('\\bibitem[%s]{%s}{%s}\n' % (bi[0], cite_key, bi[1]))
+ self.body.append('\\end{thebibliography}\n')
+
+ self.body_suffix.append('\\end{document}\n')
+
+ def visit_emphasis(self, node):
+ self.body.append('\\emph{')
+ self.literal_block_stack.append('\\emph{')
+
+ def depart_emphasis(self, node):
+ self.body.append('}')
+ self.literal_block_stack.pop()
+
+ def visit_entry(self, node):
+ self.active_table.visit_entry()
+ # cell separation
+ if self.active_table.get_entry_number() == 1:
+ # if the firstrow is a multirow, this actually is the second row.
+ # this gets hairy if rowspans follow each other.
+ if self.active_table.get_rowspan(0):
+ count = 0
+ while self.active_table.get_rowspan(count):
+ count += 1
+ self.body.append(' & ')
+ self.active_table.visit_entry() # increment cell count
+ else:
+ self.body.append(' & ')
+
+ # multi{row,column}
+ # IN WORK BUG TODO HACK continues here
+ # multirow in LaTeX simply will enlarge the cell over several rows
+ # (the following n if n is positive, the former if negative).
+ if node.has_key('morerows') and node.has_key('morecols'):
+ raise NotImplementedError('Cells that '
+ 'span multiple rows *and* columns are not supported, sorry.')
+ if node.has_key('morerows'):
+ count = node['morerows'] + 1
+ self.active_table.set_rowspan(self.active_table.get_entry_number()-1,count)
+ self.body.append('\\multirow{%d}{%s}{' % \
+ (count,self.active_table.get_column_width()))
+ self.context.append('}')
+ # BUG following rows must have empty cells.
+ elif node.has_key('morecols'):
+ # the vertical bar before column is missing if it is the first column.
+ # the one after always.
+ if self.active_table.get_entry_number() == 1:
+ bar1 = self.active_table.get_vertical_bar()
+ else:
+ bar1 = ''
+ count = node['morecols'] + 1
+ self.body.append('\\multicolumn{%d}{%sl%s}{' % \
+ (count, bar1, self.active_table.get_vertical_bar()))
+ self.context.append('}')
+ else:
+ self.context.append('')
+
+ # header / not header
+ if isinstance(node.parent.parent, nodes.thead):
+ self.body.append('\\textbf{')
+ self.context.append('}')
+ else:
+ self.context.append('')
+
+ def depart_entry(self, node):
+ self.body.append(self.context.pop()) # header / not header
+ self.body.append(self.context.pop()) # multirow/column
+ # if following row is spanned from above.
+ if self.active_table.get_rowspan(self.active_table.get_entry_number()):
+ self.body.append(' & ')
+ self.active_table.visit_entry() # increment cell count
+
+ def visit_row(self, node):
+ self.active_table.visit_row()
+
+ def depart_row(self, node):
+ self.body.extend(self.active_table.depart_row())
+
+ def visit_enumerated_list(self, node):
+ # We create our own enumeration list environment.
+ # This allows to set the style and starting value
+ # and unlimited nesting.
+ self._enum_cnt += 1
+
+ enum_style = {'arabic':'arabic',
+ 'loweralpha':'alph',
+ 'upperalpha':'Alph',
+ 'lowerroman':'roman',
+ 'upperroman':'Roman' }
+ enum_suffix = ""
+ if node.has_key('suffix'):
+ enum_suffix = node['suffix']
+ enum_prefix = ""
+ if node.has_key('prefix'):
+ enum_prefix = node['prefix']
+ if self.compound_enumerators:
+ pref = ""
+ if self.section_prefix_for_enumerators and self.section_level:
+ for i in range(self.section_level):
+ pref += '%d.' % self._section_number[i]
+ pref = pref[:-1] + self.section_enumerator_separator
+ enum_prefix += pref
+ for counter in self._enumeration_counters:
+ enum_prefix += counter + '.'
+ enum_type = "arabic"
+ if node.has_key('enumtype'):
+ enum_type = node['enumtype']
+ if enum_style.has_key(enum_type):
+ enum_type = enum_style[enum_type]
+ counter_name = "listcnt%d" % self._enum_cnt;
+ self._enumeration_counters.append("\\%s{%s}" % (enum_type,counter_name))
+ self.body.append('\\newcounter{%s}\n' % counter_name)
+ self.body.append('\\begin{list}{%s\\%s{%s}%s}\n' % \
+ (enum_prefix,enum_type,counter_name,enum_suffix))
+ self.body.append('{\n')
+ self.body.append('\\usecounter{%s}\n' % counter_name)
+ # set start after usecounter, because it initializes to zero.
+ if node.has_key('start'):
+ self.body.append('\\addtocounter{%s}{%d}\n' \
+ % (counter_name,node['start']-1))
+ ## set rightmargin equal to leftmargin
+ self.body.append('\\setlength{\\rightmargin}{\\leftmargin}\n')
+ self.body.append('}\n')
+
+ def depart_enumerated_list(self, node):
+ self.body.append('\\end{list}\n')
+ self._enumeration_counters.pop()
+
+ def visit_error(self, node):
+ self.visit_admonition(node, 'error')
+
+ def depart_error(self, node):
+ self.depart_admonition()
+
+ def visit_field(self, node):
+ # real output is done in siblings: _argument, _body, _name
+ pass
+
+ def depart_field(self, node):
+ self.body.append('\n')
+ ##self.body.append('%[depart_field]\n')
+
+ def visit_field_argument(self, node):
+ self.body.append('%[visit_field_argument]\n')
+
+ def depart_field_argument(self, node):
+ self.body.append('%[depart_field_argument]\n')
+
+ def visit_field_body(self, node):
+ # BUG by attach as text we loose references.
+ if self.docinfo:
+ self.docinfo.append('%s \\\\\n' % self.encode(node.astext()))
+ raise nodes.SkipNode
+ # BUG: what happens if not docinfo
+
+ def depart_field_body(self, node):
+ self.body.append( '\n' )
+
+ def visit_field_list(self, node):
+ if not self.docinfo:
+ self.body.append('\\begin{quote}\n')
+ self.body.append('\\begin{description}\n')
+
+ def depart_field_list(self, node):
+ if not self.docinfo:
+ self.body.append('\\end{description}\n')
+ self.body.append('\\end{quote}\n')
+
+ def visit_field_name(self, node):
+ # BUG this duplicates docinfo_item
+ if self.docinfo:
+ self.docinfo.append('\\textbf{%s}: &\n\t' % self.encode(node.astext()))
+ raise nodes.SkipNode
+ else:
+ self.body.append('\\item [')
+
+ def depart_field_name(self, node):
+ if not self.docinfo:
+ self.body.append(':]')
+
+ def visit_figure(self, node):
+ if not node.attributes.has_key('align'):
+ align = 'center'
+ else:
+ align = 'flush'+node.attributes['align']
+ self.body.append( '\\begin{figure}[htbp]\\begin{%s}\n' % align )
+ self.context.append( '\\end{%s}\\end{figure}\n' % align )
+
+ def depart_figure(self, node):
+ self.body.append( self.context.pop() )
+
+ def visit_footer(self, node):
+ self.context.append(len(self.body))
+
+ def depart_footer(self, node):
+ start = self.context.pop()
+ footer = (['\n\\begin{center}\small\n']
+ + self.body[start:] + ['\n\\end{center}\n'])
+ self.body_suffix[:0] = footer
+ del self.body[start:]
+
+ def visit_footnote(self, node):
+ if self.use_latex_footnotes:
+ num,text = node.astext().split(None,1)
+ num = self.encode(num.strip())
+ self.body.append('\\footnotetext['+num+']')
+ self.body.append('{')
+ else:
+ self.body.append('\\begin{figure}[b]')
+ for id in node['ids']:
+ self.body.append('\\hypertarget{%s}' % id)
+
+ def depart_footnote(self, node):
+ if self.use_latex_footnotes:
+ self.body.append('}\n')
+ else:
+ self.body.append('\\end{figure}\n')
+
+ def visit_footnote_reference(self, node):
+ if self.use_latex_footnotes:
+ self.body.append("\\footnotemark["+self.encode(node.astext())+"]")
+ raise nodes.SkipNode
+ href = ''
+ if node.has_key('refid'):
+ href = node['refid']
+ elif node.has_key('refname'):
+ href = self.document.nameids[node['refname']]
+ format = self.settings.footnote_references
+ if format == 'brackets':
+ suffix = '['
+ self.context.append(']')
+ elif format == 'superscript':
+ suffix = '\\raisebox{.5em}[0em]{\\scriptsize'
+ self.context.append('}')
+ else: # shouldn't happen
+ raise AssertionError('Illegal footnote reference format.')
+ self.body.append('%s\\hyperlink{%s}{' % (suffix,href))
+
+ def depart_footnote_reference(self, node):
+ if self.use_latex_footnotes:
+ return
+ self.body.append('}%s' % self.context.pop())
+
+ # footnote/citation label
+ def label_delim(self, node, bracket, superscript):
+ if isinstance(node.parent, nodes.footnote):
+ if self.use_latex_footnotes:
+ raise nodes.SkipNode
+ if self.settings.footnote_references == 'brackets':
+ self.body.append(bracket)
+ else:
+ self.body.append(superscript)
+ else:
+ assert isinstance(node.parent, nodes.citation)
+ if not self._use_latex_citations:
+ self.body.append(bracket)
+
+ def visit_label(self, node):
+ self.label_delim(node, '[', '$^{')
+
+ def depart_label(self, node):
+ self.label_delim(node, ']', '}$')
+
+ # elements generated by the framework e.g. section numbers.
+ def visit_generated(self, node):
+ pass
+
+ def depart_generated(self, node):
+ pass
+
+ def visit_header(self, node):
+ self.context.append(len(self.body))
+
+ def depart_header(self, node):
+ start = self.context.pop()
+ self.body_prefix.append('\n\\verb|begin_header|\n')
+ self.body_prefix.extend(self.body[start:])
+ self.body_prefix.append('\n\\verb|end_header|\n')
+ del self.body[start:]
+
+ def visit_hint(self, node):
+ self.visit_admonition(node, 'hint')
+
+ def depart_hint(self, node):
+ self.depart_admonition()
+
+ def visit_image(self, node):
+ attrs = node.attributes
+ # Add image URI to dependency list, assuming that it's
+ # referring to a local file.
+ self.settings.record_dependencies.add(attrs['uri'])
+ pre = [] # in reverse order
+ post = []
+ include_graphics_options = ""
+ inline = isinstance(node.parent, nodes.TextElement)
+ if attrs.has_key('scale'):
+ # Could also be done with ``scale`` option to
+ # ``\includegraphics``; doing it this way for consistency.
+ pre.append('\\scalebox{%f}{' % (attrs['scale'] / 100.0,))
+ post.append('}')
+ if attrs.has_key('width'):
+ include_graphics_options = '[width=%s]' % attrs['width']
+ if attrs.has_key('align'):
+ align_prepost = {
+ # By default latex aligns the top of an image.
+ (1, 'top'): ('', ''),
+ (1, 'middle'): ('\\raisebox{-0.5\\height}{', '}'),
+ (1, 'bottom'): ('\\raisebox{-\\height}{', '}'),
+ (0, 'center'): ('{\\hfill', '\\hfill}'),
+ # These 2 don't exactly do the right thing. The image should
+ # be floated alongside the paragraph. See
+ # http://www.w3.org/TR/html4/struct/objects.html#adef-align-IMG
+ (0, 'left'): ('{', '\\hfill}'),
+ (0, 'right'): ('{\\hfill', '}'),}
+ try:
+ pre.append(align_prepost[inline, attrs['align']][0])
+ post.append(align_prepost[inline, attrs['align']][1])
+ except KeyError:
+ pass # XXX complain here?
+ if not inline:
+ pre.append('\n')
+ post.append('\n')
+ pre.reverse()
+ self.body.extend( pre )
+ self.body.append( '\\includegraphics%s{%s}' % (
+ include_graphics_options, attrs['uri'] ) )
+ self.body.extend( post )
+
+ def depart_image(self, node):
+ pass
+
+ def visit_important(self, node):
+ self.visit_admonition(node, 'important')
+
+ def depart_important(self, node):
+ self.depart_admonition()
+
+ def visit_interpreted(self, node):
+ # @@@ Incomplete, pending a proper implementation on the
+ # Parser/Reader end.
+ self.visit_literal(node)
+
+ def depart_interpreted(self, node):
+ self.depart_literal(node)
+
+ def visit_legend(self, node):
+ self.body.append('{\\small ')
+
+ def depart_legend(self, node):
+ self.body.append('}')
+
+ def visit_line(self, node):
+ self.body.append('\item[] ')
+
+ def depart_line(self, node):
+ self.body.append('\n')
+
+ def visit_line_block(self, node):
+ if isinstance(node.parent, nodes.line_block):
+ self.body.append('\\item[] \n'
+ '\\begin{lineblock}{\\lineblockindentation}\n')
+ else:
+ self.body.append('\n\\begin{lineblock}{0em}\n')
+
+ def depart_line_block(self, node):
+ self.body.append('\\end{lineblock}\n')
+
+ def visit_list_item(self, node):
+ # Append "{}" in case the next character is "[", which would break
+ # LaTeX's list environment (no numbering and the "[" is not printed).
+ self.body.append('\\item {} ')
+
+ def depart_list_item(self, node):
+ self.body.append('\n')
+
+ def visit_literal(self, node):
+ self.literal = 1
+ self.body.append('\\texttt{')
+
+ def depart_literal(self, node):
+ self.body.append('}')
+ self.literal = 0
+
+ def visit_literal_block(self, node):
+ """
+ Render a literal-block.
+
+ Literal blocks are used for "::"-prefixed literal-indented
+ blocks of text, where the inline markup is not recognized,
+ but are also the product of the parsed-literal directive,
+ where the markup is respected.
+ """
+ # In both cases, we want to use a typewriter/monospaced typeface.
+ # For "real" literal-blocks, we can use \verbatim, while for all
+ # the others we must use \mbox.
+ #
+ # We can distinguish between the two kinds by the number of
+ # siblings the compose this node: if it is composed by a
+ # single element, it's surely is either a real one, otherwise
+ # it's a parsed-literal that does not contain any markup.
+ #
+ if (self.settings.use_verbatim_when_possible and (len(node) == 1)
+ # in case of a parsed-literal containing just a "**bold**" word:
+ and isinstance(node[0], nodes.Text)):
+ self.verbatim = 1
+ self.body.append('\\begin{quote}\\begin{verbatim}\n')
+ else:
+ self.literal_block = 1
+ self.insert_none_breaking_blanks = 1
+ if self.active_table.is_open():
+ self.body.append('\n{\\ttfamily \\raggedright \\noindent\n')
+ else:
+ # no quote inside tables, to avoid vertical sppace between
+ # table border and literal block.
+ # BUG: fails if normal text preceeds the literal block.
+ self.body.append('\\begin{quote}')
+ self.body.append('{\\ttfamily \\raggedright \\noindent\n')
+ # * obey..: is from julien and never worked for me (grubert).
+ # self.body.append('{\\obeylines\\obeyspaces\\ttfamily\n')
+
+ def depart_literal_block(self, node):
+ if self.verbatim:
+ self.body.append('\n\\end{verbatim}\\end{quote}\n')
+ self.verbatim = 0
+ else:
+ if self.active_table.is_open():
+ self.body.append('\n}\n')
+ else:
+ self.body.append('\n')
+ self.body.append('}\\end{quote}\n')
+ self.insert_none_breaking_blanks = 0
+ self.literal_block = 0
+ # obey end: self.body.append('}\n')
+
+ def visit_meta(self, node):
+ self.body.append('[visit_meta]\n')
+ # BUG maybe set keywords for pdf
+ ##self.head.append(self.starttag(node, 'meta', **node.attributes))
+
+ def depart_meta(self, node):
+ self.body.append('[depart_meta]\n')
+
+ def visit_note(self, node):
+ self.visit_admonition(node, 'note')
+
+ def depart_note(self, node):
+ self.depart_admonition()
+
+ def visit_option(self, node):
+ if self.context[-1]:
+ # this is not the first option
+ self.body.append(', ')
+
+ def depart_option(self, node):
+ # flag tha the first option is done.
+ self.context[-1] += 1
+
+ def visit_option_argument(self, node):
+ """The delimiter betweeen an option and its argument."""
+ self.body.append(node.get('delimiter', ' '))
+
+ def depart_option_argument(self, node):
+ pass
+
+ def visit_option_group(self, node):
+ if self.use_optionlist_for_option_list:
+ self.body.append('\\item [')
+ else:
+ if len(node.astext()) > 14:
+ self.body.append('\\multicolumn{2}{l}{')
+ self.context.append('} \\\\\n ')
+ else:
+ self.context.append('')
+ self.body.append('\\texttt{')
+ # flag for first option
+ self.context.append(0)
+
+ def depart_option_group(self, node):
+ self.context.pop() # the flag
+ if self.use_optionlist_for_option_list:
+ self.body.append('] ')
+ else:
+ self.body.append('}')
+ self.body.append(self.context.pop())
+
+ def visit_option_list(self, node):
+ self.body.append('% [option list]\n')
+ if self.use_optionlist_for_option_list:
+ self.body.append('\\begin{optionlist}{3cm}\n')
+ else:
+ self.body.append('\\begin{center}\n')
+ # BUG: use admwidth or make it relative to textwidth ?
+ self.body.append('\\begin{tabularx}{.9\\linewidth}{lX}\n')
+
+ def depart_option_list(self, node):
+ if self.use_optionlist_for_option_list:
+ self.body.append('\\end{optionlist}\n')
+ else:
+ self.body.append('\\end{tabularx}\n')
+ self.body.append('\\end{center}\n')
+
+ def visit_option_list_item(self, node):
+ pass
+
+ def depart_option_list_item(self, node):
+ if not self.use_optionlist_for_option_list:
+ self.body.append('\\\\\n')
+
+ def visit_option_string(self, node):
+ ##self.body.append(self.starttag(node, 'span', '', CLASS='option'))
+ pass
+
+ def depart_option_string(self, node):
+ ##self.body.append('</span>')
+ pass
+
+ def visit_organization(self, node):
+ self.visit_docinfo_item(node, 'organization')
+
+ def depart_organization(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_paragraph(self, node):
+ index = node.parent.index(node)
+ if not ('contents' in self.topic_classes or
+ (isinstance(node.parent, nodes.compound) and
+ index > 0 and
+ not isinstance(node.parent[index - 1], nodes.paragraph) and
+ not isinstance(node.parent[index - 1], nodes.compound))):
+ self.body.append('\n')
+
+ def depart_paragraph(self, node):
+ self.body.append('\n')
+
+ def visit_problematic(self, node):
+ self.body.append('{\\color{red}\\bfseries{}')
+
+ def depart_problematic(self, node):
+ self.body.append('}')
+
+ def visit_raw(self, node):
+ if 'latex' in node.get('format', '').split():
+ self.body.append(node.astext())
+ raise nodes.SkipNode
+
+ def visit_reference(self, node):
+ # BUG: hash_char "#" is trouble some in LaTeX.
+ # mbox and other environment do not like the '#'.
+ hash_char = '\\#'
+ if node.has_key('refuri'):
+ href = node['refuri'].replace('#',hash_char)
+ elif node.has_key('refid'):
+ href = hash_char + node['refid']
+ elif node.has_key('refname'):
+ href = hash_char + self.document.nameids[node['refname']]
+ else:
+ raise AssertionError('Unknown reference.')
+ self.body.append('\\href{%s}{' % href)
+
+ def depart_reference(self, node):
+ self.body.append('}')
+
+ def visit_revision(self, node):
+ self.visit_docinfo_item(node, 'revision')
+
+ def depart_revision(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_section(self, node):
+ self.section_level += 1
+ # Initialize counter for potential subsections:
+ self._section_number.append(0)
+ # Counter for this section's level (initialized by parent section):
+ self._section_number[self.section_level - 1] += 1
+
+ def depart_section(self, node):
+ # Remove counter for potential subsections:
+ self._section_number.pop()
+ self.section_level -= 1
+
+ def visit_sidebar(self, node):
+ # BUG: this is just a hack to make sidebars render something
+ self.body.append('\n\\setlength{\\locallinewidth}{0.9\\admonitionwidth}\n')
+ self.body.append('\\begin{center}\\begin{sffamily}\n')
+ self.body.append('\\fbox{\\colorbox[gray]{0.80}{\\parbox{\\admonitionwidth}{\n')
+
+ def depart_sidebar(self, node):
+ self.body.append('}}}\n') # end parbox colorbox fbox
+ self.body.append('\\end{sffamily}\n\\end{center}\n');
+ self.body.append('\n\\setlength{\\locallinewidth}{\\linewidth}\n')
+
+
+ attribution_formats = {'dash': ('---', ''),
+ 'parentheses': ('(', ')'),
+ 'parens': ('(', ')'),
+ 'none': ('', '')}
+
+ def visit_attribution(self, node):
+ prefix, suffix = self.attribution_formats[self.settings.attribution]
+ self.body.append('\n\\begin{flushright}\n')
+ self.body.append(prefix)
+ self.context.append(suffix)
+
+ def depart_attribution(self, node):
+ self.body.append(self.context.pop() + '\n')
+ self.body.append('\\end{flushright}\n')
+
+ def visit_status(self, node):
+ self.visit_docinfo_item(node, 'status')
+
+ def depart_status(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_strong(self, node):
+ self.body.append('\\textbf{')
+ self.literal_block_stack.append('\\textbf{')
+
+ def depart_strong(self, node):
+ self.body.append('}')
+ self.literal_block_stack.pop()
+
+ def visit_substitution_definition(self, node):
+ raise nodes.SkipNode
+
+ def visit_substitution_reference(self, node):
+ self.unimplemented_visit(node)
+
+ def visit_subtitle(self, node):
+ if isinstance(node.parent, nodes.sidebar):
+ self.body.append('~\\\\\n\\textbf{')
+ self.context.append('}\n\\smallskip\n')
+ elif isinstance(node.parent, nodes.document):
+ self.title = self.title + \
+ '\\\\\n\\large{%s}\n' % self.encode(node.astext())
+ raise nodes.SkipNode
+ elif isinstance(node.parent, nodes.section):
+ self.body.append('\\textbf{')
+ self.context.append('}\\vspace{0.2cm}\n\n\\noindent ')
+
+ def depart_subtitle(self, node):
+ self.body.append(self.context.pop())
+
+ def visit_system_message(self, node):
+ pass
+
+ def depart_system_message(self, node):
+ self.body.append('\n')
+
+ def visit_table(self, node):
+ if self.active_table.is_open():
+ print 'nested tables are not supported'
+ raise AssertionError
+ self.active_table.open()
+ self.body.append('\n' + self.active_table.get_opening())
+
+ def depart_table(self, node):
+ self.body.append(self.active_table.get_closing() + '\n')
+ self.active_table.close()
+
+ def visit_target(self, node):
+ # BUG: why not (refuri or refid or refname) means not footnote ?
+ if not (node.has_key('refuri') or node.has_key('refid')
+ or node.has_key('refname')):
+ for id in node['ids']:
+ self.body.append('\\hypertarget{%s}{' % id)
+ self.context.append('}' * len(node['ids']))
+ else:
+ self.context.append('')
+
+ def depart_target(self, node):
+ self.body.append(self.context.pop())
+
+ def visit_tbody(self, node):
+ # BUG write preamble if not yet done (colspecs not [])
+ # for tables without heads.
+ if not self.active_table.get('preamble written'):
+ self.visit_thead(None)
+ # self.depart_thead(None)
+
+ def depart_tbody(self, node):
+ pass
+
+ def visit_term(self, node):
+ self.body.append('\\item[{')
+
+ def depart_term(self, node):
+ # definition list term.
+ self.body.append('}] ')
+
+ def visit_tgroup(self, node):
+ #self.body.append(self.starttag(node, 'colgroup'))
+ #self.context.append('</colgroup>\n')
+ pass
+
+ def depart_tgroup(self, node):
+ pass
+
+ def visit_thead(self, node):
+ self.body.append('{%s}\n' % self.active_table.get_colspecs())
+ if self.active_table.caption:
+ self.body.append('\\caption{%s}\\\\\n' % self.active_table.caption)
+ self.active_table.set('preamble written',1)
+ # TODO longtable supports firsthead and lastfoot too.
+ self.body.extend(self.active_table.visit_thead())
+
+ def depart_thead(self, node):
+ # the table header written should be on every page
+ # => \endhead
+ self.body.extend(self.active_table.depart_thead())
+ # and the firsthead => \endfirsthead
+ # BUG i want a "continued from previous page" on every not
+ # firsthead, but then we need the header twice.
+ #
+ # there is a \endfoot and \endlastfoot too.
+ # but we need the number of columns to
+ # self.body.append('\\multicolumn{%d}{c}{"..."}\n' % number_of_columns)
+ # self.body.append('\\hline\n\\endfoot\n')
+ # self.body.append('\\hline\n')
+ # self.body.append('\\endlastfoot\n')
+
+ def visit_tip(self, node):
+ self.visit_admonition(node, 'tip')
+
+ def depart_tip(self, node):
+ self.depart_admonition()
+
+ def bookmark(self, node):
+ """Append latex href and pdfbookmarks for titles.
+ """
+ if node.parent['ids']:
+ for id in node.parent['ids']:
+ self.body.append('\\hypertarget{%s}{}\n' % id)
+ if not self.use_latex_toc:
+ # BUG level depends on style. pdflatex allows level 0 to 3
+ # ToC would be the only on level 0 so i choose to decrement the rest.
+ # "Table of contents" bookmark to see the ToC. To avoid this
+ # we set all zeroes to one.
+ l = self.section_level
+ if l>0:
+ l = l-1
+ # pdftex does not like "_" subscripts in titles
+ text = self.encode(node.astext())
+ for id in node.parent['ids']:
+ self.body.append('\\pdfbookmark[%d]{%s}{%s}\n' % \
+ (l, text, id))
+
+ def visit_title(self, node):
+ """Only 3 section levels are supported by LaTeX article (AFAIR)."""
+
+ if isinstance(node.parent, nodes.topic):
+ # section titles before the table of contents.
+ self.bookmark(node)
+ # BUG: latex chokes on center environment with "perhaps a missing item".
+ # so we use hfill.
+ self.body.append('\\subsubsection*{~\\hfill ')
+ # the closing brace for subsection.
+ self.context.append('\\hfill ~}\n')
+ # TODO: for admonition titles before the first section
+ # either specify every possible node or ... ?
+ elif isinstance(node.parent, nodes.sidebar) \
+ or isinstance(node.parent, nodes.admonition):
+ self.body.append('\\textbf{\\large ')
+ self.context.append('}\n\\smallskip\n')
+ elif isinstance(node.parent, nodes.table):
+ # caption must be written after column spec
+ self.active_table.caption = self.encode(node.astext())
+ raise nodes.SkipNode
+ elif self.section_level == 0:
+ # document title
+ self.title = self.encode(node.astext())
+ if not self.pdfinfo == None:
+ self.pdfinfo.append( 'pdftitle={%s}' % self.encode(node.astext()) )
+ raise nodes.SkipNode
+ else:
+ self.body.append('\n\n')
+ self.body.append('%' + '_' * 75)
+ self.body.append('\n\n')
+ self.bookmark(node)
+
+ if self.use_latex_toc:
+ section_star = ""
+ else:
+ section_star = "*"
+
+ section_name = self.d_class.section(self.section_level)
+ self.body.append('\\%s%s{' % (section_name, section_star))
+
+ self.context.append('}\n')
+
+ def depart_title(self, node):
+ self.body.append(self.context.pop())
+
+ def visit_topic(self, node):
+ self.topic_classes = node['classes']
+ if 'contents' in node['classes'] and self.use_latex_toc:
+ self.body.append('\\tableofcontents\n\n\\bigskip\n')
+ self.topic_classes = []
+ raise nodes.SkipNode
+
+ def visit_inline(self, node): # titlereference
+ self.body.append( '\\docutilsrole%s{' % node.get('class'))
+
+ def depart_inline(self, node):
+ self.body.append( '}' )
+
+ def depart_topic(self, node):
+ self.topic_classes = []
+ self.body.append('\n')
+
+ def visit_rubric(self, node):
+ self.body.append('\\rubric{')
+ self.context.append('}\n')
+
+ def depart_rubric(self, node):
+ self.body.append(self.context.pop())
+
+ def visit_transition(self, node):
+ self.body.append('\n\n')
+ self.body.append('%' + '_' * 75)
+ self.body.append('\n\\hspace*{\\fill}\\hrulefill\\hspace*{\\fill}')
+ self.body.append('\n\n')
+
+ def depart_transition(self, node):
+ pass
+
+ def visit_version(self, node):
+ self.visit_docinfo_item(node, 'version')
+
+ def depart_version(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_warning(self, node):
+ self.visit_admonition(node, 'warning')
+
+ def depart_warning(self, node):
+ self.depart_admonition()
+
+ def unimplemented_visit(self, node):
+ raise NotImplementedError('visiting unimplemented node type: %s'
+ % node.__class__.__name__)
+
+# def unknown_visit(self, node):
+# def default_visit(self, node):
+
+# vim: set ts=4 et ai :
diff --git a/docutils/writers/latex2e/latex2e.tex b/docutils/writers/latex2e/latex2e.tex
new file mode 100644
index 000000000..6e041a14b
--- /dev/null
+++ b/docutils/writers/latex2e/latex2e.tex
@@ -0,0 +1,74 @@
+% latex include file for docutils latex writer
+% --------------------------------------------
+%
+% CVS: $Id$
+%
+% This is included at the end of the latex header in the generated file,
+% to allow overwriting defaults, although this could get hairy.
+% Generated files should process well standalone too, LaTeX might give a
+% message about a missing file.
+
+% donot indent first line of paragraph.
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{5pt plus 2pt minus 1pt}
+
+% sloppy
+% ------
+% Less strict (opposite to default fussy) space size between words. Therefore
+% less hyphenation.
+\sloppy
+
+% fonts
+% -----
+% times for pdf generation, gives smaller pdf files.
+%
+% But in standard postscript fonts: courier and times/helvetica do not fit.
+% Maybe use pslatex.
+\usepackage{times}
+
+% pagestyle
+% ---------
+% headings might put section titles in the page heading, but not if
+% the table of contents is done by docutils.
+% If pagestyle{headings} is used, \geometry{headheight=10pt,headsep=1pt}
+% should be set too.
+%\pagestyle{plain}
+%
+% or use fancyhdr (untested !)
+%\usepackage{fancyhdr}
+%\pagestyle{fancy}
+%\addtolength{\headheight}{\\baselineskip}
+%\renewcommand{\sectionmark}[1]{\markboth{#1}{}}
+%\renewcommand{\subsectionmark}[1]{\markright{#1}}
+%\fancyhf{}
+%\fancyhead[LE,RO]{\\bfseries\\textsf{\Large\\thepage}}
+%\fancyhead[LO]{\\textsf{\\footnotesize\\rightmark}}
+%\fancyhead[RE]{\\textsc{\\textsf{\\footnotesize\leftmark}}}
+%\\fancyfoot[LE,RO]{\\bfseries\\textsf{\scriptsize Docutils}}
+%\fancyfoot[RE,LO]{\\textsf{\scriptsize\\today}}
+
+% geometry
+% --------
+% = papersizes and margins
+%\geometry{a4paper,twoside,tmargin=1.5cm,
+% headheight=1cm,headsep=0.75cm}
+
+% Do section number display
+% -------------------------
+%\makeatletter
+%\def\@seccntformat#1{}
+%\makeatother
+% no numbers in toc
+%\renewcommand{\numberline}[1]{}
+
+
+% change maketitle
+% ----------------
+%\renewcommand{\maketitle}{
+% \begin{titlepage}
+% \begin{center}
+% \textsf{TITLE \@title} \\
+% Date: \today
+% \end{center}
+% \end{titlepage}
+%}
diff --git a/docutils/writers/newlatex2e/__init__.py b/docutils/writers/newlatex2e/__init__.py
new file mode 100644
index 000000000..e46866d0d
--- /dev/null
+++ b/docutils/writers/newlatex2e/__init__.py
@@ -0,0 +1,788 @@
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+LaTeX2e document tree Writer.
+"""
+
+# Thanks to Engelbert Gruber and various contributors for the original
+# LaTeX writer, some code and many ideas of which have been used for
+# this writer.
+
+__docformat__ = 'reStructuredText'
+
+
+import re
+import os.path
+from types import ListType
+
+import docutils
+from docutils import nodes, writers, utils
+from docutils.writers.newlatex2e import unicode_map
+from docutils.transforms import writer_aux
+
+
+class Writer(writers.Writer):
+
+ supported = ('newlatex', 'newlatex2e')
+ """Formats this writer supports."""
+
+ default_stylesheet = 'base.tex'
+
+ default_stylesheet_path = utils.relative_path(
+ os.path.join(os.getcwd(), 'dummy'),
+ os.path.join(os.path.dirname(__file__), default_stylesheet))
+
+ settings_spec = (
+ 'LaTeX-Specific Options',
+ 'Note that this LaTeX writer is still EXPERIMENTAL. '
+ 'You must specify the location of the tools/stylesheets/latex.tex '
+ 'stylesheet file contained in the Docutils distribution tarball to '
+ 'make the LaTeX output work.',
+ (('Specify a stylesheet file. The path is used verbatim to include '
+ 'the file. Overrides --stylesheet-path.',
+ ['--stylesheet'],
+ {'default': '', 'metavar': '<file>',
+ 'overrides': 'stylesheet_path'}),
+ ('Specify a stylesheet file, relative to the current working '
+ 'directory. Overrides --stylesheet. Default: "%s"'
+ % default_stylesheet_path,
+ ['--stylesheet-path'],
+ {'metavar': '<file>', 'overrides': 'stylesheet',
+ 'default': default_stylesheet_path}),
+ ('Specify a user stylesheet file. See --stylesheet.',
+ ['--user-stylesheet'],
+ {'default': '', 'metavar': '<file>',
+ 'overrides': 'user_stylesheet_path'}),
+ ('Specify a user stylesheet file. See --stylesheet-path.',
+ ['--user-stylesheet-path'],
+ {'metavar': '<file>', 'overrides': 'user_stylesheet'})
+ ),)
+
+ settings_defaults = {
+ # Many Unicode characters are provided by unicode_map.py.
+ 'output_encoding': 'ascii',
+ 'output_encoding_error_handler': 'strict',
+ # Since we are using superscript footnotes, it is necessary to
+ # trim whitespace in front of footnote references.
+ 'trim_footnote_reference_space': 1,
+ # Currently unsupported:
+ 'docinfo_xform': 0,
+ # During development:
+ 'traceback': 1
+ }
+
+ relative_path_settings = ('stylesheet_path', 'user_stylesheet_path')
+
+ config_section = 'newlatex2e writer'
+ config_section_dependencies = ('writers',)
+
+ output = None
+ """Final translated form of `document`."""
+
+ def get_transforms(self):
+ return writers.Writer.get_transforms(self) + [writer_aux.Compound]
+
+ def __init__(self):
+ writers.Writer.__init__(self)
+ self.translator_class = LaTeXTranslator
+
+ def translate(self):
+ visitor = self.translator_class(self.document)
+ self.document.walkabout(visitor)
+ assert not visitor.context, 'context not empty: %s' % visitor.context
+ self.output = visitor.astext()
+ self.head = visitor.header
+ self.body = visitor.body
+
+
+class LaTeXException(Exception):
+ """
+ Exception base class to for exceptions which influence the
+ automatic generation of LaTeX code.
+ """
+
+
+class SkipAttrParentLaTeX(LaTeXException):
+ """
+ Do not generate ``\Dattr`` and ``\renewcommand{\Dparent}{...}`` for this
+ node.
+
+ To be raised from ``before_...`` methods.
+ """
+
+
+class SkipParentLaTeX(LaTeXException):
+ """
+ Do not generate ``\renewcommand{\DNparent}{...}`` for this node.
+
+ To be raised from ``before_...`` methods.
+ """
+
+
+class LaTeXTranslator(nodes.SparseNodeVisitor):
+
+ # Country code by a.schlock.
+ # Partly manually converted from iso and babel stuff.
+ iso639_to_babel = {
+ 'no': 'norsk', # added by hand
+ 'gd': 'scottish', # added by hand
+ 'sl': 'slovenian',
+ 'af': 'afrikaans',
+ 'bg': 'bulgarian',
+ 'br': 'breton',
+ 'ca': 'catalan',
+ 'cs': 'czech',
+ 'cy': 'welsh',
+ 'da': 'danish',
+ 'fr': 'french',
+ # french, francais, canadien, acadian
+ 'de': 'ngerman',
+ # ngerman, naustrian, german, germanb, austrian
+ 'el': 'greek',
+ 'en': 'english',
+ # english, USenglish, american, UKenglish, british, canadian
+ 'eo': 'esperanto',
+ 'es': 'spanish',
+ 'et': 'estonian',
+ 'eu': 'basque',
+ 'fi': 'finnish',
+ 'ga': 'irish',
+ 'gl': 'galician',
+ 'he': 'hebrew',
+ 'hr': 'croatian',
+ 'hu': 'hungarian',
+ 'is': 'icelandic',
+ 'it': 'italian',
+ 'la': 'latin',
+ 'nl': 'dutch',
+ 'pl': 'polish',
+ 'pt': 'portuguese',
+ 'ro': 'romanian',
+ 'ru': 'russian',
+ 'sk': 'slovak',
+ 'sr': 'serbian',
+ 'sv': 'swedish',
+ 'tr': 'turkish',
+ 'uk': 'ukrainian'
+ }
+
+ # Start with left double quote.
+ left_quote = 1
+
+ def __init__(self, document):
+ nodes.NodeVisitor.__init__(self, document)
+ self.settings = document.settings
+ self.header = []
+ self.body = []
+ self.context = []
+ self.stylesheet_path = utils.get_stylesheet_reference(
+ self.settings, os.path.join(os.getcwd(), 'dummy'))
+ if self.stylesheet_path:
+ self.settings.record_dependencies.add(self.stylesheet_path)
+ # This ugly hack will be cleaned up when refactoring the
+ # stylesheet mess.
+ self.settings.stylesheet = self.settings.user_stylesheet
+ self.settings.stylesheet_path = self.settings.user_stylesheet_path
+ self.user_stylesheet_path = utils.get_stylesheet_reference(
+ self.settings, os.path.join(os.getcwd(), 'dummy'))
+ if self.user_stylesheet_path:
+ self.settings.record_dependencies.add(self.user_stylesheet_path)
+ self.write_header()
+
+ def write_header(self):
+ a = self.header.append
+ a('%% Generated by Docutils %s <http://docutils.sourceforge.net>.'
+ % docutils.__version__)
+ a('')
+ a('% Docutils settings:')
+ lang = self.settings.language_code or ''
+ a(r'\providecommand{\Dlanguageiso}{%s}' % lang)
+ a(r'\providecommand{\Dlanguagebabel}{%s}' % self.iso639_to_babel.get(
+ lang, self.iso639_to_babel.get(lang.split('_')[0], '')))
+ a('')
+ if self.user_stylesheet_path:
+ a('% User stylesheet:')
+ a(r'\input{%s}' % self.user_stylesheet_path)
+ a('% Docutils stylesheet:')
+ a(r'\input{%s}' % self.stylesheet_path)
+ a('')
+ a('% Default definitions for Docutils nodes:')
+ for node_name in nodes.node_class_names:
+ a(r'\providecommand{\DN%s}[1]{#1}' % node_name.replace('_', ''))
+ a('')
+ a('% Auxiliary definitions:')
+ a(r'\providecommand{\Dsetattr}[2]{}')
+ a(r'\providecommand{\Dparent}{} % variable')
+ a(r'\providecommand{\Dattr}[5]{#5}')
+ a(r'\providecommand{\Dattrlen}{} % variable')
+ a(r'\providecommand{\Dtitleastext}{x} % variable')
+ a(r'\providecommand{\Dsinglebackref}{} % variable')
+ a(r'\providecommand{\Dmultiplebackrefs}{} % variable')
+ a(r'\providecommand{\Dparagraphindented}{false} % variable')
+ a('\n\n')
+
+ unicode_map = unicode_map.unicode_map # comprehensive Unicode map
+ # Fix problems with unimap.py.
+ unicode_map.update({
+ # We have AE or T1 encoding, so "``" etc. work. The macros
+ # from unimap.py may *not* work.
+ u'\u201C': '{``}',
+ u'\u201D': "{''}",
+ u'\u201E': '{,,}',
+ })
+
+ character_map = {
+ '\\': r'{\textbackslash}',
+ '{': r'{\{}',
+ '}': r'{\}}',
+ '$': r'{\$}',
+ '&': r'{\&}',
+ '%': r'{\%}',
+ '#': r'{\#}',
+ '[': r'{[}',
+ ']': r'{]}',
+ '-': r'{-}',
+ '`': r'{`}',
+ "'": r"{'}",
+ ',': r'{,}',
+ '"': r'{"}',
+ '|': r'{\textbar}',
+ '<': r'{\textless}',
+ '>': r'{\textgreater}',
+ '^': r'{\textasciicircum}',
+ '~': r'{\textasciitilde}',
+ '_': r'{\Dtextunderscore}',
+ }
+ character_map.update(unicode_map)
+ #character_map.update(special_map)
+
+ # `att_map` is for encoding attributes. According to
+ # <http://www-h.eng.cam.ac.uk/help/tpl/textprocessing/teTeX/latex/latex2e-html/ltx-164.html>,
+ # the following characters are special: # $ % & ~ _ ^ \ { }
+ # These work without special treatment in macro parameters:
+ # $, &, ~, _, ^
+ att_map = {'#': '\\#',
+ '%': '\\%',
+ # We cannot do anything about backslashes.
+ '\\': '',
+ '{': '\\{',
+ '}': '\\}',
+ # The quotation mark may be redefined by babel.
+ '"': '"{}',
+ }
+ att_map.update(unicode_map)
+
+ def encode(self, text, attval=None):
+ """
+ Encode special characters in ``text`` and return it.
+
+ If attval is true, preserve as much as possible verbatim (used
+ in attribute value encoding). If attval is 'width' or
+ 'height', `text` is interpreted as a length value.
+ """
+ if attval in ('width', 'height'):
+ match = re.match(r'([0-9.]+)(\S*)$', text)
+ assert match, '%s="%s" must be a length' % (attval, text)
+ value, unit = match.groups()
+ if unit == '%':
+ value = str(float(value) / 100)
+ unit = r'\Drelativeunit'
+ elif unit in ('', 'px'):
+ # If \Dpixelunit is "pt", this gives the same notion
+ # of pixels as graphicx.
+ value = str(float(value) * 0.75)
+ unit = '\Dpixelunit'
+ return '%s%s' % (value, unit)
+ if attval:
+ get = self.att_map.get
+ else:
+ get = self.character_map.get
+ text = ''.join([get(c, c) for c in text])
+ if (self.literal_block or self.inline_literal) and not attval:
+ # NB: We can have inline literals within literal blocks.
+ # Shrink '\r\n'.
+ text = text.replace('\r\n', '\n')
+ # Convert space. If "{ }~~~~~" is wrapped (at the
+ # brace-enclosed space "{ }"), the following non-breaking
+ # spaces ("~~~~") do *not* wind up at the beginning of the
+ # next line. Also note that, for some not-so-obvious
+ # reason, no hyphenation is done if the breaking space ("{
+ # }") comes *after* the non-breaking spaces.
+ if self.literal_block:
+ # Replace newlines with real newlines.
+ text = text.replace('\n', '\mbox{}\\\\')
+ replace_fn = self.encode_replace_for_literal_block_spaces
+ else:
+ replace_fn = self.encode_replace_for_inline_literal_spaces
+ text = re.sub(r'\s+', replace_fn, text)
+ # Protect hyphens; if we don't, line breaks will be
+ # possible at the hyphens and even the \textnhtt macro
+ # from the hyphenat package won't change that.
+ text = text.replace('-', r'\mbox{-}')
+ text = text.replace("'", r'{\Dtextliteralsinglequote}')
+ return text
+ else:
+ if not attval:
+ # Replace space with single protected space.
+ text = re.sub(r'\s+', '{ }', text)
+ # Replace double quotes with macro calls.
+ L = []
+ for part in text.split(self.character_map['"']):
+ if L:
+ # Insert quote.
+ L.append(self.left_quote and r'{\Dtextleftdblquote}'
+ or r'{\Dtextrightdblquote}')
+ self.left_quote = not self.left_quote
+ L.append(part)
+ return ''.join(L)
+ else:
+ return text
+
+ def encode_replace_for_literal_block_spaces(self, match):
+ return '~' * len(match.group())
+
+ def encode_replace_for_inline_literal_spaces(self, match):
+ return '{ }' + '~' * (len(match.group()) - 1)
+
+ def astext(self):
+ return '\n'.join(self.header) + (''.join(self.body))
+
+ def append(self, text, newline='%\n'):
+ """
+ Append text, stripping newlines, producing nice LaTeX code.
+ """
+ lines = [' ' * self.indentation_level + line + newline
+ for line in text.splitlines(0)]
+ self.body.append(''.join(lines))
+
+ def visit_Text(self, node):
+ self.append(self.encode(node.astext()))
+
+ def depart_Text(self, node):
+ pass
+
+ def is_indented(self, paragraph):
+ """Return true if `paragraph` should be first-line-indented."""
+ assert isinstance(paragraph, nodes.paragraph)
+ siblings = [n for n in paragraph.parent if
+ self.is_visible(n) and not isinstance(n, nodes.Titular)]
+ index = siblings.index(paragraph)
+ if ('continued' in paragraph['classes'] or
+ index > 0 and isinstance(siblings[index-1], nodes.transition)):
+ return 0
+ # Indent all but the first paragraphs.
+ return index > 0
+
+ def before_paragraph(self, node):
+ self.append(r'\renewcommand{\Dparagraphindented}{%s}'
+ % (self.is_indented(node) and 'true' or 'false'))
+
+ def before_title(self, node):
+ self.append(r'\renewcommand{\Dtitleastext}{%s}'
+ % self.encode(node.astext()))
+ self.append(r'\renewcommand{\Dhassubtitle}{%s}'
+ % ((len(node.parent) > 2 and
+ isinstance(node.parent[1], nodes.subtitle))
+ and 'true' or 'false'))
+
+ def before_generated(self, node):
+ if 'sectnum' in node['classes']:
+ node[0] = node[0].strip()
+
+ literal_block = 0
+
+ def visit_literal_block(self, node):
+ self.literal_block = 1
+
+ def depart_literal_block(self, node):
+ self.literal_block = 0
+
+ visit_doctest_block = visit_literal_block
+ depart_doctest_block = depart_literal_block
+
+ inline_literal = 0
+
+ def visit_literal(self, node):
+ self.inline_literal += 1
+
+ def depart_literal(self, node):
+ self.inline_literal -= 1
+
+ def visit_comment(self, node):
+ self.append('\n'.join(['% ' + line for line
+ in node.astext().splitlines(0)]), newline='\n')
+ raise nodes.SkipChildren
+
+ def before_topic(self, node):
+ if 'contents' in node['classes']:
+ for bullet_list in list(node.traverse(nodes.bullet_list)):
+ p = bullet_list.parent
+ if isinstance(p, nodes.list_item):
+ p.parent.insert(p.parent.index(p) + 1, bullet_list)
+ del p[1]
+ for paragraph in node.traverse(nodes.paragraph):
+ paragraph.attributes.update(paragraph[0].attributes)
+ paragraph[:] = paragraph[0]
+ paragraph.parent['tocrefid'] = paragraph['refid']
+ node['contents'] = 1
+ else:
+ node['contents'] = 0
+
+ bullet_list_level = 0
+
+ def visit_bullet_list(self, node):
+ self.append(r'\Dsetbullet{\labelitem%s}' %
+ ['i', 'ii', 'iii', 'iv'][min(self.bullet_list_level, 3)])
+ self.bullet_list_level += 1
+
+ def depart_bullet_list(self, node):
+ self.bullet_list_level -= 1
+
+ enum_styles = {'arabic': 'arabic', 'loweralpha': 'alph', 'upperalpha':
+ 'Alph', 'lowerroman': 'roman', 'upperroman': 'Roman'}
+
+ enum_counter = 0
+
+ def visit_enumerated_list(self, node):
+ # We create our own enumeration list environment. This allows
+ # to set the style and starting value and unlimited nesting.
+ # Maybe this can be moved to the stylesheet?
+ self.enum_counter += 1
+ enum_prefix = self.encode(node['prefix'])
+ enum_suffix = self.encode(node['suffix'])
+ enum_type = '\\' + self.enum_styles.get(node['enumtype'], r'arabic')
+ start = node.get('start', 1) - 1
+ counter = 'Denumcounter%d' % self.enum_counter
+ self.append(r'\Dmakeenumeratedlist{%s}{%s}{%s}{%s}{%s}{'
+ % (enum_prefix, enum_type, enum_suffix, counter, start))
+ # for Emacs: }
+
+ def depart_enumerated_list(self, node):
+ self.append('}') # for Emacs: {
+
+ def before_list_item(self, node):
+ # XXX needs cleanup.
+ if (len(node) and (isinstance(node[-1], nodes.TextElement) or
+ isinstance(node[-1], nodes.Text)) and
+ node.parent.index(node) == len(node.parent) - 1):
+ node['lastitem'] = 'true'
+
+ before_line = before_list_item
+
+ def before_raw(self, node):
+ if 'latex' in node.get('format', '').split():
+ # We're inserting the text in before_raw and thus outside
+ # of \DN... and \Dattr in order to make grouping with
+ # curly brackets work.
+ self.append(node.astext())
+ raise nodes.SkipChildren
+
+ def process_backlinks(self, node, type):
+ self.append(r'\renewcommand{\Dsinglebackref}{}')
+ self.append(r'\renewcommand{\Dmultiplebackrefs}{}')
+ if len(node['backrefs']) > 1:
+ refs = []
+ for i in range(len(node['backrefs'])):
+ refs.append(r'\Dmulti%sbacklink{%s}{%s}'
+ % (type, node['backrefs'][i], i + 1))
+ self.append(r'\renewcommand{\Dmultiplebackrefs}{(%s){ }}'
+ % ', '.join(refs))
+ elif len(node['backrefs']) == 1:
+ self.append(r'\renewcommand{\Dsinglebackref}{%s}'
+ % node['backrefs'][0])
+
+ def visit_footnote(self, node):
+ self.process_backlinks(node, 'footnote')
+
+ def visit_citation(self, node):
+ self.process_backlinks(node, 'citation')
+
+ def before_table(self, node):
+ # A table contains exactly one tgroup. See before_tgroup.
+ pass
+
+ def before_tgroup(self, node):
+ widths = []
+ total_width = 0
+ for i in range(int(node['cols'])):
+ assert isinstance(node[i], nodes.colspec)
+ widths.append(int(node[i]['colwidth']) + 1)
+ total_width += widths[-1]
+ del node[:len(widths)]
+ tablespec = '|'
+ for w in widths:
+ # 0.93 is probably wrong in many cases. XXX Find a
+ # solution which works *always*.
+ tablespec += r'p{%s\textwidth}|' % (0.93 * w /
+ max(total_width, 60))
+ self.append(r'\Dmaketable{%s}{' % tablespec)
+ self.context.append('}')
+ raise SkipAttrParentLaTeX
+
+ def depart_tgroup(self, node):
+ self.append(self.context.pop())
+
+ def before_row(self, node):
+ raise SkipAttrParentLaTeX
+
+ def before_thead(self, node):
+ raise SkipAttrParentLaTeX
+
+ def before_tbody(self, node):
+ raise SkipAttrParentLaTeX
+
+ def is_simply_entry(self, node):
+ return (len(node) == 1 and isinstance(node[0], nodes.paragraph) or
+ len(node) == 0)
+
+ def before_entry(self, node):
+ is_leftmost = 0
+ if node.hasattr('morerows'):
+ self.document.reporter.severe('Rowspans are not supported.')
+ # Todo: Add empty cells below rowspanning cell and issue
+ # warning instead of severe.
+ if node.hasattr('morecols'):
+ # The author got a headache trying to implement
+ # multicolumn support.
+ if not self.is_simply_entry(node):
+ self.document.reporter.severe(
+ 'Colspanning table cells may only contain one paragraph.')
+ # Todo: Same as above.
+ # The number of columns this entry spans (as a string).
+ colspan = int(node['morecols']) + 1
+ del node['morecols']
+ else:
+ colspan = 1
+ # Macro to call.
+ macro_name = r'\Dcolspan'
+ if node.parent.index(node) == 0:
+ # Leftmost column.
+ macro_name += 'left'
+ is_leftmost = 1
+ if colspan > 1:
+ self.append('%s{%s}{' % (macro_name, colspan))
+ self.context.append('}')
+ else:
+ # Do not add a multicolumn with colspan 1 beacuse we need
+ # at least one non-multicolumn cell per column to get the
+ # desired column widths, and we can only do colspans with
+ # cells consisting of only one paragraph.
+ if not is_leftmost:
+ self.append(r'\Dsubsequententry{')
+ self.context.append('}')
+ else:
+ self.context.append('')
+ if isinstance(node.parent.parent, nodes.thead):
+ node['tableheaderentry'] = 'true'
+
+ # Don't add \renewcommand{\Dparent}{...} because there must
+ # not be any non-expandable commands in front of \multicolumn.
+ raise SkipParentLaTeX
+
+ def depart_entry(self, node):
+ self.append(self.context.pop())
+
+ def before_substitution_definition(self, node):
+ raise nodes.SkipNode
+
+ indentation_level = 0
+
+ def node_name(self, node):
+ return node.__class__.__name__.replace('_', '')
+
+ # Attribute propagation order.
+ attribute_order = ['align', 'classes', 'ids']
+
+ def attribute_cmp(self, a1, a2):
+ """
+ Compare attribute names `a1` and `a2`. Used in
+ propagate_attributes to determine propagation order.
+
+ See built-in function `cmp` for return value.
+ """
+ if a1 in self.attribute_order and a2 in self.attribute_order:
+ return cmp(self.attribute_order.index(a1),
+ self.attribute_order.index(a2))
+ if (a1 in self.attribute_order) != (a2 in self.attribute_order):
+ # Attributes not in self.attribute_order come last.
+ return a1 in self.attribute_order and -1 or 1
+ else:
+ return cmp(a1, a2)
+
+ def propagate_attributes(self, node):
+ # Propagate attributes using \Dattr macros.
+ node_name = self.node_name(node)
+ attlist = []
+ if isinstance(node, nodes.Element):
+ attlist = node.attlist()
+ attlist.sort(lambda pair1, pair2: self.attribute_cmp(pair1[0],
+ pair2[0]))
+ # `numatts` may be greater than len(attlist) due to list
+ # attributes.
+ numatts = 0
+ pass_contents = self.pass_contents(node)
+ for key, value in attlist:
+ if isinstance(value, ListType):
+ self.append(r'\renewcommand{\Dattrlen}{%s}' % len(value))
+ for i in range(len(value)):
+ self.append(r'\Dattr{%s}{%s}{%s}{%s}{' %
+ (i+1, key, self.encode(value[i], attval=key),
+ node_name))
+ if not pass_contents:
+ self.append('}')
+ numatts += len(value)
+ else:
+ self.append(r'\Dattr{}{%s}{%s}{%s}{' %
+ (key, self.encode(unicode(value), attval=key),
+ node_name))
+ if not pass_contents:
+ self.append('}')
+ numatts += 1
+ if pass_contents:
+ self.context.append('}' * numatts) # for Emacs: {
+ else:
+ self.context.append('')
+
+ def visit_docinfo(self, node):
+ raise NotImplementedError('Docinfo not yet implemented.')
+
+ def visit_document(self, node):
+ document = node
+ # Move IDs into TextElements. This won't work for images.
+ # Need to review this.
+ for node in document.traverse(nodes.Element):
+ if node.has_key('ids') and not isinstance(node,
+ nodes.TextElement):
+ next_text_element = node.next_node(nodes.TextElement)
+ if next_text_element:
+ next_text_element['ids'].extend(node['ids'])
+ node['ids'] = []
+
+ def pass_contents(self, node):
+ r"""
+ Return true if the node contents should be passed in
+ parameters of \DN... and \Dattr.
+ """
+ return not isinstance(node, (nodes.document, nodes.section))
+
+ def dispatch_visit(self, node):
+ skip_attr = skip_parent = 0
+ # TreePruningException to be propagated.
+ tree_pruning_exception = None
+ if hasattr(self, 'before_' + node.__class__.__name__):
+ try:
+ getattr(self, 'before_' + node.__class__.__name__)(node)
+ except SkipParentLaTeX:
+ skip_parent = 1
+ except SkipAttrParentLaTeX:
+ skip_attr = 1
+ skip_parent = 1
+ except nodes.SkipNode:
+ raise
+ except (nodes.SkipChildren, nodes.SkipSiblings), instance:
+ tree_pruning_exception = instance
+ except nodes.SkipDeparture:
+ raise NotImplementedError(
+ 'SkipDeparture not usable in LaTeX writer')
+
+ if not isinstance(node, nodes.Text):
+ node_name = self.node_name(node)
+ # attribute_deleters will be appended to self.context.
+ attribute_deleters = []
+ if not skip_parent and not isinstance(node, nodes.document):
+ self.append(r'\renewcommand{\Dparent}{%s}'
+ % self.node_name(node.parent))
+ for name, value in node.attlist():
+ if not isinstance(value, ListType) and not ':' in name:
+ macro = r'\DcurrentN%sA%s' % (node_name, name)
+ self.append(r'\def%s{%s}' % (
+ macro, self.encode(unicode(value), attval=name)))
+ attribute_deleters.append(r'\let%s=\relax' % macro)
+ self.context.append('\n'.join(attribute_deleters))
+ if self.pass_contents(node):
+ self.append(r'\DN%s{' % node_name)
+ self.context.append('}')
+ else:
+ self.append(r'\Dvisit%s' % node_name)
+ self.context.append(r'\Ddepart%s' % node_name)
+ self.indentation_level += 1
+ if not skip_attr:
+ self.propagate_attributes(node)
+ else:
+ self.context.append('')
+
+ if (isinstance(node, nodes.TextElement) and
+ not isinstance(node.parent, nodes.TextElement)):
+ # Reset current quote to left.
+ self.left_quote = 1
+
+ # Call visit_... method.
+ try:
+ nodes.SparseNodeVisitor.dispatch_visit(self, node)
+ except LaTeXException:
+ raise NotImplementedError(
+ 'visit_... methods must not raise LaTeXExceptions')
+
+ if tree_pruning_exception:
+ # Propagate TreePruningException raised in before_... method.
+ raise tree_pruning_exception
+
+ def is_invisible(self, node):
+ # Return true if node is invisible or moved away in the LaTeX
+ # rendering.
+ return (not isinstance(node, nodes.Text) and
+ (isinstance(node, nodes.Invisible) or
+ isinstance(node, nodes.footnote) or
+ isinstance(node, nodes.citation) or
+ # Assume raw nodes to be invisible.
+ isinstance(node, nodes.raw) or
+ # Floating image or figure.
+ node.get('align') in ('left', 'right')))
+
+ def is_visible(self, node):
+ return not self.is_invisible(node)
+
+ def needs_space(self, node):
+ """Two nodes for which `needs_space` is true need auxiliary space."""
+ # Return true if node is a visible block-level element.
+ return ((isinstance(node, nodes.Body) or
+ isinstance(node, nodes.topic)) and
+ not (self.is_invisible(node) or
+ isinstance(node.parent, nodes.TextElement)))
+
+ def always_needs_space(self, node):
+ """
+ Always add space around nodes for which `always_needs_space()`
+ is true, regardless of whether the other node needs space as
+ well. (E.g. transition next to section.)
+ """
+ return isinstance(node, nodes.transition)
+
+ def dispatch_departure(self, node):
+ # Call departure method.
+ nodes.SparseNodeVisitor.dispatch_departure(self, node)
+
+ if not isinstance(node, nodes.Text):
+ # Close attribute and node handler call (\DN...{...}).
+ self.indentation_level -= 1
+ self.append(self.context.pop() + self.context.pop())
+ # Delete \Dcurrent... attribute macros.
+ self.append(self.context.pop())
+ # Get next sibling.
+ next_node = node.next_node(
+ ascend=0, siblings=1, descend=0,
+ condition=self.is_visible)
+ # Insert space if necessary.
+ if (self.needs_space(node) and self.needs_space(next_node) or
+ self.always_needs_space(node) or
+ self.always_needs_space(next_node)):
+ if isinstance(node, nodes.paragraph) and isinstance(next_node, nodes.paragraph):
+ # Space between paragraphs.
+ self.append(r'\Dparagraphspace')
+ else:
+ # One of the elements is not a paragraph.
+ self.append(r'\Dauxiliaryspace')
diff --git a/docutils/writers/newlatex2e/base.tex b/docutils/writers/newlatex2e/base.tex
new file mode 100644
index 000000000..231f3911f
--- /dev/null
+++ b/docutils/writers/newlatex2e/base.tex
@@ -0,0 +1,1108 @@
+\makeatletter
+
+% Development notes at
+% http://docutils.python-hosting.com/wiki/NewLatex
+
+
+\providecommand{\Dprinting}{false}
+
+
+\providecommand{\DSearly}{}
+\providecommand{\DSlate}{}
+
+\providecommand{\Ddocumentclass}{scrartcl}
+\providecommand{\Ddocumentoptions}{a4paper}
+
+\documentclass[\Ddocumentoptions]{\Ddocumentclass}
+
+\DSearly
+
+
+\providecommand{\DSfontencoding}{
+ % Set up font encoding.
+ % AE is a T1-emulation. It provides most characters and features
+ % as T1-encoded fonts but doesn't use ugly bitmap fonts.
+ \usepackage{ae}
+ % Provide the characters not contained in AE from EC bitmap fonts.
+ \usepackage{aecompl}
+ % Guillemets ("<<", ">>") in AE.
+ \usepackage{aeguill}
+}
+
+
+\providecommand{\DSsymbols}{%
+ % Fix up symbols.
+ % The Euro symbol in Computer Modern looks, um, funny. Let's get a
+ % proper Euro symbol.
+ \RequirePackage{eurosym}%
+ \renewcommand{\texteuro}{\euro}%
+}
+
+
+% Taken from
+% <http://groups.google.de/groups?selm=1i0n5tgtplti420e1omp4pctlv19jpuhbb%404ax.com>
+% and modified. Used with permission.
+\providecommand{\Dprovidelength}[2]{%
+ \begingroup%
+ \escapechar\m@ne%
+ \xdef\@gtempa{{\string#1}}%
+ \endgroup%
+ \expandafter\@ifundefined\@gtempa%
+ {\newlength{#1}\setlength{#1}{#2}}%
+ {}%
+}
+
+\providecommand{\Dprovidecounter}[1]{%
+ % Like \newcounter except that it doesn't crash if the counter
+ % already exists.
+ \@ifundefined{c@#1}{\newcounter{#1}}{}
+}
+
+\Dprovidelength{\Dboxparindent}{\parindent}
+\providecommand{\Dmakeboxminipage}[1]{%
+ % Make minipage for use in a box created by \Dmakefbox.
+ \begin{minipage}[t]{0.9\linewidth}%
+ \setlength{\parindent}{\Dboxparindent}%
+ #1%
+ \end{minipage}%
+}
+\providecommand{\Dmakefbox}[1]{%
+ % Make a centered, framed box. Useful e.g. for admonitions.
+ \vspace{0.4\baselineskip}%
+ \begin{center}%
+ \fbox{\Dmakeboxminipage{#1}}%
+ \end{center}%
+ \vspace{0.4\baselineskip}%
+}
+\providecommand{\Dmakebox}[1]{%
+ % Make a centered, frameless box. Useful e.g. for block quotes.
+ % Do not use minipages here, but create pseudo-lists to allow
+ % page-breaking. (Don't use KOMA-script's addmargin environment
+ % because it messes up bullet lists.)
+ \Dmakelistenvironment{}{}{%
+ \setlength{\parskip}{0pt}%
+ \setlength{\parindent}{\Dboxparindent}%
+ \item{#1}%
+ }%
+}
+
+
+\RequirePackage{ifthen}
+\providecommand{\Dfrenchspacing}{true}
+\ifthenelse{\equal{\Dfrenchspacing}{true}}{\frenchspacing}{}
+
+
+\Dprovidelength{\Dblocklevelvspace}{%
+ % Space between block-level elements other than paragraphs.
+ 0.7\baselineskip plus 0.3\baselineskip minus 0.2\baselineskip%
+}
+\providecommand{\Dauxiliaryspace}{%
+ \ifthenelse{\equal{\Dneedvspace}{true}}{\vspace{\Dblocklevelvspace}}{}%
+ \par\noindent%
+}
+\providecommand{\Dparagraphspace}{\par}
+\providecommand{\Dneedvspace}{true}
+
+
+\providecommand{\DSlinks}{
+ % Targets and references.
+ \RequirePackage[colorlinks=false,pdfborder={0 0 0}]{hyperref}
+
+ \providecommand{\Draisedlink}[1]{\Hy@raisedlink{##1}}
+
+ % References.
+ % We're assuming here that the "refid" and "refuri" attributes occur
+ % only in inline context (in TextElements).
+ \providecommand{\DArefid}[5]{%
+ \ifthenelse{\equal{##4}{reference}}{%
+ \Dexplicitreference{\###3}{##5}%
+ }{%
+ % If this is not a target node (targets with refids are
+ % uninteresting and should be silently dropped).
+ \ifthenelse{\not\equal{##4}{target}}{%
+ % If this is a footnote reference, call special macro.
+ \ifthenelse{\equal{##4}{footnotereference}}{%
+ \Dimplicitfootnotereference{\###3}{##5}%
+ }{%
+ \ifthenelse{\equal{##4}{citationreference}}{%
+ \Dimplicitcitationreference{\###3}{##5}%
+ }{%
+ \Dimplicitreference{\###3}{##5}%
+ }%
+ }%
+ }{}%
+ }%
+ }
+ \providecommand{\DArefuri}[5]{%
+ \ifthenelse{\equal{##4}{target}}{%
+ % Hyperlink targets can (and should be) ignored because they are
+ % invisible.
+ }{%
+ % We only have explicit URI references, so one macro suffices.
+ \Durireference{##3}{##5}%
+ }%
+ }
+ % Targets.
+ \providecommand{\DAids}[5]{%
+ \label{##3}%
+ \ifthenelse{\equal{##4}{footnotereference}}{%
+ {%
+ \renewcommand{\HyperRaiseLinkDefault}{%
+ % Dirty hack to make backrefs to footnote references work.
+ % For some reason, \baselineskip is 0pt in fn references.
+ 0.5\Doriginalbaselineskip%
+ }%
+ \Draisedlink{\hypertarget{##3}{}}##5%
+ }%
+ }{%
+ \Draisedlink{\hypertarget{##3}{}}##5%
+ }%
+ }
+ % Color in references.
+ \RequirePackage{color}
+ \providecommand{\Dimplicitreference}[2]{%
+ % Create implicit reference to ID. Implicit references occur
+ % e.g. in TOC-backlinks of section titles. Parameters:
+ % 1. Target.
+ % 2. Link text.
+ \href{##1}{##2}%
+ }
+ \providecommand{\Dimplicitfootnotereference}[2]{%
+ % Ditto, but for the special case of footnotes.
+ % We want them to be rendered like explicit references.
+ \Dexplicitreference{##1}{##2}%
+ }
+ \providecommand{\Dimplicitcitationreference}[2]{%
+ % Ditto for citation references.
+ \Dimplicitfootnotereference{##1}{##2}%
+ }
+ \ifthenelse{\equal{\Dprinting}{true}}{
+ \providecommand{\Dexplicitreferencecolor}{black}
+ }{
+ \providecommand{\Dexplicitreferencecolor}{blue}
+ }
+ \providecommand{\Dexplicitreference}[2]{%
+ % Create explicit reference to ID, e.g. created with "foo_".
+ % Parameters:
+ % 1. Target.
+ % 2. Link text.
+ \href{##1}{{\color{\Dexplicitreferencecolor}##2}}%
+ }
+ \providecommand{\Durireferencecolor}{\Dexplicitreferencecolor}
+ \providecommand{\Durireference}[2]{%
+ % Create reference to URI. Parameters:
+ % 1. Target.
+ % 2. Link text.
+ \href{##1}{{\color{\Durireferencecolor}##2}}%
+ }
+}
+
+
+\providecommand{\DSlanguage}{%
+ % Set up babel.
+ \ifthenelse{\equal{\Dlanguagebabel}{}}{}{
+ \RequirePackage[\Dlanguagebabel]{babel}
+ }
+}
+
+
+
+
+\providecommand{\DAclasses}[5]{%
+ \Difdefined{DN#4C#3}{%
+ % Pass only contents, nothing else!
+ \csname DN#4C#3\endcsname{#5}%
+ }{%
+ \Difdefined{DC#3}{%
+ \csname DC#3\endcsname{#5}%
+ }{%
+ #5%
+ }%
+ }%
+}
+
+\providecommand{\Difdefined}[3]{\@ifundefined{#1}{#3}{#2}}
+
+\providecommand{\Dattr}[5]{%
+ % Global attribute dispatcher.
+ % Parameters:
+ % 1. Attribute number.
+ % 2. Attribute name.
+ % 3. Attribute value.
+ % 4. Node name.
+ % 5. Node contents.
+ \Difdefined{DN#4A#2V#3}{%
+ \csname DN#4A#2V#3\endcsname{#1}{#2}{#3}{#4}{#5}%
+ }{\Difdefined{DN#4A#2}{%
+ \csname DN#4A#2\endcsname{#1}{#2}{#3}{#4}{#5}%
+ }{\Difdefined{DA#2V#3}{%
+ \csname DA#2V#3\endcsname{#1}{#2}{#3}{#4}{#5}%
+ }{\Difdefined{DA#2}{%
+ \csname DA#2\endcsname{#1}{#2}{#3}{#4}{#5}%
+ }{#5%
+ }}}}%
+}
+
+\providecommand{\DNparagraph}[1]{%
+ \ifthenelse{\equal{\Dparagraphindented}{true}}{\indent}{\noindent}%
+ #1%
+}
+\providecommand{\Dformatboxtitle}[1]{{\Large\textbf{#1}}}
+\providecommand{\Dformatboxsubtitle}[1]{{\large\textbf{#1}}}
+\providecommand{\Dtopictitle}[1]{%
+ \Difinsidetoc{\vspace{1em}\par}{}%
+ \noindent\Dformatboxtitle{#1}%
+ \ifthenelse{\equal{\Dhassubtitle}{false}}{\vspace{1em}}{\vspace{0.5em}}%
+ \par%
+}
+\providecommand{\Dtopicsubtitle}[1]{%
+ \noindent\Dformatboxsubtitle{#1}%
+ \vspace{1em}%
+ \par%
+}
+\providecommand{\Dsidebartitle}[1]{\Dtopictitle{#1}}
+\providecommand{\Dsidebarsubtitle}[1]{\Dtopicsubtitle{#1}}
+\providecommand{\Ddocumenttitle}[1]{%
+ \begin{center}{\Huge#1}\end{center}%
+ \ifthenelse{\equal{\Dhassubtitle}{true}}{\vspace{0.1cm}}{\vspace{1cm}}%
+}
+\providecommand{\Ddocumentsubtitle}[1]{%
+ \begin{center}{\huge#1}\end{center}%
+ \vspace{1cm}%
+}
+% Can be overwritten by user stylesheet.
+\providecommand{\Dformatsectiontitle}[1]{#1}
+\providecommand{\Dformatsectionsubtitle}[1]{\Dformatsectiontitle{#1}}
+\providecommand{\Dbookmarksectiontitle}[1]{%
+ % Return text suitable for use in \section*, \subsection*, etc.,
+ % containing a PDF bookmark. Parameter: The title (as node tree).
+ \Draisedlink{\Dpdfbookmark{\Dtitleastext}}%
+ #1%
+}
+\providecommand{\Dsectiontitlehook}[1]{#1}
+\providecommand{\Dsectiontitle}[1]{%
+ \Dsectiontitlehook{%
+ \Ddispatchsectiontitle{\Dbookmarksectiontitle{\Dformatsectiontitle{#1}}}%
+ }%
+}
+\providecommand{\Ddispatchsectiontitle}[1]{%
+ \@ifundefined{Dsectiontitle\roman{Dsectionlevel}}{%
+ \Ddeepsectiontitle{#1}%
+ }{%
+ \csname Dsectiontitle\roman{Dsectionlevel}\endcsname{#1}%
+ }%
+}
+\providecommand{\Ddispatchsectionsubtitle}[1]{%
+ \Ddispatchsectiontitle{#1}%
+}
+\providecommand{\Dsectiontitlei}[1]{\section*{#1}}
+\providecommand{\Dsectiontitleii}[1]{\subsection*{#1}}
+\providecommand{\Ddeepsectiontitle}[1]{%
+ % Anything below \subsubsection (like \paragraph or \subparagraph)
+ % is useless because it uses the same font. The only way to
+ % (visually) distinguish such deeply nested sections is to use
+ % section numbering.
+ \subsubsection*{#1}%
+}
+\providecommand{\Dsectionsubtitlehook}[1]{#1}
+\Dprovidelength{\Dsectionsubtitleraisedistance}{0.7em}
+\providecommand{\Dsectionsubtitlescaling}{0.85}
+\providecommand{\Dsectionsubtitle}[1]{%
+ \Dsectionsubtitlehook{%
+ % Move the subtitle nearer to the title.
+ \vspace{-\Dsectionsubtitleraisedistance}%
+ % Don't create a PDF bookmark.
+ \Ddispatchsectionsubtitle{%
+ \Dformatsectionsubtitle{\scalebox{\Dsectionsubtitlescaling}{#1}}%
+ }%
+ }%
+}
+% Boolean variable.
+\providecommand{\Dhassubtitle}{false}
+\providecommand{\DNtitle}[1]{%
+ \csname D\Dparent title\endcsname{#1}%
+}
+\providecommand{\DNsubtitle}[1]{%
+ \csname D\Dparent subtitle\endcsname{#1}%
+}
+\newcounter{Dpdfbookmarkid}
+\setcounter{Dpdfbookmarkid}{0}
+\providecommand{\Dpdfbookmark}[1]{%
+ % Temporarily decrement Desctionlevel counter.
+ \addtocounter{Dsectionlevel}{-1}%
+ %\typeout{\arabic{Dsectionlevel}}%
+ %\typeout{#1}%
+ %\typeout{docutils\roman{Dpdfbookmarkid}}%
+ %\typeout{}%
+ \pdfbookmark[\arabic{Dsectionlevel}]{#1}{docutils\arabic{Dpdfbookmarkid}}%
+ \addtocounter{Dsectionlevel}{1}%
+ \addtocounter{Dpdfbookmarkid}{1}%
+}
+
+%\providecommand{\DNliteralblock}[1]{\begin{quote}\ttfamily\raggedright#1\end{quote}}
+\providecommand{\DNliteralblock}[1]{%
+ \Dmakelistenvironment{}{%
+ \ifthenelse{\equal{\Dinsidetabular}{true}}{%
+ \setlength{\leftmargin}{0pt}%
+ }{}%
+ \setlength{\rightmargin}{0pt}%
+ }{%
+ \raggedright\item\noindent\nohyphens{\textnhtt{#1\Dfinalstrut}}%
+ }%
+}
+\providecommand{\DNdoctestblock}[1]{%
+ % Treat doctest blocks the same as literal blocks.
+ \DNliteralblock{#1}%
+}
+\RequirePackage{hyphenat}
+\providecommand{\DNliteral}[1]{\textnhtt{#1}}
+\providecommand{\DNemphasis}[1]{\emph{#1}}
+\providecommand{\DNstrong}[1]{\textbf{#1}}
+\providecommand{\Dvisitdocument}{\begin{document}\noindent}
+\providecommand{\Ddepartdocument}{\end{document}}
+\providecommand{\DNtopic}[1]{%
+ \ifthenelse{\equal{\DcurrentNtopicAcontents}{1}}{%
+ \addtocounter{Dtoclevel}{1}%
+ \par\noindent%
+ #1%
+ \addtocounter{Dtoclevel}{-1}%
+ }{%
+ \par\noindent%
+ \Dmakebox{#1}%
+ }%
+}
+\providecommand{\Dformatrubric}[1]{\textbf{#1}}
+\Dprovidelength{\Dprerubricspace}{0.3em}
+\providecommand{\DNrubric}[1]{%
+ \vspace{\Dprerubricspace}\par\noindent\Dformatrubric{#1}\par%
+}
+
+\providecommand{\Dbullet}{}
+\providecommand{\Dsetbullet}[1]{\renewcommand{\Dbullet}{#1}}
+\providecommand{\DNbulletlist}[1]{%
+ \Difinsidetoc{%
+ \Dtocbulletlist{#1}%
+ }{%
+ \Dmakelistenvironment{\Dbullet}{}{#1}%
+ }%
+}
+\renewcommand{\@pnumwidth}{2.2em}
+\providecommand{\DNlistitem}[1]{%
+ \Difinsidetoc{%
+ \ifthenelse{\equal{\theDtoclevel}{1}\and\equal{\Dlocaltoc}{false}}{%
+ {%
+ \par\addvspace{1em}\noindent%
+ \sectfont%
+ #1\hfill\pageref{\DcurrentNlistitemAtocrefid}%
+ }%
+ }{%
+ \@dottedtocline{0}{\Dtocindent}{0em}{#1}{%
+ \pageref{\DcurrentNlistitemAtocrefid}%
+ }%
+ }%
+ }{%
+ \item{#1}%
+ }%
+}
+\providecommand{\DNenumeratedlist}[1]{#1}
+\newcounter{Dsectionlevel}
+\providecommand{\Dvisitsectionhook}{}
+\providecommand{\Ddepartsectionhook}{}
+\providecommand{\Dvisitsection}{%
+ \addtocounter{Dsectionlevel}{1}%
+ \Dvisitsectionhook%
+}
+\providecommand{\Ddepartsection}{%
+ \Ddepartsectionhook%
+ \addtocounter{Dsectionlevel}{-1}%
+}
+
+% Using \_ will cause hyphenation after _ even in \textnhtt-typewriter
+% because the hyphenat package redefines \_. So we use
+% \textunderscore here.
+\providecommand{\Dtextunderscore}{\textunderscore}
+
+\providecommand{\Dtextinlineliteralfirstspace}{{ }}
+\providecommand{\Dtextinlineliteralsecondspace}{{~}}
+
+\Dprovidelength{\Dlistspacing}{0.8\baselineskip}
+
+\providecommand{\Dsetlistrightmargin}{%
+ \ifthenelse{\lengthtest{\linewidth>12em}}{%
+ % Equal margins.
+ \setlength{\rightmargin}{\leftmargin}%
+ }{%
+ % If the line is narrower than 10em, we don't remove any further
+ % space from the right.
+ \setlength{\rightmargin}{0pt}%
+ }%
+}
+\providecommand{\Dresetlistdepth}{false}
+\Dprovidelength{\Doriginallabelsep}{\labelsep}
+\providecommand{\Dmakelistenvironment}[3]{%
+ % Make list environment with support for unlimited nesting and with
+ % reasonable default lengths. Parameters:
+ % 1. Label (same as in list environment).
+ % 2. Spacing (same as in list environment).
+ % 3. List contents (contents of list environment).
+ \ifthenelse{\equal{\Dinsidetabular}{true}}{%
+ % Unfortunately, vertical spacing doesn't work correctly when
+ % using lists inside tabular environments, so we use a minipage.
+ \begin{minipage}[t]{\linewidth}%
+ }{}%
+ {%
+ \renewcommand{\Dneedvspace}{false}%
+ % \parsep0.5\baselineskip
+ \renewcommand{\Dresetlistdepth}{false}%
+ \ifnum \@listdepth>5%
+ \protect\renewcommand{\Dresetlistdepth}{true}%
+ \@listdepth=5%
+ \fi%
+ \begin{list}{%
+ #1%
+ }{%
+ \setlength{\itemsep}{0pt}%
+ \setlength{\partopsep}{0pt}%
+ \setlength{\topsep}{0pt}%
+ % List should take 90% of total width.
+ \setlength{\leftmargin}{0.05\linewidth}%
+ \ifthenelse{\lengthtest{\leftmargin<1.8em}}{%
+ \setlength{\leftmargin}{1.8em}%
+ }{}%
+ \setlength{\labelsep}{\Doriginallabelsep}%
+ \Dsetlistrightmargin%
+ #2%
+ }{%
+ #3%
+ }%
+ \end{list}%
+ \ifthenelse{\equal{\Dresetlistdepth}{true}}{\@listdepth=5}{}%
+ }%
+ \ifthenelse{\equal{\Dinsidetabular}{true}}{\end{minipage}}{}%
+}
+\providecommand{\Dfinalstrut}{\@finalstrut\@arstrutbox}
+\providecommand{\DAlastitem}[5]{#5\Dfinalstrut}
+
+\Dprovidelength{\Ditemsep}{0pt}
+\providecommand{\Dmakeenumeratedlist}[6]{%
+ % Make enumerated list.
+ % Parameters:
+ % - prefix
+ % - type (\arabic, \roman, ...)
+ % - suffix
+ % - suggested counter name
+ % - start number - 1
+ % - list contents
+ \newcounter{#4}%
+ \Dmakelistenvironment{#1#2{#4}#3}{%
+ % Use as much space as needed for the label.
+ \setlength{\labelwidth}{10em}%
+ % Reserve enough space so that the label doesn't go beyond the
+ % left margin of preceding paragraphs. Like that:
+ %
+ % A paragraph.
+ %
+ % 1. First item.
+ \setlength{\leftmargin}{2.5em}%
+ \Dsetlistrightmargin%
+ \setlength{\itemsep}{\Ditemsep}%
+ % Use counter recommended by Python module.
+ \usecounter{#4}%
+ % Set start value.
+ \addtocounter{#4}{#5}%
+ }{%
+ % The list contents.
+ #6%
+ }%
+}
+
+
+% Single quote in literal mode. \textquotesingle from package
+% textcomp has wrong width when using package ae, so we use a normal
+% single curly quote here.
+\providecommand{\Dtextliteralsinglequote}{'}
+
+
+% "Tabular lists" are field lists and options lists (not definition
+% lists because there the term always appears on its own line). We'll
+% use the terminology of field lists now ("field", "field name",
+% "field body"), but the same is also analogously applicable to option
+% lists.
+%
+% We want these lists to be breakable across pages. We cannot
+% automatically get the narrowest possible size for the left column
+% (i.e. the field names or option groups) because tabularx does not
+% support multi-page tables, ltxtable needs to have the table in an
+% external file and we don't want to clutter the user's directories
+% with auxiliary files created by the filecontents environment, and
+% ltablex is not included in teTeX.
+%
+% Thus we set a fixed length for the left column and use list
+% environments. This also has the nice side effect that breaking is
+% now possible anywhere, not just between fields.
+%
+% Note that we are creating a distinct list environment for each
+% field. There is no macro for a whole tabular list!
+\Dprovidelength{\Dtabularlistfieldnamewidth}{6em}
+\Dprovidelength{\Dtabularlistfieldnamesep}{0.5em}
+\providecommand{\Dinsidetabular}{false}
+\providecommand{\Dsavefieldname}{}
+\providecommand{\Dsavefieldbody}{}
+\Dprovidelength{\Dusedfieldnamewidth}{0pt}
+\Dprovidelength{\Drealfieldnamewidth}{0pt}
+\providecommand{\Dtabularlistfieldname}[1]{\renewcommand{\Dsavefieldname}{#1}}
+\providecommand{\Dtabularlistfieldbody}[1]{\renewcommand{\Dsavefieldbody}{#1}}
+\Dprovidelength{\Dparskiptemp}{0pt}
+\providecommand{\Dtabularlistfield}[1]{%
+ {%
+ % This only saves field name and field body in \Dsavefieldname and
+ % \Dsavefieldbody, resp. It does not insert any text into the
+ % document.
+ #1%
+ % Recalculate the real field name width everytime we encounter a
+ % tabular list field because it may have been changed using a
+ % "raw" node.
+ \setlength{\Drealfieldnamewidth}{\Dtabularlistfieldnamewidth}%
+ \addtolength{\Drealfieldnamewidth}{\Dtabularlistfieldnamesep}%
+ \Dmakelistenvironment{%
+ \makebox[\Drealfieldnamewidth][l]{\Dsavefieldname}%
+ }{%
+ \setlength{\labelwidth}{\Drealfieldnamewidth}%
+ \setlength{\leftmargin}{\Drealfieldnamewidth}%
+ \setlength{\rightmargin}{0pt}%
+ \setlength{\labelsep}{0pt}%
+ }{%
+ \item%
+ \settowidth{\Dusedfieldnamewidth}{\Dsavefieldname}%
+ \setlength{\Dparskiptemp}{\parskip}%
+ \ifthenelse{%
+ \lengthtest{\Dusedfieldnamewidth>\Dtabularlistfieldnamewidth}%
+ }{%
+ \mbox{}\par%
+ \setlength{\parskip}{0pt}%
+ }{}%
+ \Dsavefieldbody%
+ \setlength{\parskip}{\Dparskiptemp}%
+ %XXX Why did we need this?
+ %\@finalstrut\@arstrutbox%
+ }%
+ \par%
+ }%
+}
+
+\providecommand{\Dformatfieldname}[1]{\textbf{#1:}}
+\providecommand{\DNfieldlist}[1]{#1}
+\providecommand{\DNfield}[1]{\Dtabularlistfield{#1}}
+\providecommand{\DNfieldname}[1]{%
+ \Dtabularlistfieldname{%
+ \Dformatfieldname{#1}%
+ }%
+}
+\providecommand{\DNfieldbody}[1]{\Dtabularlistfieldbody{#1}}
+
+\providecommand{\Dformatoptiongroup}[1]{%
+ % Format option group, e.g. "-f file, --input file".
+ \texttt{#1}%
+}
+\providecommand{\Dformatoption}[1]{%
+ % Format option, e.g. "-f file".
+ % Put into mbox to avoid line-breaking at spaces.
+ \mbox{#1}%
+}
+\providecommand{\Dformatoptionstring}[1]{%
+ % Format option string, e.g. "-f".
+ #1%
+}
+\providecommand{\Dformatoptionargument}[1]{%
+ % Format option argument, e.g. "file".
+ \textsl{#1}%
+}
+\providecommand{\Dformatoptiondescription}[1]{%
+ % Format option description, e.g.
+ % "\DNparagraph{Read input data from file.}"
+ #1%
+}
+\providecommand{\DNoptionlist}[1]{#1}
+\providecommand{\Doptiongroupjoiner}{,{ }}
+\providecommand{\Disfirstoption}{%
+ % Auxiliary macro indicating if a given option is the first child
+ % of its option group (if it's not, it has to preceded by
+ % \Doptiongroupjoiner).
+ false%
+}
+\providecommand{\DNoptionlistitem}[1]{%
+ \Dtabularlistfield{#1}%
+}
+\providecommand{\DNoptiongroup}[1]{%
+ \renewcommand{\Disfirstoption}{true}%
+ \Dtabularlistfieldname{\Dformatoptiongroup{#1}}%
+}
+\providecommand{\DNoption}[1]{%
+ % If this is not the first option in this option group, add a
+ % joiner.
+ \ifthenelse{\equal{\Disfirstoption}{true}}{%
+ \renewcommand{\Disfirstoption}{false}%
+ }{%
+ \Doptiongroupjoiner%
+ }%
+ \Dformatoption{#1}%
+}
+\providecommand{\DNoptionstring}[1]{\Dformatoptionstring{#1}}
+\providecommand{\DNoptionargument}[1]{{ }\Dformatoptionargument{#1}}
+\providecommand{\DNdescription}[1]{%
+ \Dtabularlistfieldbody{\Dformatoptiondescription{#1}}%
+}
+
+\providecommand{\DNdefinitionlist}[1]{%
+ \begin{description}%
+ \parskip0pt%
+ #1%
+ \end{description}%
+}
+\providecommand{\DNdefinitionlistitem}[1]{%
+ % LaTeX expects the label in square brackets; we provide an empty
+ % label.
+ \item[]#1%
+}
+\providecommand{\Dformatterm}[1]{#1}
+\providecommand{\DNterm}[1]{\hspace{-5pt}\Dformatterm{#1}}
+% I'm still not sure what's the best rendering for classifiers. The
+% colon syntax is used by reStructuredText, so it's at least WYSIWYG.
+% Use slanted text because italic would cause too much emphasis.
+\providecommand{\Dformatclassifier}[1]{\textsl{#1}}
+\providecommand{\DNclassifier}[1]{~:~\Dformatclassifier{#1}}
+\providecommand{\Dformatdefinition}[1]{#1}
+\providecommand{\DNdefinition}[1]{\par\Dformatdefinition{#1}}
+
+\providecommand{\Dlineblockindentation}{2.5em}
+\providecommand{\DNlineblock}[1]{%
+ \Dmakelistenvironment{}{%
+ \ifthenelse{\equal{\Dparent}{lineblock}}{%
+ % Parent is a line block, so indent.
+ \setlength{\leftmargin}{\Dlineblockindentation}%
+ }{%
+ % At top level; don't indent.
+ \setlength{\leftmargin}{0pt}%
+ }%
+ \setlength{\rightmargin}{0pt}%
+ \setlength{\parsep}{0pt}%
+ }{%
+ #1%
+ }%
+}
+\providecommand{\DNline}[1]{\item#1}
+
+
+\providecommand{\DNtransition}{%
+ \raisebox{0.25em}{\parbox{\linewidth}{\hspace*{\fill}\hrulefill\hrulefill\hspace*{\fill}}}%
+}
+
+
+\providecommand{\Dformatblockquote}[1]{%
+ % Format contents of block quote.
+ % This occurs in block-level context, so we cannot use \textsl.
+ {\slshape#1}%
+}
+\providecommand{\Dformatattribution}[1]{---\textup{#1}}
+\providecommand{\DNblockquote}[1]{%
+ \Dmakebox{%
+ \Dformatblockquote{#1}
+ }%
+}
+\providecommand{\DNattribution}[1]{%
+ \par%
+ \begin{flushright}\Dformatattribution{#1}\end{flushright}%
+}
+
+
+% Sidebars:
+\RequirePackage{picins}
+% Vertical and horizontal margins.
+\Dprovidelength{\Dsidebarvmargin}{0.5em}
+\Dprovidelength{\Dsidebarhmargin}{1em}
+% Padding (space between contents and frame).
+\Dprovidelength{\Dsidebarpadding}{1em}
+% Frame width.
+\Dprovidelength{\Dsidebarframewidth}{2\fboxrule}
+% Position ("l" or "r").
+\providecommand{\Dsidebarposition}{r}
+% Width.
+\Dprovidelength{\Dsidebarwidth}{0.45\linewidth}
+\providecommand{\DNsidebar}[1]{
+ \parpic[\Dsidebarposition]{%
+ \begin{minipage}[t]{\Dsidebarwidth}%
+ % Doing this with nested minipages is ugly, but I haven't found
+ % another way to place vertical space before and after the fbox.
+ \vspace{\Dsidebarvmargin}%
+ {%
+ \setlength{\fboxrule}{\Dsidebarframewidth}%
+ \setlength{\fboxsep}{\Dsidebarpadding}%
+ \fbox{%
+ \begin{minipage}[t]{\linewidth}%
+ \setlength{\parindent}{\Dboxparindent}%
+ #1%
+ \end{minipage}%
+ }%
+ }%
+ \vspace{\Dsidebarvmargin}%
+ \end{minipage}%
+ }%
+}
+
+
+% Citations and footnotes.
+\providecommand{\Dformatfootnote}[1]{%
+ % Format footnote.
+ {%
+ \footnotesize#1%
+ % \par is necessary for LaTeX to adjust baselineskip to the
+ % changed font size.
+ \par%
+ }%
+}
+\providecommand{\Dformatcitation}[1]{\Dformatfootnote{#1}}
+\Dprovidelength{\Doriginalbaselineskip}{0pt}
+\providecommand{\DNfootnotereference}[1]{%
+ {%
+ % \baselineskip is 0pt in \textsuperscript, so we save it here.
+ \setlength{\Doriginalbaselineskip}{\baselineskip}%
+ \textsuperscript{#1}%
+ }%
+}
+\providecommand{\DNcitationreference}[1]{{[}#1{]}}
+\Dprovidelength{\Dfootnotesep}{3.5pt}
+\providecommand{\Dsetfootnotespacing}{%
+ % Spacing commands executed at the beginning of footnotes.
+ \setlength{\parindent}{0pt}%
+ \hspace{1em}%
+}
+\providecommand{\DNfootnote}[1]{%
+ % See ltfloat.dtx for details.
+ {%
+ \insert\footins{%
+ \vspace{\Dfootnotesep}%
+ \Dsetfootnotespacing%
+ \Dformatfootnote{#1}%
+ }%
+ }%
+}
+\providecommand{\DNcitation}[1]{\DNfootnote{#1}}
+\providecommand{\Dformatfootnotelabel}[1]{%
+ % Keep \footnotesize in footnote labels (\textsuperscript would
+ % reduce the font size even more).
+ \textsuperscript{\footnotesize#1{ }}%
+}
+\providecommand{\Dformatcitationlabel}[1]{{[}#1{]}{ }}
+\providecommand{\Dformatmultiplebackrefs}[1]{%
+ % If in printing mode, do not write out multiple backrefs.
+ \ifthenelse{\equal{\Dprinting}{true}}{}{\textsl{#1}}%
+}
+\providecommand{\Dthislabel}{}
+\providecommand{\DNlabel}[1]{%
+ \renewcommand{\Dthislabel}{#1}
+ \ifthenelse{\not\equal{\Dsinglebackref}{}}{%
+ \let\Doriginallabel=\Dthislabel%
+ \def\Dthislabel{%
+ \Dsinglefootnotebacklink{\Dsinglebackref}{\Doriginallabel}%
+ }%
+ }{}%
+ \ifthenelse{\equal{\Dparent}{footnote}}{%
+ % Footnote label.
+ \Dformatfootnotelabel{\Dthislabel}%
+ }{%
+ \ifthenelse{\equal{\Dparent}{citation}}{%
+ % Citation label.
+ \Dformatcitationlabel{\Dthislabel}%
+ }{}%
+ }%
+ % If there are multiple backrefs, add them now.
+ \Dformatmultiplebackrefs{\Dmultiplebackrefs}%
+}
+\providecommand{\Dsinglefootnotebacklink}[2]{%
+ % Create normal backlink of a footnote label. Parameters:
+ % 1. ID.
+ % 2. Link text.
+ % Treat like a footnote reference.
+ \Dimplicitfootnotereference{\##1}{#2}%
+}
+\providecommand{\Dmultifootnotebacklink}[2]{%
+ % Create generated backlink, as in (1, 2). Parameters:
+ % 1. ID.
+ % 2. Link text.
+ % Treat like a footnote reference.
+ \Dimplicitfootnotereference{\##1}{#2}%
+}
+\providecommand{\Dsinglecitationbacklink}[2]{\Dsinglefootnotebacklink{#1}{#2}}
+\providecommand{\Dmulticitationbacklink}[2]{\Dmultifootnotebacklink{#1}{#2}}
+
+
+\RequirePackage{longtable}
+\providecommand{\Dmaketable}[2]{%
+ % Make table. Parameters:
+ % 1. Table spec (like "|p|p|").
+ % 2. Table contents.
+ {%
+ \ifthenelse{\equal{\Dinsidetabular}{true}}{%
+ % Inside longtable; we cannot have nested longtables.
+ \begin{tabular}{#1}%
+ \hline%
+ #2%
+ \end{tabular}%
+ }{%
+ \renewcommand{\Dinsidetabular}{true}%
+ \begin{longtable}{#1}%
+ \hline%
+ #2%
+ \end{longtable}%
+ }%
+ }%
+}
+\providecommand{\DNthead}[1]{%
+ #1%
+ \endhead%
+}
+\providecommand{\DNrow}[1]{%
+ #1\tabularnewline%
+ \hline%
+}
+\providecommand{\Dinsidemulticolumn}{false}
+\providecommand{\Dcompensatingmulticol}[3]{%
+ \multicolumn{#1}{#2}{%
+ {%
+ \renewcommand{\Dinsidemulticolumn}{true}%
+ % Compensate for weird missing vertical space at top of paragraph.
+ \raisebox{-2.5pt}{#3}%
+ }%
+ }%
+}
+\providecommand{\Dcolspan}[2]{%
+ % Take care of the morecols attribute (but incremented by 1).
+ &%
+ \Dcompensatingmulticol{#1}{l|}{#2}%
+}
+\providecommand{\Dcolspanleft}[2]{%
+ % Like \Dmorecols, but called for the leftmost entries in a table
+ % row.
+ \Dcompensatingmulticol{#1}{|l|}{#2}%
+}
+\providecommand{\Dsubsequententry}[1]{%
+ &#1%
+}
+\providecommand{\DNentry}[1]{%
+ % The following sequence adds minimal vertical space above the top
+ % lines of the first cell paragraph, so that vertical space is
+ % balanced at the top and bottom of table cells.
+ \ifthenelse{\equal{\Dinsidemulticolumn}{false}}{%
+ \vspace{-1em}\vspace{-\parskip}\par%
+ }{}%
+ #1%
+ % No need to add an ampersand ("&"); that's done by \Dsubsequententry.
+}
+\providecommand{\DAtableheaderentry}[5]{\Dformattableheaderentry{#5}}
+\providecommand{\Dformattableheaderentry}[1]{{\bfseries#1}}
+
+
+\providecommand{\DNsystemmessage}[1]{%
+ {%
+ \ifthenelse{\equal{\Dprinting}{false}}{\color{red}}{}%
+ \bfseries%
+ #1%
+ }%
+}
+
+
+\providecommand{\Dinsidehalign}{false}
+\newsavebox{\Dalignedimagebox}
+\Dprovidelength{\Dalignedimagewidth}{0pt}
+\providecommand{\Dhalign}[2]{%
+ % Horizontally align the contents to the left or right so that the
+ % text flows around it.
+ % Parameters:
+ % 1. l or r
+ % 2. Contents.
+ \renewcommand{\Dinsidehalign}{true}%
+ % For some obscure reason \parpic consumes some vertical space.
+ \vspace{-3pt}%
+ % Now we do something *really* ugly, but this enables us to wrap the
+ % image in a minipage while still allowing tight frames when
+ % class=border (see \DNimageCborder).
+ \sbox{\Dalignedimagebox}{#2}%
+ \settowidth{\Dalignedimagewidth}{\usebox{\Dalignedimagebox}}%
+ \parpic[#1]{%
+ \begin{minipage}[b]{\Dalignedimagewidth}%
+ % Compensate for previously added space, but not entirely.
+ \vspace*{2.0pt}%
+ \vspace*{\Dfloatimagetopmargin}%
+ \usebox{\Dalignedimagebox}%
+ \vspace*{1.5pt}%
+ \vspace*{\Dfloatimagebottommargin}%
+ \end{minipage}%
+ }%
+ \renewcommand{\Dinsidehalign}{false}%
+}
+
+
+\RequirePackage{graphicx}
+% Maximum width of an image.
+\providecommand{\Dimagemaxwidth}{\linewidth}
+\providecommand{\Dfloatimagemaxwidth}{0.5\linewidth}
+% Auxiliary variable.
+\Dprovidelength{\Dcurrentimagewidth}{0pt}
+\providecommand{\DNimageAalign}[5]{%
+ \ifthenelse{\equal{#3}{left}}{%
+ \Dhalign{l}{#5}%
+ }{%
+ \ifthenelse{\equal{#3}{right}}{%
+ \Dhalign{r}{#5}%
+ }{%
+ \ifthenelse{\equal{#3}{center}}{%
+ % Text floating around centered figures is a bad idea. Thus
+ % we use a center environment. Note that no extra space is
+ % added by the writer, so the space added by the center
+ % environment is fine.
+ \begin{center}#5\end{center}%
+ }{%
+ #5%
+ }%
+ }%
+ }%
+}
+% Base path for images.
+\providecommand{\Dimagebase}{}
+% Auxiliary command. Current image path.
+\providecommand{\Dimagepath}{}
+\providecommand{\DNimageAuri}[5]{%
+ % Insert image. We treat the URI like a path here.
+ \renewcommand{\Dimagepath}{\Dimagebase#3}%
+ \Difdefined{DcurrentNimageAwidth}{%
+ \Dwidthimage{\DcurrentNimageAwidth}{\Dimagepath}%
+ }{%
+ \Dsimpleimage{\Dimagepath}%
+ }%
+}
+\Dprovidelength{\Dfloatimagevmargin}{0pt}
+\providecommand{\Dfloatimagetopmargin}{\Dfloatimagevmargin}
+\providecommand{\Dfloatimagebottommargin}{\Dfloatimagevmargin}
+\providecommand{\Dwidthimage}[2]{%
+ % Image with specified width.
+ % Parameters:
+ % 1. Image width.
+ % 2. Image path.
+ % Need to make bottom-alignment dependent on align attribute (add
+ % functional test first). Need to observe height attribute.
+ %\begin{minipage}[b]{#1}%
+ \includegraphics[width=#1,height=\textheight,keepaspectratio]{#2}%
+ %\end{minipage}%
+}
+\providecommand{\Dcurrentimagemaxwidth}{}
+\providecommand{\Dsimpleimage}[1]{%
+ % Insert image, without much parametrization.
+ \settowidth{\Dcurrentimagewidth}{\includegraphics{#1}}%
+ \ifthenelse{\equal{\Dinsidehalign}{true}}{%
+ \renewcommand{\Dcurrentimagemaxwidth}{\Dfloatimagemaxwidth}%
+ }{%
+ \renewcommand{\Dcurrentimagemaxwidth}{\Dimagemaxwidth}%
+ }%
+ \ifthenelse{\lengthtest{\Dcurrentimagewidth>\Dcurrentimagemaxwidth}}{%
+ \Dwidthimage{\Dcurrentimagemaxwidth}{#1}%
+ }{%
+ \Dwidthimage{\Dcurrentimagewidth}{#1}%
+ }%
+}
+\providecommand{\Dwidthimage}[2]{%
+ % Image with specified width.
+ % Parameters:
+ % 1. Image width.
+ % 2. Image path.
+ \Dwidthimage{#1}{#2}%
+}
+
+% Figures.
+\providecommand{\DNfigureAalign}[5]{%
+ % Hack to make it work Right Now.
+ %\def\DcurrentNimageAwidth{\DcurrentNfigureAwidth}%
+ %
+ %\def\DcurrentNimageAwidth{\linewidth}%
+ \DNimageAalign{#1}{#2}{#3}{#4}{%
+ \begin{minipage}[b]{0.4\linewidth}#5\end{minipage}}%
+ %\let\DcurrentNimageAwidth=\relax%
+ %
+ %\let\DcurrentNimageAwidth=\relax%
+}
+\providecommand{\DNcaption}[1]{\par\noindent{\slshape#1}}
+\providecommand{\DNlegend}[1]{\Dauxiliaryspace#1}
+
+\providecommand{\DCborder}[1]{\fbox{#1}}
+% No padding between image and border.
+\providecommand{\DNimageCborder}[1]{\frame{#1}}
+
+
+% Need to replace with language-specific stuff. Maybe look at
+% csquotes.sty and ask the author for permission to use parts of it.
+\providecommand{\Dtextleftdblquote}{``}
+\providecommand{\Dtextrightdblquote}{''}
+
+% Table of contents:
+\Dprovidelength{\Dtocininitialsectnumwidth}{2.4em}
+\Dprovidelength{\Dtocadditionalsectnumwidth}{0.7em}
+% Level inside a table of contents. While this is at -1, we are not
+% inside a TOC.
+\Dprovidecounter{Dtoclevel}%
+\setcounter{Dtoclevel}{-1}
+\providecommand{\Dlocaltoc}{false}%
+\providecommand{\DNtopicClocal}[1]{%
+ \renewcommand{\Dlocaltoc}{true}%
+ \addtolength{\Dtocsectnumwidth}{2\Dtocadditionalsectnumwidth}%
+ \addtolength{\Dtocindent}{-2\Dtocadditionalsectnumwidth}%
+ #1%
+ \addtolength{\Dtocindent}{2\Dtocadditionalsectnumwidth}%
+ \addtolength{\Dtocsectnumwidth}{-2\Dtocadditionalsectnumwidth}%
+ \renewcommand{\Dlocaltoc}{false}%
+}
+\Dprovidelength{\Dtocindent}{0pt}%
+\Dprovidelength{\Dtocsectnumwidth}{\Dtocininitialsectnumwidth}
+% Compensate for one additional TOC indentation space so that the
+% top-level is unindented.
+\addtolength{\Dtocsectnumwidth}{-\Dtocadditionalsectnumwidth}
+\addtolength{\Dtocindent}{-\Dtocsectnumwidth}
+\providecommand{\Difinsidetoc}[2]{%
+ \ifthenelse{\not\equal{\theDtoclevel}{-1}}{#1}{#2}%
+}
+\providecommand{\DNgeneratedCsectnum}[1]{%
+ \Difinsidetoc{%
+ % Section number inside TOC.
+ \makebox[\Dtocsectnumwidth][l]{#1}%
+ }{%
+ % Section number inside section title.
+ #1\quad%
+ }%
+}
+\providecommand{\Dtocbulletlist}[1]{%
+ \addtocounter{Dtoclevel}{1}%
+ \addtolength{\Dtocindent}{\Dtocsectnumwidth}%
+ \addtolength{\Dtocsectnumwidth}{\Dtocadditionalsectnumwidth}%
+ #1%
+ \addtolength{\Dtocsectnumwidth}{-\Dtocadditionalsectnumwidth}%
+ \addtolength{\Dtocindent}{-\Dtocsectnumwidth}%
+ \addtocounter{Dtoclevel}{-1}%
+}
+
+
+% For \Dpixelunit, the length value is pre-multiplied with 0.75, so by
+% specifying "pt" we get the same notion of "pixel" as graphicx.
+\providecommand{\Dpixelunit}{pt}
+% Normally lengths are relative to the current linewidth.
+\providecommand{\Drelativeunit}{\linewidth}
+
+
+%\RequirePackage{fixmath}
+%\RequirePackage{amsmath}
+
+
+\DSfontencoding
+\DSlanguage
+\DSlinks
+\DSsymbols
+\DSlate
+
+\makeatother
diff --git a/docutils/writers/newlatex2e/unicode_map.py b/docutils/writers/newlatex2e/unicode_map.py
new file mode 100644
index 000000000..2998178f4
--- /dev/null
+++ b/docutils/writers/newlatex2e/unicode_map.py
@@ -0,0 +1,2371 @@
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This file has been placed in the public domain.
+
+# This is a mapping of Unicode characters to LaTeX equivalents.
+# The information has been extracted from
+# <http://www.w3.org/2003/entities/xml/unicode.xml>, written by
+# David Carlisle and Sebastian Rahtz.
+#
+# The extraction has been done by the "create_unimap.py" script
+# located at <http://docutils.sf.net/tools/dev/create_unimap.py>.
+
+unicode_map = {u'\xa0': '$~$',
+u'\xa1': '{\\textexclamdown}',
+u'\xa2': '{\\textcent}',
+u'\xa3': '{\\textsterling}',
+u'\xa4': '{\\textcurrency}',
+u'\xa5': '{\\textyen}',
+u'\xa6': '{\\textbrokenbar}',
+u'\xa7': '{\\textsection}',
+u'\xa8': '{\\textasciidieresis}',
+u'\xa9': '{\\textcopyright}',
+u'\xaa': '{\\textordfeminine}',
+u'\xab': '{\\guillemotleft}',
+u'\xac': '$\\lnot$',
+u'\xad': '$\\-$',
+u'\xae': '{\\textregistered}',
+u'\xaf': '{\\textasciimacron}',
+u'\xb0': '{\\textdegree}',
+u'\xb1': '$\\pm$',
+u'\xb2': '${^2}$',
+u'\xb3': '${^3}$',
+u'\xb4': '{\\textasciiacute}',
+u'\xb5': '$\\mathrm{\\mu}$',
+u'\xb6': '{\\textparagraph}',
+u'\xb7': '$\\cdot$',
+u'\xb8': '{\\c{}}',
+u'\xb9': '${^1}$',
+u'\xba': '{\\textordmasculine}',
+u'\xbb': '{\\guillemotright}',
+u'\xbc': '{\\textonequarter}',
+u'\xbd': '{\\textonehalf}',
+u'\xbe': '{\\textthreequarters}',
+u'\xbf': '{\\textquestiondown}',
+u'\xc0': '{\\`{A}}',
+u'\xc1': "{\\'{A}}",
+u'\xc2': '{\\^{A}}',
+u'\xc3': '{\\~{A}}',
+u'\xc4': '{\\"{A}}',
+u'\xc5': '{\\AA}',
+u'\xc6': '{\\AE}',
+u'\xc7': '{\\c{C}}',
+u'\xc8': '{\\`{E}}',
+u'\xc9': "{\\'{E}}",
+u'\xca': '{\\^{E}}',
+u'\xcb': '{\\"{E}}',
+u'\xcc': '{\\`{I}}',
+u'\xcd': "{\\'{I}}",
+u'\xce': '{\\^{I}}',
+u'\xcf': '{\\"{I}}',
+u'\xd0': '{\\DH}',
+u'\xd1': '{\\~{N}}',
+u'\xd2': '{\\`{O}}',
+u'\xd3': "{\\'{O}}",
+u'\xd4': '{\\^{O}}',
+u'\xd5': '{\\~{O}}',
+u'\xd6': '{\\"{O}}',
+u'\xd7': '{\\texttimes}',
+u'\xd8': '{\\O}',
+u'\xd9': '{\\`{U}}',
+u'\xda': "{\\'{U}}",
+u'\xdb': '{\\^{U}}',
+u'\xdc': '{\\"{U}}',
+u'\xdd': "{\\'{Y}}",
+u'\xde': '{\\TH}',
+u'\xdf': '{\\ss}',
+u'\xe0': '{\\`{a}}',
+u'\xe1': "{\\'{a}}",
+u'\xe2': '{\\^{a}}',
+u'\xe3': '{\\~{a}}',
+u'\xe4': '{\\"{a}}',
+u'\xe5': '{\\aa}',
+u'\xe6': '{\\ae}',
+u'\xe7': '{\\c{c}}',
+u'\xe8': '{\\`{e}}',
+u'\xe9': "{\\'{e}}",
+u'\xea': '{\\^{e}}',
+u'\xeb': '{\\"{e}}',
+u'\xec': '{\\`{\\i}}',
+u'\xed': "{\\'{\\i}}",
+u'\xee': '{\\^{\\i}}',
+u'\xef': '{\\"{\\i}}',
+u'\xf0': '{\\dh}',
+u'\xf1': '{\\~{n}}',
+u'\xf2': '{\\`{o}}',
+u'\xf3': "{\\'{o}}",
+u'\xf4': '{\\^{o}}',
+u'\xf5': '{\\~{o}}',
+u'\xf6': '{\\"{o}}',
+u'\xf7': '$\\div$',
+u'\xf8': '{\\o}',
+u'\xf9': '{\\`{u}}',
+u'\xfa': "{\\'{u}}",
+u'\xfb': '{\\^{u}}',
+u'\xfc': '{\\"{u}}',
+u'\xfd': "{\\'{y}}",
+u'\xfe': '{\\th}',
+u'\xff': '{\\"{y}}',
+u'\u0100': '{\\={A}}',
+u'\u0101': '{\\={a}}',
+u'\u0102': '{\\u{A}}',
+u'\u0103': '{\\u{a}}',
+u'\u0104': '{\\k{A}}',
+u'\u0105': '{\\k{a}}',
+u'\u0106': "{\\'{C}}",
+u'\u0107': "{\\'{c}}",
+u'\u0108': '{\\^{C}}',
+u'\u0109': '{\\^{c}}',
+u'\u010a': '{\\.{C}}',
+u'\u010b': '{\\.{c}}',
+u'\u010c': '{\\v{C}}',
+u'\u010d': '{\\v{c}}',
+u'\u010e': '{\\v{D}}',
+u'\u010f': '{\\v{d}}',
+u'\u0110': '{\\DJ}',
+u'\u0111': '{\\dj}',
+u'\u0112': '{\\={E}}',
+u'\u0113': '{\\={e}}',
+u'\u0114': '{\\u{E}}',
+u'\u0115': '{\\u{e}}',
+u'\u0116': '{\\.{E}}',
+u'\u0117': '{\\.{e}}',
+u'\u0118': '{\\k{E}}',
+u'\u0119': '{\\k{e}}',
+u'\u011a': '{\\v{E}}',
+u'\u011b': '{\\v{e}}',
+u'\u011c': '{\\^{G}}',
+u'\u011d': '{\\^{g}}',
+u'\u011e': '{\\u{G}}',
+u'\u011f': '{\\u{g}}',
+u'\u0120': '{\\.{G}}',
+u'\u0121': '{\\.{g}}',
+u'\u0122': '{\\c{G}}',
+u'\u0123': '{\\c{g}}',
+u'\u0124': '{\\^{H}}',
+u'\u0125': '{\\^{h}}',
+u'\u0126': '{{\\fontencoding{LELA}\\selectfont\\char40}}',
+u'\u0127': '$\\Elzxh$',
+u'\u0128': '{\\~{I}}',
+u'\u0129': '{\\~{\\i}}',
+u'\u012a': '{\\={I}}',
+u'\u012b': '{\\={\\i}}',
+u'\u012c': '{\\u{I}}',
+u'\u012d': '{\\u{\\i}}',
+u'\u012e': '{\\k{I}}',
+u'\u012f': '{\\k{i}}',
+u'\u0130': '{\\.{I}}',
+u'\u0131': '{\\i}',
+u'\u0132': '{IJ}',
+u'\u0133': '{ij}',
+u'\u0134': '{\\^{J}}',
+u'\u0135': '{\\^{\\j}}',
+u'\u0136': '{\\c{K}}',
+u'\u0137': '{\\c{k}}',
+u'\u0138': '{{\\fontencoding{LELA}\\selectfont\\char91}}',
+u'\u0139': "{\\'{L}}",
+u'\u013a': "{\\'{l}}",
+u'\u013b': '{\\c{L}}',
+u'\u013c': '{\\c{l}}',
+u'\u013d': '{\\v{L}}',
+u'\u013e': '{\\v{l}}',
+u'\u013f': '{{\\fontencoding{LELA}\\selectfont\\char201}}',
+u'\u0140': '{{\\fontencoding{LELA}\\selectfont\\char202}}',
+u'\u0141': '{\\L}',
+u'\u0142': '{\\l}',
+u'\u0143': "{\\'{N}}",
+u'\u0144': "{\\'{n}}",
+u'\u0145': '{\\c{N}}',
+u'\u0146': '{\\c{n}}',
+u'\u0147': '{\\v{N}}',
+u'\u0148': '{\\v{n}}',
+u'\u0149': "{'n}",
+u'\u014a': '{\\NG}',
+u'\u014b': '{\\ng}',
+u'\u014c': '{\\={O}}',
+u'\u014d': '{\\={o}}',
+u'\u014e': '{\\u{O}}',
+u'\u014f': '{\\u{o}}',
+u'\u0150': '{\\H{O}}',
+u'\u0151': '{\\H{o}}',
+u'\u0152': '{\\OE}',
+u'\u0153': '{\\oe}',
+u'\u0154': "{\\'{R}}",
+u'\u0155': "{\\'{r}}",
+u'\u0156': '{\\c{R}}',
+u'\u0157': '{\\c{r}}',
+u'\u0158': '{\\v{R}}',
+u'\u0159': '{\\v{r}}',
+u'\u015a': "{\\'{S}}",
+u'\u015b': "{\\'{s}}",
+u'\u015c': '{\\^{S}}',
+u'\u015d': '{\\^{s}}',
+u'\u015e': '{\\c{S}}',
+u'\u015f': '{\\c{s}}',
+u'\u0160': '{\\v{S}}',
+u'\u0161': '{\\v{s}}',
+u'\u0162': '{\\c{T}}',
+u'\u0163': '{\\c{t}}',
+u'\u0164': '{\\v{T}}',
+u'\u0165': '{\\v{t}}',
+u'\u0166': '{{\\fontencoding{LELA}\\selectfont\\char47}}',
+u'\u0167': '{{\\fontencoding{LELA}\\selectfont\\char63}}',
+u'\u0168': '{\\~{U}}',
+u'\u0169': '{\\~{u}}',
+u'\u016a': '{\\={U}}',
+u'\u016b': '{\\={u}}',
+u'\u016c': '{\\u{U}}',
+u'\u016d': '{\\u{u}}',
+u'\u016e': '{\\r{U}}',
+u'\u016f': '{\\r{u}}',
+u'\u0170': '{\\H{U}}',
+u'\u0171': '{\\H{u}}',
+u'\u0172': '{\\k{U}}',
+u'\u0173': '{\\k{u}}',
+u'\u0174': '{\\^{W}}',
+u'\u0175': '{\\^{w}}',
+u'\u0176': '{\\^{Y}}',
+u'\u0177': '{\\^{y}}',
+u'\u0178': '{\\"{Y}}',
+u'\u0179': "{\\'{Z}}",
+u'\u017a': "{\\'{z}}",
+u'\u017b': '{\\.{Z}}',
+u'\u017c': '{\\.{z}}',
+u'\u017d': '{\\v{Z}}',
+u'\u017e': '{\\v{z}}',
+u'\u0192': '$f$',
+u'\u0195': '{\\texthvlig}',
+u'\u019e': '{\\textnrleg}',
+u'\u01aa': '$\\eth$',
+u'\u01ba': '{{\\fontencoding{LELA}\\selectfont\\char195}}',
+u'\u01c2': '{\\textdoublepipe}',
+u'\u01f5': "{\\'{g}}",
+u'\u0250': '$\\Elztrna$',
+u'\u0252': '$\\Elztrnsa$',
+u'\u0254': '$\\Elzopeno$',
+u'\u0256': '$\\Elzrtld$',
+u'\u0258': '{{\\fontencoding{LEIP}\\selectfont\\char61}}',
+u'\u0259': '$\\Elzschwa$',
+u'\u025b': '$\\varepsilon$',
+u'\u0261': '{g}',
+u'\u0263': '$\\Elzpgamma$',
+u'\u0264': '$\\Elzpbgam$',
+u'\u0265': '$\\Elztrnh$',
+u'\u026c': '$\\Elzbtdl$',
+u'\u026d': '$\\Elzrtll$',
+u'\u026f': '$\\Elztrnm$',
+u'\u0270': '$\\Elztrnmlr$',
+u'\u0271': '$\\Elzltlmr$',
+u'\u0272': '{\\Elzltln}',
+u'\u0273': '$\\Elzrtln$',
+u'\u0277': '$\\Elzclomeg$',
+u'\u0278': '{\\textphi}',
+u'\u0279': '$\\Elztrnr$',
+u'\u027a': '$\\Elztrnrl$',
+u'\u027b': '$\\Elzrttrnr$',
+u'\u027c': '$\\Elzrl$',
+u'\u027d': '$\\Elzrtlr$',
+u'\u027e': '$\\Elzfhr$',
+u'\u027f': '{{\\fontencoding{LEIP}\\selectfont\\char202}}',
+u'\u0282': '$\\Elzrtls$',
+u'\u0283': '$\\Elzesh$',
+u'\u0287': '$\\Elztrnt$',
+u'\u0288': '$\\Elzrtlt$',
+u'\u028a': '$\\Elzpupsil$',
+u'\u028b': '$\\Elzpscrv$',
+u'\u028c': '$\\Elzinvv$',
+u'\u028d': '$\\Elzinvw$',
+u'\u028e': '$\\Elztrny$',
+u'\u0290': '$\\Elzrtlz$',
+u'\u0292': '$\\Elzyogh$',
+u'\u0294': '$\\Elzglst$',
+u'\u0295': '$\\Elzreglst$',
+u'\u0296': '$\\Elzinglst$',
+u'\u029e': '{\\textturnk}',
+u'\u02a4': '$\\Elzdyogh$',
+u'\u02a7': '$\\Elztesh$',
+u'\u02bc': "{'}",
+u'\u02c7': '{\\textasciicaron}',
+u'\u02c8': '$\\Elzverts$',
+u'\u02cc': '$\\Elzverti$',
+u'\u02d0': '$\\Elzlmrk$',
+u'\u02d1': '$\\Elzhlmrk$',
+u'\u02d2': '$\\Elzsbrhr$',
+u'\u02d3': '$\\Elzsblhr$',
+u'\u02d4': '$\\Elzrais$',
+u'\u02d5': '$\\Elzlow$',
+u'\u02d8': '{\\textasciibreve}',
+u'\u02d9': '{\\textperiodcentered}',
+u'\u02da': '{\\r{}}',
+u'\u02db': '{\\k{}}',
+u'\u02dc': '{\\texttildelow}',
+u'\u02dd': '{\\H{}}',
+u'\u02e5': '{\\tone{55}}',
+u'\u02e6': '{\\tone{44}}',
+u'\u02e7': '{\\tone{33}}',
+u'\u02e8': '{\\tone{22}}',
+u'\u02e9': '{\\tone{11}}',
+u'\u0300': '{\\`}',
+u'\u0301': "{\\'}",
+u'\u0302': '{\\^}',
+u'\u0303': '{\\~}',
+u'\u0304': '{\\=}',
+u'\u0306': '{\\u}',
+u'\u0307': '{\\.}',
+u'\u0308': '{\\"}',
+u'\u030a': '{\\r}',
+u'\u030b': '{\\H}',
+u'\u030c': '{\\v}',
+u'\u030f': '{\\cyrchar\\C}',
+u'\u0311': '{{\\fontencoding{LECO}\\selectfont\\char177}}',
+u'\u0318': '{{\\fontencoding{LECO}\\selectfont\\char184}}',
+u'\u0319': '{{\\fontencoding{LECO}\\selectfont\\char185}}',
+u'\u0321': '$\\Elzpalh$',
+u'\u0322': '{\\Elzrh}',
+u'\u0327': '{\\c}',
+u'\u0328': '{\\k}',
+u'\u032a': '$\\Elzsbbrg$',
+u'\u032b': '{{\\fontencoding{LECO}\\selectfont\\char203}}',
+u'\u032f': '{{\\fontencoding{LECO}\\selectfont\\char207}}',
+u'\u0335': '{\\Elzxl}',
+u'\u0336': '{\\Elzbar}',
+u'\u0337': '{{\\fontencoding{LECO}\\selectfont\\char215}}',
+u'\u0338': '{{\\fontencoding{LECO}\\selectfont\\char216}}',
+u'\u033a': '{{\\fontencoding{LECO}\\selectfont\\char218}}',
+u'\u033b': '{{\\fontencoding{LECO}\\selectfont\\char219}}',
+u'\u033c': '{{\\fontencoding{LECO}\\selectfont\\char220}}',
+u'\u033d': '{{\\fontencoding{LECO}\\selectfont\\char221}}',
+u'\u0361': '{{\\fontencoding{LECO}\\selectfont\\char225}}',
+u'\u0386': "{\\'{A}}",
+u'\u0388': "{\\'{E}}",
+u'\u0389': "{\\'{H}}",
+u'\u038a': "{\\'{}{I}}",
+u'\u038c': "{\\'{}O}",
+u'\u038e': "$\\mathrm{'Y}$",
+u'\u038f': "$\\mathrm{'\\Omega}$",
+u'\u0390': '$\\acute{\\ddot{\\iota}}$',
+u'\u0391': '$\\Alpha$',
+u'\u0392': '$\\Beta$',
+u'\u0393': '$\\Gamma$',
+u'\u0394': '$\\Delta$',
+u'\u0395': '$\\Epsilon$',
+u'\u0396': '$\\Zeta$',
+u'\u0397': '$\\Eta$',
+u'\u0398': '$\\Theta$',
+u'\u0399': '$\\Iota$',
+u'\u039a': '$\\Kappa$',
+u'\u039b': '$\\Lambda$',
+u'\u039c': '$M$',
+u'\u039d': '$N$',
+u'\u039e': '$\\Xi$',
+u'\u039f': '$O$',
+u'\u03a0': '$\\Pi$',
+u'\u03a1': '$\\Rho$',
+u'\u03a3': '$\\Sigma$',
+u'\u03a4': '$\\Tau$',
+u'\u03a5': '$\\Upsilon$',
+u'\u03a6': '$\\Phi$',
+u'\u03a7': '$\\Chi$',
+u'\u03a8': '$\\Psi$',
+u'\u03a9': '$\\Omega$',
+u'\u03aa': '$\\mathrm{\\ddot{I}}$',
+u'\u03ab': '$\\mathrm{\\ddot{Y}}$',
+u'\u03ac': "{\\'{$\\alpha$}}",
+u'\u03ad': '$\\acute{\\epsilon}$',
+u'\u03ae': '$\\acute{\\eta}$',
+u'\u03af': '$\\acute{\\iota}$',
+u'\u03b0': '$\\acute{\\ddot{\\upsilon}}$',
+u'\u03b1': '$\\alpha$',
+u'\u03b2': '$\\beta$',
+u'\u03b3': '$\\gamma$',
+u'\u03b4': '$\\delta$',
+u'\u03b5': '$\\epsilon$',
+u'\u03b6': '$\\zeta$',
+u'\u03b7': '$\\eta$',
+u'\u03b8': '{\\texttheta}',
+u'\u03b9': '$\\iota$',
+u'\u03ba': '$\\kappa$',
+u'\u03bb': '$\\lambda$',
+u'\u03bc': '$\\mu$',
+u'\u03bd': '$\\nu$',
+u'\u03be': '$\\xi$',
+u'\u03bf': '$o$',
+u'\u03c0': '$\\pi$',
+u'\u03c1': '$\\rho$',
+u'\u03c2': '$\\varsigma$',
+u'\u03c3': '$\\sigma$',
+u'\u03c4': '$\\tau$',
+u'\u03c5': '$\\upsilon$',
+u'\u03c6': '$\\varphi$',
+u'\u03c7': '$\\chi$',
+u'\u03c8': '$\\psi$',
+u'\u03c9': '$\\omega$',
+u'\u03ca': '$\\ddot{\\iota}$',
+u'\u03cb': '$\\ddot{\\upsilon}$',
+u'\u03cc': "{\\'{o}}",
+u'\u03cd': '$\\acute{\\upsilon}$',
+u'\u03ce': '$\\acute{\\omega}$',
+u'\u03d0': '{\\Pisymbol{ppi022}{87}}',
+u'\u03d1': '{\\textvartheta}',
+u'\u03d2': '$\\Upsilon$',
+u'\u03d5': '$\\phi$',
+u'\u03d6': '$\\varpi$',
+u'\u03da': '$\\Stigma$',
+u'\u03dc': '$\\Digamma$',
+u'\u03dd': '$\\digamma$',
+u'\u03de': '$\\Koppa$',
+u'\u03e0': '$\\Sampi$',
+u'\u03f0': '$\\varkappa$',
+u'\u03f1': '$\\varrho$',
+u'\u03f4': '{\\textTheta}',
+u'\u03f6': '$\\backepsilon$',
+u'\u0401': '{\\cyrchar\\CYRYO}',
+u'\u0402': '{\\cyrchar\\CYRDJE}',
+u'\u0403': "{\\cyrchar{\\'\\CYRG}}",
+u'\u0404': '{\\cyrchar\\CYRIE}',
+u'\u0405': '{\\cyrchar\\CYRDZE}',
+u'\u0406': '{\\cyrchar\\CYRII}',
+u'\u0407': '{\\cyrchar\\CYRYI}',
+u'\u0408': '{\\cyrchar\\CYRJE}',
+u'\u0409': '{\\cyrchar\\CYRLJE}',
+u'\u040a': '{\\cyrchar\\CYRNJE}',
+u'\u040b': '{\\cyrchar\\CYRTSHE}',
+u'\u040c': "{\\cyrchar{\\'\\CYRK}}",
+u'\u040e': '{\\cyrchar\\CYRUSHRT}',
+u'\u040f': '{\\cyrchar\\CYRDZHE}',
+u'\u0410': '{\\cyrchar\\CYRA}',
+u'\u0411': '{\\cyrchar\\CYRB}',
+u'\u0412': '{\\cyrchar\\CYRV}',
+u'\u0413': '{\\cyrchar\\CYRG}',
+u'\u0414': '{\\cyrchar\\CYRD}',
+u'\u0415': '{\\cyrchar\\CYRE}',
+u'\u0416': '{\\cyrchar\\CYRZH}',
+u'\u0417': '{\\cyrchar\\CYRZ}',
+u'\u0418': '{\\cyrchar\\CYRI}',
+u'\u0419': '{\\cyrchar\\CYRISHRT}',
+u'\u041a': '{\\cyrchar\\CYRK}',
+u'\u041b': '{\\cyrchar\\CYRL}',
+u'\u041c': '{\\cyrchar\\CYRM}',
+u'\u041d': '{\\cyrchar\\CYRN}',
+u'\u041e': '{\\cyrchar\\CYRO}',
+u'\u041f': '{\\cyrchar\\CYRP}',
+u'\u0420': '{\\cyrchar\\CYRR}',
+u'\u0421': '{\\cyrchar\\CYRS}',
+u'\u0422': '{\\cyrchar\\CYRT}',
+u'\u0423': '{\\cyrchar\\CYRU}',
+u'\u0424': '{\\cyrchar\\CYRF}',
+u'\u0425': '{\\cyrchar\\CYRH}',
+u'\u0426': '{\\cyrchar\\CYRC}',
+u'\u0427': '{\\cyrchar\\CYRCH}',
+u'\u0428': '{\\cyrchar\\CYRSH}',
+u'\u0429': '{\\cyrchar\\CYRSHCH}',
+u'\u042a': '{\\cyrchar\\CYRHRDSN}',
+u'\u042b': '{\\cyrchar\\CYRERY}',
+u'\u042c': '{\\cyrchar\\CYRSFTSN}',
+u'\u042d': '{\\cyrchar\\CYREREV}',
+u'\u042e': '{\\cyrchar\\CYRYU}',
+u'\u042f': '{\\cyrchar\\CYRYA}',
+u'\u0430': '{\\cyrchar\\cyra}',
+u'\u0431': '{\\cyrchar\\cyrb}',
+u'\u0432': '{\\cyrchar\\cyrv}',
+u'\u0433': '{\\cyrchar\\cyrg}',
+u'\u0434': '{\\cyrchar\\cyrd}',
+u'\u0435': '{\\cyrchar\\cyre}',
+u'\u0436': '{\\cyrchar\\cyrzh}',
+u'\u0437': '{\\cyrchar\\cyrz}',
+u'\u0438': '{\\cyrchar\\cyri}',
+u'\u0439': '{\\cyrchar\\cyrishrt}',
+u'\u043a': '{\\cyrchar\\cyrk}',
+u'\u043b': '{\\cyrchar\\cyrl}',
+u'\u043c': '{\\cyrchar\\cyrm}',
+u'\u043d': '{\\cyrchar\\cyrn}',
+u'\u043e': '{\\cyrchar\\cyro}',
+u'\u043f': '{\\cyrchar\\cyrp}',
+u'\u0440': '{\\cyrchar\\cyrr}',
+u'\u0441': '{\\cyrchar\\cyrs}',
+u'\u0442': '{\\cyrchar\\cyrt}',
+u'\u0443': '{\\cyrchar\\cyru}',
+u'\u0444': '{\\cyrchar\\cyrf}',
+u'\u0445': '{\\cyrchar\\cyrh}',
+u'\u0446': '{\\cyrchar\\cyrc}',
+u'\u0447': '{\\cyrchar\\cyrch}',
+u'\u0448': '{\\cyrchar\\cyrsh}',
+u'\u0449': '{\\cyrchar\\cyrshch}',
+u'\u044a': '{\\cyrchar\\cyrhrdsn}',
+u'\u044b': '{\\cyrchar\\cyrery}',
+u'\u044c': '{\\cyrchar\\cyrsftsn}',
+u'\u044d': '{\\cyrchar\\cyrerev}',
+u'\u044e': '{\\cyrchar\\cyryu}',
+u'\u044f': '{\\cyrchar\\cyrya}',
+u'\u0451': '{\\cyrchar\\cyryo}',
+u'\u0452': '{\\cyrchar\\cyrdje}',
+u'\u0453': "{\\cyrchar{\\'\\cyrg}}",
+u'\u0454': '{\\cyrchar\\cyrie}',
+u'\u0455': '{\\cyrchar\\cyrdze}',
+u'\u0456': '{\\cyrchar\\cyrii}',
+u'\u0457': '{\\cyrchar\\cyryi}',
+u'\u0458': '{\\cyrchar\\cyrje}',
+u'\u0459': '{\\cyrchar\\cyrlje}',
+u'\u045a': '{\\cyrchar\\cyrnje}',
+u'\u045b': '{\\cyrchar\\cyrtshe}',
+u'\u045c': "{\\cyrchar{\\'\\cyrk}}",
+u'\u045e': '{\\cyrchar\\cyrushrt}',
+u'\u045f': '{\\cyrchar\\cyrdzhe}',
+u'\u0460': '{\\cyrchar\\CYROMEGA}',
+u'\u0461': '{\\cyrchar\\cyromega}',
+u'\u0462': '{\\cyrchar\\CYRYAT}',
+u'\u0464': '{\\cyrchar\\CYRIOTE}',
+u'\u0465': '{\\cyrchar\\cyriote}',
+u'\u0466': '{\\cyrchar\\CYRLYUS}',
+u'\u0467': '{\\cyrchar\\cyrlyus}',
+u'\u0468': '{\\cyrchar\\CYRIOTLYUS}',
+u'\u0469': '{\\cyrchar\\cyriotlyus}',
+u'\u046a': '{\\cyrchar\\CYRBYUS}',
+u'\u046c': '{\\cyrchar\\CYRIOTBYUS}',
+u'\u046d': '{\\cyrchar\\cyriotbyus}',
+u'\u046e': '{\\cyrchar\\CYRKSI}',
+u'\u046f': '{\\cyrchar\\cyrksi}',
+u'\u0470': '{\\cyrchar\\CYRPSI}',
+u'\u0471': '{\\cyrchar\\cyrpsi}',
+u'\u0472': '{\\cyrchar\\CYRFITA}',
+u'\u0474': '{\\cyrchar\\CYRIZH}',
+u'\u0478': '{\\cyrchar\\CYRUK}',
+u'\u0479': '{\\cyrchar\\cyruk}',
+u'\u047a': '{\\cyrchar\\CYROMEGARND}',
+u'\u047b': '{\\cyrchar\\cyromegarnd}',
+u'\u047c': '{\\cyrchar\\CYROMEGATITLO}',
+u'\u047d': '{\\cyrchar\\cyromegatitlo}',
+u'\u047e': '{\\cyrchar\\CYROT}',
+u'\u047f': '{\\cyrchar\\cyrot}',
+u'\u0480': '{\\cyrchar\\CYRKOPPA}',
+u'\u0481': '{\\cyrchar\\cyrkoppa}',
+u'\u0482': '{\\cyrchar\\cyrthousands}',
+u'\u0488': '{\\cyrchar\\cyrhundredthousands}',
+u'\u0489': '{\\cyrchar\\cyrmillions}',
+u'\u048c': '{\\cyrchar\\CYRSEMISFTSN}',
+u'\u048d': '{\\cyrchar\\cyrsemisftsn}',
+u'\u048e': '{\\cyrchar\\CYRRTICK}',
+u'\u048f': '{\\cyrchar\\cyrrtick}',
+u'\u0490': '{\\cyrchar\\CYRGUP}',
+u'\u0491': '{\\cyrchar\\cyrgup}',
+u'\u0492': '{\\cyrchar\\CYRGHCRS}',
+u'\u0493': '{\\cyrchar\\cyrghcrs}',
+u'\u0494': '{\\cyrchar\\CYRGHK}',
+u'\u0495': '{\\cyrchar\\cyrghk}',
+u'\u0496': '{\\cyrchar\\CYRZHDSC}',
+u'\u0497': '{\\cyrchar\\cyrzhdsc}',
+u'\u0498': '{\\cyrchar\\CYRZDSC}',
+u'\u0499': '{\\cyrchar\\cyrzdsc}',
+u'\u049a': '{\\cyrchar\\CYRKDSC}',
+u'\u049b': '{\\cyrchar\\cyrkdsc}',
+u'\u049c': '{\\cyrchar\\CYRKVCRS}',
+u'\u049d': '{\\cyrchar\\cyrkvcrs}',
+u'\u049e': '{\\cyrchar\\CYRKHCRS}',
+u'\u049f': '{\\cyrchar\\cyrkhcrs}',
+u'\u04a0': '{\\cyrchar\\CYRKBEAK}',
+u'\u04a1': '{\\cyrchar\\cyrkbeak}',
+u'\u04a2': '{\\cyrchar\\CYRNDSC}',
+u'\u04a3': '{\\cyrchar\\cyrndsc}',
+u'\u04a4': '{\\cyrchar\\CYRNG}',
+u'\u04a5': '{\\cyrchar\\cyrng}',
+u'\u04a6': '{\\cyrchar\\CYRPHK}',
+u'\u04a7': '{\\cyrchar\\cyrphk}',
+u'\u04a8': '{\\cyrchar\\CYRABHHA}',
+u'\u04a9': '{\\cyrchar\\cyrabhha}',
+u'\u04aa': '{\\cyrchar\\CYRSDSC}',
+u'\u04ab': '{\\cyrchar\\cyrsdsc}',
+u'\u04ac': '{\\cyrchar\\CYRTDSC}',
+u'\u04ad': '{\\cyrchar\\cyrtdsc}',
+u'\u04ae': '{\\cyrchar\\CYRY}',
+u'\u04af': '{\\cyrchar\\cyry}',
+u'\u04b0': '{\\cyrchar\\CYRYHCRS}',
+u'\u04b1': '{\\cyrchar\\cyryhcrs}',
+u'\u04b2': '{\\cyrchar\\CYRHDSC}',
+u'\u04b3': '{\\cyrchar\\cyrhdsc}',
+u'\u04b4': '{\\cyrchar\\CYRTETSE}',
+u'\u04b5': '{\\cyrchar\\cyrtetse}',
+u'\u04b6': '{\\cyrchar\\CYRCHRDSC}',
+u'\u04b7': '{\\cyrchar\\cyrchrdsc}',
+u'\u04b8': '{\\cyrchar\\CYRCHVCRS}',
+u'\u04b9': '{\\cyrchar\\cyrchvcrs}',
+u'\u04ba': '{\\cyrchar\\CYRSHHA}',
+u'\u04bb': '{\\cyrchar\\cyrshha}',
+u'\u04bc': '{\\cyrchar\\CYRABHCH}',
+u'\u04bd': '{\\cyrchar\\cyrabhch}',
+u'\u04be': '{\\cyrchar\\CYRABHCHDSC}',
+u'\u04bf': '{\\cyrchar\\cyrabhchdsc}',
+u'\u04c0': '{\\cyrchar\\CYRpalochka}',
+u'\u04c3': '{\\cyrchar\\CYRKHK}',
+u'\u04c4': '{\\cyrchar\\cyrkhk}',
+u'\u04c7': '{\\cyrchar\\CYRNHK}',
+u'\u04c8': '{\\cyrchar\\cyrnhk}',
+u'\u04cb': '{\\cyrchar\\CYRCHLDSC}',
+u'\u04cc': '{\\cyrchar\\cyrchldsc}',
+u'\u04d4': '{\\cyrchar\\CYRAE}',
+u'\u04d5': '{\\cyrchar\\cyrae}',
+u'\u04d8': '{\\cyrchar\\CYRSCHWA}',
+u'\u04d9': '{\\cyrchar\\cyrschwa}',
+u'\u04e0': '{\\cyrchar\\CYRABHDZE}',
+u'\u04e1': '{\\cyrchar\\cyrabhdze}',
+u'\u04e8': '{\\cyrchar\\CYROTLD}',
+u'\u04e9': '{\\cyrchar\\cyrotld}',
+u'\u2002': '{\\hspace{0.6em}}',
+u'\u2003': '{\\hspace{1em}}',
+u'\u2004': '{\\hspace{0.33em}}',
+u'\u2005': '{\\hspace{0.25em}}',
+u'\u2006': '{\\hspace{0.166em}}',
+u'\u2007': '{\\hphantom{0}}',
+u'\u2008': '{\\hphantom{,}}',
+u'\u2009': '{\\hspace{0.167em}}',
+u'\u200a': '$\\mkern1mu$',
+u'\u2010': '{-}',
+u'\u2013': '{\\textendash}',
+u'\u2014': '{\\textemdash}',
+u'\u2015': '{\\rule{1em}{1pt}}',
+u'\u2016': '$\\Vert$',
+u'\u2018': '{`}',
+u'\u2019': "{'}",
+u'\u201a': '{,}',
+u'\u201b': '$\\Elzreapos$',
+u'\u201c': '{\\textquotedblleft}',
+u'\u201d': '{\\textquotedblright}',
+u'\u201e': '{,,}',
+u'\u2020': '{\\textdagger}',
+u'\u2021': '{\\textdaggerdbl}',
+u'\u2022': '{\\textbullet}',
+u'\u2024': '{.}',
+u'\u2025': '{..}',
+u'\u2026': '{\\ldots}',
+u'\u2030': '{\\textperthousand}',
+u'\u2031': '{\\textpertenthousand}',
+u'\u2032': "${'}$",
+u'\u2033': "${''}$",
+u'\u2034': "${'''}$",
+u'\u2035': '$\\backprime$',
+u'\u2039': '{\\guilsinglleft}',
+u'\u203a': '{\\guilsinglright}',
+u'\u2057': "$''''$",
+u'\u205f': '{\\mkern4mu}',
+u'\u2060': '{\\nolinebreak}',
+u'\u20a7': '{\\ensuremath{\\Elzpes}}',
+u'\u20ac': '{\\mbox{\\texteuro}}',
+u'\u20db': '$\\dddot$',
+u'\u20dc': '$\\ddddot$',
+u'\u2102': '$\\mathbb{C}$',
+u'\u210a': '{\\mathscr{g}}',
+u'\u210b': '$\\mathscr{H}$',
+u'\u210c': '$\\mathfrak{H}$',
+u'\u210d': '$\\mathbb{H}$',
+u'\u210f': '$\\hslash$',
+u'\u2110': '$\\mathscr{I}$',
+u'\u2111': '$\\mathfrak{I}$',
+u'\u2112': '$\\mathscr{L}$',
+u'\u2113': '$\\mathscr{l}$',
+u'\u2115': '$\\mathbb{N}$',
+u'\u2116': '{\\cyrchar\\textnumero}',
+u'\u2118': '$\\wp$',
+u'\u2119': '$\\mathbb{P}$',
+u'\u211a': '$\\mathbb{Q}$',
+u'\u211b': '$\\mathscr{R}$',
+u'\u211c': '$\\mathfrak{R}$',
+u'\u211d': '$\\mathbb{R}$',
+u'\u211e': '$\\Elzxrat$',
+u'\u2122': '{\\texttrademark}',
+u'\u2124': '$\\mathbb{Z}$',
+u'\u2126': '$\\Omega$',
+u'\u2127': '$\\mho$',
+u'\u2128': '$\\mathfrak{Z}$',
+u'\u2129': '$\\ElsevierGlyph{2129}$',
+u'\u212b': '{\\AA}',
+u'\u212c': '$\\mathscr{B}$',
+u'\u212d': '$\\mathfrak{C}$',
+u'\u212f': '$\\mathscr{e}$',
+u'\u2130': '$\\mathscr{E}$',
+u'\u2131': '$\\mathscr{F}$',
+u'\u2133': '$\\mathscr{M}$',
+u'\u2134': '$\\mathscr{o}$',
+u'\u2135': '$\\aleph$',
+u'\u2136': '$\\beth$',
+u'\u2137': '$\\gimel$',
+u'\u2138': '$\\daleth$',
+u'\u2153': '$\\textfrac{1}{3}$',
+u'\u2154': '$\\textfrac{2}{3}$',
+u'\u2155': '$\\textfrac{1}{5}$',
+u'\u2156': '$\\textfrac{2}{5}$',
+u'\u2157': '$\\textfrac{3}{5}$',
+u'\u2158': '$\\textfrac{4}{5}$',
+u'\u2159': '$\\textfrac{1}{6}$',
+u'\u215a': '$\\textfrac{5}{6}$',
+u'\u215b': '$\\textfrac{1}{8}$',
+u'\u215c': '$\\textfrac{3}{8}$',
+u'\u215d': '$\\textfrac{5}{8}$',
+u'\u215e': '$\\textfrac{7}{8}$',
+u'\u2190': '$\\leftarrow$',
+u'\u2191': '$\\uparrow$',
+u'\u2192': '$\\rightarrow$',
+u'\u2193': '$\\downarrow$',
+u'\u2194': '$\\leftrightarrow$',
+u'\u2195': '$\\updownarrow$',
+u'\u2196': '$\\nwarrow$',
+u'\u2197': '$\\nearrow$',
+u'\u2198': '$\\searrow$',
+u'\u2199': '$\\swarrow$',
+u'\u219a': '$\\nleftarrow$',
+u'\u219b': '$\\nrightarrow$',
+u'\u219c': '$\\arrowwaveright$',
+u'\u219d': '$\\arrowwaveright$',
+u'\u219e': '$\\twoheadleftarrow$',
+u'\u21a0': '$\\twoheadrightarrow$',
+u'\u21a2': '$\\leftarrowtail$',
+u'\u21a3': '$\\rightarrowtail$',
+u'\u21a6': '$\\mapsto$',
+u'\u21a9': '$\\hookleftarrow$',
+u'\u21aa': '$\\hookrightarrow$',
+u'\u21ab': '$\\looparrowleft$',
+u'\u21ac': '$\\looparrowright$',
+u'\u21ad': '$\\leftrightsquigarrow$',
+u'\u21ae': '$\\nleftrightarrow$',
+u'\u21b0': '$\\Lsh$',
+u'\u21b1': '$\\Rsh$',
+u'\u21b3': '$\\ElsevierGlyph{21B3}$',
+u'\u21b6': '$\\curvearrowleft$',
+u'\u21b7': '$\\curvearrowright$',
+u'\u21ba': '$\\circlearrowleft$',
+u'\u21bb': '$\\circlearrowright$',
+u'\u21bc': '$\\leftharpoonup$',
+u'\u21bd': '$\\leftharpoondown$',
+u'\u21be': '$\\upharpoonright$',
+u'\u21bf': '$\\upharpoonleft$',
+u'\u21c0': '$\\rightharpoonup$',
+u'\u21c1': '$\\rightharpoondown$',
+u'\u21c2': '$\\downharpoonright$',
+u'\u21c3': '$\\downharpoonleft$',
+u'\u21c4': '$\\rightleftarrows$',
+u'\u21c5': '$\\dblarrowupdown$',
+u'\u21c6': '$\\leftrightarrows$',
+u'\u21c7': '$\\leftleftarrows$',
+u'\u21c8': '$\\upuparrows$',
+u'\u21c9': '$\\rightrightarrows$',
+u'\u21ca': '$\\downdownarrows$',
+u'\u21cb': '$\\leftrightharpoons$',
+u'\u21cc': '$\\rightleftharpoons$',
+u'\u21cd': '$\\nLeftarrow$',
+u'\u21ce': '$\\nLeftrightarrow$',
+u'\u21cf': '$\\nRightarrow$',
+u'\u21d0': '$\\Leftarrow$',
+u'\u21d1': '$\\Uparrow$',
+u'\u21d2': '$\\Rightarrow$',
+u'\u21d3': '$\\Downarrow$',
+u'\u21d4': '$\\Leftrightarrow$',
+u'\u21d5': '$\\Updownarrow$',
+u'\u21da': '$\\Lleftarrow$',
+u'\u21db': '$\\Rrightarrow$',
+u'\u21dd': '$\\rightsquigarrow$',
+u'\u21f5': '$\\DownArrowUpArrow$',
+u'\u2200': '$\\forall$',
+u'\u2201': '$\\complement$',
+u'\u2202': '$\\partial$',
+u'\u2203': '$\\exists$',
+u'\u2204': '$\\nexists$',
+u'\u2205': '$\\varnothing$',
+u'\u2207': '$\\nabla$',
+u'\u2208': '$\\in$',
+u'\u2209': '$\\not\\in$',
+u'\u220b': '$\\ni$',
+u'\u220c': '$\\not\\ni$',
+u'\u220f': '$\\prod$',
+u'\u2210': '$\\coprod$',
+u'\u2211': '$\\sum$',
+u'\u2212': '{-}',
+u'\u2213': '$\\mp$',
+u'\u2214': '$\\dotplus$',
+u'\u2216': '$\\setminus$',
+u'\u2217': '${_\\ast}$',
+u'\u2218': '$\\circ$',
+u'\u2219': '$\\bullet$',
+u'\u221a': '$\\surd$',
+u'\u221d': '$\\propto$',
+u'\u221e': '$\\infty$',
+u'\u221f': '$\\rightangle$',
+u'\u2220': '$\\angle$',
+u'\u2221': '$\\measuredangle$',
+u'\u2222': '$\\sphericalangle$',
+u'\u2223': '$\\mid$',
+u'\u2224': '$\\nmid$',
+u'\u2225': '$\\parallel$',
+u'\u2226': '$\\nparallel$',
+u'\u2227': '$\\wedge$',
+u'\u2228': '$\\vee$',
+u'\u2229': '$\\cap$',
+u'\u222a': '$\\cup$',
+u'\u222b': '$\\int$',
+u'\u222c': '$\\int\\!\\int$',
+u'\u222d': '$\\int\\!\\int\\!\\int$',
+u'\u222e': '$\\oint$',
+u'\u222f': '$\\surfintegral$',
+u'\u2230': '$\\volintegral$',
+u'\u2231': '$\\clwintegral$',
+u'\u2232': '$\\ElsevierGlyph{2232}$',
+u'\u2233': '$\\ElsevierGlyph{2233}$',
+u'\u2234': '$\\therefore$',
+u'\u2235': '$\\because$',
+u'\u2237': '$\\Colon$',
+u'\u2238': '$\\ElsevierGlyph{2238}$',
+u'\u223a': '$\\mathbin{{:}\\!\\!{-}\\!\\!{:}}$',
+u'\u223b': '$\\homothetic$',
+u'\u223c': '$\\sim$',
+u'\u223d': '$\\backsim$',
+u'\u223e': '$\\lazysinv$',
+u'\u2240': '$\\wr$',
+u'\u2241': '$\\not\\sim$',
+u'\u2242': '$\\ElsevierGlyph{2242}$',
+u'\u2243': '$\\simeq$',
+u'\u2244': '$\\not\\simeq$',
+u'\u2245': '$\\cong$',
+u'\u2246': '$\\approxnotequal$',
+u'\u2247': '$\\not\\cong$',
+u'\u2248': '$\\approx$',
+u'\u2249': '$\\not\\approx$',
+u'\u224a': '$\\approxeq$',
+u'\u224b': '$\\tildetrpl$',
+u'\u224c': '$\\allequal$',
+u'\u224d': '$\\asymp$',
+u'\u224e': '$\\Bumpeq$',
+u'\u224f': '$\\bumpeq$',
+u'\u2250': '$\\doteq$',
+u'\u2251': '$\\doteqdot$',
+u'\u2252': '$\\fallingdotseq$',
+u'\u2253': '$\\risingdotseq$',
+u'\u2254': '{:=}',
+u'\u2255': '$=:$',
+u'\u2256': '$\\eqcirc$',
+u'\u2257': '$\\circeq$',
+u'\u2259': '$\\estimates$',
+u'\u225a': '$\\ElsevierGlyph{225A}$',
+u'\u225b': '$\\starequal$',
+u'\u225c': '$\\triangleq$',
+u'\u225f': '$\\ElsevierGlyph{225F}$',
+u'\u2260': '$\\not =$',
+u'\u2261': '$\\equiv$',
+u'\u2262': '$\\not\\equiv$',
+u'\u2264': '$\\leq$',
+u'\u2265': '$\\geq$',
+u'\u2266': '$\\leqq$',
+u'\u2267': '$\\geqq$',
+u'\u2268': '$\\lneqq$',
+u'\u2269': '$\\gneqq$',
+u'\u226a': '$\\ll$',
+u'\u226b': '$\\gg$',
+u'\u226c': '$\\between$',
+u'\u226d': '$\\not\\kern-0.3em\\times$',
+u'\u226e': '$\\not<$',
+u'\u226f': '$\\not>$',
+u'\u2270': '$\\not\\leq$',
+u'\u2271': '$\\not\\geq$',
+u'\u2272': '$\\lessequivlnt$',
+u'\u2273': '$\\greaterequivlnt$',
+u'\u2274': '$\\ElsevierGlyph{2274}$',
+u'\u2275': '$\\ElsevierGlyph{2275}$',
+u'\u2276': '$\\lessgtr$',
+u'\u2277': '$\\gtrless$',
+u'\u2278': '$\\notlessgreater$',
+u'\u2279': '$\\notgreaterless$',
+u'\u227a': '$\\prec$',
+u'\u227b': '$\\succ$',
+u'\u227c': '$\\preccurlyeq$',
+u'\u227d': '$\\succcurlyeq$',
+u'\u227e': '$\\precapprox$',
+u'\u227f': '$\\succapprox$',
+u'\u2280': '$\\not\\prec$',
+u'\u2281': '$\\not\\succ$',
+u'\u2282': '$\\subset$',
+u'\u2283': '$\\supset$',
+u'\u2284': '$\\not\\subset$',
+u'\u2285': '$\\not\\supset$',
+u'\u2286': '$\\subseteq$',
+u'\u2287': '$\\supseteq$',
+u'\u2288': '$\\not\\subseteq$',
+u'\u2289': '$\\not\\supseteq$',
+u'\u228a': '$\\subsetneq$',
+u'\u228b': '$\\supsetneq$',
+u'\u228e': '$\\uplus$',
+u'\u228f': '$\\sqsubset$',
+u'\u2290': '$\\sqsupset$',
+u'\u2291': '$\\sqsubseteq$',
+u'\u2292': '$\\sqsupseteq$',
+u'\u2293': '$\\sqcap$',
+u'\u2294': '$\\sqcup$',
+u'\u2295': '$\\oplus$',
+u'\u2296': '$\\ominus$',
+u'\u2297': '$\\otimes$',
+u'\u2298': '$\\oslash$',
+u'\u2299': '$\\odot$',
+u'\u229a': '$\\circledcirc$',
+u'\u229b': '$\\circledast$',
+u'\u229d': '$\\circleddash$',
+u'\u229e': '$\\boxplus$',
+u'\u229f': '$\\boxminus$',
+u'\u22a0': '$\\boxtimes$',
+u'\u22a1': '$\\boxdot$',
+u'\u22a2': '$\\vdash$',
+u'\u22a3': '$\\dashv$',
+u'\u22a4': '$\\top$',
+u'\u22a5': '$\\perp$',
+u'\u22a7': '$\\truestate$',
+u'\u22a8': '$\\forcesextra$',
+u'\u22a9': '$\\Vdash$',
+u'\u22aa': '$\\Vvdash$',
+u'\u22ab': '$\\VDash$',
+u'\u22ac': '$\\nvdash$',
+u'\u22ad': '$\\nvDash$',
+u'\u22ae': '$\\nVdash$',
+u'\u22af': '$\\nVDash$',
+u'\u22b2': '$\\vartriangleleft$',
+u'\u22b3': '$\\vartriangleright$',
+u'\u22b4': '$\\trianglelefteq$',
+u'\u22b5': '$\\trianglerighteq$',
+u'\u22b6': '$\\original$',
+u'\u22b7': '$\\image$',
+u'\u22b8': '$\\multimap$',
+u'\u22b9': '$\\hermitconjmatrix$',
+u'\u22ba': '$\\intercal$',
+u'\u22bb': '$\\veebar$',
+u'\u22be': '$\\rightanglearc$',
+u'\u22c0': '$\\ElsevierGlyph{22C0}$',
+u'\u22c1': '$\\ElsevierGlyph{22C1}$',
+u'\u22c2': '$\\bigcap$',
+u'\u22c3': '$\\bigcup$',
+u'\u22c4': '$\\diamond$',
+u'\u22c5': '$\\cdot$',
+u'\u22c6': '$\\star$',
+u'\u22c7': '$\\divideontimes$',
+u'\u22c8': '$\\bowtie$',
+u'\u22c9': '$\\ltimes$',
+u'\u22ca': '$\\rtimes$',
+u'\u22cb': '$\\leftthreetimes$',
+u'\u22cc': '$\\rightthreetimes$',
+u'\u22cd': '$\\backsimeq$',
+u'\u22ce': '$\\curlyvee$',
+u'\u22cf': '$\\curlywedge$',
+u'\u22d0': '$\\Subset$',
+u'\u22d1': '$\\Supset$',
+u'\u22d2': '$\\Cap$',
+u'\u22d3': '$\\Cup$',
+u'\u22d4': '$\\pitchfork$',
+u'\u22d6': '$\\lessdot$',
+u'\u22d7': '$\\gtrdot$',
+u'\u22d8': '$\\verymuchless$',
+u'\u22d9': '$\\verymuchgreater$',
+u'\u22da': '$\\lesseqgtr$',
+u'\u22db': '$\\gtreqless$',
+u'\u22de': '$\\curlyeqprec$',
+u'\u22df': '$\\curlyeqsucc$',
+u'\u22e2': '$\\not\\sqsubseteq$',
+u'\u22e3': '$\\not\\sqsupseteq$',
+u'\u22e5': '$\\Elzsqspne$',
+u'\u22e6': '$\\lnsim$',
+u'\u22e7': '$\\gnsim$',
+u'\u22e8': '$\\precedesnotsimilar$',
+u'\u22e9': '$\\succnsim$',
+u'\u22ea': '$\\ntriangleleft$',
+u'\u22eb': '$\\ntriangleright$',
+u'\u22ec': '$\\ntrianglelefteq$',
+u'\u22ed': '$\\ntrianglerighteq$',
+u'\u22ee': '$\\vdots$',
+u'\u22ef': '$\\cdots$',
+u'\u22f0': '$\\upslopeellipsis$',
+u'\u22f1': '$\\downslopeellipsis$',
+u'\u2305': '{\\barwedge}',
+u'\u2306': '$\\perspcorrespond$',
+u'\u2308': '$\\lceil$',
+u'\u2309': '$\\rceil$',
+u'\u230a': '$\\lfloor$',
+u'\u230b': '$\\rfloor$',
+u'\u2315': '$\\recorder$',
+u'\u2316': '$\\mathchar"2208$',
+u'\u231c': '$\\ulcorner$',
+u'\u231d': '$\\urcorner$',
+u'\u231e': '$\\llcorner$',
+u'\u231f': '$\\lrcorner$',
+u'\u2322': '$\\frown$',
+u'\u2323': '$\\smile$',
+u'\u2329': '$\\langle$',
+u'\u232a': '$\\rangle$',
+u'\u233d': '$\\ElsevierGlyph{E838}$',
+u'\u23a3': '$\\Elzdlcorn$',
+u'\u23b0': '$\\lmoustache$',
+u'\u23b1': '$\\rmoustache$',
+u'\u2423': '{\\textvisiblespace}',
+u'\u2460': '{\\ding{172}}',
+u'\u2461': '{\\ding{173}}',
+u'\u2462': '{\\ding{174}}',
+u'\u2463': '{\\ding{175}}',
+u'\u2464': '{\\ding{176}}',
+u'\u2465': '{\\ding{177}}',
+u'\u2466': '{\\ding{178}}',
+u'\u2467': '{\\ding{179}}',
+u'\u2468': '{\\ding{180}}',
+u'\u2469': '{\\ding{181}}',
+u'\u24c8': '$\\circledS$',
+u'\u2506': '$\\Elzdshfnc$',
+u'\u2519': '$\\Elzsqfnw$',
+u'\u2571': '$\\diagup$',
+u'\u25a0': '{\\ding{110}}',
+u'\u25a1': '$\\square$',
+u'\u25aa': '$\\blacksquare$',
+u'\u25ad': '$\\fbox{~~}$',
+u'\u25af': '$\\Elzvrecto$',
+u'\u25b1': '$\\ElsevierGlyph{E381}$',
+u'\u25b2': '{\\ding{115}}',
+u'\u25b3': '$\\bigtriangleup$',
+u'\u25b4': '$\\blacktriangle$',
+u'\u25b5': '$\\vartriangle$',
+u'\u25b8': '$\\blacktriangleright$',
+u'\u25b9': '$\\triangleright$',
+u'\u25bc': '{\\ding{116}}',
+u'\u25bd': '$\\bigtriangledown$',
+u'\u25be': '$\\blacktriangledown$',
+u'\u25bf': '$\\triangledown$',
+u'\u25c2': '$\\blacktriangleleft$',
+u'\u25c3': '$\\triangleleft$',
+u'\u25c6': '{\\ding{117}}',
+u'\u25ca': '$\\lozenge$',
+u'\u25cb': '$\\bigcirc$',
+u'\u25cf': '{\\ding{108}}',
+u'\u25d0': '$\\Elzcirfl$',
+u'\u25d1': '$\\Elzcirfr$',
+u'\u25d2': '$\\Elzcirfb$',
+u'\u25d7': '{\\ding{119}}',
+u'\u25d8': '$\\Elzrvbull$',
+u'\u25e7': '$\\Elzsqfl$',
+u'\u25e8': '$\\Elzsqfr$',
+u'\u25ea': '$\\Elzsqfse$',
+u'\u25ef': '$\\bigcirc$',
+u'\u2605': '{\\ding{72}}',
+u'\u2606': '{\\ding{73}}',
+u'\u260e': '{\\ding{37}}',
+u'\u261b': '{\\ding{42}}',
+u'\u261e': '{\\ding{43}}',
+u'\u263e': '{\\rightmoon}',
+u'\u263f': '{\\mercury}',
+u'\u2640': '{\\venus}',
+u'\u2642': '{\\male}',
+u'\u2643': '{\\jupiter}',
+u'\u2644': '{\\saturn}',
+u'\u2645': '{\\uranus}',
+u'\u2646': '{\\neptune}',
+u'\u2647': '{\\pluto}',
+u'\u2648': '{\\aries}',
+u'\u2649': '{\\taurus}',
+u'\u264a': '{\\gemini}',
+u'\u264b': '{\\cancer}',
+u'\u264c': '{\\leo}',
+u'\u264d': '{\\virgo}',
+u'\u264e': '{\\libra}',
+u'\u264f': '{\\scorpio}',
+u'\u2650': '{\\sagittarius}',
+u'\u2651': '{\\capricornus}',
+u'\u2652': '{\\aquarius}',
+u'\u2653': '{\\pisces}',
+u'\u2660': '{\\ding{171}}',
+u'\u2662': '$\\diamond$',
+u'\u2663': '{\\ding{168}}',
+u'\u2665': '{\\ding{170}}',
+u'\u2666': '{\\ding{169}}',
+u'\u2669': '{\\quarternote}',
+u'\u266a': '{\\eighthnote}',
+u'\u266d': '$\\flat$',
+u'\u266e': '$\\natural$',
+u'\u266f': '$\\sharp$',
+u'\u2701': '{\\ding{33}}',
+u'\u2702': '{\\ding{34}}',
+u'\u2703': '{\\ding{35}}',
+u'\u2704': '{\\ding{36}}',
+u'\u2706': '{\\ding{38}}',
+u'\u2707': '{\\ding{39}}',
+u'\u2708': '{\\ding{40}}',
+u'\u2709': '{\\ding{41}}',
+u'\u270c': '{\\ding{44}}',
+u'\u270d': '{\\ding{45}}',
+u'\u270e': '{\\ding{46}}',
+u'\u270f': '{\\ding{47}}',
+u'\u2710': '{\\ding{48}}',
+u'\u2711': '{\\ding{49}}',
+u'\u2712': '{\\ding{50}}',
+u'\u2713': '{\\ding{51}}',
+u'\u2714': '{\\ding{52}}',
+u'\u2715': '{\\ding{53}}',
+u'\u2716': '{\\ding{54}}',
+u'\u2717': '{\\ding{55}}',
+u'\u2718': '{\\ding{56}}',
+u'\u2719': '{\\ding{57}}',
+u'\u271a': '{\\ding{58}}',
+u'\u271b': '{\\ding{59}}',
+u'\u271c': '{\\ding{60}}',
+u'\u271d': '{\\ding{61}}',
+u'\u271e': '{\\ding{62}}',
+u'\u271f': '{\\ding{63}}',
+u'\u2720': '{\\ding{64}}',
+u'\u2721': '{\\ding{65}}',
+u'\u2722': '{\\ding{66}}',
+u'\u2723': '{\\ding{67}}',
+u'\u2724': '{\\ding{68}}',
+u'\u2725': '{\\ding{69}}',
+u'\u2726': '{\\ding{70}}',
+u'\u2727': '{\\ding{71}}',
+u'\u2729': '{\\ding{73}}',
+u'\u272a': '{\\ding{74}}',
+u'\u272b': '{\\ding{75}}',
+u'\u272c': '{\\ding{76}}',
+u'\u272d': '{\\ding{77}}',
+u'\u272e': '{\\ding{78}}',
+u'\u272f': '{\\ding{79}}',
+u'\u2730': '{\\ding{80}}',
+u'\u2731': '{\\ding{81}}',
+u'\u2732': '{\\ding{82}}',
+u'\u2733': '{\\ding{83}}',
+u'\u2734': '{\\ding{84}}',
+u'\u2735': '{\\ding{85}}',
+u'\u2736': '{\\ding{86}}',
+u'\u2737': '{\\ding{87}}',
+u'\u2738': '{\\ding{88}}',
+u'\u2739': '{\\ding{89}}',
+u'\u273a': '{\\ding{90}}',
+u'\u273b': '{\\ding{91}}',
+u'\u273c': '{\\ding{92}}',
+u'\u273d': '{\\ding{93}}',
+u'\u273e': '{\\ding{94}}',
+u'\u273f': '{\\ding{95}}',
+u'\u2740': '{\\ding{96}}',
+u'\u2741': '{\\ding{97}}',
+u'\u2742': '{\\ding{98}}',
+u'\u2743': '{\\ding{99}}',
+u'\u2744': '{\\ding{100}}',
+u'\u2745': '{\\ding{101}}',
+u'\u2746': '{\\ding{102}}',
+u'\u2747': '{\\ding{103}}',
+u'\u2748': '{\\ding{104}}',
+u'\u2749': '{\\ding{105}}',
+u'\u274a': '{\\ding{106}}',
+u'\u274b': '{\\ding{107}}',
+u'\u274d': '{\\ding{109}}',
+u'\u274f': '{\\ding{111}}',
+u'\u2750': '{\\ding{112}}',
+u'\u2751': '{\\ding{113}}',
+u'\u2752': '{\\ding{114}}',
+u'\u2756': '{\\ding{118}}',
+u'\u2758': '{\\ding{120}}',
+u'\u2759': '{\\ding{121}}',
+u'\u275a': '{\\ding{122}}',
+u'\u275b': '{\\ding{123}}',
+u'\u275c': '{\\ding{124}}',
+u'\u275d': '{\\ding{125}}',
+u'\u275e': '{\\ding{126}}',
+u'\u2761': '{\\ding{161}}',
+u'\u2762': '{\\ding{162}}',
+u'\u2763': '{\\ding{163}}',
+u'\u2764': '{\\ding{164}}',
+u'\u2765': '{\\ding{165}}',
+u'\u2766': '{\\ding{166}}',
+u'\u2767': '{\\ding{167}}',
+u'\u2776': '{\\ding{182}}',
+u'\u2777': '{\\ding{183}}',
+u'\u2778': '{\\ding{184}}',
+u'\u2779': '{\\ding{185}}',
+u'\u277a': '{\\ding{186}}',
+u'\u277b': '{\\ding{187}}',
+u'\u277c': '{\\ding{188}}',
+u'\u277d': '{\\ding{189}}',
+u'\u277e': '{\\ding{190}}',
+u'\u277f': '{\\ding{191}}',
+u'\u2780': '{\\ding{192}}',
+u'\u2781': '{\\ding{193}}',
+u'\u2782': '{\\ding{194}}',
+u'\u2783': '{\\ding{195}}',
+u'\u2784': '{\\ding{196}}',
+u'\u2785': '{\\ding{197}}',
+u'\u2786': '{\\ding{198}}',
+u'\u2787': '{\\ding{199}}',
+u'\u2788': '{\\ding{200}}',
+u'\u2789': '{\\ding{201}}',
+u'\u278a': '{\\ding{202}}',
+u'\u278b': '{\\ding{203}}',
+u'\u278c': '{\\ding{204}}',
+u'\u278d': '{\\ding{205}}',
+u'\u278e': '{\\ding{206}}',
+u'\u278f': '{\\ding{207}}',
+u'\u2790': '{\\ding{208}}',
+u'\u2791': '{\\ding{209}}',
+u'\u2792': '{\\ding{210}}',
+u'\u2793': '{\\ding{211}}',
+u'\u2794': '{\\ding{212}}',
+u'\u2798': '{\\ding{216}}',
+u'\u2799': '{\\ding{217}}',
+u'\u279a': '{\\ding{218}}',
+u'\u279b': '{\\ding{219}}',
+u'\u279c': '{\\ding{220}}',
+u'\u279d': '{\\ding{221}}',
+u'\u279e': '{\\ding{222}}',
+u'\u279f': '{\\ding{223}}',
+u'\u27a0': '{\\ding{224}}',
+u'\u27a1': '{\\ding{225}}',
+u'\u27a2': '{\\ding{226}}',
+u'\u27a3': '{\\ding{227}}',
+u'\u27a4': '{\\ding{228}}',
+u'\u27a5': '{\\ding{229}}',
+u'\u27a6': '{\\ding{230}}',
+u'\u27a7': '{\\ding{231}}',
+u'\u27a8': '{\\ding{232}}',
+u'\u27a9': '{\\ding{233}}',
+u'\u27aa': '{\\ding{234}}',
+u'\u27ab': '{\\ding{235}}',
+u'\u27ac': '{\\ding{236}}',
+u'\u27ad': '{\\ding{237}}',
+u'\u27ae': '{\\ding{238}}',
+u'\u27af': '{\\ding{239}}',
+u'\u27b1': '{\\ding{241}}',
+u'\u27b2': '{\\ding{242}}',
+u'\u27b3': '{\\ding{243}}',
+u'\u27b4': '{\\ding{244}}',
+u'\u27b5': '{\\ding{245}}',
+u'\u27b6': '{\\ding{246}}',
+u'\u27b7': '{\\ding{247}}',
+u'\u27b8': '{\\ding{248}}',
+u'\u27b9': '{\\ding{249}}',
+u'\u27ba': '{\\ding{250}}',
+u'\u27bb': '{\\ding{251}}',
+u'\u27bc': '{\\ding{252}}',
+u'\u27bd': '{\\ding{253}}',
+u'\u27be': '{\\ding{254}}',
+u'\u27f5': '$\\longleftarrow$',
+u'\u27f6': '$\\longrightarrow$',
+u'\u27f7': '$\\longleftrightarrow$',
+u'\u27f8': '$\\Longleftarrow$',
+u'\u27f9': '$\\Longrightarrow$',
+u'\u27fa': '$\\Longleftrightarrow$',
+u'\u27fc': '$\\longmapsto$',
+u'\u27ff': '$\\sim\\joinrel\\leadsto$',
+u'\u2905': '$\\ElsevierGlyph{E212}$',
+u'\u2912': '$\\UpArrowBar$',
+u'\u2913': '$\\DownArrowBar$',
+u'\u2923': '$\\ElsevierGlyph{E20C}$',
+u'\u2924': '$\\ElsevierGlyph{E20D}$',
+u'\u2925': '$\\ElsevierGlyph{E20B}$',
+u'\u2926': '$\\ElsevierGlyph{E20A}$',
+u'\u2927': '$\\ElsevierGlyph{E211}$',
+u'\u2928': '$\\ElsevierGlyph{E20E}$',
+u'\u2929': '$\\ElsevierGlyph{E20F}$',
+u'\u292a': '$\\ElsevierGlyph{E210}$',
+u'\u2933': '$\\ElsevierGlyph{E21C}$',
+u'\u2936': '$\\ElsevierGlyph{E21A}$',
+u'\u2937': '$\\ElsevierGlyph{E219}$',
+u'\u2940': '$\\Elolarr$',
+u'\u2941': '$\\Elorarr$',
+u'\u2942': '$\\ElzRlarr$',
+u'\u2944': '$\\ElzrLarr$',
+u'\u2947': '$\\Elzrarrx$',
+u'\u294e': '$\\LeftRightVector$',
+u'\u294f': '$\\RightUpDownVector$',
+u'\u2950': '$\\DownLeftRightVector$',
+u'\u2951': '$\\LeftUpDownVector$',
+u'\u2952': '$\\LeftVectorBar$',
+u'\u2953': '$\\RightVectorBar$',
+u'\u2954': '$\\RightUpVectorBar$',
+u'\u2955': '$\\RightDownVectorBar$',
+u'\u2956': '$\\DownLeftVectorBar$',
+u'\u2957': '$\\DownRightVectorBar$',
+u'\u2958': '$\\LeftUpVectorBar$',
+u'\u2959': '$\\LeftDownVectorBar$',
+u'\u295a': '$\\LeftTeeVector$',
+u'\u295b': '$\\RightTeeVector$',
+u'\u295c': '$\\RightUpTeeVector$',
+u'\u295d': '$\\RightDownTeeVector$',
+u'\u295e': '$\\DownLeftTeeVector$',
+u'\u295f': '$\\DownRightTeeVector$',
+u'\u2960': '$\\LeftUpTeeVector$',
+u'\u2961': '$\\LeftDownTeeVector$',
+u'\u296e': '$\\UpEquilibrium$',
+u'\u296f': '$\\ReverseUpEquilibrium$',
+u'\u2970': '$\\RoundImplies$',
+u'\u297c': '$\\ElsevierGlyph{E214}$',
+u'\u297d': '$\\ElsevierGlyph{E215}$',
+u'\u2980': '$\\Elztfnc$',
+u'\u2985': '$\\ElsevierGlyph{3018}$',
+u'\u2986': '$\\Elroang$',
+u'\u2993': '$<\\kern-0.58em($',
+u'\u2994': '$\\ElsevierGlyph{E291}$',
+u'\u2999': '$\\Elzddfnc$',
+u'\u299c': '$\\Angle$',
+u'\u29a0': '$\\Elzlpargt$',
+u'\u29b5': '$\\ElsevierGlyph{E260}$',
+u'\u29b6': '$\\ElsevierGlyph{E61B}$',
+u'\u29ca': '$\\ElzLap$',
+u'\u29cb': '$\\Elzdefas$',
+u'\u29cf': '$\\LeftTriangleBar$',
+u'\u29d0': '$\\RightTriangleBar$',
+u'\u29dc': '$\\ElsevierGlyph{E372}$',
+u'\u29eb': '$\\blacklozenge$',
+u'\u29f4': '$\\RuleDelayed$',
+u'\u2a04': '$\\Elxuplus$',
+u'\u2a05': '$\\ElzThr$',
+u'\u2a06': '$\\Elxsqcup$',
+u'\u2a07': '$\\ElzInf$',
+u'\u2a08': '$\\ElzSup$',
+u'\u2a0d': '$\\ElzCint$',
+u'\u2a0f': '$\\clockoint$',
+u'\u2a10': '$\\ElsevierGlyph{E395}$',
+u'\u2a16': '$\\sqrint$',
+u'\u2a25': '$\\ElsevierGlyph{E25A}$',
+u'\u2a2a': '$\\ElsevierGlyph{E25B}$',
+u'\u2a2d': '$\\ElsevierGlyph{E25C}$',
+u'\u2a2e': '$\\ElsevierGlyph{E25D}$',
+u'\u2a2f': '$\\ElzTimes$',
+u'\u2a34': '$\\ElsevierGlyph{E25E}$',
+u'\u2a35': '$\\ElsevierGlyph{E25E}$',
+u'\u2a3c': '$\\ElsevierGlyph{E259}$',
+u'\u2a3f': '$\\amalg$',
+u'\u2a53': '$\\ElzAnd$',
+u'\u2a54': '$\\ElzOr$',
+u'\u2a55': '$\\ElsevierGlyph{E36E}$',
+u'\u2a56': '$\\ElOr$',
+u'\u2a5e': '$\\perspcorrespond$',
+u'\u2a5f': '$\\Elzminhat$',
+u'\u2a63': '$\\ElsevierGlyph{225A}$',
+u'\u2a6e': '$\\stackrel{*}{=}$',
+u'\u2a75': '$\\Equal$',
+u'\u2a7d': '$\\leqslant$',
+u'\u2a7e': '$\\geqslant$',
+u'\u2a85': '$\\lessapprox$',
+u'\u2a86': '$\\gtrapprox$',
+u'\u2a87': '$\\lneq$',
+u'\u2a88': '$\\gneq$',
+u'\u2a89': '$\\lnapprox$',
+u'\u2a8a': '$\\gnapprox$',
+u'\u2a8b': '$\\lesseqqgtr$',
+u'\u2a8c': '$\\gtreqqless$',
+u'\u2a95': '$\\eqslantless$',
+u'\u2a96': '$\\eqslantgtr$',
+u'\u2a9d': '$\\Pisymbol{ppi020}{117}$',
+u'\u2a9e': '$\\Pisymbol{ppi020}{105}$',
+u'\u2aa1': '$\\NestedLessLess$',
+u'\u2aa2': '$\\NestedGreaterGreater$',
+u'\u2aaf': '$\\preceq$',
+u'\u2ab0': '$\\succeq$',
+u'\u2ab5': '$\\precneqq$',
+u'\u2ab6': '$\\succneqq$',
+u'\u2ab7': '$\\precapprox$',
+u'\u2ab8': '$\\succapprox$',
+u'\u2ab9': '$\\precnapprox$',
+u'\u2aba': '$\\succnapprox$',
+u'\u2ac5': '$\\subseteqq$',
+u'\u2ac6': '$\\supseteqq$',
+u'\u2acb': '$\\subsetneqq$',
+u'\u2acc': '$\\supsetneqq$',
+u'\u2aeb': '$\\ElsevierGlyph{E30D}$',
+u'\u2af6': '$\\Elztdcol$',
+u'\u2afd': '${{/}\\!\\!{/}}$',
+u'\u300a': '$\\ElsevierGlyph{300A}$',
+u'\u300b': '$\\ElsevierGlyph{300B}$',
+u'\u3018': '$\\ElsevierGlyph{3018}$',
+u'\u3019': '$\\ElsevierGlyph{3019}$',
+u'\u301a': '$\\openbracketleft$',
+u'\u301b': '$\\openbracketright$',
+u'\ufb00': '{ff}',
+u'\ufb01': '{fi}',
+u'\ufb02': '{fl}',
+u'\ufb03': '{ffi}',
+u'\ufb04': '{ffl}',
+u'\U0001d400': '$\\mathbf{A}$',
+u'\U0001d401': '$\\mathbf{B}$',
+u'\U0001d402': '$\\mathbf{C}$',
+u'\U0001d403': '$\\mathbf{D}$',
+u'\U0001d404': '$\\mathbf{E}$',
+u'\U0001d405': '$\\mathbf{F}$',
+u'\U0001d406': '$\\mathbf{G}$',
+u'\U0001d407': '$\\mathbf{H}$',
+u'\U0001d408': '$\\mathbf{I}$',
+u'\U0001d409': '$\\mathbf{J}$',
+u'\U0001d40a': '$\\mathbf{K}$',
+u'\U0001d40b': '$\\mathbf{L}$',
+u'\U0001d40c': '$\\mathbf{M}$',
+u'\U0001d40d': '$\\mathbf{N}$',
+u'\U0001d40e': '$\\mathbf{O}$',
+u'\U0001d40f': '$\\mathbf{P}$',
+u'\U0001d410': '$\\mathbf{Q}$',
+u'\U0001d411': '$\\mathbf{R}$',
+u'\U0001d412': '$\\mathbf{S}$',
+u'\U0001d413': '$\\mathbf{T}$',
+u'\U0001d414': '$\\mathbf{U}$',
+u'\U0001d415': '$\\mathbf{V}$',
+u'\U0001d416': '$\\mathbf{W}$',
+u'\U0001d417': '$\\mathbf{X}$',
+u'\U0001d418': '$\\mathbf{Y}$',
+u'\U0001d419': '$\\mathbf{Z}$',
+u'\U0001d41a': '$\\mathbf{a}$',
+u'\U0001d41b': '$\\mathbf{b}$',
+u'\U0001d41c': '$\\mathbf{c}$',
+u'\U0001d41d': '$\\mathbf{d}$',
+u'\U0001d41e': '$\\mathbf{e}$',
+u'\U0001d41f': '$\\mathbf{f}$',
+u'\U0001d420': '$\\mathbf{g}$',
+u'\U0001d421': '$\\mathbf{h}$',
+u'\U0001d422': '$\\mathbf{i}$',
+u'\U0001d423': '$\\mathbf{j}$',
+u'\U0001d424': '$\\mathbf{k}$',
+u'\U0001d425': '$\\mathbf{l}$',
+u'\U0001d426': '$\\mathbf{m}$',
+u'\U0001d427': '$\\mathbf{n}$',
+u'\U0001d428': '$\\mathbf{o}$',
+u'\U0001d429': '$\\mathbf{p}$',
+u'\U0001d42a': '$\\mathbf{q}$',
+u'\U0001d42b': '$\\mathbf{r}$',
+u'\U0001d42c': '$\\mathbf{s}$',
+u'\U0001d42d': '$\\mathbf{t}$',
+u'\U0001d42e': '$\\mathbf{u}$',
+u'\U0001d42f': '$\\mathbf{v}$',
+u'\U0001d430': '$\\mathbf{w}$',
+u'\U0001d431': '$\\mathbf{x}$',
+u'\U0001d432': '$\\mathbf{y}$',
+u'\U0001d433': '$\\mathbf{z}$',
+u'\U0001d434': '$\\mathsl{A}$',
+u'\U0001d435': '$\\mathsl{B}$',
+u'\U0001d436': '$\\mathsl{C}$',
+u'\U0001d437': '$\\mathsl{D}$',
+u'\U0001d438': '$\\mathsl{E}$',
+u'\U0001d439': '$\\mathsl{F}$',
+u'\U0001d43a': '$\\mathsl{G}$',
+u'\U0001d43b': '$\\mathsl{H}$',
+u'\U0001d43c': '$\\mathsl{I}$',
+u'\U0001d43d': '$\\mathsl{J}$',
+u'\U0001d43e': '$\\mathsl{K}$',
+u'\U0001d43f': '$\\mathsl{L}$',
+u'\U0001d440': '$\\mathsl{M}$',
+u'\U0001d441': '$\\mathsl{N}$',
+u'\U0001d442': '$\\mathsl{O}$',
+u'\U0001d443': '$\\mathsl{P}$',
+u'\U0001d444': '$\\mathsl{Q}$',
+u'\U0001d445': '$\\mathsl{R}$',
+u'\U0001d446': '$\\mathsl{S}$',
+u'\U0001d447': '$\\mathsl{T}$',
+u'\U0001d448': '$\\mathsl{U}$',
+u'\U0001d449': '$\\mathsl{V}$',
+u'\U0001d44a': '$\\mathsl{W}$',
+u'\U0001d44b': '$\\mathsl{X}$',
+u'\U0001d44c': '$\\mathsl{Y}$',
+u'\U0001d44d': '$\\mathsl{Z}$',
+u'\U0001d44e': '$\\mathsl{a}$',
+u'\U0001d44f': '$\\mathsl{b}$',
+u'\U0001d450': '$\\mathsl{c}$',
+u'\U0001d451': '$\\mathsl{d}$',
+u'\U0001d452': '$\\mathsl{e}$',
+u'\U0001d453': '$\\mathsl{f}$',
+u'\U0001d454': '$\\mathsl{g}$',
+u'\U0001d456': '$\\mathsl{i}$',
+u'\U0001d457': '$\\mathsl{j}$',
+u'\U0001d458': '$\\mathsl{k}$',
+u'\U0001d459': '$\\mathsl{l}$',
+u'\U0001d45a': '$\\mathsl{m}$',
+u'\U0001d45b': '$\\mathsl{n}$',
+u'\U0001d45c': '$\\mathsl{o}$',
+u'\U0001d45d': '$\\mathsl{p}$',
+u'\U0001d45e': '$\\mathsl{q}$',
+u'\U0001d45f': '$\\mathsl{r}$',
+u'\U0001d460': '$\\mathsl{s}$',
+u'\U0001d461': '$\\mathsl{t}$',
+u'\U0001d462': '$\\mathsl{u}$',
+u'\U0001d463': '$\\mathsl{v}$',
+u'\U0001d464': '$\\mathsl{w}$',
+u'\U0001d465': '$\\mathsl{x}$',
+u'\U0001d466': '$\\mathsl{y}$',
+u'\U0001d467': '$\\mathsl{z}$',
+u'\U0001d468': '$\\mathbit{A}$',
+u'\U0001d469': '$\\mathbit{B}$',
+u'\U0001d46a': '$\\mathbit{C}$',
+u'\U0001d46b': '$\\mathbit{D}$',
+u'\U0001d46c': '$\\mathbit{E}$',
+u'\U0001d46d': '$\\mathbit{F}$',
+u'\U0001d46e': '$\\mathbit{G}$',
+u'\U0001d46f': '$\\mathbit{H}$',
+u'\U0001d470': '$\\mathbit{I}$',
+u'\U0001d471': '$\\mathbit{J}$',
+u'\U0001d472': '$\\mathbit{K}$',
+u'\U0001d473': '$\\mathbit{L}$',
+u'\U0001d474': '$\\mathbit{M}$',
+u'\U0001d475': '$\\mathbit{N}$',
+u'\U0001d476': '$\\mathbit{O}$',
+u'\U0001d477': '$\\mathbit{P}$',
+u'\U0001d478': '$\\mathbit{Q}$',
+u'\U0001d479': '$\\mathbit{R}$',
+u'\U0001d47a': '$\\mathbit{S}$',
+u'\U0001d47b': '$\\mathbit{T}$',
+u'\U0001d47c': '$\\mathbit{U}$',
+u'\U0001d47d': '$\\mathbit{V}$',
+u'\U0001d47e': '$\\mathbit{W}$',
+u'\U0001d47f': '$\\mathbit{X}$',
+u'\U0001d480': '$\\mathbit{Y}$',
+u'\U0001d481': '$\\mathbit{Z}$',
+u'\U0001d482': '$\\mathbit{a}$',
+u'\U0001d483': '$\\mathbit{b}$',
+u'\U0001d484': '$\\mathbit{c}$',
+u'\U0001d485': '$\\mathbit{d}$',
+u'\U0001d486': '$\\mathbit{e}$',
+u'\U0001d487': '$\\mathbit{f}$',
+u'\U0001d488': '$\\mathbit{g}$',
+u'\U0001d489': '$\\mathbit{h}$',
+u'\U0001d48a': '$\\mathbit{i}$',
+u'\U0001d48b': '$\\mathbit{j}$',
+u'\U0001d48c': '$\\mathbit{k}$',
+u'\U0001d48d': '$\\mathbit{l}$',
+u'\U0001d48e': '$\\mathbit{m}$',
+u'\U0001d48f': '$\\mathbit{n}$',
+u'\U0001d490': '$\\mathbit{o}$',
+u'\U0001d491': '$\\mathbit{p}$',
+u'\U0001d492': '$\\mathbit{q}$',
+u'\U0001d493': '$\\mathbit{r}$',
+u'\U0001d494': '$\\mathbit{s}$',
+u'\U0001d495': '$\\mathbit{t}$',
+u'\U0001d496': '$\\mathbit{u}$',
+u'\U0001d497': '$\\mathbit{v}$',
+u'\U0001d498': '$\\mathbit{w}$',
+u'\U0001d499': '$\\mathbit{x}$',
+u'\U0001d49a': '$\\mathbit{y}$',
+u'\U0001d49b': '$\\mathbit{z}$',
+u'\U0001d49c': '$\\mathscr{A}$',
+u'\U0001d49e': '$\\mathscr{C}$',
+u'\U0001d49f': '$\\mathscr{D}$',
+u'\U0001d4a2': '$\\mathscr{G}$',
+u'\U0001d4a5': '$\\mathscr{J}$',
+u'\U0001d4a6': '$\\mathscr{K}$',
+u'\U0001d4a9': '$\\mathscr{N}$',
+u'\U0001d4aa': '$\\mathscr{O}$',
+u'\U0001d4ab': '$\\mathscr{P}$',
+u'\U0001d4ac': '$\\mathscr{Q}$',
+u'\U0001d4ae': '$\\mathscr{S}$',
+u'\U0001d4af': '$\\mathscr{T}$',
+u'\U0001d4b0': '$\\mathscr{U}$',
+u'\U0001d4b1': '$\\mathscr{V}$',
+u'\U0001d4b2': '$\\mathscr{W}$',
+u'\U0001d4b3': '$\\mathscr{X}$',
+u'\U0001d4b4': '$\\mathscr{Y}$',
+u'\U0001d4b5': '$\\mathscr{Z}$',
+u'\U0001d4b6': '$\\mathscr{a}$',
+u'\U0001d4b7': '$\\mathscr{b}$',
+u'\U0001d4b8': '$\\mathscr{c}$',
+u'\U0001d4b9': '$\\mathscr{d}$',
+u'\U0001d4bb': '$\\mathscr{f}$',
+u'\U0001d4bd': '$\\mathscr{h}$',
+u'\U0001d4be': '$\\mathscr{i}$',
+u'\U0001d4bf': '$\\mathscr{j}$',
+u'\U0001d4c0': '$\\mathscr{k}$',
+u'\U0001d4c1': '$\\mathscr{l}$',
+u'\U0001d4c2': '$\\mathscr{m}$',
+u'\U0001d4c3': '$\\mathscr{n}$',
+u'\U0001d4c5': '$\\mathscr{p}$',
+u'\U0001d4c6': '$\\mathscr{q}$',
+u'\U0001d4c7': '$\\mathscr{r}$',
+u'\U0001d4c8': '$\\mathscr{s}$',
+u'\U0001d4c9': '$\\mathscr{t}$',
+u'\U0001d4ca': '$\\mathscr{u}$',
+u'\U0001d4cb': '$\\mathscr{v}$',
+u'\U0001d4cc': '$\\mathscr{w}$',
+u'\U0001d4cd': '$\\mathscr{x}$',
+u'\U0001d4ce': '$\\mathscr{y}$',
+u'\U0001d4cf': '$\\mathscr{z}$',
+u'\U0001d4d0': '$\\mathmit{A}$',
+u'\U0001d4d1': '$\\mathmit{B}$',
+u'\U0001d4d2': '$\\mathmit{C}$',
+u'\U0001d4d3': '$\\mathmit{D}$',
+u'\U0001d4d4': '$\\mathmit{E}$',
+u'\U0001d4d5': '$\\mathmit{F}$',
+u'\U0001d4d6': '$\\mathmit{G}$',
+u'\U0001d4d7': '$\\mathmit{H}$',
+u'\U0001d4d8': '$\\mathmit{I}$',
+u'\U0001d4d9': '$\\mathmit{J}$',
+u'\U0001d4da': '$\\mathmit{K}$',
+u'\U0001d4db': '$\\mathmit{L}$',
+u'\U0001d4dc': '$\\mathmit{M}$',
+u'\U0001d4dd': '$\\mathmit{N}$',
+u'\U0001d4de': '$\\mathmit{O}$',
+u'\U0001d4df': '$\\mathmit{P}$',
+u'\U0001d4e0': '$\\mathmit{Q}$',
+u'\U0001d4e1': '$\\mathmit{R}$',
+u'\U0001d4e2': '$\\mathmit{S}$',
+u'\U0001d4e3': '$\\mathmit{T}$',
+u'\U0001d4e4': '$\\mathmit{U}$',
+u'\U0001d4e5': '$\\mathmit{V}$',
+u'\U0001d4e6': '$\\mathmit{W}$',
+u'\U0001d4e7': '$\\mathmit{X}$',
+u'\U0001d4e8': '$\\mathmit{Y}$',
+u'\U0001d4e9': '$\\mathmit{Z}$',
+u'\U0001d4ea': '$\\mathmit{a}$',
+u'\U0001d4eb': '$\\mathmit{b}$',
+u'\U0001d4ec': '$\\mathmit{c}$',
+u'\U0001d4ed': '$\\mathmit{d}$',
+u'\U0001d4ee': '$\\mathmit{e}$',
+u'\U0001d4ef': '$\\mathmit{f}$',
+u'\U0001d4f0': '$\\mathmit{g}$',
+u'\U0001d4f1': '$\\mathmit{h}$',
+u'\U0001d4f2': '$\\mathmit{i}$',
+u'\U0001d4f3': '$\\mathmit{j}$',
+u'\U0001d4f4': '$\\mathmit{k}$',
+u'\U0001d4f5': '$\\mathmit{l}$',
+u'\U0001d4f6': '$\\mathmit{m}$',
+u'\U0001d4f7': '$\\mathmit{n}$',
+u'\U0001d4f8': '$\\mathmit{o}$',
+u'\U0001d4f9': '$\\mathmit{p}$',
+u'\U0001d4fa': '$\\mathmit{q}$',
+u'\U0001d4fb': '$\\mathmit{r}$',
+u'\U0001d4fc': '$\\mathmit{s}$',
+u'\U0001d4fd': '$\\mathmit{t}$',
+u'\U0001d4fe': '$\\mathmit{u}$',
+u'\U0001d4ff': '$\\mathmit{v}$',
+u'\U0001d500': '$\\mathmit{w}$',
+u'\U0001d501': '$\\mathmit{x}$',
+u'\U0001d502': '$\\mathmit{y}$',
+u'\U0001d503': '$\\mathmit{z}$',
+u'\U0001d504': '$\\mathfrak{A}$',
+u'\U0001d505': '$\\mathfrak{B}$',
+u'\U0001d507': '$\\mathfrak{D}$',
+u'\U0001d508': '$\\mathfrak{E}$',
+u'\U0001d509': '$\\mathfrak{F}$',
+u'\U0001d50a': '$\\mathfrak{G}$',
+u'\U0001d50d': '$\\mathfrak{J}$',
+u'\U0001d50e': '$\\mathfrak{K}$',
+u'\U0001d50f': '$\\mathfrak{L}$',
+u'\U0001d510': '$\\mathfrak{M}$',
+u'\U0001d511': '$\\mathfrak{N}$',
+u'\U0001d512': '$\\mathfrak{O}$',
+u'\U0001d513': '$\\mathfrak{P}$',
+u'\U0001d514': '$\\mathfrak{Q}$',
+u'\U0001d516': '$\\mathfrak{S}$',
+u'\U0001d517': '$\\mathfrak{T}$',
+u'\U0001d518': '$\\mathfrak{U}$',
+u'\U0001d519': '$\\mathfrak{V}$',
+u'\U0001d51a': '$\\mathfrak{W}$',
+u'\U0001d51b': '$\\mathfrak{X}$',
+u'\U0001d51c': '$\\mathfrak{Y}$',
+u'\U0001d51e': '$\\mathfrak{a}$',
+u'\U0001d51f': '$\\mathfrak{b}$',
+u'\U0001d520': '$\\mathfrak{c}$',
+u'\U0001d521': '$\\mathfrak{d}$',
+u'\U0001d522': '$\\mathfrak{e}$',
+u'\U0001d523': '$\\mathfrak{f}$',
+u'\U0001d524': '$\\mathfrak{g}$',
+u'\U0001d525': '$\\mathfrak{h}$',
+u'\U0001d526': '$\\mathfrak{i}$',
+u'\U0001d527': '$\\mathfrak{j}$',
+u'\U0001d528': '$\\mathfrak{k}$',
+u'\U0001d529': '$\\mathfrak{l}$',
+u'\U0001d52a': '$\\mathfrak{m}$',
+u'\U0001d52b': '$\\mathfrak{n}$',
+u'\U0001d52c': '$\\mathfrak{o}$',
+u'\U0001d52d': '$\\mathfrak{p}$',
+u'\U0001d52e': '$\\mathfrak{q}$',
+u'\U0001d52f': '$\\mathfrak{r}$',
+u'\U0001d530': '$\\mathfrak{s}$',
+u'\U0001d531': '$\\mathfrak{t}$',
+u'\U0001d532': '$\\mathfrak{u}$',
+u'\U0001d533': '$\\mathfrak{v}$',
+u'\U0001d534': '$\\mathfrak{w}$',
+u'\U0001d535': '$\\mathfrak{x}$',
+u'\U0001d536': '$\\mathfrak{y}$',
+u'\U0001d537': '$\\mathfrak{z}$',
+u'\U0001d538': '$\\mathbb{A}$',
+u'\U0001d539': '$\\mathbb{B}$',
+u'\U0001d53b': '$\\mathbb{D}$',
+u'\U0001d53c': '$\\mathbb{E}$',
+u'\U0001d53d': '$\\mathbb{F}$',
+u'\U0001d53e': '$\\mathbb{G}$',
+u'\U0001d540': '$\\mathbb{I}$',
+u'\U0001d541': '$\\mathbb{J}$',
+u'\U0001d542': '$\\mathbb{K}$',
+u'\U0001d543': '$\\mathbb{L}$',
+u'\U0001d544': '$\\mathbb{M}$',
+u'\U0001d546': '$\\mathbb{O}$',
+u'\U0001d54a': '$\\mathbb{S}$',
+u'\U0001d54b': '$\\mathbb{T}$',
+u'\U0001d54c': '$\\mathbb{U}$',
+u'\U0001d54d': '$\\mathbb{V}$',
+u'\U0001d54e': '$\\mathbb{W}$',
+u'\U0001d54f': '$\\mathbb{X}$',
+u'\U0001d550': '$\\mathbb{Y}$',
+u'\U0001d552': '$\\mathbb{a}$',
+u'\U0001d553': '$\\mathbb{b}$',
+u'\U0001d554': '$\\mathbb{c}$',
+u'\U0001d555': '$\\mathbb{d}$',
+u'\U0001d556': '$\\mathbb{e}$',
+u'\U0001d557': '$\\mathbb{f}$',
+u'\U0001d558': '$\\mathbb{g}$',
+u'\U0001d559': '$\\mathbb{h}$',
+u'\U0001d55a': '$\\mathbb{i}$',
+u'\U0001d55b': '$\\mathbb{j}$',
+u'\U0001d55c': '$\\mathbb{k}$',
+u'\U0001d55d': '$\\mathbb{l}$',
+u'\U0001d55e': '$\\mathbb{m}$',
+u'\U0001d55f': '$\\mathbb{n}$',
+u'\U0001d560': '$\\mathbb{o}$',
+u'\U0001d561': '$\\mathbb{p}$',
+u'\U0001d562': '$\\mathbb{q}$',
+u'\U0001d563': '$\\mathbb{r}$',
+u'\U0001d564': '$\\mathbb{s}$',
+u'\U0001d565': '$\\mathbb{t}$',
+u'\U0001d566': '$\\mathbb{u}$',
+u'\U0001d567': '$\\mathbb{v}$',
+u'\U0001d568': '$\\mathbb{w}$',
+u'\U0001d569': '$\\mathbb{x}$',
+u'\U0001d56a': '$\\mathbb{y}$',
+u'\U0001d56b': '$\\mathbb{z}$',
+u'\U0001d56c': '$\\mathslbb{A}$',
+u'\U0001d56d': '$\\mathslbb{B}$',
+u'\U0001d56e': '$\\mathslbb{C}$',
+u'\U0001d56f': '$\\mathslbb{D}$',
+u'\U0001d570': '$\\mathslbb{E}$',
+u'\U0001d571': '$\\mathslbb{F}$',
+u'\U0001d572': '$\\mathslbb{G}$',
+u'\U0001d573': '$\\mathslbb{H}$',
+u'\U0001d574': '$\\mathslbb{I}$',
+u'\U0001d575': '$\\mathslbb{J}$',
+u'\U0001d576': '$\\mathslbb{K}$',
+u'\U0001d577': '$\\mathslbb{L}$',
+u'\U0001d578': '$\\mathslbb{M}$',
+u'\U0001d579': '$\\mathslbb{N}$',
+u'\U0001d57a': '$\\mathslbb{O}$',
+u'\U0001d57b': '$\\mathslbb{P}$',
+u'\U0001d57c': '$\\mathslbb{Q}$',
+u'\U0001d57d': '$\\mathslbb{R}$',
+u'\U0001d57e': '$\\mathslbb{S}$',
+u'\U0001d57f': '$\\mathslbb{T}$',
+u'\U0001d580': '$\\mathslbb{U}$',
+u'\U0001d581': '$\\mathslbb{V}$',
+u'\U0001d582': '$\\mathslbb{W}$',
+u'\U0001d583': '$\\mathslbb{X}$',
+u'\U0001d584': '$\\mathslbb{Y}$',
+u'\U0001d585': '$\\mathslbb{Z}$',
+u'\U0001d586': '$\\mathslbb{a}$',
+u'\U0001d587': '$\\mathslbb{b}$',
+u'\U0001d588': '$\\mathslbb{c}$',
+u'\U0001d589': '$\\mathslbb{d}$',
+u'\U0001d58a': '$\\mathslbb{e}$',
+u'\U0001d58b': '$\\mathslbb{f}$',
+u'\U0001d58c': '$\\mathslbb{g}$',
+u'\U0001d58d': '$\\mathslbb{h}$',
+u'\U0001d58e': '$\\mathslbb{i}$',
+u'\U0001d58f': '$\\mathslbb{j}$',
+u'\U0001d590': '$\\mathslbb{k}$',
+u'\U0001d591': '$\\mathslbb{l}$',
+u'\U0001d592': '$\\mathslbb{m}$',
+u'\U0001d593': '$\\mathslbb{n}$',
+u'\U0001d594': '$\\mathslbb{o}$',
+u'\U0001d595': '$\\mathslbb{p}$',
+u'\U0001d596': '$\\mathslbb{q}$',
+u'\U0001d597': '$\\mathslbb{r}$',
+u'\U0001d598': '$\\mathslbb{s}$',
+u'\U0001d599': '$\\mathslbb{t}$',
+u'\U0001d59a': '$\\mathslbb{u}$',
+u'\U0001d59b': '$\\mathslbb{v}$',
+u'\U0001d59c': '$\\mathslbb{w}$',
+u'\U0001d59d': '$\\mathslbb{x}$',
+u'\U0001d59e': '$\\mathslbb{y}$',
+u'\U0001d59f': '$\\mathslbb{z}$',
+u'\U0001d5a0': '$\\mathsf{A}$',
+u'\U0001d5a1': '$\\mathsf{B}$',
+u'\U0001d5a2': '$\\mathsf{C}$',
+u'\U0001d5a3': '$\\mathsf{D}$',
+u'\U0001d5a4': '$\\mathsf{E}$',
+u'\U0001d5a5': '$\\mathsf{F}$',
+u'\U0001d5a6': '$\\mathsf{G}$',
+u'\U0001d5a7': '$\\mathsf{H}$',
+u'\U0001d5a8': '$\\mathsf{I}$',
+u'\U0001d5a9': '$\\mathsf{J}$',
+u'\U0001d5aa': '$\\mathsf{K}$',
+u'\U0001d5ab': '$\\mathsf{L}$',
+u'\U0001d5ac': '$\\mathsf{M}$',
+u'\U0001d5ad': '$\\mathsf{N}$',
+u'\U0001d5ae': '$\\mathsf{O}$',
+u'\U0001d5af': '$\\mathsf{P}$',
+u'\U0001d5b0': '$\\mathsf{Q}$',
+u'\U0001d5b1': '$\\mathsf{R}$',
+u'\U0001d5b2': '$\\mathsf{S}$',
+u'\U0001d5b3': '$\\mathsf{T}$',
+u'\U0001d5b4': '$\\mathsf{U}$',
+u'\U0001d5b5': '$\\mathsf{V}$',
+u'\U0001d5b6': '$\\mathsf{W}$',
+u'\U0001d5b7': '$\\mathsf{X}$',
+u'\U0001d5b8': '$\\mathsf{Y}$',
+u'\U0001d5b9': '$\\mathsf{Z}$',
+u'\U0001d5ba': '$\\mathsf{a}$',
+u'\U0001d5bb': '$\\mathsf{b}$',
+u'\U0001d5bc': '$\\mathsf{c}$',
+u'\U0001d5bd': '$\\mathsf{d}$',
+u'\U0001d5be': '$\\mathsf{e}$',
+u'\U0001d5bf': '$\\mathsf{f}$',
+u'\U0001d5c0': '$\\mathsf{g}$',
+u'\U0001d5c1': '$\\mathsf{h}$',
+u'\U0001d5c2': '$\\mathsf{i}$',
+u'\U0001d5c3': '$\\mathsf{j}$',
+u'\U0001d5c4': '$\\mathsf{k}$',
+u'\U0001d5c5': '$\\mathsf{l}$',
+u'\U0001d5c6': '$\\mathsf{m}$',
+u'\U0001d5c7': '$\\mathsf{n}$',
+u'\U0001d5c8': '$\\mathsf{o}$',
+u'\U0001d5c9': '$\\mathsf{p}$',
+u'\U0001d5ca': '$\\mathsf{q}$',
+u'\U0001d5cb': '$\\mathsf{r}$',
+u'\U0001d5cc': '$\\mathsf{s}$',
+u'\U0001d5cd': '$\\mathsf{t}$',
+u'\U0001d5ce': '$\\mathsf{u}$',
+u'\U0001d5cf': '$\\mathsf{v}$',
+u'\U0001d5d0': '$\\mathsf{w}$',
+u'\U0001d5d1': '$\\mathsf{x}$',
+u'\U0001d5d2': '$\\mathsf{y}$',
+u'\U0001d5d3': '$\\mathsf{z}$',
+u'\U0001d5d4': '$\\mathsfbf{A}$',
+u'\U0001d5d5': '$\\mathsfbf{B}$',
+u'\U0001d5d6': '$\\mathsfbf{C}$',
+u'\U0001d5d7': '$\\mathsfbf{D}$',
+u'\U0001d5d8': '$\\mathsfbf{E}$',
+u'\U0001d5d9': '$\\mathsfbf{F}$',
+u'\U0001d5da': '$\\mathsfbf{G}$',
+u'\U0001d5db': '$\\mathsfbf{H}$',
+u'\U0001d5dc': '$\\mathsfbf{I}$',
+u'\U0001d5dd': '$\\mathsfbf{J}$',
+u'\U0001d5de': '$\\mathsfbf{K}$',
+u'\U0001d5df': '$\\mathsfbf{L}$',
+u'\U0001d5e0': '$\\mathsfbf{M}$',
+u'\U0001d5e1': '$\\mathsfbf{N}$',
+u'\U0001d5e2': '$\\mathsfbf{O}$',
+u'\U0001d5e3': '$\\mathsfbf{P}$',
+u'\U0001d5e4': '$\\mathsfbf{Q}$',
+u'\U0001d5e5': '$\\mathsfbf{R}$',
+u'\U0001d5e6': '$\\mathsfbf{S}$',
+u'\U0001d5e7': '$\\mathsfbf{T}$',
+u'\U0001d5e8': '$\\mathsfbf{U}$',
+u'\U0001d5e9': '$\\mathsfbf{V}$',
+u'\U0001d5ea': '$\\mathsfbf{W}$',
+u'\U0001d5eb': '$\\mathsfbf{X}$',
+u'\U0001d5ec': '$\\mathsfbf{Y}$',
+u'\U0001d5ed': '$\\mathsfbf{Z}$',
+u'\U0001d5ee': '$\\mathsfbf{a}$',
+u'\U0001d5ef': '$\\mathsfbf{b}$',
+u'\U0001d5f0': '$\\mathsfbf{c}$',
+u'\U0001d5f1': '$\\mathsfbf{d}$',
+u'\U0001d5f2': '$\\mathsfbf{e}$',
+u'\U0001d5f3': '$\\mathsfbf{f}$',
+u'\U0001d5f4': '$\\mathsfbf{g}$',
+u'\U0001d5f5': '$\\mathsfbf{h}$',
+u'\U0001d5f6': '$\\mathsfbf{i}$',
+u'\U0001d5f7': '$\\mathsfbf{j}$',
+u'\U0001d5f8': '$\\mathsfbf{k}$',
+u'\U0001d5f9': '$\\mathsfbf{l}$',
+u'\U0001d5fa': '$\\mathsfbf{m}$',
+u'\U0001d5fb': '$\\mathsfbf{n}$',
+u'\U0001d5fc': '$\\mathsfbf{o}$',
+u'\U0001d5fd': '$\\mathsfbf{p}$',
+u'\U0001d5fe': '$\\mathsfbf{q}$',
+u'\U0001d5ff': '$\\mathsfbf{r}$',
+u'\U0001d600': '$\\mathsfbf{s}$',
+u'\U0001d601': '$\\mathsfbf{t}$',
+u'\U0001d602': '$\\mathsfbf{u}$',
+u'\U0001d603': '$\\mathsfbf{v}$',
+u'\U0001d604': '$\\mathsfbf{w}$',
+u'\U0001d605': '$\\mathsfbf{x}$',
+u'\U0001d606': '$\\mathsfbf{y}$',
+u'\U0001d607': '$\\mathsfbf{z}$',
+u'\U0001d608': '$\\mathsfsl{A}$',
+u'\U0001d609': '$\\mathsfsl{B}$',
+u'\U0001d60a': '$\\mathsfsl{C}$',
+u'\U0001d60b': '$\\mathsfsl{D}$',
+u'\U0001d60c': '$\\mathsfsl{E}$',
+u'\U0001d60d': '$\\mathsfsl{F}$',
+u'\U0001d60e': '$\\mathsfsl{G}$',
+u'\U0001d60f': '$\\mathsfsl{H}$',
+u'\U0001d610': '$\\mathsfsl{I}$',
+u'\U0001d611': '$\\mathsfsl{J}$',
+u'\U0001d612': '$\\mathsfsl{K}$',
+u'\U0001d613': '$\\mathsfsl{L}$',
+u'\U0001d614': '$\\mathsfsl{M}$',
+u'\U0001d615': '$\\mathsfsl{N}$',
+u'\U0001d616': '$\\mathsfsl{O}$',
+u'\U0001d617': '$\\mathsfsl{P}$',
+u'\U0001d618': '$\\mathsfsl{Q}$',
+u'\U0001d619': '$\\mathsfsl{R}$',
+u'\U0001d61a': '$\\mathsfsl{S}$',
+u'\U0001d61b': '$\\mathsfsl{T}$',
+u'\U0001d61c': '$\\mathsfsl{U}$',
+u'\U0001d61d': '$\\mathsfsl{V}$',
+u'\U0001d61e': '$\\mathsfsl{W}$',
+u'\U0001d61f': '$\\mathsfsl{X}$',
+u'\U0001d620': '$\\mathsfsl{Y}$',
+u'\U0001d621': '$\\mathsfsl{Z}$',
+u'\U0001d622': '$\\mathsfsl{a}$',
+u'\U0001d623': '$\\mathsfsl{b}$',
+u'\U0001d624': '$\\mathsfsl{c}$',
+u'\U0001d625': '$\\mathsfsl{d}$',
+u'\U0001d626': '$\\mathsfsl{e}$',
+u'\U0001d627': '$\\mathsfsl{f}$',
+u'\U0001d628': '$\\mathsfsl{g}$',
+u'\U0001d629': '$\\mathsfsl{h}$',
+u'\U0001d62a': '$\\mathsfsl{i}$',
+u'\U0001d62b': '$\\mathsfsl{j}$',
+u'\U0001d62c': '$\\mathsfsl{k}$',
+u'\U0001d62d': '$\\mathsfsl{l}$',
+u'\U0001d62e': '$\\mathsfsl{m}$',
+u'\U0001d62f': '$\\mathsfsl{n}$',
+u'\U0001d630': '$\\mathsfsl{o}$',
+u'\U0001d631': '$\\mathsfsl{p}$',
+u'\U0001d632': '$\\mathsfsl{q}$',
+u'\U0001d633': '$\\mathsfsl{r}$',
+u'\U0001d634': '$\\mathsfsl{s}$',
+u'\U0001d635': '$\\mathsfsl{t}$',
+u'\U0001d636': '$\\mathsfsl{u}$',
+u'\U0001d637': '$\\mathsfsl{v}$',
+u'\U0001d638': '$\\mathsfsl{w}$',
+u'\U0001d639': '$\\mathsfsl{x}$',
+u'\U0001d63a': '$\\mathsfsl{y}$',
+u'\U0001d63b': '$\\mathsfsl{z}$',
+u'\U0001d63c': '$\\mathsfbfsl{A}$',
+u'\U0001d63d': '$\\mathsfbfsl{B}$',
+u'\U0001d63e': '$\\mathsfbfsl{C}$',
+u'\U0001d63f': '$\\mathsfbfsl{D}$',
+u'\U0001d640': '$\\mathsfbfsl{E}$',
+u'\U0001d641': '$\\mathsfbfsl{F}$',
+u'\U0001d642': '$\\mathsfbfsl{G}$',
+u'\U0001d643': '$\\mathsfbfsl{H}$',
+u'\U0001d644': '$\\mathsfbfsl{I}$',
+u'\U0001d645': '$\\mathsfbfsl{J}$',
+u'\U0001d646': '$\\mathsfbfsl{K}$',
+u'\U0001d647': '$\\mathsfbfsl{L}$',
+u'\U0001d648': '$\\mathsfbfsl{M}$',
+u'\U0001d649': '$\\mathsfbfsl{N}$',
+u'\U0001d64a': '$\\mathsfbfsl{O}$',
+u'\U0001d64b': '$\\mathsfbfsl{P}$',
+u'\U0001d64c': '$\\mathsfbfsl{Q}$',
+u'\U0001d64d': '$\\mathsfbfsl{R}$',
+u'\U0001d64e': '$\\mathsfbfsl{S}$',
+u'\U0001d64f': '$\\mathsfbfsl{T}$',
+u'\U0001d650': '$\\mathsfbfsl{U}$',
+u'\U0001d651': '$\\mathsfbfsl{V}$',
+u'\U0001d652': '$\\mathsfbfsl{W}$',
+u'\U0001d653': '$\\mathsfbfsl{X}$',
+u'\U0001d654': '$\\mathsfbfsl{Y}$',
+u'\U0001d655': '$\\mathsfbfsl{Z}$',
+u'\U0001d656': '$\\mathsfbfsl{a}$',
+u'\U0001d657': '$\\mathsfbfsl{b}$',
+u'\U0001d658': '$\\mathsfbfsl{c}$',
+u'\U0001d659': '$\\mathsfbfsl{d}$',
+u'\U0001d65a': '$\\mathsfbfsl{e}$',
+u'\U0001d65b': '$\\mathsfbfsl{f}$',
+u'\U0001d65c': '$\\mathsfbfsl{g}$',
+u'\U0001d65d': '$\\mathsfbfsl{h}$',
+u'\U0001d65e': '$\\mathsfbfsl{i}$',
+u'\U0001d65f': '$\\mathsfbfsl{j}$',
+u'\U0001d660': '$\\mathsfbfsl{k}$',
+u'\U0001d661': '$\\mathsfbfsl{l}$',
+u'\U0001d662': '$\\mathsfbfsl{m}$',
+u'\U0001d663': '$\\mathsfbfsl{n}$',
+u'\U0001d664': '$\\mathsfbfsl{o}$',
+u'\U0001d665': '$\\mathsfbfsl{p}$',
+u'\U0001d666': '$\\mathsfbfsl{q}$',
+u'\U0001d667': '$\\mathsfbfsl{r}$',
+u'\U0001d668': '$\\mathsfbfsl{s}$',
+u'\U0001d669': '$\\mathsfbfsl{t}$',
+u'\U0001d66a': '$\\mathsfbfsl{u}$',
+u'\U0001d66b': '$\\mathsfbfsl{v}$',
+u'\U0001d66c': '$\\mathsfbfsl{w}$',
+u'\U0001d66d': '$\\mathsfbfsl{x}$',
+u'\U0001d66e': '$\\mathsfbfsl{y}$',
+u'\U0001d66f': '$\\mathsfbfsl{z}$',
+u'\U0001d670': '$\\mathtt{A}$',
+u'\U0001d671': '$\\mathtt{B}$',
+u'\U0001d672': '$\\mathtt{C}$',
+u'\U0001d673': '$\\mathtt{D}$',
+u'\U0001d674': '$\\mathtt{E}$',
+u'\U0001d675': '$\\mathtt{F}$',
+u'\U0001d676': '$\\mathtt{G}$',
+u'\U0001d677': '$\\mathtt{H}$',
+u'\U0001d678': '$\\mathtt{I}$',
+u'\U0001d679': '$\\mathtt{J}$',
+u'\U0001d67a': '$\\mathtt{K}$',
+u'\U0001d67b': '$\\mathtt{L}$',
+u'\U0001d67c': '$\\mathtt{M}$',
+u'\U0001d67d': '$\\mathtt{N}$',
+u'\U0001d67e': '$\\mathtt{O}$',
+u'\U0001d67f': '$\\mathtt{P}$',
+u'\U0001d680': '$\\mathtt{Q}$',
+u'\U0001d681': '$\\mathtt{R}$',
+u'\U0001d682': '$\\mathtt{S}$',
+u'\U0001d683': '$\\mathtt{T}$',
+u'\U0001d684': '$\\mathtt{U}$',
+u'\U0001d685': '$\\mathtt{V}$',
+u'\U0001d686': '$\\mathtt{W}$',
+u'\U0001d687': '$\\mathtt{X}$',
+u'\U0001d688': '$\\mathtt{Y}$',
+u'\U0001d689': '$\\mathtt{Z}$',
+u'\U0001d68a': '$\\mathtt{a}$',
+u'\U0001d68b': '$\\mathtt{b}$',
+u'\U0001d68c': '$\\mathtt{c}$',
+u'\U0001d68d': '$\\mathtt{d}$',
+u'\U0001d68e': '$\\mathtt{e}$',
+u'\U0001d68f': '$\\mathtt{f}$',
+u'\U0001d690': '$\\mathtt{g}$',
+u'\U0001d691': '$\\mathtt{h}$',
+u'\U0001d692': '$\\mathtt{i}$',
+u'\U0001d693': '$\\mathtt{j}$',
+u'\U0001d694': '$\\mathtt{k}$',
+u'\U0001d695': '$\\mathtt{l}$',
+u'\U0001d696': '$\\mathtt{m}$',
+u'\U0001d697': '$\\mathtt{n}$',
+u'\U0001d698': '$\\mathtt{o}$',
+u'\U0001d699': '$\\mathtt{p}$',
+u'\U0001d69a': '$\\mathtt{q}$',
+u'\U0001d69b': '$\\mathtt{r}$',
+u'\U0001d69c': '$\\mathtt{s}$',
+u'\U0001d69d': '$\\mathtt{t}$',
+u'\U0001d69e': '$\\mathtt{u}$',
+u'\U0001d69f': '$\\mathtt{v}$',
+u'\U0001d6a0': '$\\mathtt{w}$',
+u'\U0001d6a1': '$\\mathtt{x}$',
+u'\U0001d6a2': '$\\mathtt{y}$',
+u'\U0001d6a3': '$\\mathtt{z}$',
+u'\U0001d6a8': '$\\mathbf{\\Alpha}$',
+u'\U0001d6a9': '$\\mathbf{\\Beta}$',
+u'\U0001d6aa': '$\\mathbf{\\Gamma}$',
+u'\U0001d6ab': '$\\mathbf{\\Delta}$',
+u'\U0001d6ac': '$\\mathbf{\\Epsilon}$',
+u'\U0001d6ad': '$\\mathbf{\\Zeta}$',
+u'\U0001d6ae': '$\\mathbf{\\Eta}$',
+u'\U0001d6af': '$\\mathbf{\\Theta}$',
+u'\U0001d6b0': '$\\mathbf{\\Iota}$',
+u'\U0001d6b1': '$\\mathbf{\\Kappa}$',
+u'\U0001d6b2': '$\\mathbf{\\Lambda}$',
+u'\U0001d6b3': '$M$',
+u'\U0001d6b4': '$N$',
+u'\U0001d6b5': '$\\mathbf{\\Xi}$',
+u'\U0001d6b6': '$O$',
+u'\U0001d6b7': '$\\mathbf{\\Pi}$',
+u'\U0001d6b8': '$\\mathbf{\\Rho}$',
+u'\U0001d6b9': '{\\mathbf{\\vartheta}}',
+u'\U0001d6ba': '$\\mathbf{\\Sigma}$',
+u'\U0001d6bb': '$\\mathbf{\\Tau}$',
+u'\U0001d6bc': '$\\mathbf{\\Upsilon}$',
+u'\U0001d6bd': '$\\mathbf{\\Phi}$',
+u'\U0001d6be': '$\\mathbf{\\Chi}$',
+u'\U0001d6bf': '$\\mathbf{\\Psi}$',
+u'\U0001d6c0': '$\\mathbf{\\Omega}$',
+u'\U0001d6c1': '$\\mathbf{\\nabla}$',
+u'\U0001d6c2': '$\\mathbf{\\Alpha}$',
+u'\U0001d6c3': '$\\mathbf{\\Beta}$',
+u'\U0001d6c4': '$\\mathbf{\\Gamma}$',
+u'\U0001d6c5': '$\\mathbf{\\Delta}$',
+u'\U0001d6c6': '$\\mathbf{\\Epsilon}$',
+u'\U0001d6c7': '$\\mathbf{\\Zeta}$',
+u'\U0001d6c8': '$\\mathbf{\\Eta}$',
+u'\U0001d6c9': '$\\mathbf{\\theta}$',
+u'\U0001d6ca': '$\\mathbf{\\Iota}$',
+u'\U0001d6cb': '$\\mathbf{\\Kappa}$',
+u'\U0001d6cc': '$\\mathbf{\\Lambda}$',
+u'\U0001d6cd': '$M$',
+u'\U0001d6ce': '$N$',
+u'\U0001d6cf': '$\\mathbf{\\Xi}$',
+u'\U0001d6d0': '$O$',
+u'\U0001d6d1': '$\\mathbf{\\Pi}$',
+u'\U0001d6d2': '$\\mathbf{\\Rho}$',
+u'\U0001d6d3': '$\\mathbf{\\varsigma}$',
+u'\U0001d6d4': '$\\mathbf{\\Sigma}$',
+u'\U0001d6d5': '$\\mathbf{\\Tau}$',
+u'\U0001d6d6': '$\\mathbf{\\Upsilon}$',
+u'\U0001d6d7': '$\\mathbf{\\Phi}$',
+u'\U0001d6d8': '$\\mathbf{\\Chi}$',
+u'\U0001d6d9': '$\\mathbf{\\Psi}$',
+u'\U0001d6da': '$\\mathbf{\\Omega}$',
+u'\U0001d6db': '$\\partial$',
+u'\U0001d6dc': '$\\in$',
+u'\U0001d6dd': '{\\mathbf{\\vartheta}}',
+u'\U0001d6de': '{\\mathbf{\\varkappa}}',
+u'\U0001d6df': '{\\mathbf{\\phi}}',
+u'\U0001d6e0': '{\\mathbf{\\varrho}}',
+u'\U0001d6e1': '{\\mathbf{\\varpi}}',
+u'\U0001d6e2': '$\\mathsl{\\Alpha}$',
+u'\U0001d6e3': '$\\mathsl{\\Beta}$',
+u'\U0001d6e4': '$\\mathsl{\\Gamma}$',
+u'\U0001d6e5': '$\\mathsl{\\Delta}$',
+u'\U0001d6e6': '$\\mathsl{\\Epsilon}$',
+u'\U0001d6e7': '$\\mathsl{\\Zeta}$',
+u'\U0001d6e8': '$\\mathsl{\\Eta}$',
+u'\U0001d6e9': '$\\mathsl{\\Theta}$',
+u'\U0001d6ea': '$\\mathsl{\\Iota}$',
+u'\U0001d6eb': '$\\mathsl{\\Kappa}$',
+u'\U0001d6ec': '$\\mathsl{\\Lambda}$',
+u'\U0001d6ed': '$M$',
+u'\U0001d6ee': '$N$',
+u'\U0001d6ef': '$\\mathsl{\\Xi}$',
+u'\U0001d6f0': '$O$',
+u'\U0001d6f1': '$\\mathsl{\\Pi}$',
+u'\U0001d6f2': '$\\mathsl{\\Rho}$',
+u'\U0001d6f3': '{\\mathsl{\\vartheta}}',
+u'\U0001d6f4': '$\\mathsl{\\Sigma}$',
+u'\U0001d6f5': '$\\mathsl{\\Tau}$',
+u'\U0001d6f6': '$\\mathsl{\\Upsilon}$',
+u'\U0001d6f7': '$\\mathsl{\\Phi}$',
+u'\U0001d6f8': '$\\mathsl{\\Chi}$',
+u'\U0001d6f9': '$\\mathsl{\\Psi}$',
+u'\U0001d6fa': '$\\mathsl{\\Omega}$',
+u'\U0001d6fb': '$\\mathsl{\\nabla}$',
+u'\U0001d6fc': '$\\mathsl{\\Alpha}$',
+u'\U0001d6fd': '$\\mathsl{\\Beta}$',
+u'\U0001d6fe': '$\\mathsl{\\Gamma}$',
+u'\U0001d6ff': '$\\mathsl{\\Delta}$',
+u'\U0001d700': '$\\mathsl{\\Epsilon}$',
+u'\U0001d701': '$\\mathsl{\\Zeta}$',
+u'\U0001d702': '$\\mathsl{\\Eta}$',
+u'\U0001d703': '$\\mathsl{\\Theta}$',
+u'\U0001d704': '$\\mathsl{\\Iota}$',
+u'\U0001d705': '$\\mathsl{\\Kappa}$',
+u'\U0001d706': '$\\mathsl{\\Lambda}$',
+u'\U0001d707': '$M$',
+u'\U0001d708': '$N$',
+u'\U0001d709': '$\\mathsl{\\Xi}$',
+u'\U0001d70a': '$O$',
+u'\U0001d70b': '$\\mathsl{\\Pi}$',
+u'\U0001d70c': '$\\mathsl{\\Rho}$',
+u'\U0001d70d': '$\\mathsl{\\varsigma}$',
+u'\U0001d70e': '$\\mathsl{\\Sigma}$',
+u'\U0001d70f': '$\\mathsl{\\Tau}$',
+u'\U0001d710': '$\\mathsl{\\Upsilon}$',
+u'\U0001d711': '$\\mathsl{\\Phi}$',
+u'\U0001d712': '$\\mathsl{\\Chi}$',
+u'\U0001d713': '$\\mathsl{\\Psi}$',
+u'\U0001d714': '$\\mathsl{\\Omega}$',
+u'\U0001d715': '$\\partial$',
+u'\U0001d716': '$\\in$',
+u'\U0001d717': '{\\mathsl{\\vartheta}}',
+u'\U0001d718': '{\\mathsl{\\varkappa}}',
+u'\U0001d719': '{\\mathsl{\\phi}}',
+u'\U0001d71a': '{\\mathsl{\\varrho}}',
+u'\U0001d71b': '{\\mathsl{\\varpi}}',
+u'\U0001d71c': '$\\mathbit{\\Alpha}$',
+u'\U0001d71d': '$\\mathbit{\\Beta}$',
+u'\U0001d71e': '$\\mathbit{\\Gamma}$',
+u'\U0001d71f': '$\\mathbit{\\Delta}$',
+u'\U0001d720': '$\\mathbit{\\Epsilon}$',
+u'\U0001d721': '$\\mathbit{\\Zeta}$',
+u'\U0001d722': '$\\mathbit{\\Eta}$',
+u'\U0001d723': '$\\mathbit{\\Theta}$',
+u'\U0001d724': '$\\mathbit{\\Iota}$',
+u'\U0001d725': '$\\mathbit{\\Kappa}$',
+u'\U0001d726': '$\\mathbit{\\Lambda}$',
+u'\U0001d727': '$M$',
+u'\U0001d728': '$N$',
+u'\U0001d729': '$\\mathbit{\\Xi}$',
+u'\U0001d72a': '$O$',
+u'\U0001d72b': '$\\mathbit{\\Pi}$',
+u'\U0001d72c': '$\\mathbit{\\Rho}$',
+u'\U0001d72d': '{\\mathbit{O}}',
+u'\U0001d72e': '$\\mathbit{\\Sigma}$',
+u'\U0001d72f': '$\\mathbit{\\Tau}$',
+u'\U0001d730': '$\\mathbit{\\Upsilon}$',
+u'\U0001d731': '$\\mathbit{\\Phi}$',
+u'\U0001d732': '$\\mathbit{\\Chi}$',
+u'\U0001d733': '$\\mathbit{\\Psi}$',
+u'\U0001d734': '$\\mathbit{\\Omega}$',
+u'\U0001d735': '$\\mathbit{\\nabla}$',
+u'\U0001d736': '$\\mathbit{\\Alpha}$',
+u'\U0001d737': '$\\mathbit{\\Beta}$',
+u'\U0001d738': '$\\mathbit{\\Gamma}$',
+u'\U0001d739': '$\\mathbit{\\Delta}$',
+u'\U0001d73a': '$\\mathbit{\\Epsilon}$',
+u'\U0001d73b': '$\\mathbit{\\Zeta}$',
+u'\U0001d73c': '$\\mathbit{\\Eta}$',
+u'\U0001d73d': '$\\mathbit{\\Theta}$',
+u'\U0001d73e': '$\\mathbit{\\Iota}$',
+u'\U0001d73f': '$\\mathbit{\\Kappa}$',
+u'\U0001d740': '$\\mathbit{\\Lambda}$',
+u'\U0001d741': '$M$',
+u'\U0001d742': '$N$',
+u'\U0001d743': '$\\mathbit{\\Xi}$',
+u'\U0001d744': '$O$',
+u'\U0001d745': '$\\mathbit{\\Pi}$',
+u'\U0001d746': '$\\mathbit{\\Rho}$',
+u'\U0001d747': '$\\mathbit{\\varsigma}$',
+u'\U0001d748': '$\\mathbit{\\Sigma}$',
+u'\U0001d749': '$\\mathbit{\\Tau}$',
+u'\U0001d74a': '$\\mathbit{\\Upsilon}$',
+u'\U0001d74b': '$\\mathbit{\\Phi}$',
+u'\U0001d74c': '$\\mathbit{\\Chi}$',
+u'\U0001d74d': '$\\mathbit{\\Psi}$',
+u'\U0001d74e': '$\\mathbit{\\Omega}$',
+u'\U0001d74f': '$\\partial$',
+u'\U0001d750': '$\\in$',
+u'\U0001d751': '{\\mathbit{\\vartheta}}',
+u'\U0001d752': '{\\mathbit{\\varkappa}}',
+u'\U0001d753': '{\\mathbit{\\phi}}',
+u'\U0001d754': '{\\mathbit{\\varrho}}',
+u'\U0001d755': '{\\mathbit{\\varpi}}',
+u'\U0001d756': '$\\mathsfbf{\\Alpha}$',
+u'\U0001d757': '$\\mathsfbf{\\Beta}$',
+u'\U0001d758': '$\\mathsfbf{\\Gamma}$',
+u'\U0001d759': '$\\mathsfbf{\\Delta}$',
+u'\U0001d75a': '$\\mathsfbf{\\Epsilon}$',
+u'\U0001d75b': '$\\mathsfbf{\\Zeta}$',
+u'\U0001d75c': '$\\mathsfbf{\\Eta}$',
+u'\U0001d75d': '$\\mathsfbf{\\Theta}$',
+u'\U0001d75e': '$\\mathsfbf{\\Iota}$',
+u'\U0001d75f': '$\\mathsfbf{\\Kappa}$',
+u'\U0001d760': '$\\mathsfbf{\\Lambda}$',
+u'\U0001d761': '$M$',
+u'\U0001d762': '$N$',
+u'\U0001d763': '$\\mathsfbf{\\Xi}$',
+u'\U0001d764': '$O$',
+u'\U0001d765': '$\\mathsfbf{\\Pi}$',
+u'\U0001d766': '$\\mathsfbf{\\Rho}$',
+u'\U0001d767': '{\\mathsfbf{\\vartheta}}',
+u'\U0001d768': '$\\mathsfbf{\\Sigma}$',
+u'\U0001d769': '$\\mathsfbf{\\Tau}$',
+u'\U0001d76a': '$\\mathsfbf{\\Upsilon}$',
+u'\U0001d76b': '$\\mathsfbf{\\Phi}$',
+u'\U0001d76c': '$\\mathsfbf{\\Chi}$',
+u'\U0001d76d': '$\\mathsfbf{\\Psi}$',
+u'\U0001d76e': '$\\mathsfbf{\\Omega}$',
+u'\U0001d76f': '$\\mathsfbf{\\nabla}$',
+u'\U0001d770': '$\\mathsfbf{\\Alpha}$',
+u'\U0001d771': '$\\mathsfbf{\\Beta}$',
+u'\U0001d772': '$\\mathsfbf{\\Gamma}$',
+u'\U0001d773': '$\\mathsfbf{\\Delta}$',
+u'\U0001d774': '$\\mathsfbf{\\Epsilon}$',
+u'\U0001d775': '$\\mathsfbf{\\Zeta}$',
+u'\U0001d776': '$\\mathsfbf{\\Eta}$',
+u'\U0001d777': '$\\mathsfbf{\\Theta}$',
+u'\U0001d778': '$\\mathsfbf{\\Iota}$',
+u'\U0001d779': '$\\mathsfbf{\\Kappa}$',
+u'\U0001d77a': '$\\mathsfbf{\\Lambda}$',
+u'\U0001d77b': '$M$',
+u'\U0001d77c': '$N$',
+u'\U0001d77d': '$\\mathsfbf{\\Xi}$',
+u'\U0001d77e': '$O$',
+u'\U0001d77f': '$\\mathsfbf{\\Pi}$',
+u'\U0001d780': '$\\mathsfbf{\\Rho}$',
+u'\U0001d781': '$\\mathsfbf{\\varsigma}$',
+u'\U0001d782': '$\\mathsfbf{\\Sigma}$',
+u'\U0001d783': '$\\mathsfbf{\\Tau}$',
+u'\U0001d784': '$\\mathsfbf{\\Upsilon}$',
+u'\U0001d785': '$\\mathsfbf{\\Phi}$',
+u'\U0001d786': '$\\mathsfbf{\\Chi}$',
+u'\U0001d787': '$\\mathsfbf{\\Psi}$',
+u'\U0001d788': '$\\mathsfbf{\\Omega}$',
+u'\U0001d789': '$\\partial$',
+u'\U0001d78a': '$\\in$',
+u'\U0001d78b': '{\\mathsfbf{\\vartheta}}',
+u'\U0001d78c': '{\\mathsfbf{\\varkappa}}',
+u'\U0001d78d': '{\\mathsfbf{\\phi}}',
+u'\U0001d78e': '{\\mathsfbf{\\varrho}}',
+u'\U0001d78f': '{\\mathsfbf{\\varpi}}',
+u'\U0001d790': '$\\mathsfbfsl{\\Alpha}$',
+u'\U0001d791': '$\\mathsfbfsl{\\Beta}$',
+u'\U0001d792': '$\\mathsfbfsl{\\Gamma}$',
+u'\U0001d793': '$\\mathsfbfsl{\\Delta}$',
+u'\U0001d794': '$\\mathsfbfsl{\\Epsilon}$',
+u'\U0001d795': '$\\mathsfbfsl{\\Zeta}$',
+u'\U0001d796': '$\\mathsfbfsl{\\Eta}$',
+u'\U0001d797': '$\\mathsfbfsl{\\vartheta}$',
+u'\U0001d798': '$\\mathsfbfsl{\\Iota}$',
+u'\U0001d799': '$\\mathsfbfsl{\\Kappa}$',
+u'\U0001d79a': '$\\mathsfbfsl{\\Lambda}$',
+u'\U0001d79b': '$M$',
+u'\U0001d79c': '$N$',
+u'\U0001d79d': '$\\mathsfbfsl{\\Xi}$',
+u'\U0001d79e': '$O$',
+u'\U0001d79f': '$\\mathsfbfsl{\\Pi}$',
+u'\U0001d7a0': '$\\mathsfbfsl{\\Rho}$',
+u'\U0001d7a1': '{\\mathsfbfsl{\\vartheta}}',
+u'\U0001d7a2': '$\\mathsfbfsl{\\Sigma}$',
+u'\U0001d7a3': '$\\mathsfbfsl{\\Tau}$',
+u'\U0001d7a4': '$\\mathsfbfsl{\\Upsilon}$',
+u'\U0001d7a5': '$\\mathsfbfsl{\\Phi}$',
+u'\U0001d7a6': '$\\mathsfbfsl{\\Chi}$',
+u'\U0001d7a7': '$\\mathsfbfsl{\\Psi}$',
+u'\U0001d7a8': '$\\mathsfbfsl{\\Omega}$',
+u'\U0001d7a9': '$\\mathsfbfsl{\\nabla}$',
+u'\U0001d7aa': '$\\mathsfbfsl{\\Alpha}$',
+u'\U0001d7ab': '$\\mathsfbfsl{\\Beta}$',
+u'\U0001d7ac': '$\\mathsfbfsl{\\Gamma}$',
+u'\U0001d7ad': '$\\mathsfbfsl{\\Delta}$',
+u'\U0001d7ae': '$\\mathsfbfsl{\\Epsilon}$',
+u'\U0001d7af': '$\\mathsfbfsl{\\Zeta}$',
+u'\U0001d7b0': '$\\mathsfbfsl{\\Eta}$',
+u'\U0001d7b1': '$\\mathsfbfsl{\\vartheta}$',
+u'\U0001d7b2': '$\\mathsfbfsl{\\Iota}$',
+u'\U0001d7b3': '$\\mathsfbfsl{\\Kappa}$',
+u'\U0001d7b4': '$\\mathsfbfsl{\\Lambda}$',
+u'\U0001d7b5': '$M$',
+u'\U0001d7b6': '$N$',
+u'\U0001d7b7': '$\\mathsfbfsl{\\Xi}$',
+u'\U0001d7b8': '$O$',
+u'\U0001d7b9': '$\\mathsfbfsl{\\Pi}$',
+u'\U0001d7ba': '$\\mathsfbfsl{\\Rho}$',
+u'\U0001d7bb': '$\\mathsfbfsl{\\varsigma}$',
+u'\U0001d7bc': '$\\mathsfbfsl{\\Sigma}$',
+u'\U0001d7bd': '$\\mathsfbfsl{\\Tau}$',
+u'\U0001d7be': '$\\mathsfbfsl{\\Upsilon}$',
+u'\U0001d7bf': '$\\mathsfbfsl{\\Phi}$',
+u'\U0001d7c0': '$\\mathsfbfsl{\\Chi}$',
+u'\U0001d7c1': '$\\mathsfbfsl{\\Psi}$',
+u'\U0001d7c2': '$\\mathsfbfsl{\\Omega}$',
+u'\U0001d7c3': '$\\partial$',
+u'\U0001d7c4': '$\\in$',
+u'\U0001d7c5': '{\\mathsfbfsl{\\vartheta}}',
+u'\U0001d7c6': '{\\mathsfbfsl{\\varkappa}}',
+u'\U0001d7c7': '{\\mathsfbfsl{\\phi}}',
+u'\U0001d7c8': '{\\mathsfbfsl{\\varrho}}',
+u'\U0001d7c9': '{\\mathsfbfsl{\\varpi}}',
+u'\U0001d7ce': '$\\mathbf{0}$',
+u'\U0001d7cf': '$\\mathbf{1}$',
+u'\U0001d7d0': '$\\mathbf{2}$',
+u'\U0001d7d1': '$\\mathbf{3}$',
+u'\U0001d7d2': '$\\mathbf{4}$',
+u'\U0001d7d3': '$\\mathbf{5}$',
+u'\U0001d7d4': '$\\mathbf{6}$',
+u'\U0001d7d5': '$\\mathbf{7}$',
+u'\U0001d7d6': '$\\mathbf{8}$',
+u'\U0001d7d7': '$\\mathbf{9}$',
+u'\U0001d7d8': '$\\mathbb{0}$',
+u'\U0001d7d9': '$\\mathbb{1}$',
+u'\U0001d7da': '$\\mathbb{2}$',
+u'\U0001d7db': '$\\mathbb{3}$',
+u'\U0001d7dc': '$\\mathbb{4}$',
+u'\U0001d7dd': '$\\mathbb{5}$',
+u'\U0001d7de': '$\\mathbb{6}$',
+u'\U0001d7df': '$\\mathbb{7}$',
+u'\U0001d7e0': '$\\mathbb{8}$',
+u'\U0001d7e1': '$\\mathbb{9}$',
+u'\U0001d7e2': '$\\mathsf{0}$',
+u'\U0001d7e3': '$\\mathsf{1}$',
+u'\U0001d7e4': '$\\mathsf{2}$',
+u'\U0001d7e5': '$\\mathsf{3}$',
+u'\U0001d7e6': '$\\mathsf{4}$',
+u'\U0001d7e7': '$\\mathsf{5}$',
+u'\U0001d7e8': '$\\mathsf{6}$',
+u'\U0001d7e9': '$\\mathsf{7}$',
+u'\U0001d7ea': '$\\mathsf{8}$',
+u'\U0001d7eb': '$\\mathsf{9}$',
+u'\U0001d7ec': '$\\mathsfbf{0}$',
+u'\U0001d7ed': '$\\mathsfbf{1}$',
+u'\U0001d7ee': '$\\mathsfbf{2}$',
+u'\U0001d7ef': '$\\mathsfbf{3}$',
+u'\U0001d7f0': '$\\mathsfbf{4}$',
+u'\U0001d7f1': '$\\mathsfbf{5}$',
+u'\U0001d7f2': '$\\mathsfbf{6}$',
+u'\U0001d7f3': '$\\mathsfbf{7}$',
+u'\U0001d7f4': '$\\mathsfbf{8}$',
+u'\U0001d7f5': '$\\mathsfbf{9}$',
+u'\U0001d7f6': '$\\mathtt{0}$',
+u'\U0001d7f7': '$\\mathtt{1}$',
+u'\U0001d7f8': '$\\mathtt{2}$',
+u'\U0001d7f9': '$\\mathtt{3}$',
+u'\U0001d7fa': '$\\mathtt{4}$',
+u'\U0001d7fb': '$\\mathtt{5}$',
+u'\U0001d7fc': '$\\mathtt{6}$',
+u'\U0001d7fd': '$\\mathtt{7}$',
+u'\U0001d7fe': '$\\mathtt{8}$',
+u'\U0001d7ff': '$\\mathtt{9}$'}
diff --git a/docutils/writers/null.py b/docutils/writers/null.py
new file mode 100644
index 000000000..4632c7457
--- /dev/null
+++ b/docutils/writers/null.py
@@ -0,0 +1,23 @@
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+A do-nothing Writer.
+"""
+
+from docutils import writers
+
+
+class Writer(writers.UnfilteredWriter):
+
+ supported = ('null',)
+ """Formats this writer supports."""
+
+ config_section = 'null writer'
+ config_section_dependencies = ('writers',)
+
+ def translate(self):
+ pass
diff --git a/docutils/writers/pep_html/__init__.py b/docutils/writers/pep_html/__init__.py
new file mode 100644
index 000000000..a672e1c6d
--- /dev/null
+++ b/docutils/writers/pep_html/__init__.py
@@ -0,0 +1,108 @@
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+PEP HTML Writer.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+import sys
+import os
+import os.path
+import docutils
+from docutils import frontend, nodes, utils, writers
+from docutils.writers import html4css1
+
+
+class Writer(html4css1.Writer):
+
+ default_stylesheet = 'pep.css'
+
+ default_stylesheet_path = utils.relative_path(
+ os.path.join(os.getcwd(), 'dummy'),
+ os.path.join(os.path.dirname(__file__), default_stylesheet))
+
+ default_template = 'template.txt'
+
+ default_template_path = utils.relative_path(
+ os.path.join(os.getcwd(), 'dummy'),
+ os.path.join(os.path.dirname(__file__), default_template))
+
+ settings_spec = html4css1.Writer.settings_spec + (
+ 'PEP/HTML-Specific Options',
+ 'The default value for the --stylesheet-path option (defined in '
+ 'HTML-Specific Options above) is "%s" for the PEP/HTML writer.'
+ % default_stylesheet_path,
+ (('Specify a template file. Default is "%s".' % default_template_path,
+ ['--template'],
+ {'default': default_template_path, 'metavar': '<file>'}),
+ ('Python\'s home URL. Default is "http://www.python.org".',
+ ['--python-home'],
+ {'default': 'http://www.python.org', 'metavar': '<URL>'}),
+ ('Home URL prefix for PEPs. Default is "." (current directory).',
+ ['--pep-home'],
+ {'default': '.', 'metavar': '<URL>'}),
+ # For testing.
+ (frontend.SUPPRESS_HELP,
+ ['--no-random'],
+ {'action': 'store_true', 'validator': frontend.validate_boolean}),))
+
+ settings_default_overrides = {'stylesheet_path': default_stylesheet_path}
+
+ relative_path_settings = (html4css1.Writer.relative_path_settings
+ + ('template',))
+
+ config_section = 'pep_html writer'
+ config_section_dependencies = ('writers', 'html4css1 writer')
+
+ def __init__(self):
+ html4css1.Writer.__init__(self)
+ self.translator_class = HTMLTranslator
+
+ def translate(self):
+ html4css1.Writer.translate(self)
+ settings = self.document.settings
+ template = open(settings.template).read()
+ # Substitutions dict for template:
+ subs = {}
+ subs['encoding'] = settings.output_encoding
+ subs['version'] = docutils.__version__
+ subs['stylesheet'] = ''.join(self.stylesheet)
+ pyhome = settings.python_home
+ subs['pyhome'] = pyhome
+ subs['pephome'] = settings.pep_home
+ if pyhome == '..':
+ subs['pepindex'] = '.'
+ else:
+ subs['pepindex'] = pyhome + '/peps'
+ index = self.document.first_child_matching_class(nodes.field_list)
+ header = self.document[index]
+ pepnum = header[0][1].astext()
+ subs['pep'] = pepnum
+ if settings.no_random:
+ subs['banner'] = 0
+ else:
+ import random
+ subs['banner'] = random.randrange(64)
+ try:
+ subs['pepnum'] = '%04i' % int(pepnum)
+ except ValueError:
+ subs['pepnum'] = pepnum
+ subs['title'] = header[1][1].astext()
+ subs['body'] = ''.join(
+ self.body_pre_docinfo + self.docinfo + self.body)
+ subs['body_suffix'] = ''.join(self.body_suffix)
+ self.output = template % subs
+
+
+class HTMLTranslator(html4css1.HTMLTranslator):
+
+ def depart_field_list(self, node):
+ html4css1.HTMLTranslator.depart_field_list(self, node)
+ if 'rfc2822' in node['classes']:
+ self.body.append('<hr />\n')
diff --git a/docutils/writers/pep_html/pep.css b/docutils/writers/pep_html/pep.css
new file mode 100644
index 000000000..014d3e423
--- /dev/null
+++ b/docutils/writers/pep_html/pep.css
@@ -0,0 +1,348 @@
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:date: $Date$
+:version: $Revision$
+:copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the PEP HTML output of Docutils.
+*/
+
+/* "! important" is used here to override other ``margin-top`` and
+ ``margin-bottom`` styles that are later in the stylesheet or
+ more specific. See http://www.w3.org/TR/CSS1#the-cascade */
+.first {
+ margin-top: 0 ! important }
+
+.last, .with-subtitle {
+ margin-bottom: 0 ! important }
+
+.hidden {
+ display: none }
+
+.navigation {
+ width: 100% ;
+ background: #99ccff ;
+ margin-top: 0px ;
+ margin-bottom: 0px }
+
+.navigation .navicon {
+ width: 150px ;
+ height: 35px }
+
+.navigation .textlinks {
+ padding-left: 1em ;
+ text-align: left }
+
+.navigation td, .navigation th {
+ padding-left: 0em ;
+ padding-right: 0em ;
+ vertical-align: middle }
+
+.rfc2822 {
+ margin-top: 0.5em ;
+ margin-left: 0.5em ;
+ margin-right: 0.5em ;
+ margin-bottom: 0em }
+
+.rfc2822 td {
+ text-align: left }
+
+.rfc2822 th.field-name {
+ text-align: right ;
+ font-family: sans-serif ;
+ padding-right: 0.5em ;
+ font-weight: bold ;
+ margin-bottom: 0em }
+
+a.toc-backref {
+ text-decoration: none ;
+ color: black }
+
+blockquote.epigraph {
+ margin: 2em 5em ; }
+
+body {
+ margin: 0px ;
+ margin-bottom: 1em ;
+ padding: 0px }
+
+dl.docutils dd {
+ margin-bottom: 0.5em }
+
+div.section {
+ margin-left: 1em ;
+ margin-right: 1em ;
+ margin-bottom: 1.5em }
+
+div.section div.section {
+ margin-left: 0em ;
+ margin-right: 0em ;
+ margin-top: 1.5em }
+
+div.abstract {
+ margin: 2em 5em }
+
+div.abstract p.topic-title {
+ font-weight: bold ;
+ text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+ margin: 2em ;
+ border: medium outset ;
+ padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+ color: red ;
+ font-weight: bold ;
+ font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+ compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+ margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+ margin-top: 0.5em }
+*/
+
+div.dedication {
+ margin: 2em 5em ;
+ text-align: center ;
+ font-style: italic }
+
+div.dedication p.topic-title {
+ font-weight: bold ;
+ font-style: normal }
+
+div.figure {
+ margin-left: 2em ;
+ margin-right: 2em }
+
+div.footer, div.header {
+ clear: both;
+ font-size: smaller }
+
+div.footer {
+ margin-left: 1em ;
+ margin-right: 1em }
+
+div.line-block {
+ display: block ;
+ margin-top: 1em ;
+ margin-bottom: 1em }
+
+div.line-block div.line-block {
+ margin-top: 0 ;
+ margin-bottom: 0 ;
+ margin-left: 1.5em }
+
+div.sidebar {
+ margin-left: 1em ;
+ border: medium outset ;
+ padding: 1em ;
+ background-color: #ffffee ;
+ width: 40% ;
+ float: right ;
+ clear: right }
+
+div.sidebar p.rubric {
+ font-family: sans-serif ;
+ font-size: medium }
+
+div.system-messages {
+ margin: 5em }
+
+div.system-messages h1 {
+ color: red }
+
+div.system-message {
+ border: medium outset ;
+ padding: 1em }
+
+div.system-message p.system-message-title {
+ color: red ;
+ font-weight: bold }
+
+div.topic {
+ margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+ margin-top: 0.4em }
+
+h1 {
+ font-family: sans-serif ;
+ font-size: large }
+
+h2 {
+ font-family: sans-serif ;
+ font-size: medium }
+
+h3 {
+ font-family: sans-serif ;
+ font-size: small }
+
+h4 {
+ font-family: sans-serif ;
+ font-style: italic ;
+ font-size: small }
+
+h5 {
+ font-family: sans-serif;
+ font-size: x-small }
+
+h6 {
+ font-family: sans-serif;
+ font-style: italic ;
+ font-size: x-small }
+
+hr.docutils {
+ width: 75% }
+
+img.align-left {
+ clear: left }
+
+img.align-right {
+ clear: right }
+
+img.borderless {
+ border: 0 }
+
+ol.simple, ul.simple {
+ margin-bottom: 1em }
+
+ol.arabic {
+ list-style: decimal }
+
+ol.loweralpha {
+ list-style: lower-alpha }
+
+ol.upperalpha {
+ list-style: upper-alpha }
+
+ol.lowerroman {
+ list-style: lower-roman }
+
+ol.upperroman {
+ list-style: upper-roman }
+
+p.attribution {
+ text-align: right ;
+ margin-left: 50% }
+
+p.caption {
+ font-style: italic }
+
+p.credits {
+ font-style: italic ;
+ font-size: smaller }
+
+p.label {
+ white-space: nowrap }
+
+p.rubric {
+ font-weight: bold ;
+ font-size: larger ;
+ color: maroon ;
+ text-align: center }
+
+p.sidebar-title {
+ font-family: sans-serif ;
+ font-weight: bold ;
+ font-size: larger }
+
+p.sidebar-subtitle {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+p.topic-title {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+pre.address {
+ margin-bottom: 0 ;
+ margin-top: 0 ;
+ font-family: serif ;
+ font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+ margin-left: 2em ;
+ margin-right: 2em ;
+ background-color: #eeeeee }
+
+span.classifier {
+ font-family: sans-serif ;
+ font-style: oblique }
+
+span.classifier-delimiter {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+span.interpreted {
+ font-family: sans-serif }
+
+span.option {
+ white-space: nowrap }
+
+span.option-argument {
+ font-style: italic }
+
+span.pre {
+ white-space: pre }
+
+span.problematic {
+ color: red }
+
+span.section-subtitle {
+ /* font-size relative to parent (h1..h6 element) */
+ font-size: 80% }
+
+table.citation {
+ border-left: solid 1px gray;
+ margin-left: 1px }
+
+table.docinfo {
+ margin: 2em 4em }
+
+table.docutils {
+ margin-top: 0.5em ;
+ margin-bottom: 0.5em }
+
+table.footnote {
+ border-left: solid 1px black;
+ margin-left: 1px }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+ padding-left: 0.5em ;
+ padding-right: 0.5em ;
+ vertical-align: top }
+
+td.num {
+ text-align: right }
+
+th.field-name {
+ font-weight: bold ;
+ text-align: left ;
+ white-space: nowrap ;
+ padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+ font-size: 100% }
+
+tt.docutils {
+ background-color: #eeeeee }
+
+ul.auto-toc {
+ list-style-type: none }
diff --git a/docutils/writers/pep_html/template.txt b/docutils/writers/pep_html/template.txt
new file mode 100644
index 000000000..6f96977e8
--- /dev/null
+++ b/docutils/writers/pep_html/template.txt
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="%(encoding)s" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<!--
+This HTML is auto-generated. DO NOT EDIT THIS FILE! If you are writing a new
+PEP, see http://www.python.org/peps/pep-0001.html for instructions and links
+to templates. DO NOT USE THIS HTML FILE AS YOUR TEMPLATE!
+-->
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=%(encoding)s" />
+ <meta name="generator" content="Docutils %(version)s: http://docutils.sourceforge.net/" />
+ <title>PEP %(pep)s -- %(title)s</title>
+ %(stylesheet)s</head>
+<body bgcolor="white">
+<table class="navigation" cellpadding="0" cellspacing="0"
+ width="100%%" border="0">
+<tr><td class="navicon" width="150" height="35">
+<a href="%(pyhome)s/" title="Python Home Page">
+<img src="%(pyhome)s/pics/PyBanner%(banner)03d.gif" alt="[Python]"
+ border="0" width="150" height="35" /></a></td>
+<td class="textlinks" align="left">
+[<b><a href="%(pyhome)s/">Python Home</a></b>]
+[<b><a href="%(pepindex)s/">PEP Index</a></b>]
+[<b><a href="%(pephome)s/pep-%(pepnum)s.txt">PEP Source</a></b>]
+</td></tr></table>
+<div class="document">
+%(body)s
+%(body_suffix)s
diff --git a/docutils/writers/pseudoxml.py b/docutils/writers/pseudoxml.py
new file mode 100644
index 000000000..c0e18bffb
--- /dev/null
+++ b/docutils/writers/pseudoxml.py
@@ -0,0 +1,33 @@
+# Authors: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Simple internal document tree Writer, writes indented pseudo-XML.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+from docutils import writers
+
+
+class Writer(writers.Writer):
+
+ supported = ('pprint', 'pformat', 'pseudoxml')
+ """Formats this writer supports."""
+
+ config_section = 'pseudoxml writer'
+ config_section_dependencies = ('writers',)
+
+ output = None
+ """Final translated form of `document`."""
+
+ def translate(self):
+ self.output = self.document.pformat()
+
+ def supports(self, format):
+ """This writer supports all format-specific elements."""
+ return 1
diff --git a/docutils/writers/s5_html/__init__.py b/docutils/writers/s5_html/__init__.py
new file mode 100644
index 000000000..e4bde3375
--- /dev/null
+++ b/docutils/writers/s5_html/__init__.py
@@ -0,0 +1,326 @@
+# Author: Chris Liechti
+# Contact: cliechti@gmx.net
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+S5/HTML Slideshow Writer.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+import sys
+import os
+import re
+import docutils
+from docutils import frontend, nodes, utils
+from docutils.writers import html4css1
+from docutils.parsers.rst import directives
+
+themes_dir_path = utils.relative_path(
+ os.path.join(os.getcwd(), 'dummy'),
+ os.path.join(os.path.dirname(__file__), 'themes'))
+
+def find_theme(name):
+ # Where else to look for a theme?
+ # Check working dir? Destination dir? Config dir? Plugins dir?
+ path = os.path.join(themes_dir_path, name)
+ if not os.path.isdir(path):
+ raise docutils.ApplicationError(
+ 'Theme directory not found: %r (path: %r)' % (name, path))
+ return path
+
+
+class Writer(html4css1.Writer):
+
+ settings_spec = html4css1.Writer.settings_spec + (
+ 'S5 Slideshow Specific Options',
+ 'For the S5/HTML writer, the --no-toc-backlinks option '
+ '(defined in General Docutils Options above) is the default, '
+ 'and should not be changed.',
+ (('Specify an installed S5 theme by name. Overrides --theme-url. '
+ 'The default theme name is "default". The theme files will be '
+ 'copied into a "ui/<theme>" directory, in the same directory as the '
+ 'destination file (output HTML). Note that existing theme files '
+ 'will not be overwritten (unless --overwrite-theme-files is used).',
+ ['--theme'],
+ {'default': 'default', 'metavar': '<name>',
+ 'overrides': 'theme_url'}),
+ ('Specify an S5 theme URL. The destination file (output HTML) will '
+ 'link to this theme; nothing will be copied. Overrides --theme.',
+ ['--theme-url'],
+ {'metavar': '<URL>', 'overrides': 'theme'}),
+ ('Allow existing theme files in the ``ui/<theme>`` directory to be '
+ 'overwritten. The default is not to overwrite theme files.',
+ ['--overwrite-theme-files'],
+ {'action': 'store_true'}),
+ ('Keep existing theme files in the ``ui/<theme>`` directory; do not '
+ 'overwrite any. This is the default.',
+ ['--keep-theme-files'],
+ {'dest': 'overwrite_theme_files', 'action': 'store_false'}),
+ ('Enable the current slide indicator ("1 / 15"). '
+ 'The default is to disable it.',
+ ['--current-slide'],
+ {'action': 'store_true'}),
+ ('Disable the current slide indicator. This is the default.',
+ ['--no-current-slide'],
+ {'dest': 'current_slide', 'action': 'store_false'}),))
+
+ settings_default_overrides = {'toc_backlinks': 0}
+
+ config_section = 's5_html writer'
+ config_section_dependencies = ('writers', 'html4css1 writer')
+
+ def __init__(self):
+ html4css1.Writer.__init__(self)
+ self.translator_class = S5HTMLTranslator
+
+
+class S5HTMLTranslator(html4css1.HTMLTranslator):
+
+ doctype = (
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
+ ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n')
+
+ s5_stylesheet_template = """\
+<!-- configuration parameters -->
+<meta name="defaultView" content="slideshow" />
+<meta name="controlVis" content="hidden" />
+<!-- style sheet links -->
+<script src="%(path)s/slides.js" type="text/javascript"></script>
+<link rel="stylesheet" href="%(path)s/slides.css"
+ type="text/css" media="projection" id="slideProj" />
+<link rel="stylesheet" href="%(path)s/outline.css"
+ type="text/css" media="screen" id="outlineStyle" />
+<link rel="stylesheet" href="%(path)s/print.css"
+ type="text/css" media="print" id="slidePrint" />
+<link rel="stylesheet" href="%(path)s/opera.css"
+ type="text/css" media="projection" id="operaFix" />\n"""
+ # The script element must go in front of the link elements to
+ # avoid a flash of unstyled content (FOUC), reproducible with
+ # Firefox.
+
+ disable_current_slide = """
+<style type="text/css">
+#currentSlide {display: none;}
+</style>\n"""
+
+ layout_template = """\
+<div class="layout">
+<div id="controls"></div>
+<div id="currentSlide"></div>
+<div id="header">
+%(header)s
+</div>
+<div id="footer">
+%(title)s%(footer)s
+</div>
+</div>\n"""
+# <div class="topleft"></div>
+# <div class="topright"></div>
+# <div class="bottomleft"></div>
+# <div class="bottomright"></div>
+
+ default_theme = 'default'
+ """Name of the default theme."""
+
+ base_theme_file = '__base__'
+ """Name of the file containing the name of the base theme."""
+
+ direct_theme_files = (
+ 'slides.css', 'outline.css', 'print.css', 'opera.css', 'slides.js')
+ """Names of theme files directly linked to in the output HTML"""
+
+ indirect_theme_files = (
+ 's5-core.css', 'framing.css', 'pretty.css', 'blank.gif', 'iepngfix.htc')
+ """Names of files used indirectly; imported or used by files in
+ `direct_theme_files`."""
+
+ required_theme_files = indirect_theme_files + direct_theme_files
+ """Names of mandatory theme files."""
+
+ def __init__(self, *args):
+ html4css1.HTMLTranslator.__init__(self, *args)
+ #insert S5-specific stylesheet and script stuff:
+ self.theme_file_path = None
+ self.setup_theme()
+ self.stylesheet.append(self.s5_stylesheet_template
+ % {'path': self.theme_file_path})
+ if not self.document.settings.current_slide:
+ self.stylesheet.append(self.disable_current_slide)
+ self.add_meta('<meta name="version" content="S5 1.1" />\n')
+ self.s5_footer = []
+ self.s5_header = []
+ self.section_count = 0
+ self.theme_files_copied = None
+
+ def setup_theme(self):
+ if self.document.settings.theme:
+ self.copy_theme()
+ elif self.document.settings.theme_url:
+ self.theme_file_path = self.document.settings.theme_url
+ else:
+ raise docutils.ApplicationError(
+ 'No theme specified for S5/HTML writer.')
+
+ def copy_theme(self):
+ """
+ Locate & copy theme files.
+
+ A theme may be explicitly based on another theme via a '__base__'
+ file. The default base theme is 'default'. Files are accumulated
+ from the specified theme, any base themes, and 'default'.
+ """
+ settings = self.document.settings
+ path = find_theme(settings.theme)
+ theme_paths = [path]
+ self.theme_files_copied = {}
+ required_files_copied = {}
+ # This is a link (URL) in HTML, so we use "/", not os.sep:
+ self.theme_file_path = '%s/%s' % ('ui', settings.theme)
+ if settings._destination:
+ dest = os.path.join(
+ os.path.dirname(settings._destination), 'ui', settings.theme)
+ if not os.path.isdir(dest):
+ os.makedirs(dest)
+ else:
+ # no destination, so we can't copy the theme
+ return
+ default = 0
+ while path:
+ for f in os.listdir(path): # copy all files from each theme
+ if f == self.base_theme_file:
+ continue # ... except the "__base__" file
+ if ( self.copy_file(f, path, dest)
+ and f in self.required_theme_files):
+ required_files_copied[f] = 1
+ if default:
+ break # "default" theme has no base theme
+ # Find the "__base__" file in theme directory:
+ base_theme_file = os.path.join(path, self.base_theme_file)
+ # If it exists, read it and record the theme path:
+ if os.path.isfile(base_theme_file):
+ lines = open(base_theme_file).readlines()
+ for line in lines:
+ line = line.strip()
+ if line and not line.startswith('#'):
+ path = find_theme(line)
+ if path in theme_paths: # check for duplicates (cycles)
+ path = None # if found, use default base
+ else:
+ theme_paths.append(path)
+ break
+ else: # no theme name found
+ path = None # use default base
+ else: # no base theme file found
+ path = None # use default base
+ if not path:
+ path = find_theme(self.default_theme)
+ theme_paths.append(path)
+ default = 1
+ if len(required_files_copied) != len(self.required_theme_files):
+ # Some required files weren't found & couldn't be copied.
+ required = list(self.required_theme_files)
+ for f in required_files_copied.keys():
+ required.remove(f)
+ raise docutils.ApplicationError(
+ 'Theme files not found: %s'
+ % ', '.join(['%r' % f for f in required]))
+
+ files_to_skip_pattern = re.compile(r'~$|\.bak$|#$|\.cvsignore$')
+
+ def copy_file(self, name, source_dir, dest_dir):
+ """
+ Copy file `name` from `source_dir` to `dest_dir`.
+ Return 1 if the file exists in either `source_dir` or `dest_dir`.
+ """
+ source = os.path.join(source_dir, name)
+ dest = os.path.join(dest_dir, name)
+ if self.theme_files_copied.has_key(dest):
+ return 1
+ else:
+ self.theme_files_copied[dest] = 1
+ if os.path.isfile(source):
+ if self.files_to_skip_pattern.search(source):
+ return None
+ settings = self.document.settings
+ if os.path.exists(dest) and not settings.overwrite_theme_files:
+ settings.record_dependencies.add(dest)
+ else:
+ src_file = open(source, 'rb')
+ src_data = src_file.read()
+ src_file.close()
+ dest_file = open(dest, 'wb')
+ dest_dir = dest_dir.replace(os.sep, '/')
+ dest_file.write(src_data.replace(
+ 'ui/default', dest_dir[dest_dir.rfind('ui/'):]))
+ dest_file.close()
+ settings.record_dependencies.add(source)
+ return 1
+ if os.path.isfile(dest):
+ return 1
+
+ def depart_document(self, node):
+ header = ''.join(self.s5_header)
+ footer = ''.join(self.s5_footer)
+ title = ''.join(self.html_title).replace('<h1 class="title">', '<h1>')
+ layout = self.layout_template % {'header': header,
+ 'title': title,
+ 'footer': footer}
+ self.fragment.extend(self.body)
+ self.body_prefix.extend(layout)
+ self.body_prefix.append('<div class="presentation">\n')
+ self.body_prefix.append(
+ self.starttag({'classes': ['slide'], 'ids': ['slide0']}, 'div'))
+ if not self.section_count:
+ self.body.append('</div>\n')
+ self.body_suffix.insert(0, '</div>\n')
+ # skip content-type meta tag with interpolated charset value:
+ self.html_head.extend(self.head[1:])
+ self.html_body.extend(self.body_prefix[1:] + self.body_pre_docinfo
+ + self.docinfo + self.body
+ + self.body_suffix[:-1])
+
+ def depart_footer(self, node):
+ start = self.context.pop()
+ self.s5_footer.append('<h2>')
+ self.s5_footer.extend(self.body[start:])
+ self.s5_footer.append('</h2>')
+ del self.body[start:]
+
+ def depart_header(self, node):
+ start = self.context.pop()
+ header = ['<div id="header">\n']
+ header.extend(self.body[start:])
+ header.append('\n</div>\n')
+ del self.body[start:]
+ self.s5_header.extend(header)
+
+ def visit_section(self, node):
+ if not self.section_count:
+ self.body.append('\n</div>\n')
+ self.section_count += 1
+ self.section_level += 1
+ if self.section_level > 1:
+ # dummy for matching div's
+ self.body.append(self.starttag(node, 'div', CLASS='section'))
+ else:
+ self.body.append(self.starttag(node, 'div', CLASS='slide'))
+
+ def visit_subtitle(self, node):
+ if isinstance(node.parent, nodes.section):
+ level = self.section_level + self.initial_header_level - 1
+ if level == 1:
+ level = 2
+ tag = 'h%s' % level
+ self.body.append(self.starttag(node, tag, ''))
+ self.context.append('</%s>\n' % tag)
+ else:
+ html4css1.HTMLTranslator.visit_subtitle(self, node)
+
+ def visit_title(self, node, move_ids=0):
+ html4css1.HTMLTranslator.visit_title(self, node, move_ids=move_ids)
diff --git a/docutils/writers/s5_html/themes/README.txt b/docutils/writers/s5_html/themes/README.txt
new file mode 100644
index 000000000..2e01b51ee
--- /dev/null
+++ b/docutils/writers/s5_html/themes/README.txt
@@ -0,0 +1,6 @@
+Except where otherwise noted (default/iepngfix.htc), all files in this
+directory have been released into the Public Domain.
+
+These files are based on files from S5 1.1, released into the Public
+Domain by Eric Meyer. For further details, please see
+http://www.meyerweb.com/eric/tools/s5/credits.html.
diff --git a/docutils/writers/s5_html/themes/big-black/__base__ b/docutils/writers/s5_html/themes/big-black/__base__
new file mode 100644
index 000000000..f08be9ad5
--- /dev/null
+++ b/docutils/writers/s5_html/themes/big-black/__base__
@@ -0,0 +1,2 @@
+# base theme of this theme:
+big-white
diff --git a/docutils/writers/s5_html/themes/big-black/framing.css b/docutils/writers/s5_html/themes/big-black/framing.css
new file mode 100644
index 000000000..5a31113fb
--- /dev/null
+++ b/docutils/writers/s5_html/themes/big-black/framing.css
@@ -0,0 +1,25 @@
+/* The following styles size, place, and layer the slide components.
+ Edit these if you want to change the overall slide layout.
+ The commented lines can be uncommented (and modified, if necessary)
+ to help you with the rearrangement process. */
+
+/* target = 1024x768 */
+
+div#header, div#footer, .slide {width: 100%; top: 0; left: 0;}
+div#header {top: 0; z-index: 1;}
+div#footer {display:none;}
+.slide {top: 0; width: 92%; padding: 0.1em 4% 4%; z-index: 2;}
+/* list-style: none;} */
+div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0;}
+#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em;
+ z-index: 10;}
+html>body #currentSlide {position: fixed;}
+
+/*
+div#header {background: #FCC;}
+div#footer {background: #CCF;}
+div#controls {background: #BBD;}
+div#currentSlide {background: #FFC;}
+*/
diff --git a/docutils/writers/s5_html/themes/big-black/pretty.css b/docutils/writers/s5_html/themes/big-black/pretty.css
new file mode 100644
index 000000000..82bcc9dc4
--- /dev/null
+++ b/docutils/writers/s5_html/themes/big-black/pretty.css
@@ -0,0 +1,109 @@
+/* This file has been placed in the public domain. */
+/* Following are the presentation styles -- edit away! */
+
+html, body {margin: 0; padding: 0;}
+body {background: black; color: white;}
+:link, :visited {text-decoration: none; color: cyan;}
+#controls :active {color: #888 !important;}
+#controls :focus {outline: 1px dotted #CCC;}
+
+blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;}
+blockquote p {margin: 0;}
+
+kbd {font-weight: bold; font-size: 1em;}
+sup {font-size: smaller; line-height: 1px;}
+
+.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;}
+.slide ul ul li {list-style: square;}
+.slide img.leader {display: block; margin: 0 auto;}
+.slide tt {font-size: 90%;}
+
+.slide {font-size: 3em; font-family: sans-serif; font-weight: bold;}
+.slide h1 {padding-top: 0; z-index: 1; margin: 0; font-size: 120%;}
+.slide h2 {font-size: 110%;}
+.slide h3 {font-size: 105%;}
+h1 abbr {font-variant: small-caps;}
+
+div#controls {position: absolute; left: 50%; bottom: 0;
+ width: 50%; text-align: right; font: bold 0.9em sans-serif;}
+html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0; padding: 0;}
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+ border: none; color: #888; cursor: pointer;}
+#controls #navList {height: 1em;}
+#controls #navList #jumplist {position: absolute; bottom: 0; right: 0;
+ background: black; color: #CCC;}
+
+#currentSlide {text-align: center; font-size: 0.5em; color: #AAA;
+ font-family: sans-serif; font-weight: bold;}
+
+#slide0 h1 {position: static; margin: 0 0 0.5em; padding-top: 0.3em; top: 0;
+ font-size: 150%; white-space: normal; background: transparent;}
+#slide0 h2 {font: 110%; font-style: italic; color: gray;}
+#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;}
+#slide0 h4 {margin-top: 0; font-size: 1em;}
+
+ul.urls {list-style: none; display: inline; margin: 0;}
+.urls li {display: inline; margin: 0;}
+.external {border-bottom: 1px dotted gray;}
+html>body .external {border-bottom: none;}
+.external:after {content: " \274F"; font-size: smaller; color: #FCC;}
+
+.incremental, .incremental *, .incremental *:after {
+ color: black; visibility: visible; border: 0;}
+img.incremental {visibility: hidden;}
+.slide .current {color: lime;}
+
+.slide-display {display: inline ! important;}
+
+.huge {font-size: 150%;}
+.big {font-size: 120%;}
+.small {font-size: 75%;}
+.tiny {font-size: 50%;}
+.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;}
+.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;}
+
+.maroon {color: maroon;}
+.red {color: red;}
+.magenta {color: magenta;}
+.fuchsia {color: fuchsia;}
+.pink {color: #FAA;}
+.orange {color: orange;}
+.yellow {color: yellow;}
+.lime {color: lime;}
+.green {color: green;}
+.olive {color: olive;}
+.teal {color: teal;}
+.cyan {color: cyan;}
+.aqua {color: aqua;}
+.blue {color: blue;}
+.navy {color: navy;}
+.purple {color: purple;}
+.black {color: black;}
+.gray {color: gray;}
+.silver {color: silver;}
+.white {color: white;}
+
+.left {text-align: left ! important;}
+.center {text-align: center ! important;}
+.right {text-align: right ! important;}
+
+.animation {position: relative; margin: 1em 0; padding: 0;}
+.animation img {position: absolute;}
+
+/* Docutils-specific overrides */
+
+.slide table.docinfo {margin: 0.5em 0 0.5em 1em;}
+
+div.sidebar {background-color: black;}
+
+pre.literal-block, pre.doctest-block {background-color: black;}
+
+tt.docutils {background-color: black;}
+
+/* diagnostics */
+/*
+li:after {content: " [" attr(class) "]"; color: #F88;}
+div:before {content: "[" attr(class) "]"; color: #F88;}
+*/
diff --git a/docutils/writers/s5_html/themes/big-white/framing.css b/docutils/writers/s5_html/themes/big-white/framing.css
new file mode 100644
index 000000000..cd343432b
--- /dev/null
+++ b/docutils/writers/s5_html/themes/big-white/framing.css
@@ -0,0 +1,24 @@
+/* This file has been placed in the public domain. */
+/* The following styles size, place, and layer the slide components.
+ Edit these if you want to change the overall slide layout.
+ The commented lines can be uncommented (and modified, if necessary)
+ to help you with the rearrangement process. */
+
+/* target = 1024x768 */
+
+div#header, div#footer, .slide {width: 100%; top: 0; left: 0;}
+div#footer {display:none;}
+.slide {top: 0; width: 92%; padding: 0.25em 4% 4%; z-index: 2;}
+div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0;}
+#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em;
+ z-index: 10;}
+html>body #currentSlide {position: fixed;}
+
+/*
+div#header {background: #FCC;}
+div#footer {background: #CCF;}
+div#controls {background: #BBD;}
+div#currentSlide {background: #FFC;}
+*/
diff --git a/docutils/writers/s5_html/themes/big-white/pretty.css b/docutils/writers/s5_html/themes/big-white/pretty.css
new file mode 100644
index 000000000..c5e2fcf97
--- /dev/null
+++ b/docutils/writers/s5_html/themes/big-white/pretty.css
@@ -0,0 +1,107 @@
+/* This file has been placed in the public domain. */
+/* Following are the presentation styles -- edit away! */
+
+html, body {margin: 0; padding: 0;}
+body {background: white; color: black;}
+:link, :visited {text-decoration: none; color: #00C;}
+#controls :active {color: #88A !important;}
+#controls :focus {outline: 1px dotted #227;}
+
+blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;}
+blockquote p {margin: 0;}
+
+kbd {font-weight: bold; font-size: 1em;}
+sup {font-size: smaller; line-height: 1px;}
+
+.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;}
+.slide ul ul li {list-style: square;}
+.slide img.leader {display: block; margin: 0 auto;}
+.slide tt {font-size: 90%;}
+
+.slide {font-size: 3em; font-family: sans-serif; font-weight: bold;}
+.slide h1 {padding-top: 0; z-index: 1; margin: 0; font-size: 120%;}
+.slide h2 {font-size: 110%;}
+.slide h3 {font-size: 105%;}
+h1 abbr {font-variant: small-caps;}
+
+div#controls {position: absolute; left: 50%; bottom: 0;
+ width: 50%; text-align: right; font: bold 0.9em sans-serif;}
+html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0; padding: 0;}
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+ border: none; color: #005; cursor: pointer;}
+#controls #navList {height: 1em;}
+#controls #navList #jumplist {position: absolute; bottom: 0; right: 0;
+ background: #DDD; color: #227;}
+
+#currentSlide {text-align: center; font-size: 0.5em; color: #444;
+ font-family: sans-serif; font-weight: bold;}
+
+#slide0 h1 {position: static; margin: 0 0 0.5em; padding-top: 0.3em; top: 0;
+ font-size: 150%; white-space: normal; background: transparent;}
+#slide0 h2 {font: 110%; font-style: italic; color: gray;}
+#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;}
+#slide0 h4 {margin-top: 0; font-size: 1em;}
+
+ul.urls {list-style: none; display: inline; margin: 0;}
+.urls li {display: inline; margin: 0;}
+.external {border-bottom: 1px dotted gray;}
+html>body .external {border-bottom: none;}
+.external:after {content: " \274F"; font-size: smaller; color: #77B;}
+
+.incremental, .incremental *, .incremental *:after {
+ color: white; visibility: visible; border: 0;}
+img.incremental {visibility: hidden;}
+.slide .current {color: green;}
+
+.slide-display {display: inline ! important;}
+
+.huge {font-size: 150%;}
+.big {font-size: 120%;}
+.small {font-size: 75%;}
+.tiny {font-size: 50%;}
+.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;}
+.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;}
+
+.maroon {color: maroon;}
+.red {color: red;}
+.magenta {color: magenta;}
+.fuchsia {color: fuchsia;}
+.pink {color: #FAA;}
+.orange {color: orange;}
+.yellow {color: yellow;}
+.lime {color: lime;}
+.green {color: green;}
+.olive {color: olive;}
+.teal {color: teal;}
+.cyan {color: cyan;}
+.aqua {color: aqua;}
+.blue {color: blue;}
+.navy {color: navy;}
+.purple {color: purple;}
+.black {color: black;}
+.gray {color: gray;}
+.silver {color: silver;}
+.white {color: white;}
+
+.left {text-align: left ! important;}
+.center {text-align: center ! important;}
+.right {text-align: right ! important;}
+
+.animation {position: relative; margin: 1em 0; padding: 0;}
+.animation img {position: absolute;}
+
+/* Docutils-specific overrides */
+
+.slide table.docinfo {margin: 0.5em 0 0.5em 1em;}
+
+pre.literal-block, pre.doctest-block {background-color: white;}
+
+tt.docutils {background-color: white;}
+
+/* diagnostics */
+/*
+li:after {content: " [" attr(class) "]"; color: #F88;}
+div:before {content: "[" attr(class) "]"; color: #F88;}
+*/
diff --git a/docutils/writers/s5_html/themes/default/blank.gif b/docutils/writers/s5_html/themes/default/blank.gif
new file mode 100644
index 000000000..75b945d25
--- /dev/null
+++ b/docutils/writers/s5_html/themes/default/blank.gif
Binary files differ
diff --git a/docutils/writers/s5_html/themes/default/framing.css b/docutils/writers/s5_html/themes/default/framing.css
new file mode 100644
index 000000000..c4727f303
--- /dev/null
+++ b/docutils/writers/s5_html/themes/default/framing.css
@@ -0,0 +1,25 @@
+/* This file has been placed in the public domain. */
+/* The following styles size, place, and layer the slide components.
+ Edit these if you want to change the overall slide layout.
+ The commented lines can be uncommented (and modified, if necessary)
+ to help you with the rearrangement process. */
+
+/* target = 1024x768 */
+
+div#header, div#footer, .slide {width: 100%; top: 0; left: 0;}
+div#header {position: fixed; top: 0; height: 3em; z-index: 1;}
+div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;}
+.slide {top: 0; width: 92%; padding: 2.5em 4% 4%; z-index: 2;}
+div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0;}
+#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em;
+ z-index: 10;}
+html>body #currentSlide {position: fixed;}
+
+/*
+div#header {background: #FCC;}
+div#footer {background: #CCF;}
+div#controls {background: #BBD;}
+div#currentSlide {background: #FFC;}
+*/
diff --git a/docutils/writers/s5_html/themes/default/iepngfix.htc b/docutils/writers/s5_html/themes/default/iepngfix.htc
new file mode 100644
index 000000000..9f3d628b5
--- /dev/null
+++ b/docutils/writers/s5_html/themes/default/iepngfix.htc
@@ -0,0 +1,42 @@
+<public:component>
+<public:attach event="onpropertychange" onevent="doFix()" />
+
+<script>
+
+// IE5.5+ PNG Alpha Fix v1.0 by Angus Turnbull http://www.twinhelix.com
+// Free usage permitted as long as this notice remains intact.
+
+// This must be a path to a blank image. That's all the configuration you need here.
+var blankImg = 'ui/default/blank.gif';
+
+var f = 'DXImageTransform.Microsoft.AlphaImageLoader';
+
+function filt(s, m) {
+ if (filters[f]) {
+ filters[f].enabled = s ? true : false;
+ if (s) with (filters[f]) { src = s; sizingMethod = m }
+ } else if (s) style.filter = 'progid:'+f+'(src="'+s+'",sizingMethod="'+m+'")';
+}
+
+function doFix() {
+ if ((parseFloat(navigator.userAgent.match(/MSIE (\S+)/)[1]) < 5.5) ||
+ (event && !/(background|src)/.test(event.propertyName))) return;
+
+ if (tagName == 'IMG') {
+ if ((/\.png$/i).test(src)) {
+ filt(src, 'image'); // was 'scale'
+ src = blankImg;
+ } else if (src.indexOf(blankImg) < 0) filt();
+ } else if (style.backgroundImage) {
+ if (style.backgroundImage.match(/^url[("']+(.*\.png)[)"']+$/i)) {
+ var s = RegExp.$1;
+ style.backgroundImage = '';
+ filt(s, 'crop');
+ } else filt();
+ }
+}
+
+doFix();
+
+</script>
+</public:component> \ No newline at end of file
diff --git a/docutils/writers/s5_html/themes/default/opera.css b/docutils/writers/s5_html/themes/default/opera.css
new file mode 100644
index 000000000..c9d1148be
--- /dev/null
+++ b/docutils/writers/s5_html/themes/default/opera.css
@@ -0,0 +1,8 @@
+/* This file has been placed in the public domain. */
+/* DO NOT CHANGE THESE unless you really want to break Opera Show */
+.slide {
+ visibility: visible !important;
+ position: static !important;
+ page-break-before: always;
+}
+#slide0 {page-break-before: avoid;}
diff --git a/docutils/writers/s5_html/themes/default/outline.css b/docutils/writers/s5_html/themes/default/outline.css
new file mode 100644
index 000000000..fa767e227
--- /dev/null
+++ b/docutils/writers/s5_html/themes/default/outline.css
@@ -0,0 +1,16 @@
+/* This file has been placed in the public domain. */
+/* Don't change this unless you want the layout stuff to show up in the
+ outline view! */
+
+.layout div, #footer *, #controlForm * {display: none;}
+#footer, #controls, #controlForm, #navLinks, #toggle {
+ display: block; visibility: visible; margin: 0; padding: 0;}
+#toggle {float: right; padding: 0.5em;}
+html>body #toggle {position: fixed; top: 0; right: 0;}
+
+/* making the outline look pretty-ish */
+
+#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;}
+#toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;}
+
+.outline {display: inline ! important;}
diff --git a/docutils/writers/s5_html/themes/default/pretty.css b/docutils/writers/s5_html/themes/default/pretty.css
new file mode 100644
index 000000000..1cede72d4
--- /dev/null
+++ b/docutils/writers/s5_html/themes/default/pretty.css
@@ -0,0 +1,120 @@
+/* This file has been placed in the public domain. */
+/* Following are the presentation styles -- edit away! */
+
+html, body {margin: 0; padding: 0;}
+body {background: white; color: black;}
+/* Replace the background style above with the style below (and again for
+ div#header) for a graphic: */
+/* background: white url(bodybg.gif) -16px 0 no-repeat; */
+:link, :visited {text-decoration: none; color: #00C;}
+#controls :active {color: #88A !important;}
+#controls :focus {outline: 1px dotted #227;}
+h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;}
+
+blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;}
+blockquote p {margin: 0;}
+
+kbd {font-weight: bold; font-size: 1em;}
+sup {font-size: smaller; line-height: 1px;}
+
+.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;}
+.slide ul ul li {list-style: square;}
+.slide img.leader {display: block; margin: 0 auto;}
+.slide tt {font-size: 90%;}
+
+div#header, div#footer {background: #005; color: #AAB; font-family: sans-serif;}
+/* background: #005 url(bodybg.gif) -16px 0 no-repeat; */
+div#footer {font-size: 0.5em; font-weight: bold; padding: 1em 0;}
+#footer h1 {display: block; padding: 0 1em;}
+#footer h2 {display: block; padding: 0.8em 1em 0;}
+
+.slide {font-size: 1.2em;}
+.slide h1 {position: absolute; top: 0.45em; z-index: 1;
+ margin: 0; padding-left: 0.7em; white-space: nowrap;
+ font: bold 150% sans-serif; color: #DDE; background: #005;}
+.slide h2 {font: bold 120%/1em sans-serif; padding-top: 0.5em;}
+.slide h3 {font: bold 100% sans-serif; padding-top: 0.5em;}
+h1 abbr {font-variant: small-caps;}
+
+div#controls {position: absolute; left: 50%; bottom: 0;
+ width: 50%; text-align: right; font: bold 0.9em sans-serif;}
+html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0; padding: 0;}
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+ background: #005; border: none; color: #779; cursor: pointer;}
+#controls #navList {height: 1em;}
+#controls #navList #jumplist {position: absolute; bottom: 0; right: 0;
+ background: #DDD; color: #227;}
+
+#currentSlide {text-align: center; font-size: 0.5em; color: #449;
+ font-family: sans-serif; font-weight: bold;}
+
+#slide0 {padding-top: 1.5em}
+#slide0 h1 {position: static; margin: 1em 0 0; padding: 0; color: #000;
+ font: bold 2em sans-serif; white-space: normal; background: transparent;}
+#slide0 h2 {font: bold italic 1em sans-serif; margin: 0.25em;}
+#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;}
+#slide0 h4 {margin-top: 0; font-size: 1em;}
+
+ul.urls {list-style: none; display: inline; margin: 0;}
+.urls li {display: inline; margin: 0;}
+.external {border-bottom: 1px dotted gray;}
+html>body .external {border-bottom: none;}
+.external:after {content: " \274F"; font-size: smaller; color: #77B;}
+
+.incremental, .incremental *, .incremental *:after {visibility: visible;
+ color: white; border: 0;}
+img.incremental {visibility: hidden;}
+.slide .current {color: green;}
+
+.slide-display {display: inline ! important;}
+
+.huge {font-family: sans-serif; font-weight: bold; font-size: 150%;}
+.big {font-family: sans-serif; font-weight: bold; font-size: 120%;}
+.small {font-size: 75%;}
+.tiny {font-size: 50%;}
+.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;}
+.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;}
+
+.maroon {color: maroon;}
+.red {color: red;}
+.magenta {color: magenta;}
+.fuchsia {color: fuchsia;}
+.pink {color: #FAA;}
+.orange {color: orange;}
+.yellow {color: yellow;}
+.lime {color: lime;}
+.green {color: green;}
+.olive {color: olive;}
+.teal {color: teal;}
+.cyan {color: cyan;}
+.aqua {color: aqua;}
+.blue {color: blue;}
+.navy {color: navy;}
+.purple {color: purple;}
+.black {color: black;}
+.gray {color: gray;}
+.silver {color: silver;}
+.white {color: white;}
+
+.left {text-align: left ! important;}
+.center {text-align: center ! important;}
+.right {text-align: right ! important;}
+
+.animation {position: relative; margin: 1em 0; padding: 0;}
+.animation img {position: absolute;}
+
+/* Docutils-specific overrides */
+
+.slide table.docinfo {margin: 1em 0 0.5em 2em;}
+
+pre.literal-block, pre.doctest-block {background-color: white;}
+
+tt.docutils {background-color: white;}
+
+/* diagnostics */
+/*
+li:after {content: " [" attr(class) "]"; color: #F88;}
+div:before {content: "[" attr(class) "]"; color: #F88;}
+*/
diff --git a/docutils/writers/s5_html/themes/default/print.css b/docutils/writers/s5_html/themes/default/print.css
new file mode 100644
index 000000000..9d057cc8c
--- /dev/null
+++ b/docutils/writers/s5_html/themes/default/print.css
@@ -0,0 +1,24 @@
+/* This file has been placed in the public domain. */
+/* The following rule is necessary to have all slides appear in print!
+ DO NOT REMOVE IT! */
+.slide, ul {page-break-inside: avoid; visibility: visible !important;}
+h1 {page-break-after: avoid;}
+
+body {font-size: 12pt; background: white;}
+* {color: black;}
+
+#slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;}
+#slide0 h3 {margin: 0; padding: 0;}
+#slide0 h4 {margin: 0 0 0.5em; padding: 0;}
+#slide0 {margin-bottom: 3em;}
+
+#header {display: none;}
+#footer h1 {margin: 0; border-bottom: 1px solid; color: gray;
+ font-style: italic;}
+#footer h2, #controls {display: none;}
+
+.print {display: inline ! important;}
+
+/* The following rule keeps the layout stuff out of print.
+ Remove at your own risk! */
+.layout, .layout * {display: none !important;}
diff --git a/docutils/writers/s5_html/themes/default/s5-core.css b/docutils/writers/s5_html/themes/default/s5-core.css
new file mode 100644
index 000000000..6965f5e8f
--- /dev/null
+++ b/docutils/writers/s5_html/themes/default/s5-core.css
@@ -0,0 +1,11 @@
+/* This file has been placed in the public domain. */
+/* Do not edit or override these styles!
+ The system will likely break if you do. */
+
+div#header, div#footer, div#controls, .slide {position: absolute;}
+html>body div#header, html>body div#footer,
+ html>body div#controls, html>body .slide {position: fixed;}
+.handout {display: none;}
+.layout {display: block;}
+.slide, .hideme, .incremental {visibility: hidden;}
+#slide0 {visibility: visible;}
diff --git a/docutils/writers/s5_html/themes/default/slides.css b/docutils/writers/s5_html/themes/default/slides.css
new file mode 100644
index 000000000..82bdc0ee0
--- /dev/null
+++ b/docutils/writers/s5_html/themes/default/slides.css
@@ -0,0 +1,10 @@
+/* This file has been placed in the public domain. */
+
+/* required to make the slide show run at all */
+@import url(s5-core.css);
+
+/* sets basic placement and size of slide components */
+@import url(framing.css);
+
+/* styles that make the slides look good */
+@import url(pretty.css);
diff --git a/docutils/writers/s5_html/themes/default/slides.js b/docutils/writers/s5_html/themes/default/slides.js
new file mode 100644
index 000000000..81e04e5d4
--- /dev/null
+++ b/docutils/writers/s5_html/themes/default/slides.js
@@ -0,0 +1,558 @@
+// S5 v1.1 slides.js -- released into the Public Domain
+// Modified for Docutils (http://docutils.sf.net) by David Goodger
+//
+// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for
+// information about all the wonderful and talented contributors to this code!
+
+var undef;
+var slideCSS = '';
+var snum = 0;
+var smax = 1;
+var slideIDs = new Array();
+var incpos = 0;
+var number = undef;
+var s5mode = true;
+var defaultView = 'slideshow';
+var controlVis = 'visible';
+
+var isIE = navigator.appName == 'Microsoft Internet Explorer' ? 1 : 0;
+var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0;
+var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0;
+
+function hasClass(object, className) {
+ if (!object.className) return false;
+ return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1);
+}
+
+function hasValue(object, value) {
+ if (!object) return false;
+ return (object.search('(^|\\s)' + value + '(\\s|$)') != -1);
+}
+
+function removeClass(object,className) {
+ if (!object) return;
+ object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2);
+}
+
+function addClass(object,className) {
+ if (!object || hasClass(object, className)) return;
+ if (object.className) {
+ object.className += ' '+className;
+ } else {
+ object.className = className;
+ }
+}
+
+function GetElementsWithClassName(elementName,className) {
+ var allElements = document.getElementsByTagName(elementName);
+ var elemColl = new Array();
+ for (var i = 0; i< allElements.length; i++) {
+ if (hasClass(allElements[i], className)) {
+ elemColl[elemColl.length] = allElements[i];
+ }
+ }
+ return elemColl;
+}
+
+function isParentOrSelf(element, id) {
+ if (element == null || element.nodeName=='BODY') return false;
+ else if (element.id == id) return true;
+ else return isParentOrSelf(element.parentNode, id);
+}
+
+function nodeValue(node) {
+ var result = "";
+ if (node.nodeType == 1) {
+ var children = node.childNodes;
+ for (var i = 0; i < children.length; ++i) {
+ result += nodeValue(children[i]);
+ }
+ }
+ else if (node.nodeType == 3) {
+ result = node.nodeValue;
+ }
+ return(result);
+}
+
+function slideLabel() {
+ var slideColl = GetElementsWithClassName('*','slide');
+ var list = document.getElementById('jumplist');
+ smax = slideColl.length;
+ for (var n = 0; n < smax; n++) {
+ var obj = slideColl[n];
+
+ var did = 'slide' + n.toString();
+ if (obj.getAttribute('id')) {
+ slideIDs[n] = obj.getAttribute('id');
+ }
+ else {
+ obj.setAttribute('id',did);
+ slideIDs[n] = did;
+ }
+ if (isOp) continue;
+
+ var otext = '';
+ var menu = obj.firstChild;
+ if (!menu) continue; // to cope with empty slides
+ while (menu && menu.nodeType == 3) {
+ menu = menu.nextSibling;
+ }
+ if (!menu) continue; // to cope with slides with only text nodes
+
+ var menunodes = menu.childNodes;
+ for (var o = 0; o < menunodes.length; o++) {
+ otext += nodeValue(menunodes[o]);
+ }
+ list.options[list.length] = new Option(n + ' : ' + otext, n);
+ }
+}
+
+function currentSlide() {
+ var cs;
+ var footer_nodes;
+ var vis = 'visible';
+ if (document.getElementById) {
+ cs = document.getElementById('currentSlide');
+ footer_nodes = document.getElementById('footer').childNodes;
+ } else {
+ cs = document.currentSlide;
+ footer = document.footer.childNodes;
+ }
+ cs.innerHTML = '<span id="csHere">' + snum + '<\/span> ' +
+ '<span id="csSep">\/<\/span> ' +
+ '<span id="csTotal">' + (smax-1) + '<\/span>';
+ if (snum == 0) {
+ vis = 'hidden';
+ }
+ cs.style.visibility = vis;
+ for (var i = 0; i < footer_nodes.length; i++) {
+ if (footer_nodes[i].nodeType == 1) {
+ footer_nodes[i].style.visibility = vis;
+ }
+ }
+}
+
+function go(step) {
+ if (document.getElementById('slideProj').disabled || step == 0) return;
+ var jl = document.getElementById('jumplist');
+ var cid = slideIDs[snum];
+ var ce = document.getElementById(cid);
+ if (incrementals[snum].length > 0) {
+ for (var i = 0; i < incrementals[snum].length; i++) {
+ removeClass(incrementals[snum][i], 'current');
+ removeClass(incrementals[snum][i], 'incremental');
+ }
+ }
+ if (step != 'j') {
+ snum += step;
+ lmax = smax - 1;
+ if (snum > lmax) snum = lmax;
+ if (snum < 0) snum = 0;
+ } else
+ snum = parseInt(jl.value);
+ var nid = slideIDs[snum];
+ var ne = document.getElementById(nid);
+ if (!ne) {
+ ne = document.getElementById(slideIDs[0]);
+ snum = 0;
+ }
+ if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;}
+ if (incrementals[snum].length > 0 && incpos == 0) {
+ for (var i = 0; i < incrementals[snum].length; i++) {
+ if (hasClass(incrementals[snum][i], 'current'))
+ incpos = i + 1;
+ else
+ addClass(incrementals[snum][i], 'incremental');
+ }
+ }
+ if (incrementals[snum].length > 0 && incpos > 0)
+ addClass(incrementals[snum][incpos - 1], 'current');
+ ce.style.visibility = 'hidden';
+ ne.style.visibility = 'visible';
+ jl.selectedIndex = snum;
+ currentSlide();
+ number = 0;
+}
+
+function goTo(target) {
+ if (target >= smax || target == snum) return;
+ go(target - snum);
+}
+
+function subgo(step) {
+ if (step > 0) {
+ removeClass(incrementals[snum][incpos - 1],'current');
+ removeClass(incrementals[snum][incpos], 'incremental');
+ addClass(incrementals[snum][incpos],'current');
+ incpos++;
+ } else {
+ incpos--;
+ removeClass(incrementals[snum][incpos],'current');
+ addClass(incrementals[snum][incpos], 'incremental');
+ addClass(incrementals[snum][incpos - 1],'current');
+ }
+}
+
+function toggle() {
+ var slideColl = GetElementsWithClassName('*','slide');
+ var slides = document.getElementById('slideProj');
+ var outline = document.getElementById('outlineStyle');
+ if (!slides.disabled) {
+ slides.disabled = true;
+ outline.disabled = false;
+ s5mode = false;
+ fontSize('1em');
+ for (var n = 0; n < smax; n++) {
+ var slide = slideColl[n];
+ slide.style.visibility = 'visible';
+ }
+ } else {
+ slides.disabled = false;
+ outline.disabled = true;
+ s5mode = true;
+ fontScale();
+ for (var n = 0; n < smax; n++) {
+ var slide = slideColl[n];
+ slide.style.visibility = 'hidden';
+ }
+ slideColl[snum].style.visibility = 'visible';
+ }
+}
+
+function showHide(action) {
+ var obj = GetElementsWithClassName('*','hideme')[0];
+ switch (action) {
+ case 's': obj.style.visibility = 'visible'; break;
+ case 'h': obj.style.visibility = 'hidden'; break;
+ case 'k':
+ if (obj.style.visibility != 'visible') {
+ obj.style.visibility = 'visible';
+ } else {
+ obj.style.visibility = 'hidden';
+ }
+ break;
+ }
+}
+
+// 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/)
+function keys(key) {
+ if (!key) {
+ key = event;
+ key.which = key.keyCode;
+ }
+ if (key.which == 84) {
+ toggle();
+ return;
+ }
+ if (s5mode) {
+ switch (key.which) {
+ case 10: // return
+ case 13: // enter
+ if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
+ if (key.target && isParentOrSelf(key.target, 'controls')) return;
+ if(number != undef) {
+ goTo(number);
+ break;
+ }
+ case 32: // spacebar
+ case 34: // page down
+ case 39: // rightkey
+ case 40: // downkey
+ if(number != undef) {
+ go(number);
+ } else if (!incrementals[snum] || incpos >= incrementals[snum].length) {
+ go(1);
+ } else {
+ subgo(1);
+ }
+ break;
+ case 33: // page up
+ case 37: // leftkey
+ case 38: // upkey
+ if(number != undef) {
+ go(-1 * number);
+ } else if (!incrementals[snum] || incpos <= 0) {
+ go(-1);
+ } else {
+ subgo(-1);
+ }
+ break;
+ case 36: // home
+ goTo(0);
+ break;
+ case 35: // end
+ goTo(smax-1);
+ break;
+ case 67: // c
+ showHide('k');
+ break;
+ }
+ if (key.which < 48 || key.which > 57) {
+ number = undef;
+ } else {
+ if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
+ if (key.target && isParentOrSelf(key.target, 'controls')) return;
+ number = (((number != undef) ? number : 0) * 10) + (key.which - 48);
+ }
+ }
+ return false;
+}
+
+function clicker(e) {
+ number = undef;
+ var target;
+ if (window.event) {
+ target = window.event.srcElement;
+ e = window.event;
+ } else target = e.target;
+ if (target.href != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target, 'object')) return true;
+ if (!e.which || e.which == 1) {
+ if (!incrementals[snum] || incpos >= incrementals[snum].length) {
+ go(1);
+ } else {
+ subgo(1);
+ }
+ }
+}
+
+function findSlide(hash) {
+ var target = document.getElementById(hash);
+ if (target) {
+ for (var i = 0; i < slideIDs.length; i++) {
+ if (target.id == slideIDs[i]) return i;
+ }
+ }
+ return null;
+}
+
+function slideJump() {
+ if (window.location.hash == null || window.location.hash == '') {
+ currentSlide();
+ return;
+ }
+ if (window.location.hash == null) return;
+ var dest = null;
+ dest = findSlide(window.location.hash.slice(1));
+ if (dest == null) {
+ dest = 0;
+ }
+ go(dest - snum);
+}
+
+function fixLinks() {
+ var thisUri = window.location.href;
+ thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length);
+ var aelements = document.getElementsByTagName('A');
+ for (var i = 0; i < aelements.length; i++) {
+ var a = aelements[i].href;
+ var slideID = a.match('\#.+');
+ if ((slideID) && (slideID[0].slice(0,1) == '#')) {
+ var dest = findSlide(slideID[0].slice(1));
+ if (dest != null) {
+ if (aelements[i].addEventListener) {
+ aelements[i].addEventListener("click", new Function("e",
+ "if (document.getElementById('slideProj').disabled) return;" +
+ "go("+dest+" - snum); " +
+ "if (e.preventDefault) e.preventDefault();"), true);
+ } else if (aelements[i].attachEvent) {
+ aelements[i].attachEvent("onclick", new Function("",
+ "if (document.getElementById('slideProj').disabled) return;" +
+ "go("+dest+" - snum); " +
+ "event.returnValue = false;"));
+ }
+ }
+ }
+ }
+}
+
+function externalLinks() {
+ if (!document.getElementsByTagName) return;
+ var anchors = document.getElementsByTagName('a');
+ for (var i=0; i<anchors.length; i++) {
+ var anchor = anchors[i];
+ if (anchor.getAttribute('href') && hasValue(anchor.rel, 'external')) {
+ anchor.target = '_blank';
+ addClass(anchor,'external');
+ }
+ }
+}
+
+function createControls() {
+ var controlsDiv = document.getElementById("controls");
+ if (!controlsDiv) return;
+ var hider = ' onmouseover="showHide(\'s\');" onmouseout="showHide(\'h\');"';
+ var hideDiv, hideList = '';
+ if (controlVis == 'hidden') {
+ hideDiv = hider;
+ } else {
+ hideList = hider;
+ }
+ controlsDiv.innerHTML = '<form action="#" id="controlForm"' + hideDiv + '>' +
+ '<div id="navLinks">' +
+ '<a accesskey="t" id="toggle" href="javascript:toggle();">&#216;<\/a>' +
+ '<a accesskey="z" id="prev" href="javascript:go(-1);">&laquo;<\/a>' +
+ '<a accesskey="x" id="next" href="javascript:go(1);">&raquo;<\/a>' +
+ '<div id="navList"' + hideList + '><select id="jumplist" onchange="go(\'j\');"><\/select><\/div>' +
+ '<\/div><\/form>';
+ if (controlVis == 'hidden') {
+ var hidden = document.getElementById('navLinks');
+ } else {
+ var hidden = document.getElementById('jumplist');
+ }
+ addClass(hidden,'hideme');
+}
+
+function fontScale() { // causes layout problems in FireFox that get fixed if browser's Reload is used; same may be true of other Gecko-based browsers
+ if (!s5mode) return false;
+ var vScale = 22; // both yield 32 (after rounding) at 1024x768
+ var hScale = 32; // perhaps should auto-calculate based on theme's declared value?
+ if (window.innerHeight) {
+ var vSize = window.innerHeight;
+ var hSize = window.innerWidth;
+ } else if (document.documentElement.clientHeight) {
+ var vSize = document.documentElement.clientHeight;
+ var hSize = document.documentElement.clientWidth;
+ } else if (document.body.clientHeight) {
+ var vSize = document.body.clientHeight;
+ var hSize = document.body.clientWidth;
+ } else {
+ var vSize = 700; // assuming 1024x768, minus chrome and such
+ var hSize = 1024; // these do not account for kiosk mode or Opera Show
+ }
+ var newSize = Math.min(Math.round(vSize/vScale),Math.round(hSize/hScale));
+ fontSize(newSize + 'px');
+ if (isGe) { // hack to counter incremental reflow bugs
+ var obj = document.getElementsByTagName('body')[0];
+ obj.style.display = 'none';
+ obj.style.display = 'block';
+ }
+}
+
+function fontSize(value) {
+ if (!(s5ss = document.getElementById('s5ss'))) {
+ if (!isIE) {
+ document.getElementsByTagName('head')[0].appendChild(s5ss = document.createElement('style'));
+ s5ss.setAttribute('media','screen, projection');
+ s5ss.setAttribute('id','s5ss');
+ } else {
+ document.createStyleSheet();
+ document.s5ss = document.styleSheets[document.styleSheets.length - 1];
+ }
+ }
+ if (!isIE) {
+ while (s5ss.lastChild) s5ss.removeChild(s5ss.lastChild);
+ s5ss.appendChild(document.createTextNode('body {font-size: ' + value + ' !important;}'));
+ } else {
+ document.s5ss.addRule('body','font-size: ' + value + ' !important;');
+ }
+}
+
+function notOperaFix() {
+ slideCSS = document.getElementById('slideProj').href;
+ var slides = document.getElementById('slideProj');
+ var outline = document.getElementById('outlineStyle');
+ slides.setAttribute('media','screen');
+ outline.disabled = true;
+ if (isGe) {
+ slides.setAttribute('href','null'); // Gecko fix
+ slides.setAttribute('href',slideCSS); // Gecko fix
+ }
+ if (isIE && document.styleSheets && document.styleSheets[0]) {
+ document.styleSheets[0].addRule('img', 'behavior: url(ui/default/iepngfix.htc)');
+ document.styleSheets[0].addRule('div', 'behavior: url(ui/default/iepngfix.htc)');
+ document.styleSheets[0].addRule('.slide', 'behavior: url(ui/default/iepngfix.htc)');
+ }
+}
+
+function getIncrementals(obj) {
+ var incrementals = new Array();
+ if (!obj)
+ return incrementals;
+ var children = obj.childNodes;
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ if (hasClass(child, 'incremental')) {
+ if (child.nodeName == 'OL' || child.nodeName == 'UL') {
+ removeClass(child, 'incremental');
+ for (var j = 0; j < child.childNodes.length; j++) {
+ if (child.childNodes[j].nodeType == 1) {
+ addClass(child.childNodes[j], 'incremental');
+ }
+ }
+ } else {
+ incrementals[incrementals.length] = child;
+ removeClass(child,'incremental');
+ }
+ }
+ if (hasClass(child, 'show-first')) {
+ if (child.nodeName == 'OL' || child.nodeName == 'UL') {
+ removeClass(child, 'show-first');
+ if (child.childNodes[isGe].nodeType == 1) {
+ removeClass(child.childNodes[isGe], 'incremental');
+ }
+ } else {
+ incrementals[incrementals.length] = child;
+ }
+ }
+ incrementals = incrementals.concat(getIncrementals(child));
+ }
+ return incrementals;
+}
+
+function createIncrementals() {
+ var incrementals = new Array();
+ for (var i = 0; i < smax; i++) {
+ incrementals[i] = getIncrementals(document.getElementById(slideIDs[i]));
+ }
+ return incrementals;
+}
+
+function defaultCheck() {
+ var allMetas = document.getElementsByTagName('meta');
+ for (var i = 0; i< allMetas.length; i++) {
+ if (allMetas[i].name == 'defaultView') {
+ defaultView = allMetas[i].content;
+ }
+ if (allMetas[i].name == 'controlVis') {
+ controlVis = allMetas[i].content;
+ }
+ }
+}
+
+// Key trap fix, new function body for trap()
+function trap(e) {
+ if (!e) {
+ e = event;
+ e.which = e.keyCode;
+ }
+ try {
+ modifierKey = e.ctrlKey || e.altKey || e.metaKey;
+ }
+ catch(e) {
+ modifierKey = false;
+ }
+ return modifierKey || e.which == 0;
+}
+
+function startup() {
+ defaultCheck();
+ if (!isOp) createControls();
+ slideLabel();
+ fixLinks();
+ externalLinks();
+ fontScale();
+ if (!isOp) {
+ notOperaFix();
+ incrementals = createIncrementals();
+ slideJump();
+ if (defaultView == 'outline') {
+ toggle();
+ }
+ document.onkeyup = keys;
+ document.onkeypress = trap;
+ document.onclick = clicker;
+ }
+}
+
+window.onload = startup;
+window.onresize = function(){setTimeout('fontScale()', 50);}
diff --git a/docutils/writers/s5_html/themes/medium-black/__base__ b/docutils/writers/s5_html/themes/medium-black/__base__
new file mode 100644
index 000000000..401b621bd
--- /dev/null
+++ b/docutils/writers/s5_html/themes/medium-black/__base__
@@ -0,0 +1,2 @@
+# base theme of this theme:
+medium-white
diff --git a/docutils/writers/s5_html/themes/medium-black/pretty.css b/docutils/writers/s5_html/themes/medium-black/pretty.css
new file mode 100644
index 000000000..2ec10e2e8
--- /dev/null
+++ b/docutils/writers/s5_html/themes/medium-black/pretty.css
@@ -0,0 +1,115 @@
+/* This file has been placed in the public domain. */
+/* Following are the presentation styles -- edit away! */
+
+html, body {margin: 0; padding: 0;}
+body {background: black; color: white;}
+:link, :visited {text-decoration: none; color: cyan;}
+#controls :active {color: #888 !important;}
+#controls :focus {outline: 1px dotted #CCC;}
+h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;}
+
+blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;}
+blockquote p {margin: 0;}
+
+kbd {font-weight: bold; font-size: 1em;}
+sup {font-size: smaller; line-height: 1px;}
+
+.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;}
+.slide ul ul li {list-style: square;}
+.slide img.leader {display: block; margin: 0 auto;}
+.slide tt {font-size: 90%;}
+
+div#footer {font-family: sans-serif; color: #AAA;
+ font-size: 0.5em; font-weight: bold; padding: 1em 0;}
+#footer h1 {display: block; padding: 0 1em;}
+#footer h2 {display: block; padding: 0.8em 1em 0;}
+
+.slide {font-size: 1.75em;}
+.slide h1 {padding-top: 0; z-index: 1; margin: 0; font: bold 150% sans-serif;}
+.slide h2 {font: bold 125% sans-serif; padding-top: 0.5em;}
+.slide h3 {font: bold 110% sans-serif; padding-top: 0.5em;}
+h1 abbr {font-variant: small-caps;}
+
+div#controls {position: absolute; left: 50%; bottom: 0;
+ width: 50%; text-align: right; font: bold 0.9em sans-serif;}
+html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0; padding: 0;}
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+ border: none; color: #888; cursor: pointer;}
+#controls #navList {height: 1em;}
+#controls #navList #jumplist {position: absolute; bottom: 0; right: 0;
+ background: black; color: #CCC;}
+
+#currentSlide {text-align: center; font-size: 0.5em; color: #AAA;
+ font-family: sans-serif; font-weight: bold;}
+
+#slide0 h1 {position: static; margin: 0 0 0.5em; padding-top: 1em; top: 0;
+ font: bold 150% sans-serif; white-space: normal; background: transparent;}
+#slide0 h2 {font: bold italic 125% sans-serif; color: gray;}
+#slide0 h3 {margin-top: 1.5em; font: bold 110% sans-serif;}
+#slide0 h4 {margin-top: 0; font-size: 1em;}
+
+ul.urls {list-style: none; display: inline; margin: 0;}
+.urls li {display: inline; margin: 0;}
+.external {border-bottom: 1px dotted gray;}
+html>body .external {border-bottom: none;}
+.external:after {content: " \274F"; font-size: smaller; color: #FCC;}
+
+.incremental, .incremental *, .incremental *:after {
+ color: black; visibility: visible; border: 0;}
+img.incremental {visibility: hidden;}
+.slide .current {color: lime;}
+
+.slide-display {display: inline ! important;}
+
+.huge {font-family: sans-serif; font-weight: bold; font-size: 150%;}
+.big {font-family: sans-serif; font-weight: bold; font-size: 120%;}
+.small {font-size: 75%;}
+.tiny {font-size: 50%;}
+.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;}
+.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;}
+
+.maroon {color: maroon;}
+.red {color: red;}
+.magenta {color: magenta;}
+.fuchsia {color: fuchsia;}
+.pink {color: #FAA;}
+.orange {color: orange;}
+.yellow {color: yellow;}
+.lime {color: lime;}
+.green {color: green;}
+.olive {color: olive;}
+.teal {color: teal;}
+.cyan {color: cyan;}
+.aqua {color: aqua;}
+.blue {color: blue;}
+.navy {color: navy;}
+.purple {color: purple;}
+.black {color: black;}
+.gray {color: gray;}
+.silver {color: silver;}
+.white {color: white;}
+
+.left {text-align: left ! important;}
+.center {text-align: center ! important;}
+.right {text-align: right ! important;}
+
+.animation {position: relative; margin: 1em 0; padding: 0;}
+.animation img {position: absolute;}
+
+/* Docutils-specific overrides */
+
+.slide table.docinfo {margin: 0.5em 0 0.5em 1em;}
+
+div.sidebar {background-color: black;}
+
+pre.literal-block, pre.doctest-block {background-color: black;}
+
+tt.docutils {background-color: black;}
+
+/* diagnostics */
+/*
+li:after {content: " [" attr(class) "]"; color: #F88;}
+div:before {content: "[" attr(class) "]"; color: #F88;}
+*/
diff --git a/docutils/writers/s5_html/themes/medium-white/framing.css b/docutils/writers/s5_html/themes/medium-white/framing.css
new file mode 100644
index 000000000..6c4e3abf2
--- /dev/null
+++ b/docutils/writers/s5_html/themes/medium-white/framing.css
@@ -0,0 +1,24 @@
+/* This file has been placed in the public domain. */
+/* The following styles size, place, and layer the slide components.
+ Edit these if you want to change the overall slide layout.
+ The commented lines can be uncommented (and modified, if necessary)
+ to help you with the rearrangement process. */
+
+/* target = 1024x768 */
+
+div#header, div#footer, .slide {width: 100%; top: 0; left: 0;}
+div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;}
+.slide {top: 0; width: 92%; padding: 0.75em 4% 0 4%; z-index: 2;}
+div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0;}
+#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em;
+ z-index: 10;}
+html>body #currentSlide {position: fixed;}
+
+/*
+div#header {background: #FCC;}
+div#footer {background: #CCF;}
+div#controls {background: #BBD;}
+div#currentSlide {background: #FFC;}
+*/
diff --git a/docutils/writers/s5_html/themes/medium-white/pretty.css b/docutils/writers/s5_html/themes/medium-white/pretty.css
new file mode 100644
index 000000000..07e07b9ab
--- /dev/null
+++ b/docutils/writers/s5_html/themes/medium-white/pretty.css
@@ -0,0 +1,113 @@
+/* This file has been placed in the public domain. */
+/* Following are the presentation styles -- edit away! */
+
+html, body {margin: 0; padding: 0;}
+body {background: white; color: black;}
+:link, :visited {text-decoration: none; color: #00C;}
+#controls :active {color: #888 !important;}
+#controls :focus {outline: 1px dotted #222;}
+h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;}
+
+blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;}
+blockquote p {margin: 0;}
+
+kbd {font-weight: bold; font-size: 1em;}
+sup {font-size: smaller; line-height: 1px;}
+
+.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;}
+.slide ul ul li {list-style: square;}
+.slide img.leader {display: block; margin: 0 auto;}
+.slide tt {font-size: 90%;}
+
+div#footer {font-family: sans-serif; color: #444;
+ font-size: 0.5em; font-weight: bold; padding: 1em 0;}
+#footer h1 {display: block; padding: 0 1em;}
+#footer h2 {display: block; padding: 0.8em 1em 0;}
+
+.slide {font-size: 1.75em;}
+.slide h1 {padding-top: 0; z-index: 1; margin: 0; font: bold 150% sans-serif;}
+.slide h2 {font: bold 125% sans-serif; padding-top: 0.5em;}
+.slide h3 {font: bold 110% sans-serif; padding-top: 0.5em;}
+h1 abbr {font-variant: small-caps;}
+
+div#controls {position: absolute; left: 50%; bottom: 0;
+ width: 50%; text-align: right; font: bold 0.9em sans-serif;}
+html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0; padding: 0;}
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+ border: none; color: #888; cursor: pointer;}
+#controls #navList {height: 1em;}
+#controls #navList #jumplist {position: absolute; bottom: 0; right: 0;
+ background: #DDD; color: #222;}
+
+#currentSlide {text-align: center; font-size: 0.5em; color: #444;
+ font-family: sans-serif; font-weight: bold;}
+
+#slide0 h1 {position: static; margin: 0 0 0.5em; padding-top: 1em; top: 0;
+ font: bold 150% sans-serif; white-space: normal; background: transparent;}
+#slide0 h2 {font: bold italic 125% sans-serif; color: gray;}
+#slide0 h3 {margin-top: 1.5em; font: bold 110% sans-serif;}
+#slide0 h4 {margin-top: 0; font-size: 1em;}
+
+ul.urls {list-style: none; display: inline; margin: 0;}
+.urls li {display: inline; margin: 0;}
+.external {border-bottom: 1px dotted gray;}
+html>body .external {border-bottom: none;}
+.external:after {content: " \274F"; font-size: smaller; color: #77B;}
+
+.incremental, .incremental *, .incremental *:after {
+ color: white; visibility: visible; border: 0;}
+img.incremental {visibility: hidden;}
+.slide .current {color: green;}
+
+.slide-display {display: inline ! important;}
+
+.huge {font-family: sans-serif; font-weight: bold; font-size: 150%;}
+.big {font-family: sans-serif; font-weight: bold; font-size: 120%;}
+.small {font-size: 75%;}
+.tiny {font-size: 50%;}
+.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;}
+.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;}
+
+.maroon {color: maroon;}
+.red {color: red;}
+.magenta {color: magenta;}
+.fuchsia {color: fuchsia;}
+.pink {color: #FAA;}
+.orange {color: orange;}
+.yellow {color: yellow;}
+.lime {color: lime;}
+.green {color: green;}
+.olive {color: olive;}
+.teal {color: teal;}
+.cyan {color: cyan;}
+.aqua {color: aqua;}
+.blue {color: blue;}
+.navy {color: navy;}
+.purple {color: purple;}
+.black {color: black;}
+.gray {color: gray;}
+.silver {color: silver;}
+.white {color: white;}
+
+.left {text-align: left ! important;}
+.center {text-align: center ! important;}
+.right {text-align: right ! important;}
+
+.animation {position: relative; margin: 1em 0; padding: 0;}
+.animation img {position: absolute;}
+
+/* Docutils-specific overrides */
+
+.slide table.docinfo {margin: 0.5em 0 0.5em 1em;}
+
+pre.literal-block, pre.doctest-block {background-color: white;}
+
+tt.docutils {background-color: white;}
+
+/* diagnostics */
+/*
+li:after {content: " [" attr(class) "]"; color: #F88;}
+div:before {content: "[" attr(class) "]"; color: #F88;}
+*/
diff --git a/docutils/writers/s5_html/themes/small-black/__base__ b/docutils/writers/s5_html/themes/small-black/__base__
new file mode 100644
index 000000000..67f4db2bf
--- /dev/null
+++ b/docutils/writers/s5_html/themes/small-black/__base__
@@ -0,0 +1,2 @@
+# base theme of this theme:
+small-white
diff --git a/docutils/writers/s5_html/themes/small-black/pretty.css b/docutils/writers/s5_html/themes/small-black/pretty.css
new file mode 100644
index 000000000..5c1932704
--- /dev/null
+++ b/docutils/writers/s5_html/themes/small-black/pretty.css
@@ -0,0 +1,116 @@
+/* This file has been placed in the public domain. */
+/* Following are the presentation styles -- edit away! */
+
+html, body {margin: 0; padding: 0;}
+body {background: black; color: white;}
+:link, :visited {text-decoration: none; color: cyan;}
+#controls :active {color: #888 !important;}
+#controls :focus {outline: 1px dotted #CCC;}
+h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;}
+
+blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;}
+blockquote p {margin: 0;}
+
+kbd {font-weight: bold; font-size: 1em;}
+sup {font-size: smaller; line-height: 1px;}
+
+.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;}
+.slide ul ul li {list-style: square;}
+.slide img.leader {display: block; margin: 0 auto;}
+.slide tt {font-size: 90%;}
+
+div#footer {font-family: sans-serif; color: #AAA;
+ font-size: 0.5em; font-weight: bold; padding: 1em 0;}
+#footer h1 {display: block; padding: 0 1em;}
+#footer h2 {display: block; padding: 0.8em 1em 0;}
+
+.slide {font-size: 1.2em;}
+.slide h1 {padding-top: 0; z-index: 1; margin: 0; font: bold 150% sans-serif;}
+.slide h2 {font: bold 120% sans-serif; padding-top: 0.5em;}
+.slide h3 {font: bold 100% sans-serif; padding-top: 0.5em;}
+h1 abbr {font-variant: small-caps;}
+
+div#controls {position: absolute; left: 50%; bottom: 0;
+ width: 50%; text-align: right; font: bold 0.9em sans-serif;}
+html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0; padding: 0;}
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+ border: none; color: #888; cursor: pointer;}
+#controls #navList {height: 1em;}
+#controls #navList #jumplist {position: absolute; bottom: 0; right: 0;
+ background: black; color: #CCC;}
+
+#currentSlide {text-align: center; font-size: 0.5em; color: #AAA;
+ font-family: sans-serif; font-weight: bold;}
+
+#slide0 {padding-top: 0em}
+#slide0 h1 {position: static; margin: 1em 0 0; padding: 0;
+ font: bold 2em sans-serif; white-space: normal; background: transparent;}
+#slide0 h2 {font: bold italic 1em sans-serif; margin: 0.25em;}
+#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;}
+#slide0 h4 {margin-top: 0; font-size: 1em;}
+
+ul.urls {list-style: none; display: inline; margin: 0;}
+.urls li {display: inline; margin: 0;}
+.external {border-bottom: 1px dotted gray;}
+html>body .external {border-bottom: none;}
+.external:after {content: " \274F"; font-size: smaller; color: #FCC;}
+
+.incremental, .incremental *, .incremental *:after {
+ color: black; visibility: visible; border: 0;}
+img.incremental {visibility: hidden;}
+.slide .current {color: lime;}
+
+.slide-display {display: inline ! important;}
+
+.huge {font-family: sans-serif; font-weight: bold; font-size: 150%;}
+.big {font-family: sans-serif; font-weight: bold; font-size: 120%;}
+.small {font-size: 75%;}
+.tiny {font-size: 50%;}
+.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;}
+.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;}
+
+.maroon {color: maroon;}
+.red {color: red;}
+.magenta {color: magenta;}
+.fuchsia {color: fuchsia;}
+.pink {color: #FAA;}
+.orange {color: orange;}
+.yellow {color: yellow;}
+.lime {color: lime;}
+.green {color: green;}
+.olive {color: olive;}
+.teal {color: teal;}
+.cyan {color: cyan;}
+.aqua {color: aqua;}
+.blue {color: blue;}
+.navy {color: navy;}
+.purple {color: purple;}
+.black {color: black;}
+.gray {color: gray;}
+.silver {color: silver;}
+.white {color: white;}
+
+.left {text-align: left ! important;}
+.center {text-align: center ! important;}
+.right {text-align: right ! important;}
+
+.animation {position: relative; margin: 1em 0; padding: 0;}
+.animation img {position: absolute;}
+
+/* Docutils-specific overrides */
+
+.slide table.docinfo {margin: 1em 0 0.5em 2em;}
+
+div.sidebar {background-color: black;}
+
+pre.literal-block, pre.doctest-block {background-color: black;}
+
+tt.docutils {background-color: black;}
+
+/* diagnostics */
+/*
+li:after {content: " [" attr(class) "]"; color: #F88;}
+div:before {content: "[" attr(class) "]"; color: #F88;}
+*/
diff --git a/docutils/writers/s5_html/themes/small-white/framing.css b/docutils/writers/s5_html/themes/small-white/framing.css
new file mode 100644
index 000000000..70287dd06
--- /dev/null
+++ b/docutils/writers/s5_html/themes/small-white/framing.css
@@ -0,0 +1,24 @@
+/* This file has been placed in the public domain. */
+/* The following styles size, place, and layer the slide components.
+ Edit these if you want to change the overall slide layout.
+ The commented lines can be uncommented (and modified, if necessary)
+ to help you with the rearrangement process. */
+
+/* target = 1024x768 */
+
+div#header, div#footer, .slide {width: 100%; top: 0; left: 0;}
+div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;}
+.slide {top: 0; width: 92%; padding: 1em 4% 0 4%; z-index: 2;}
+div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0;}
+#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em;
+ z-index: 10;}
+html>body #currentSlide {position: fixed;}
+
+/*
+div#header {background: #FCC;}
+div#footer {background: #CCF;}
+div#controls {background: #BBD;}
+div#currentSlide {background: #FFC;}
+*/
diff --git a/docutils/writers/s5_html/themes/small-white/pretty.css b/docutils/writers/s5_html/themes/small-white/pretty.css
new file mode 100644
index 000000000..ba988e13b
--- /dev/null
+++ b/docutils/writers/s5_html/themes/small-white/pretty.css
@@ -0,0 +1,114 @@
+/* This file has been placed in the public domain. */
+/* Following are the presentation styles -- edit away! */
+
+html, body {margin: 0; padding: 0;}
+body {background: white; color: black;}
+:link, :visited {text-decoration: none; color: #00C;}
+#controls :active {color: #888 !important;}
+#controls :focus {outline: 1px dotted #222;}
+h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;}
+
+blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;}
+blockquote p {margin: 0;}
+
+kbd {font-weight: bold; font-size: 1em;}
+sup {font-size: smaller; line-height: 1px;}
+
+.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;}
+.slide ul ul li {list-style: square;}
+.slide img.leader {display: block; margin: 0 auto;}
+.slide tt {font-size: 90%;}
+
+div#footer {font-family: sans-serif; color: #444;
+ font-size: 0.5em; font-weight: bold; padding: 1em 0;}
+#footer h1 {display: block; padding: 0 1em;}
+#footer h2 {display: block; padding: 0.8em 1em 0;}
+
+.slide {font-size: 1.2em;}
+.slide h1 {padding-top: 0; z-index: 1; margin: 0; font: bold 150% sans-serif;}
+.slide h2 {font: bold 120% sans-serif; padding-top: 0.5em;}
+.slide h3 {font: bold 100% sans-serif; padding-top: 0.5em;}
+h1 abbr {font-variant: small-caps;}
+
+div#controls {position: absolute; left: 50%; bottom: 0;
+ width: 50%; text-align: right; font: bold 0.9em sans-serif;}
+html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0; padding: 0;}
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+ border: none; color: #888; cursor: pointer;}
+#controls #navList {height: 1em;}
+#controls #navList #jumplist {position: absolute; bottom: 0; right: 0;
+ background: #DDD; color: #222;}
+
+#currentSlide {text-align: center; font-size: 0.5em; color: #444;
+ font-family: sans-serif; font-weight: bold;}
+
+#slide0 {padding-top: 0em}
+#slide0 h1 {position: static; margin: 1em 0 0; padding: 0;
+ font: bold 2em sans-serif; white-space: normal; background: transparent;}
+#slide0 h2 {font: bold italic 1em sans-serif; margin: 0.25em;}
+#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;}
+#slide0 h4 {margin-top: 0; font-size: 1em;}
+
+ul.urls {list-style: none; display: inline; margin: 0;}
+.urls li {display: inline; margin: 0;}
+.external {border-bottom: 1px dotted gray;}
+html>body .external {border-bottom: none;}
+.external:after {content: " \274F"; font-size: smaller; color: #77B;}
+
+.incremental, .incremental *, .incremental *:after {
+ color: white; visibility: visible; border: 0; border: 0;}
+img.incremental {visibility: hidden;}
+.slide .current {color: green;}
+
+.slide-display {display: inline ! important;}
+
+.huge {font-family: sans-serif; font-weight: bold; font-size: 150%;}
+.big {font-family: sans-serif; font-weight: bold; font-size: 120%;}
+.small {font-size: 75%;}
+.tiny {font-size: 50%;}
+.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;}
+.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;}
+
+.maroon {color: maroon;}
+.red {color: red;}
+.magenta {color: magenta;}
+.fuchsia {color: fuchsia;}
+.pink {color: #FAA;}
+.orange {color: orange;}
+.yellow {color: yellow;}
+.lime {color: lime;}
+.green {color: green;}
+.olive {color: olive;}
+.teal {color: teal;}
+.cyan {color: cyan;}
+.aqua {color: aqua;}
+.blue {color: blue;}
+.navy {color: navy;}
+.purple {color: purple;}
+.black {color: black;}
+.gray {color: gray;}
+.silver {color: silver;}
+.white {color: white;}
+
+.left {text-align: left ! important;}
+.center {text-align: center ! important;}
+.right {text-align: right ! important;}
+
+.animation {position: relative; margin: 1em 0; padding: 0;}
+.animation img {position: absolute;}
+
+/* Docutils-specific overrides */
+
+.slide table.docinfo {margin: 1em 0 0.5em 2em;}
+
+pre.literal-block, pre.doctest-block {background-color: white;}
+
+tt.docutils {background-color: white;}
+
+/* diagnostics */
+/*
+li:after {content: " [" attr(class) "]"; color: #F88;}
+div:before {content: "[" attr(class) "]"; color: #F88;}
+*/