diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..522866e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+docs/_site
diff --git a/.ruby-version b/.ruby-version
new file mode 100644
index 0000000..276cbf9
--- /dev/null
+++ b/.ruby-version
@@ -0,0 +1 @@
+2.3.0
diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock
new file mode 100644
index 0000000..eceddc5
--- /dev/null
+++ b/docs/Gemfile.lock
@@ -0,0 +1,199 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ activesupport (4.2.8)
+ i18n (~> 0.7)
+ minitest (~> 5.1)
+ thread_safe (~> 0.3, >= 0.3.4)
+ tzinfo (~> 1.1)
+ addressable (2.5.1)
+ public_suffix (~> 2.0, >= 2.0.2)
+ coffee-script (2.4.1)
+ coffee-script-source
+ execjs
+ coffee-script-source (1.12.2)
+ colorator (1.1.0)
+ ethon (0.10.1)
+ ffi (>= 1.3.0)
+ execjs (2.7.0)
+ faraday (0.12.1)
+ multipart-post (>= 1.2, < 3)
+ ffi (1.9.18)
+ forwardable-extended (2.6.0)
+ gemoji (3.0.0)
+ github-pages (141)
+ activesupport (= 4.2.8)
+ github-pages-health-check (= 1.3.4)
+ jekyll (= 3.4.3)
+ jekyll-avatar (= 0.4.2)
+ jekyll-coffeescript (= 1.0.1)
+ jekyll-default-layout (= 0.1.4)
+ jekyll-feed (= 0.9.2)
+ jekyll-gist (= 1.4.0)
+ jekyll-github-metadata (= 2.4.0)
+ jekyll-mentions (= 1.2.0)
+ jekyll-optional-front-matter (= 0.1.2)
+ jekyll-paginate (= 1.1.0)
+ jekyll-readme-index (= 0.1.0)
+ jekyll-redirect-from (= 0.12.1)
+ jekyll-relative-links (= 0.4.1)
+ jekyll-sass-converter (= 1.5.0)
+ jekyll-seo-tag (= 2.2.3)
+ jekyll-sitemap (= 1.0.0)
+ jekyll-swiss (= 0.4.0)
+ jekyll-theme-architect (= 0.0.4)
+ jekyll-theme-cayman (= 0.0.4)
+ jekyll-theme-dinky (= 0.0.4)
+ jekyll-theme-hacker (= 0.0.4)
+ jekyll-theme-leap-day (= 0.0.4)
+ jekyll-theme-merlot (= 0.0.4)
+ jekyll-theme-midnight (= 0.0.4)
+ jekyll-theme-minimal (= 0.0.4)
+ jekyll-theme-modernist (= 0.0.4)
+ jekyll-theme-primer (= 0.2.1)
+ jekyll-theme-slate (= 0.0.4)
+ jekyll-theme-tactile (= 0.0.4)
+ jekyll-theme-time-machine (= 0.0.4)
+ jekyll-titles-from-headings (= 0.2.0)
+ jemoji (= 0.8.0)
+ kramdown (= 1.13.2)
+ liquid (= 3.0.6)
+ listen (= 3.0.6)
+ mercenary (~> 0.3)
+ minima (= 2.1.1)
+ rouge (= 1.11.1)
+ terminal-table (~> 1.4)
+ github-pages-health-check (1.3.4)
+ addressable (~> 2.3)
+ net-dns (~> 0.8)
+ octokit (~> 4.0)
+ public_suffix (~> 2.0)
+ typhoeus (~> 0.7)
+ html-pipeline (2.6.0)
+ activesupport (>= 2)
+ nokogiri (>= 1.4)
+ i18n (0.8.5)
+ jekyll (3.4.3)
+ addressable (~> 2.4)
+ colorator (~> 1.0)
+ jekyll-sass-converter (~> 1.0)
+ jekyll-watch (~> 1.1)
+ kramdown (~> 1.3)
+ liquid (~> 3.0)
+ mercenary (~> 0.3.3)
+ pathutil (~> 0.9)
+ rouge (~> 1.7)
+ safe_yaml (~> 1.0)
+ jekyll-avatar (0.4.2)
+ jekyll (~> 3.0)
+ jekyll-coffeescript (1.0.1)
+ coffee-script (~> 2.2)
+ jekyll-default-layout (0.1.4)
+ jekyll (~> 3.0)
+ jekyll-feed (0.9.2)
+ jekyll (~> 3.3)
+ jekyll-gist (1.4.0)
+ octokit (~> 4.2)
+ jekyll-github-metadata (2.4.0)
+ jekyll (~> 3.1)
+ octokit (~> 4.0, != 4.4.0)
+ jekyll-mentions (1.2.0)
+ activesupport (~> 4.0)
+ html-pipeline (~> 2.3)
+ jekyll (~> 3.0)
+ jekyll-optional-front-matter (0.1.2)
+ jekyll (~> 3.0)
+ jekyll-paginate (1.1.0)
+ jekyll-readme-index (0.1.0)
+ jekyll (~> 3.0)
+ jekyll-redirect-from (0.12.1)
+ jekyll (~> 3.3)
+ jekyll-relative-links (0.4.1)
+ jekyll (~> 3.3)
+ jekyll-sass-converter (1.5.0)
+ sass (~> 3.4)
+ jekyll-seo-tag (2.2.3)
+ jekyll (~> 3.3)
+ jekyll-sitemap (1.0.0)
+ jekyll (~> 3.3)
+ jekyll-swiss (0.4.0)
+ jekyll-theme-architect (0.0.4)
+ jekyll (~> 3.3)
+ jekyll-theme-cayman (0.0.4)
+ jekyll (~> 3.3)
+ jekyll-theme-dinky (0.0.4)
+ jekyll (~> 3.3)
+ jekyll-theme-hacker (0.0.4)
+ jekyll (~> 3.3)
+ jekyll-theme-leap-day (0.0.4)
+ jekyll (~> 3.3)
+ jekyll-theme-merlot (0.0.4)
+ jekyll (~> 3.3)
+ jekyll-theme-midnight (0.0.4)
+ jekyll (~> 3.3)
+ jekyll-theme-minimal (0.0.4)
+ jekyll (~> 3.3)
+ jekyll-theme-modernist (0.0.4)
+ jekyll (~> 3.3)
+ jekyll-theme-primer (0.2.1)
+ jekyll (~> 3.3)
+ jekyll-theme-slate (0.0.4)
+ jekyll (~> 3.3)
+ jekyll-theme-tactile (0.0.4)
+ jekyll (~> 3.3)
+ jekyll-theme-time-machine (0.0.4)
+ jekyll (~> 3.3)
+ jekyll-titles-from-headings (0.2.0)
+ jekyll (~> 3.3)
+ jekyll-watch (1.5.0)
+ listen (~> 3.0, < 3.1)
+ jemoji (0.8.0)
+ activesupport (~> 4.0)
+ gemoji (~> 3.0)
+ html-pipeline (~> 2.2)
+ jekyll (>= 3.0)
+ kramdown (1.13.2)
+ liquid (3.0.6)
+ listen (3.0.6)
+ rb-fsevent (>= 0.9.3)
+ rb-inotify (>= 0.9.7)
+ mercenary (0.3.6)
+ mini_portile2 (2.2.0)
+ minima (2.1.1)
+ jekyll (~> 3.3)
+ minitest (5.10.2)
+ multipart-post (2.0.0)
+ net-dns (0.8.0)
+ nokogiri (1.8.0)
+ mini_portile2 (~> 2.2.0)
+ octokit (4.7.0)
+ sawyer (~> 0.8.0, >= 0.5.3)
+ pathutil (0.14.0)
+ forwardable-extended (~> 2.6)
+ public_suffix (2.0.5)
+ rb-fsevent (0.10.2)
+ rb-inotify (0.9.10)
+ ffi (>= 0.5.0, < 2)
+ rouge (1.11.1)
+ safe_yaml (1.0.4)
+ sass (3.4.25)
+ sawyer (0.8.1)
+ addressable (>= 2.3.5, < 2.6)
+ faraday (~> 0.8, < 1.0)
+ terminal-table (1.8.0)
+ unicode-display_width (~> 1.1, >= 1.1.1)
+ thread_safe (0.3.6)
+ typhoeus (0.8.0)
+ ethon (>= 0.8.0)
+ tzinfo (1.2.3)
+ thread_safe (~> 0.1)
+ unicode-display_width (1.3.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ github-pages
+
+BUNDLED WITH
+ 1.14.6
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000..6c88dc6
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1,35 @@
+# Welcome to Jekyll!
+#
+# This config file is meant for settings that affect your whole blog, values
+# which you are expected to set up once and rarely edit after that. If you find
+# yourself editing this file very often, consider using Jekyll's data files
+# feature for the data you need to update frequently.
+#
+# For technical reasons, this file is *NOT* reloaded automatically when you use
+# 'bundle exec jekyll serve'. If you change this file, please restart the server process.
+
+# Site settings
+# These are used to personalize your new site. If you look in the HTML files,
+# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
+# You can create any custom variable you would like, and they will be accessible
+# in the templates via {{ site.myvariable }}.
+title: Draco 3D Data Compression
+
+email: webmaster@webmproject.org
+description: >
+ Description here
+baseurl: "/docs" # the subpath of your site, e.g. /blog
+url: "" # the base hostname & protocol for your site, e.g. http://example.com
+twitter_username: webm
+github_username: webmproject
+timezone: America/Los_Angeles
+
+# Build settings
+markdown: kramdown
+gems:
+exclude:
+ - Gemfile
+ - Gemfile.lock
+ - docs/_site
+sass:
+ style: compressed
diff --git a/docs/_layouts/spec.html b/docs/_layouts/spec.html
new file mode 100644
index 0000000..1181d44
--- /dev/null
+++ b/docs/_layouts/spec.html
@@ -0,0 +1,29 @@
+
+
+
+
+ {{ page.title }}
+
+
+
+
+
+{{ content }}
+
+
+
+
diff --git a/docs/assets/css/pygments/README.md b/docs/assets/css/pygments/README.md
new file mode 100644
index 0000000..83c205a
--- /dev/null
+++ b/docs/assets/css/pygments/README.md
@@ -0,0 +1,23 @@
+# jekyll-pygments-themes
+
+A set of CSS theme files for Pygments (Python-based code highlighting tool)
+created from the original built-in Pygments styles, ready for use with Jekyll.
+
+## Theme Previews and Custom Theme Builder
+-
+
+## Using Themes Without Jekyll
+If you want to use the themes with something other than Jekyll, you may need to
+remove or change the CSS style prefix of `.highlight`.
+
+## Links
+
+- [Jekyll](http://jekyllrb.com/) ([direct link to code highlighting documentation](http://jekyllrb.com/docs/templates/#code-snippet-highlighting))
+- [Pygments](http://pygments.org)
+
+## Hacking
+
+If you want to hack on the site, check out the [gh-pages](https://github.com/jwarby/jekyll-pygments-themes/tree/gh-pages) branch.
+
+## Acknowledgements
+Forked from [richleland/pygments-css](https://github.com/richleland/pygments-css).
diff --git a/docs/assets/css/pygments/UNLICENSE.txt b/docs/assets/css/pygments/UNLICENSE.txt
new file mode 100644
index 0000000..cf1ab25
--- /dev/null
+++ b/docs/assets/css/pygments/UNLICENSE.txt
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to
diff --git a/docs/assets/css/pygments/autumn.css b/docs/assets/css/pygments/autumn.css
new file mode 100644
index 0000000..a5f3d4c
--- /dev/null
+++ b/docs/assets/css/pygments/autumn.css
@@ -0,0 +1,58 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #aaaaaa; font-style: italic } /* Comment */
+.highlight .err { color: #F00000; background-color: #F0A0A0 } /* Error */
+.highlight .k { color: #0000aa } /* Keyword */
+.highlight .cm { color: #aaaaaa; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #4c8317 } /* Comment.Preproc */
+.highlight .c1 { color: #aaaaaa; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #0000aa; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #aa0000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #aa0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00aa00 } /* Generic.Inserted */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #555555 } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #aa0000 } /* Generic.Traceback */
+.highlight .kc { color: #0000aa } /* Keyword.Constant */
+.highlight .kd { color: #0000aa } /* Keyword.Declaration */
+.highlight .kn { color: #0000aa } /* Keyword.Namespace */
+.highlight .kp { color: #0000aa } /* Keyword.Pseudo */
+.highlight .kr { color: #0000aa } /* Keyword.Reserved */
+.highlight .kt { color: #00aaaa } /* Keyword.Type */
+.highlight .m { color: #009999 } /* Literal.Number */
+.highlight .s { color: #aa5500 } /* Literal.String */
+.highlight .na { color: #1e90ff } /* Name.Attribute */
+.highlight .nb { color: #00aaaa } /* Name.Builtin */
+.highlight .nc { color: #00aa00; text-decoration: underline } /* Name.Class */
+.highlight .no { color: #aa0000 } /* Name.Constant */
+.highlight .nd { color: #888888 } /* Name.Decorator */
+.highlight .ni { color: #800000; font-weight: bold } /* Name.Entity */
+.highlight .nf { color: #00aa00 } /* Name.Function */
+.highlight .nn { color: #00aaaa; text-decoration: underline } /* Name.Namespace */
+.highlight .nt { color: #1e90ff; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #aa0000 } /* Name.Variable */
+.highlight .ow { color: #0000aa } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #009999 } /* Literal.Number.Float */
+.highlight .mh { color: #009999 } /* Literal.Number.Hex */
+.highlight .mi { color: #009999 } /* Literal.Number.Integer */
+.highlight .mo { color: #009999 } /* Literal.Number.Oct */
+.highlight .sb { color: #aa5500 } /* Literal.String.Backtick */
+.highlight .sc { color: #aa5500 } /* Literal.String.Char */
+.highlight .sd { color: #aa5500 } /* Literal.String.Doc */
+.highlight .s2 { color: #aa5500 } /* Literal.String.Double */
+.highlight .se { color: #aa5500 } /* Literal.String.Escape */
+.highlight .sh { color: #aa5500 } /* Literal.String.Heredoc */
+.highlight .si { color: #aa5500 } /* Literal.String.Interpol */
+.highlight .sx { color: #aa5500 } /* Literal.String.Other */
+.highlight .sr { color: #009999 } /* Literal.String.Regex */
+.highlight .s1 { color: #aa5500 } /* Literal.String.Single */
+.highlight .ss { color: #0000aa } /* Literal.String.Symbol */
+.highlight .bp { color: #00aaaa } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #aa0000 } /* Name.Variable.Class */
+.highlight .vg { color: #aa0000 } /* Name.Variable.Global */
+.highlight .vi { color: #aa0000 } /* Name.Variable.Instance */
+.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/borland.css b/docs/assets/css/pygments/borland.css
new file mode 100644
index 0000000..2e98c79
--- /dev/null
+++ b/docs/assets/css/pygments/borland.css
@@ -0,0 +1,46 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #008800; font-style: italic } /* Comment */
+.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.highlight .k { color: #000080; font-weight: bold } /* Keyword */
+.highlight .cm { color: #008800; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #008080 } /* Comment.Preproc */
+.highlight .c1 { color: #008800; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #008800; font-weight: bold } /* Comment.Special */
+.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #aa0000 } /* Generic.Error */
+.highlight .gh { color: #999999 } /* Generic.Heading */
+.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #555555 } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
+.highlight .gt { color: #aa0000 } /* Generic.Traceback */
+.highlight .kc { color: #000080; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #000080; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #000080; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #000080; font-weight: bold } /* Keyword.Pseudo */
+.highlight .kr { color: #000080; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #000080; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #0000FF } /* Literal.Number */
+.highlight .s { color: #0000FF } /* Literal.String */
+.highlight .na { color: #FF0000 } /* Name.Attribute */
+.highlight .nt { color: #000080; font-weight: bold } /* Name.Tag */
+.highlight .ow { font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #0000FF } /* Literal.Number.Float */
+.highlight .mh { color: #0000FF } /* Literal.Number.Hex */
+.highlight .mi { color: #0000FF } /* Literal.Number.Integer */
+.highlight .mo { color: #0000FF } /* Literal.Number.Oct */
+.highlight .sb { color: #0000FF } /* Literal.String.Backtick */
+.highlight .sc { color: #800080 } /* Literal.String.Char */
+.highlight .sd { color: #0000FF } /* Literal.String.Doc */
+.highlight .s2 { color: #0000FF } /* Literal.String.Double */
+.highlight .se { color: #0000FF } /* Literal.String.Escape */
+.highlight .sh { color: #0000FF } /* Literal.String.Heredoc */
+.highlight .si { color: #0000FF } /* Literal.String.Interpol */
+.highlight .sx { color: #0000FF } /* Literal.String.Other */
+.highlight .sr { color: #0000FF } /* Literal.String.Regex */
+.highlight .s1 { color: #0000FF } /* Literal.String.Single */
+.highlight .ss { color: #0000FF } /* Literal.String.Symbol */
+.highlight .il { color: #0000FF } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/bw.css b/docs/assets/css/pygments/bw.css
new file mode 100644
index 0000000..632756b
--- /dev/null
+++ b/docs/assets/css/pygments/bw.css
@@ -0,0 +1,34 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { font-weight: bold } /* Keyword */
+.highlight .cm { font-style: italic } /* Comment.Multiline */
+.highlight .c1 { font-style: italic } /* Comment.Single */
+.highlight .cs { font-style: italic } /* Comment.Special */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gh { font-weight: bold } /* Generic.Heading */
+.highlight .gp { font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { font-weight: bold } /* Generic.Subheading */
+.highlight .kc { font-weight: bold } /* Keyword.Constant */
+.highlight .kd { font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { font-weight: bold } /* Keyword.Namespace */
+.highlight .kr { font-weight: bold } /* Keyword.Reserved */
+.highlight .s { font-style: italic } /* Literal.String */
+.highlight .nc { font-weight: bold } /* Name.Class */
+.highlight .ni { font-weight: bold } /* Name.Entity */
+.highlight .ne { font-weight: bold } /* Name.Exception */
+.highlight .nn { font-weight: bold } /* Name.Namespace */
+.highlight .nt { font-weight: bold } /* Name.Tag */
+.highlight .ow { font-weight: bold } /* Operator.Word */
+.highlight .sb { font-style: italic } /* Literal.String.Backtick */
+.highlight .sc { font-style: italic } /* Literal.String.Char */
+.highlight .sd { font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { font-style: italic } /* Literal.String.Double */
+.highlight .se { font-weight: bold; font-style: italic } /* Literal.String.Escape */
+.highlight .sh { font-style: italic } /* Literal.String.Heredoc */
+.highlight .si { font-weight: bold; font-style: italic } /* Literal.String.Interpol */
+.highlight .sx { font-style: italic } /* Literal.String.Other */
+.highlight .sr { font-style: italic } /* Literal.String.Regex */
+.highlight .s1 { font-style: italic } /* Literal.String.Single */
+.highlight .ss { font-style: italic } /* Literal.String.Symbol */
diff --git a/docs/assets/css/pygments/colorful.css b/docs/assets/css/pygments/colorful.css
new file mode 100644
index 0000000..e5abd69
--- /dev/null
+++ b/docs/assets/css/pygments/colorful.css
@@ -0,0 +1,61 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #808080 } /* Comment */
+.highlight .err { color: #F00000; background-color: #F0A0A0 } /* Error */
+.highlight .k { color: #008000; font-weight: bold } /* Keyword */
+.highlight .o { color: #303030 } /* Operator */
+.highlight .cm { color: #808080 } /* Comment.Multiline */
+.highlight .cp { color: #507090 } /* Comment.Preproc */
+.highlight .c1 { color: #808080 } /* Comment.Single */
+.highlight .cs { color: #cc0000; font-weight: bold } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #808080 } /* Generic.Output */
+.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0040D0 } /* Generic.Traceback */
+.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #003080; font-weight: bold } /* Keyword.Pseudo */
+.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #303090; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #6000E0; font-weight: bold } /* Literal.Number */
+.highlight .s { background-color: #fff0f0 } /* Literal.String */
+.highlight .na { color: #0000C0 } /* Name.Attribute */
+.highlight .nb { color: #007020 } /* Name.Builtin */
+.highlight .nc { color: #B00060; font-weight: bold } /* Name.Class */
+.highlight .no { color: #003060; font-weight: bold } /* Name.Constant */
+.highlight .nd { color: #505050; font-weight: bold } /* Name.Decorator */
+.highlight .ni { color: #800000; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #F00000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #0060B0; font-weight: bold } /* Name.Function */
+.highlight .nl { color: #907000; font-weight: bold } /* Name.Label */
+.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #007000 } /* Name.Tag */
+.highlight .nv { color: #906030 } /* Name.Variable */
+.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #6000E0; font-weight: bold } /* Literal.Number.Float */
+.highlight .mh { color: #005080; font-weight: bold } /* Literal.Number.Hex */
+.highlight .mi { color: #0000D0; font-weight: bold } /* Literal.Number.Integer */
+.highlight .mo { color: #4000E0; font-weight: bold } /* Literal.Number.Oct */
+.highlight .sb { background-color: #fff0f0 } /* Literal.String.Backtick */
+.highlight .sc { color: #0040D0 } /* Literal.String.Char */
+.highlight .sd { color: #D04020 } /* Literal.String.Doc */
+.highlight .s2 { background-color: #fff0f0 } /* Literal.String.Double */
+.highlight .se { color: #606060; font-weight: bold; background-color: #fff0f0 } /* Literal.String.Escape */
+.highlight .sh { background-color: #fff0f0 } /* Literal.String.Heredoc */
+.highlight .si { background-color: #e0e0e0 } /* Literal.String.Interpol */
+.highlight .sx { color: #D02000; background-color: #fff0f0 } /* Literal.String.Other */
+.highlight .sr { color: #000000; background-color: #fff0ff } /* Literal.String.Regex */
+.highlight .s1 { background-color: #fff0f0 } /* Literal.String.Single */
+.highlight .ss { color: #A06000 } /* Literal.String.Symbol */
+.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #306090 } /* Name.Variable.Class */
+.highlight .vg { color: #d07000; font-weight: bold } /* Name.Variable.Global */
+.highlight .vi { color: #3030B0 } /* Name.Variable.Instance */
+.highlight .il { color: #0000D0; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/default.css b/docs/assets/css/pygments/default.css
new file mode 100644
index 0000000..8070f2f
--- /dev/null
+++ b/docs/assets/css/pygments/default.css
@@ -0,0 +1,61 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #408080; font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #008000; font-weight: bold } /* Keyword */
+.highlight .o { color: #666666 } /* Operator */
+.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
+.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #808080 } /* Generic.Output */
+.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0040D0 } /* Generic.Traceback */
+.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #008000 } /* Keyword.Pseudo */
+.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #B00040 } /* Keyword.Type */
+.highlight .m { color: #666666 } /* Literal.Number */
+.highlight .s { color: #BA2121 } /* Literal.String */
+.highlight .na { color: #7D9029 } /* Name.Attribute */
+.highlight .nb { color: #008000 } /* Name.Builtin */
+.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.highlight .no { color: #880000 } /* Name.Constant */
+.highlight .nd { color: #AA22FF } /* Name.Decorator */
+.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #0000FF } /* Name.Function */
+.highlight .nl { color: #A0A000 } /* Name.Label */
+.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #19177C } /* Name.Variable */
+.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #666666 } /* Literal.Number.Float */
+.highlight .mh { color: #666666 } /* Literal.Number.Hex */
+.highlight .mi { color: #666666 } /* Literal.Number.Integer */
+.highlight .mo { color: #666666 } /* Literal.Number.Oct */
+.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
+.highlight .sc { color: #BA2121 } /* Literal.String.Char */
+.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
+.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
+.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.highlight .sx { color: #008000 } /* Literal.String.Other */
+.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
+.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
+.highlight .ss { color: #19177C } /* Literal.String.Symbol */
+.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #19177C } /* Name.Variable.Class */
+.highlight .vg { color: #19177C } /* Name.Variable.Global */
+.highlight .vi { color: #19177C } /* Name.Variable.Instance */
+.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/emacs.css b/docs/assets/css/pygments/emacs.css
new file mode 100644
index 0000000..489c0ad
--- /dev/null
+++ b/docs/assets/css/pygments/emacs.css
@@ -0,0 +1,61 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #008800; font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #AA22FF; font-weight: bold } /* Keyword */
+.highlight .o { color: #666666 } /* Operator */
+.highlight .cm { color: #008800; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #008800 } /* Comment.Preproc */
+.highlight .c1 { color: #008800; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #008800; font-weight: bold } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #808080 } /* Generic.Output */
+.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0040D0 } /* Generic.Traceback */
+.highlight .kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #AA22FF; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #AA22FF } /* Keyword.Pseudo */
+.highlight .kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #00BB00; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #666666 } /* Literal.Number */
+.highlight .s { color: #BB4444 } /* Literal.String */
+.highlight .na { color: #BB4444 } /* Name.Attribute */
+.highlight .nb { color: #AA22FF } /* Name.Builtin */
+.highlight .nc { color: #0000FF } /* Name.Class */
+.highlight .no { color: #880000 } /* Name.Constant */
+.highlight .nd { color: #AA22FF } /* Name.Decorator */
+.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #00A000 } /* Name.Function */
+.highlight .nl { color: #A0A000 } /* Name.Label */
+.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #B8860B } /* Name.Variable */
+.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #666666 } /* Literal.Number.Float */
+.highlight .mh { color: #666666 } /* Literal.Number.Hex */
+.highlight .mi { color: #666666 } /* Literal.Number.Integer */
+.highlight .mo { color: #666666 } /* Literal.Number.Oct */
+.highlight .sb { color: #BB4444 } /* Literal.String.Backtick */
+.highlight .sc { color: #BB4444 } /* Literal.String.Char */
+.highlight .sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #BB4444 } /* Literal.String.Double */
+.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #BB4444 } /* Literal.String.Heredoc */
+.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.highlight .sx { color: #008000 } /* Literal.String.Other */
+.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
+.highlight .s1 { color: #BB4444 } /* Literal.String.Single */
+.highlight .ss { color: #B8860B } /* Literal.String.Symbol */
+.highlight .bp { color: #AA22FF } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #B8860B } /* Name.Variable.Class */
+.highlight .vg { color: #B8860B } /* Name.Variable.Global */
+.highlight .vi { color: #B8860B } /* Name.Variable.Instance */
+.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/friendly.css b/docs/assets/css/pygments/friendly.css
new file mode 100644
index 0000000..846e048
--- /dev/null
+++ b/docs/assets/css/pygments/friendly.css
@@ -0,0 +1,61 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #60a0b0; font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #007020; font-weight: bold } /* Keyword */
+.highlight .o { color: #666666 } /* Operator */
+.highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #007020 } /* Comment.Preproc */
+.highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #808080 } /* Generic.Output */
+.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0040D0 } /* Generic.Traceback */
+.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #007020 } /* Keyword.Pseudo */
+.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #902000 } /* Keyword.Type */
+.highlight .m { color: #40a070 } /* Literal.Number */
+.highlight .s { color: #4070a0 } /* Literal.String */
+.highlight .na { color: #4070a0 } /* Name.Attribute */
+.highlight .nb { color: #007020 } /* Name.Builtin */
+.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
+.highlight .no { color: #60add5 } /* Name.Constant */
+.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #007020 } /* Name.Exception */
+.highlight .nf { color: #06287e } /* Name.Function */
+.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
+.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #bb60d5 } /* Name.Variable */
+.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #40a070 } /* Literal.Number.Float */
+.highlight .mh { color: #40a070 } /* Literal.Number.Hex */
+.highlight .mi { color: #40a070 } /* Literal.Number.Integer */
+.highlight .mo { color: #40a070 } /* Literal.Number.Oct */
+.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
+.highlight .sc { color: #4070a0 } /* Literal.String.Char */
+.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
+.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
+.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
+.highlight .sx { color: #c65d09 } /* Literal.String.Other */
+.highlight .sr { color: #235388 } /* Literal.String.Regex */
+.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
+.highlight .ss { color: #517918 } /* Literal.String.Symbol */
+.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
+.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
+.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
+.highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/fruity.css b/docs/assets/css/pygments/fruity.css
new file mode 100644
index 0000000..9152350
--- /dev/null
+++ b/docs/assets/css/pygments/fruity.css
@@ -0,0 +1,70 @@
+.highlight pre { background-color: #333; }
+.highlight .hll { background-color: #333333 }
+.highlight .c { color: #008800; font-style: italic; background-color: #0f140f } /* Comment */
+.highlight .err { color: #ffffff } /* Error */
+.highlight .g { color: #ffffff } /* Generic */
+.highlight .k { color: #fb660a; font-weight: bold } /* Keyword */
+.highlight .l { color: #ffffff } /* Literal */
+.highlight .n { color: #ffffff } /* Name */
+.highlight .o { color: #ffffff } /* Operator */
+.highlight .x { color: #ffffff } /* Other */
+.highlight .p { color: #ffffff } /* Punctuation */
+.highlight .cm { color: #008800; font-style: italic; background-color: #0f140f } /* Comment.Multiline */
+.highlight .cp { color: #ff0007; font-weight: bold; font-style: italic; background-color: #0f140f } /* Comment.Preproc */
+.highlight .c1 { color: #008800; font-style: italic; background-color: #0f140f } /* Comment.Single */
+.highlight .cs { color: #008800; font-style: italic; background-color: #0f140f } /* Comment.Special */
+.highlight .gd { color: #ffffff } /* Generic.Deleted */
+.highlight .ge { color: #ffffff } /* Generic.Emph */
+.highlight .gr { color: #ffffff } /* Generic.Error */
+.highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #ffffff } /* Generic.Inserted */
+.highlight .go { color: #444444; background-color: #222222 } /* Generic.Output */
+.highlight .gp { color: #ffffff } /* Generic.Prompt */
+.highlight .gs { color: #ffffff } /* Generic.Strong */
+.highlight .gu { color: #ffffff; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #ffffff } /* Generic.Traceback */
+.highlight .kc { color: #fb660a; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #fb660a; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #fb660a; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #fb660a } /* Keyword.Pseudo */
+.highlight .kr { color: #fb660a; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #cdcaa9; font-weight: bold } /* Keyword.Type */
+.highlight .ld { color: #ffffff } /* Literal.Date */
+.highlight .m { color: #0086f7; font-weight: bold } /* Literal.Number */
+.highlight .s { color: #0086d2 } /* Literal.String */
+.highlight .na { color: #ff0086; font-weight: bold } /* Name.Attribute */
+.highlight .nb { color: #ffffff } /* Name.Builtin */
+.highlight .nc { color: #ffffff } /* Name.Class */
+.highlight .no { color: #0086d2 } /* Name.Constant */
+.highlight .nd { color: #ffffff } /* Name.Decorator */
+.highlight .ni { color: #ffffff } /* Name.Entity */
+.highlight .ne { color: #ffffff } /* Name.Exception */
+.highlight .nf { color: #ff0086; font-weight: bold } /* Name.Function */
+.highlight .nl { color: #ffffff } /* Name.Label */
+.highlight .nn { color: #ffffff } /* Name.Namespace */
+.highlight .nx { color: #ffffff } /* Name.Other */
+.highlight .py { color: #ffffff } /* Name.Property */
+.highlight .nt { color: #fb660a; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #fb660a } /* Name.Variable */
+.highlight .ow { color: #ffffff } /* Operator.Word */
+.highlight .w { color: #888888 } /* Text.Whitespace */
+.highlight .mf { color: #0086f7; font-weight: bold } /* Literal.Number.Float */
+.highlight .mh { color: #0086f7; font-weight: bold } /* Literal.Number.Hex */
+.highlight .mi { color: #0086f7; font-weight: bold } /* Literal.Number.Integer */
+.highlight .mo { color: #0086f7; font-weight: bold } /* Literal.Number.Oct */
+.highlight .sb { color: #0086d2 } /* Literal.String.Backtick */
+.highlight .sc { color: #0086d2 } /* Literal.String.Char */
+.highlight .sd { color: #0086d2 } /* Literal.String.Doc */
+.highlight .s2 { color: #0086d2 } /* Literal.String.Double */
+.highlight .se { color: #0086d2 } /* Literal.String.Escape */
+.highlight .sh { color: #0086d2 } /* Literal.String.Heredoc */
+.highlight .si { color: #0086d2 } /* Literal.String.Interpol */
+.highlight .sx { color: #0086d2 } /* Literal.String.Other */
+.highlight .sr { color: #0086d2 } /* Literal.String.Regex */
+.highlight .s1 { color: #0086d2 } /* Literal.String.Single */
+.highlight .ss { color: #0086d2 } /* Literal.String.Symbol */
+.highlight .bp { color: #ffffff } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #fb660a } /* Name.Variable.Class */
+.highlight .vg { color: #fb660a } /* Name.Variable.Global */
+.highlight .vi { color: #fb660a } /* Name.Variable.Instance */
+.highlight .il { color: #0086f7; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/github.css b/docs/assets/css/pygments/github.css
new file mode 100644
index 0000000..5c45e67
--- /dev/null
+++ b/docs/assets/css/pygments/github.css
@@ -0,0 +1,61 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #999988; font-style: italic } /* Comment */
+.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.highlight .k { color: #000000; font-weight: bold } /* Keyword */
+.highlight .o { color: #000000; font-weight: bold } /* Operator */
+.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #999999; font-weight: bold; font-style: italic } /* Comment.Preproc */
+.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #aa0000 } /* Generic.Error */
+.highlight .gh { color: #999999 } /* Generic.Heading */
+.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #555555 } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
+.highlight .gt { color: #aa0000 } /* Generic.Traceback */
+.highlight .kc { color: #000000; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #000000; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #000000; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */
+.highlight .kr { color: #000000; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #009999 } /* Literal.Number */
+.highlight .s { color: #d01040 } /* Literal.String */
+.highlight .na { color: #008080 } /* Name.Attribute */
+.highlight .nb { color: #0086B3 } /* Name.Builtin */
+.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
+.highlight .no { color: #008080 } /* Name.Constant */
+.highlight .nd { color: #3c5d5d; font-weight: bold } /* Name.Decorator */
+.highlight .ni { color: #800080 } /* Name.Entity */
+.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
+.highlight .nl { color: #990000; font-weight: bold } /* Name.Label */
+.highlight .nn { color: #555555 } /* Name.Namespace */
+.highlight .nt { color: #000080 } /* Name.Tag */
+.highlight .nv { color: #008080 } /* Name.Variable */
+.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #009999 } /* Literal.Number.Float */
+.highlight .mh { color: #009999 } /* Literal.Number.Hex */
+.highlight .mi { color: #009999 } /* Literal.Number.Integer */
+.highlight .mo { color: #009999 } /* Literal.Number.Oct */
+.highlight .sb { color: #d01040 } /* Literal.String.Backtick */
+.highlight .sc { color: #d01040 } /* Literal.String.Char */
+.highlight .sd { color: #d01040 } /* Literal.String.Doc */
+.highlight .s2 { color: #d01040 } /* Literal.String.Double */
+.highlight .se { color: #d01040 } /* Literal.String.Escape */
+.highlight .sh { color: #d01040 } /* Literal.String.Heredoc */
+.highlight .si { color: #d01040 } /* Literal.String.Interpol */
+.highlight .sx { color: #d01040 } /* Literal.String.Other */
+.highlight .sr { color: #009926 } /* Literal.String.Regex */
+.highlight .s1 { color: #d01040 } /* Literal.String.Single */
+.highlight .ss { color: #990073 } /* Literal.String.Symbol */
+.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #008080 } /* Name.Variable.Class */
+.highlight .vg { color: #008080 } /* Name.Variable.Global */
+.highlight .vi { color: #008080 } /* Name.Variable.Instance */
+.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/manni.css b/docs/assets/css/pygments/manni.css
new file mode 100644
index 0000000..d5bc47e
--- /dev/null
+++ b/docs/assets/css/pygments/manni.css
@@ -0,0 +1,61 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #0099FF; font-style: italic } /* Comment */
+.highlight .err { color: #AA0000; background-color: #FFAAAA } /* Error */
+.highlight .k { color: #006699; font-weight: bold } /* Keyword */
+.highlight .o { color: #555555 } /* Operator */
+.highlight .cm { color: #0099FF; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #009999 } /* Comment.Preproc */
+.highlight .c1 { color: #0099FF; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */
+.highlight .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #003300; font-weight: bold } /* Generic.Heading */
+.highlight .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */
+.highlight .go { color: #AAAAAA } /* Generic.Output */
+.highlight .gp { color: #000099; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #003300; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #99CC66 } /* Generic.Traceback */
+.highlight .kc { color: #006699; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #006699; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #006699; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #006699 } /* Keyword.Pseudo */
+.highlight .kr { color: #006699; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #007788; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #FF6600 } /* Literal.Number */
+.highlight .s { color: #CC3300 } /* Literal.String */
+.highlight .na { color: #330099 } /* Name.Attribute */
+.highlight .nb { color: #336666 } /* Name.Builtin */
+.highlight .nc { color: #00AA88; font-weight: bold } /* Name.Class */
+.highlight .no { color: #336600 } /* Name.Constant */
+.highlight .nd { color: #9999FF } /* Name.Decorator */
+.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #CC0000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #CC00FF } /* Name.Function */
+.highlight .nl { color: #9999FF } /* Name.Label */
+.highlight .nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #330099; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #003333 } /* Name.Variable */
+.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #FF6600 } /* Literal.Number.Float */
+.highlight .mh { color: #FF6600 } /* Literal.Number.Hex */
+.highlight .mi { color: #FF6600 } /* Literal.Number.Integer */
+.highlight .mo { color: #FF6600 } /* Literal.Number.Oct */
+.highlight .sb { color: #CC3300 } /* Literal.String.Backtick */
+.highlight .sc { color: #CC3300 } /* Literal.String.Char */
+.highlight .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #CC3300 } /* Literal.String.Double */
+.highlight .se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #CC3300 } /* Literal.String.Heredoc */
+.highlight .si { color: #AA0000 } /* Literal.String.Interpol */
+.highlight .sx { color: #CC3300 } /* Literal.String.Other */
+.highlight .sr { color: #33AAAA } /* Literal.String.Regex */
+.highlight .s1 { color: #CC3300 } /* Literal.String.Single */
+.highlight .ss { color: #FFCC33 } /* Literal.String.Symbol */
+.highlight .bp { color: #336666 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #003333 } /* Name.Variable.Class */
+.highlight .vg { color: #003333 } /* Name.Variable.Global */
+.highlight .vi { color: #003333 } /* Name.Variable.Instance */
+.highlight .il { color: #FF6600 } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/monokai.css b/docs/assets/css/pygments/monokai.css
new file mode 100644
index 0000000..5ce9493
--- /dev/null
+++ b/docs/assets/css/pygments/monokai.css
@@ -0,0 +1,66 @@
+.highlight pre, pre.highlight { background-color: #272822; }
+.highlight code { color: #fff; }
+.highlight .hll { background-color: #272822; }
+.highlight .c { color: #75715e } /* Comment */
+.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
+.highlight .k { color: #66d9ef } /* Keyword */
+.highlight .l { color: #ae81ff } /* Literal */
+.highlight .n { color: #f8f8f2 } /* Name */
+.highlight .o { color: #f92672 } /* Operator */
+.highlight .p { color: #f8f8f2 } /* Punctuation */
+.highlight .cm { color: #75715e } /* Comment.Multiline */
+.highlight .cp { color: #75715e } /* Comment.Preproc */
+.highlight .c1 { color: #75715e } /* Comment.Single */
+.highlight .cs { color: #75715e } /* Comment.Special */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .kc { color: #66d9ef } /* Keyword.Constant */
+.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
+.highlight .kn { color: #f92672 } /* Keyword.Namespace */
+.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
+.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
+.highlight .kt { color: #66d9ef } /* Keyword.Type */
+.highlight .ld { color: #e6db74 } /* Literal.Date */
+.highlight .m { color: #ae81ff } /* Literal.Number */
+.highlight .s { color: #e6db74 } /* Literal.String */
+.highlight .na { color: #a6e22e } /* Name.Attribute */
+.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
+.highlight .nc { color: #a6e22e } /* Name.Class */
+.highlight .no { color: #66d9ef } /* Name.Constant */
+.highlight .nd { color: #a6e22e } /* Name.Decorator */
+.highlight .ni { color: #f8f8f2 } /* Name.Entity */
+.highlight .ne { color: #a6e22e } /* Name.Exception */
+.highlight .nf { color: #a6e22e } /* Name.Function */
+.highlight .nl { color: #f8f8f2 } /* Name.Label */
+.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
+.highlight .nx { color: #a6e22e } /* Name.Other */
+.highlight .py { color: #f8f8f2 } /* Name.Property */
+.highlight .nt { color: #f92672 } /* Name.Tag */
+.highlight .nv { color: #f8f8f2 } /* Name.Variable */
+.highlight .ow { color: #f92672 } /* Operator.Word */
+.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
+.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
+.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
+.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
+.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
+.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
+.highlight .sc { color: #e6db74 } /* Literal.String.Char */
+.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
+.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
+.highlight .se { color: #ae81ff } /* Literal.String.Escape */
+.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
+.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
+.highlight .sx { color: #e6db74 } /* Literal.String.Other */
+.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
+.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
+.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
+.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
+.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
+.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
+.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
+
+.highlight .gh { } /* Generic Heading & Diff Header */
+.highlight .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */
+.highlight .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */
+.highlight .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */
diff --git a/docs/assets/css/pygments/murphy.css b/docs/assets/css/pygments/murphy.css
new file mode 100644
index 0000000..482d46b
--- /dev/null
+++ b/docs/assets/css/pygments/murphy.css
@@ -0,0 +1,61 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #606060; font-style: italic } /* Comment */
+.highlight .err { color: #F00000; background-color: #F0A0A0 } /* Error */
+.highlight .k { color: #208090; font-weight: bold } /* Keyword */
+.highlight .o { color: #303030 } /* Operator */
+.highlight .cm { color: #606060; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #507090 } /* Comment.Preproc */
+.highlight .c1 { color: #606060; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #c00000; font-weight: bold; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #808080 } /* Generic.Output */
+.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0040D0 } /* Generic.Traceback */
+.highlight .kc { color: #208090; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #208090; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #208090; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #0080f0; font-weight: bold } /* Keyword.Pseudo */
+.highlight .kr { color: #208090; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #6060f0; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #6000E0; font-weight: bold } /* Literal.Number */
+.highlight .s { background-color: #e0e0ff } /* Literal.String */
+.highlight .na { color: #000070 } /* Name.Attribute */
+.highlight .nb { color: #007020 } /* Name.Builtin */
+.highlight .nc { color: #e090e0; font-weight: bold } /* Name.Class */
+.highlight .no { color: #50e0d0; font-weight: bold } /* Name.Constant */
+.highlight .nd { color: #505050; font-weight: bold } /* Name.Decorator */
+.highlight .ni { color: #800000 } /* Name.Entity */
+.highlight .ne { color: #F00000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #50e0d0; font-weight: bold } /* Name.Function */
+.highlight .nl { color: #907000; font-weight: bold } /* Name.Label */
+.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #007000 } /* Name.Tag */
+.highlight .nv { color: #003060 } /* Name.Variable */
+.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #6000E0; font-weight: bold } /* Literal.Number.Float */
+.highlight .mh { color: #005080; font-weight: bold } /* Literal.Number.Hex */
+.highlight .mi { color: #6060f0; font-weight: bold } /* Literal.Number.Integer */
+.highlight .mo { color: #4000E0; font-weight: bold } /* Literal.Number.Oct */
+.highlight .sb { background-color: #e0e0ff } /* Literal.String.Backtick */
+.highlight .sc { color: #8080F0 } /* Literal.String.Char */
+.highlight .sd { color: #D04020 } /* Literal.String.Doc */
+.highlight .s2 { background-color: #e0e0ff } /* Literal.String.Double */
+.highlight .se { color: #606060; font-weight: bold; background-color: #e0e0ff } /* Literal.String.Escape */
+.highlight .sh { background-color: #e0e0ff } /* Literal.String.Heredoc */
+.highlight .si { background-color: #e0e0e0 } /* Literal.String.Interpol */
+.highlight .sx { color: #f08080; background-color: #e0e0ff } /* Literal.String.Other */
+.highlight .sr { color: #000000; background-color: #e0e0ff } /* Literal.String.Regex */
+.highlight .s1 { background-color: #e0e0ff } /* Literal.String.Single */
+.highlight .ss { color: #f0c080 } /* Literal.String.Symbol */
+.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #c0c0f0 } /* Name.Variable.Class */
+.highlight .vg { color: #f08040 } /* Name.Variable.Global */
+.highlight .vi { color: #a0a0f0 } /* Name.Variable.Instance */
+.highlight .il { color: #6060f0; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/native.css b/docs/assets/css/pygments/native.css
new file mode 100644
index 0000000..eac4a78
--- /dev/null
+++ b/docs/assets/css/pygments/native.css
@@ -0,0 +1,70 @@
+.highlight pre { background-color: #404040 }
+.highlight .hll { background-color: #404040 }
+.highlight .c { color: #999999; font-style: italic } /* Comment */
+.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.highlight .g { color: #d0d0d0 } /* Generic */
+.highlight .k { color: #6ab825; font-weight: bold } /* Keyword */
+.highlight .l { color: #d0d0d0 } /* Literal */
+.highlight .n { color: #d0d0d0 } /* Name */
+.highlight .o { color: #d0d0d0 } /* Operator */
+.highlight .x { color: #d0d0d0 } /* Other */
+.highlight .p { color: #d0d0d0 } /* Punctuation */
+.highlight .cm { color: #999999; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #cd2828; font-weight: bold } /* Comment.Preproc */
+.highlight .c1 { color: #999999; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */
+.highlight .gd { color: #d22323 } /* Generic.Deleted */
+.highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #d22323 } /* Generic.Error */
+.highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #589819 } /* Generic.Inserted */
+.highlight .go { color: #cccccc } /* Generic.Output */
+.highlight .gp { color: #aaaaaa } /* Generic.Prompt */
+.highlight .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */
+.highlight .gt { color: #d22323 } /* Generic.Traceback */
+.highlight .kc { color: #6ab825; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #6ab825; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #6ab825; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #6ab825 } /* Keyword.Pseudo */
+.highlight .kr { color: #6ab825; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #6ab825; font-weight: bold } /* Keyword.Type */
+.highlight .ld { color: #d0d0d0 } /* Literal.Date */
+.highlight .m { color: #3677a9 } /* Literal.Number */
+.highlight .s { color: #ed9d13 } /* Literal.String */
+.highlight .na { color: #bbbbbb } /* Name.Attribute */
+.highlight .nb { color: #24909d } /* Name.Builtin */
+.highlight .nc { color: #447fcf; text-decoration: underline } /* Name.Class */
+.highlight .no { color: #40ffff } /* Name.Constant */
+.highlight .nd { color: #ffa500 } /* Name.Decorator */
+.highlight .ni { color: #d0d0d0 } /* Name.Entity */
+.highlight .ne { color: #bbbbbb } /* Name.Exception */
+.highlight .nf { color: #447fcf } /* Name.Function */
+.highlight .nl { color: #d0d0d0 } /* Name.Label */
+.highlight .nn { color: #447fcf; text-decoration: underline } /* Name.Namespace */
+.highlight .nx { color: #d0d0d0 } /* Name.Other */
+.highlight .py { color: #d0d0d0 } /* Name.Property */
+.highlight .nt { color: #6ab825; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #40ffff } /* Name.Variable */
+.highlight .ow { color: #6ab825; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #666666 } /* Text.Whitespace */
+.highlight .mf { color: #3677a9 } /* Literal.Number.Float */
+.highlight .mh { color: #3677a9 } /* Literal.Number.Hex */
+.highlight .mi { color: #3677a9 } /* Literal.Number.Integer */
+.highlight .mo { color: #3677a9 } /* Literal.Number.Oct */
+.highlight .sb { color: #ed9d13 } /* Literal.String.Backtick */
+.highlight .sc { color: #ed9d13 } /* Literal.String.Char */
+.highlight .sd { color: #ed9d13 } /* Literal.String.Doc */
+.highlight .s2 { color: #ed9d13 } /* Literal.String.Double */
+.highlight .se { color: #ed9d13 } /* Literal.String.Escape */
+.highlight .sh { color: #ed9d13 } /* Literal.String.Heredoc */
+.highlight .si { color: #ed9d13 } /* Literal.String.Interpol */
+.highlight .sx { color: #ffa500 } /* Literal.String.Other */
+.highlight .sr { color: #ed9d13 } /* Literal.String.Regex */
+.highlight .s1 { color: #ed9d13 } /* Literal.String.Single */
+.highlight .ss { color: #ed9d13 } /* Literal.String.Symbol */
+.highlight .bp { color: #24909d } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #40ffff } /* Name.Variable.Class */
+.highlight .vg { color: #40ffff } /* Name.Variable.Global */
+.highlight .vi { color: #40ffff } /* Name.Variable.Instance */
+.highlight .il { color: #3677a9 } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/pastie.css b/docs/assets/css/pygments/pastie.css
new file mode 100644
index 0000000..538bdc6
--- /dev/null
+++ b/docs/assets/css/pygments/pastie.css
@@ -0,0 +1,60 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #888888 } /* Comment */
+.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.highlight .k { color: #008800; font-weight: bold } /* Keyword */
+.highlight .cm { color: #888888 } /* Comment.Multiline */
+.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
+.highlight .c1 { color: #888888 } /* Comment.Single */
+.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
+.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #aa0000 } /* Generic.Error */
+.highlight .gh { color: #303030 } /* Generic.Heading */
+.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #555555 } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #606060 } /* Generic.Subheading */
+.highlight .gt { color: #aa0000 } /* Generic.Traceback */
+.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #008800 } /* Keyword.Pseudo */
+.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
+.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
+.highlight .na { color: #336699 } /* Name.Attribute */
+.highlight .nb { color: #003388 } /* Name.Builtin */
+.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
+.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
+.highlight .nd { color: #555555 } /* Name.Decorator */
+.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
+.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
+.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
+.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
+.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #336699 } /* Name.Variable */
+.highlight .ow { color: #008800 } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
+.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
+.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
+.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
+.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
+.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
+.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
+.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
+.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
+.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
+.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
+.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
+.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
+.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
+.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
+.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #336699 } /* Name.Variable.Class */
+.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
+.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
+.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/perldoc.css b/docs/assets/css/pygments/perldoc.css
new file mode 100644
index 0000000..50516f2
--- /dev/null
+++ b/docs/assets/css/pygments/perldoc.css
@@ -0,0 +1,58 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #228B22 } /* Comment */
+.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.highlight .k { color: #8B008B; font-weight: bold } /* Keyword */
+.highlight .cm { color: #228B22 } /* Comment.Multiline */
+.highlight .cp { color: #1e889b } /* Comment.Preproc */
+.highlight .c1 { color: #228B22 } /* Comment.Single */
+.highlight .cs { color: #8B008B; font-weight: bold } /* Comment.Special */
+.highlight .gd { color: #aa0000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #aa0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00aa00 } /* Generic.Inserted */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #555555 } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #aa0000 } /* Generic.Traceback */
+.highlight .kc { color: #8B008B; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #8B008B; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #8B008B; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #8B008B; font-weight: bold } /* Keyword.Pseudo */
+.highlight .kr { color: #8B008B; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #a7a7a7; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #B452CD } /* Literal.Number */
+.highlight .s { color: #CD5555 } /* Literal.String */
+.highlight .na { color: #658b00 } /* Name.Attribute */
+.highlight .nb { color: #658b00 } /* Name.Builtin */
+.highlight .nc { color: #008b45; font-weight: bold } /* Name.Class */
+.highlight .no { color: #00688B } /* Name.Constant */
+.highlight .nd { color: #707a7c } /* Name.Decorator */
+.highlight .ne { color: #008b45; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #008b45 } /* Name.Function */
+.highlight .nn { color: #008b45; text-decoration: underline } /* Name.Namespace */
+.highlight .nt { color: #8B008B; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #00688B } /* Name.Variable */
+.highlight .ow { color: #8B008B } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #B452CD } /* Literal.Number.Float */
+.highlight .mh { color: #B452CD } /* Literal.Number.Hex */
+.highlight .mi { color: #B452CD } /* Literal.Number.Integer */
+.highlight .mo { color: #B452CD } /* Literal.Number.Oct */
+.highlight .sb { color: #CD5555 } /* Literal.String.Backtick */
+.highlight .sc { color: #CD5555 } /* Literal.String.Char */
+.highlight .sd { color: #CD5555 } /* Literal.String.Doc */
+.highlight .s2 { color: #CD5555 } /* Literal.String.Double */
+.highlight .se { color: #CD5555 } /* Literal.String.Escape */
+.highlight .sh { color: #1c7e71; font-style: italic } /* Literal.String.Heredoc */
+.highlight .si { color: #CD5555 } /* Literal.String.Interpol */
+.highlight .sx { color: #cb6c20 } /* Literal.String.Other */
+.highlight .sr { color: #1c7e71 } /* Literal.String.Regex */
+.highlight .s1 { color: #CD5555 } /* Literal.String.Single */
+.highlight .ss { color: #CD5555 } /* Literal.String.Symbol */
+.highlight .bp { color: #658b00 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #00688B } /* Name.Variable.Class */
+.highlight .vg { color: #00688B } /* Name.Variable.Global */
+.highlight .vi { color: #00688B } /* Name.Variable.Instance */
+.highlight .il { color: #B452CD } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/tango.css b/docs/assets/css/pygments/tango.css
new file mode 100644
index 0000000..bfd3803
--- /dev/null
+++ b/docs/assets/css/pygments/tango.css
@@ -0,0 +1,69 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #8f5902; font-style: italic } /* Comment */
+.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */
+.highlight .g { color: #000000 } /* Generic */
+.highlight .k { color: #204a87; font-weight: bold } /* Keyword */
+.highlight .l { color: #000000 } /* Literal */
+.highlight .n { color: #000000 } /* Name */
+.highlight .o { color: #ce5c00; font-weight: bold } /* Operator */
+.highlight .x { color: #000000 } /* Other */
+.highlight .p { color: #000000; font-weight: bold } /* Punctuation */
+.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */
+.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #a40000 } /* Generic.Deleted */
+.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #ef2929 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #000000; font-style: italic } /* Generic.Output */
+.highlight .gp { color: #8f5902 } /* Generic.Prompt */
+.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */
+.highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */
+.highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */
+.highlight .ld { color: #000000 } /* Literal.Date */
+.highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */
+.highlight .s { color: #4e9a06 } /* Literal.String */
+.highlight .na { color: #c4a000 } /* Name.Attribute */
+.highlight .nb { color: #204a87 } /* Name.Builtin */
+.highlight .nc { color: #000000 } /* Name.Class */
+.highlight .no { color: #000000 } /* Name.Constant */
+.highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */
+.highlight .ni { color: #ce5c00 } /* Name.Entity */
+.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #000000 } /* Name.Function */
+.highlight .nl { color: #f57900 } /* Name.Label */
+.highlight .nn { color: #000000 } /* Name.Namespace */
+.highlight .nx { color: #000000 } /* Name.Other */
+.highlight .py { color: #000000 } /* Name.Property */
+.highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #000000 } /* Name.Variable */
+.highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */
+.highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */
+.highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */
+.highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */
+.highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */
+.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */
+.highlight .sc { color: #4e9a06 } /* Literal.String.Char */
+.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */
+.highlight .se { color: #4e9a06 } /* Literal.String.Escape */
+.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */
+.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */
+.highlight .sx { color: #4e9a06 } /* Literal.String.Other */
+.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */
+.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */
+.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */
+.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #000000 } /* Name.Variable.Class */
+.highlight .vg { color: #000000 } /* Name.Variable.Global */
+.highlight .vi { color: #000000 } /* Name.Variable.Instance */
+.highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/trac.css b/docs/assets/css/pygments/trac.css
new file mode 100644
index 0000000..851ba3c
--- /dev/null
+++ b/docs/assets/css/pygments/trac.css
@@ -0,0 +1,59 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #999988; font-style: italic } /* Comment */
+.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.highlight .k { font-weight: bold } /* Keyword */
+.highlight .o { font-weight: bold } /* Operator */
+.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
+.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #aa0000 } /* Generic.Error */
+.highlight .gh { color: #999999 } /* Generic.Heading */
+.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #555555 } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
+.highlight .gt { color: #aa0000 } /* Generic.Traceback */
+.highlight .kc { font-weight: bold } /* Keyword.Constant */
+.highlight .kd { font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
+.highlight .kr { font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #009999 } /* Literal.Number */
+.highlight .s { color: #bb8844 } /* Literal.String */
+.highlight .na { color: #008080 } /* Name.Attribute */
+.highlight .nb { color: #999999 } /* Name.Builtin */
+.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
+.highlight .no { color: #008080 } /* Name.Constant */
+.highlight .ni { color: #800080 } /* Name.Entity */
+.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
+.highlight .nn { color: #555555 } /* Name.Namespace */
+.highlight .nt { color: #000080 } /* Name.Tag */
+.highlight .nv { color: #008080 } /* Name.Variable */
+.highlight .ow { font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #009999 } /* Literal.Number.Float */
+.highlight .mh { color: #009999 } /* Literal.Number.Hex */
+.highlight .mi { color: #009999 } /* Literal.Number.Integer */
+.highlight .mo { color: #009999 } /* Literal.Number.Oct */
+.highlight .sb { color: #bb8844 } /* Literal.String.Backtick */
+.highlight .sc { color: #bb8844 } /* Literal.String.Char */
+.highlight .sd { color: #bb8844 } /* Literal.String.Doc */
+.highlight .s2 { color: #bb8844 } /* Literal.String.Double */
+.highlight .se { color: #bb8844 } /* Literal.String.Escape */
+.highlight .sh { color: #bb8844 } /* Literal.String.Heredoc */
+.highlight .si { color: #bb8844 } /* Literal.String.Interpol */
+.highlight .sx { color: #bb8844 } /* Literal.String.Other */
+.highlight .sr { color: #808000 } /* Literal.String.Regex */
+.highlight .s1 { color: #bb8844 } /* Literal.String.Single */
+.highlight .ss { color: #bb8844 } /* Literal.String.Symbol */
+.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #008080 } /* Name.Variable.Class */
+.highlight .vg { color: #008080 } /* Name.Variable.Global */
+.highlight .vi { color: #008080 } /* Name.Variable.Instance */
+.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/vim.css b/docs/assets/css/pygments/vim.css
new file mode 100644
index 0000000..3af4a14
--- /dev/null
+++ b/docs/assets/css/pygments/vim.css
@@ -0,0 +1,70 @@
+.highlight pre { background-color: #222222 }
+.highlight .hll { background-color: #222222 }
+.highlight .c { color: #000080 } /* Comment */
+.highlight .err { color: #cccccc; border: 1px solid #FF0000 } /* Error */
+.highlight .g { color: #cccccc } /* Generic */
+.highlight .k { color: #cdcd00 } /* Keyword */
+.highlight .l { color: #cccccc } /* Literal */
+.highlight .n { color: #cccccc } /* Name */
+.highlight .o { color: #3399cc } /* Operator */
+.highlight .x { color: #cccccc } /* Other */
+.highlight .p { color: #cccccc } /* Punctuation */
+.highlight .cm { color: #000080 } /* Comment.Multiline */
+.highlight .cp { color: #000080 } /* Comment.Preproc */
+.highlight .c1 { color: #000080 } /* Comment.Single */
+.highlight .cs { color: #cd0000; font-weight: bold } /* Comment.Special */
+.highlight .gd { color: #cd0000 } /* Generic.Deleted */
+.highlight .ge { color: #cccccc; font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00cd00 } /* Generic.Inserted */
+.highlight .go { color: #808080 } /* Generic.Output */
+.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { color: #cccccc; font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0040D0 } /* Generic.Traceback */
+.highlight .kc { color: #cdcd00 } /* Keyword.Constant */
+.highlight .kd { color: #00cd00 } /* Keyword.Declaration */
+.highlight .kn { color: #cd00cd } /* Keyword.Namespace */
+.highlight .kp { color: #cdcd00 } /* Keyword.Pseudo */
+.highlight .kr { color: #cdcd00 } /* Keyword.Reserved */
+.highlight .kt { color: #00cd00 } /* Keyword.Type */
+.highlight .ld { color: #cccccc } /* Literal.Date */
+.highlight .m { color: #cd00cd } /* Literal.Number */
+.highlight .s { color: #cd0000 } /* Literal.String */
+.highlight .na { color: #cccccc } /* Name.Attribute */
+.highlight .nb { color: #cd00cd } /* Name.Builtin */
+.highlight .nc { color: #00cdcd } /* Name.Class */
+.highlight .no { color: #cccccc } /* Name.Constant */
+.highlight .nd { color: #cccccc } /* Name.Decorator */
+.highlight .ni { color: #cccccc } /* Name.Entity */
+.highlight .ne { color: #666699; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #cccccc } /* Name.Function */
+.highlight .nl { color: #cccccc } /* Name.Label */
+.highlight .nn { color: #cccccc } /* Name.Namespace */
+.highlight .nx { color: #cccccc } /* Name.Other */
+.highlight .py { color: #cccccc } /* Name.Property */
+.highlight .nt { color: #cccccc } /* Name.Tag */
+.highlight .nv { color: #00cdcd } /* Name.Variable */
+.highlight .ow { color: #cdcd00 } /* Operator.Word */
+.highlight .w { color: #cccccc } /* Text.Whitespace */
+.highlight .mf { color: #cd00cd } /* Literal.Number.Float */
+.highlight .mh { color: #cd00cd } /* Literal.Number.Hex */
+.highlight .mi { color: #cd00cd } /* Literal.Number.Integer */
+.highlight .mo { color: #cd00cd } /* Literal.Number.Oct */
+.highlight .sb { color: #cd0000 } /* Literal.String.Backtick */
+.highlight .sc { color: #cd0000 } /* Literal.String.Char */
+.highlight .sd { color: #cd0000 } /* Literal.String.Doc */
+.highlight .s2 { color: #cd0000 } /* Literal.String.Double */
+.highlight .se { color: #cd0000 } /* Literal.String.Escape */
+.highlight .sh { color: #cd0000 } /* Literal.String.Heredoc */
+.highlight .si { color: #cd0000 } /* Literal.String.Interpol */
+.highlight .sx { color: #cd0000 } /* Literal.String.Other */
+.highlight .sr { color: #cd0000 } /* Literal.String.Regex */
+.highlight .s1 { color: #cd0000 } /* Literal.String.Single */
+.highlight .ss { color: #cd0000 } /* Literal.String.Symbol */
+.highlight .bp { color: #cd00cd } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #00cdcd } /* Name.Variable.Class */
+.highlight .vg { color: #00cdcd } /* Name.Variable.Global */
+.highlight .vi { color: #00cdcd } /* Name.Variable.Instance */
+.highlight .il { color: #cd00cd } /* Literal.Number.Integer.Long */
diff --git a/docs/assets/css/pygments/vs.css b/docs/assets/css/pygments/vs.css
new file mode 100644
index 0000000..e1e55d8
--- /dev/null
+++ b/docs/assets/css/pygments/vs.css
@@ -0,0 +1,33 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight .c { color: #008000 } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #0000ff } /* Keyword */
+.highlight .cm { color: #008000 } /* Comment.Multiline */
+.highlight .cp { color: #0000ff } /* Comment.Preproc */
+.highlight .c1 { color: #008000 } /* Comment.Single */
+.highlight .cs { color: #008000 } /* Comment.Special */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gh { font-weight: bold } /* Generic.Heading */
+.highlight .gp { font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { font-weight: bold } /* Generic.Subheading */
+.highlight .kc { color: #0000ff } /* Keyword.Constant */
+.highlight .kd { color: #0000ff } /* Keyword.Declaration */
+.highlight .kn { color: #0000ff } /* Keyword.Namespace */
+.highlight .kp { color: #0000ff } /* Keyword.Pseudo */
+.highlight .kr { color: #0000ff } /* Keyword.Reserved */
+.highlight .kt { color: #2b91af } /* Keyword.Type */
+.highlight .s { color: #a31515 } /* Literal.String */
+.highlight .nc { color: #2b91af } /* Name.Class */
+.highlight .ow { color: #0000ff } /* Operator.Word */
+.highlight .sb { color: #a31515 } /* Literal.String.Backtick */
+.highlight .sc { color: #a31515 } /* Literal.String.Char */
+.highlight .sd { color: #a31515 } /* Literal.String.Doc */
+.highlight .s2 { color: #a31515 } /* Literal.String.Double */
+.highlight .se { color: #a31515 } /* Literal.String.Escape */
+.highlight .sh { color: #a31515 } /* Literal.String.Heredoc */
+.highlight .si { color: #a31515 } /* Literal.String.Interpol */
+.highlight .sx { color: #a31515 } /* Literal.String.Other */
+.highlight .sr { color: #a31515 } /* Literal.String.Regex */
+.highlight .s1 { color: #a31515 } /* Literal.String.Single */
+.highlight .ss { color: #a31515 } /* Literal.String.Symbol */
diff --git a/docs/assets/css/pygments/zenburn.css b/docs/assets/css/pygments/zenburn.css
new file mode 100644
index 0000000..287591d
--- /dev/null
+++ b/docs/assets/css/pygments/zenburn.css
@@ -0,0 +1,136 @@
+.highlight code, .highlight pre {
+color:#fdce93;
+background-color:#3f3f3f;
+}
+
+.highlight .hll {
+background-color:#222;
+}
+
+.highlight .err {
+color:#e37170;
+background-color:#3d3535;
+}
+
+.highlight .k {
+color:#f0dfaf;
+}
+
+.highlight .p {
+color:#41706f;
+}
+
+.highlight .cs {
+color:#cd0000;
+font-weight:700;
+}
+
+.highlight .gd {
+color:#cd0000;
+}
+
+.highlight .ge {
+color:#ccc;
+font-style:italic;
+}
+
+.highlight .gr {
+color:red;
+}
+
+.highlight .go {
+color:gray;
+}
+
+.highlight .gs {
+color:#ccc;
+font-weight:700;
+}
+
+.highlight .gu {
+color:purple;
+font-weight:700;
+}
+
+.highlight .gt {
+color:#0040D0;
+}
+
+.highlight .kc {
+color:#dca3a3;
+}
+
+.highlight .kd {
+color:#ffff86;
+}
+
+.highlight .kn {
+color:#dfaf8f;
+font-weight:700;
+}
+
+.highlight .kp {
+color:#cdcf99;
+}
+
+.highlight .kr {
+color:#cdcd00;
+}
+
+.highlight .ni {
+color:#c28182;
+}
+
+.highlight .ne {
+color:#c3bf9f;
+font-weight:700;
+}
+
+.highlight .nn {
+color:#8fbede;
+}
+
+.highlight .vi {
+color:#ffffc7;
+}
+
+.highlight .c,.preview-zenburn .highlight .g,.preview-zenburn .highlight .cm,.preview-zenburn .highlight .cp,.preview-zenburn .highlight .c1 {
+color:#7f9f7f;
+}
+
+.highlight .l,.preview-zenburn .highlight .x,.preview-zenburn .highlight .no,.preview-zenburn .highlight .nd,.preview-zenburn .highlight .nl,.preview-zenburn .highlight .nx,.preview-zenburn .highlight .py,.preview-zenburn .highlight .w {
+color:#ccc;
+}
+
+.highlight .n,.preview-zenburn .highlight .nv,.preview-zenburn .highlight .vg {
+color:#dcdccc;
+}
+
+.highlight .o,.preview-zenburn .highlight .ow {
+color:#f0efd0;
+}
+
+.highlight .gh,.preview-zenburn .highlight .gp {
+color:#dcdccc;
+font-weight:700;
+}
+
+.highlight .gi,.preview-zenburn .highlight .kt {
+color:#00cd00;
+}
+
+.highlight .ld,.preview-zenburn .highlight .s,.preview-zenburn .highlight .sb,.preview-zenburn .highlight .sc,.preview-zenburn .highlight .sd,.preview-zenburn .highlight .s2,.preview-zenburn .highlight .se,.preview-zenburn .highlight .sh,.preview-zenburn .highlight .si,.preview-zenburn .highlight .sx,.preview-zenburn .highlight .sr,.preview-zenburn .highlight .s1,.preview-zenburn .highlight .ss {
+color:#cc9393;
+}
+
+.highlight .m,.preview-zenburn .highlight .mf,.preview-zenburn .highlight .mh,.preview-zenburn .highlight .mi,.preview-zenburn .highlight .mo,.preview-zenburn .highlight .il {
+color:#8cd0d3;
+}
+
+.highlight .na,.preview-zenburn .highlight .nt {
+color:#9ac39f;
+}
+
+.highlight .nb,.preview-zenburn .highlight .nc,.preview-zenburn .highlight .nf,.preview-zenburn .highlight .bp,.preview-zenburn .highlight .vc {
+color:#efef8f;
+}
diff --git a/docs/assets/css/spec-style.sass b/docs/assets/css/spec-style.sass
new file mode 100644
index 0000000..7fbd02c
--- /dev/null
+++ b/docs/assets/css/spec-style.sass
@@ -0,0 +1,96 @@
+---
+---
+/*
+ * style.sass
+ */
+@import url('https://fonts.googleapis.com/css?family=Inconsolata')
+
+$monofont: 'Inconsolata', monospace
+$gridcolor: #ddd
+$gridweight: 2px
+
+body
+ font-family: Arial, sans-serif
+ margin: 10% 25% 10% 10%
+ line-height: 1.3
+
+a
+ color: navy
+ text-decoration: none
+ &:visited
+ color: navy
+ text-decoration: none
+ &:hover
+ text-decoration: underline
+
+pre
+ //font-family: $monofont
+ //border: $gridweight solid $gridcolor
+ //background-color: #f7f7f7
+ //padding: 1em
+ //margin-left: 1em
+ //overflow-x: auto
+
+code
+ //color: #060
+ //background-color: #f2f2f2
+ font-family: $monofont
+
+table
+ border-collapse: collapse
+ min-width: 50%
+ margin-left: 1em
+
+th, td
+ border: $gridweight solid #ccc
+ padding: .5em
+
+th
+ background-color: #333
+ color: #fff
+
+table.terms
+ th
+ display: none
+ td
+ vertical-align: top
+
+table.conventions
+ th
+ display: none
+ td
+ vertical-align: top
+ td:first-child
+ white-space: nowrap
+
+table.nohead
+ th
+ display: none
+
+table.xyhead
+ th, td:first-child
+ background-color: #9bbb59
+ th
+ color: #000
+ font-weight: normal
+
+figure.highlight
+ background-color: #f2f2f2
+ padding-left: 1em
+ padding-right: 1em
+ border: $gridweight solid #ccc
+
+div.draco-syntax pre
+ background-color: #fff
+ background-image: linear-gradient(90deg, transparent 580px, #abced4 580px, #abced4 582px, transparent 582px), linear-gradient($gridcolor .1em, transparent .1em)
+ background-size: 100% 1.3em
+ border-left: $gridweight solid $gridcolor
+ border-right: $gridweight solid $gridcolor
+ border-bottom: $gridweight solid $gridcolor
+ white-space: pre
+ font-family: $monofont
+ font-size: 1em
+ padding-left: 1em
+ margin-left: 1em
+ width: 720px
+ //overflow: auto
diff --git a/docs/assets/favicon.ico b/docs/assets/favicon.ico
new file mode 100644
index 0000000..4ca5dba
Binary files /dev/null and b/docs/assets/favicon.ico differ
diff --git a/docs/assets/js/ASCIIMathML.js b/docs/assets/js/ASCIIMathML.js
new file mode 100644
index 0000000..727111c
--- /dev/null
+++ b/docs/assets/js/ASCIIMathML.js
@@ -0,0 +1,1127 @@
+/*
+ASCIIMathML.js
+==============
+This file contains JavaScript functions to convert ASCII math notation
+and (some) LaTeX to Presentation MathML. The conversion is done while the
+HTML page loads, and should work with Firefox and other browsers that can
+render MathML.
+
+Just add the next line to your HTML page with this file in the same folder:
+
+
+
+Version 2.2 Mar 3, 2014.
+Latest version at https://github.com/mathjax/asciimathml
+If you use it on a webpage, please send the URL to jipsen@chapman.edu
+
+Copyright (c) 2014 Peter Jipsen and other ASCIIMathML.js contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+var asciimath = {};
+
+(function(){
+var mathcolor = "blue"; // change it to "" (to inherit) or another color
+var mathfontsize = "1em"; // change to e.g. 1.2em for larger math
+var mathfontfamily = "serif"; // change to "" to inherit (works in IE)
+ // or another family (e.g. "arial")
+var automathrecognize = false; // writing "amath" on page makes this true
+var checkForMathML = true; // check if browser can display MathML
+var notifyIfNoMathML = true; // display note at top if no MathML capability
+var alertIfNoMathML = false; // show alert box if no MathML capability
+var translateOnLoad = true; // set to false to do call translators from js
+var translateASCIIMath = true; // false to preserve `..`
+var displaystyle = true; // puts limits above and below large operators
+var showasciiformulaonhover = true; // helps students learn ASCIIMath
+var decimalsign = "."; // change to "," if you like, beware of `(1,2)`!
+var AMdelimiter1 = "`", AMescape1 = "\\\\`"; // can use other characters
+var AMdocumentId = "wikitext" // PmWiki element containing math (default=body)
+var fixphi = true; //false to return to legacy phi/varphi mapping
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+
+var isIE = (navigator.appName.slice(0,9)=="Microsoft");
+var noMathML = false, translated = false;
+
+if (isIE) { // add MathPlayer info to IE webpages
+ document.write(" ");
+ document.write("");
+}
+
+// Add a stylesheet, replacing any previous custom stylesheet (adapted from TW)
+function setStylesheet(s) {
+ var id = "AMMLcustomStyleSheet";
+ var n = document.getElementById(id);
+ if(document.createStyleSheet) {
+ // Test for IE's non-standard createStyleSheet method
+ if(n)
+ n.parentNode.removeChild(n);
+ // This failed without the
+ document.getElementsByTagName("head")[0].insertAdjacentHTML("beforeEnd"," ");
+ } else {
+ if(n) {
+ n.replaceChild(document.createTextNode(s),n.firstChild);
+ } else {
+ n = document.createElement("style");
+ n.type = "text/css";
+ n.id = id;
+ n.appendChild(document.createTextNode(s));
+ document.getElementsByTagName("head")[0].appendChild(n);
+ }
+ }
+}
+
+setStylesheet("#AMMLcloseDiv \{font-size:0.8em; padding-top:1em; color:#014\}\n#AMMLwarningBox \{position:absolute; width:100%; top:0; left:0; z-index:200; text-align:center; font-size:1em; font-weight:bold; padding:0.5em 0 0.5em 0; color:#ffc; background:#c30\}");
+
+function init(){
+ var msg, warnings = new Array();
+ if (document.getElementById==null){
+ alert("This webpage requires a recent browser such as Mozilla Firefox");
+ return null;
+ }
+ if (checkForMathML && (msg = checkMathML())) warnings.push(msg);
+ if (warnings.length>0) displayWarnings(warnings);
+ if (!noMathML) initSymbols();
+ return true;
+}
+
+function checkMathML(){
+ if (navigator.appName.slice(0,8)=="Netscape")
+ if (navigator.appVersion.slice(0,1)>="5") noMathML = null;
+ else noMathML = true;
+ else if (navigator.appName.slice(0,9)=="Microsoft")
+ try {
+ var ActiveX = new ActiveXObject("MathPlayer.Factory.1");
+ noMathML = null;
+ } catch (e) {
+ noMathML = true;
+ }
+ else if (navigator.appName.slice(0,5)=="Opera")
+ if (navigator.appVersion.slice(0,3)>="9.5") noMathML = null;
+ else noMathML = true;
+//noMathML = true; //uncomment to check
+ if (noMathML && notifyIfNoMathML) {
+ var msg = "To view the ASCIIMathML notation use Internet Explorer + MathPlayer or Mozilla Firefox 2.0 or later.";
+ if (alertIfNoMathML)
+ alert(msg);
+ else return msg;
+ }
+}
+
+function hideWarning(){
+ var body = document.getElementsByTagName("body")[0];
+ body.removeChild(document.getElementById('AMMLwarningBox'));
+ body.onclick = null;
+}
+
+function displayWarnings(warnings) {
+ var i, frag, nd = createElementXHTML("div");
+ var body = document.getElementsByTagName("body")[0];
+ body.onclick=hideWarning;
+ nd.id = 'AMMLwarningBox';
+ for (i=0; i<", tag:"mo", output:"\u22C9", tex:"ltimes", ttype:CONST},
+{input:"><|", tag:"mo", output:"\u22CA", tex:"rtimes", ttype:CONST},
+{input:"|><|", tag:"mo", output:"\u22C8", tex:"bowtie", ttype:CONST},
+{input:"-:", tag:"mo", output:"\u00F7", tex:"div", ttype:CONST},
+{input:"divide", tag:"mo", output:"-:", tex:null, ttype:DEFINITION},
+{input:"@", tag:"mo", output:"\u2218", tex:"circ", ttype:CONST},
+{input:"o+", tag:"mo", output:"\u2295", tex:"oplus", ttype:CONST},
+{input:"ox", tag:"mo", output:"\u2297", tex:"otimes", ttype:CONST},
+{input:"o.", tag:"mo", output:"\u2299", tex:"odot", ttype:CONST},
+{input:"sum", tag:"mo", output:"\u2211", tex:null, ttype:UNDEROVER},
+{input:"prod", tag:"mo", output:"\u220F", tex:null, ttype:UNDEROVER},
+{input:"^^", tag:"mo", output:"\u2227", tex:"wedge", ttype:CONST},
+{input:"^^^", tag:"mo", output:"\u22C0", tex:"bigwedge", ttype:UNDEROVER},
+{input:"vv", tag:"mo", output:"\u2228", tex:"vee", ttype:CONST},
+{input:"vvv", tag:"mo", output:"\u22C1", tex:"bigvee", ttype:UNDEROVER},
+{input:"nn", tag:"mo", output:"\u2229", tex:"cap", ttype:CONST},
+{input:"nnn", tag:"mo", output:"\u22C2", tex:"bigcap", ttype:UNDEROVER},
+{input:"uu", tag:"mo", output:"\u222A", tex:"cup", ttype:CONST},
+{input:"uuu", tag:"mo", output:"\u22C3", tex:"bigcup", ttype:UNDEROVER},
+
+//binary relation symbols
+{input:"!=", tag:"mo", output:"\u2260", tex:"ne", ttype:CONST},
+{input:":=", tag:"mo", output:":=", tex:null, ttype:CONST},
+{input:"lt", tag:"mo", output:"<", tex:null, ttype:CONST},
+{input:"<=", tag:"mo", output:"\u2264", tex:"le", ttype:CONST},
+{input:"lt=", tag:"mo", output:"\u2264", tex:"leq", ttype:CONST},
+{input:"gt", tag:"mo", output:">", tex:null, ttype:CONST},
+{input:">=", tag:"mo", output:"\u2265", tex:"ge", ttype:CONST},
+{input:"gt=", tag:"mo", output:"\u2265", tex:"geq", ttype:CONST},
+{input:"-<", tag:"mo", output:"\u227A", tex:"prec", ttype:CONST},
+{input:"-lt", tag:"mo", output:"\u227A", tex:null, ttype:CONST},
+{input:">-", tag:"mo", output:"\u227B", tex:"succ", ttype:CONST},
+{input:"-<=", tag:"mo", output:"\u2AAF", tex:"preceq", ttype:CONST},
+{input:">-=", tag:"mo", output:"\u2AB0", tex:"succeq", ttype:CONST},
+{input:"in", tag:"mo", output:"\u2208", tex:null, ttype:CONST},
+{input:"!in", tag:"mo", output:"\u2209", tex:"notin", ttype:CONST},
+{input:"sub", tag:"mo", output:"\u2282", tex:"subset", ttype:CONST},
+{input:"sup", tag:"mo", output:"\u2283", tex:"supset", ttype:CONST},
+{input:"sube", tag:"mo", output:"\u2286", tex:"subseteq", ttype:CONST},
+{input:"supe", tag:"mo", output:"\u2287", tex:"supseteq", ttype:CONST},
+{input:"-=", tag:"mo", output:"\u2261", tex:"equiv", ttype:CONST},
+{input:"~=", tag:"mo", output:"\u2245", tex:"cong", ttype:CONST},
+{input:"~~", tag:"mo", output:"\u2248", tex:"approx", ttype:CONST},
+{input:"prop", tag:"mo", output:"\u221D", tex:"propto", ttype:CONST},
+
+//logical symbols
+{input:"and", tag:"mtext", output:"and", tex:null, ttype:SPACE},
+{input:"or", tag:"mtext", output:"or", tex:null, ttype:SPACE},
+{input:"not", tag:"mo", output:"\u00AC", tex:"neg", ttype:CONST},
+{input:"=>", tag:"mo", output:"\u21D2", tex:"implies", ttype:CONST},
+{input:"if", tag:"mo", output:"if", tex:null, ttype:SPACE},
+{input:"<=>", tag:"mo", output:"\u21D4", tex:"iff", ttype:CONST},
+{input:"AA", tag:"mo", output:"\u2200", tex:"forall", ttype:CONST},
+{input:"EE", tag:"mo", output:"\u2203", tex:"exists", ttype:CONST},
+{input:"_|_", tag:"mo", output:"\u22A5", tex:"bot", ttype:CONST},
+{input:"TT", tag:"mo", output:"\u22A4", tex:"top", ttype:CONST},
+{input:"|--", tag:"mo", output:"\u22A2", tex:"vdash", ttype:CONST},
+{input:"|==", tag:"mo", output:"\u22A8", tex:"models", ttype:CONST},
+
+//grouping brackets
+{input:"(", tag:"mo", output:"(", tex:null, ttype:LEFTBRACKET},
+{input:")", tag:"mo", output:")", tex:null, ttype:RIGHTBRACKET},
+{input:"[", tag:"mo", output:"[", tex:null, ttype:LEFTBRACKET},
+{input:"]", tag:"mo", output:"]", tex:null, ttype:RIGHTBRACKET},
+{input:"{", tag:"mo", output:"{", tex:null, ttype:LEFTBRACKET},
+{input:"}", tag:"mo", output:"}", tex:null, ttype:RIGHTBRACKET},
+{input:"|", tag:"mo", output:"|", tex:null, ttype:LEFTRIGHT},
+//{input:"||", tag:"mo", output:"||", tex:null, ttype:LEFTRIGHT},
+{input:"(:", tag:"mo", output:"\u2329", tex:"langle", ttype:LEFTBRACKET},
+{input:":)", tag:"mo", output:"\u232A", tex:"rangle", ttype:RIGHTBRACKET},
+{input:"<<", tag:"mo", output:"\u2329", tex:null, ttype:LEFTBRACKET},
+{input:">>", tag:"mo", output:"\u232A", tex:null, ttype:RIGHTBRACKET},
+{input:"{:", tag:"mo", output:"{:", tex:null, ttype:LEFTBRACKET, invisible:true},
+{input:":}", tag:"mo", output:":}", tex:null, ttype:RIGHTBRACKET, invisible:true},
+
+//miscellaneous symbols
+{input:"int", tag:"mo", output:"\u222B", tex:null, ttype:CONST},
+{input:"dx", tag:"mi", output:"{:d x:}", tex:null, ttype:DEFINITION},
+{input:"dy", tag:"mi", output:"{:d y:}", tex:null, ttype:DEFINITION},
+{input:"dz", tag:"mi", output:"{:d z:}", tex:null, ttype:DEFINITION},
+{input:"dt", tag:"mi", output:"{:d t:}", tex:null, ttype:DEFINITION},
+{input:"oint", tag:"mo", output:"\u222E", tex:null, ttype:CONST},
+{input:"del", tag:"mo", output:"\u2202", tex:"partial", ttype:CONST},
+{input:"grad", tag:"mo", output:"\u2207", tex:"nabla", ttype:CONST},
+{input:"+-", tag:"mo", output:"\u00B1", tex:"pm", ttype:CONST},
+{input:"O/", tag:"mo", output:"\u2205", tex:"emptyset", ttype:CONST},
+{input:"oo", tag:"mo", output:"\u221E", tex:"infty", ttype:CONST},
+{input:"aleph", tag:"mo", output:"\u2135", tex:null, ttype:CONST},
+{input:"...", tag:"mo", output:"...", tex:"ldots", ttype:CONST},
+{input:":.", tag:"mo", output:"\u2234", tex:"therefore", ttype:CONST},
+{input:":'", tag:"mo", output:"\u2235", tex:"because", ttype:CONST},
+{input:"/_", tag:"mo", output:"\u2220", tex:"angle", ttype:CONST},
+{input:"/_\\", tag:"mo", output:"\u25B3", tex:"triangle", ttype:CONST},
+{input:"'", tag:"mo", output:"\u2032", tex:"prime", ttype:CONST},
+{input:"tilde", tag:"mover", output:"~", tex:null, ttype:UNARY, acc:true},
+{input:"\\ ", tag:"mo", output:"\u00A0", tex:null, ttype:CONST},
+{input:"frown", tag:"mo", output:"\u2322", tex:null, ttype:CONST},
+{input:"quad", tag:"mo", output:"\u00A0\u00A0", tex:null, ttype:CONST},
+{input:"qquad", tag:"mo", output:"\u00A0\u00A0\u00A0\u00A0", tex:null, ttype:CONST},
+{input:"cdots", tag:"mo", output:"\u22EF", tex:null, ttype:CONST},
+{input:"vdots", tag:"mo", output:"\u22EE", tex:null, ttype:CONST},
+{input:"ddots", tag:"mo", output:"\u22F1", tex:null, ttype:CONST},
+{input:"diamond", tag:"mo", output:"\u22C4", tex:null, ttype:CONST},
+{input:"square", tag:"mo", output:"\u25A1", tex:null, ttype:CONST},
+{input:"|__", tag:"mo", output:"\u230A", tex:"lfloor", ttype:CONST},
+{input:"__|", tag:"mo", output:"\u230B", tex:"rfloor", ttype:CONST},
+{input:"|~", tag:"mo", output:"\u2308", tex:"lceiling", ttype:CONST},
+{input:"~|", tag:"mo", output:"\u2309", tex:"rceiling", ttype:CONST},
+{input:"CC", tag:"mo", output:"\u2102", tex:null, ttype:CONST},
+{input:"NN", tag:"mo", output:"\u2115", tex:null, ttype:CONST},
+{input:"QQ", tag:"mo", output:"\u211A", tex:null, ttype:CONST},
+{input:"RR", tag:"mo", output:"\u211D", tex:null, ttype:CONST},
+{input:"ZZ", tag:"mo", output:"\u2124", tex:null, ttype:CONST},
+{input:"f", tag:"mi", output:"f", tex:null, ttype:UNARY, func:true},
+{input:"g", tag:"mi", output:"g", tex:null, ttype:UNARY, func:true},
+
+//standard functions
+{input:"lim", tag:"mo", output:"lim", tex:null, ttype:UNDEROVER},
+{input:"Lim", tag:"mo", output:"Lim", tex:null, ttype:UNDEROVER},
+{input:"sin", tag:"mo", output:"sin", tex:null, ttype:UNARY, func:true},
+{input:"cos", tag:"mo", output:"cos", tex:null, ttype:UNARY, func:true},
+{input:"tan", tag:"mo", output:"tan", tex:null, ttype:UNARY, func:true},
+{input:"sinh", tag:"mo", output:"sinh", tex:null, ttype:UNARY, func:true},
+{input:"cosh", tag:"mo", output:"cosh", tex:null, ttype:UNARY, func:true},
+{input:"tanh", tag:"mo", output:"tanh", tex:null, ttype:UNARY, func:true},
+{input:"cot", tag:"mo", output:"cot", tex:null, ttype:UNARY, func:true},
+{input:"sec", tag:"mo", output:"sec", tex:null, ttype:UNARY, func:true},
+{input:"csc", tag:"mo", output:"csc", tex:null, ttype:UNARY, func:true},
+{input:"arcsin", tag:"mo", output:"arcsin", tex:null, ttype:UNARY, func:true},
+{input:"arccos", tag:"mo", output:"arccos", tex:null, ttype:UNARY, func:true},
+{input:"arctan", tag:"mo", output:"arctan", tex:null, ttype:UNARY, func:true},
+{input:"coth", tag:"mo", output:"coth", tex:null, ttype:UNARY, func:true},
+{input:"sech", tag:"mo", output:"sech", tex:null, ttype:UNARY, func:true},
+{input:"csch", tag:"mo", output:"csch", tex:null, ttype:UNARY, func:true},
+{input:"exp", tag:"mo", output:"exp", tex:null, ttype:UNARY, func:true},
+{input:"abs", tag:"mo", output:"abs", tex:null, ttype:UNARY, rewriteleftright:["|","|"]},
+{input:"norm", tag:"mo", output:"norm", tex:null, ttype:UNARY, rewriteleftright:["\u2225","\u2225"]},
+{input:"floor", tag:"mo", output:"floor", tex:null, ttype:UNARY, rewriteleftright:["\u230A","\u230B"]},
+{input:"ceil", tag:"mo", output:"ceil", tex:null, ttype:UNARY, rewriteleftright:["\u2308","\u2309"]},
+{input:"log", tag:"mo", output:"log", tex:null, ttype:UNARY, func:true},
+{input:"ln", tag:"mo", output:"ln", tex:null, ttype:UNARY, func:true},
+{input:"det", tag:"mo", output:"det", tex:null, ttype:UNARY, func:true},
+{input:"dim", tag:"mo", output:"dim", tex:null, ttype:CONST},
+{input:"mod", tag:"mo", output:"mod", tex:null, ttype:CONST},
+{input:"gcd", tag:"mo", output:"gcd", tex:null, ttype:UNARY, func:true},
+{input:"lcm", tag:"mo", output:"lcm", tex:null, ttype:UNARY, func:true},
+{input:"lub", tag:"mo", output:"lub", tex:null, ttype:CONST},
+{input:"glb", tag:"mo", output:"glb", tex:null, ttype:CONST},
+{input:"min", tag:"mo", output:"min", tex:null, ttype:UNDEROVER},
+{input:"max", tag:"mo", output:"max", tex:null, ttype:UNDEROVER},
+
+//arrows
+{input:"uarr", tag:"mo", output:"\u2191", tex:"uparrow", ttype:CONST},
+{input:"darr", tag:"mo", output:"\u2193", tex:"downarrow", ttype:CONST},
+{input:"rarr", tag:"mo", output:"\u2192", tex:"rightarrow", ttype:CONST},
+{input:"->", tag:"mo", output:"\u2192", tex:"to", ttype:CONST},
+{input:">->", tag:"mo", output:"\u21A3", tex:"rightarrowtail", ttype:CONST},
+{input:"->>", tag:"mo", output:"\u21A0", tex:"twoheadrightarrow", ttype:CONST},
+{input:">->>", tag:"mo", output:"\u2916", tex:"twoheadrightarrowtail", ttype:CONST},
+{input:"|->", tag:"mo", output:"\u21A6", tex:"mapsto", ttype:CONST},
+{input:"larr", tag:"mo", output:"\u2190", tex:"leftarrow", ttype:CONST},
+{input:"harr", tag:"mo", output:"\u2194", tex:"leftrightarrow", ttype:CONST},
+{input:"rArr", tag:"mo", output:"\u21D2", tex:"Rightarrow", ttype:CONST},
+{input:"lArr", tag:"mo", output:"\u21D0", tex:"Leftarrow", ttype:CONST},
+{input:"hArr", tag:"mo", output:"\u21D4", tex:"Leftrightarrow", ttype:CONST},
+//commands with argument
+{input:"sqrt", tag:"msqrt", output:"sqrt", tex:null, ttype:UNARY},
+{input:"root", tag:"mroot", output:"root", tex:null, ttype:BINARY},
+{input:"frac", tag:"mfrac", output:"/", tex:null, ttype:BINARY},
+{input:"/", tag:"mfrac", output:"/", tex:null, ttype:INFIX},
+{input:"stackrel", tag:"mover", output:"stackrel", tex:null, ttype:BINARY},
+{input:"overset", tag:"mover", output:"stackrel", tex:null, ttype:BINARY},
+{input:"underset", tag:"munder", output:"stackrel", tex:null, ttype:BINARY},
+{input:"_", tag:"msub", output:"_", tex:null, ttype:INFIX},
+{input:"^", tag:"msup", output:"^", tex:null, ttype:INFIX},
+{input:"hat", tag:"mover", output:"\u005E", tex:null, ttype:UNARY, acc:true},
+{input:"bar", tag:"mover", output:"\u00AF", tex:"overline", ttype:UNARY, acc:true},
+{input:"vec", tag:"mover", output:"\u2192", tex:null, ttype:UNARY, acc:true},
+{input:"dot", tag:"mover", output:".", tex:null, ttype:UNARY, acc:true},
+{input:"ddot", tag:"mover", output:"..", tex:null, ttype:UNARY, acc:true},
+{input:"ul", tag:"munder", output:"\u0332", tex:"underline", ttype:UNARY, acc:true},
+{input:"ubrace", tag:"munder", output:"\u23DF", tex:"underbrace", ttype:UNARYUNDEROVER, acc:true},
+{input:"obrace", tag:"mover", output:"\u23DE", tex:"overbrace", ttype:UNARYUNDEROVER, acc:true},
+{input:"text", tag:"mtext", output:"text", tex:null, ttype:TEXT},
+{input:"mbox", tag:"mtext", output:"mbox", tex:null, ttype:TEXT},
+{input:"color", tag:"mstyle", ttype:BINARY},
+{input:"cancel", tag:"menclose", output:"cancel", tex:null, ttype:UNARY},
+AMquote,
+{input:"bb", tag:"mstyle", atname:"mathvariant", atval:"bold", output:"bb", tex:null, ttype:UNARY},
+{input:"mathbf", tag:"mstyle", atname:"mathvariant", atval:"bold", output:"mathbf", tex:null, ttype:UNARY},
+{input:"sf", tag:"mstyle", atname:"mathvariant", atval:"sans-serif", output:"sf", tex:null, ttype:UNARY},
+{input:"mathsf", tag:"mstyle", atname:"mathvariant", atval:"sans-serif", output:"mathsf", tex:null, ttype:UNARY},
+{input:"bbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", output:"bbb", tex:null, ttype:UNARY, codes:AMbbb},
+{input:"mathbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", output:"mathbb", tex:null, ttype:UNARY, codes:AMbbb},
+{input:"cc", tag:"mstyle", atname:"mathvariant", atval:"script", output:"cc", tex:null, ttype:UNARY, codes:AMcal},
+{input:"mathcal", tag:"mstyle", atname:"mathvariant", atval:"script", output:"mathcal", tex:null, ttype:UNARY, codes:AMcal},
+{input:"tt", tag:"mstyle", atname:"mathvariant", atval:"monospace", output:"tt", tex:null, ttype:UNARY},
+{input:"mathtt", tag:"mstyle", atname:"mathvariant", atval:"monospace", output:"mathtt", tex:null, ttype:UNARY},
+{input:"fr", tag:"mstyle", atname:"mathvariant", atval:"fraktur", output:"fr", tex:null, ttype:UNARY, codes:AMfrk},
+{input:"mathfrak", tag:"mstyle", atname:"mathvariant", atval:"fraktur", output:"mathfrak", tex:null, ttype:UNARY, codes:AMfrk}
+];
+
+function compareNames(s1,s2) {
+ if (s1.input > s2.input) return 1
+ else return -1;
+}
+
+var AMnames = []; //list of input symbols
+
+function initSymbols() {
+ var i;
+ var symlen = AMsymbols.length;
+ for (i=0; i=n where str appears or would be inserted
+// assumes arr is sorted
+ if (n==0) {
+ var h,m;
+ n = -1;
+ h = arr.length;
+ while (n+1> 1;
+ if (arr[m]=str
+}
+
+function AMgetSymbol(str) {
+//return maximal initial substring of str that appears in names
+//return null if there is none
+ var k = 0; //new pos
+ var j = 0; //old pos
+ var mk; //match pos
+ var st;
+ var tagst;
+ var match = "";
+ var more = true;
+ for (var i=1; i<=str.length && more; i++) {
+ st = str.slice(0,i); //initial substring of length i
+ j = k;
+ k = position(AMnames, st, j);
+ if (k=AMnames[k];
+ }
+ AMpreviousSymbol=AMcurrentSymbol;
+ if (match!=""){
+ AMcurrentSymbol=AMsymbols[mk].ttype;
+ return AMsymbols[mk];
+ }
+// if str[0] is a digit or - return maxsubstring of digits.digits
+ AMcurrentSymbol=CONST;
+ k = 1;
+ st = str.slice(0,1);
+ var integ = true;
+ while ("0"<=st && st<="9" && k<=str.length) {
+ st = str.slice(k,k+1);
+ k++;
+ }
+ if (st == decimalsign) {
+ st = str.slice(k,k+1);
+ if ("0"<=st && st<="9") {
+ integ = false;
+ k++;
+ while ("0"<=st && st<="9" && k<=str.length) {
+ st = str.slice(k,k+1);
+ k++;
+ }
+ }
+ }
+ if ((integ && k>1) || k>2) {
+ st = str.slice(0,k-1);
+ tagst = "mn";
+ } else {
+ k = 2;
+ st = str.slice(0,1); //take 1 character
+ tagst = (("A">st || st>"Z") && ("a">st || st>"z")?"mo":"mi");
+ }
+ if (st=="-" && AMpreviousSymbol==INFIX) {
+ AMcurrentSymbol = INFIX; //trick "/" into recognizing "-" on second parse
+ return {input:st, tag:tagst, output:st, ttype:UNARY, func:true};
+ }
+ return {input:st, tag:tagst, output:st, ttype:CONST};
+}
+
+function AMremoveBrackets(node) {
+ var st;
+ if (!node.hasChildNodes()) { return; }
+ if (node.firstChild.hasChildNodes() && (node.nodeName=="mrow" || node.nodeName=="M:MROW")) {
+ st = node.firstChild.firstChild.nodeValue;
+ if (st=="(" || st=="[" || st=="{") node.removeChild(node.firstChild);
+ }
+ if (node.lastChild.hasChildNodes() && (node.nodeName=="mrow" || node.nodeName=="M:MROW")) {
+ st = node.lastChild.firstChild.nodeValue;
+ if (st==")" || st=="]" || st=="}") node.removeChild(node.lastChild);
+ }
+}
+
+/*Parsing ASCII math expressions with the following grammar
+v ::= [A-Za-z] | greek letters | numbers | other constant symbols
+u ::= sqrt | text | bb | other unary symbols for font commands
+b ::= frac | root | stackrel binary symbols
+l ::= ( | [ | { | (: | {: left brackets
+r ::= ) | ] | } | :) | :} right brackets
+S ::= v | lEr | uS | bSS Simple expression
+I ::= S_S | S^S | S_S^S | S Intermediate expression
+E ::= IE | I/I Expression
+Each terminal symbol is translated into a corresponding mathml node.*/
+
+var AMnestingDepth,AMpreviousSymbol,AMcurrentSymbol;
+
+function AMparseSexpr(str) { //parses str and returns [node,tailstr]
+ var symbol, node, result, i, st,// rightvert = false,
+ newFrag = document.createDocumentFragment();
+ str = AMremoveCharsAndBlanks(str,0);
+ symbol = AMgetSymbol(str); //either a token or a bracket or empty
+ if (symbol == null || symbol.ttype == RIGHTBRACKET && AMnestingDepth > 0) {
+ return [null,str];
+ }
+ if (symbol.ttype == DEFINITION) {
+ str = symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length);
+ symbol = AMgetSymbol(str);
+ }
+ switch (symbol.ttype) { case UNDEROVER:
+ case CONST:
+ str = AMremoveCharsAndBlanks(str,symbol.input.length);
+ return [createMmlNode(symbol.tag, //its a constant
+ document.createTextNode(symbol.output)),str];
+ case LEFTBRACKET: //read (expr+)
+ AMnestingDepth++;
+ str = AMremoveCharsAndBlanks(str,symbol.input.length);
+ result = AMparseExpr(str,true);
+ AMnestingDepth--;
+ if (typeof symbol.invisible == "boolean" && symbol.invisible)
+ node = createMmlNode("mrow",result[0]);
+ else {
+ node = createMmlNode("mo",document.createTextNode(symbol.output));
+ node = createMmlNode("mrow",node);
+ node.appendChild(result[0]);
+ }
+ return [node,result[1]];
+ case TEXT:
+ if (symbol!=AMquote) str = AMremoveCharsAndBlanks(str,symbol.input.length);
+ if (str.charAt(0)=="{") i=str.indexOf("}");
+ else if (str.charAt(0)=="(") i=str.indexOf(")");
+ else if (str.charAt(0)=="[") i=str.indexOf("]");
+ else if (symbol==AMquote) i=str.slice(1).indexOf("\"")+1;
+ else i = 0;
+ if (i==-1) i = str.length;
+ st = str.slice(1,i);
+ if (st.charAt(0) == " ") {
+ node = createMmlNode("mspace");
+ node.setAttribute("width","1ex");
+ newFrag.appendChild(node);
+ }
+ newFrag.appendChild(
+ createMmlNode(symbol.tag,document.createTextNode(st)));
+ if (st.charAt(st.length-1) == " ") {
+ node = createMmlNode("mspace");
+ node.setAttribute("width","1ex");
+ newFrag.appendChild(node);
+ }
+ str = AMremoveCharsAndBlanks(str,i+1);
+ return [createMmlNode("mrow",newFrag),str];
+ case UNARYUNDEROVER:
+ case UNARY:
+ str = AMremoveCharsAndBlanks(str,symbol.input.length);
+ result = AMparseSexpr(str);
+ if (result[0]==null) return [createMmlNode(symbol.tag,
+ document.createTextNode(symbol.output)),str];
+ if (typeof symbol.func == "boolean" && symbol.func) { // functions hack
+ st = str.charAt(0);
+ if (st=="^" || st=="_" || st=="/" || st=="|" || st=="," ||
+ (symbol.input.length==1 && symbol.input.match(/\w/) && st!="(")) {
+ return [createMmlNode(symbol.tag,
+ document.createTextNode(symbol.output)),str];
+ } else {
+ node = createMmlNode("mrow",
+ createMmlNode(symbol.tag,document.createTextNode(symbol.output)));
+ node.appendChild(result[0]);
+ return [node,result[1]];
+ }
+ }
+ AMremoveBrackets(result[0]);
+ if (symbol.input == "sqrt") { // sqrt
+ return [createMmlNode(symbol.tag,result[0]),result[1]];
+ } else if (typeof symbol.rewriteleftright != "undefined") { // abs, floor, ceil
+ node = createMmlNode("mrow", createMmlNode("mo",document.createTextNode(symbol.rewriteleftright[0])));
+ node.appendChild(result[0]);
+ node.appendChild(createMmlNode("mo",document.createTextNode(symbol.rewriteleftright[1])));
+ return [node,result[1]];
+ } else if (symbol.input == "cancel") { // cancel
+ node = createMmlNode(symbol.tag,result[0]);
+ node.setAttribute("notation","updiagonalstrike");
+ return [node,result[1]];
+ } else if (typeof symbol.acc == "boolean" && symbol.acc) { // accent
+ node = createMmlNode(symbol.tag,result[0]);
+ node.appendChild(createMmlNode("mo",document.createTextNode(symbol.output)));
+ return [node,result[1]];
+ } else { // font change command
+ if (!isIE && typeof symbol.codes != "undefined") {
+ for (i=0; i64 && st.charCodeAt(j)<91)
+ newst = newst + symbol.codes[st.charCodeAt(j)-65];
+ else if (st.charCodeAt(j)>96 && st.charCodeAt(j)<123)
+ newst = newst + symbol.codes[st.charCodeAt(j)-71];
+ else newst = newst + st.charAt(j);
+ if (result[0].nodeName=="mi")
+ result[0]=createMmlNode("mo").
+ appendChild(document.createTextNode(newst));
+ else result[0].replaceChild(createMmlNode("mo").
+ appendChild(document.createTextNode(newst)),
+ result[0].childNodes[i]);
+ }
+ }
+ node = createMmlNode(symbol.tag,result[0]);
+ node.setAttribute(symbol.atname,symbol.atval);
+ return [node,result[1]];
+ }
+ case BINARY:
+ str = AMremoveCharsAndBlanks(str,symbol.input.length);
+ result = AMparseSexpr(str);
+ if (result[0]==null) return [createMmlNode("mo",
+ document.createTextNode(symbol.input)),str];
+ AMremoveBrackets(result[0]);
+ var result2 = AMparseSexpr(result[1]);
+ if (result2[0]==null) return [createMmlNode("mo",
+ document.createTextNode(symbol.input)),str];
+ AMremoveBrackets(result2[0]);
+ if (symbol.input=="color") {
+ if (str.charAt(0)=="{") i=str.indexOf("}");
+ else if (str.charAt(0)=="(") i=str.indexOf(")");
+ else if (str.charAt(0)=="[") i=str.indexOf("]");
+ st = str.slice(1,i);
+ node = createMmlNode(symbol.tag,result2[0]);
+ node.setAttribute("mathcolor",st);
+ return [node,result2[1]];
+ }
+ if (symbol.input=="root" || symbol.output=="stackrel")
+ newFrag.appendChild(result2[0]);
+ newFrag.appendChild(result[0]);
+ if (symbol.input=="frac") newFrag.appendChild(result2[0]);
+ return [createMmlNode(symbol.tag,newFrag),result2[1]];
+ case INFIX:
+ str = AMremoveCharsAndBlanks(str,symbol.input.length);
+ return [createMmlNode("mo",document.createTextNode(symbol.output)),str];
+ case SPACE:
+ str = AMremoveCharsAndBlanks(str,symbol.input.length);
+ node = createMmlNode("mspace");
+ node.setAttribute("width","1ex");
+ newFrag.appendChild(node);
+ newFrag.appendChild(
+ createMmlNode(symbol.tag,document.createTextNode(symbol.output)));
+ node = createMmlNode("mspace");
+ node.setAttribute("width","1ex");
+ newFrag.appendChild(node);
+ return [createMmlNode("mrow",newFrag),str];
+ case LEFTRIGHT:
+// if (rightvert) return [null,str]; else rightvert = true;
+ AMnestingDepth++;
+ str = AMremoveCharsAndBlanks(str,symbol.input.length);
+ result = AMparseExpr(str,false);
+ AMnestingDepth--;
+ st = "";
+ if (result[0].lastChild!=null)
+ st = result[0].lastChild.firstChild.nodeValue;
+ if (st == "|") { // its an absolute value subterm
+ node = createMmlNode("mo",document.createTextNode(symbol.output));
+ node = createMmlNode("mrow",node);
+ node.appendChild(result[0]);
+ return [node,result[1]];
+ } else { // the "|" is a \mid so use unicode 2223 (divides) for spacing
+ node = createMmlNode("mo",document.createTextNode("\u2223"));
+ node = createMmlNode("mrow",node);
+ return [node,str];
+ }
+ default:
+//alert("default");
+ str = AMremoveCharsAndBlanks(str,symbol.input.length);
+ return [createMmlNode(symbol.tag, //its a constant
+ document.createTextNode(symbol.output)),str];
+ }
+}
+
+function AMparseIexpr(str) {
+ var symbol, sym1, sym2, node, result, underover;
+ str = AMremoveCharsAndBlanks(str,0);
+ sym1 = AMgetSymbol(str);
+ result = AMparseSexpr(str);
+ node = result[0];
+ str = result[1];
+ symbol = AMgetSymbol(str);
+ if (symbol.ttype == INFIX && symbol.input != "/") {
+ str = AMremoveCharsAndBlanks(str,symbol.input.length);
+// if (symbol.input == "/") result = AMparseIexpr(str); else ...
+ result = AMparseSexpr(str);
+ if (result[0] == null) // show box in place of missing argument
+ result[0] = createMmlNode("mo",document.createTextNode("\u25A1"));
+ else AMremoveBrackets(result[0]);
+ str = result[1];
+// if (symbol.input == "/") AMremoveBrackets(node);
+ underover = (sym1.ttype == UNDEROVER || sym1.ttype == UNARYUNDEROVER);
+ if (symbol.input == "_") {
+ sym2 = AMgetSymbol(str);
+ if (sym2.input == "^") {
+ str = AMremoveCharsAndBlanks(str,sym2.input.length);
+ var res2 = AMparseSexpr(str);
+ AMremoveBrackets(res2[0]);
+ str = res2[1];
+ node = createMmlNode((underover?"munderover":"msubsup"),node);
+ node.appendChild(result[0]);
+ node.appendChild(res2[0]);
+ node = createMmlNode("mrow",node); // so sum does not stretch
+ } else {
+ node = createMmlNode((underover?"munder":"msub"),node);
+ node.appendChild(result[0]);
+ }
+ } else if (symbol.input == "^" && underover) {
+ node = createMmlNode("mover",node);
+ node.appendChild(result[0]);
+ } else {
+ node = createMmlNode(symbol.tag,node);
+ node.appendChild(result[0]);
+ }
+ if (typeof sym1.func != 'undefined' && sym1.func) {
+ sym2 = AMgetSymbol(str);
+ if (sym2.ttype != INFIX && sym2.ttype != RIGHTBRACKET) {
+ result = AMparseIexpr(str);
+ node = createMmlNode("mrow",node);
+ node.appendChild(result[0]);
+ str = result[1];
+ }
+ }
+ }
+ return [node,str];
+}
+
+function AMparseExpr(str,rightbracket) {
+ var symbol, node, result, i,
+ newFrag = document.createDocumentFragment();
+ do {
+ str = AMremoveCharsAndBlanks(str,0);
+ result = AMparseIexpr(str);
+ node = result[0];
+ str = result[1];
+ symbol = AMgetSymbol(str);
+ if (symbol.ttype == INFIX && symbol.input == "/") {
+ str = AMremoveCharsAndBlanks(str,symbol.input.length);
+ result = AMparseIexpr(str);
+ if (result[0] == null) // show box in place of missing argument
+ result[0] = createMmlNode("mo",document.createTextNode("\u25A1"));
+ else AMremoveBrackets(result[0]);
+ str = result[1];
+ AMremoveBrackets(node);
+ node = createMmlNode(symbol.tag,node);
+ node.appendChild(result[0]);
+ newFrag.appendChild(node);
+ symbol = AMgetSymbol(str);
+ }
+ else if (node!=undefined) newFrag.appendChild(node);
+ } while ((symbol.ttype != RIGHTBRACKET &&
+ (symbol.ttype != LEFTRIGHT || rightbracket)
+ || AMnestingDepth == 0) && symbol!=null && symbol.output!="");
+ if (symbol.ttype == RIGHTBRACKET || symbol.ttype == LEFTRIGHT) {
+// if (AMnestingDepth > 0) AMnestingDepth--;
+ var len = newFrag.childNodes.length;
+ if (len>0 && newFrag.childNodes[len-1].nodeName == "mrow"
+ && newFrag.childNodes[len-1].lastChild
+ && newFrag.childNodes[len-1].lastChild.firstChild ) { //matrix
+ //removed to allow row vectors: //&& len>1 &&
+ //newFrag.childNodes[len-2].nodeName == "mo" &&
+ //newFrag.childNodes[len-2].firstChild.nodeValue == ","
+ var right = newFrag.childNodes[len-1].lastChild.firstChild.nodeValue;
+ if (right==")" || right=="]") {
+ var left = newFrag.childNodes[len-1].firstChild.firstChild.nodeValue;
+ if (left=="(" && right==")" && symbol.output != "}" ||
+ left=="[" && right=="]") {
+ var pos = []; // positions of commas
+ var matrix = true;
+ var m = newFrag.childNodes.length;
+ for (i=0; matrix && i1) matrix = pos[i].length == pos[i-2].length;
+ }
+ matrix = matrix && (pos.length>1 || pos[0].length>0);
+ if (matrix) {
+ var row, frag, n, k, table = document.createDocumentFragment();
+ for (i=0; i(-,-,...,-,-)
+ n = node.childNodes.length;
+ k = 0;
+ node.removeChild(node.firstChild); //remove (
+ for (j=1; j2) {
+ newFrag.removeChild(newFrag.firstChild); //remove )
+ newFrag.removeChild(newFrag.firstChild); //remove ,
+ }
+ table.appendChild(createMmlNode("mtr",row));
+ }
+ node = createMmlNode("mtable",table);
+ if (typeof symbol.invisible == "boolean" && symbol.invisible) node.setAttribute("columnalign","left");
+ newFrag.replaceChild(node,newFrag.firstChild);
+ }
+ }
+ }
+ }
+ str = AMremoveCharsAndBlanks(str,symbol.input.length);
+ if (typeof symbol.invisible != "boolean" || !symbol.invisible) {
+ node = createMmlNode("mo",document.createTextNode(symbol.output));
+ newFrag.appendChild(node);
+ }
+ }
+ return [newFrag,str];
+}
+
+function parseMath(str,latex) {
+ var frag, node;
+ AMnestingDepth = 0;
+ //some basic cleanup for dealing with stuff editors like TinyMCE adds
+ str = str.replace(/ /g,"");
+ str = str.replace(/>/g,">");
+ str = str.replace(/</g,"<");
+ str = str.replace(/(Sin|Cos|Tan|Arcsin|Arccos|Arctan|Sinh|Cosh|Tanh|Cot|Sec|Csc|Log|Ln|Abs)/g, function(v) { return v.toLowerCase(); });
+ frag = AMparseExpr(str.replace(/^\s+/g,""),false)[0];
+ node = createMmlNode("mstyle",frag);
+ if (mathcolor != "") node.setAttribute("mathcolor",mathcolor);
+ if (mathfontfamily != "") node.setAttribute("fontfamily",mathfontfamily);
+ if (displaystyle) node.setAttribute("displaystyle","true");
+ node = createMmlNode("math",node);
+ if (showasciiformulaonhover) //fixed by djhsu so newline
+ node.setAttribute("title",str.replace(/\s+/g," "));//does not show in Gecko
+ return node;
+}
+
+function strarr2docFrag(arr, linebreaks, latex) {
+ var newFrag=document.createDocumentFragment();
+ var expr = false;
+ for (var i=0; i,\\|!:;'~]|\\.(?!(?:\x20|$))|"+ambigAMtoken+englishAMtoken+simpleAMtoken;
+ var re = new RegExp("(^|\\s)((("+token+")\\s?)(("+token+secondenglishAMtoken+")\\s?)+)([,.?]?(?=\\s|$))","g");
+ str = str.replace(re," `$2`$7");
+ var arr = str.split(AMdelimiter1);
+ var re1 = new RegExp("(^|\\s)([b-zB-HJ-Z+*<>]|"+texcommand+ambigAMtoken+simpleAMtoken+")(\\s|\\n|$)","g");
+ var re2 = new RegExp("(^|\\s)([a-z]|"+texcommand+ambigAMtoken+simpleAMtoken+")([,.])","g"); // removed |\d+ for now
+ for (i=0; i1 || mtch) {
+ if (!noMathML) {
+ frg = strarr2docFrag(arr,n.nodeType==8,latex);
+ var len = frg.childNodes.length;
+ n.parentNode.replaceChild(frg,n);
+ return len-1;
+ } else return 0;
+ }
+ }
+ } else return 0;
+ } else if (n.nodeName!="math") {
+ for (i=0; i topOfWindow &&
+ monitoredDOMElements[element].offset < bottomOfWindow) {
+ $(monitoredDOMElements[element].anchor).addClass("selected");
+ $(".autotoc li").not(monitoredDOMElements[element].anchor).removeClass("selected");
+ break;
+ }
+ }
+ });
+
+
+ // Default settings
+ var settings = $.extend({
+ toc: "#toc"
+ },options);
+
+ var toc = $('');
+
+ $(settings.toc).append(toc);
+
+ return this.each(function() {
+ tocEntry = $('' + $(this).html() + ' ');
+ tocEntry.data("parentHeading",this);
+ tocEntry.on("click", function() {
+ $('html, body').animate({
+ scrollTop: $($(this).data("parentHeading")).offset().top - (windowHeight * .2)
+ }, 750 );
+ });
+
+ $(".autotoc").append(tocEntry);
+
+ monitoredDOMElements.push({
+ offset: $(this).offset().top,
+ anchor: tocEntry
+ });
+ });
+ }
+});
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..fcf894c
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,10 @@
+---
+layout: spec
+title: Draco 3D Graphics Compression
+---
+
+ * [Draft Draco Bitstream Specification][spec]
+ * [README file for specification authors][readme]
+
+[spec]: /docs/spec/
+[readme]: /docs/spec/README
\ No newline at end of file
diff --git a/docs/spec/00.00.00.title.md b/docs/spec/00.00.00.title.md
new file mode 100644
index 0000000..fffa716
--- /dev/null
+++ b/docs/spec/00.00.00.title.md
@@ -0,0 +1,3 @@
+
+# {{ page.title }}
+{:.no_toc}
diff --git a/docs/spec/00.00.01.version.md b/docs/spec/00.00.01.version.md
new file mode 100644
index 0000000..1796d22
--- /dev/null
+++ b/docs/spec/00.00.01.version.md
@@ -0,0 +1,3 @@
+
+_{{ page.version }}_
+_{{ page.version_date }}_
diff --git a/docs/spec/00.00.02.authors.md b/docs/spec/00.00.02.authors.md
new file mode 100644
index 0000000..2cf7726
--- /dev/null
+++ b/docs/spec/00.00.02.authors.md
@@ -0,0 +1,4 @@
+
+_Frank Galligan, Google
+\[author]
+\[author]_
diff --git a/docs/spec/00.00.03.last.modified.md b/docs/spec/00.00.03.last.modified.md
new file mode 100644
index 0000000..092b08c
--- /dev/null
+++ b/docs/spec/00.00.03.last.modified.md
@@ -0,0 +1,2 @@
+
+_Last modified: {{ site.time }}_
diff --git a/docs/spec/00.00.04.abstract.md b/docs/spec/00.00.04.abstract.md
new file mode 100644
index 0000000..2fc4a46
--- /dev/null
+++ b/docs/spec/00.00.04.abstract.md
@@ -0,0 +1,6 @@
+
+## Abstract
+{:.no_toc .nocount}
+
+This document defines the bitstream format and decoding process for the
+Draco 3D Data Compression scheme.
diff --git a/docs/spec/00.00.05.toc.md b/docs/spec/00.00.05.toc.md
new file mode 100644
index 0000000..9ce6baf
--- /dev/null
+++ b/docs/spec/00.00.05.toc.md
@@ -0,0 +1,5 @@
+
+**Contents**
+
+* TOC
+{:toc}
diff --git a/docs/spec/01.00.00.scope.md b/docs/spec/01.00.00.scope.md
new file mode 100644
index 0000000..d17eff9
--- /dev/null
+++ b/docs/spec/01.00.00.scope.md
@@ -0,0 +1,5 @@
+
+## Scope
+
+This document specifies the open-source Draco #D Data Compression bitstream
+format and decoding process.
diff --git a/docs/spec/02.00.00.terms.md b/docs/spec/02.00.00.terms.md
new file mode 100644
index 0000000..cfca0dd
--- /dev/null
+++ b/docs/spec/02.00.00.terms.md
@@ -0,0 +1,8 @@
+
+## Terms and Definitions
+
+For the purposes of this document, the following terms and definitions apply:
+
+| Term | Definition |
+| ------- | ---------------- |
+| | |
diff --git a/docs/spec/03.00.00.symbols.md b/docs/spec/03.00.00.symbols.md
new file mode 100644
index 0000000..58b42cf
--- /dev/null
+++ b/docs/spec/03.00.00.symbols.md
@@ -0,0 +1,18 @@
+
+## Symbols (and abbreviated terms)
+
+**DCT:** Discrete Cosine Transform
+
+FIXME
+
+The specification makes use of a number of constant integers. Constants that
+relate to the semantics of a particular syntax element are defined in section
+7.
+
+Additional constants are defined below:
+
+
+| Symbol name | Value | Description |
+| ------------------------ |:-----:| ----------- |
+| `SYMBOL` | |
+
diff --git a/docs/spec/04.00.00.conventions.md b/docs/spec/04.00.00.conventions.md
new file mode 100644
index 0000000..762653f
--- /dev/null
+++ b/docs/spec/04.00.00.conventions.md
@@ -0,0 +1,77 @@
+## Conventions
+
+### General Conventions
+
+ * When bit reading is finished it will always pad the read to the current
+ byte.
+
+ * Draco encoded mesh files are comprised of three main sections. This first
+ section is the header. The second section contains the connectivity data.
+ The third section contains the attribute data. The header must be decoded
+ first, then the connectivity section, and then the attribute section.
+
+ * The Connectivity section is composed of the following sections in order:
+
+ * Connectivity header
+
+ * EdgeBreaker symbol buffer
+
+ * Start face buffer
+
+ * EdgeBreaker valence header
+
+ * Context data for the valence prediction
+
+ * Hole and Split data
+
+ * The hole and split data must be decoded before the EdgeBreaker symbols are
+ decoded.
+
+
+### Method of describing bitstream syntax
+
+**FIXME: This section is borrowed from AV1, and should be modified for the Draco
+spec.**
+
+The description style of the syntax is similar to the C++ programming language.
+Syntax elements in the bitstream are represented in bold type. Each syntax
+element is described by its name (using only lower case letters with
+underscore characters) and a descriptor for its method of coded
+representation. The decoding process behaves according to the value of the
+syntax element and to the values of previously decoded syntax elements. When a
+value of a syntax element is used in the syntax tables or the text, it appears
+in regular (i.e. not bold) type. If the value of a syntax element is being
+computed (e.g. being written with a default value instead of being coded in
+the bitstream), it also appears in regular type.
+
+In some cases the syntax tables may use the values of other variables derived
+from syntax elements values. Such variables appear in the syntax tables, or
+text, named by a mixture of lower case and upper case letter and without any
+underscore characters. Variables starting with an upper case letter are
+derived for the decoding of the current syntax structure and all depending
+syntax structures. These variables may be used in the decoding process for
+later syntax structures. Variables starting with a lower case letter are only
+used within the process from which they are derived.
+
+Constant values appear in all upper case letters with underscore characters.
+
+Constant lookup tables appear in all lower case letters with underscore
+characters.
+
+Hexadecimal notation, indicated by prefixing the hexadecimal number by `0x`,
+may be used when the number of bits is an integer multiple of 4. For example,
+`0x1a` represents a bit string `0001 1010`.
+
+Binary notation is indicated by prefixing the binary number by `0b`. For
+example, `0b00011010` represents a bit string `0001 1010`. Binary numbers may
+include underscore characters to enhance readability. If present, the
+underscore characters appear every 4 binary digits starting from the LSB. For
+example, `0b11010` may also be written as `0b1_1010`.
+
+A value equal to 0 represents a FALSE condition in a test statement. The
+value TRUE is represented by any value not equal to 0.
+
+The following table lists examples of the syntax specification format. When
+`syntax_element` appears (with bold face font), it specifies that this syntax
+element is parsed from the bitstream.
+
diff --git a/docs/spec/README.md b/docs/spec/README.md
new file mode 100644
index 0000000..3927aad
--- /dev/null
+++ b/docs/spec/README.md
@@ -0,0 +1,266 @@
+---
+layout: spec
+title: "README: Draco Spec Authoring Information"
+---
+
+
+
+
+
+# Authoring Info, Draco 3D Bitstream Specification
+{:.no_toc}
+
+This document, once published, will define the Draco 3D Geometry Compression
+bitstream format and decoding process.
+
+**Contents**
+
+* TOC
+{:toc}
+
+The document is built from plaintext section and subsection [Markdown] files
+(more specifically, [kramdown] files) using the [Jekyll] static site building
+tool. GitHub supports Jekyll natively.
+
+The `docs/` directory of this project is meant to contain only documentation
+and web content. The commands below should be issued from `docs/`. We do not
+want to pollute the code tree with Ruby and Jekyll config information and
+content.
+
+The `docs/spec/` directory contains the files needed to work on this
+specification document.
+
+
+## Building Locally
+
+Contributors will want to preview their edits locally before submitting pull
+requests. Doing so requires a sane Ruby and rubygems environment. We use [rbenv]
+and [bundler] to "groom" the project environment and avoid conflicts.
+
+_**Important:** All commands are to be run as an ordinary, unprivileged user._
+
+
+### Ruby and rbenv
+
+This project currently depends on Ruby v2.3.0. Because your distro may lack this
+version -- or installing it may conflict with your system's installed version --
+first [install rbenv], then install Ruby v2.3.0 within it (again, in userland).
+
+~~~~~
+# list all available versions:
+$ rbenv install -l
+2.2.6
+2.3.0-dev
+2.3.0-preview1
+2.3.0-preview2
+2.3.0
+
+# install a Ruby version:
+$ rbenv install 2.3.0
+~~~~~
+
+
+### Bundler
+
+Gem dependencies are managed by [bundler].
+
+~~~~~
+$ gem install bundler
+
+# Filesystem location where gems are installed
+$ gem env home
+# => ~/.rbenv/versions//lib/ruby/gems/...
+~~~~~
+
+
+## Fork and Clone the Repo
+
+First, use the **Fork** button on the repo's [homepage] to fork a copy to your
+GitHub account.
+
+Second, clone your fork locally:
+
+~~~~~
+git clone git@github.com:/draco.git
+cd draco
+~~~~~
+
+_**Note** that we **strongly** recommend [using SSH] with GitHub, not HTTPS._
+
+Third, add a Git remote `upstream` that points to google/draco:
+
+~~~~~
+git remote add upstream git@github.com:google/draco.git
+~~~~~
+
+Your local repo with then have two remotes, `upstream` pointing at the
+authoritative GitHub repo and `origin` pointing at your GitHub fork.
+
+~~~~~
+$ git remote
+origin
+upstream
+
+$ git remote show origin
+* remote origin
+ Fetch URL: git@github.com:/draco.git
+ Push URL: git@github.com:/draco.git
+ HEAD branch: master
+ Remote branch:
+ master tracked
+ Local branch configured for 'git pull':
+ master merges with remote master
+ Local ref configured for 'git push':
+ master pushes to master (up to date)
+
+$ git remote show upstream
+* remote upstream
+ Fetch URL: git@github.com:google/draco.git
+ Push URL: git@github.com:google/draco.git
+ HEAD branch: master
+ Remote branch:
+ master tracked
+ Local ref configured for 'git push':
+ master pushes to master (up to date)
+~~~~~
+
+[**See this page**][1] for a longer discussion of managing remotes and general
+GitHub workflow.
+
+**Important: The following commands should be issued from the `docs/`
+directory.**
+
+
+### Set Local Ruby Version (rbenv)
+
+In the `docs/` directory of your local clone, do:
+
+~~~~~
+rbenv local 2.3.0
+~~~~~
+
+Regardless of any other Rubies installed on your system, the project environment
+will now use v2.3.0 and gems appropriate for it.
+
+
+### Install Gem Dependencies with Bundler
+
+In the `docs/` directory of your local clone, run
+
+~~~~~
+bundle install
+~~~~~
+
+Bundler will set dependencies and install needed gems as listed in
+`Gemfile.lock`.
+
+_**Note** that you may need Ruby development headers installed on your system
+for some gems to compile successfully._
+
+
+### Build and Preview Locally with Jekyll
+
+~~~~~
+bundle exec jekyll serve
+~~~~~
+
+This will build the documentation tree and launch a local webserver at
+`http://127.0.0.1:4000/docs/` (by default). Jekyll will also watch the
+the filesystem for changes and rebuild the document as needed.
+
+
+## **Markdown & Formatting Conventions**
+
+The spec document is composed mostly of syntax tables, styled with CSS. Mark
+them up as follows:
+
+ * Use the [fenced code block][fenced] kramdown syntax: A line beginning with
+ three or more tildes (`~`) starts the code block, another such line ends it.
+
+ * Use kramdown's [inline attribute syntax][inline] to apply the CSS class
+ `draco-syntax` to your code block by placing `{:.draco-syntax }` on the line
+ immediately after the code-block closing delimiter.
+
+ * Some syntax elements as annotated with their type and size in a right-hand
+ column. In your text editor, position these annotations at column 73.
+
+**Example:**
+
+~~~~~
+DecodeHeader() {
+ draco_string UI8[5]
+ major_version UI8
+ minor_version UI8
+ encoder_type UI8
+ encoder_method UI8
+ flags
+}
+~~~~~
+{:.draco-syntax}
+
+... **will render as:**
+
+
+~~~~~
+DecodeHeader() {
+ draco_string UI8[5]
+ major_version UI8
+ minor_version UI8
+ encoder_type UI8
+ encoder_method UI8
+ flags
+}
+~~~~~
+{:.draco-syntax}
+
+
+## General GitHub Workflow
+
+Always do your work in a local branch.
+
+~~~~~
+git co -b my-branch-name
+## work ##
+git add
+git ci -m "Reasonably clear commit message"
+~~~~~
+
+Push your branch to `origin` (your GitHub fork):
+
+~~~~~
+git push origin my-branch-name
+~~~~~
+
+Next, visit the `upstream` [homepage]. If you are logged-in, GitHub will be
+aware of your recently pushed branch, and offer an in-page widget for submitting
+a pull request for the project maintainers to consider.
+
+Once your pull request is merged into upstream's master branch, you may
+synchronize your clone (and remote `origin`) as follows:
+
+~~~~~
+git co master
+git fetch upstream
+git merge upstream/master
+git push origin
+~~~~~
+
+Your old working branch is no longer needed, so do some housekeeping:
+
+~~~~~
+git br -d my-branch-name
+~~~~~
+
+
+[Markdown]: https://daringfireball.net/projects/markdown/
+[kramdown]: https://kramdown.gettalong.org/
+[Jekyll]: https://jekyllrb.com/
+[rbenv]: https://github.com/rbenv/rbenv
+[bundler]: http://bundler.io/
+[install rbenv]: https://github.com/rbenv/rbenv#installation
+[homepage]: https://github.com/google/draco
+[using SSH]: https://help.github.com/articles/connecting-to-github-with-ssh/
+[1]: https://2buntu.com/articles/1459/keeping-your-forked-repo-synced-with-the-upstream-source/
+[fenced]: https://kramdown.gettalong.org/syntax.html#fenced-code-blocks
+[inline]: https://kramdown.gettalong.org/syntax.html#block-ials
+
diff --git a/docs/spec/attributes.decoder.md b/docs/spec/attributes.decoder.md
new file mode 100644
index 0000000..32eaa36
--- /dev/null
+++ b/docs/spec/attributes.decoder.md
@@ -0,0 +1,21 @@
+
+## Attributes Decoder
+
+### DecodeAttributesDecoderData()
+
+~~~~~
+DecodeAttributesDecoderData(buffer) {
+ num_attributes I32
+ point_attribute_ids_.resize(num_attributes);
+ for (i = 0; i < num_attributes; ++i) {
+ att_type UI8
+ data_type UI8
+ components_count UI8
+ normalized UI8
+ custom_id UI16
+ Initialize GeometryAttribute ga
+ att_id = pc->AddAttribute(new PointAttribute(ga));
+ point_attribute_ids_[i] = att_id;
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/core.functions.md b/docs/spec/core.functions.md
new file mode 100644
index 0000000..955a033
--- /dev/null
+++ b/docs/spec/core.functions.md
@@ -0,0 +1,66 @@
+
+## Core Functions
+
+### DecodeVarint
+
+~~~~~
+DecodeVarint() {
+ If (std::is_unsigned::value) {
+ in UI8
+ If (in & (1 << 7)) {
+ out = DecodeVarint()
+ out = (out << 7) | (in & ((1 << 7) - 1))
+ } else {
+ typename std::make_unsigned::type UIT;
+ out = DecodeVarint()
+ out = ConvertSymbolToSignedInt(out)
+ }
+ return out;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### ConvertSymbolToSignedInt()
+
+~~~~~
+ConvertSymbolToSignedInt() {
+ abs_val = val >> 1
+ If (val & 1 == 0) {
+ return abs_val
+ } else {
+ signed_val = -abs_val - 1
+ }
+ return signed_val
+}
+~~~~~
+{:.draco-syntax }
+
+
+Sequential Decoder
+
+FIXME: ^^^ Heading level?
+
+### decode_connectivity()
+
+~~~~~
+decode_connectivity() {
+ num_faces I32
+ num_points I32
+ connectivity _method UI8
+ If (connectivity _method == 0) {
+ // TODO
+ } else {
+ loop num_faces {
+ If (num_points < 256) {
+ face[] UI8
+ } else if (num_points < (1 << 16)) {
+ face[] UI16
+ } else {
+ face[] UI32
+ }
+ }
+ }
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/corner.table.md b/docs/spec/corner.table.md
new file mode 100644
index 0000000..afbb395
--- /dev/null
+++ b/docs/spec/corner.table.md
@@ -0,0 +1,213 @@
+
+## Corner Table
+
+### Opposite()
+
+~~~~~
+Opposite(corner) {
+ return opposite_corners_[corner];
+}
+~~~~~
+{:.draco-syntax }
+
+
+### Next()
+
+~~~~~
+Next(corner) {
+ return LocalIndex(++corner) ? corner : corner - 3;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### Previous()
+
+~~~~~
+Previous(corner) {
+ return LocalIndex(corner) ? corner - 1 : corner + 2;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### Vertex()
+
+~~~~~
+Vertex(corner) {
+ faces_[Face(corner)][LocalIndex(corner)];
+}
+~~~~~
+{:.draco-syntax }
+
+
+### Face()
+
+~~~~~
+Face(corner) {
+ return corner / 3;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### LocalIndex()
+
+~~~~~
+LocalIndex(corner) {
+ return corner % 3;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### num_vertices()
+
+~~~~~
+num_vertices() {
+ return vertex_corners_.size();
+}
+~~~~~
+{:.draco-syntax }
+
+
+### num_corners()
+
+~~~~~
+num_corners() {
+ return faces_.size() * 3;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### num_faces()
+
+~~~~~
+num_faces() {
+ return faces_.size();
+}
+~~~~~
+{:.draco-syntax }
+
+
+### bool IsOnBoundary()
+
+~~~~~
+bool IsOnBoundary(vert) {
+ corner = LeftMostCorner(vert);
+ if (SwingLeft(corner) < 0)
+ return true;
+ return false;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### SwingRight()
+
+~~~~~
+SwingRight(corner) {
+ return Previous(Opposite(Previous(corner)));
+}
+~~~~~
+{:.draco-syntax }
+
+
+### SwingLeft()
+
+~~~~~
+SwingLeft(corner) {
+ return Next(Opposite(Next(corner)));
+}
+~~~~~
+{:.draco-syntax }
+
+
+### GetLeftCorner()
+
+~~~~~
+GetLeftCorner(corner_id) {
+ if (corner_id < 0)
+ return kInvalidCornerIndex;
+ return Opposite(Previous(corner_id));
+}
+~~~~~
+{:.draco-syntax }
+
+
+### GetRightCorner()
+
+~~~~~
+GetRightCorner(corner_id) {
+ if (corner_id < 0)
+ return kInvalidCornerIndex;
+ return Opposite(Next(corner_id));
+}
+~~~~~
+{:.draco-syntax }
+
+
+### SetOppositeCorner()
+
+~~~~~
+SetOppositeCorner(corner_id, pp_corner_id) {
+ opposite_corners_[corner_id] = opp_corner_id;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### MapCornerToVertex()
+
+~~~~~
+MapCornerToVertex(corner_id, vert_id) {
+ face = Face(corner_id);
+ faces_[face][LocalIndex(corner_id)] = vert_id;
+ if (vert_id >= 0) {
+ vertex_corners_[vert_id] = corner_id;
+ }
+}
+~~~~~
+{:.draco-syntax }
+
+
+### UpdateVertexToCornerMap()
+
+~~~~~
+UpdateVertexToCornerMap(vert) {
+ first_c = vertex_corners_[vert];
+ if (first_c < 0)
+ return;
+ act_c = SwingLeft(first_c);
+ c = first_c;
+ while (act_c >= 0 && act_c != first_c) {
+ c = act_c;
+ act_c = SwingLeft(act_c);
+ }
+ if (act_c != first_c) {
+ vertex_corners_[vert] = c;
+ }
+}
+~~~~~
+{:.draco-syntax }
+
+
+### LeftMostCorner()
+
+~~~~~
+LeftMostCorner(v) {
+ return vertex_corners_[v];
+}
+~~~~~
+{:.draco-syntax }
+
+
+### MakeVertexIsolated()
+
+~~~~~
+MakeVertexIsolated(vert) {
+ vertex_corners_[vert] = kInvalidCornerIndex;
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/cornertable.traversal.processor.md b/docs/spec/cornertable.traversal.processor.md
new file mode 100644
index 0000000..098d795
--- /dev/null
+++ b/docs/spec/cornertable.traversal.processor.md
@@ -0,0 +1,44 @@
+
+## CornerTable Traversal Processor
+
+
+### IsFaceVisited()
+
+~~~~~
+IsFaceVisited(corner_id) {
+ if (corner_id < 0)
+ return true
+ return is_face_visited_[corner_id / 3];
+}
+~~~~~
+{:.draco-syntax }
+
+
+### MarkFaceVisited()
+
+~~~~~
+MarkFaceVisited(face_id) {
+ is_face_visited_[face_id] = true;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### IsVertexVisited()
+
+~~~~~
+IsVertexVisited(vert_id) {
+ return is_vertex_visited_[vert_id];
+}
+~~~~~
+{:.draco-syntax }
+
+
+### MarkVertexVisited()
+
+~~~~~
+MarkVertexVisited(vert_id) {
+ is_vertex_visited_[vert_id] = true;
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/draco.decoder.md b/docs/spec/draco.decoder.md
new file mode 100644
index 0000000..7cb3cc5
--- /dev/null
+++ b/docs/spec/draco.decoder.md
@@ -0,0 +1,46 @@
+## Draco Decoder
+
+### Decode()
+
+~~~~~
+Decode() {
+ DecodeHeader()
+ DecodeConnectivityData()
+ DecodeAttributeData()}
+~~~~~
+{:.draco-syntax}
+
+
+### DecodeHeader()
+
+~~~~~
+DecodeHeader() {
+ draco_string UI8[5]
+ major_version UI8
+ minor_version UI8
+ encoder_type UI8
+ encoder_method UI8
+ flags
+}
+~~~~~
+{:.draco-syntax}
+
+
+### DecodeAttributeData()
+
+~~~~~
+DecodeAttributeData() {
+ num_attributes_decoders UI8
+ for (i = 0; i < num_attributes_decoders; ++i) {
+ CreateAttributesDecoder(i);
+ }
+ for (auto &att_dec : attributes_decoders_) {
+ att_dec->Initialize(this, point_cloud_)
+ }
+ for (i = 0; i < num_attributes_decoders; ++i) {
+ attributes_decoders_[i]->DecodeAttributesDecoderData(buffer_)
+ }
+ DecodeAllAttributes()
+ OnAttributesDecoded()
+~~~~~
+{:.draco-syntax}
diff --git a/docs/spec/edgebreaker.decoder.md b/docs/spec/edgebreaker.decoder.md
new file mode 100644
index 0000000..11baa85
--- /dev/null
+++ b/docs/spec/edgebreaker.decoder.md
@@ -0,0 +1,362 @@
+## EdgeBreaker Decoder
+
+### InitializeDecoder()
+
+~~~~~
+InitializeDecoder() {
+ edgebreaker_decoder_type UI8
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeConnectivity()
+
+~~~~~
+DecodeConnectivity() {
+ num_new_verts UI32
+ num_encoded_vertices UI32
+ num_faces UI32
+ num_attribute_data I8
+ num_encoded_symbols UI32
+ num_encoded_split_symbols UI32
+ encoded_connectivity_size UI32
+ // file pointer must be set to current position
+ // + encoded_connectivity_size
+ hole_and_split_bytes = DecodeHoleAndTopologySplitEvents()
+ // file pointer must be set to old current position
+ EdgeBreakerTraversalValence_Start()
+ DecodeConnectivity(num_symbols)
+ if (attribute_data_.size() > 0) {
+ for (ci = 0; ci < corner_table_->num_corners(); ci += 3) {
+ DecodeAttributeConnectivitiesOnFace(ci)
+ }
+ }
+ for (i = 0; i < corner_table_->num_vertices(); ++i) {
+ if (is_vert_hole_[i]) {
+ corner_table_->UpdateVertexToCornerMap(i);
+ }
+ }
+ // Decode attribute connectivity.
+ for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
+ attribute_data_[i].connectivity_data.InitEmpty(corner_table_.get());
+ for (int32_t c : attribute_data_[i].attribute_seam_corners) {
+ attribute_data_[i].connectivity_data.AddSeamEdge(c);
+ }
+ attribute_data_[i].connectivity_data.RecomputeVertices(nullptr, nullptr);
+ }
+ // Preallocate vertex to value mapping
+ AssignPointsToCorners()
+}
+~~~~~
+{:.draco-syntax }
+
+
+### AssignPointsToCorners()
+
+~~~~~
+AssignPointsToCorners() {
+ decoder_->mesh()->SetNumFaces(corner_table_->num_faces());
+ if (attribute_data_.size() == 0) {
+ for (f = 0; f < decoder_->mesh()->num_faces(); ++f) {
+ for (c = 0; c < 3; ++c) {
+ vert_id = corner_table_->Vertex(3 * f + c);
+ if (point_id == -1)
+ point_id = num_points++;
+ face[c] = point_id;
+ }
+ decoder_->mesh()->SetFace(f, face);
+ }
+ decoder_->point_cloud()->set_num_points(num_points);
+ Return true;
+ }
+ for (v = 0; v < corner_table_->num_vertices(); ++v) {
+ c = corner_table_->LeftMostCorner(v);
+ if (c < 0)
+ continue;
+ deduplication_first_corner = c;
+ if (!is_vert_hole_[v]) {
+ for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
+ if (!attribute_data_[i].connectivity_data.IsCornerOnSeam(c))
+ continue;
+ vert_id = attribute_data_[i].connectivity_data.Vertex(c);
+ act_c = corner_table_->SwingRight(c);
+ seam_found = false;
+ while (act_c != c) {
+ if (attribute_data_[i].connectivity_data.Vertex(act_c) != vert_id) {
+ deduplication_first_corner = act_c;
+ seam_found = true;
+ break;
+ }
+ act_c = corner_table_->SwingRight(act_c);
+ }
+ if (seam_found)
+ break;
+ }
+ }
+ c = deduplication_first_corner;
+ corner_to_point_map[c] = point_to_corner_map.size();
+ point_to_corner_map.push_back(c);
+ prev_c = c;
+ c = corner_table_->SwingRight(c);
+ while (c >= 0 && c != deduplication_first_corner) {
+ attribute_seam = false;
+ for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
+ if (attribute_data_[i].connectivity_data.Vertex(c) !=
+ attribute_data_[i].connectivity_data.Vertex(prev_c)) {
+ attribute_seam = true;
+ break;
+ }
+ }
+ if (attribute_seam) {
+ corner_to_point_map[c] = point_to_corner_map.size();
+ point_to_corner_map.push_back(c);
+ } else {
+ corner_to_point_map[c] = corner_to_point_map[prev_c];
+ }
+ prev_c = c;
+ c = corner_table_->SwingRight(c);
+ }
+ }
+ for (f = 0; f < decoder_->mesh()->num_faces(); ++f) {
+ for (c = 0; c < 3; ++c) {
+ face[c] = corner_to_point_map[3 * f + c];
+ }
+ decoder_->mesh()->SetFace(f, face);
+ }
+ decoder_->point_cloud()->set_num_points(point_to_corner_map.size());
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeConnectivity()
+
+~~~~~
+DecodeConnectivity(num_symbols) {
+ for (i = 0; i < num_symbols; ++i) {
+ symbol = TraversalValence_DecodeSymbol()
+ corner = 3 * num_faces++
+ if (symbol == TOPOLOGY_C) {
+ vertex_x = UpdateCornerTableForSymbolC()
+ is_vert_hole_[vertex_x] = false;
+ } else if (symbol == TOPOLOGY_R || symbol == TOPOLOGY_L) {
+ UpdateCornerTableForSymbolLR()
+ check_topology_split = true;
+ } else if (symbol == TOPOLOGY_S) {
+ HandleSymbolS()
+ } else if (symbol == TOPOLOGY_E) {
+ UpdateCornerTableForSymbolE()
+ check_topology_split = true;
+ }
+ active_corner_stack.back() = corner;
+ traversal_decoder_.NewActiveCornerReached(corner);
+ if (check_topology_split) {
+ encoder_symbol_id = num_symbols - symbol_id - 1;
+ while (true) {
+ split = IsTopologySplit(encoder_symbol_id, &split_edge,
+ &encoder_split_symbol_id);
+ if (!split) {
+ break;
+ }
+ act_top_corner = corner;
+ if (split_edge == RIGHT_FACE_EDGE) {
+ new_active_corner = corner_table_->Next(act_top_corner);
+ } else {
+ new_active_corner = corner_table_->Previous(act_top_corner);
+ }
+ decoder_split_symbol_id = num_symbols - encoder_split_symbol_id - 1;
+ topology_split_active_corners[decoder_split_symbol_id] =
+ new_active_corner;
+ }
+ }
+ }
+ while (active_corner_stack.size() > 0) {
+ corner = active_corner_stack.pop_back();
+ interior_face = traversal_decoder_.DecodeStartFaceConfiguration();
+ if (interior_face == true) {
+ UpdateCornerTableForInteriorFace()
+ for (ci = 0; ci < 3; ++ci) {
+ is_vert_hole_[corner_table_->Vertex(new_corner + ci)] = false;
+ }
+ init_face_configurations_.push_back(true);
+ init_corners_.push_back(new_corner);
+ } else {
+ init_face_configurations_.push_back(false);
+ init_corners_.push_back(corner);
+ }
+ }
+ Return num_vertices;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### UpdateCornerTableForSymbolC()
+
+~~~~~
+UpdateCornerTableForSymbolC(corner) {
+ corner_a = active_corner_stack.back();
+ corner_b = corner_table_->Previous(corner_a);
+ while (corner_table_->Opposite(corner_b) >= 0) {
+ corner_b = corner_table_->Previous(corner_table_->Opposite(corner_b));
+ }
+ SetOppositeCorners(corner_a, corner + 1);
+ SetOppositeCorners(corner_b, corner + 2);
+ vertex_x = corner_table_->Vertex(corner_table_->Next(corner_a));
+ corner_table_->MapCornerToVertex(corner, vertex_x);
+ corner_table_->MapCornerToVertex(
+ corner + 1, corner_table_->Vertex(corner_table_->Next(corner_b)));
+ corner_table_->MapCornerToVertex(
+ corner + 2, corner_table_->Vertex(corner_table_->Previous(corner_a)));
+ return vertex_x;
+}
+~~~~~
+{:.draco-syntax }
+
+
+
+### UpdateCornerTableForSymbolLR()
+
+~~~~~
+UpdateCornerTableForSymbolLR(corner, symbol) {
+ if (symbol == TOPOLOGY_R) {
+ opp_corner = corner + 2;
+ } else {
+ opp_corner = corner + 1;
+ }
+ SetOppositeCorners(opp_corner, corner_a);
+ corner_table_->MapCornerToVertex(opp_corner,num_vertices++);
+ corner_table_->MapCornerToVertex(
+ corner_table_->Next(opp_corner),
+ corner_table_->Vertex(corner_table_->Previous(corner_a)));
+ corner_table_->MapCornerToVertex(
+ corner_table_->Previous(opp_corner),
+ corner_table_->Vertex(corner_table_->Next(corner_a)));
+}
+~~~~~
+{:.draco-syntax }
+
+
+### HandleSymbolS()
+
+~~~~~
+HandleSymbolS(corner) {
+ corner_b = active_corner_stack.pop_back();
+ it = topology_split_active_corners.find(symbol_id);
+ if (it != topology_split_active_corners.end()) {
+ active_corner_stack.push_back(it->second);
+ }
+ corner_a = active_corner_stack.back();
+ SetOppositeCorners(corner_a, corner + 2);
+ SetOppositeCorners(corner_b, corner + 1);
+ vertex_p = corner_table_->Vertex(corner_table_->Previous(corner_a));
+ corner_table_->MapCornerToVertex(corner, vertex_p);
+ corner_table_->MapCornerToVertex(
+ corner + 1, corner_table_->Vertex(corner_table_->Next(corner_a)));
+ corner_table_->MapCornerToVertex(corner + 2,
+ corner_table_->Vertex(corner_table_->Previous(corner_b)));
+ corner_n = corner_table_->Next(corner_b);
+ vertex_n = corner_table_->Vertex(corner_n);
+ traversal_decoder_.MergeVertices(vertex_p, vertex_n);
+ // TraversalValence_MergeVertices
+ while (corner_n >= 0) {
+ corner_table_->MapCornerToVertex(corner_n, vertex_p);
+ corner_n = corner_table_->SwingLeft(corner_n);
+ }
+ corner_table_->MakeVertexIsolated(vertex_n);
+}
+~~~~~
+{:.draco-syntax }
+
+
+### UpdateCornerTableForSymbolE()
+
+~~~~~
+UpdateCornerTableForSymbolE() {
+ corner_table_->MapCornerToVertex(corner, num_vertices++);
+ corner_table_->MapCornerToVertex(corner + 1, num_vertices++);
+ corner_table_->MapCornerToVertex(corner + 2, num_vertices++);
+}
+~~~~~
+{:.draco-syntax }
+
+
+### UpdateCornerTableForInteriorFace()
+
+~~~~~
+UpdateCornerTableForInteriorFace() {
+ corner_b = corner_table_->Previous(corner);
+ while (corner_table_->Opposite(corner_b) >= 0) {
+ corner_b = corner_table_->Previous(corner_table_->Opposite(corner_b));
+ }
+ corner_c = corner_table_->Next(corner);
+ while (corner_table_->Opposite(corner_c) >= 0) {
+ corner_c = corner_table_->Next(corner_table_->Opposite(corner_c));
+ }
+ face(num_faces++);
+ corner_table_->MapCornerToVertex(
+ new_corner, corner_table_->Vertex(corner_table_->Next(corner_b)));
+ corner_table_->MapCornerToVertex(
+ new_corner + 1, corner_table_->Vertex(corner_table_->Next(corner_c)));
+ corner_table_->MapCornerToVertex(
+ new_corner + 2, corner_table_->Vertex(corner_table_->Next(corner)));
+}
+~~~~~
+{:.draco-syntax }
+
+
+### IsTopologySplit()
+
+~~~~~
+IsTopologySplit(encoder_symbol_id, *out_face_edge,
+ *out_encoder_split_symbol_id) {
+ if (topology_split_data_.size() == 0)
+ return false;
+ if (topology_split_data_.back().source_symbol_id != encoder_symbol_id)
+ return false;
+ *out_face_edge = topology_split_data_.back().source_edge;
+ *out_encoder_split_symbol_id =
+ topology_split_data_.back().split_symbol_id;
+ topology_split_data_.pop_back();
+ return true;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeAttributeConnectivitiesOnFace()
+
+~~~~~
+DecodeAttributeConnectivitiesOnFace(corner) {
+ corners[3] = {corner, corner_table_->Next(corner),
+ corner_table_->Previous(corner)}
+ for (c = 0; c < 3; ++c) {
+ opp_corner = corner_table_->Opposite(corners[c]);
+ if (opp_corner < 0) {
+ for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
+ attribute_data_[i].attribute_seam_corners.push_back(corners[c]);
+ }
+ continue
+ }
+ for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
+ bool is_seam = traversal_decoder_.DecodeAttributeSeam(i);
+ if (is_seam) {
+ attribute_data_[i].attribute_seam_corners.push_back(corners[c]);
+ }
+ }
+ }
+}
+~~~~~
+{:.draco-syntax }
+
+
+### SetOppositeCorners()
+
+~~~~~
+SetOppositeCorners(corner_0, corner_1) {
+ corner_table_->SetOppositeCorner(corner_0, corner_1);
+ corner_table_->SetOppositeCorner(corner_1, corner_0);
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/edgebreaker.hole.and.topology.md b/docs/spec/edgebreaker.hole.and.topology.md
new file mode 100644
index 0000000..5e3ae03
--- /dev/null
+++ b/docs/spec/edgebreaker.hole.and.topology.md
@@ -0,0 +1,65 @@
+
+## EdgeBreaker Hole and Topology Split Events
+
+
+### DecodeHoleAndTopologySplitEvents()
+
+~~~~~
+DecodeHoleAndTopologySplitEvents() {
+ num_topologoy_splits UI32
+ source_symbol_id = 0
+ for (i = 0; i < num_topologoy_splits; ++i) {
+ DecodeVarint(&delta)
+ split_data[i].source_symbol_id = delta + source_symbol_id
+ DecodeVarint(&delta)
+ split_data[i].split_symbol_id = source_symbol_id - delta
+ }
+ for (i = 0; i < num_topologoy_splits; ++i) {
+ split_data[i].split_edge bits1
+ split_data[i].source_edge bits1
+ }
+ num_hole_events UI32
+ symbol_id = 0
+ for (i = 0; i < num_hole_events; ++i) {
+ DecodeVarint(&delta)
+ hole_data[i].symbol_id = delta + symbol_id
+ }
+ return bytes_decoded;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### CreateAttributesDecoder
+
+~~~~~
+CreateAttributesDecoder() {
+ att_data_id I8
+ decoder_type UI8
+ if (att_data_id >= 0) {
+ attribute_data_[att_data_id].decoder_id = att_decoder_id;
+ }
+ traversal_method_encoded UI8
+ if (decoder_type == MESH_VERTEX_ATTRIBUTE) {
+ if (att_data_id < 0) {
+ encoding_data = &pos_encoding_data_;
+ } else {
+ encoding_data = &attribute_data_[att_data_id].encoding_data;
+ attribute_data_[att_data_id].is_connectivity_used = false;
+ }
+ if (traversal_method == MESH_TRAVERSAL_DEPTH_FIRST) {
+ typedef EdgeBreakerTraverser AttTraverser;
+ sequencer = CreateVertexTraversalSequencer(encoding_data);
+ } else if (traversal_method == MESH_TRAVERSAL_PREDICTION_DEGREE) {
+ typedef PredictionDegreeTraverser AttTraverser;
+ sequencer = CreateVertexTraversalSequencer(encoding_data);
+ }
+ } else {
+ // TODO
+ }
+ att_controller(new SequentialAttributeDecodersController(std::move(sequencer)))
+ decoder_->SetAttributesDecoder(att_decoder_id, std::move(att_controller));
+}
+~~~~~
+{:.draco-syntax }
+
diff --git a/docs/spec/edgebreaker.traversal.decoder.md b/docs/spec/edgebreaker.traversal.decoder.md
new file mode 100644
index 0000000..87658b6
--- /dev/null
+++ b/docs/spec/edgebreaker.traversal.decoder.md
@@ -0,0 +1,46 @@
+
+## Edgebreaker Traversal Decoder
+
+### EdgebreakerTraversal_Start()
+
+~~~~~
+EdgebreakerTraversal_Start() {
+ size UI64
+ symbol_buffer_ size * UI8
+ size UI64
+ start_face_buffer_ size * UI8
+ if (num_attribute_data_ > 0) {
+ attribute_connectivity_decoders_ = std::unique_ptr(
+ new BinaryDecoder[num_attribute_data_]);
+ for (i = 0; i < num_attribute_data_; ++i) {
+ attribute_connectivity_decoders_[i].StartDecoding()
+ // RansBitDecoder_StartDecoding
+ }
+}
+~~~~~
+{:.draco-syntax }
+
+
+### Traversal_DecodeSymbol()
+
+~~~~~
+Traversal_DecodeSymbol() {
+ symbol_buffer_.DecodeLeastSignificantBits32(1, &symbol); bits1
+ if (symbol != TOPOLOGY_C) {
+ symbol_buffer_.DecodeLeastSignificantBits32(2, &symbol_suffix); bits2
+ symbol |= (symbol_suffix << 1);
+ }
+ return symbol
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeAttributeSeam()
+
+~~~~~
+DecodeAttributeSeam(int attribute) {
+ return attribute_connectivity_decoders_[attribute].DecodeNextBit();
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/edgebreaker.traversal.valence.decoder.md b/docs/spec/edgebreaker.traversal.valence.decoder.md
new file mode 100644
index 0000000..444ed94
--- /dev/null
+++ b/docs/spec/edgebreaker.traversal.valence.decoder.md
@@ -0,0 +1,91 @@
+
+## EdgeBreaker Traversal Valence Decoder
+
+### EdgeBreakerTraversalValence_Start()
+
+~~~~~
+EdgeBreakerTraversalValence_Start(num_vertices, num_attribute_data) {
+ out_buffer = EdgebreakerTraversal_Start()
+ num_split_symbols I32
+ mode == 0 I8
+ num_vertices_ += num_split_symbols
+ vertex_valences_ init to 0
+ vertex_valences_.resize(num_vertices_, 0);
+ min_valence_ = 2;
+ max_valence_ = 7;
+ num_unique_valences = 6 (max_valence_ - min_valence_ + 1)
+ for (i = 0; i < num_unique_valences; ++i) {
+ DecodeVarint(&num_symbols, out_buffer)
+ If (num_symbols > 0) {
+ DecodeSymbols(num_symbols, out_buffer, &context_symbols_[i])
+ }
+ context_counters_[i] = num_symbols
+ }
+ return out_buffer;
+}
+~~~~~
+{:.draco-syntax }
+
+
+
+### TraversalValence_DecodeSymbol()
+
+~~~~~
+TraversalValence_DecodeSymbol() {
+ if (active_context_ != -1) {
+ symbol_id = context_symbols_[active_context_]
+ [--context_counters_[active_context_]]
+ last_symbol_ = edge_breaker_symbol_to_topology_id[symbol_id]
+ } else {
+ last_symbol_ = Traversal_DecodeSymbol()
+ }
+ return last_symbol_
+}
+~~~~~
+{:.draco-syntax }
+
+
+
+### TraversalValence_NewActiveCornerReached()
+
+~~~~~
+TraversalValence_NewActiveCornerReached(corner) {
+ switch (last_symbol_) {
+ case TOPOLOGY_C:
+ case TOPOLOGY_S:
+ vertex_valences_[ct(next)] += 1;
+ vertex_valences_[ct(prev)] += 1;
+ break;
+ case TOPOLOGY_R:
+ vertex_valences_[corner] += 1;
+ vertex_valences_[ct(next)] += 1;
+ vertex_valences_[ct(prev)] += 2;
+ break;
+ case TOPOLOGY_L:
+ vertex_valences_[corner] += 1;
+ vertex_valences_[ct(next)] += 2;
+ vertex_valences_[ct(prev)] += 1;
+ break;
+ case TOPOLOGY_E:
+ vertex_valences_[corner] += 2;
+ vertex_valences_[ct(next)] += 2;
+ vertex_valences_[ct(prev)] += 2;
+ break;
+ }
+ valence = vertex_valences_[ct(next)]
+ valence = max(valence, min_valence_)
+ valence = min(valence, max_valence_)
+ active_context_ = (valence - min_valence_);
+}
+~~~~~
+{:.draco-syntax }
+
+
+### TraversalValence_MergeVertices()
+
+~~~~~
+TraversalValence_MergeVertices(dest, source) {
+ vertex_valences_[dest] += vertex_valences_[source];
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/edgebreaker.traverser.md b/docs/spec/edgebreaker.traverser.md
new file mode 100644
index 0000000..7ded44c
--- /dev/null
+++ b/docs/spec/edgebreaker.traverser.md
@@ -0,0 +1,71 @@
+
+## EdgeBreaker Traverser
+
+### TraverseFromCorner()
+
+~~~~~
+TraverseFromCorner(corner_id) {
+ if (processor_.IsFaceVisited(corner_id))
+ return
+ corner_traversal_stack_.clear();
+ corner_traversal_stack_.push_back(corner_id);
+ next_vert = corner_table_->Vertex(corner_table_->Next(corner_id));
+ prev_vert = corner_table_->Vertex(corner_table_->Previous(corner_id));
+ if (!processor_.IsVertexVisited(next_vert)) {
+ processor_.MarkVertexVisited(next_vert);
+ traversal_observer_.OnNewVertexVisited(next_vert,
+ corner_table_->Next(corner_id));
+ }
+ if (!processor_.IsVertexVisited(prev_vert)) {
+ processor_.MarkVertexVisited(prev_vert);
+ traversal_observer_.OnNewVertexVisited(prev_vert,
+ corner_table_->Previous(corner_id));
+ }
+ while (!corner_traversal_stack_.empty()) {
+ corner_id = corner_traversal_stack_.back();
+ face_id =corner_id / 3;
+ if (processor_.IsFaceVisited(face_id)) {
+ corner_traversal_stack_.pop_back();
+ continue
+ }
+ while(true) {
+ face_id = corner_id / 3;
+ processor_.MarkFaceVisited(face_id);
+ traversal_observer_.OnNewFaceVisited(face_id);
+ vert_id = corner_table_->Vertex(corner_id);
+ on_boundary = corner_table_->IsOnBoundary(vert_id);
+ if (!processor_.IsVertexVisited(vert_id)) {
+ processor_.MarkVertexVisited(vert_id);
+ traversal_observer_.OnNewVertexVisited(vert_id, corner_id);
+ if (!on_boundary) {
+ corner_id = corner_table_->GetRightCorner(corner_id);
+ continue;
+ }
+ }
+ // The current vertex has been already visited or it was on a boundary.
+ right_corner_id = corner_table_->GetRightCorner(corner_id);
+ left_corner_id = corner_table_->GetLeftCorner(corner_id);
+ right_face_id((right_corner_id < 0 ? -1 : right_corner_id / 3));
+ left_face_id((left_corner_id < 0 ? -1 : left_corner_id / 3));
+ if (processor_.IsFaceVisited(right_face_id)) {
+ if (processor_.IsFaceVisited(left_face_id)) {
+ corner_traversal_stack_.pop_back();
+ break; // Break from while(true) loop
+ } else {
+ corner_id = left_corner_id;
+ }
+ } else {
+ if (processor_.IsFaceVisited(left_face_id)) {
+ corner_id = right_corner_id;
+ } else {
+ // Split the traversal.
+ corner_traversal_stack_.back() = left_corner_id;
+ corner_traversal_stack_.push_back(right_corner_id);
+ break; // Break from while(true) loop
+ }
+ }
+ }
+ }
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/index.md b/docs/spec/index.md
new file mode 100644
index 0000000..28c6157
--- /dev/null
+++ b/docs/spec/index.md
@@ -0,0 +1,47 @@
+---
+layout: spec
+title: Draco Bitstream Specification (Draft)
+version: Version 1,2
+version_date: Released 2017-xx-xx
+---
+
+{% include_relative 00.00.00.title.md %}
+{% include_relative 00.00.01.version.md %}
+{% include_relative 00.00.02.authors.md %}
+{% include_relative 00.00.03.last.modified.md %}
+{% include_relative 00.00.04.abstract.md %}
+{% include_relative 00.00.05.toc.md %}
+
+{% include_relative 01.00.00.scope.md %}
+{% include_relative 02.00.00.terms.md %}
+{% include_relative 03.00.00.symbols.md %}
+{% include_relative 04.00.00.conventions.md %}
+{% include_relative draco.decoder.md %}
+{% include_relative mesh.decoder.md %}
+{% include_relative edgebreaker.decoder.md %}
+{% include_relative edgebreaker.hole.and.topology.md %}
+{% include_relative edgebreaker.traversal.decoder.md %}
+{% include_relative edgebreaker.traversal.valence.decoder.md %}
+{% include_relative attributes.decoder.md %}
+{% include_relative sequential.attributes.decoders.controller.md %}
+{% include_relative sequential.attribute.decoder.md %}
+{% include_relative sequential.integer.attribute.decoder.md %}
+{% include_relative sequential.quantization.attribute.decoder.md %}
+{% include_relative prediction.scheme.transform.md %}
+{% include_relative prediction.scheme.wrap.transform.md %}
+{% include_relative mesh.prediction.scheme.parallelogram.md %}
+{% include_relative cornertable.traversal.processor.md %}
+{% include_relative mesh.attribute.indices.encoding.observer.md %}
+{% include_relative edgebreaker.traverser.md %}
+{% include_relative mesh.traversal.sequencer.md %}
+{% include_relative corner.table.md %}
+{% include_relative mesh.attribute.corner.table.md %}
+{% include_relative symbol.decoding.md %}
+{% include_relative rans.decoding.md %}
+{% include_relative rans.bit.decoder.md %}
+{% include_relative core.functions.md %}
+
+
+{% comment %}
+{% include_relative 99.00.01.testing.md %}
+{% endcomment %}
diff --git a/docs/spec/mesh.attribute.corner.table.md b/docs/spec/mesh.attribute.corner.table.md
new file mode 100644
index 0000000..bdb87da
--- /dev/null
+++ b/docs/spec/mesh.attribute.corner.table.md
@@ -0,0 +1,78 @@
+
+## Mesh Attribute Corner Table
+
+### bool IsCornerOnSeam()
+
+~~~~~
+bool IsCornerOnSeam(corner) {
+ return is_vertex_on_seam_[corner_table_->Vertex(corner)];
+}
+~~~~~
+{:.draco-syntax }
+
+
+### AddSeamEdge()
+
+~~~~~
+AddSeamEdge(c) {
+ MarkSeam(c)
+ opp_corner = corner_table_->Opposite(c);
+ if (opp_corner >= 0) {
+ no_interior_seams_ = false;
+ MarkSeam(opp_corner)
+ }
+}
+~~~~~
+{:.draco-syntax }
+
+
+### MarkSeam()
+
+~~~~~
+MarkSeam(c) {
+ is_edge_on_seam_[c] = true;
+ is_vertex_on_seam_[corner_table_->Vertex(corner_table_->Next(c))] = true;
+ is_vertex_on_seam_[corner_table_->Vertex(corner_table_->Previous(c))
+ ] = true;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### RecomputeVertices()
+
+~~~~~
+RecomputeVertices() {
+ // in code RecomputeVerticesInternal(nullptr, nullptr)
+ num_new_vertices = 0;
+ for (v = 0; v < corner_table_->num_vertices(); ++v) {
+ c = corner_table_->LeftMostCorner(v);
+ if (c < 0)
+ continue;
+ first_vert_id(num_new_vertices++);
+ vertex_to_attribute_entry_id_map_.push_back(first_vert_id);
+ first_c = c;
+ if (is_vertex_on_seam_[v]) {
+ act_c = SwingLeft(first_c);
+ while (act_c >= 0) {
+ first_c = act_c;
+ act_c = SwingLeft(act_c);
+ }
+ }
+ corner_to_vertex_map_[first_c] =first_vert_id;
+ vertex_to_left_most_corner_map_.push_back(first_c);
+ act_c = corner_table_->SwingRight(first_c);
+ while (act_c >= 0 && act_c != first_c) {
+ if (is_edge_on_seam_[corner_table_->Next(act_c)]) {
+ // in code IsCornerOppositeToSeamEdge()
+ first_vert_id = AttributeValueIndex(num_new_vertices++);
+ vertex_to_attribute_entry_id_map_.push_back(first_vert_id);
+ vertex_to_left_most_corner_map_.push_back(act_c);
+ }
+ corner_to_vertex_map_[act_c] = first_vert_id;
+ act_c = corner_table_->SwingRight(act_c);
+ }
+ }
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/mesh.attribute.indices.encoding.observer.md b/docs/spec/mesh.attribute.indices.encoding.observer.md
new file mode 100644
index 0000000..538c014
--- /dev/null
+++ b/docs/spec/mesh.attribute.indices.encoding.observer.md
@@ -0,0 +1,18 @@
+
+## Mesh Attribute Indices Encoding Observer
+
+### OnNewVertexVisited()
+
+~~~~~
+OnNewVertexVisited(vertex, corner) {
+ point_id = mesh_->face(corner / 3)[corner % 3];
+ sequencer_->AddPointId(point_id);
+ // Keep track of visited corners.
+ encoding_data_->encoded_attribute_value_index_to_corner_map.push_back(corner);
+ encoding_data_
+ ->vertex_to_encoded_attribute_value_index_map[vertex] =
+ encoding_data_->num_values;
+ encoding_data_->num_values++;
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/mesh.decoder.md b/docs/spec/mesh.decoder.md
new file mode 100644
index 0000000..47d57bf
--- /dev/null
+++ b/docs/spec/mesh.decoder.md
@@ -0,0 +1,11 @@
+## Mesh Decoder
+
+### DecodeConnectivityData()
+
+~~~~~
+DecodeConnectivityData()
+ InitializeDecoder()
+ DecodeConnectivity()
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/mesh.prediction.scheme.parallelogram.md b/docs/spec/mesh.prediction.scheme.parallelogram.md
new file mode 100644
index 0000000..bdf0783
--- /dev/null
+++ b/docs/spec/mesh.prediction.scheme.parallelogram.md
@@ -0,0 +1,63 @@
+
+## Mesh Prediction Scheme Parallelogram
+
+### Decode()
+
+~~~~~
+Decode(...) {
+ this->transform().InitializeDecoding(num_components);
+ // restore the first value
+ this->transform().ComputeOriginalValue(pred_vals.get(),
+ in_corr, out_data, 0);
+ // PredictionSchemeWrapTransform_ComputeOriginalValue()
+ corner_map_size = this->mesh_data().data_to_corner_map()->size();
+ for (p = 1; p < corner_map_size; ++p) {
+ corner_id = this->mesh_data().data_to_corner_map()->at(p);
+ dst_offset = p * num_components;
+ b= ComputeParallelogramPrediction(p, corner_id, table,
+ *vertex_to_data_map, out_data,
+ num_components, pred_vals.get())
+ if (!b) {
+ src_offset = (p - 1) * num_components;
+ this->transform().ComputeOriginalValue(out_data + src_offset, in_corr,
+ out_data + dst_offset, dst_offset);
+ // PredictionSchemeWrapTransform_ComputeOriginalValue()
+ } else {
+ this->transform().ComputeOriginalValue(pred_vals.get(), in_corr,
+ out_data + dst_offset, dst_offset);
+ // PredictionSchemeWrapTransform_ComputeOriginalValue()
+ }
+ }
+}
+~~~~~
+{:.draco-syntax }
+
+
+MeshPredictionSchemeParallelogramShared
+
+FIXME: ^^^ Heading level?
+
+
+### ComputeParallelogramPrediction()
+
+~~~~~
+ComputeParallelogramPrediction(...) {
+ oci = table->Opposite(ci);
+ vert_opp = vertex_to_data_map[table->Vertex(ci)];
+ vert_next = vertex_to_data_map[table->Vertex(table->Next(ci))];
+ vert_prev = vertex_to_data_map[table->Vertex(table->Previous(ci))];
+ if (vert_opp < data_entry_id && vert_next < data_entry_id &&
+ vert_prev < data_entry_id) {
+ v_opp_off = vert_opp * num_components;
+ v_next_off = vert_next * num_components;
+ v_prev_off = vert_prev * num_components;
+ for (c = 0; c < num_components; ++c) {
+ out_prediction[c] = (in_data[v_next_off + c] + in_data[v_prev_off + c]) -
+ in_data[v_opp_off + c];
+ }
+ Return true;
+ }
+ return false;
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/mesh.traversal.sequencer.md b/docs/spec/mesh.traversal.sequencer.md
new file mode 100644
index 0000000..a0c3864
--- /dev/null
+++ b/docs/spec/mesh.traversal.sequencer.md
@@ -0,0 +1,68 @@
+
+## Mesh Traversal Sequencer
+
+### GenerateSequenceInternal()
+
+~~~~~
+GenerateSequenceInternal() {
+ traverser_.OnTraversalStart();
+ If (corner_order_) {
+ // TODO
+ } else {
+ int32_t num_faces = traverser_.corner_table()->num_faces();
+ for (i = 0; i < num_faces; ++i) {
+ ProcessCorner(3 * i)
+ }
+ }
+ traverser_.OnTraversalEnd();
+}
+~~~~~
+{:.draco-syntax }
+
+
+### ProcessCorner()
+
+~~~~~
+ProcessCorner(corner_id) {
+ traverser_.TraverseFromCorner(corner_id);
+}
+~~~~~
+{:.draco-syntax }
+
+
+### UpdatePointToAttributeIndexMapping()
+
+~~~~~
+UpdatePointToAttributeIndexMapping(PointAttribute *attribute) {
+ corner_table = traverser_.corner_table();
+ attribute->SetExplicitMapping(mesh_->num_points());
+ num_faces = mesh_->num_faces();
+ num_points = mesh_->num_points();
+ for (f = 0; f < num_faces; ++f) {
+ face = mesh_->face(f);
+ for (p = 0; p < 3; ++p) {
+ point_id = face[p];
+ vert_id = corner_table->Vertex(3 * f + p);
+ att_entry_id(
+ encoding_data_
+ ->vertex_to_encoded_attribute_value_index_map[vert_id]);
+ attribute->SetPointMapEntry(point_id, att_entry_id);
+ }
+ }
+}
+~~~~~
+{:.draco-syntax }
+
+
+PointsSequencer
+
+FIXME: ^^^ Heading level?
+
+### AddPointId()
+
+~~~~~
+AddPointId(point_id) {
+ out_point_ids_->push_back(point_id);
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/prediction.scheme.transform.md b/docs/spec/prediction.scheme.transform.md
new file mode 100644
index 0000000..6057f14
--- /dev/null
+++ b/docs/spec/prediction.scheme.transform.md
@@ -0,0 +1,15 @@
+
+## Prediction Scheme Transform
+
+### ComputeOriginalValue()
+
+~~~~~
+ComputeOriginalValue(const DataTypeT *predicted_vals,
+ const CorrTypeT *corr_vals,
+ DataTypeT *out_original_vals, int val_id) {
+ for (i = 0; i < num_components_; ++i) {
+ out_original_vals[i] = predicted_vals[i] + corr_vals[val_id + i];
+ }
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/prediction.scheme.wrap.transform.md b/docs/spec/prediction.scheme.wrap.transform.md
new file mode 100644
index 0000000..10888a9
--- /dev/null
+++ b/docs/spec/prediction.scheme.wrap.transform.md
@@ -0,0 +1,46 @@
+
+## Prediction Scheme Wrap Transform
+
+### DecodeTransformData()
+
+~~~~~
+DecodeTransformData(buffer) {
+ min_value_ DT
+ max_value_ DT
+}
+~~~~~
+{:.draco-syntax }
+
+
+### ComputeOriginalValue()
+
+~~~~~
+ComputeOriginalValue(const DataTypeT *predicted_vals,
+ const CorrTypeT *corr_vals,
+ DataTypeT *out_original_vals, int val_id) {
+ clamped_vals = ClampPredictedValue(predicted_vals);
+ ComputeOriginalValue(clamped_vals, corr_vals, out_original_vals, val_id)
+ // PredictionSchemeTransform_ComputeOriginalValue()
+ for (i = 0; i < this->num_components(); ++i) {
+ if (out_original_vals[i] > max_value_) {
+ out_original_vals[i] -= max_dif_;
+ } else if (out_original_vals[i] < min_value_) {
+ out_original_vals[i] += max_dif_;
+ }
+}
+~~~~~
+{:.draco-syntax }
+
+
+### ClampPredictedValue()
+
+~~~~~
+ClampPredictedValue(const DataTypeT *predicted_val) {
+ for (i = 0; i < this->num_components(); ++i) {
+ clamped_value_[i] = min(predicted_val[i], max_value_)
+ clamped_value_[i] = max(predicted_val[i], min_value_)
+ }
+ return &clamped_value_[0];
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/rans.bit.decoder.md b/docs/spec/rans.bit.decoder.md
new file mode 100644
index 0000000..595c21e
--- /dev/null
+++ b/docs/spec/rans.bit.decoder.md
@@ -0,0 +1,25 @@
+
+## Rans Bit Decoder
+
+### RansBitDecoder_StartDecoding()
+
+~~~~~
+RansBitDecoder_StartDecoding(DecoderBuffer *source_buffer) {
+ prob_zero_ UI8
+ size UI32
+ buffer_ size * UI8
+ ans_read_init(&ans_decoder_, buffer_, size)
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeNextBit()
+
+~~~~~
+DecodeNextBit() {
+ uint8_t bit = rabs_desc_read(&ans_decoder_, prob_zero_);
+ return bit > 0;
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/rans.decoding.md b/docs/spec/rans.decoding.md
new file mode 100644
index 0000000..c5cb358
--- /dev/null
+++ b/docs/spec/rans.decoding.md
@@ -0,0 +1,124 @@
+
+## Rans Decoding
+
+### ans_read_init()
+
+~~~~~
+ans_read_init(struct AnsDecoder *const ans, const uint8_t *const buf,
+ int offset) {
+ x = buf[offset - 1] >> 6
+ If (x == 0) {
+ ans->buf_offset = offset - 1;
+ ans->state = buf[offset - 1] & 0x3F;
+ } else if (x == 1) {
+ ans->buf_offset = offset - 2;
+ ans->state = mem_get_le16(buf + offset - 2) & 0x3FFF;
+ } else if (x == 2) {
+ ans->buf_offset = offset - 3;
+ ans->state = mem_get_le24(buf + offset - 3) & 0x3FFFFF;
+ } else if (x == 3) {
+ // x == 3 implies this byte is a superframe marker
+ return 1;
+ }
+ ans->state += l_base;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### int rabs_desc_read()
+
+~~~~~
+int rabs_desc_read(struct AnsDecoder *ans, AnsP8 p0) {
+ AnsP8 p = ans_p8_precision - p0;
+ if (ans->state < l_base) {
+ ans->state = ans->state * io_base + ans->buf[--ans->buf_offset];
+ }
+ x = ans->state;
+ quot = x / ans_p8_precision;
+ rem = x % ans_p8_precision;
+ xn = quot * p;
+ val = rem < p;
+ if (val) {
+ ans->state = xn + rem;
+ } else {
+ ans->state = x - xn - p;
+ }
+ return val;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### rans_read_init()
+
+~~~~~
+rans_read_init(UI8 *buf, int offset) {
+ ans_.buf = buf;
+ x = buf[offset - 1] >> 6
+ If (x == 0) {
+ ans_.buf_offset = offset - 1;
+ ans_.state = buf[offset - 1] & 0x3F;
+ } else if (x == 1) {
+ ans_.buf_offset = offset - 2;
+ ans_.state = mem_get_le16(buf + offset - 2) & 0x3FFF;
+ } else if (x == 2) {
+ ans_.buf_offset = offset - 3;
+ ans_.state = mem_get_le24(buf + offset - 3) & 0x3FFFFF;
+ } else if (x == 3) {
+ ans_.buf_offset = offset - 4;
+ ans_.state = mem_get_le32(buf + offset - 4) & 0x3FFFFFFF;
+ }
+ ans_.state += l_rans_base;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### rans_build_look_up_table()
+
+~~~~~
+rans_build_look_up_table() {
+ cum_prob = 0
+ act_prob = 0
+ for (i = 0; i < num_symbols; ++i) {
+ probability_table_[i].prob = token_probs[i];
+ probability_table_[i].cum_prob = cum_prob;
+ cum_prob += token_probs[i];
+ for (j = act_prob; j < cum_prob; ++j) {
+ Lut_table_[j] = i
+ }
+ act_prob = cum_prob
+}
+~~~~~
+{:.draco-syntax }
+
+
+### rans_read()
+
+~~~~~
+rans_read() {
+ while (ans_.state < l_rans_base) {
+ ans_.state = ans_.state * io_base + ans_.buf[--ans_.buf_offset];
+ }
+ quo = ans_.state / rans_precision;
+ rem = ans_.state % rans_precision;
+ sym = fetch_sym()
+ ans_.state = quo * sym.prob + rem - sym.cum_prob;
+ return sym.val;
+}
+~~~~~
+{:.draco-syntax }
+
+
+### fetch_sym()
+
+~~~~~
+fetch_sym() {
+ symbol = lut_table[rem]
+ out->val = symbol
+ out->prob = probability_table_[symbol].prob;
+ out->cum_prob = probability_table_[symbol].cum_prob;
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/sequential.attribute.decoder.md b/docs/spec/sequential.attribute.decoder.md
new file mode 100644
index 0000000..2a09f44
--- /dev/null
+++ b/docs/spec/sequential.attribute.decoder.md
@@ -0,0 +1,28 @@
+
+## Sequential Attribute Decoder
+
+~~~~~
+Initialize(...) {
+ // Init some members
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeValues()
+
+~~~~~
+DecodeValues(const std::vector &point_ids) {
+ num_values = point_ids.size();
+ entry_size = attribute_->byte_stride();
+ std::unique_ptr value_data_ptr(new uint8_t[entry_size]);
+ out_byte_pos = 0;
+ for (i = 0; i < num_values; ++i) {
+ value_data UI8 * entry_size
+ attribute_->buffer()->Write(out_byte_pos, value_data, entry_size);
+ out_byte_pos += entry_size;
+ }
+}
+~~~~~
+{:.draco-syntax }
+
diff --git a/docs/spec/sequential.attributes.decoders.controller.md b/docs/spec/sequential.attributes.decoders.controller.md
new file mode 100644
index 0000000..6edffba
--- /dev/null
+++ b/docs/spec/sequential.attributes.decoders.controller.md
@@ -0,0 +1,54 @@
+
+## Sequential Attributes Decoders Controller
+
+### DecodeAttributesDecoderData()
+
+~~~~~
+DecodeAttributesDecoderData(buffer) {
+ AttributesDecoder_DecodeAttributesDecoderData(buffer)
+ sequential_decoders_.resize(num_attributes());
+ for (i = 0; i < num_attributes(); ++i) {
+ decoder_type UI8
+ sequential_decoders_[i] = CreateSequentialDecoder(decoder_type);
+ sequential_decoders_[i]->Initialize(decoder(), GetAttributeId(i))
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeAttributes()
+
+~~~~~
+DecodeAttributes(buffer) {
+ sequencer_->GenerateSequence(&point_ids_)
+ for (i = 0; i < num_attributes(); ++i) {
+ pa = decoder()->point_cloud()->attribute(GetAttributeId(i));
+ sequencer_->UpdatePointToAttributeIndexMapping(pa)
+ }
+ for (i = 0; i < num_attributes(); ++i) {
+ sequential_decoders_[i]->Decode(point_ids_, buffer)
+ //SequentialAttributeDecoder_Decode()
+ }
+}
+~~~~~
+{:.draco-syntax }
+
+
+### CreateSequentialDecoder()
+
+~~~~~
+CreateSequentialDecoder(type) {
+ switch (type) {
+ case SEQUENTIAL_ATTRIBUTE_ENCODER_GENERIC:
+ return new SequentialAttributeDecoder()
+ case SEQUENTIAL_ATTRIBUTE_ENCODER_INTEGER:
+ return new SequentialIntegerAttributeDecoder()
+ case SEQUENTIAL_ATTRIBUTE_ENCODER_QUANTIZATION:
+ return new SequentialQuantizationAttributeDecoder()
+ case SEQUENTIAL_ATTRIBUTE_ENCODER_NORMALS:
+ return new SequentialNormalAttributeDecoder()
+ }
+}
+~~~~~
+{:.draco-syntax }
+
diff --git a/docs/spec/sequential.integer.attribute.decoder.md b/docs/spec/sequential.integer.attribute.decoder.md
new file mode 100644
index 0000000..ac663d1
--- /dev/null
+++ b/docs/spec/sequential.integer.attribute.decoder.md
@@ -0,0 +1,55 @@
+
+## Sequential Integer Attribute Decoder
+
+~~~~~
+Initialize(...) {
+ SequentialAttributeDecoder_Initialize()
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeValues()
+
+~~~~~
+DecodeValues(point_ids) {
+ prediction_scheme_method I8
+ if (prediction_scheme_method != PREDICTION_NONE) {
+ prediction_transform_type I8
+ prediction_scheme_ = CreateIntPredictionScheme(...)
+ }
+ if (prediction_scheme_) {
+ }
+ DecodeIntegerValues(point_ids)
+ //SequentialQuantizationAttributeDecoder_DecodeIntegerValues()
+ //StoreValues()
+ DequantizeValues(num_values)
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeIntegerValues()
+
+~~~~~
+DecodeIntegerValues(point_ids) {
+ compressed UI8
+ if (compressed) {
+ DecodeSymbols(..., values_.data())
+ } else {
+ // TODO
+ }
+ if (!prediction_scheme_->AreCorrectionsPositive()) {
+ ConvertSymbolsToSignedInts(...)
+ }
+ if (prediction_scheme_) {
+ prediction_scheme_->DecodePredictionData(buffer)
+ // DecodeTransformData(buffer)
+ if (!values_.empty()) {
+ prediction_scheme_->Decode(values_.data(), &values_[0],
+ values_.size(), num_components, point_ids.data())
+ // MeshPredictionSchemeParallelogram_Decode()
+}
+~~~~~
+{:.draco-syntax }
+
diff --git a/docs/spec/sequential.quantization.attribute.decoder.md b/docs/spec/sequential.quantization.attribute.decoder.md
new file mode 100644
index 0000000..692cf9b
--- /dev/null
+++ b/docs/spec/sequential.quantization.attribute.decoder.md
@@ -0,0 +1,49 @@
+
+## Sequential Quantization Attribute Decoder
+
+~~~~~
+Initialize(...) {
+ SequentialIntegerAttributeDecoder_Initialize()
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeIntegerValues()
+
+~~~~~
+DecodeIntegerValues(point_ids) {
+ // DecodeQuantizedDataInfo()
+ num_components = attribute()->components_count();
+ for (i = 0; i < num_components; ++i) {
+ min_value_[i] F32
+ }
+ max_value_dif_ F32
+ quantization_bits_ UI8
+ SequentialIntegerAttributeDecoder::DecodeIntegerValues()
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DequantizeValues()
+
+~~~~~
+DequantizeValues(num_values) {
+ max_quantized_value = (1 << (quantization_bits_)) - 1;
+ num_components = attribute()->components_count();
+ entry_size = sizeof(float) * num_components;
+ quant_val_id = 0;
+ out_byte_pos = 0;
+ for (i = 0; i < num_values; ++i) {
+ for (c = 0; c < num_components; ++c) {
+ value = dequantizer.DequantizeFloat(values()->at(quant_val_id++));
+ value = value + min_value_[c];
+ att_val[c] = value;
+ }
+ attribute()->buffer()->Write(out_byte_pos, att_val.get(), entry_size);
+ out_byte_pos += entry_size;
+ }
+}
+~~~~~
+{:.draco-syntax }
diff --git a/docs/spec/symbol.decoding.md b/docs/spec/symbol.decoding.md
new file mode 100644
index 0000000..084187d
--- /dev/null
+++ b/docs/spec/symbol.decoding.md
@@ -0,0 +1,109 @@
+
+## Symbol Decoding
+
+### DecodeSymbols()
+
+~~~~~
+DecodeSymbols(num_symbols, out_buffer, out_values) {
+ scheme UI8
+ If (scheme == 0) {
+ DecodeTaggedSymbols<>(num_symbols, src_buffer, out_values)
+ } else if (scheme == 1) {
+ DecodeRawSymbols<>(num_symbols, src_buffer, out_values)
+ }
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeTaggedSymbols()
+
+~~~~~
+DecodeTaggedSymbols() {
+ FIXME
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeRawSymbols()
+
+~~~~~
+DecodeRawSymbols() {
+ max_bit_length UI8
+ DecodeRawSymbolsInternal(max_bit_length, out_values)
+ return symbols
+}
+~~~~~
+{:.draco-syntax }
+
+
+### DecodeRawSymbolsInternal()
+
+~~~~~
+DecodeRawSymbolsInternal(max_bit_length, out_values) {
+ decoder = CreateRansSymbolDecoder(max_bit_length)
+ decoder.StartDecoding()
+ // RansSymbolDecoder_StartDecoding
+ for (i = 0; i < num_values; ++i) {
+ out_values[i] = decoder.DecodeSymbol()
+ // RansSymbolDecoder_DecodeSymbol
+ }
+}
+~~~~~
+{:.draco-syntax }
+
+
+### CreateRansSymbolDecoder()
+
+~~~~~
+CreateRansSymbolDecoder(max_bit_length) {
+ rans_precision_bits = (3 * max_bit_length) / 2;
+ rans_precision_bits = min(rans_precision_bits, 20)
+ rans_precision_bits = max(rans_precision_bits, 12)
+ rans_precision = 1 << rans_precision_bits_;
+ l_rans_base = rans_precision * 4;
+ num_symbols_ UI32
+ for (i = 0; i < num_symbols_; ++i) {
+ prob_data UI8
+ if ((prob_data & 3) == 3) {
+ offset = prob_data >> 2
+ for (j = 0; j < offset + 1; ++j) {
+ probability_table_[i + j] = 0;
+ }
+ i += offset;
+ } else {
+ prob = prob_data >> 2
+ for (j = 0; j < token; ++j) {
+ eb UI8
+ prob = prob | (eb << (8 * (j + 1) - 2)
+ }
+ probability_table_[i] = prob;
+ }
+ }
+ rans_build_look_up_table()
+}
+~~~~~
+{:.draco-syntax }
+
+
+### RansSymbolDecoder_StartDecoding()
+
+~~~~~
+RansSymbolDecoder_StartDecoding() {
+ bytes_encoded UI64
+ buffer bytes_encoded * UI8
+ rans_read_init(buffer, bytes_encoded)
+}
+~~~~~
+{:.draco-syntax }
+
+
+### RansSymbolDecoder_DecodeSymbol()
+
+~~~~~
+RansSymbolDecoder_DecodeSymbol() {
+ ans_.rans_read()
+}
+~~~~~
+{:.draco-syntax }